Spec-Zone.ru › GCC 8 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 года идентификаторы могут содержать буквы, не входящие в «основной набор символов исходного текста», по усмотрению реализации (например, акцентированные латинские буквы, греческие буквы или китайские иероглифы). Это может быть сделано с расширенным набором символов или с помощью управляющих последовательностей «\u» и «\U». GCC принимает такие символы только в форматах «\u» и «\U».

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

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

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

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

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

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

Ни один строковый литерал не может выходить за пределы строки. Вместо этого можно использовать продолжение строк или конкатенацию строковых констант.

Знаки препинания — это все обычные знаки препинания, имеющие значение для 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-8.5.0/cpp/Tokenization.html

Spec-Zone.ru

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