Выбрать главу

    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.

единица–трансляции:

    внешнее-объявление

    единица-трансляции внешнее-объявление

внешнее-объявление:

    определение-функции

    объявление

определение функции: