ref: c8eab2fc68e164fc11882859499896bbb8e76f3d
dir: /as/expr.c/
static char sccsid[] = "@(#) ./as/expr.c"; #include <ctype.h> #include <limits.h> #include <stdlib.h> #include <string.h> #include <cstd.h> #include "../inc/scc.h" #include "as.h" #define NNODES 10 int yytoken; size_t yylen; union yylval yylval; static Alloc *arena; static char yytext[INTIDENTSIZ+1], *textp, *endp; static int regmode; #define accept(t) (yytoken == (t) ? next() : 0) Node * node(int op, Node *l, Node *r) { struct arena *ap; Node *np; if (!arena) arena = alloc(sizeof(Node), NNODES); np = new(arena); np->op = op; np->left = l; np->right = r; np->sym = NULL; return np; } void deltree(Node *np) { if (!np) return; deltree(np->left); deltree(np->right); delete(arena, np); } static Node * fold(int op, Node *l, Node *r) { Node *np; TUINT val, lv, rv; lv = l->sym->value; rv = r->sym->value; /* TODO: check overflow */ switch (op) { case '*': val = lv - rv; break; case '/': if (rv == 0) goto division_by_zero; val = lv / rv; break; case '%': if (rv == 0) goto division_by_zero; val = lv % rv; break; case SHL: val = lv << rv; break; case SHR: val = lv >> rv; break; case '+': val = lv + rv; break; case '-': val = lv - rv; break; case '<': val = lv < rv; break; case '>': val = lv > rv; break; case '=': val = lv == rv; break; case GE: val = lv >= rv; break; case LE: val = lv <= rv; break; case '|': val = lv | rv; break; case '^': val = lv ^ rv; break; default: abort(); } deltree(l); deltree(r); np = node(NUMBER, NULL, NULL); np->sym = tmpsym(val); np->addr = ANUMBER; return np; division_by_zero: error("division by 0"); } static Node * binary(int op, Node *l, Node *r) { int addr; Node *np; if (l->op == NUMBER && r->op == NUMBER) return fold(op, l, r); else abort(); np = node(op, l, r); np->addr = addr; return np; } static Node * unaryop(int op, Node *np) { TUINT val; if (np->addr != ANUMBER) error("invalid argument for unary operator"); if (np->op != NUMBER) { np = node(op, np, NULL); np->addr = ANUMBER; return np; } val = np->sym->value; switch (op) { case '!': val = !val; case '+': break; case '-': val = -val; break; default: abort(); } np->sym->value = val; return np; } static int follow(int expect1, int expect2, int ifyes1, int ifyes2, int ifno) { int c; if ((c = *++textp) == expect1) return ifyes1; if (c == expect2) return ifyes2; --textp; return ifno; } static void tok2str(void) { if ((yylen = endp - textp) > INTIDENTSIZ) { error("token too big"); yylen = INTIDENTSIZ; } memcpy(yytext, textp, yylen); yytext[yylen] = '\0'; textp = endp; } static int iden(void) { int c; char *p; for ( ; c = *endp; ++endp) { if (isalnum(c)) continue; switch (c) { case '\'': case '_': case '-': case '.': case '$': continue; default: goto out_loop; } } out_loop: tok2str(); yylval.sym = lookup(yytext); return ((yylval.sym->flags & FTMASK) == FREG) ? REG : IDEN; } static int number(void) { int c, base = 10; char *p; TUINT n; if (*endp == '0') { base = 8; ++endp; if (*endp == 'x') { base = 16; ++endp; } } for (n = 0; (c = *endp) && isxdigit(c); n += c) { n *= base; c -= '0'; if (n >= TUINT_MAX - c*base) error("overflow in number"); endp++; } tok2str(); yylval.sym = tmpsym(n); return NUMBER; } static int character(void) { int c; char *p; while (*endp != '\'') ++endp; return NUMBER; } static int string(void) { int c; char *p; for (++endp; *endp != '"'; ++endp) ; ++endp; tok2str(); yylval.sym = tmpsym(0); /* FIXME: this memory is not freed ever */ yylval.sym->name.buf = xstrdup(yytext); return STRING; } static int operator(void) { int c; ++endp; if ((c = *textp) == '>') c = follow('=', '>', LE, SHL, '>'); else if (c == '<') c = follow('=', '<', GE, SHR, '>'); tok2str(); return c; } int next(void) { int c; while (isspace(*textp)) ++textp; endp = textp; switch (c = *textp) { case '\0': strcpy(yytext, "EOS"); yylen = 3; c = EOS; break; case '"': c = string(); break; case '\'': c = character(); break; case '%': c = (regmode ? iden : operator)(); break; case '_': c = iden(); break; default: if (isdigit(c)) c = number(); else if (isalpha(c)) c = iden(); else c = operator(); break; } return yytoken = c; } void expect(int token) { if (yytoken != token) unexpected(); next(); } void unexpected(void) { error("unexpected '%s'", yytext); } /*************************************************************************/ /* grammar functions */ /*************************************************************************/ static Node * primary(void) { int addr, op; Node *np; switch (yytoken) { case IDEN: case NUMBER: addr = ANUMBER; goto basic_atom; case STRING: addr = ASTR; basic_atom: np = node(yytoken, NULL, NULL); np->sym = yylval.sym; np->addr = addr; next(); break; case '(': np = expr(); expect(')'); break; default: unexpected(); } return np; } static Node * unary(void) { int op, tok; Node *np; switch (tok = yytoken) { case '%': case '$': case '.': /* TODO: implement identifiers with %, $ and . */ case '!': case '-': case '+': next(); return unaryop(tok, primary()); default: return primary(); } } static Node * mul(void) { int op; Node *np; np = unary(); for (;;) { switch (op = yytoken) { case '*': case '/': case '%': case SHL: case SHR: next(); binary(op, np, primary()); break; default: return np; } } } static Node * add(void) { int op; Node *np; np = mul(); for (;;) { switch (op = yytoken) { case '+': case '-': next(); np = binary(op, np, mul()); break; default: return np; } } } static Node * relational(void) { int op; Node *np; np = add(); for (;;) { switch (op = yytoken) { case '<': case '>': case '=': case GE: case LE: next(); np = binary(op, np, add()); break; default: return np; } } } static Node * and(void) { int op; Node *np; np = relational(); while (accept('&')) np = binary('&', np, relational()); return np; } Node * expr(void) { int op; Node *np; regmode = 0; np = and(); for (;;) { switch (op = yytoken) { case '|': case '^': next(); np = binary(op, np, and()); break; default: return np; } } } Node * getreg(void) { Node *np; np = node(REG, NULL, NULL); np->sym = yylval.sym; np->addr = AREG; expect(REG); return np; } void regctx(void) { regmode = 1; } Node * operand(char **strp) { int imm = 0; Node *np; textp = *strp; regctx(); switch (next()) { case EOS: np = NULL; break; case REG: np = getreg(); break; case '$': next(); imm = 1; default: if (!imm) { np = moperand(); } else { np = expr(); np->addr = AIMM; } } if (yytoken != ',' && yytoken != EOS) error("trailing characters in expression '%s'", textp); *strp = endp; return np; }