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






