Думая о препроцессоре C как очень простой компилятор, чтобы перевести файл, препроцессор C концептуально выполняет несколько этапов.
- Лексический анализ - Группы последовательность символов, составляющих блок предварительной обработки перевода в строках, имеющих идентифицированного значение (маркеры) на языке препроцессора.
- Синтаксический анализ - Группирует маркеры блока предварительной обработки в синтаксические структуры, построенные в соответствии с грамматикой языка предварительной обработки.
- Генерация кода - Переводит все файлы, составляющие блок перевода предварительной обработки, в один файл, содержащий только «чистые» инструкции C.
Строго говоря, фазы перевода, упомянутые в §5.1.1.2 части C Standard (ISO/IEC 9899:201x), относящейся к предварительной обработке фазе 3 и фаза 4. Фаза 3 соответствует почти точно лексического анализа в то время фазы 4 составляет примерно генерации кода.
Синтаксический анализ (синтаксический анализ), кажется, отсутствует на этом снимке. Действительно, грамматика препроцессора C настолько проста, что реальные препроцессоры/компиляторы выполняют ее вместе с лексическим анализом.
Если фаза синтаксического анализа завершается успешно - то есть все утверждения в блоке перевода препроцессора являются законными в соответствии с грамматикой препроцессора - может генерироваться генерация кода и выполняются все предпроцессорные директивы.
Выполнение директивы предварительной обработки означает преобразование исходного файла в соответствии с его семантикой, а затем удаление директивы из исходного файла.
Семантика для каждой директивы препроцессора указана в §6.10.1-6.10.9 Стандарта C.
Возвращаясь к вашей примерной программе, 2 файла, которые вы предоставили, т. Е. a.h
и b.h
, концептуально обрабатываются следующим образом.
Лексический анализ - Каждый отдельный маркер предварительной обработки ограничен а «{» на левый и а «}» справа.
a.h
{#}{if} {1}
{#}{include} {"b.h"}
b.h
{#}{endif}
Эта фаза выполняется без ошибок и его результат, последовательность предварительной обработки маркеров, передается на последующем этапе: синтаксический анализ.
синтаксический анализ
Предварительный вывод для ах приведен ниже
preprocessing-file →
group →
group-part →
if-section →
if-group endif-line →
if-group #endif new-line →
…
, и ясно, что содержание ах не может быть выведена из грамматики предварительной обработки - на самом деле согласующим #endif
отсутствует - и поэтому a.h
не является синтаксически правильным. Это именно то, что ваш компилятор говорит вам, когда он пишет
a.h:1:0: error: unterminated #if
Нечто подобное происходит и для b.h
; рассуждения в обратном направлении, то #endif
может быть получена только из правила
if-section →
if-group elif-groups[opt] else-group[opt] endif-line
Это означает, что содержимое файла должно быть получено из одного из следующих 3 групп
# if constant-expression new-line group[opt]
# ifdef identifier new-line group[opt]
# ifndef identifier new-line group[opt]
Поскольку это не так, потому что b.h
не содержит # if/# ifdef/# ifndef
, а только одну строку #endif
, содержимое b.h
не является синтаксически правильным, и ваш компилятор сообщает вам об этом таким образом
In file included from a.h:2:0:
b.h:1:2: error: #endif without #if
Генерация кода
Конечно, так как ваша программа лексически звук, но синтаксически не правильно, эта фаза никогда не будет выполнена.
Даже если положить '# if' в один файл и соответствующий' # endif' в другой законный, это будет ИМХО быть плохой идеей. –