ОСНОВНЫЕ СПЕЦИФИКАЦИИ
Имена обозначают лексемы или нетерминальные символы. yacc требует, чтобы имена лексем были указаны явно. Хотя лексический анализатор можно включить в файл спецификаций, определение его в отдельном файле, вероятно, более соответствует принципам модульного проектирования. Подобно лексическому анализатору, в файл спецификаций могут быть также включены и другие подпрограммы. Таким образом, каждый файл спецификаций теоретически состоит из трех секций: определений, (грамматических) правил и подпрограмм. Секции отделяются двумя знаками процента %% (знак % используется в yacc-спецификациях как универсальный управляющий).
Если используются все секции, полный файл спецификаций выглядит следующим образом:
определения
%% правила
%% подпрограммы
Секции определений и подпрограмм являются необязательными. Минимальная допустимая yacc-спецификация - это
%% правила
Пробелы, табуляции и переводы строки, которые встречаются вне имен и зарезервированных слов, игнорируются. Комментарии могут быть везде, где допустимо имя. Они заключаются в "скобки" /*...*/, как в языке C.
Секция правил составляется из одного или большего числа грамматических правил. Грамматическое правило имеет вид:
нтс : тело ;
где нтс - нетерминальный символ, а тело - последовательность из нуля или нескольких имен и литералов. Двоеточие и точка с запятой - знаки препинания yacc'а.
Имена могут иметь произвольную длину и должны состоять из букв, точек, подчеркиваний и цифр, однако имя не может начинаться с цифры. Прописные и строчные буквы различаются. Имена, используемые в теле грамматического правила, могут представлять лексемы или нетерминальные символы.
Литерал - это знак, заключенный в одиночные кавычки, '. Как и в языке C, в качестве управляющего используется знак \, восприни-маются также все принятые в C управляющие последовательности. Например, yacc трактует перечисленные ниже последовательности следующим образом:
'\n' перевод строки
'\r' возврат каретки
'\'' одинарная кавычка ' '\\' обратная наклонная черта \ '\t' табуляция
'\b' забой
'\f' переход к новой странице
'\xxx' xxx в восьмеричной записи
По ряду технических причин символ NULL (\0 или 0) нельзя использовать в грамматических правилах.
Если есть несколько грамматических правил с одной и той же левой частью, то, чтобы избежать переписывания левой части, можно использовать вертикальную черту, |. Перед вертикальной чертой точку с запятой ставить не нужно. Например, грамматические правила
A : B C D ; A : E F ; A : G ;
с использованием вертикальной черты могут быть заданы для yacc'а в виде
A : B C D | E F | G ;
Не обязательно, чтобы грамматические правила с одной и той же левой частью появлялись в секции правил все вместе, однако такая запись облегчает чтение спецификации и ее модификацию.
Если нетерминал сопоставляется с пустой цепочкой, это можно выразить следующим образом:
epsilon : ;
yacc истолковывает пустое место после двоеточия как нетерминальный символ, называемый epsilon.
Имена, представляющие лексемы, должны быть описаны. Проще всего это сделать, поместив в секции определений конструкцию вида
%token имя1 имя2 ...
Считается, что всякое имя, не описанное в секции определений, представляет нетерминальный символ. Каждый нетерминальный символ должен встретиться в левой части по крайней мере одного правила.
Из всех нетерминальных символов особую роль играет начальный символ. По умолчанию начальным считается символ, стоящий в левой части первого грамматического правила в секции правил. Можно (и желательно) явно объявить начальный символ в секции определений при помощи ключевого слова %start:
%start начальный_символ
О конце входного текста процедуре разбора сигнализирует специальная лексема, называемая маркером конца. Маркер конца представляется нулем или отрицательным числом. Если прочитанные лексемы, исключая маркер конца, образуют конструкцию, сопоставляющуюся с начальным символом, то после того, как найден маркер конца и исходный текст принят, процедура разбора возвращает управление вызвавшей ее процедуре. Если маркер конца встречается в любом другом контексте, это ошибка.
Возвратить, когда следует, маркер конца, - задача определяемого пользователем лексического анализатора. Обычно маркер конца представляет некоторые вполне очевидные состояния ввода/вывода, такие как конец файла или конец записи.