Анимация
JavaScript
|
Главная Библионтека Не забудьте, что новая версия 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 |