Spec-Zone.ru › C

Этапы трансляции

Файл исходного кода C обрабатывается компилятором как если бы выполнялись следующие этапы в точном порядке. Фактическая реализация может объединять эти действия или обрабатывать их по-разному, при условии сохранения одинакового поведения.

Этап 1

1) Отдельные байты файла исходного кода (который, как правило, является текстовым файлом в какой-либо многобайтовой кодировке, такой как UTF-8) отображаются, по определению реализации, на символы исходного набора символов. В частности, зависящие от ОС индикаторы конца строки заменяются символами новой строки. Исходный набор символов — это многобайтовый набор символов, который включает базовый набор символов исходного кода как однобайтовый подмножество, состоящий из следующих 96 символов:
a) 5 символов пробела (пробел, табуляция, вертикальная табуляция, перевод страницы, новая строка)
b) 10 цифр от '0' до '9'
c) 52 буквы от 'a' до 'z' и от 'A' до 'Z'
d) 29 символов пунктуации: _ { } [ ] # ( ) < > % : ; . ? * + - / ^ & | ~ ! = , \ " '
2) Последовательности триграфов заменяются соответствующими представлениями одиночных символов.(до C23)

Этап 2

1) Всякий раз, когда обратный слэш появляется в конце строки (непосредственно перед символом новой строки), и обратный слэш, и символ новой строки удаляются, объединяя две физические строки исходного кода в одну логическую строку. Это однопроходная операция: строка, заканчивающаяся двумя обратными слэшами, за которыми следует пустая строка, не объединяет три строки в одну.
#include <stdio.h>
 
#define PUTS p\
u\
t\
s
/* Line splicing is in phase 2 while macros
 * are tokenized in phase 3 and expanded in phase 4,
 * so the above is equivalent to #define PUTS puts
 */
 
int main(void)
{
 /* Use line splicing to call puts */ PUT\
S\
("Output ends here\\
0Not printed" /* After line splicing, the remaining backslash
               * escapes the 0, ending the string early.
               */
);
}
2) Если непустой файл исходного кода по окончании этого этапа не завершается символом новой строки (независимо от того, был ли он изначально без символа новой строки или завершался обратным слэшем), поведение является неопределённым.

Этап 3

1) Файл исходного кода разлагается на комментарии, последовательности символов пробела (пробел, горизонтальная табуляция, новая строка, вертикальная табуляция и перевод страницы) и предпроцессорные токены, которые следующие
a) имена заголовков: <stdio.h> или "myfile.h"
b) идентификаторы
c) предпроцессорные числа, которые охватывают целые константы и константы с плавающей точкой, но также охватывают некоторые недопустимые токены, такие как 1..E+3.foo или 0JBK
d) символьные константы и строковые литералы
e) операторы и разделители, такие как +, <<=, <%, или ##.
f) отдельные символы, не являющиеся пробелами, которые не подходят ни к одной другой категории
2) Каждый комментарий заменяется одним символом пробела
3) Символы новой строки сохраняются, и определяется реализацией, могут ли последовательности пробелов, не являющиеся символами новой строки, быть объединены в один символ пробела.

Если входной файл был проанализирован в предпроцессорные токены до заданного символа, то следующим предпроцессорным токеном, как правило, считается самая длинная последовательность символов, которая может составлять предпроцессорный токен, даже если это приведет к последующему анализу с ошибкой. Это обычно известно как максимальное поглощение.

int foo = 1;
// int bar = 0xE+foo; // error: invalid preprocessing number 0xE+foo
int bar = 0xE/*Comment expands to a space*/+foo; // OK: 0xE + foo
int baz = 0xE + foo; // OK: 0xE + foo
int pub = bar+++baz; // OK: bar++ + baz
int ham = bar++-++baz; // OK: bar++ - ++baz
// int qux = bar+++++baz; // error: bar++ ++ +baz, not bar++ + ++baz
int qux = bar+++/*Saving comment*/++baz; // OK: bar++ + ++baz

Единственное исключение из правила максимального поглощения:

  • Предпроцессорные токены имён заголовков формируются только в #include или #embed(с C23) директиве, в __has_include и __has_embed выражениях(с C23) и в определённых реализацией местах в #pragma директиве.
#define MACRO_1 1
#define MACRO_2 2
#define MACRO_3 3
#define MACRO_EXPR (MACRO_1 <MACRO_2> MACRO_3) // OK: <MACRO_2> is not a header-name

Этап 4

1) Выполняется предпроцессор.
2) Каждый файл, введённый с помощью директивы #include, проходит этапы 1–4 рекурсивно.
3) По завершении этого этапа все директивы предпроцессора удаляются из исходного кода.

Этап 5

1) Все символы и последовательности экранирования в символьных константах и строковых литералах преобразуются из исходного набора символов в набор символов выполнения (который может быть многобайтовым набором символов, таким как UTF-8, при условии, что все 96 символов из базового набора символов исходного кода, перечисленных на этапе 1, имеют однобайтовые представления). Если символ, указанный последовательностью экранирования, не является членом набора символов выполнения, результат определяется реализацией, но гарантируется, что он не будет нулевым (широким) символом.

Примечание: преобразование, выполняемое на данном этапе, может контролироваться параметрами командной строки в некоторых реализациях: gcc и clang используют -finput-charset для указания кодировки исходного набора символов, -fexec-charset и -fwide-exec-charset для указания кодировок набора символов выполнения в строковых литералах и символьных константах без префикса кодировки(с C11).

Этап 6

Смежные строковые литералы конкатенируются.

Этап 7

Происходит компиляция: токены анализируются с точки зрения синтаксиса и семантики и переводятся как единица трансляции.

Этап 8

Происходит компоновка: единицы трансляции и необходимые библиотечные компоненты для удовлетворения внешних ссылок собираются в образ программы, который содержит информацию, необходимую для выполнения в среде выполнения (ОС).

Ссылки

  • Стандарт C23 (ISO/IEC 9899:2023):
    • 5.1.1.2 Этапы трансляции (стр.: TBD)
    • 5.2.1 Наборы символов (стр.: TBD)
    • 6.4 Лексические элементы (стр.: TBD)
  • Стандарт C17 (ISO/IEC 9899:2018):
    • 5.1.1.2 Этапы трансляции (стр.: 9-10)
    • 5.2.1 Наборы символов (стр.: 17)
    • 6.4 Лексические элементы (стр.: 41-54)
  • Стандарт C11 (ISO/IEC 9899:2011):
    • 5.1.1.2 Этапы трансляции (стр.: 10-11)
    • 5.2.1 Наборы символов (стр.: 22-24)
    • 6.4 Лексические элементы (стр.: 57-75)
  • Стандарт C99 (ISO/IEC 9899:1999):
    • 5.1.1.2 Этапы трансляции (стр.: 9-10)
    • 5.2.1 Наборы символов (стр.: 17-19)
    • 6.4 Лексические элементы (стр.: 49-66)
  • Стандарт C89/C90 (ISO/IEC 9899:1990):
    • 2.1.1.2 Этапы трансляции
    • 2.2.1 Наборы символов
    • 3.1 Лексические элементы

См. также

Документация C++ для Этапов трансляции

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/c/language/translation_phases

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API