Книга: Давайте создадим компилятор!

Многосимвольные имена переменных

Многосимвольные имена переменных

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

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

Естественным путем реализации таблицы идентификаторов на 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;

{–}

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

Оглавление книги


Генерация: 1.809. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз