3.6 Динамическая компоновка |
Предыдущая Содержание Следующая |
Распознаватель завершён. value.h полностью скрывает блок вычислений арифметических выражений и в то же время определяет, что мы должны реализовать. new() принимает описание, например, Add (сложение) и подходящие аргументы, например, указатели на операнды сложения и возвращает указатель, представляющий собой данную сумму:
struct Type { void * (* new) (va_list ap); double (* exec) (const void * tree); void (* delete) (void * tree); };
void * new (const void * type, ...) { va_list ap; void * result;
assert(type && ((struct Type *) type) -> new);
va_start(ap, type); result = ((struct Type *) type) -> new(ap); * (const struct Type **) result = type; va_end(ap); return result; }
Мы используем динамическую компоновку и передаём вызов в зависимую от узла подпрограмму, которая в случае Add должна создать узел и записать два указателя:
struct Bin { const void * type; void * left, * right; };
static void * mkBin (va_list ap) { struct Bin * node = malloc(sizeof(struct Bin));
assert(node); node -> left = va_arg(ap, void *); node -> right = va_arg(ap, void *); return node; }
Обратите внимание, что только mkBin() знает, какой узел создаётся. Всё, что требуется, чтобы различные узлы начинались с указателя для динамической компоновки. Этот указатель вводится new() так, чтобы delete() могла добраться своей до зависимой от узла функции:
void delete (void * tree) { assert(tree && * (struct Type **) tree && (* (struct Type **) tree) -> delete);
(* (struct Type **) tree) -> delete(tree); }
static void freeBin (void * tree) { delete(((struct Bin *) tree) -> left); delete(((struct Bin *) tree) -> right); free(tree); }
Динамическая компоновка элегантно избегает сложных узлов. .new() создаёт совершенно правильный узел для каждого описания типа: бинарные операторы имеют два потомка, унарные операторы имеют одного, а узел со значением содержит только это значение. delete() очень простая функция, потому что каждый узел обрабатывает свою собственное уничтожение: бинарные операторы удаляют два поддерева и очищают свой собственный узел, унарные операторы удаляют только одно поддерево, а узел со значением будет очищать только самого себя. Переменные или константы даже могут быть оставлены — они просто ничего не будут делать в ответ на delete().
|
Предыдущая Содержание Следующая |