5.5 Реализация суперкласса — Var |
Предыдущая Содержание Следующая |
screen() вызывает new(), чтобы создать новую переменную символа, и возвращает его в распознаватель, который вставляет его в дерево выражений. Поэтому Var должна создавать записи таблицы символов, которые могут работать подобно узлам, то есть при определении struct Var нам необходимо расширить struct Name, чтобы унаследовать способность жить в таблице символов, и необходимо поддерживать динамически скомпонованные функции, применимые к узлам выражений. Описываем интерфейс в Var.h:
const void * Var; const void * Assign;
Переменная имеет имя и значение. Если вычисляется арифметическое выражение, необходимо вернуть компонент .value. Если выражение удаляется, удалять переменную узла не надо, так как она живёт в таблице символов:
struct Var { struct Name _; double value; };
#define value(tree) (((struct Var *) tree) -> value)
static double doVar (const void * tree) { return value(tree); }
static void freeVar (void * tree) { }
Как уже обсуждалось в разделе 4.6, код упрощается предоставлением функции доступа к значению. Создание переменной требует выделения памяти для struct Var, вставки динамической копии имени переменной и значения VAR для маркера, заданного распознавателем:
static void * mkVar (va_list ap) { struct Var * node = calloc(1, sizeof(struct Var)); const char * name = va_arg(ap, const char *); size_t len = strlen(name);
assert(node); node -> _.name = malloc(len+1); assert(node -> _.name); strcpy((void *) node -> _.name, name); node -> _.token = VAR; return node; }
static struct Type _Var = { mkVar, doVar, freeVar };
const void * Var = & _Var;
new() заботится о вставке описания типа Var в узел до того, как символ возвращается в screen() или любому, кто захочет использовать его. Технически, mkVar() является конструктором для Name. Тем не менее, динамически должны сохраняться только имена переменных. Поскольку мы решили, что в нашем калькуляторе конструктор отвечает за выделение памяти для объекта, то не можем позволить конструктору Var вызывать конструктор Name, чтобы создать компоненты .name и .token — конструктор Name выделил бы память для struct Name, а не для struct Var.
|
Предыдущая Содержание Следующая |