diff options
author | Otto Moerbeek <otto@cvs.openbsd.org> | 2007-10-12 07:22:45 +0000 |
---|---|---|
committer | Otto Moerbeek <otto@cvs.openbsd.org> | 2007-10-12 07:22:45 +0000 |
commit | b1fd7f6f4066096ad9c2a4bd8317d46cee5181fe (patch) | |
tree | 7dd087ec4391f3be756e169a5d501d0c1c987f5b /usr.bin/pcc/cpp/cpy.y | |
parent | e0c264df5c171a82d3b6d8518afb06b9b53ddf8f (diff) |
rewrite of constant expression evaluation; taking into account
signed vs unsigned and shortcutting of && and ||
ok ragge@
Diffstat (limited to 'usr.bin/pcc/cpp/cpy.y')
-rw-r--r-- | usr.bin/pcc/cpp/cpy.y | 194 |
1 files changed, 163 insertions, 31 deletions
diff --git a/usr.bin/pcc/cpp/cpy.y b/usr.bin/pcc/cpp/cpy.y index cb0345a8eda..ed73fceebcc 100644 --- a/usr.bin/pcc/cpp/cpy.y +++ b/usr.bin/pcc/cpp/cpy.y @@ -1,4 +1,4 @@ -/* $OpenBSD: cpy.y,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* $OpenBSD: cpy.y,v 1.2 2007/10/12 07:22:44 otto Exp $ */ /* * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se). @@ -65,8 +65,12 @@ #include <stdlib.h> #include <string.h> #include <ctype.h> + +#include "cpp.h" + void yyerror(char *); int yylex(void); +struct val eval(struct nd *); %} %term stop @@ -93,74 +97,202 @@ int yylex(void); %left '(' '.' %union { - long long val; + struct val val; + struct nd *node; } -%type <val> term NUMBER e +%type <val> NUMBER +%type <node> term e %% -S: e '\n' { return($1 != 0);} +S: e '\n' { return(eval($1).v.val != 0);} e: e '*' e - {$$ = $1 * $3;} + {$$ = mknode('*', $1, $3);} | e '/' e - {$$ = $1 / $3;} + {$$ = mknode('/', $1, $3);} | e '%' e - {$$ = $1 % $3;} + {$$ = mknode('%', $1, $3);} | e '+' e - {$$ = $1 + $3;} + {$$ = mknode('+', $1, $3);} | e '-' e - {$$ = $1 - $3;} + {$$ = mknode('-', $1, $3);} | e LS e - {$$ = $1 << $3;} + {$$ = mknode(LS, $1, $3);} | e RS e - {$$ = $1 >> $3;} + {$$ = mknode(RS, $1, $3);} | e '<' e - {$$ = $1 < $3;} + {$$ = mknode('<', $1, $3);} | e '>' e - {$$ = $1 > $3;} + {$$ = mknode('>', $1, $3);} | e LE e - {$$ = $1 <= $3;} + {$$ = mknode(LE, $1, $3);} | e GE e - {$$ = $1 >= $3;} + {$$ = mknode(GE, $1, $3);} | e EQ e - {$$ = $1 == $3;} + {$$ = mknode(EQ, $1, $3);} | e NE e - {$$ = $1 != $3;} + {$$ = mknode(NE, $1, $3);} | e '&' e - {$$ = $1 & $3;} + {$$ = mknode('&', $1, $3);} | e '^' e - {$$ = $1 ^ $3;} + {$$ = mknode('^', $1, $3);} | e '|' e - {$$ = $1 | $3;} + {$$ = mknode('|', $1, $3);} | e ANDAND e - {$$ = $1 && $3;} + {$$ = mknode(ANDAND, $1, $3);} | e OROR e - {$$ = $1 || $3;} - | e '?' e ':' e - {$$ = $1 ? $3 : $5;} + {$$ = mknode(OROR, $1, $3);} + | e '?' e ':' e { + struct nd *n = mknode(':', $3, $5); + $$ = mknode('?', $1, n);} | e ',' e - {$$ = $3;} + {$$ = mknode(',', $1, $3);} | term {$$ = $1;} term: '-' term %prec UMINUS - {$$ = -$2;} + {$$ = mknode(UMINUS, $2, NULL);} + | '+' term %prec UMINUS + {$$ = $2;} | '!' term - {$$ = !$2;} + {$$ = mknode('!', $2, NULL);} | '~' term - {$$ = ~$2;} + {$$ = mknode('~', $2, NULL);} | '(' e ')' {$$ = $2;} | NUMBER - {$$= $1;} + {$$= mknum($1);} %% -#include "cpp.h" - void yyerror(char *err) { error(err); } + +struct nd * +mknode(int op, struct nd *left, struct nd *right) +{ + struct nd *r = malloc(sizeof(*r)); + if (r == NULL) + error("out of mem"); + + r->op = op; + r->nd_left = left; + r->nd_right = right; + + return r; +} + +struct nd * +mknum(struct val val) +{ + struct nd *r = malloc(sizeof(*r)); + if (r == NULL) + error("out of mem"); + + r->op = NUMBER; + r->n.v = val; + return r; +} + +#define EVALUNARY(tok, op, t, x) \ + case (tok): if (t) ret.v.uval = op x.v.uval; \ + else ret.v.val = op x.v.val; \ + ret.type = t; \ + break; + +#define EVALBIN(tok, op, t, x, y, r) \ + case (tok): if (t) ret.v.uval = x.v.uval op y.v.uval; \ + else ret.v.val = x.v.val op y.v.val; \ + ret.type = r; \ + break; + +struct val +eval(struct nd *tree) +{ + struct val ret, l, r; + int t; + + switch (tree->op) { + case NUMBER: + ret.type = tree->nd_type; + if (ret.type) + ret.v.uval = tree->nd_uval; + else + ret.v.val = tree->nd_val; + goto out; + case LS: + case RS: + r = eval(tree->nd_right); + /* FALLTHROUGH */ + case UMINUS: + case '~': + case '!': + l = eval(tree->nd_left); + switch (tree->op) { + EVALBIN(LS, <<, l.type, l, r, l.type); + EVALBIN(RS, >>, l.type, l, r, l.type); + EVALUNARY(UMINUS, -, l.type, l); + EVALUNARY('~', ~, l.type, l); + EVALUNARY('!', !, 0, l); + } + goto out; + case '?': + l = eval(tree->nd_left); + // XXX mem leak + if (l.v.val) + ret = eval(tree->nd_right->nd_left); + else + ret = eval(tree->nd_right->nd_right); + goto out; + case OROR: + l = eval(tree->nd_left); + // XXX mem leak + if (l.v.val) + ret = l; + else + ret = eval(tree->nd_right); + ret.type = 0; + goto out; + case ANDAND: + l = eval(tree->nd_left); + // XXX mem leak + if (l.v.val) + ret = eval(tree->nd_right); + else + ret = l; + ret.type = 0; + goto out; + case ',': + // XXX mem leak + ret = eval(tree->nd_right); + goto out; + } + + l = eval(tree->nd_left); + r = eval(tree->nd_right); + t = l.type || r.type; + switch (tree->op) { + EVALBIN(EQ, ==, t, l, r, 0); + EVALBIN(NE, !=, t, l, r, 0); + EVALBIN('<', <, t, l, r, 0); + EVALBIN('>', >, t, l, r, 0); + EVALBIN(GE, >=, t, l, r, 0); + EVALBIN(LE, <=, t, l, r, 0); + EVALBIN('+', +, t, l, r, t); + EVALBIN('-', -, t, l, r, t); + EVALBIN('*', *, t, l, r, t); + // XXX check /,% by zero + EVALBIN('/', /, t, l, r, t); + EVALBIN('%', %, t, l, r, t); + EVALBIN('&', &, t, l, r, t); + EVALBIN('|', |, t, l, r, t); + EVALBIN('^', ^, t, l, r, t); + } +out: + free(tree); + return ret; +} |