Сложности еще не закончились. Если вы не уверены, что все правильно поняли, то вернитесь и перечитайте раздел 6.4 с самого начала. Возможно, при втором чтении вы поймете, о чем идет речь!
6.4.2. Запись грамматики
Как выбираются грамматические правила для разбора указанных выше выражений? Самым честным ответом является “опыт”. Способ, который мы применили, просто повторяет способ, с помощью которого люди обычно записывают грамматики. Однако запись грамматики совершенно очевидна: нам необходимо лишь сделать следующее.
2. Записывать правила одно за другим (последовательно).
3. Выражать альтернативные варианты (разветвление).
4. Выражать повторяющиеся варианты (повторение).
5. Распознавать начальное правило.
В разных учебниках и системах грамматического разбора используются разные соглашения и терминология. Например, иногда лексемы называют
Список:
"{"Последовательность"}"
Последовательность:
Элемент
Элемент "," Последовательность
Элемент:
"A"
"B"
Итак, Последовательность — это Элемент или Элемент, за которым следует разделяющая запятая и другая Последовательность. Элемент — это либо буква A, либо B. Список — это Последовательность в фигурных скобках. Можно сгенерировать следующие Списки (как?):
{A}
{B}
{A,B}
{A,A,A,A,B}
Однако то, что перечислено ниже, списком не является (почему?):
{}
A
{A,A,A,A,B
{A,A,C,A,B}
{A B C}
{A,A,A,A,B,}
Этим правилам вас в детском садике не учили, и в вашем мозге они не “встроены”, но понять их не сложно. Примеры их использования для выражения синтаксических идей можно найти в разделах 7.4 и 7.8.1.
6.5. Превращение грамматики в программу
Существует много способов заставить компьютер следовать грамматическим правилам. Мы используем простейший из них: напишем функцию для каждого грамматического правила, а для представления лексем применим класс Token
. Программу, реализующую грамматику, часто называют программой
6.5.1. Реализация грамматических правил
Для реализации калькулятора нам нужны четыре функции: одна — для считывания лексем и по одной для каждого грамматического правила.
get_token() // считывает символы и составляет лексемы
// использует поток cin
expression() // реализует операции + и –
// вызывает функции term() и get_token()
term() // реализует операции *, / и %
// вызывает функции primary() и get_token()
primary() // реализует числа и скобки
// вызывает функции expression() и get_token()
Что же эти функции должны делать в действительности? Каждая из них должна вызывать другие грамматические функции в соответствии с грамматическим правилом, которое она реализует, а также функцию get_token()
, если в правиле упоминается лексема. Например, когда функция primary()
пытается следовать правилу (Выражение), она должна вызвать следующие функции:
get_token() // чтобы обработать скобки ( и )
expression() // чтобы обработать Выражение