Spec-Zone.ru › GCC 4 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’, и только если -fextended-identifiers используется.

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

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

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

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

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

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

Ни один строковый литерал не может выходить за пределы строки. Более старые версии 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 сохраняются. В последних двух случаях препроцессор выводит сообщение об ошибке.

Примечания

[1] В стандарте C термин «строковый литерал» используется только для обозначения того, что мы называем строковыми константами.

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

Spec-Zone.ru

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