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 | |
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')
-rw-r--r-- | usr.bin/pcc/cpp/cpp.h | 30 | ||||
-rw-r--r-- | usr.bin/pcc/cpp/cpy.y | 194 | ||||
-rw-r--r-- | usr.bin/pcc/cpp/scanner.l | 49 |
3 files changed, 233 insertions, 40 deletions
diff --git a/usr.bin/pcc/cpp/cpp.h b/usr.bin/pcc/cpp/cpp.h index 25eeaccf5c3..d12968dcf08 100644 --- a/usr.bin/pcc/cpp/cpp.h +++ b/usr.bin/pcc/cpp/cpp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpp.h,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* $OpenBSD: cpp.h,v 1.2 2007/10/12 07:22:44 otto Exp $ */ /* * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se). @@ -90,6 +90,34 @@ struct initar { char *str; }; +struct val { + union { + long long val; + unsigned long long uval; + } v; + int type; +}; + +struct nd { + union { + struct { + struct nd *left; + struct nd *right; + } t; + struct val v; + } n; + int op; +}; + +#define nd_left n.t.left +#define nd_right n.t.right +#define nd_val n.v.v.val +#define nd_uval n.v.v.uval +#define nd_type n.v.type + +struct nd *mknode(int, struct nd *, struct nd *); +struct nd *mknum(struct val); + struct recur; /* not used outside cpp.c */ int subst(struct symtab *, struct recur *); struct symtab *lookup(usch *namep, int enterf); 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; +} diff --git a/usr.bin/pcc/cpp/scanner.l b/usr.bin/pcc/cpp/scanner.l index d021d9991e0..13297fdeade 100644 --- a/usr.bin/pcc/cpp/scanner.l +++ b/usr.bin/pcc/cpp/scanner.l @@ -1,5 +1,5 @@ %{ -/* $OpenBSD: scanner.l,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* $OpenBSD: scanner.l,v 1.2 2007/10/12 07:22:44 otto Exp $ */ /* * Copyright (c) 2004 Anders Magnusson. All rights reserved. @@ -39,6 +39,7 @@ %{ static long long cvtdig(int rad); +static unsigned long long cvtdigu(int rad); static int charcon(void); static void elsestmt(void); static void ifdefstmt(void); @@ -161,26 +162,39 @@ WS [\t ] <IFR>{WS}+ { ; } <IFR>{L}({L}|{D})* { if (gotdef) { - yylval.val = + yylval.val.type = 0; + yylval.val.v.val = lookup((usch *)yytext, FIND) != 0; gotdef = 0; return IDENT; } - yylval.val = 0; + yylval.val.type = 0; + yylval.val.v.val = 0; return NUMBER; } [1-9][0-9]* { if (slow && !YYSTATE) return IDENT; scale = 10; goto num; } 0[xX]{H}+{IS}? { scale = 16; - num: if (YYSTATE) - yylval.val = cvtdig(scale); + num: if (YYSTATE) { + yylval.val.type = + strrchr(yytext, 'U') != NULL || + strrchr(yytext, 'u') != NULL; + if (yylval.val.type) + yylval.val.v.uval = + cvtdigu(scale); + else + yylval.val.v.val = + cvtdig(scale); + } PRTOUT(NUMBER); } 0{D}+{IS}? { scale = 8; goto num; } {D}+{IS}? { scale = 10; goto num; } -L?'(\\.|[^\\'])+' { if (YYSTATE) - yylval.val = charcon(); +L?'(\\.|[^\\'])+' { if (YYSTATE) { + yylval.val.type = 0; + yylval.val.v.val = charcon(); + } PRTOUT(NUMBER); } @@ -489,7 +503,6 @@ dig2num(int c) /* * Convert some string numbers to long long. - * Do not care about UL trailers, should we? */ static long long cvtdig(int rad) @@ -508,6 +521,26 @@ cvtdig(int rad) return rv; } +/* + * Convert some string numbers to unsigned long long. + */ +static unsigned long long +cvtdigu(int rad) +{ + unsigned long long rv = 0; + char *y = yytext; + int c; + + c = *y++; + if (rad == 16) + y++; + while (isxdigit(c)) { + rv = rv * rad + dig2num(c); + c = *y++; + } + return rv; +} + static int charcon(void) { |