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

GetNum := Value; end;

Достаточно удивительно, что это фактически все необходимые изменения! Локальная переменная Name в процедурах Ident и Assignment были первоначально объявлены как "char" и теперь должны быть объявлены как string[8]. (Ясно, что мы могли бы сделать длину строки больше, если бы захотели, но большинство ассемблеров в любом случае ограничивают длину.) Внесите эти изменения и затем откомпилируйте и протестируйте. Сейчас вы верите, что это просто?

ПРОБЕЛЫ

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

Ключом к облегчению обработки пробелов является введение простого правила для того, как синтаксический анализатор должен обрабатывать входной поток и использование этого правила везде. До настоящего времени, поскольку пробелы не были разрешены, у нас была возможность знать, что после каждого действия синтаксического анализатора предсказывающий символ Look содержит следующий значимый символ, поэтому мы могли немедленно выполнять его проверку. Наш проект был основан на этом принципе.

Это все еще звучит для меня как хорошее правило, поэтому мы будем его использовать. Это означает, что каждая подпрограмма, которая продвигает входной поток, должна пропустить пробелы и оставить следующий символ (не являющийся пробелом) в Look. К счастью, так как мы были осторожны и использовали GetName, GetNum, и Match для большей части обработки входного потока, только эти три процедуры (плюс Init) необходимо изменить.

Неудивительно, что мы начинаем с еще одной подпрограммы распознавания:

{ Recognize White Space }

function IsWhite(c: char): boolean;

begin

IsWhite := c in [ , TAB]; end;

Нам также нужна процедура, "съедающая" символы пробела до тех пор, пока не найдет отличный от пробела символ:

{ Skip Over Leading White Space } procedure SkipWhite;

begin

while IsWhite(Look) do GetChar;

end;

Сейчас добавьте вызовы SkipWhite в Match, GetName и GetNum как показано ниже:



{ Match a Specific Input Character }

procedure Match(x: char);

begin

if Look <> x then Expected( + x + ") else begin

GetChar; SkipWhite; end; end;

{ Get an Identifier } function GetName: string; var Token: string; begin

Token := ;

if not IsAlpha(Look) then Expected(Name); while IsAlNum(Look) do begin

Token := Token + UpCase(Look);

GetChar; end;

GetName := Token; SkipWhite; end;

{ Get a Number } function GetNum: string; var Value: string; begin

Value := ;

if not IsDigit(Look) then Expected(Integer); while IsDigit(Look) do begin Value := Value + Look;

GetChar; end;

GetNum := Value; SkipWhite; end;

(Обратите внимание, как я немного реорганизовал Match без изменения функциональности.)

Наконец, мы должны пропустить начальные пробелы в том месте, где мы "запускаем помпу" в Init:

{ Initialize } procedure Init; begin

GetChar;

SkipWhite; end;

Внесите эти изменения и повторно откомпилируйте программу. Вы обнаружите, что необходимо переместить Match ниже SkipWhite чтобы избежать сообщение об ошибке от компилятора Pascal. Протестируйте программу как всегда, чтобы удостовериться, что она работает правильно.

Поскольку мы сделали довольно много изменений в течение этого урока , ниже я воспроизвожу полный текст синтаксического анализатора:



program parse;

{ Constant Declarations }

const TAB = CR =

{ 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;

{ 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;

{ Recognize an Alphanumeric } function IsAlNum(c: char): boolean; begin

IsAlNum := IsAlpha(c) or IsDigit(c); end;

{ Recognize an Addop }

function IsAddop(c: char): boolean;

begin

IsAddop := c in [+, -]; 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