Анимация
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

Не забудьте, что новая версия Scan не продвигает входной поток, она только сканирует ключевые слова. Входной поток должен продвигаться каждой процедурой, которую вызывает Block.

В общих чертах, мы должны заменить каждую проверку Look на аналогичную проверку Token. Например:

{ Parse and Translate a Boolean Expression }

procedure BoolExpression;

begin

BoolTerm;

while IsOrOp(Token) do begin Push;

case Token of l: BoolOr;

BoolXor;

end; end; end;

В процедурах типа Add мы больше не должны использовать Match. Нам необходимо только вызывать Next для продвижения входного потока:

{ Recognize and Translate an Add }

procedure Add;

begin

Next;

Term;

PopAdd; end;

Управляющие структуры фактически более простые. Мы просто вызываем Next для продвижения через ключевые слова управляющих конструкций:

{ Recognize and Translate an IF Construct } procedure Block; Forward; procedure DoIf; var L1, L2: string; begin Next;

BoolExpression; L1 := NewLabel; L2 := L1; BranchFalse(L1); Block;

if Token = Ч then begin

Next;

L2 := NewLabel; Branch(L2); PostLabel(L1); Block;

end;

PostLabel(L2);

MatchString(ENDIF); end;



Это все необходимые изменения. В листинге Tiny Version 1.1, данном ниже, я также сделал ряд других "усовершенствований", которые в действительности не нужны. Позвольте мне кратко разъяснить их:

1. Я удалил две процедуры Prog и Main и объединил их функции в основной программе. Они кажется не добавляли ясности... фактически они просто немного загрязняли программу.

2. Я удалил ключевые слова PROGRAM и BEGIN из списка ключевых слов. Каждое из них появляется в одном месте, так что нет необходимости искать его.

3. Обжегшись однажды на чрезмерной дозе сообразительности, я напомнил себе, что TINY предназначен быть минималистским языком. Поэтому я заменил причудливую обработку унарного минуса на самую простую какую мог придумать. Гигантский шаг назад в качестве кода, но огромное упрощение компилятора. Для использования другой версии правильным местом был бы KISS.

4. Я добавил несколько подпрограмм проверок ошибок типа CheckTable и CheckDup и заменил встроенный код на их вызовы. Это навело порядок во многих подпрограммах.

5. Я убрал проверку ошибок из подпрограмм генерации кода типа Store и поместил их в подпрограммы анализа, к которым они относятся. Смотрите например Assignment.

6. Существовала ошибка в InTable и Locate которая заставляла их проверять все позиции вместо позиций только с достоверными данными. Теперь они проверяют только допустимые ячейки. Это позволяет нам устранить необходимость инициализации таблицы идентификаторов, которая была в Init.

7. Процедура AddEntry теперь имеет два параметра, что помогает сделать программу немного более модульной.

8. Я подчистил код для операторов отношений добавив новые процедуры CompareExpression и NextExpression.

9. Я устранил ошибку в подпрограмме Read... старая версия не выполняла проверку на правильность имени переменной.

ЗАКЛЮЧЕНИЕ

Полученный компилятор Tiny показан ниже. Не считая удаленного ключевого слова PROGRAM он анализирует тот же самый язык что и раньше. Он просто немного чище и, что более важно, значительно более надежный. Он мне нравится.

В следующей главе будет другое отклонение: сперва обсуждение точек с запятой и все, что привело меня такому беспорядку. Затем мы займемся процедурами и типами. Добавление этих возможностей далеко продвинет нас на пути к выведению KISS из категории "игрушечных языков". Мы подобрались очень близко к возможности написать серъезный компилятор.



TINY VERSION 1.1

program Tiny11;

{ Constant Declarations }

const TAB =

CR = *M; LF =

LCount: integer = 0; NEntry: integer = 0;

{ Type Declarations } type Symbol = string[8];

SymTab = array[1..1000] of Symbol;

TabPtr = SymTab;

{ Variable Declarations }

var Look : char; { Lookahead Character }

Token: char; { Encoded Token }

Value: string[16]; { Unencoded Token

const MaxEntry = 100;

var ST : array[1..MaxEntry] of Symbol; SType: array[1..MaxEntry] of char;

{ Definition of Keywords and Token Types } const NKW = 9;

NKW1 = 10;

const KWlist: array[1..NKW] of Symbol =

(IF, ELSE, ENDIF, WHILE, ENDWHILE, READ, WRITE, VAR, END); const KWcode: string[NKW1] = xileweRWve;

{ Read New Character From Input Stream }

procedure GetChar;

begin

Read(Look); end;

{ Report an Error } procedure Error(s: string); begin

WriteLn;

WriteLn(*G, Error: , s, .); end;

{ Report Error and Halt } procedure Abort(s: string); begin

Error(s);

Halt;

end;

{ Report What Was Expected }



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