А 12.4. Включение файла
Управляющая строка
# include <имя-файла> заменяется на содержимое файла с именем имя-файла. Среди символов, составляющих имя-файла, не должно быть знака
>
и символа новой строки. Результат не определен, если имя-файла содержит любой из символов "
,
'
,
\
или пару символов
/*
. Порядок поиска указанного файла зависит от реализации.
Подобным же образом выполняется управляющая строка
# include "имя-файла"
Сначала поиск осуществляется по тем же правилам, по каким компилятор ищет первоначальный исходный файл (механизм этого поиска зависит от реализации), а в случае неудачи осуществляется методом поиска, принятым в
#include первого типа. Результат остается неопределенным, если имя файла содержит "
,
\
или
/*
; использование знака
>
разрешается.
Наконец,директива
# include последовательность-лексем
не совпадающая ни с одной из предыдущих форм, рассматривает последовательность лексем как текст, который в результате всех макроподстановок должен дать
#include <...>
или
#include "..."
Сгенерированная таким образом директива далее будет интерпретироваться в соответствии с полученной формой.
Файлы, вставляемые с помощью
#include
, сами могут содержать в себе директивы
#include
А 12.5. Условная компиляция Части программы могут компилироваться условно, если они оформлены в соответствии со следующим схематично изображенным синтаксисом:
условная-конструкция-препроцессора:
if-строка текст elif-части else-частьнеоб #endif if-строка:
# if
константное-выражение # ifdef
идентификатор # ifndef
идентификатор elif-части:
elif-строка текст elif-частинеобelif-строка:
# elif
константное-выражение else-часть:
else-строка текст else-строка:
# else
Каждая из директив (
if-строка,
elif-строка,
else-строка и
#endif
) записывается на отдельной строке.
Константные выражения в
#if и последующих строках
#elif вычисляются по порядку, пока не обнаружится выражение с ненулевым (истинным) значением; текст, следующий за строкой с нулевым значением, выбрасывается. Текст, расположенный за директивой с ненулевым значением, обрабатывается обычным образом. Под словом "текст" здесь имеется в виду любая последовательность строк,
включая строки препроцессора, которые не являются частью условной структуры; текст может быть и пустым. Если строка
#if или
#elif с ненулевым значением выражения найдена и ее текст обработан, то последующие строки
#elif и
#else вместе со своими текстами выбрасываются. Если все выражения имеют нулевые значения и присутствует строка
#else
, то следующий за ней текст обрабатывается обычным образом. Тексты "неактивных" ветвей условных конструкций, за исключением тех, которые заведуют вложенностью условных конструкций, игнорируются.
Константные выражения в
#if и
#elif являются объектами для обычной макроподстановки. Более того, прежде чем просматривать выражения вида defined
идентификатор и defined (
идентификатор)
на предмет наличия в них макровызова, они заменяются на
1L
или
0L
в зависимости от того, был или не был определен препроцессором указанный в них идентификатор. Все идентификаторы, оставшиеся после макрорасширения, заменяются на 0L. Наконец, предполагается, что любая целая константа всегда имеет суффикс
L
, т. е. вся арифметика имеет дело с операндами только типа long или unsigned long
Константное выражение (А7.19) здесь используется с ограничениями: оно
должно быть целочисленным, не может содержать в себе перечислимых констант, преобразований типа и операторов sizeof.
Управляющие строки
#ifdef
идентификатор #ifndef
идентификатор эквивалентны соответственно строкам
# if defined
идентификатор # if ! defined
идентификатор Строки
#еlif не было в первой версии языка, хотя она и использовалась в некоторых препроцессорах. Оператор препроцессора defined
— также новый.
А 12.6. Нумерация строк Для удобства работы с другими препроцессорами, генерирующими Си-программы, можно использовать одну из следующих директив:
# line
константа "
имя-файла"
# line
константа Эти директивы предписывают компилятору считать, что указанные десятичное целое и идентификатор являются номером следующей строки и именем текущего файла соответственно. Если имя файла отсутствует, то ранее запомненное имя не изменяется. Расширения макровызовов в директиве
#line выполняются до интерпретации последней.
А 12.7. Генерация сообщения об ошибке Строка препроцессора вида
# error
последовательность-лексемнеобприказывает ему выдать диагностическое сообщение, включающее заданную последовательность лексем.
А 12.8. Прагма Управляющая строка вида
# pragma последователъностъ-лексемнеоб призывает препроцессор выполнить зависящие от реализации действия. Неопознанная прагма игнорируется.
А 12.9. Пустая директива Строка препроцессора вида
# не вызывает никаких действий.
А 12.10. Заранее определенные имена Препроцессор "понимает" несколько заранее определенных идентификаторов; их он заменяет специальной информацией. Эти идентификаторы (и оператор препроцессора defined в том числе) нельзя повторно переопределять, к ним нельзя также применять директиву
#undef
. Это следующие идентификаторы:
LINE
Номер текущей строки исходного текста, десятичная константа.
FILE
Имя компилируемого файла, строка.
DATE
Дата компиляции в виде "Ммм дд гггг", строка.
TIME
Время компиляции в виде "чч: мм: ее", строка.
STDC
Константа 1. Предполагается, что этот идентификатор определен как 1 только в тех реализациях, которые следуют стандарту.
Строки
#error и
#pragma впервые введены ANSI-стандартом. Заранее определенные макросы
препроцессора также до сих пор не описывались, хотя и использовались в некоторых реализациях.
А 13. Грамматика Ниже приведены грамматические правила, которые мы уже рассматривали в данном приложении. Они имеют то же содержание, но даны в ином порядке.
Здесь не приводятся определения следующих символов-терминов:
целая-константа,
символьная-константа,
константа-с-плавающей-точкой,
идентификатор,
строка и
константа-перечисление. Слова, набранные обычным латинским шрифтом (не курсивом), и знаки рассматриваются как символы-термины и используются точно в том виде, как записаны. Данную грамматику можно механически трансформировать в текст, понятный системе автоматической генерации грамматического распознавателя. Для этого помимо добавления некоторых синтаксических пометок, предназначенных для указания альтернативных продукций, потребуется расшифровка конструкции со словами "один из" и дублирование каждой продукции, использующей символ с индексом
необ., причем один вариант
продукции должен быть написан с этим символом, а другой - без него. С одним изменением, а именно — удалением процукции
typedef-имя: идентификатор и объявлением
typedef-имени символом-термином, данная грамматика будет понятна генератору грамматического распознавателя YАСС. Ей присуще лишь одно противоречие, вызываемое неоднозначностью конструкции if
- else
единица-трансляции:
внешнее-объявление единица-трансляции внешнее-объявление внешнее-объявление:
определение-функции объявление определение-функции:
спецификаторы-объявлениянеоб объявитель список-объявленийнеоб составная-инструщия объявление:
спецификаторы-объявления список-инициализаторов-объявителейнеобсписок-объявлений:
объявление список-объявлений объявление
спецификаторы-объявления:
спецификатор-класса-памяти спецификаторы-объявления
необ
спецификатор-типа спецификаторы-объявления
необ
квалификатор-типа спецификаторы-объявления
необ
спецификатор-класса-памяти: один из auto register static extern typedef
спецификатор-типа: один из void char short int long float double signed unsigned
спецификатор-структуры-или-объединения
спецификатор-перечисления
typedef-имя
квалификатор-типа: один из const volatile
спецификатор-структуры-или-объединения:
структура-или-объединение идентификатор
необ
{ список-объявлений-
структуры }
структура-или-объединение идентификатор
структура-или-объединение: одно из struct union
список-объявлений-структуры:
объявление-структуры
список-объявлений-структуры объявление-структуры
список-объявителей-инициализаторов:
объявитель-инициализатор
список-объявителей-инициализаторов , объявитель-инициализатор
объявитель-инициализатор:
объявитель
объявитель = инициализатор
объявление-структуры:
список-спецификаторов-квалификаторов список-объявителей-структуры
список-спецификаторов-квалификаторов:
спецификатор-типа список-спецификаторов-квалификаторов
необ
квалификатор-типа список-спецификаторов-квалификаторов
необ
список-структуры-объявителей:
структуры-объявитель
список-структуры-объявителей , структуры-объявителъ
структуры-объявитель:
объявитель
объявитель
необ
: константное-выражение
спецификатор-перечисления: enum идентификатор
необ
{ список-перечислителей } enuь идентификатор
список-перечислителей:
перечислитель
список-перечислителей перечислитель
перечислитель:
идентификатор
указатель
необ
собственно-объявитель
собственно-объявитель:
идентификатор
( объявитель )
собственно-объявитель [ константное-выражение
необ
]
собственно-объявитель ( список-типов-параметров )
собственно-объявитель ( список-идентификаторов
необ
)
указатель:
* список-квалификаторов-типа
необ
* список-квалификаторов-типа
необ
указатель
список-квалификаторов-типа:
квалификатор-типа
список-квалификаторов-типа квалификатор-типа
список-типов-параметров:
список-параметров
список-параметров , ...
список-параметров:
объявление-параметра
список-параметров , объявление-параметра
объявление-параметра:
спецификаторы-объявления объявитель
спецификаторы-объявления абстрактный-объявитель
необ
список-идентификаторов:
идентификатор
список-идентификаторов , идентификатор
инициализатор:
выражение-присваивания
{ список-инициализаторов }
{ список-инициализаторов , }
список-инициализаторов:
инициализатор
список-инициализаторов , инициализатор
имя-типа:
список-спецификаторов-квалификаторов абстрактный-объявитель
необ
абстрактный-объявитель:
указатель
указатель
необ
собственно-абстрактный-объявитель
собственно-абстрактный-объявитель:
( абстрактный-объявитель )
собственно-абстрактный-обьявитель
необ
[ константное-выражение
необ
]
собственно-аострактныи-объявитель
необ
( список-типов-параметров
необ
)
typedef-имя:
идентификатор
инструкция:
помеченная-инструкция
инструкция-выражение
составная-инструкция
инструкция-выбора
циклическая-инструкция
инструкция-перехода
помеченная-инструкция:
идентификатор : инструкция case константное-выражение : инструкция default : инструкция
инструкция-выражение:
выражение
необ
;
составная-инструкция:
{ список-объявлений
необ
список-инструкций
необ
}
список-инструкций:
инструкция
список-инструкций инструкция
инструкция-выбора: if ( выражение ) инструкция if ( выражение ) инструкция else инструкция switch ( выражение ) инструкция
циклическая-инструкция: while ( выражение ) инструкция do инструкция while ( выражение ) for ( выражение
необ
; выражение
необ
; выражение
необ
) инструкция
инструкция-перехода: goto идентификатор ; continue ; break ; return выражение
необ
;
выражение:
выражение-присваивания
выражение , выражение-присваивания
выражение-присваивания:
условное-выражение
унарное-выражение оператор-присваивания выражение-присваивания
оператор-присваивания: один из
*=
/=
%=
+=
-=
<<= >>= &=
^=
|=
условное-выражение:
логическое-ИЛИ-выражение
логическое-ИЛИ-выражение ? выражение : условное-выражение
константное-выражение:
условное-выражение
логическое-ИЛИ-выражение:
логическое-И-выражение
логическое-ИЛИ-выражение || логическое-И-выражение
логическое-И-выражение:
ИЛИ-выражение
логическое-И-выражение && ИЛИ-выражение
ИЛИ-выражение:
исключающее-ИЛИ-выражение
ИЛИ-выражение | исключающее-ИЛИ-выражение
исключающее-ИЛИ-выражение:
И-выражение
исключающее-ИЛИ-выражение ^ И-выражение
И-выражение:
выражение-равенства
И-выражение & выражение-равенства
выражение-равенства:
выражение-отношения
выражение-равенства == выражение-отношения
выражение-равенства != выражение-отношения
выражение-отношения:
сдвиговое-выражение
выражение-отношения < сдвиговое-выражение
выражение-отношения > сдвиговое-выражение
выражение-отношения <= сдвиговое-выражение
выражение-отношения >= сдвиговое-выражение
сдвиговое-выражение:
аддитивное-выражение
сдвиговое-выражение >> аддитивное-выражение
сдвиговое-выражение << аддитивное-выражение
аддитивное-выражение:
мультипликативное-выражение
аддитивное-выражение + мультипликативное-выражение
аддитивное-выражение - мультипликативное-выражение
мультипликативное-выражение:
выражение-приведенное-к-типу
мультипликативное-выражение * выражение-приведенное-к-типу
мультипликативное-выражение / выражение-приведенное-к-типу
мулътипликативное-выражение % выражение-приведенное-к-типу
выражение-приведенное-к-типу:
унарное-выражение
( имя-типа ) выражение-приведенное-к-типу
унарное-выражение:
постфиксное-выражение
++ унарное-выражение
-- унарное-выражение
унарный-оператор выражение-приведенное-к-типу
sizeof унарное-выражение sizeof ( имя-типа )
унарный-оператор: один из
&
*
+
-
!
постфиксное-выражение:
первичное-выражение
постфиксное-выражение [ выражение ]
постфиксное-выражение ( список-аргументов-выражений
необ
)
постфиксное-выражение . идентификатор
постфиксное-выражение -> идентификатор
постфиксное-выражение ++
постфиксное-выражение --
первичное-выражение:
идентификатор
константа
строка
( выражение )
список-аргументов-выражений:
выражение-присваивания
список-аргументов-выражений , выражение-присваивания
константа:
целая-константа
символьная-константа
константа-с-плавающей-точкой
константа-перечисление
Ниже приводится грамматика языка препроцессора в виде перечня структур управляющих строк. Для механического получения программы грамматического разбора она не годится. Грамматика включает символ текст, который означает текст обычной программы, безусловные управляющие строки препроцессора и его законченные условные конструкции.
управляющая-строка:
# define идентификатор последовательность-лексем
# define идентификатор ( идентификатор ... идентификатор )
последовательность-лексем
# undef идентификатор
# include <имя-файла>
# include "имя-файла"
# include последовательность-лексем
# line константа "идентификатор"
# line константа
# error последовательность-лексем
необ
# pragma последовательность-лексем
необ
#
условная-конструкция-препроцессора
условная-конструкция-препроцессора: if-строка текст elif-части else-часть
необ
# endif
if-строка:
# if константное-выражение
# ifdef идентификатор
# ifndef идентификатор
elif-части:
elif-строка текст
elif-части
необ
elif-строка:
# elif константное-выражение else-часть: else-строка текст еlsе-строка:
# else