Spec-Zone.ru › C++

Фазы трансляции

Файл исходного кода C++ обрабатывается компилятором как будто выполняются следующие фазы в точном порядке:

Фаза 1

1) Отдельные байты файла исходного кода отображаются (по определению реализации) на символы основного набора символов исходного текста. В частности, зависящие от ОС маркеры конца строки заменяются символами новой строки. 2) Набор символов исходного файла, которые принимаются, определяется реализацией(с C++11). Любой символ исходного файла, который не может быть отображён на символ основного набора символов исходного текста, заменяется его универсальным именем символа (с экранированием \u или \U) или некоторым определённым реализацией способом, который обрабатывается эквивалентно.
3) Последовательности триграфов заменяются соответствующими односимвольными представлениями. (до C++17)
(до C++23)

Файлы-входы, являющиеся последовательностью единиц кодировки UTF-8 (файлы UTF-8), гарантированно поддерживаются. Набор других типов поддерживаемых файлов-входов определяется реализацией. Если набор не пуст, тип файла-входа определяется реализацией определённым способом, который включает способ обозначения файлов-входов как файлов UTF-8, независимо от их содержимого (распознавание маркера порядка байтов недостаточно).

  • Если файл-вход определяется как файл UTF-8, то он должен быть хорошо сформированной последовательностью единиц кодировки UTF-8, и он декодируется для получения последовательности скалярных значений Unicode. Последовательность элементов набора символов трансляции затем формируется путём сопоставления каждого скалярного значения Unicode с соответствующим элементом набора символов трансляции. В результирующей последовательности каждая пара символов во входной последовательности, состоящая из возврата каретки (U+000D) и переноса строки (U+000A), а также каждый возврат каретки (U+000D), не являющийся непосредственно перед переносом строки (U+000A), заменяется одним символом новой строки.
  • Для любого другого типа файла-входа, поддерживаемого реализацией, символы отображаются (по определению реализации) в последовательность элементов набора символов трансляции. В частности, зависящие от ОС маркеры конца строки заменяются символами новой строки.
(с C++23)

Фаза 2

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

Фаза 3

1) Исходный файл разлагается на комментарии, последовательности символов пробела (пробел, горизонтальная табуляция, новая строка, вертикальная табуляция и перевод страницы) и предпроцессорные токены, которые являются следующими:
a) имена заголовочных файлов, такие как <iostream> или "myfile.h"
b) маркеры-заполнители, созданные предпроцессором директивами импорта и модулей (т.е. import XXX; и module XXX;) (с C++20)
c) идентификаторы
d) предпроцессорные числа
e) символьные литералы, включая пользовательские символьные литералы(с C++11)
f) строковые литералы, включая пользовательские строковые литералы(с C++11)
g) операторы и разделители (включая альтернативные токены), такие как +, <<=, <%, ##, или and
h) отдельные символы, не являющиеся пробелами, которые не подходят ни под какую другую категорию
Программа является некорректной, если символ, соответствующий этой категории,
  • апостроф (', U+0027),
  • кавычка (", U+0022), или
  • символ, не входящий в основной набор символов.
2) Любые преобразования, выполненные во время фазе 1 и(до C++23) фазе 2 между начальной и конечной двойной кавычкой любого сырого строкового литерала отменяются. (с C++11)
3) Каждый комментарий заменяется одним символом пробела.

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

Когда символы из файла исходного кода потребляются для формирования следующего предпроцессорного токена (то есть не потребляемого как часть комментария или других форм пробелов), универсальные имена символов распознаются и заменяются указанным элементом набора символов трансляции, кроме случаев соответствия последовательности символов в:

a) символьном литерале (c-char-sequence) b) строковом литерале (s-char-sequence и r-char-sequence), исключая разделители (d-char-sequence) c) имени файла для включения (h-char-sequence и q-char-sequence)
(с C++23)

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

int foo = 1;
int bar = 0xE+foo;   // error, invalid preprocessing number 0xE+foo
int baz = 0xE + foo; // OK
 
int quux = bar+++++baz; // error: bar++ ++ +baz, not bar++ + ++baz.

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

  • Если следующий символ начинается с последовательности символов, которые могут быть префиксом и начальной двойной кавычкой сырого строкового литерала, следующий предпроцессорный токен должен быть сырым строковым литералом. Литерал состоит из самой короткой последовательности символов, которая соответствует шаблону сырой строки.
#define R "x"
const char* s = R"y"; // ill-formed raw string literal, not "x" "y"
const char* s2 = R"(a)" "b)"; // a raw string literal followed by a normal string literal
  • Если следующие три символа — <:: и последующий символ не является ни : ни >, то < обрабатывается как предпроцессорный токен сам по себе (а не как первый символ альтернативного токена <:).
struct Foo { static const int v = 1; };
std::vector<::Foo> x; // OK, <: not taken as the alternative token for [
extern int y<::>;     // OK, same as extern int y[].
int z<:::Foo::value:>; // OK, int z[::Foo::value];
(с C++11)
  • Токены имени заголовочного файла образуются только внутри #include или import(с C++20) директивы или в __has_include выражении(с C++17).
std::vector<int> x; // OK, <int> not a header-name

Фаза 4

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

Фаза 5

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

Примечание: преобразование, выполняемое на этом этапе, может контролироваться параметрами командной строки в некоторых реализациях: gcc и clang используют -finput-charset для указания кодировки исходной кодовой страницы, -fexec-charset и -fwide-exec-charset для указания обычной и широкой литеральной кодировки соответственно, в то время как Visual Studio 2015 Update 2 и более поздние версии используют /source-charset и /execution-charset для указания исходной кодовой страницы и литеральной кодировки соответственно.

(до C++23)

Для последовательности двух или более смежных строковых литералов общий префикс кодировки определяется, как описано здесь. Каждый такой строковый литерал затем рассматривается как имеющий этот общий префикс кодировки. (Преобразование символов перенесено на этап 3)

(с C++23)

Этап 6

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

Этап 7

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

Этап 8

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

Этап 9

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

Примечания

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

Отчеты об ошибках

Следующие отчеты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применено к Поведение, как опубликовано Корректное поведение
CWG 787 C++98 поведение было неопределенным, если непустой исходный файл не заканчивается символом новой строки в конце этапа 2 добавление завершающего символа новой строки
в этом случае
CWG 1775 C++11 формирование универсального имени символа внутри несырого строкового литерала на этапе 2 приводило к неопределенному поведению сделано определённым
P2621R2 C++98 универсальные имена символов не разрешались для
формирования с помощью слияния строк или конкатенации токенов
разрешено

Ссылки

  • Стандарт C++23 (ISO/IEC 14882:2023):
    • 5.2 Фазы трансляции [lex.phases]
  • Стандарт C++20 (ISO/IEC 14882:2020):
    • 5.2 Фазы трансляции [lex.phases]
  • Стандарт C++17 (ISO/IEC 14882:2017):
    • 5.2 Фазы трансляции [lex.phases]
  • Стандарт C++14 (ISO/IEC 14882:2014):
    • 2.2 Фазы трансляции [lex.phases]
  • Стандарт C++11 (ISO/IEC 14882:2011):
    • 2.2 Фазы трансляции [lex.phases]
  • Стандарт C++03 (ISO/IEC 14882:2003):
    • 2.1 Фазы трансляции [lex.phases]
  • Стандарт C++98 (ISO/IEC 14882:1998):
    • 2.1 Фазы трансляции [lex.phases]

См. также

C документация для Фазы трансляции

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

Spec-Zone.ru

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