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

program Cradle;

{ Constant Declarations } const TAB =

{ Variable Declarations }

var Look: char; { Lookahead Character }

{ 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 } procedure Expected(s: string); begin

Abort(s + Expected); end;

{ Match a Specific Input Character }

procedure Match(x: char);

begin

if Look = x then GetChar else Expected( + x + ); end;

{ Recognize an Alpha Character } function IsAlpha(c: char): boolean; begin

IsAlpha := upcase(c) in [A..Z]; end;

{ Recognize a Decimal Digit } function IsDigit(c: char): boolean; begin

IsDigit := c in [0..9]; end;



{ Get an Identifier } function GetName: char; begin

if not IsAlpha(Look) then Expected(Name);

GetName := UpCase(Look); GetChar; end;

{ Get a Number } function GetNum: char; begin

if not IsDigit(Look) then Expected(Integer); GetNum := Look; GetChar; end;

{ Output a String with Tab } procedure Emit(s: string); begin

Write(TAB, s); end;

{ Output a String with Tab and CRLF }

procedure EmitLn(s: string);

begin

Emit(s);

WriteLn; end;

{ Initialize } procedure Init; begin

GetChar; end;

{ Main Program } begin Init;

end.

Скопируйте код, представленный выше, в TP и откомпилируйте. Удостоверьтесь, что программа откомпилировалась и запустилась корректно. Затем переходим к первому уроку, синтаксическому анализу выражений.



2. Синтаксический анализ выражений

НАЧАЛО

Если вы прочитали введение, то вы уже в курсе дела. Вы также скопировали программу Cradle в Turbo Pascal и откомпилировали ее. Итак, вы готовы.

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

x = 2*y + 3/(4*z)

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

ОДИНОЧНЫЕ ЦИФРЫ

В соответствии с общей темой этой серии (KISS-принцип, помнишь?), начнем с самого простого случая, который можно себе представить. Это выражение, состоящее из одной цифры.

Перед тем как начать, удостоверьтесь, что у вас есть базовая копия Cradle. Мы будем использовать ее для других экспериментов. Затем добавьте следующие строки:

{ Parse and Translate a Math Expression }

procedure Expression;

begin

EmitLn(MOVE # + GetNum + ,D0) end;

И добавьте строку [Expression; в основную программу, которая должна выглядеть так:

begin Init;

Expression; end.

Теперь запустите программу. Попробуйте ввести любую одиночную цифру. Вы получите результат в виде одной строчки на ассемблере. Затем попробуйте ввести любой другой символ и вы увидите, что синтаксический анализатор правильно сообщает об ошибке.

Поздравляю! Вы только что написали работающий транслятор!

Конечно, я понимаю, что он очень ограничен. Но не отмахивайтесь от него. Этот маленький «компилятор» в ограниченных масштабах делает точно то же, что делает любой большой компилятор: он корректно распознает допустимые утверждения на входном «языке», который мы для него определили, и производит корректный, выполнимый ассемблерный код, пригодный для перевода в объектный формат. И, что важно, корректно распознает недопустимые утверждения, выдавая сообщение об ошибке. Кому требовалось больше?

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



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