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.
Константное выражение (A7.19) здесь используется с ограничениями: оно должно быть целочисленным, не может содержать в себе перечислимых констант, преобразований типа и операторов sizeof.
Управляющие строки
#ifdef идентификатор
#ifndef идентификатор
эквивалентны соответственно строкам
#if defined идентификатор
#if !defined идентификатор
Строки #elif не было в первой версии языка, хотя она и использовалась в некоторых препроцессорах. Оператор препроцессора defined - также новый.
A12.6. Нумерация строк
Для удобства работы с другими препроцессорами, генерирующими Си-программы, можно использовать одну из следующих директив:
#line константа "имя-файла"
#line константа
Эти директивы предписывают компилятору считать, что указанные десятичное целое и идентификатор являются номером следующей строки и именем текущего файла соответственно. Если имя файла отсутствует, то ранее запомненное имя не изменяется. Расширения макровызовов в директиве #line выполняются до интерпретации последней.
A12.7. Генерация сообщения об ошибке
Строка препроцессора вида
#error последовательность-лексемнеоб
приказывает ему выдать диагностическое сообщение, включающее заданную последовательность лексем.
A12.8. Прагма
Управляющая строка вида
#pragma последовательность-лексемнеоб
призывает препроцессор выполнить зависящие от реализации действия. Неопознанная прагма игнорируется.
A12.9. Пустая директива
Строка препроцессора вида
#
не вызывает никаких действий.
A12.10. Заранее определенные имена
Препроцессор "понимает" несколько заранее определенных идентификаторов; их он заменяет специальной информацией. Эти идентификаторы (и оператор препроцессора defined в том числе) нельзя повторно переопределять, к ним нельзя также применять директиву #undef. Это следующие идентификаторы:
__LINE__ Номер текущей строки исходного текста, десятичная константа.
__FILE__ Имя компилируемого файла, строка.
__DATE__ Дата компиляции в виде "MMM DD YYYY",строка.
__TIME__ Время компиляции в виде "hh:mm:ss", строка.
__STDC__ Константа 1. Предполагается, что этот идентификатор определен как 1
только в тех реализациях, которые следуют стандарту.
Строки #error и #pragma впервые введены ANSI-стандартом. Заранее определенные макросы препроцессора также до сих пор не описывались, хотя и использовались в некоторых реализациях.
A13. Грамматика
Ниже приведены грамматические правила, которые мы уже рассматривали в данном приложении. Они имеют то же содержание, но даны в ином порядке.
Здесь не приводятся определения следующих символов-терминов: целая-константа, символьная-константа, константа-с-плавающей-точкой, идентификатор, строка и константа-перечисление. Слова, набранные обычным латинским шрифтом (не курсивом), и знаки рассматриваются как символы-термины и используются точно в том виде, как записаны. Данную грамматику можно механически трансформировать в текст, понятный системе автоматической генерации грамматического распознавателя. Для этого помимо добавления некоторых синтаксических пометок, предназначенных для указания альтернативных продукций, потребуется расшифровка конструкции со словами "один из" и дублирование каждой продукции, использующей символ с индексом необ., причем один вариант продукции должен быть написан с этим символом, а другой - без него. С одним изменением, а именно - удалением продукции typedef-имя:идентификатор и объявлением typedef-имени символом-термином, данная грамматика будет понятна генератору грамматического распознавателя YACC. Ей присуще лишь одно противоречие, вызываемое неоднозначностью конструкции if-else.
единица–трансляции:
внешнее-объявление
единица-трансляции внешнее-объявление
внешнее-объявление:
определение-функции
объявление
определение функции: