Spec-Zone.ru › GCC 9 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’, используются для шестнадцатеричных вещественных констант).

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

Числа предварительной обработки могут привести к неправильной интерпретации программ. Например, 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-9.5.0/cpp/Tokenization.html

Spec-Zone.ru

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