summaryrefslogtreecommitdiff
path: root/usr.bin
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
parente0c264df5c171a82d3b6d8518afb06b9b53ddf8f (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.h30
-rw-r--r--usr.bin/pcc/cpp/cpy.y194
-rw-r--r--usr.bin/pcc/cpp/scanner.l49
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)
{