Книга: Давайте создадим компилятор!
Многосимвольные имена переменных
Многосимвольные имена переменных
Одна из них – ограничение, требующее использования односимвольных имен переменных. Теперь, когда мы можем обрабатывать многосимвольные ключевые слова, это ограничение начинает казаться произвольным и ненужным. И действительно это так. В основном, единственное его достоинство в том, что он позволяет получить тривиально простую реализацию таблицы идентификаторов. Но это просто удобство для создателей компиляторов и оно должно быть уничтожено.
Мы уже делали этот шаг прежде. На этот раз, как обычно, я сделаю это немного по-другому. Я думаю подход, примененный здесь, сохранит простоту настолько, насколько это возможно.
Естественным путем реализации таблицы идентификаторов на 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;
{–}
Это должно работать. Испытайте ее и проверьте, что вы действительно можете использовать многосимвольные имена переменных.
- Имена индексов ограничений
- Значения переменных по умолчанию
- Имена объектов длиной 68 символов
- Множественные интерфейсы и имена методов
- При подключении к локальной сети компьютер выдает сообщение об ошибке «В сети существуют совпадающие имена». Что делать?
- Как выборочно скрыть имена пользователей, отображаемых на экране приветствия?
- Использование переменных документа
- Просмотр переменных
- 8.3 Этап 3: переменные с произвольными именами; встроенные функции
- Типы ссылок. Имена ячеек
- Стоит ли использовать для нишевых сайтов доменные имена с дефисом?
- Пример 5-1. Вывод "причудливых" переменных