scc

Simple C99 Compiler
Log | Files | Refs | README | LICENSE

commit 8de30f6330165bf0b1ba05155030318f34190f47
parent 9a911ac4ee93084336a8f55d6815615b09b6b722
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Tue, 25 Mar 2014 18:38:40 +0100

First version with some semantic analysis

Diffstat:
decl.c | 15++++++++++-----
expr.c | 148+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
stmt.c | 4++--
symbol.h | 18++++++++++--------
4 files changed, 155 insertions(+), 30 deletions(-)

diff --git a/decl.c b/decl.c @@ -140,6 +140,7 @@ declarator(struct ctype *tp, uint8_t ns, int8_t flags) register struct dcldata *bp; struct symbol *sym; + memset(data, 0, sizeof(data)); data[NR_DECLARATORS].op = 255; for (bp = declarator0(data, ns, flags); bp >= data; --bp) { switch (bp->op) { @@ -471,7 +472,7 @@ typename(void) void extdecl(void) { - struct ctype *tp; + struct ctype *base; int8_t sclass; struct symbol *sym; char *err; @@ -481,7 +482,7 @@ extdecl(void) switch (yytoken) { case IDEN: case TYPE: case SCLASS: case TQUALIFIER: - tp = specifier(&sclass); + base = specifier(&sclass); if (sclass == REGISTER || sclass == AUTO) goto bad_storage; case ';': @@ -492,10 +493,14 @@ extdecl(void) if (yytoken != ';') { do { - sym = declarator(tp, NS_IDEN, ID_EXPECTED); + struct ctype *tp; + + sym = declarator(base, NS_IDEN, ID_EXPECTED); + tp = sym->type; + if (!(sclass & STATIC)) sym->s.isglobal = 1; - if (ISFUN(sym->type)) { + if (isfun(BTYPE(tp))) { emitfun(sym); if (yytoken == '{') { emitframe(sym); @@ -509,7 +514,7 @@ extdecl(void) if (sclass & EXTERN) ; /* TODO: handle extern */ else if (accept('=')) - initializer(sym->type); + initializer(tp); } } while (accept(',')); } diff --git a/expr.c b/expr.c @@ -6,20 +6,46 @@ #include "tokens.h" #include "symbol.h" +struct node *expr(void); -struct ctype *expr(void); +enum { + OSYM = 1, OARY, OADDR, OADD +}; -static struct ctype * +struct node { + uint8_t op; + struct ctype *type; + + struct { + bool constant : 1; + } f; + union { + struct symbol *sym; + } u; + struct node *left, *right; +}; + +struct node * +newnode(uint8_t op, struct ctype *tp) +{ + struct node *np = xcalloc(1, sizeof(*np)); + + np->op = op; + np->type = tp; + return np; +} + +static struct node * primary(void) { - register struct ctype *tp; + register struct node *np; switch (yytoken) { case IDEN: if (yylval.sym == NULL) error("'%s' undeclared", yytext); - emitsym(yylval.sym); - tp = yylval.sym->type; + np = newnode(OSYM, yylval.sym->type); + np->u.sym = yylval.sym; next(); break; case CONSTANT: @@ -28,31 +54,122 @@ primary(void) break; case '(': next(); - tp = expr(); + np = expr(); expect(')'); break; default: - error("unexpected '%s'", yytoken); + error("unexpected '%s'", yytext); + } + return np; +} + +static struct node * +ary2ptr(struct node *np) +{ + struct ctype *tp = np->type; + + struct node *aux; + + tp = mktype(UNQUAL(tp)->type, PTR, NULL, 0); + aux= newnode(OADDR, tp); + aux->left = np; + return aux; +} + +static struct node * +int2ptr(struct node *np) +{ + return np; +} + +static struct node * +ary(struct node *np1) +{ + struct node *np2, *naux; + struct ctype *tp; + uint8_t t1, t2, taux; + + np2 = expr(); + expect(']'); + t1 = BTYPE(np1->type); + t2 = BTYPE(np2->type); + + if (!isaddr(t1)) { + taux = t1, t1 = t2, t2 = taux; + naux = np1, np1 = np2, np2 = naux; } - return tp; + if (!isaddr(t1)) + error("expected array or pointer"); + if (isary(t1)) + np1 = ary2ptr(np1); + if (!isarith(t2)) + error("array subscript is not an integer"); + + tp = np1->type; + tp = UNQUAL(tp); + naux = newnode(OADD, tp); + naux->left = np1; + naux->right = int2ptr(np2); + return naux; } -static struct ctype * +static struct node * postfix(void) { - struct ctype * tp; + struct node *np; - tp = primary(); + np = primary(); + for (;;) { + switch (yytoken) { + case '[': next(); np = ary(np); break; + default: return np; + } + } } -struct ctype * +struct node * expr(void) { - register struct ctype *tp; + register struct node *np; do - tp = postfix(); + np = postfix(); while (yytoken == ','); - return tp; + return np; +} + +static void +evalnode(struct node *np) +{ + if (!np) + return; + + switch (np->op) { + case OSYM: + emitsym(np->u.sym); + break; + case OARY: + evalnode(np->left); + evalnode(np->right); + fputs("\t'", stdout); + break; + case OADDR: + evalnode(np->left); + evalnode(np->right); + fputs("\t@", stdout); + break; + case OADD: + evalnode(np->left); + evalnode(np->right); + fputs("\t+", stdout); + break; + } } + +void +eval(struct node *np) +{ + evalnode(np); + putchar('\n'); +}+ \ No newline at end of file diff --git a/stmt.c b/stmt.c @@ -8,7 +8,7 @@ void compound(void) { - extern struct ctype *expr(void); + extern struct node *expr(void); extern void decl(void); expect('{'); @@ -18,7 +18,7 @@ compound(void) decl(); break; default: - expr(); + eval(expr()); } expect(';'); } diff --git a/symbol.h b/symbol.h @@ -97,14 +97,16 @@ extern struct ctype *voidtype, *doubletype, *cdoubletype, *idoubletype, *ldoubletype, *cldoubletype,*ildoubletype; -#define UNQUAL(t) (ISQUAL(t) ? (t)->type : (t)) -#define BTYPE(t) (UNQUAL(t)->op) -#define ISFUN(t) ((t)->op == FTN) -#define ISPTR(t) ((t)->op == PTR) -#define ISARITH(t) ((t)->op & ARITH) -#define ISADDR(t) ((t)->op & POINTER) -#define ISRECORD(t) ((t)->op & RECORD) -#define ISQUAL(t) ((t)->op & TQUALIFIER) +#define ISQUAL(t) (isqual((t)->op)) +#define UNQUAL(t) (ISQUAL(t) ? (t)->type : (t)) +#define BTYPE(t) (UNQUAL(t)->op) +#define isfun(op) ((op) == FTN) +#define isptr(op) ((op) == PTR) +#define isary(op) ((op) == ARY) +#define isarith(op) ((op) & ARITH) +#define isaddr(op) ((op) & POINTER) +#define isrecord(op) ((op) & RECORD) +#define isqual(op) ((op) & TQUALIFIER) #endif