5.5 Реализация суперкласса — Var

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

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.

 

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