Spec-Zone.ru › GCC 5 CPP

1.3 Токенизация

После завершения текстовых преобразований входной файл преобразуется в последовательность токенов предварительной обработки. Они в основном соответствуют синтаксическим токенам, используемым компилятором C, но есть и некоторые различия. Пробелы отделяют токены; сам по себе он не является токеном. Токены не обязательно должны быть разделены пробелами, но часто это необходимо для избежания неоднозначностей.

При столкновении с последовательностью символов, которая допускает более одного возможного разбиения на токены, препроцессор действует жадно. Он всегда делает каждый токен, начиная слева, максимально большим, прежде чем переходить к следующему токену. Например, a+++++b интерпретируется как a ++ ++ + b, а не как a ++ + ++ b, даже если последнее разбиение может быть частью корректной программы на C, а первое — нет.

После того, как входной файл разбит на токены, границы токенов никогда не меняются, за исключением случаев, когда используется оператор предварительной обработки ‘##’ для склеивания токенов. См. Конкатенацию. Например,

#define foo() bar
foo()baz
     → bar baz
not
     → barbaz

Компилятор не повторно разбивает на токены вывод препроцессора. Каждый токен предварительной обработки становится одним токеном компилятора.

Токены предварительной обработки делятся на пять основных категорий: идентификаторы, числовые константы предварительной обработки, строковые литералы, знаки препинания и прочие. Идентификатор такой же, как и в C: любая последовательность букв, цифр или символов подчеркивания, начинающаяся с буквы или символа подчеркивания. Ключевые слова языка C не имеют значения для препроцессора; они являются обычными идентификаторами. Например, можно определить макрос, имя которого является ключевым словом. Единственный идентификатор, который можно считать ключевым словом препроцессора, это defined. См. Определено.

Это в основном справедливо и для других языков, использующих препроцессор C. Однако некоторые ключевые слова C++ имеют значение даже в препроцессоре. См. Именованные операторы C++.

В стандарте C 1999 года идентификаторы могут содержать буквы, которые не входят в «основной набор символов исходного кода», по усмотрению реализации (например, буквы с диакритическими знаками, греческие буквы или китайские иероглифы). Это может быть сделано с использованием расширенного набора символов или с помощью escape-последовательностей ‘\u’ и ‘\U’. GCC принимает такие символы только в форматах ‘\u’ и ‘\U’.

В качестве расширения, GCC обрабатывает ‘$’ как букву. Это сделано для совместимости с некоторыми системами, такими как VMS, где ‘$’ обычно используется в именах системных функций и объектов. ‘$’ не является буквой в строго конформном режиме или при указании опции -$. См. Вызов.

Числовая константа предварительной обработки имеет довольно странное определение. Эта категория включает все обычные целые и вещественные константы, ожидаемые в C, а также ряд других элементов, которые изначально могут не восприниматься как числа. Формально, числовые константы предварительной обработки начинаются с необязательной точки, обязательной десятичной цифры, а затем продолжаются любой последовательностью букв, цифр, символов подчеркивания, точек и экспоненциальных обозначений. Экспоненциальные обозначения — это двухсимвольные последовательности ‘e+’, ‘e-’, ‘E+’, ‘E-’, ‘p+’, ‘p-’, ‘P+’, и ‘P-’. (Экспоненциальные обозначения, начинающиеся с ‘p’ или ‘P’, являются новыми в C99. Они используются для шестнадцатеричных вещественных констант.)

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

Числовые константы предварительной обработки могут привести к неправильной интерпретации программ. Например, 0xE+12 — это числовая константа предварительной обработки, которая не переводится ни в одну корректную числовую константу, поэтому это синтаксическая ошибка. Это не означает 0xE + 12, что вы, возможно, имели в виду.

Строковые литералы — это строковые константы, символьные константы и имена файлов заголовков (аргумент ‘#include’).2 Строковые константы и символьные константы просты: "…" или '…'. В обоих случаях вложенные кавычки должны экранироваться обратной косой чертой: '\'' — это символьная константа для ‘'’. Длина символьной константы не ограничена, но значение символьной константы, содержащей более одного символа, определяется реализацией. См. Детали реализации.

Имена файлов заголовков либо похожи на строковые константы, "…", либо записываются с использованием угловых скобок вместо них, <…>. В обоих случаях обратная косая черта является обычным символом. Нет способа экранировать закрывающую кавычку или угловую скобку. Препроцессор ищет файл заголовка в разных местах, в зависимости от используемого вами формата. См. Операцию включения.

Ни один строковый литерал не может выходить за пределы строки. Более ранние версии GCC принимали многострочные строковые константы. Вместо этого можно использовать продолженные строки или конкатенацию строковых констант. См. Отличия от предыдущих версий.

Знаки препинания — это все обычные знаки препинания, имеющие значение для C и C++. Все знаки препинания в ASCII, кроме трех, являются знаками препинания C. Исключениями являются ‘@’, ‘$’, и ‘`’. Кроме того, все двух- и трехсимвольные операторы являются знаками препинания. Также существует шесть диграфов, которые стандарт C++ называет альтернативными токенами, которые просто представляют собой альтернативные способы написания других знаков препинания. Это вторая попытка обойти отсутствие знаков препинания в устаревших системах. Она не имеет негативных побочных эффектов, в отличие от триграфов, но не охватывает такой же объем. Диграфы и соответствующие им знаки препинания:

Digraph:        <%  %>  <:  :>  %:  %:%:
Punctuator:      {   }   [   ]   #    ##

Любой другой одиночный символ считается «прочим». Он передаётся на вывод препроцессора без изменений. Компилятор C почти наверняка отклонит исходный код, содержащий токены «прочие». В ASCII единственными другими символами являются ‘@’, ‘$’, ‘`’, и управляющие символы, отличные от NUL (все биты равны нулю). (Обратите внимание, что ‘$’ обычно рассматривается как буква.) Все символы с установленным старшим битом (числовой диапазон 0x7F–0xFF) также являются «прочими» в данной реализации. Это изменится, когда в GCC будет добавлена надлежащая поддержка международных наборов символов.

NUL — это особый случай из-за высокой вероятности того, что его появление является случайным, и потому что он может быть невидим для пользователя (многие терминалы вообще не отображают NUL). Внутри комментариев NUL игнорируются без звука, как и любой другой символ. В обычном тексте NUL считается пробелом. Например, эти две директивы имеют одинаковый смысл.

#define X^@1
#define X 1

(где ‘^@’ — это ASCII NUL). Внутри строковых или символьных констант NUL сохраняются. В последних двух случаях препроцессор выводит сообщение об ошибке.

Примечания

(2)

Стандарт C использует термин строковый литерал, чтобы обозначить только то, что мы называем строковой константой.

Далее: Язык предварительной обработки, Предыдущий: Начальная обработка, Наверх: Обзор [Содержание][Индекс]

© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-5.5.0/cpp/Tokenization.html

Spec-Zone.ru

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