ВВЕДЕНИЕ У меня есть хорошие и плохие
новости. Плохие новости - эта глава не та, которую я вам обещал последний
раз. Более того, и следующая глава также.
ПРЕДПОСЫЛКА Если вы помните, мы подробно
говорили на тему лексических анализаторов в Главе 7 и я оставил вас с проектом
распределенного сканера который, я чувствовал, был почти настолько простым,
насколько я cмог сделать... более чем большинство из того, что я где-либо
видел. Мы использовали эту идею в Главе 10. Полученная структура компилятора
была простой и она делала свою работу.
ПРОБЛЕМА Проблема начинает проявлять себя в процедуре Block, которую я воспроизвел ниже: {--------------------------------------------------------------}
procedure Block;
Как вы можете видеть, Block ориентирован
на индивидуальные утверждения программы. При каждом проходе цикла мы знаем,
что мы находимся в начале утверждения. Мы выходим из блока когда обнаруживаем
END или ELSE.
РЕШЕНИЕ Давайте начнем решение проблемы с пересмотра двух процедуры: {--------------------------------------------------------------}
procedure GetName;
{--------------------------------------------------------------}
procedure GetNum;
Эти две процедуры функционально
почти идентичны тем, которые я показал вам в Главе 7. Каждая из них выбирает
текущий токен, или идентификатор или число, в глобальную строковую переменную
Value. Они также присваивают кодированной версии, Token, соответствующий
код. Входной поток останавливается на Look, содержащем первый символ, не
являющийся частью токена.
{--------------------------------------------------------------}
procedure GetOp;
Обратите внимание, что GetOps
возвращает в качестве закодированного токена первый символ оператора. Это
важно, потому что это означает, что теперь мы можем использовать этот одиночный
символ для управления синтаксическим анализатором вместо предсказывающего
символа.
{--------------------------------------------------------------}
procedure Next;
Обратите внимание, что здесь
я поместил SkipWhite перед вызовами а не после. Это означает в основном,
что переменная Look не будет содержать значимого значения и, следовательно,
мы не должны использовать ее как тестируемое значение при синтаксическом
анализе, как мы делали до этого. Это большое отклонение от нашего нормального
подхода.
{--------------------------------------------------------------}
function IsWhite(c: char): boolean;
Мы уже пробовали аналогичные подпрограммы в Главе 7, но вы могли бы также попробовать и эти. Добавьте их к копии Cradle и вызовите Next в основной программе: {--------------------------------------------------------------}
begin
Откомпилируйте и проверьте, что
вы можете разделять программу на серии токенов и вы получаете правильные
кода для каждого токена.
{--------------------------------------------------------------}
procedure GetOp;
Обратите внимание, что я все
еще присваиваю Value значение. Если вас действительно затрагивает эффективность,
вы могли бы это опустить. Когда мы ожидаем оператор, мы в любом случае
будем проверять только Token, так что значение этой строки не будет иметь
значение. Но мне кажется хорошая практика дать ей значение на всякий случай.
{--------------------------------------------------------------}
procedure Scan;
Последняя деталь. В компиляторе
есть несколько мест, в которых мы должны фактически проверить строковое
значение токена. В основном это сделано для того, чтобы различать разные
END, но есть и пара других мест. (Я должен заметить, между прочим, что
мы могли бы навсегда устранить потребность в сравнении символов END кодируя
каждый из них различными символами. Прямо сейчас мы определенно идем маршрутом
ленивого человека.)
{--------------------------------------------------------------}
procedure MatchString(x: string);
ИСПРАВЛЕНИЕ КОМПИЛЯТОРА Вооружившись этими новыми процедурами
лексического анализа мы можем теперь начать исправлять компилятор. Изменения
весьма незначительные, но есть довольно много мест, где они необходимы.
Вместо того, чтобы показывать вам каждое место я дам вам общую идею а затем
просто покажу готовый продукт.
{--------------------------------------------------------------}
procedure Block;
Не забудьте, что новая версия
Scan не продвигает входной поток, она только сканирует ключевые слова.
Входной поток должен продвигаться каждой процедурой, которую вызывает Block.
{---------------------------------------------------------------}
procedure BoolExpression;
В процедурах типа Add мы больше не должны использовать Match. Нам необходимо только вызывать Next для продвижения входного потока: {--------------------------------------------------------------}
procedure Add;
Управляющие структуры фактически более простые. Мы просто вызываем Next для продвижения через ключевые слова управляющих конструкций: {---------------------------------------------------------------}
procedure Block; Forward; procedure DoIf;
Это все необходимые изменения. В листинге Tiny Version 1.1, данном ниже, я также сделал ряд других "усовершенствований", которые в действительности не нужны. Позвольте мне кратко разъяснить их: 1. Я удалил две процедуры Prog и Main и объединил их функции
в основной программе. Они кажется не добавляли ясности... фактически они
просто немного загрязняли программу.
ЗАКЛЮЧЕНИЕ Полученный компилятор Tiny показан
ниже. Не считая удаленного ключевого слова PROGRAM он анализирует тот же
самый язык что и раньше. Он просто немного чище и, что более важно, значительно
более надежный. Он мне нравится.
TINY VERSION 1.1
{--------------------------------------------------------------}
{--------------------------------------------------------------}
const TAB = ^I;
LCount: integer = 0;
{--------------------------------------------------------------}
type Symbol = string[8]; SymTab = array[1..1000] of Symbol; TabPtr = ^SymTab;
{--------------------------------------------------------------}
var Look : char;
{ Lookahead Character }
const MaxEntry = 100; var ST : array[1..MaxEntry] of Symbol;
{--------------------------------------------------------------}
const NKW = 9;
const KWlist: array[1..NKW] of Symbol =
const KWcode: string[NKW1] = 'xileweRWve';
{--------------------------------------------------------------}
procedure GetChar;
{--------------------------------------------------------------}
procedure Error(s: string);
{--------------------------------------------------------------}
procedure Abort(s: string);
{--------------------------------------------------------------}
procedure Expected(s: string);
{--------------------------------------------------------------}
procedure Undefined(n: string);
{--------------------------------------------------------------}
procedure Duplicate(n: string);
{--------------------------------------------------------------}
procedure CheckIdent;
{--------------------------------------------------------------}
function IsAlpha(c: char): boolean;
{--------------------------------------------------------------}
function IsDigit(c: char): boolean;
{--------------------------------------------------------------}
function IsAlNum(c: char): boolean;
{--------------------------------------------------------------}
function IsAddop(c: char): boolean;
{--------------------------------------------------------------}
function IsMulop(c: char): boolean;
{--------------------------------------------------------------}
function IsOrop(c: char): boolean;
{--------------------------------------------------------------}
function IsRelop(c: char): boolean;
{--------------------------------------------------------------}
function IsWhite(c: char): boolean;
{--------------------------------------------------------------}
procedure SkipWhite;
{--------------------------------------------------------------}
function Lookup(T: TabPtr; s: string; n: integer): integer;
{--------------------------------------------------------------}
function Locate(N: Symbol): integer;
{--------------------------------------------------------------}
function InTable(n: Symbol): Boolean;
{--------------------------------------------------------------}
procedure CheckTable(N: Symbol);
{--------------------------------------------------------------}
procedure CheckDup(N: Symbol);
{--------------------------------------------------------------}
procedure AddEntry(N: Symbol; T: char);
{--------------------------------------------------------------}
procedure GetName;
{--------------------------------------------------------------}
procedure GetNum;
{--------------------------------------------------------------}
procedure GetOp;
{--------------------------------------------------------------}
procedure Next;
{--------------------------------------------------------------}
procedure Scan;
{--------------------------------------------------------------}
procedure MatchString(x: string);
{--------------------------------------------------------------}
procedure Emit(s: string);
{--------------------------------------------------------------}
procedure EmitLn(s: string);
{--------------------------------------------------------------}
function NewLabel: string;
{--------------------------------------------------------------}
procedure PostLabel(L: string);
{---------------------------------------------------------------}
procedure Clear;
{---------------------------------------------------------------}
procedure Negate;
{---------------------------------------------------------------}
procedure NotIt;
{---------------------------------------------------------------}
procedure LoadConst(n: string);
{---------------------------------------------------------------}
procedure LoadVar(Name: string);
{---------------------------------------------------------------}
procedure Push;
{---------------------------------------------------------------}
procedure PopAdd;
{---------------------------------------------------------------}
procedure PopSub;
{---------------------------------------------------------------}
procedure PopMul;
{---------------------------------------------------------------}
procedure PopDiv;
{---------------------------------------------------------------}
procedure PopAnd;
{---------------------------------------------------------------}
procedure PopOr;
{---------------------------------------------------------------}
procedure PopXor;
{---------------------------------------------------------------}
procedure PopCompare;
{---------------------------------------------------------------}
procedure SetEqual;
{---------------------------------------------------------------}
procedure SetNEqual;
{---------------------------------------------------------------}
procedure SetGreater;
{---------------------------------------------------------------}
procedure SetLess;
{---------------------------------------------------------------}
procedure SetLessOrEqual;
{---------------------------------------------------------------}
procedure SetGreaterOrEqual;
{---------------------------------------------------------------}
procedure Store(Name: string);
{---------------------------------------------------------------}
procedure Branch(L: string);
{---------------------------------------------------------------}
procedure BranchFalse(L: string);
{---------------------------------------------------------------}
procedure ReadIt(Name: string);
{ Write from Primary Register } procedure WriteIt;
{--------------------------------------------------------------}
procedure Header;
{--------------------------------------------------------------}
procedure Prolog;
{--------------------------------------------------------------}
procedure Epilog;
{---------------------------------------------------------------}
procedure Allocate(Name, Val: string);
{---------------------------------------------------------------}
procedure BoolExpression; Forward; procedure Factor;
{--------------------------------------------------------------}
procedure Multiply;
{-------------------------------------------------------------}
procedure Divide;
{---------------------------------------------------------------}
procedure Term;
{--------------------------------------------------------------}
procedure Add;
{-------------------------------------------------------------}
procedure Subtract;
{---------------------------------------------------------------}
procedure Expression;
{---------------------------------------------------------------}
procedure CompareExpression;
{---------------------------------------------------------------}
procedure NextExpression;
{---------------------------------------------------------------}
procedure Equal;
{---------------------------------------------------------------}
procedure LessOrEqual;
{---------------------------------------------------------------}
procedure NotEqual;
{---------------------------------------------------------------}
procedure Less;
{---------------------------------------------------------------}
procedure Greater;
{---------------------------------------------------------------}
procedure Relation;
{---------------------------------------------------------------}
procedure NotFactor;
{---------------------------------------------------------------}
procedure BoolTerm;
{--------------------------------------------------------------}
procedure BoolOr;
{--------------------------------------------------------------}
procedure BoolXor;
{---------------------------------------------------------------}
procedure BoolExpression;
{--------------------------------------------------------------}
procedure Assignment;
{---------------------------------------------------------------}
procedure Block; Forward; procedure DoIf;
{--------------------------------------------------------------}
procedure DoWhile;
{--------------------------------------------------------------}
procedure ReadVar;
{--------------------------------------------------------------}
procedure DoRead;
{--------------------------------------------------------------}
procedure DoWrite;
{--------------------------------------------------------------}
procedure Block;
{--------------------------------------------------------------}
procedure Alloc;
{--------------------------------------------------------------}
procedure TopDecls;
{--------------------------------------------------------------}
procedure Init;
{--------------------------------------------------------------}
begin
|