#include #include #include #include #include "code.h" #include "sym.h" #include "error.h" static unsigned char *bufs; static unsigned bufl; static unsigned char *bufp; static void overflow(void) { yyerror("expression exceeds execution buffer"); } void put_op(enum ops op) { if (bufp >= bufs + bufl) overflow(); *bufp++ = op; } void put_long(enum ops op, long arg) { if (bufp + sizeof(long) + 1 >= bufs + bufl) overflow(); *bufp++ = op; memcpy(bufp, &arg, sizeof(long)); bufp += sizeof(long); } void put_ptr(enum ops op, void * arg) { if (bufp + sizeof(void *) + 1 >= bufs + bufl) overflow(); *bufp++ = op; memcpy(bufp, &arg, sizeof(void *)); bufp += sizeof(void *); } void start_def(struct symbol *s) { if (!s->undef) yyerror("symbol %s redefined", s->name); } void end_def(struct symbol *s) { int len; put_op(OP_RET); len = bufp - bufs; s->code = malloc(len); memcpy(s->code, bufs, len); bufp = bufs; s->undef = 0; } static void execerror(char const *msg) { fprintf(stderr, "expression execution error: %s\n", msg); exit(1); } #define STACKSIZE 16 #define CSTACKSIZE 16 long execute(unsigned char *bufp) { static void *target[] = { [OP_END] = &&end, [OP_EVENT] = NULL, [OP_NUMBER] = &&number, [OP_PLUS] = &&plus, [OP_MINUS] = &&minus, [OP_MUL] = &&mul, [OP_DIV] = &&div, [OP_MOD] = &&mod, [OP_NEGATE] = &&negate, [OP_CALL] = &&call, [OP_RET] = &&ret, [OP_XOR] = &&xor, [OP_OR] = &&or, [OP_NOT] = &¬, [OP_AND] = &&and, [OP_SHL] = &&shl, [OP_SHR] = &&shr, }; long a, b; long stack[STACKSIZE]; int stackp = 0; unsigned char *callstack[CSTACKSIZE]; int callstackp = 0; #define getop(x) memcpy(&(x), bufp, sizeof(x)); bufp += sizeof(x) #define push(x) stack[stackp++] = (x) #define pop() stack[--stackp] #define next() goto *target[(int)*bufp++] next(); number: if (stackp == STACKSIZE) execerror("expression stack overflow"); getop(a); push(a); next(); #define OP(op) \ b = pop(); \ a = pop(); \ push(a op b); \ next() plus: OP(+); minus: OP(-); mul: OP(*); div: b = pop(); if (b == 0) execerror("division by 0"); a = pop(); push(a / b); next(); mod: b = pop(); if (b == 0) execerror("modulo by 0"); a = pop(); push(a % b); next(); negate: a = pop(); push(-a); next(); and: OP(&); or: OP(|); xor: OP(^); shl: OP(<<); shr: OP(>>); not: a = pop(); push(~a); next(); call: { struct symbol *s; getop(s); if (callstackp == CSTACKSIZE) execerror("call stack overflow"); callstack[callstackp++] = bufp; bufp = s->code; next(); } ret: bufp = callstack[--callstackp]; next(); end: assert(bufp == bufs || stackp == 1); assert(callstackp == 0); return stack[0]; } #undef next #undef push #undef pop #undef getop void code_init(unsigned char *buf, unsigned len) { bufs = buf; bufp = buf; bufl = len; }