scc

simple C compiler
git clone git://git.2f30.org/scc
Log | Files | Refs | README | LICENSE

commit 609bb6b7743e8a37538a2701df3aaa3b652ebfb7
parent 10faf603cace3ffda21153466dfbd9e672bcf656
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Mon,  7 Sep 2015 16:31:39 +0200

Add correct parsing of integer constants

Until this moment there was no check of overflow, and there was no
cast to bigger types when the constant was bigger than the type declared by
the user.

Diffstat:
Mcc1/fold.c | 14++++++++++----
Mcc1/lex.c | 54++++++++++++++++++++++++++++++++++++++++++++++++++----
Mcc1/types.c | 36++++++++++++++++++------------------
3 files changed, 78 insertions(+), 26 deletions(-)

diff --git a/cc1/fold.c b/cc1/fold.c @@ -507,6 +507,7 @@ simplify(int op, Type *tp, Node *lp, Node *rp) Node * castcode(Node *np, Type *newtp) { + TUINT mask; Type *oldtp = np->type; Symbol aux, *sym, *osym = np->sym; @@ -517,6 +518,7 @@ castcode(Node *np, Type *newtp) case PTR: case INT: case ENUM: + mask = ones(newtp->size); switch (oldtp->op) { case PTR: case INT: @@ -524,21 +526,25 @@ castcode(Node *np, Type *newtp) if (newtp->sign == oldtp->sign) aux.u = osym->u; if (newtp->sign && !oldtp->sign) - aux.u.i = osym->u.u; + aux.u.i = osym->u.u & mask; else if (!newtp->sign && oldtp->sign) - aux.u.u = osym->u.u; + aux.u.u = osym->u.u & mask; break; case FLOAT: - if (newtp->sign) + if (newtp->sign) { aux.u.i = osym->u.f; - else + aux.u.i &= mask; + } else { aux.u.u = osym->u.f; + aux.u.u &= mask; + } break; default: goto noconstant; } break; case FLOAT: + /* FIXME: The cast can be from another floar type */ aux.u.f = (oldtp->sign) ? osym->u.i : osym->u.u; break; default: diff --git a/cc1/lex.c b/cc1/lex.c @@ -201,6 +201,55 @@ tok2str(void) input->begin = input->p; } +static Symbol * +readint(char *s, int base, Symbol *sym) +{ + Type *tp = sym->type; + struct limits *lim = getlimits(tp); + TUINT u, val, max, factor = 1; + int c; + + max = (tp->sign) ? lim->max.u : lim->max.i; + switch (*s++) { + case '-': factor = -1; break; + default: --s; + case '+': factor = 1; break; + } + + for (u = 0; isxdigit(c = *s++); u = u * base + val) { + val = (c <= '9') ? c - '0' : 10 + c - 'A'; + if (u <= max/base + val) + continue; + if (tp->sign) { + if (tp == inttype) + tp = longtype; + else if (tp == longtype) + tp == llongtype; + else { + errorp("overflow in integer constant"); + break; + } + } else { + if (tp == uinttype) + tp = ulongtype; + else if (tp == ulongtype) + tp == ullongtype; + else { + errorp("overflow in integer constant"); + break; + } + } + sym->type = tp; + } + + if (tp->sign) + sym->u.i = u * factor; + else + sym->u.u = u; + + return sym; +} + static unsigned integer(char *s, char base) { @@ -233,10 +282,7 @@ convert: sym = newsym(NS_IDEN); sym->type = tp; sym->flags |= ISCONSTANT; - v = strtol(s, NULL, base); - if (tp == inttype) - sym->u.i = v; - yylval.sym = sym; + yylval.sym = readint(s, base, sym); return CONSTANT; } diff --git a/cc1/types.c b/cc1/types.c @@ -17,24 +17,6 @@ */ static struct limits limits[][4] = { { - { /* 0 = signed 1 byte */ - .min.i = -127, - .max.i = 127 - }, - { /* 1 = signed 2 byte */ - .min.i = -32767, - .max.i = 327677 - }, - { /* 2 = signed 4 byte */ - .min.i = -2147483647L, - .max.i = 2147483647L - }, - { /* 3 = signed 8 byte */ - .min.i = -9223372036854775807LL, - .max.i = 9223372036854775807LL, - } - }, - { { /* 0 = unsigned 1 byte */ .min.u = 0, .max.u = 255 @@ -53,6 +35,24 @@ static struct limits limits[][4] = { } }, { + { /* 0 = signed 1 byte */ + .min.i = -127, + .max.i = 127 + }, + { /* 1 = signed 2 byte */ + .min.i = -32767, + .max.i = 32767 + }, + { /* 2 = signed 4 byte */ + .min.i = -2147483647L, + .max.i = 2147483647L + }, + { /* 3 = signed 8 byte */ + .min.i = -9223372036854775807LL, + .max.i = 9223372036854775807LL, + } + }, + { { /* 0 = float 4 bytes */ .min.f = -1,