Skip to content

amanzhola/cpp-preprocessor2

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cpp-preprocessor2

Учебный проект: свой препроцессор C++
(раскрытие #include) с использованием:

  • std::regex
  • сырых строковых литералов (R"( ... )")
  • рекурсии
  • std::filesystem

Проект демонстрирует прохождение тестов и реальное использование препроцессора в цепочке сборки.


Идея проекта

Мы пишем собственный препроцессор, а затем используем его:

  • чтобы склеить исходники другой версии проекта в один .cpp,
  • скомпилировать этот файл,
  • и запустить тесты.

То есть препроцессор работает на практике.


Кратко о версиях

  • V0 — оркестратор (launcher):

    • компилирует V1,
    • запускает тесты V1,
    • запускает V1 в режиме --flatten,
    • компилирует результат в V2,
    • запускает тесты V2.
  • V1 — минимальная реализация препроцессора по ТЗ

    • режим --flatten (склейка проекта в один .cpp).
  • V2 — улучшенная версия:

    • убирает UTF-8 BOM,
    • нормализует CRLF,
    • нормализует пути,
    • кэширует найденные include.

Итоговая цепочка работы (что реально происходит)

V0
├─ компилирует V1
├─ запускает V1 (тесты)
├─ запускает V1 --flatten
│     └─ получает build/v2_flat.cpp
├─ компилирует build/v2_flat.cpp → v2.exe
└─ запускает v2.exe (тесты)

Главное:

  • build/v2_flat.cpp создаётся препроцессором V1.
  • Это делается рекурсией + regex, ровно теми же приёмами, которые изучались в уроке.
  • В сборочной цепочке используется режим --flatten.

Ограничение склейки include (ВАЖНО)

В режиме --flatten препроцессор раскрывает ТОЛЬКО директивы вида:

#include "..."

Директивы вида:

#include <...>

НЕ раскрываются и копируются в выходной файл без изменений.

Почему так сделано

  • системные заголовки (<iostream>, <vector> и т.д.) должны обрабатываться настоящим компилятором (g++);

  • поиск и раскрытие системных include не входит в задание;

  • это соответствует реальной практике склейки пользовательского кода:

    • unity build — компиляция проекта как одного большого файла (часто для ускорения сборки);
    • amalgamation — распространение проекта в виде одного .cpp (классический пример — SQLite).

Итог:

препроцессор склеивает пользовательский код, компилятор обрабатывает стандартную библиотеку.


Структура проекта

cpp-preprocessor2/
│
├─ README.md
├─ v0.cpp                     # Оркестратор: V1 → flatten → V2
│
├─ v1_parts/
│   ├─ v1_main.cpp            # main() V1: тесты и режим --flatten
│   └─ v1_preprocess_impl.h
│       ├─ Preprocess                 # режим ТЗ
│       ├─ PreprocessOne_TZ           # рекурсия для ТЗ
│       ├─ FlattenProject             # режим --flatten
│       └─ PreprocessOne_Flatten      # рекурсивная склейка "..."
│
├─ v2_parts/
│   ├─ v2_main.cpp            # main() V2: тесты
│   └─ v2_preprocess_impl.h   # улучшенная реализация
│
├─ common/
│   └─ tests_common.h         # общие тесты (используются V1 и V2)
│
└─ build/
    └─ v2_flat.cpp            # GENERATED: результат --flatten (создаётся V1)

Ключевые функции (кто что делает)

V1 V2

v1::Preprocess(...)
Реализация по ТЗ: раскрывает "..." и <...> по правилам задания.

v1::PreprocessOne_TZ(...)
Рекурсивная функция: читает файл построчно, заменяет #include вставкой содержимого.

v1::FlattenProject(...)
Делает “склейку” проекта в один .cpp (используется в сборке V2).

v1::PreprocessOne_Flatten(...)
Главная функция склейки:
• рекурсивно раскрывает #include "..."
НЕ раскрывает #include <...>
• игнорирует #pragma once
• формирует build/v2_flat.cpp

Улучшенная реализация препроцессора:
• удаляет BOM
• нормализует CRLF (убирает \r)
• нормализует пути
• кэширует найденные include
• проходит те же тесты


Запуск (Windows / MinGW)

Чтобы русский текст корректно отображался в консоли:

chcp 65001

Далее:

set PATH=C:\Qt\Tools\mingw1310_64\bin;%PATH%
g++ -std=gnu++17 v0.cpp -o v0.exe
v0.exe

Ожидаемый вывод (как в тренажёре)

Ключевые строки:

g++ -std=gnu++17 v1_parts/v1_main.cpp -o v1.exe
v1.exe
V1: минимальная реализация + flatten (только #include "...")
Анализируем и компилируем решение...
Запускаем тесты...
Успех!
v1.exe --flatten v2_parts/v2_main.cpp build/v2_flat.cpp v2_parts common
g++ -std=gnu++17 build/v2_flat.cpp -o v2.exe
v2.exe
V2: улучшенная версия (BOM/CRLF/normalize/кэш) + flatten
Анализируем и компилируем решение...
Запускаем тесты...
Успех!

Диаграмма вызовов функций (ASCII)

v0.exe
  ├─ system("g++ ... v1_main.cpp -> v1.exe")
  ├─ system("v1.exe")                     // тесты V1
  ├─ system("v1.exe --flatten ...")       // склейка V2
  │     └─ v1_main.cpp: main()
  │           └─ FlattenProject(...)
  │                 └─ PreprocessOne_Flatten(...)
  │                      ├─ regex_match("#include \"...\"")
  │                      └─ рекурсия
  ├─ system("g++ ... build/v2_flat.cpp -> v2.exe")
  └─ system("v2.exe")                     // тесты V2

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages