Лекции по построению компилятора на Pascal

       

МНОГОСИМВОЛЬНЫЕ ИМЕНА ПЕРЕМЕННЫХ


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

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

Естественным путем реализации таблицы идентификаторов на Pascal является объявление переменной типа запись и создание таблицы идентификаторов как массива таких записей. Здесь, однако, нам в действительности пока не нужно поле типа (существует пока что только один разрешенный тип), так что нам нужен только массив символов. Это имеет свое преимущество, потому что мы можем использовать существующую процедуру Lookup для поиска в таблице идентификаторов также как и в списке ключевых слов. Оказывается, даже когда нам нужны больше полей, мы все равно можем использовать тот же самый подход, просто сохраняя другие поля в отдельных массивах.

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

NEntry: integer = 0;

Затем измените определение таблицы идентификаторов как показано ниже:

const MaxEntry = 100;

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

 (Обратите внимание, что ST не объявлен как SymTab. Это объявление липовое, чтобы заставить Lookup работать. SymTab заняли бы слишком много памяти и поэтому фактически никогда не объявляется).

Затем мы должны заменить InTable.

{--------------------------------------------------------------}

{ Look for Symbol in Table }

function InTable(n: Symbol): Boolean;



begin

   InTable := Lookup(@ST, n, MaxEntry) <> 0;

end;

{--------------------------------------------------------------}


Нам также необходима новая процедура AddEntry, которая добавляет новый элемент в таблицу:

{--------------------------------------------------------------}

{ Add a New Entry to Symbol Table }

procedure AddEntry(N: Symbol; T: char);

begin

   if InTable(N) then Abort('Duplicate Identifier ' + N);

   if NEntry = MaxEntry then Abort('Symbol Table Full');

   Inc(NEntry);

   ST[NEntry] := N;

   SType[NEntry] := T;

end;

{--------------------------------------------------------------}

Эта процедура вызывается из Alloc:

{--------------------------------------------------------------}

{ Allocate Storage for a Variable }

procedure Alloc(N: Symbol);

begin

   if InTable(N) then Abort('Duplicate Variable Name ' + N);

   AddEntry(N, 'v');

.

.

.

{--------------------------------------------------------------}

Наконец, мы должны изменить все подпрограммы, которые в настоящее время обрабатывают имена переменных как одиночный символ. Они включают LoadVar и Store (просто измените тип с char на string) и Factor, Assignment и Decl (просто измените Value[1] на Value).

Последняя вещь: измените процедуру Init для очистки массива как показано ниже:

{--------------------------------------------------------------}

{ Initialize }

procedure Init;

var i: integer;

begin

   for i := 1 to MaxEntry do begin

      ST[i] := '';

      SType[i] := ' ';

   end;

   GetChar;

   Scan;

end;

{--------------------------------------------------------------}

Это должно работать. Испытайте ее и проверьте, что вы действительно можете использовать много символьные имена переменных.


Содержание раздела