Skip to content

Latest commit

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date

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)

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

V1V2

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)

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

chcp65001

Далее:

setPATH=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

Учебный проект: реализация препроцессора C++ с рекурсивным раскрытием #include, regex, filesystem и склейкой проекта в один файл.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages