Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 [ 48 ] 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97

BoolExpression; Ll := NewLabel; L2 := Ll;

BranchFalse(Ll); Block;

if Token = l then begin

L2 := NewLabel; Branch(L2); PostLabel(Ll); Block; end;

PostLabel(L2);

MatchString(ENDIF); end;

{ Parse and Translate a WHILE Statement } procedure DoWhile; var Ll, L2: string; begin

Ll := NewLabel;

L2 := NewLabel;

PostLabel(Ll);

BoolExpression;

BranchFalse(L2);

Block;

MatchString(ENDWHILE); Branch(Ll); PostLabel(L2); end;

{ Parse and Translate a Block of Statements } procedure Block; begin Scan;

while not(Token in [e, l]) do begin case Token of

i: DoIf; w: DoWhile; else Assignment; end; Scan; end; end;

{ Parse and Translate Global Declarations } procedure TopDecls; begin Scan;

while Token <> b do begin case Token of v: Decl;

else Abort(Unrecognized Keyword + Value); end; Scan; end; end;

{ Parse and Translate a Main Program }

procedure Main;

begin



MatchString(BEGIN); Prolog;

Block;

MatchString(END); Epilog; end;

{ Parse and Translate a Program }

procedure Prog;

begin

MatchString(PROGRAM);

Header;

TopDecls;

Main;

Match(.); end;

{ Initialize } procedure Init; var i: char; begin

for i := A to Z do ST[i] := ;

GetChar; Scan; end;

Это должно работать. Если все изменения сделаны правильно, вы должны теперь анализировать программы, которые выглядят как программы. (Если вы не сделали всех изменений, не отчаивайтесь. Полный листинг конечной формы дан ниже.)

Работает? Если да, то мы почти дома. Фактически, с несколькими небольшими исключениями, мы уже получили компилятор, пригодный для использования. Имеются еще несколько областей, требующих усовершенствования.

МНОГОСИМВОЛЬНЫЕ ИМЕНА ПЕРЕМЕННЫХ

Одна из них - ограничение, требующее использования односимвольных имен переменных. Теперь, когда мы можем обрабатывать многосимвольные ключевые слова, это ограничение начинает казаться произвольным и ненужным. И действительно это так. В основном, единственное его достоинство в том, что он позволяет получить тривиально простую реализацию таблицы идентификаторов. Но это просто удобство для создателей компиляторов и оно должно быть уничтожено.

Мы уже делали этот шаг прежде. На этот раз, как обычно, я сделаю это немного по-другому. Я думаю подход, примененный здесь, сохранит простоту настолько, насколько это возможно.

Естественным путем реализации таблицы идентификаторов на Pascal является объявление переменной типа запись и создание таблицы идентификаторов как массива таких записей. Здесь, однако, нам в действительности пока не нужно поле типа (существует пока что только один разрешенный тип), так что нам нужен только массив символов. Это имеет свое преимущество, потому что мы можем использовать существующую процедуру Lookup для поиска в таблице идентификаторов также как и в списке ключевых слов. Оказывается, даже когда нам нужны больше полей, мы все равно можем использовать тот же самый подход, просто сохраняя другие поля в отдельных



массивах.

Вот изменения, которые необходимо сделать. Сперва добавьте новую типизированную константу: NEntry: integer = 0;

Затем измените определение таблицы идентификаторов как показано ниже: const MaxEntry = 1 00; var ST : array[1 ..MaxEntry] of Symbol;

(Обратите внимание, что ST не объявлен как SymTab. Это объявление липовое, чтобы заставить Lookup работать. SymTab заняля бы слишком много памяти и поэтому фактически никогда не обьявляется).

Затем мы должны заменить InTable.

{ Look for Symbol in Table } function InTable(n: Symbol): Boolean; begin

InTable := Lookup(®ST, n, MaxEntry) <> 0; end;

Нам также необходима новая процедура AddEntry, которая добавляет новый элемент в таблицу:

{ Add a New Entry to Symbol Table } procedure AddEntry(N: Symbol; T: char); begin

if InTable(N) then Abort(Duplicate Identifier + N); if NEntry = MaxEntry then Abort(Symbol Table Full); Inc(NEntry); ST[NEntry] := N; SType[NEntry] := T; end;

Эта процедура вызывается из Alloc:

{ Allocate Storage for a Variable } procedure Alloc(N: Symbol); begin

if InTable(N) then Abort(Duplicate Variable Name + N); AddEntry(N, v);

Наконец, мы должны изменить все подпрограммы, которые в настоящее время обрабатывают имена переменных как одиночный символ. Они включают LoadVar и Store (просто измените тип с char на string) и Factor, Assignment и Decl (просто измените Value[1 ] на Value).

Последняя вещь: измените процедуру Init для очистки массива как показано ниже:

{ Initialize } procedure Init; var i: integer; begin

for i := l to MaxEntry do begin

ST[i] := "; SType[i] := ;

end;

GetChar; Scan; end;



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 [ 48 ] 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97