Пространства имён
Варианты
Действия

Фазы транслятора

Материал из cppreference.com
< cpp‎ | language

Исходный файл C++ должен быть препроцессирован компилятором так, как будто последовательно выполняются следующие фазы:

Содержание

[править] Фаза 1

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

[править] Фаза 2

1 ) Всякий раз, когда символ \ (обратная косая черта, backslash) появляется в конце строки (сразу же после символа новой строки), как символ \, так и символ новой строки удаляются, объединяя две физические строки исходного кода в одну логическую строку исходного кода. Это однопроходная операция. Строка, заканчивающаяся двумя символами \, за которой следует пустая строка, не объединяет три строки в одну. Если на этой фазе сформировано универсальное имя символа (\uXXX), поведение не определено.
2 ) Если после этого шага непустой файл исходного кода не заканчился символом новой строки (независимо от того, не было ли у него символа новой строки изначально или он закончился символом \), поведение не определено (до C++11) добавляется завершающей символ новой строки (начиная с C++11).

[править] Фаза 3

1 ) Файл исходного кода разбивается на комментарии, последовательности пробельных символов и лексемы препроцессора, которые являются следующим:
a) имена заголовочных файлов, такие как <iostream> или "myfile.h" (распознаются только после директивы #include)
c) числа препроцессора
e) символы операций и пунктуаторы (в том числе альтернативные лексемы), такие как +, <<=, new, <%, ##, или and
f) отдельные непробельные символы, которые не входят ни в одну из категорий
2 ) Отменяются любые преобразования, выполненные во время фаз 1 и 2 между символами " (открывающая и закрывающая двойная кавычка), в любом необработанном строковом литерале.
(начиная с C++11)
3 ) Каждый комментарий заменяется одним пробелом.

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

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

int foo = 1;
int bar = 0xE+foo;   // ошибка, недействительное число препроцессора 0xE+foo
int baz = 0xE + foo; // OK
 
int quux = bar+++++baz; // ошибка: распознается как bar++ ++ +baz, а не как bar++ + ++baz.

Исключения из правила максимального куска:

  • Если следующий символ начинает последовательность символов, которая могла бы быть префиксом и открывающей двойной кавычкой необработанного строкового литерала, то следующей лексемой препроцессора будет необработанным строковым литералом. Этот литерал состоит из кратчайшей последовательности символов, которая совпадает с шаблоном необработанного литерала.
#define R "x"
const char* s = R"y"; 		// неверный необработанный строковый литерал, не "x" "y"
const char* s2 = R"(a)" "b)";   // необработанный строковый литерал, 
                                // за которым идёт обычный строковый литерал
  • Если следующими тремя символами будут <:: и последующий символ не : и не >, то < рассматривается как лексема препроцессора сама по себе (а не как первый символ альтернативной лексемы <:).
struct Foo { static const int v = 1; };
std::vector<::Foo> x; // OK, <: не рассматривается как альтернативная лексема для [
extern int y<::>;     // OK, эксивалентно extern int y[].
int z<:::Foo::value:>; // OK, int z[::Foo::value];
(начиная с C++11)
  • Лексемы препроцессора, указывающие имена заголовочных файлов, формируются только внутри директивы #include.
std::vector<int> x; // OK, <int> не имя заголовочного файла

[править] Фаза 4

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

[править] Фаза 5

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

Примечание: преобразование, выполняемое на этом этапе, в некоторых реализациях может управляться параметрами командной строки : GCC и Clang используют -finput-charset и -fwide-exec-charset для указания соответственно кодировок исходного и исполняемого набора символов в строковых и символьных литералах , которые не имеют префикс, указывающий кодировку (начиная с C++11). Visual Studio, начиная с Visual Studio 2015 Update 2, использует параметры /source-charset и /execution-charset соответственно.

[править] Фаза 6

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

[править] Фаза 7

Выполняется компиляция: каждая лексема препроцессора преобразуется в токен. Эти токены анализируются синтаксически и семантически, а затем преобразуются как единицы трансляции.

[править] Фаза 8

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

[править] Фаза 9

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

[править] Примечания

Некоторые компиляторы не реализуют единицы инстанцирования (также известных как репозитории шаблонов или шаблонные регистры) и просто компилируют каждое инстанцирование шаблона в фазе 7, сохраняя код в объектный файл, откуда он явно или неявно запрашивается, а затем компоновщик на этапе 9 сворачивает эти скомпилированные инстанцирования в одно.


[править] Ссылки

  • C++11 standard (ISO/IEC 14882:2011):
  • 2.2 Фазы трансляции [lex.phases]
  • C++98 standard (ISO/IEC 14882:1998):
  • 2.1 Фазы трансляции [lex.phases]

[править] Смотри также

Справка по Cphases of translation