5.3 Подменщик — Name

Предыдущая  Содержание  Следующая V*D*V

Присвоение имеет следующий синтаксис:

 

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 отбрасывается, мы не предоставляем динамически скомпонованных методов.

 

Предыдущая  Содержание  Следующая