Итак, тогда, начав с еще одной копии Cradle, давайте определим процедуру:
{–}
{ Recognize and Translate an «Other» }
procedure Other;
begin
EmitLn(GetName);
end;
{–}
Теперь включим ее вызов в основную программу таким образом:
{–}
{ Main Program }
begin
Init;
Other;
end.
{–}
Запустите программу и посмотрите, что вы получили. Не очень захватывающе, не так ли? Но не зацикливайтесь на этом, это только начало, результат будет лучше.
Первое, что нам нужно – это возможность работать с более чем одним оператором, так как однострочные ветвления довольно ограничены. Мы делали это на последнем занятии по интерпретации, но сейчас давайте будем немного более формальными. Рассмотрите следующую БНФ:
::= END
::= [ ]*
Это означает, что программа определена как блок, завершаемый утверждением END. Блок, в свою очередь, состоит из нуля или более операторов. Пока у нас есть только один вид операторов.
Что является признаком окончания блока? Это просто любая конструкция, не являющаяся оператором «other». Сейчас это только утверждение END.
Вооружившись этими идеями, мы можем приступать к созданию нашего синтаксического анализатора. Код для program (мы должны назвать его DoProgram, иначе Pascal будет ругаться) следующий:
{–}
{ Parse and Translate a Program }
procedure DoProgram;
begin
Block;
if Look <> 'e' then Expected('End');
EmitLn('END')
end;
{–}
Обратите внимание, что я выдаю ассемблеру команду «END», что своего рода расставляет знаки препинания в выходном коде и заставляет чувствовать, что мы анализируем здесь законченную программу.