summaryrefslogtreecommitdiff
path: root/usr.bin/pcc/cpp/cpy.y
diff options
context:
space:
mode:
authorOtto Moerbeek <otto@cvs.openbsd.org>2007-10-12 07:22:45 +0000
committerOtto Moerbeek <otto@cvs.openbsd.org>2007-10-12 07:22:45 +0000
commitb1fd7f6f4066096ad9c2a4bd8317d46cee5181fe (patch)
tree7dd087ec4391f3be756e169a5d501d0c1c987f5b /usr.bin/pcc/cpp/cpy.y
parente0c264df5c171a82d3b6d8518afb06b9b53ddf8f (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.y194
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;
+}