Non abbiamo ancora deciso cosa process() deve fare. Se vogliamo trattare una versione postfissa dell'espressione, dobbiamo aggiungere una stringa carattere alla struct Type per mostrare l'operazione corrente e process() gestirà quindi una singola linea di output indentata da uno stop di tabulazione (tab).
void process (const void * tree) { putchar(’\t’); exec(tree); putchar(’\n’); } exec() gestisce il dynamic linkage: static void exec (const void * tree) { assert(tree && * (struct Type **) tree && (* (struct Type **) tree) —> exec); (* (struct Type **) tree) —> exec(tree); }
ed ogni operatore binario è trattato con la seguente funzione
static void doBin (const void * tree) { exec(((struct Bin *) tree) —> left); exec(((struct Bin *) tree) —> right); printf(" %s", (* (struct Type **) tree) —> name); }
La descrizione di tipo è la seguente
static struct Type _Add = { "+", mkBin, doBin, freeBin }; static struct Type _Sub = { "—", mkBin, doBin, freeBin }; const void * Add = & _Add; const void * Sub = & _Sub;
Ora è facile indovinare come viene implementato un valore numerico. Esso viene rappresentato come una struttura con un campo double
struct Val { const void * type; double value; }; static void * mkVal (va_list ap) { struct Val * node = malloc(sizeof(struct Val)); assert(node); node —> value = va_arg(ap, double); return node; }
L'analisi di una espressione consiste nella stampa del valore
static void doVal (const void * tree) { printf(" %g", ((struct Val *) tree) —> value); }
Ed ecco fatto - non c'è alcun sottoalbero da cancellare, così possiamo usare direttamente la funzione di libreria free() per cancellare il nodo valore
static struct Type _Value = { "", mkVal, doVal, free }; const void * Value = & _Value;
Lasciamo come esercizio l'operatore unario Minus