%{ // notebook: // need unsigned operators? // don't exit on errors // don't require expr after defs // text description for defs // hash #include "sym.h" #include "code.h" #include "error.h" %} %union { long num; struct symbol *sym; } %token DEF %token EVENT // XXX own type %token NUMBER %token SYMBOL %left '|' %left '^' %left '&' %left SHL SHR %left '-' '+' %left '*' '/' '%' %left NEG NOT %{ #include #include #include #include #include #include #include static int yylex(void); static unsigned char buf[1024]; static char symname[128]; %} %% def_and_expr: def_list expr ; def_list: def_list definition | ; definition: DEF SYMBOL { start_def($2); } '=' expr ';' { end_def($2); } ; expr: EVENT { put_long(OP_EVENT, $1); } | NUMBER { put_long(OP_NUMBER, $1); } | SYMBOL { if ($1->undef) yyerror("undefined symbol %s", $1->name); put_long(OP_CALL, (long)$1); } | expr '|' expr { put_op(OP_OR); } | expr '&' expr { put_op(OP_AND); } | expr '^' expr { put_op(OP_XOR); } | expr SHL expr { put_op(OP_SHL); } | expr SHR expr { put_op(OP_SHR); } | '~' expr %prec NOT { put_op(OP_NOT); } | expr '+' expr { put_op(OP_PLUS); } | expr '-' expr { put_op(OP_MINUS); } | expr '*' expr { put_op(OP_MUL); } | expr '/' expr { put_op(OP_DIV); } | expr '%' expr { put_op(OP_MOD); } | '-' expr %prec NEG { put_op(OP_NEGATE); } | '(' expr ')' ; %% #define SYMHASHSZ 1 struct symbol *slist[SYMHASHSZ]; static int symhash(char *s) { return 0; // XXX } static struct symbol *getsymbol(char *name) { struct symbol *s; int h = symhash(name); for (s = slist[h]; s; s = s->next) if (!strcmp(s->name, name)) return s; s = malloc(sizeof(struct symbol)); s->name = strdup(name); s->undef = 1; s->next = slist[h]; slist[h] = s; return s; } static long number(int c) { char buf[32]; char *endp; long num; int i; i = 0; do { if (i == sizeof buf - 1) yyerror("number too long"); buf[i++] = c; c = getchar(); } while (isdigit(c) || c == 'x'); if (c != EOF) ungetc(c, stdin); buf[i++] = 0; errno = 0; num = strtol(buf, &endp, 0); if (errno == ERANGE) yyerror("number over/underflow"); if (endp == buf) yyerror("cannot parse number"); return num; } static int symbol(int c) { int i = 0; do { if (i >= sizeof(symname)) yyerror("symbol too long"); symname[i++] = c; c = getchar(); } while (isalpha(c) || isdigit(c) || c == '.' || c == '_'); if (c != EOF) ungetc(c, stdin); symname[i] = 0; if (!strcasecmp(symname, "def")) return DEF; yylval.sym = getsymbol(symname); return SYMBOL; } static int yylex(void) { int c, c1; for (;;) { c = getchar(); if (c == EOF) return 0; switch (c) { case '\n': yylineno++; continue; case ' ': case '\t': case '\r': continue; case '0' ... '9': yylval.num = number(c); return NUMBER; case '+': case '-': case '*': case '/': case '%': case '(': case ')': case '=': case ';': case '^': case '&': case '|': case '~': return c; case '<': case '>': c1 = getchar(); if (c1 == c) return c == '<' ? SHL : SHR; break; case 'A'...'Z': case 'a'...'z': case '_': return symbol(c); case '#': do { c = getchar(); } while (c != '\n' && c != EOF); continue; } yyerror("unknown character '%c'", c); } } int main(void) { code_init(buf, sizeof buf); yyparse(); put_op(OP_END); printf("%ld\n", execute(buf)); return 0; }