|
ВВЕДЕНИЕ В четырех первых главах этой
серии мы сконцентрировали свое внимание на синтаксическом анализе математических
выражений и операций присваивания. В этой главе мы остановимся на новой
и захватывающей теме: синтаксическом анализе и трансляции управляющих конструкций
таких как, например, операторы IF.
ПЛАН Далее мы снова начнем с пустого
Cradle и, как мы делали уже дважды до этого, будем строить программу последовательно.
Мы также сохраним концепцию односимвольных токенов, которая так хорошо
служила нам до настоящего времени. Это означает, что "код" будет выглядеть
немного забавным с "i" вместо IF, "w" вместо WHILE и т.д. Но это поможет
нам узнать основные понятия не беспокоясь о лексическом анализе.
Не бойтесь... в конечном счете мы увидим что-то похожее на "настоящий" код.
{--------------------------------------------------------------}
procedure Other;
Теперь включим ее вызов в основную программу таким образом: {--------------------------------------------------------------}
begin
Запустите программу и посмотрите,
что вы получили. Не очень захватывающе, не так ли? Но не зацикливайтесь
на этом, это только начало, результат будет лучше.
<program> ::= <block> END <block> ::= [ <statement> ]* Это означает, что программа определена
как блок, завершаемый утверждением END. Блок, в свою очередь, состоит из
нуля или более операторов. Пока у нас есть только один вид операторов.
{--------------------------------------------------------------}
procedure DoProgram;
Обратите внимание, что я выдаю
ассемблеру команду "END", что своего рода расставляет знаки препинания
в выходном коде и заставляет чувствовать, что мы анализируем здесь законченную
программу.
{--------------------------------------------------------------}
procedure Block;
(Из формы процедуры вы видите, что мы собираемся постепенно
ее расширять!)
НЕМНОГО ОСНОВ Прежде чем мы начнем определять различные управляющие конструкции, мы должны положить немного более прочное основание. Во-первых, предупреждаю: я не буду использовать для этих конструкций тот же самый синтаксис с которым вы знакомы по Паскалю или Си. К примеру синтаксис Паскаль для IF такой: IF <condition> THEN <statement> (где <statement>, конечно, может быть составным.)
IF ( <condition> ) <statement> Вместо этого я буду использовать нечто более похожее на Ada: IF <condition> <block> ENDIF Другими словами, конструкция IF имеет специфический символ
завершения. Это позволит избежать висячих else Паскаля и Си и также предотвращает
необходимость использовать скобки {} или begin-end. Синтаксис, который
я вам здесь показываю, фактически является синтаксисом языка KISS, который
я буду детализировать в следующих главах. Другие конструкции также будут
немного отличаться. Это не должно быть для вас большой проблемой. Как только
вы увидите, как это делается, вы поймете, что в действительности не имеет
большого значения, какой конкретный синтаксис используется. Как только
синтаксис определен, включить его в код достаточно просто.
IF <condition> A ENDIF B... должен быть переведен в:
Если условие не выполнено то переход на L
Ясно, что нам понадобятся несколько
процедур, которые помогут нам работать с этими переходами. Ниже я определил
две из них. Процедура NewLabel генерирует уникальные метки. Это сделано
с помощью простого способа называть каждую метку 'Lnn', где nn - это номер
метки, начинающийся с нуля. Процедура PostLabel просто выводит метки в
соответствующем месте.
{--------------------------------------------------------------}
function NewLabel: string;
{--------------------------------------------------------------}
procedure PostLabel(L: string);
Заметьте, что мы добавили новую глобальную переменную LCount, так что вы должны изменить раздел описания переменных в начале программы, следующим образом: var Look : char;
{ Lookahead Character }
Также добавьте следующий дополнительный инициализирующий код в Init: LCount := 0; (Не забудьте сделать это, иначе ваши метки будут выглядеть
действительно странными!).
IF: Сначала получить условие
и выдать код для него. Затем создать уникальную метку и выдать переход
если условие ложно.
Эти действия могут быть показаны очень кратко, если мы запишем синтаксис таким образом: IF
Это пример синтаксически-управляемого
перевода. Мы уже делали все это... мы просто никогда прежде не записывали
это таким образом. Содержимое фигурных скобок представляет собой действия,
которые будут выполняться. Хорошо в этом способе представления то, что
он не только показывает что мы должны распознать, но также и действия,
которые мы должны выполнить и в каком порядке. Как только мы получаем такой
синтаксис, код возникает почти сам собой.
|