| VAR { code3(varpush, (Inst)$1, eval); } | asgn | BLTIN '(' expr ')' { code2(bltin, (Inst)$1->u.ptr); } | '(' expr ')' | expr '+' expr { code(add); } | expr '-' expr { code(sub); } | expr '*' expr { code(mul); } | expr '/' expr { code(div); } | expr '^' expr { code(power); } | '-' expr %prec UNARYMINUS { code (negate); } ;%%/* end of grammar */...InstintcodeМы несколько изменили процедуру
mainyyparsemain(argc, argv) /* hoc4 */ char *argv[];{ int fpecatch(); progname = argv[0]; init(); setjmp(begin); signal(SIGFPE, fpecatch); for (initcode(); yyparse(); initcode()) execute(prog); return 0;}Лексический анализатор отличается мало в основном тем, что числа следует сохранять, а не использовать немедленно. Для этого достаточно занести их в таблицу имен вместе с переменными. Ниже приведена измененная часть
yylexyylex() /* hoc4 */ ... if (с == '.' || isdigit(c)) { /* number */ double d; ungetc(c, stdin); scanf("%lf", &d); yylval.sym = install("", NUMBER, d); return NUMBER; } ...Каждый элемент стека интерпретатора является вещественным значением или указателем на запись в таблице имен; тип данных стека объединение всех элементов. Сама машина реализуется как массив указателей на процедуры, выполняющие операции типа
mulhoc.h$ cat hoc.htypedef struct Symbol { /* symbol table entry */ char *name; short type; /* VAR, BLTIN, UNDEF */ union { double val; /* if VAR */ double (*ptr)(); /* if BLTIN */ } u; struct Symbol *next; /* to link to another */} Symbol;Symbol *install(), *lookup();typedef union Datum { /* interpreter stack type */ double val; Symbol *sym;} Datum;extern Datum pop();typedef int (*Inst)(); /* machine instruction */#define STOP (Inst) 0extern Inst prog[];extern eval(), add(), sub(), mul(), div(), negate(), power();extern assign(), bltin(), varpush(), constpush(), print();$Процедуры, выполняющие машинные команды и управляющие стеком, хранятся в файле с именем
code.c$ cat code.c#include "hoc.h"#include "y.tab.h"#define NSTACK 256static Datum stack[NSTACK]; /* the stack */static Datum *stackp; /* next free spot on stack */#define NPROG 2000Inst prog[NPROG]; /* the machine */Inst *progp; /* next free spot for code generation */Inst *pc; /* program counter during execution */initcode() /* initialize for code generation */{ stackp = stack; progp = prog;}...Управление стеком осуществляется путем обращений к двум процедурам
pushpoppush(d) /* push d onto stack */ Datum d;{ if (stackp >= &stack[NSTACK])