5.3 Подменщик — Name |
Предыдущая Содержание Следующая |
Присвоение имеет следующий синтаксис:
stmt : sum | LET VAR = sum
LET является примером ключевого слова. При построении подменщика мы все ещё можем решить, какой идентификатор будет представлять LET: scan() извлекает идентификатор из строки ввода и передаёт его в screen(), которая просматривает таблицу символов и возвращает подходящее значение для token и, по крайней мере для переменной, узел в symbol. Подменщик отбрасывает LET, но устанавливает данную переменную в качестве листового узла в дереве. Для других символов, таких как имя математической функции, чтобы получить новый узел нашего дерева, мы можем захотеть применить new() к тому символу, который возвращает подменщик. Таким образом записи нашей таблицы символов должны иметь по большей части одинаковые функции с динамической компоновкой, так же как и узлы нашего дерева. Для ключевого слова структура Name должна содержать входную строку и значение маркера. Мы хотим в дальнейшем наследоваться от Name; поэтому определяем эту структуру в файле представления Name.r:
struct Name { /* базовая структура */ const void * type; /* для динамической компоновки */ const char * name; /* может быть выделена динамическая память */ int token; };
Наши символы никогда не умирают: не имеет значения, являются ли их имена постоянными строками для заранее определённых ключевых слов или динамически сохранёнными строкам для определённых пользователем переменных — мы не будем их утилизировать. Прежде чем мы сможем найти символ, надо встроить его в таблицу символов. Это не может быть сделано с помощью вызова new(Name, ...), потому что мы хотим поддерживать более сложные символы, чем Name, и собираемся скрыть от них реализацию таблицы символов. Вместо этого мы предоставляем функцию install(), которая принимает объект Name и вставляет его в таблицу символов. Вот файл интерфейса символьной таблицы Name.h:
extern void * symbol; /* -> последний Name, найденный screen() */
void install (const void * symbol); int screen (const char * name);
Распознаватель должен вставить ключевые слова, такие как LET, в таблицу символов, прежде чем они смогут быть найдены подменщиком. Эти ключевые слова могут быть определены в постоянной таблице структур — это не имеет никакого значения для install(). Для инициализации распознавания используется следующая функция:
#include "Name.h" #include "Name.r"
static void initNames (void) { static const struct Name names [] = { { 0, "let", LET }, 0 }; const struct Name * np; for (np = names; np -> name; ++ np) install(np); }
Обратите внимание, что names[], таблица ключевых слов, не должна быть отсортирована. Чтобы определить names[] используем представление Name, то есть подключаем Name.r. Так как ключевое слово LET отбрасывается, мы не предоставляем динамически скомпонованных методов.
|
Предыдущая Содержание Следующая |