Spec-Zone.ru › GCC 6 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-6.5.0/cpp/Tokenization.html

Spec-Zone.ru

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