scc

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

commit 79059d14d5c6a36a81e74697aabdab5901c59b5c
parent 828528f9e6b85837d6b804aac5cbc18f97116bfb
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Sun, 15 Feb 2015 19:40:01 +0100

Merge remote-tracking branch 'gitorius/master'

Diffstat:
Mcc1/cc1.h | 67+++++++++++++++++++++++++++++++------------------------------------
Mcc1/code.c | 60++++++++++++++++++++++++++++++++++++++++++++++--------------
Mcc1/decl.c | 322+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mcc1/expr.c | 68++++++++++++++++++++++++++++++++------------------------------------
Mcc1/lex.c | 5+++--
Mcc1/stmt.c | 63+++++++++++++++++++++++++++++++++++++++++++--------------------
Mcc1/symbol.c | 32++++++++++++++------------------
Mcc1/types.c | 157++++++++++++++++++++++++++++++-------------------------------------------------
Mcc2/Makefile | 2+-
Mcc2/cc2.h | 33+++++++++++++++++++++++++++------
Mcc2/cgen.c | 188++++++++++++++++++++++++++++---------------------------------------------------
Acc2/code.c | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcc2/main.c | 10+++++++---
Acc2/optm.c | 43+++++++++++++++++++++++++++++++++++++++++++
Mcc2/parser.c | 79++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
15 files changed, 655 insertions(+), 543 deletions(-)

diff --git a/cc1/cc1.h b/cc1/cc1.h @@ -26,37 +26,26 @@ enum { NS_IDEN = 0, NS_TAG, NS_LABEL, + NS_STRUCTS, NR_NAMESPACES }; typedef struct ctype Type; typedef struct symbol Symbol; -typedef struct field { - char *name; - Type *type; - int id; - struct field *next; -} Field; - -typedef struct funpar { - Type *type; - struct funpar *next; -} Funpar; - struct ctype { uint8_t op; /* type builder operator */ + uint8_t ns; char letter; /* letter of the type */ - bool defined : 1; /* type defined (is not a forward reference) */ - bool sign : 1; /* sign type */ + bool defined : 1; /* type defined (is not a forward reference) */ + bool sign : 1; /* sign type */ struct ctype *type; /* base type */ struct ctype *next; /* next element in the hash */ - union typeval { - unsigned char rank; /* convertion rank */ - short nelem; /* number of elements in arrays */ - struct funpar *pars; /* function parameters */ - Field *fields; /* aggregate fields */ - } u; + Type **pars; /* type parameters */ + union { + unsigned char rank; /* convertion rank */ + short elem; /* number of type parameters */ + } n; }; @@ -67,18 +56,18 @@ struct symbol { Type *type; short id; uint8_t ctx; + uint8_t ns; uint8_t token; - struct { - bool isglobal : 1; - bool isstatic : 1; - bool isauto : 1; - bool isregister : 1; - bool isdefined : 1; - } s; + bool isglobal : 1; + bool isstatic : 1; + bool isauto : 1; + bool isregister : 1; + bool isdefined : 1; + bool isfield : 1; + bool isparameter : 1; union { int i; char *s; - struct symbol *sym; uint8_t token; } u; struct symbol *next; @@ -87,17 +76,17 @@ struct symbol { extern bool eqtype(Type *tp1, Type *tp2); extern Type *ctype(int8_t type, int8_t sign, int8_t size), - *mktype(Type *tp, uint8_t op, void *data); + *mktype(Type *tp, uint8_t op, short nelem, void *data); extern Symbol *lookup(char *s, unsigned char ns), *install(char *s, unsigned char ns); +extern void pushctx(void), popctx(void); + typedef struct caselist Caselist; extern void compound(Symbol *lbreak, Symbol *lcont, Caselist *lswitch); -extern Type *aggregate(Type *(*fun)(void)); -extern void context(Symbol *lbreak, Symbol *lcont, Caselist *lswitch); extern Type *typename(void); @@ -157,6 +146,7 @@ typedef struct node { void (*code)(struct node *); Type *type; uint8_t typeop; + uint8_t nchilds; struct { bool lvalue : 1; bool symbol: 1; @@ -166,7 +156,6 @@ typedef struct node { Symbol *sym; Type *type; char op; - Field *field; } u; struct node *childs[]; } Node; @@ -178,11 +167,13 @@ enum { OA_MOD, OA_ADD, OA_SUB, OA_SHL, OA_SHR, OA_AND, OA_XOR, OA_OR, OADDR,ONEG, OCPL, OEXC, OCOMMA, + /* TODO: This order is important, but must be changed */ + OAND, OOR, /* * Complementary relational operators only differ in less * significant bit */ - OEQ = 0x40, ONE, OLT, OGE, OLE, OGT, OAND, OOR + OEQ = 0x40, ONE, OLT, OGE, OLE, OGT }; extern void @@ -194,7 +185,8 @@ extern void emitswitch(short, Node *), emitcase(Symbol *, Node *), emitret(Type *tp), emitfun(Symbol *sym), - emitdefault(Symbol *); + emitdefault(Symbol *), + emitstruct(Symbol *sym), emitestruct(void); extern Node *node(void (*code)(Node *), @@ -205,12 +197,15 @@ extern Node *sizeofcode(Type *tp), *ternarycode(Node *cond, Node *ifyes, Node *ifno), *symcode(Symbol *sym), - *fieldcode(Node *child, struct field *fp); + *fieldcode(Node *child, Symbol *field); + +extern void freetree(Node *np); #define NEGATE(n, v) ((n)->u.op ^= (v)) /* TODO: remove some of these ugly macros */ #define ISNODEBIN(n) ((n)->code == emitbin) -#define ISNODECMP(n) (ISNODEBIN(n) && (n)->u.op & 0x40) +#define ISNODECMP(n) (ISNODEBIN(n) && (n)->u.op >= OEQ) +#define ISNODELOG(n) (ISNODEBIN(n) && (n)->u.op >= OAND) extern Node *expr(void); extern void extdecl(void), decl(void); diff --git a/cc1/code.c b/cc1/code.c @@ -1,6 +1,7 @@ #include <stdint.h> #include <stdio.h> +#include <stdlib.h> #include <cc.h> #include "cc1.h" @@ -58,25 +59,43 @@ node(void (*code)(Node *), Type *tp, union unode u, uint8_t nchilds) np->code = code; np->type = tp; np->typeop = tp->op; + np->nchilds = nchilds; np->u = u; np->b.symbol = np->b.lvalue = 0; return np; } +void +freetree(Node *np) +{ + Node **p; + + if (!np) + return; + + for (p = np->childs; np->nchilds--; ++p) + freetree(*p); + free(np); +} + static void -emitsym2(Symbol *sym) +emitvar(Symbol *sym) { char c; - if (sym->s.isstatic && !sym->s.isglobal) + if (sym->isstatic && !sym->isglobal) c = 'T'; - else if (sym->s.isstatic && sym->s.isglobal) + else if (sym->isstatic && sym->isglobal) c = 'Y'; - else if (sym->s.isglobal) + else if (sym->isglobal) c = 'G'; - else if (sym->s.isregister) - c = 'Q'; + else if (sym->isregister) + c = 'R'; + else if (sym->isfield) + c = 'M'; + else if (sym->isparameter) + c = 'P'; else c = 'A'; printf("%c%d", c, sym->id); @@ -98,10 +117,22 @@ emitconst(Node *np) } void +emitstruct(Symbol *sym) +{ + printf("S%d\t(\n", sym->id); +} + +void +emitestruct(void) +{ + puts(")"); +} + +void emitsym(Node *np) { putchar('\t'); - (np->b.constant) ? emitconst(np) : emitsym2(np->u.sym); + (np->b.constant) ? emitconst(np) : emitvar(np->u.sym); } static void @@ -113,7 +144,7 @@ emittype(Type *tp) void emitdcl(Symbol *sym) { - emitsym2(sym); + emitvar(sym); putchar('\t'); emittype(sym->type); putchar('\n'); @@ -185,13 +216,14 @@ emitprint(Node *np) { (*np->code)(np); printf("\tk%c\n", np->type->letter); + fflush(stdout); } void emitfun(Symbol *sym) { printf("%c%d\tF\t%s\t{\n", - sym->s.isglobal ? 'G' : 'Y', sym->id, sym->name); + sym->isglobal ? 'G' : 'Y', sym->id, sym->name); } void @@ -264,14 +296,14 @@ emitfield(Node *np) child = np->childs[0]; (*child->code)(child); - - printf("\tM%d", np->u.field->id); + putchar('\t'); + emitvar(np->u.sym); } Node * -fieldcode(Node *child, struct field *fp) +fieldcode(Node *child, Symbol *field) { - Node *np = node(emitfield, fp->type, FIELD(fp), 1); + Node *np = node(emitfield, field->type, SYM(field), 1); np->childs[0] = child; return np; } @@ -284,7 +316,7 @@ castcode(Node *child, Type *tp) np->childs[0] = child; return np; } - + Node * unarycode(char op, Type *tp, Node *child) { diff --git a/cc1/decl.c b/cc1/decl.c @@ -15,20 +15,18 @@ struct dcldata { uint8_t op; - union dclunion { - unsigned short nelem; - Symbol *sym; - Funpar *pars; - } u; + unsigned short nelem; + void *data; }; static struct dcldata * -queue(struct dcldata *dp, uint8_t op, union dclunion u) +queue(struct dcldata *dp, uint8_t op, short nelem, void *data) { if (dp->op == 255) error("too much declarators"); dp->op = op; - dp->u = u; + dp->nelem = nelem; + dp->data = data; return dp + 1; } @@ -37,78 +35,88 @@ arydcl(struct dcldata *dp) { expect('['); expect(']'); - return queue(dp, ARY, (union dclunion) {.nelem = 0}); + return queue(dp, ARY, 0, NULL); } -static Type *parameter(void); +static Symbol *parameter(void); static struct dcldata * fundcl(struct dcldata *dp) { - uint8_t n = 0; - Funpar *fp; + size_t siz; + uint8_t n, i, noname; + Type *pars[NR_FUNPARAM], **tp = pars; + Symbol *syms[NR_FUNPARAM], **sp = syms, *sym; + pushctx(); expect('('); + n = noname = 0; do { - Type *tp; - - if ((tp = parameter()) == voidtype) { + if ((sym = parameter()) == NULL) { if (n == 0) break; - else - error("incorrect void parameter"); + error("incorrect void parameter"); } - /* TODO: Use an array and allocate memory at the end */ - fp = xmalloc(sizeof(*fp)); - fp->type = tp; - fp->next = NULL; - if (!dp->u.pars) { - dp->u.pars = fp; - } else { - register Funpar *p, *q; - - for (p = dp->u.pars; q = p->next; p = q) - /* nothing */; - p->next = fp; - } - ++n; + if (n++ == NR_FUNPARAM) + error("too much parameters in function definition"); + *sp++ = sym; + *tp++ = sym->type; + noname |= sym->name[0] == '\0'; } while (accept(',')); -ret: - expect(')');; - return queue(dp, FTN, (union dclunion) {.pars = fp}); + expect(')'); + if (n != 0) { + siz = sizeof(*tp) * n; + tp = memcpy(xmalloc(siz), pars, siz); + } else { + tp = NULL; + } + + if (yytoken != '{') { + /* it is only a prototype */ + popctx(); + } else { + /* it is a function definition */ + if (noname) + error("parameter name omitted"); + sp = syms; + for (i = 0; i < n; ++i) + emitdcl(*sp++); + } + + return queue(dp, FTN, n, tp); } static Symbol * -newiden(void) +newiden(uint8_t ns) { Symbol *sym; extern uint8_t curctx; - if (yylval.sym && yylval.sym->ctx == curctx) + if (yylval.sym && yylval.sym->ctx == curctx && yylval.sym->ns == ns) error("redeclaration of '%s'", yytext); - sym = install(yytext, NS_IDEN); + sym = install(yytext, ns); next(); return sym; } -static struct dcldata *declarator0(struct dcldata *dp); +static struct dcldata *declarator0(struct dcldata *dp, uint8_t ns); static struct dcldata * -directdcl(struct dcldata *dp) +directdcl(struct dcldata *dp, uint8_t ns) { register Symbol *sym; if (accept('(')) { - dp = declarator0(dp); + dp = declarator0(dp, ns); expect(')'); } else { if (yytoken == IDEN || yytoken == TYPEIDEN) - sym = newiden(); + sym = newiden(ns); else - sym = install("", NS_IDEN); - dp = queue(dp, IDEN, (union dclunion) {.sym = sym}); + sym = install("", ns); + dp = queue(dp, IDEN, 0, sym); } for (;;) { @@ -121,7 +129,7 @@ directdcl(struct dcldata *dp) } static struct dcldata* -declarator0(struct dcldata *dp) +declarator0(struct dcldata *dp, uint8_t ns) { register uint8_t n; @@ -130,16 +138,16 @@ declarator0(struct dcldata *dp) /* nothing */; } - dp = directdcl(dp); + dp = directdcl(dp, ns); while (n--) - dp = queue(dp, PTR, (union dclunion) {}); + dp = queue(dp, PTR, 0, NULL); return dp; } static Symbol * -declarator(Type *tp, int8_t flags) +declarator(Type *tp, int8_t flags, uint8_t ns) { struct dcldata data[NR_DECLARATORS+2]; register struct dcldata *bp; @@ -147,19 +155,11 @@ declarator(Type *tp, int8_t flags) memset(data, 0, sizeof(data)); data[NR_DECLARATORS].op = 255; - for (bp = declarator0(data); bp >= data; --bp) { - switch (bp->op) { - case PTR: - tp = mktype(tp, PTR, NULL); - break; - case ARY: - tp = mktype(tp, ARY, &bp->u.nelem); - break; - case FTN: - tp = mktype(tp, FTN, bp->u.pars); - break; - case IDEN: - sym = bp->u.sym; + for (bp = declarator0(data, ns)-1; bp >= data; --bp) { + if (bp->op != IDEN) { + tp = mktype(tp, bp->op, bp->nelem, bp->data); + } else { + sym = bp->data; if (flags == ID_EXPECTED && *sym->name == '\0') error("missed identifier in declaration"); if (flags == ID_FORBIDDEN && *sym->name != '\0') @@ -231,7 +231,7 @@ specifier(int8_t *sclass) if (dcl) { if (size || sign) goto invalid_type; - tp = aggregate(dcl); + tp = (*dcl)(); } else { next(); } @@ -253,9 +253,7 @@ invalid_type: static struct node * initializer(Symbol *sym) { - register Type *tp = sym->type; - - if (!sym->s.isdefined) + if (!sym->isdefined) error("'%s' initialized and declared extern", sym->name); if (accept('{')) { @@ -266,72 +264,14 @@ initializer(Symbol *sym) expr(); } while (accept(',')); } + return NULL; } -/* TODO: bitfields */ - -static void -newfield(Type *tp, Symbol *sym) -{ - register Field *p, *q; - register char *s, *t; - - s = sym->name; - for (q = p = tp->u.fields; p; q = p, p = p->next) { - t = p->name; - if (*s == *t && !strcmp(s, t)) - error("duplicated fields '%s' and '%s'", s, t); - if (sym->u.i == p->id) - error("duplicated enumeration fields '%s' and '%s'", - s, t); - } - - p = xmalloc(sizeof(*p)); - p->name = xstrdup(s); - p->next = NULL; - p->id = sym->id; - p->type = sym->type; - if (!q) - tp->u.fields = p; - else - q->next = p; - - return; -} - -static void -fielddcl(Type *base) -{ - Type *tp; - Symbol *sym; - - switch (yytoken) { - case SCLASS: - error("storage class '%s' in struct/union field", yytext); - case IDEN: case TYPE: case TYPEIDEN: case TQUALIFIER: - tp = specifier(NULL); - case ';': - break; - default: - unexpected(); - } - - if (yytoken != ';') { - do { - sym = declarator(tp, ID_EXPECTED); - newfield(base, sym); - } while (accept(',')); - } - - expect(';'); - return; -} - -static Type * +static Symbol * newtag(uint8_t tag) { register Symbol *sym; - register Type *tp; + static uint8_t ns = NS_STRUCTS; switch (yytoken) { case IDEN: case TYPEIDEN: @@ -343,32 +283,81 @@ newtag(uint8_t tag) sym = install("", NS_TAG); break; } - if (!sym->type) - sym->type = mktype(NULL, tag, NULL); - tp = sym->type; - if (tp->op != tag) + if (!sym->type) { + if (ns == NS_STRUCTS + NR_MAXSTRUCTS) + error("too much tags declared"); + sym->type = mktype(NULL, tag, 0, NULL); + sym->type->ns = ns++; + } + + if (sym->type->op != tag) error("'%s' defined as wrong kind of tag", yytext); - return tp; + return sym; } +/* TODO: bitfields */ + static Type * structdcl(void) { - Type *tp; - uint8_t tag; + Type *tagtype, *buff[NR_MAXSTRUCTS], **bp = &buff[0]; + Symbol *tagsym, *sym; + uint8_t tag, n; + size_t siz; tag = yylval.token; next(); - tp = newtag(tag); - if (accept('{')) { - if (tp->defined) - error("redefinition of struct/union '%s'", yytext); - tp->defined = 1; - while (!accept('}')) - fielddcl(tp); + tagsym = newtag(tag); + tagtype = tagsym->type; + if (!accept('{')) + return tagtype; + + if (tagtype->defined) + error("redefinition of struct/union '%s'", yytext); + tagtype->defined = 1; + emitstruct(tagsym); + + while (!accept('}')) { + Type *base, *tp; + + switch (yytoken) { + case SCLASS: + error("storage class '%s' in struct/union field", + yytext); + case IDEN: case TYPE: case TYPEIDEN: case TQUALIFIER: + base = specifier(NULL); + break; + case ';': + next(); + continue; + default: + unexpected(); + } + + if (accept(';')) + error("identifier expected"); + + do { + sym = declarator(base, ID_EXPECTED, tagtype->ns); + sym->isfield = 1; + tp = sym->type; + if (tp->op == FTN) + error("invalid type in struct/union"); + if (bp == &buff[NR_MAXSTRUCTS]) + error("too much fields in struct/union"); + *bp++ = sym->type; + emitdcl(sym); + } while (accept(',')); + expect(';'); } - return tp; + emitestruct(); + if ((n = bp - buff) != 0) { + siz = sizeof(Type *) * n; + tagtype->n.elem = n; + tagtype->pars = memcpy(xmalloc(siz), buff, siz); + } + return tagtype; } static Type * @@ -379,7 +368,8 @@ enumdcl(void) int val = 0; next(); - tp = newtag(ENUM); + tp = newtag(ENUM)->type; + if (yytoken == ';') return tp; @@ -390,12 +380,11 @@ enumdcl(void) while (yytoken != '}') { if (yytoken != IDEN) unexpected(); - sym = newiden(); + sym = newiden(NS_IDEN); sym->type = inttype; if (accept('=')) initializer(sym); sym->u.i = val++; - newfield(tp, sym); if (!accept(',')) break; } @@ -404,7 +393,7 @@ enumdcl(void) return tp; } -static Type * +static Symbol * parameter(void) { Symbol *sym; @@ -412,21 +401,25 @@ parameter(void) Type *tp; if ((tp = specifier(&sclass)) == voidtype) - return tp; - sym = declarator(tp, ID_ACCEPTED); - sym->s.isdefined = 1; - /* TODO: check type of the parameter */ + return NULL; + sym = declarator(tp, ID_ACCEPTED, NS_IDEN); + sym->isparameter = 1; + tp = sym->type; + if (tp->op == FTN) + error("incorrect function type for a function parameter"); + if (tp->op == ARY) + tp = mktype(tp->type, PTR, 0, NULL); switch (sclass) { case REGISTER: - sym->s.isregister = 1; + sym->isregister = 1; break; case 0: - sym->s.isauto = 1; + sym->isauto = 1; break; default: error("bad storage class in function parameter"); } - return sym->type; + return sym; } void @@ -441,22 +434,21 @@ decl(void) return; do { - sym = declarator(tp, ID_EXPECTED); - sym->s.isdefined = 1; - isfun = sym->type->op != FTN; + sym = declarator(tp, ID_EXPECTED, NS_IDEN); + isfun = sym->type->op == FTN; switch (sclass) { case TYPEDEF: sym->token = TYPEIDEN; continue; case STATIC: - sym->s.isstatic = 1; + sym->isstatic = 1; break; case EXTERN: - sym->s.isdefined = 0; + sym->isdefined = 0; break; case REGISTER: - sym->s.isregister = 1; + sym->isregister = 1; if (isfun) goto bad_function; break; @@ -465,7 +457,7 @@ decl(void) goto bad_function; /* passtrough */ default: - sym->s.isauto = 1; + sym->isauto = 1; break; } if (accept('=')) @@ -490,7 +482,7 @@ typename(void) tp = specifier(&sclass); if (sclass) error("class storage in type name"); - sym = declarator(tp, ID_FORBIDDEN); + sym = declarator(tp, ID_FORBIDDEN, NS_IDEN); return sym->type; } @@ -508,20 +500,19 @@ extdecl(void) if (accept(';')) return; do { - sym = declarator(base, ID_EXPECTED); + sym = declarator(base, ID_EXPECTED, NS_IDEN); tp = sym->type; - sym->s.isstatic = 1; - sym->s.isglobal= 1; - sym->s.isdefined = 1; + sym->isstatic = 1; + sym->isglobal= 1; switch (sclass) { case REGISTER: case AUTO: error("incorrect storage class for file-scope declaration"); case STATIC: - sym->s.isglobal = 0; + sym->isglobal = 0; break; case EXTERN: - sym->s.isdefined = 0; + sym->isdefined = 0; break; case TYPEDEF: sym->token = TYPEIDEN; @@ -535,8 +526,9 @@ extdecl(void) } else if (yytoken == '{') { curfun = sym; emitfun(sym); - context(NULL, NULL, NULL); + compound(NULL, NULL, NULL); emitefun(); + popctx(); return; } } while (accept(',')); diff --git a/cc1/expr.c b/cc1/expr.c @@ -32,7 +32,7 @@ promote(Node *np) if (options.npromote) return np; tp = np->type; - r = tp->u.rank; + r = tp->n.rank; if (r > RANK_UINT || tp == inttype || tp == uinttype) return np; return castcode(np, (r == RANK_UINT) ? uinttype : inttype); @@ -51,7 +51,7 @@ typeconv(Node **p1, Node **p2) tp1 = np1->type; tp2 = np2->type; if (tp1 != tp2) { - if ((n = tp1->u.rank - tp2->u.rank) > 0) + if ((n = tp1->n.rank - tp2->n.rank) > 0) np2 = castcode(np2, tp1); else if (n < 0) np1 = castcode(np1, tp2); @@ -74,7 +74,7 @@ eval(Node *np) { if (!np) return NULL; - if (!ISNODECMP(np)) + if (!ISNODELOG(np)) return np; return ternarycode(np, symcode(one), symcode(zero)); } @@ -114,7 +114,7 @@ integeruop(char op, Node *np) static Node * decay(Node *np) { - return unarycode(OADDR, mktype(np->type, PTR, NULL), np); + return unarycode(OADDR, mktype(np->type, PTR, 0, NULL), np); } /* @@ -292,19 +292,20 @@ logic(char op, Node *np1, Node *np2) static Node * field(Node *np) { - Field *fp; + extern uint8_t lex_ns; + Symbol *sym; - if (yytoken != IDEN) - unexpected(); switch (np->typeop) { case STRUCT: case UNION: - for (fp = np->type->u.fields; fp; fp = fp->next) { - if (!strcmp(fp->name, yytext)) { - next(); - return fieldcode(np, fp); - } - } - error("field '%s' not found", yytext); + lex_ns = np->type->ns; + next(); + if (yytoken != IDEN) + unexpected(); + if ((sym = yylval.sym) == NULL) + error("incorrect field in struct/union"); + lex_ns = NS_IDEN; + next(); + return fieldcode(np, sym); default: error("struct or union expected"); } @@ -376,9 +377,9 @@ address(char op, Node *np) { if (!np->b.lvalue) error("lvalue required in unary expression"); - if (np->b.symbol && np->u.sym->s.isregister) + if (np->b.symbol && np->u.sym->isregister) error("address of register variable '%s' requested", yytext); - return unarycode(op, mktype(np->type, PTR, 0), np); + return unarycode(op, mktype(np->type, PTR, 0, NULL), np); } static Node * @@ -435,8 +436,7 @@ primary(void) expect(')'); break; default: - np = NULL; - break; + unexpected(); } return np; } @@ -483,7 +483,6 @@ postfix(void) case INDIR: np1 = content(OPTR, np1); case '.': - next(); np1 = field(np1); break; case '(': @@ -545,12 +544,12 @@ unary(void) op = (yytoken == INC) ? OA_ADD : OA_SUB; next(); return incdec(unary(), op); - case '!': op = 0; fun = negation; break; - case '+': op = OADD; fun = numericaluop; break; - case '-': op = ONEG; fun = numericaluop; break; - case '~': op = OCPL; fun = integeruop; break; - case '&': op = OADDR; fun = address; break; - case '*': op = OPTR; fun = content; break; + case '!': op = 0; fun = negation; break; + case '+': op = OADD; fun = numericaluop; break; + case '-': op = ONEG; fun = numericaluop; break; + case '~': op = OCPL; fun = integeruop; break; + case '&': op = OADDR; fun = address; break; + case '*': op = OPTR; fun = content; break; default: return postfix(); } @@ -559,15 +558,17 @@ unary(void) } static Node * -cast2(void) +cast(void) { register Node *np1, *np2; register Type *tp; - switch(yytoken) { + if (!accept('(')) + return unary(); + + switch (yytoken) { case TQUALIFIER: case TYPE: tp = typename(); - expect(')'); switch (tp->op) { case ARY: error("cast specify an array type"); @@ -582,17 +583,12 @@ cast2(void) } break; default: - np2 = unary(); - expect(')'); + np2 = expr(); break; } - return np2; -} + expect(')'); -static Node * -cast(void) -{ - return (accept('(')) ? cast2() : unary(); + return np2; } static Node * diff --git a/cc1/lex.c b/cc1/lex.c @@ -10,6 +10,7 @@ #include "cc1.h" static FILE *yyin; +uint8_t lex_ns = NS_IDEN; const char *filename; unsigned linenum; @@ -181,7 +182,7 @@ end_string: *bp = '\0'; sym = install("", NS_IDEN); sym->u.s = xstrdup(buf); - sym->type = mktype(chartype, PTR, 0); + sym->type = mktype(chartype, PTR, 0, NULL); yylval.sym = sym; return STRING; } @@ -202,7 +203,7 @@ iden(void) *bp = '\0'; ungetc(c, yyin); - sym = yylval.sym = lookup(yytext, NS_IDEN); + sym = yylval.sym = lookup(yytext, lex_ns); if (!sym || sym->token == IDEN) return IDEN; yylval.token = sym->u.token; diff --git a/cc1/stmt.c b/cc1/stmt.c @@ -31,24 +31,30 @@ label(char *s, char define) if ((sym = lookup(s, NS_LABEL)) != NULL) { if (define) { - if (sym->s.isdefined) + if (sym->isdefined) error("label '%s' already defined", s); - sym->s.isdefined = 1; + sym->isdefined = 1; } return sym; } sym = install(s, NS_LABEL); - sym->s.isdefined = define; + sym->isdefined = define; return sym; } static void stmtexp(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { - if (yytoken != ';') - emitexp(expr()); + Node *np = NULL;; + + if (yytoken != ';') { + np = expr(); + emitexp(np); + } + expect(';'); + freetree(np); } static Node * @@ -82,6 +88,7 @@ While(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) emitjump(begin, np); emiteloop(); emitlabel(end); + freetree(np); } static void @@ -96,11 +103,11 @@ For(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) expect(FOR); expect('('); - einit = expr(); + einit = (yytoken != ';') ? expr() : NULL; expect(';'); - econd = expr(); + econd = (yytoken != ';') ? expr() : NULL; expect(';'); - einc = expr(); + einc = (yytoken != ')') ? expr() : NULL; expect(')'); emitexp(einit); @@ -113,12 +120,16 @@ For(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) emitjump(begin, econd); emiteloop(); emitlabel(end); + freetree(einit); + freetree(econd); + freetree(einc); } static void Dowhile(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { Symbol *begin, *end; + Node *np; begin = install("", NS_LABEL); end = install("", NS_LABEL); @@ -127,9 +138,11 @@ Dowhile(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) emitlabel(begin); stmt(end, begin, lswitch); expect(WHILE); - emitjump(begin, condition()); + np = condition(); + emitjump(begin, np); emiteloop(); emitlabel(end); + freetree(np); } static void @@ -139,7 +152,7 @@ Return(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) Type *tp = curfun->type->type; expect(RETURN); - np = eval(expr()); + np = (yytoken != ';') ? eval(expr()) : NULL; expect(';'); if (!np) { if (tp != voidtype) @@ -153,6 +166,7 @@ Return(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) } emitret(tp); emitexp(np); + freetree(np); } static void @@ -215,8 +229,7 @@ Switch(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) expect(SWITCH); expect ('('); - if ((cond = expr()) == NULL) - unexpected(); + cond = expr(); if ((cond = convert(cond, inttype, 0)) == NULL) error("incorrect type in switch statement"); expect (')'); @@ -230,11 +243,13 @@ Switch(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) for (p = lcase.head; p; p = next) { emitcase(p->label, p->expr); next = p->next; + freetree(p->expr); free(p); } if (lcase.deflabel) emitdefault(lcase.deflabel); emitlabel(lbreak); + freetree(cond); } static void @@ -246,8 +261,7 @@ Case(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) expect(CASE); if (!lswitch) error("case label not within a switch statement"); - if ((np = expr()) == NULL) - unexpected(); + np = expr(); if ((np = convert(np, inttype, 0)) == NULL) error("incorrect type in case statement"); expect(':'); @@ -291,17 +305,19 @@ If(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) } else { emitlabel(lelse); } + freetree(np); } void compound(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { + pushctx(); expect('{'); + for (;;) { switch (yytoken) { case '}': - next(); - return; + goto end_compound; case TYPEIDEN: if (ahead() == ':') goto statement; @@ -314,15 +330,21 @@ compound(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) stmt(lbreak, lcont, lswitch); } } + +end_compound: + popctx(); + expect('}'); + return; } static void stmt(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { void (*fun)(Symbol *lbreak, Symbol *lcont, Caselist *lswitch); + Node *np; switch (yytoken) { - case '{': fun = context; break; + case '{': fun = compound; break; case RETURN: fun = Return; break; case WHILE: fun = While; break; case FOR: fun = For; break; @@ -340,9 +362,10 @@ stmt(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) break; case '@': next(); - emitprint(expr()); - break; - next(); + np = expr(); + emitprint(np); + freetree(np); + return; } (*fun)(lbreak, lcont, lswitch); } diff --git a/cc1/symbol.c b/cc1/symbol.c @@ -10,8 +10,8 @@ #define NR_SYM_HASH 32 uint8_t curctx; -short localcnt; -short globalcnt; +static short localcnt; +static short globalcnt; static struct symtab { Symbol *head; @@ -38,8 +38,10 @@ freesyms(uint8_t ns) for (sym = tbl->head; sym; sym = next) { if (sym->ctx <= curctx) break; - if (ns == NS_LABEL && !sym->s.isdefined) + if (ns == NS_LABEL && !sym->isdefined) error("label '%s' is not defined", sym->name); + if (ns == NS_TAG) + sym->type->defined = 0; tbl->htab[hash(sym->name)] = sym->hash; next = tbl->head = sym->next; free(sym->name); @@ -47,26 +49,19 @@ freesyms(uint8_t ns) } } -Type * -aggregate(Type * (*fun)(void)) +void +pushctx(void) { - Type *tp; - ++curctx; - tp = (*fun)(); - --curctx; - freesyms(NS_IDEN); - return tp; } void -context(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) +popctx(void) { - ++curctx; - compound(lbreak, lcont, lswitch); --curctx; freesyms(NS_IDEN); freesyms(NS_TAG); + freesyms(NS_STRUCTS); if (curctx == 0) { localcnt = 0; freesyms(NS_LABEL); @@ -79,9 +74,9 @@ lookup(register char *s, uint8_t ns) struct symtab *tbl; register Symbol *sym; - tbl = &symtab[ns]; + tbl = &symtab[(ns > NS_STRUCTS) ? NS_STRUCTS : ns]; for (sym = tbl->htab[hash(s)]; sym; sym = sym->hash) { - if (!strcmp(sym->name, s)) + if (!strcmp(sym->name, s) && sym->ns == ns) return sym; } @@ -99,8 +94,9 @@ install(char *s, uint8_t ns) sym->ctx = curctx; sym->token = IDEN; sym->id = (curctx) ? ++localcnt : ++globalcnt; - sym->s.isdefined = 1; - tbl = &symtab[ns]; + sym->isdefined = 1; + sym->ns = ns; + tbl = &symtab[(ns > NS_STRUCTS) ? NS_STRUCTS : ns]; sym->next = tbl->head; tbl->head = sym; diff --git a/cc1/types.c b/cc1/types.c @@ -23,96 +23,96 @@ Type .op = INT, .letter = L_BOOL, .defined = 1, - .u.rank = RANK_BOOL + .n.rank = RANK_BOOL }, *schartype = &(Type) { .op = INT, .letter = L_SCHAR, .defined = 1, - .u.rank = RANK_SCHAR + .n.rank = RANK_SCHAR }, *uchartype = &(Type) { .op = INT, .letter = L_UCHAR, .sign = 1, .defined = 1, - .u.rank = RANK_UCHAR + .n.rank = RANK_UCHAR }, *chartype = &(Type) { .op = INT, .letter = L_CHAR, .sign = 1, .defined = 1, - .u.rank = RANK_CHAR + .n.rank = RANK_CHAR }, *ushortype = &(Type) { .op = INT, .letter = L_USHORT, .defined = 1, - .u.rank = RANK_USHORT + .n.rank = RANK_USHORT }, *shortype = &(Type) { .op = INT, .letter = L_SHORT, .defined = 1, - .u.rank = RANK_SHORT + .n.rank = RANK_SHORT }, *uinttype = &(Type) { .op = INT, .letter = L_UINT, .sign = 1, .defined = 1, - .u.rank = RANK_UINT + .n.rank = RANK_UINT }, *inttype = &(Type) { .op = INT, .letter = L_INT, .defined = 1, - .u.rank = RANK_INT + .n.rank = RANK_INT }, *longtype = &(Type) { .op = INT, .letter = L_LONG, .defined = 1, - .u.rank = RANK_LONG + .n.rank = RANK_LONG }, *ulongtype = &(Type) { .op = INT, .letter = L_ULONG, .sign = 1, .defined = 1, - .u.rank = RANK_ULONG + .n.rank = RANK_ULONG }, *ullongtype = &(Type) { .op = INT, .letter = L_ULLONG, .sign = 1, .defined = 1, - .u.rank = RANK_ULLONG + .n.rank = RANK_ULLONG }, *llongtype = &(Type) { .op = INT, .letter = L_LLONG, .defined = 1, - .u.rank = RANK_LLONG + .n.rank = RANK_LLONG }, *floattype = &(Type) { .op = FLOAT, .letter = L_FLOAT, .defined = 1, - .u.rank = RANK_FLOAT + .n.rank = RANK_FLOAT }, *doubletype = &(Type) { .op = FLOAT, .letter = L_DOUBLE, .defined = 1, - .u.rank = RANK_DOUBLE + .n.rank = RANK_DOUBLE }, *ldoubletype = &(Type) { .op = FLOAT, .letter = L_LDOUBLE, .defined = 1, - .u.rank = RANK_LDOUBLE + .n.rank = RANK_LDOUBLE }; Type * @@ -186,111 +186,74 @@ invalid_type: } Type * -mktype(Type *tp, uint8_t op, void *data) +mktype(Type *tp, uint8_t op, short nelem, void *data) { - static Type *typetab[NR_TYPE_HASH], **tbl; - static uint8_t t, def; + static Type *typetab[NR_TYPE_HASH], **tbl, type; + static uint8_t t; register Type *bp; - char letter, look; - union typeval u; + static char letters[] = { + [PTR] = L_POINTER, [ARY] = L_ARRAY, + [FTN] = L_FUNCTION, [ENUM] = L_INT, + [STRUCT] = L_STRUCT, [UNION] = L_UNION + }; - switch (op) { - case PTR: - if (tp == voidtype) - return pvoidtype; - letter = L_POINTER; - def = 1; - look = 1; - break; - case ARY: - u.nelem = *(unsigned short *) data; - letter = L_ARRAY; - def = u.nelem != 0; - look = 1; - break; - case FTN: - u.pars = data; - letter = L_FUNCTION; - def = 1; - look = 0; - break; - case ENUM: - letter = L_INT; - def = 1; - look = 0; - break; - case STRUCT: case UNION: - letter = (op == STRUCT) ? L_STRUCT : L_UNION; - def = 0; - look = 0; - u.fields = NULL; - break; - default: - fputs("internal type error, aborting\n", stderr); - abort(); - } + if (op == PTR && tp == voidtype) + return pvoidtype; - t = (op ^ (uint8_t) ((unsigned short) tp >> 3)) - & NR_TYPE_HASH-1; + type.type = tp; + type.op = op; + type.sign = 0; + type.letter = letters[op]; + type.pars = data; + type.n.elem = nelem; + type.ns = 0; + + if (op == ARY && nelem == 0 || op == STRUCT || op == UNION) + type.defined = 0; + else + type.defined = 1; + + t = (op ^ (uint8_t) ((unsigned short) tp >> 3)) & NR_TYPE_HASH-1; tbl = &typetab[t]; - if (look) { - for (bp = *tbl; bp; bp = bp->next) { - if (bp->type == tp && bp->op == op && - (op != ARY || bp->u.nelem == u.nelem)) { - return bp; - } + for (bp = *tbl; bp; bp = bp->next) { + if (eqtype(bp, &type)) { + free(data); + return bp; } } - bp = xcalloc(1, sizeof(*bp)); + bp = xmalloc(sizeof(*bp)); + *bp = type; bp->next = *tbl; - bp->type = tp; - bp->op = op; - bp->letter = letter; - bp->defined = def; - bp->u = u; return *tbl = bp; } bool eqtype(Type *tp1, Type *tp2) { + uint8_t n; + Type **p1, **p2; + if (tp1 == tp2) return 1; - if (tp1->op != tp2->op) + if (tp1->op != tp2->op || tp1->n.elem != tp2->n.elem) return 0; switch (tp1->op) { + case ARY: case PTR: return eqtype(tp1->type, tp2->type); - /* TODO: use the same struct for function parameters and fields */ - case FTN: { - Funpar *fp1 = tp1->u.pars, *fp2 = tp2->u.pars; - - while (fp1 && fp2) { - if (!eqtype(fp1->type, fp2->type)) - break; - fp1 = fp1->next; - fp2 = fp2->next; - } - return fp1 == fp2; - } case UNION: - case STRUCT: { - Field *fp1 = tp1->u.fields, *fp2 = tp2->u.fields; - - while (fp1 && fp2) { - if (!eqtype(fp1->type, fp2->type)) - break; - fp1 = fp1->next; - fp2 = fp2->next; + case STRUCT: + case FTN: + p1 = tp1->pars, p2 = tp2->pars; + for (n = tp1->n.elem; n != 0; --n) { + if (!eqtype(*p1++, *p2++)) + return 0; } - return fp1 == fp2; - } - case ARY: - if (!eqtype(tp1->type, tp2->type)) - return 0; - return tp1->u.nelem == tp2->u.nelem; - case ENUM: case INT: case FLOAT: + return 1; + case ENUM: + /* TODO: Check when two enum are the same type */ + case INT: case FLOAT: return tp1->letter == tp2->letter; default: fputs("internal type error, aborting\n", stderr); diff --git a/cc2/Makefile b/cc2/Makefile @@ -1,5 +1,5 @@ -OBJS = main.o parser.o cgen.o +OBJS = main.o parser.o cgen.o code.o optm.o CPPFLAGS = -I../inc LDFLAGS = -L../lib diff --git a/cc2/cc2.h b/cc2/cc2.h @@ -1,12 +1,16 @@ +typedef struct symbol Symbol; +typedef struct node Node; + typedef struct { short size; uint8_t align; + char letter; bool sign : 1; bool c_int : 1; } Type; -typedef struct symbol { +struct symbol { char *name; bool public : 1; bool extrn : 1; @@ -23,11 +27,12 @@ typedef struct symbol { struct { short locals; short params; + Node **body; } f; } u; -} Symbol; +}; -typedef struct node { +struct node { char op; char subop; Type *type; @@ -39,7 +44,7 @@ typedef struct node { char reg; } u; struct node *left, *right; -} Node; +}; enum nerrors { EINTNUM, /* too much internal identifiers */ @@ -94,7 +99,23 @@ enum nerrors { #define ADDABLE 10 + +enum { + PUSH, POP, LD, ADD, RET, ADDI, LDI, ADDR, ADDX, ADCX, LDX, + LDFX +}; + +enum { + A = 1, B, C, D, E, H, L, IYL, IYH, NREGS, + IXL, IXH, F, I, SP, AF, HL, DE, BC, IX, IY +}; + extern void error(unsigned nerror, ...); -extern void genaddable(Node *list[]); -extern void generate(Symbol *sym, Node *list[]); +extern Node *genaddable(Node *np); +extern void generate(Symbol *fun); extern void genstack(Symbol *fun); +extern void apply(Node *list[], Node *(*fun)(Node *)); +extern Symbol *parse(void); +extern void code(char op, ...); +extern Node *optimize(Node *np); +extern void prtree(Node *np); diff --git a/cc2/cgen.c b/cc2/cgen.c @@ -9,85 +9,10 @@ #include <stdio.h> -/* TODO: Change emit to code */ -enum { - PUSH, POP, LD, ADD, RET, ADDI, LDI, ADDR, ADDX, ADCX, LDX, - LDFX -}; - -enum { - A = 1, B, C, D, E, H, L, IYL, IYH, NREGS, - IXL, IXH, F, I, SP, AF, HL, DE, BC, IX, IY -}; - -static char *opnames[] = { - [PUSH] = "PUSH", [POP] = "POP", [LD] = "LD", [ADD] = "ADD", - [RET] = "RET" , [ADDI]= "ADD", [LDI] = "LD", [ADDX] = "ADD", - [ADCX] = "ADC" , [LDX] = "LD" , [LDFX] = "LD" -}; - -static char *regnames[] = { - [AF] = "AF", [HL] = "HL", [DE] = "DE", [BC] = "BC", [IX] = "IX", - [IY] = "IY", [SP] = "SP", [A] = "A", [F] = "F", [B] = "B", - [C] = "C", [D] = "D", [E] = "E", [H] = "H", [L] = "L", - [IXL]= "IXL",[IXH]= "IXH",[IYL]= "IYL",[IYH]= "IYH", [I] = "I" -}; - static bool reguse[NREGS]; static char upper[] = {[DE] = D, [HL] = H, [BC] = B, [IX] = IXH, [IY] = IYH}; static char lower[] = {[DE] = E, [HL] = L, [BC] = C, [IX] = IXL, [IY] = IYL}; -void -emit(char op, ...) -{ - va_list va; - uint8_t reg1, reg2; - TINT imm; - short off; - char *label; - - va_start(va, op); - switch (op) { - case RET: - printf("\t%s\n", opnames[op]); - break; - case PUSH: case POP: - reg1 = va_arg(va, int); - printf("\t%s\t%s\n", opnames[op], regnames[reg1]); - break; - case ADD: case LD: - reg1 = va_arg(va, int); - reg2 = va_arg(va, int); - printf("\t%s\t%s,%s\n", - opnames[op], regnames[reg1], regnames[reg2]); - break; - case ADDI: case LDI: - reg1 = va_arg(va, int); - imm = va_arg(va, int); - printf("\t%s\t%s,%d\n", opnames[op], regnames[reg1], imm); - break; - case ADDX: case ADCX: case LDFX: - reg1 = va_arg(va, int); - reg2 = va_arg(va, int); - off = va_arg(va, int); - printf("\t%s\t%s,(%s%+d)\n", - opnames[op], regnames[reg1], regnames[reg2], off); - break; - case LDX: - reg1 = va_arg(va, int); - off = va_arg(va, int); - reg2 = va_arg(va, int); - printf("\t%s\t(%s%+d),%s\n", - opnames[op], regnames[reg1], off, regnames[reg2]); - break; - case ADDR: - label = va_arg(va, char *); - printf("%s:\n", label); - break; - } - - va_end(va); -} static char allocreg(Node *np) @@ -136,11 +61,11 @@ move(Node *np) sym = np->u.sym; switch (tp->size) { case 1: - emit(LDFX, reg, IX, sym->u.v.off); + code(LDFX, reg, IX, sym->u.v.off); break; case 2: - emit(LDFX, lower[reg], IX, sym->u.v.off); - emit(LDFX, upper[reg], IX, sym->u.v.off+1); + code(LDFX, lower[reg], IX, sym->u.v.off); + code(LDFX, upper[reg], IX, sym->u.v.off+1); break; case 4: case 8: @@ -168,7 +93,7 @@ conmute(Node *np) } static void -cgen(Node *np) +cgen(Node *np, Node *parent) { Node *lp, *rp; TINT imm; @@ -179,25 +104,26 @@ cgen(Node *np) lp = np->left; rp = np->right; if (np->addable >= ADDABLE) { + if (parent && parent->op == OASSIG) + return; move(np); return; } if (!lp) { - cgen(rp); + cgen(rp, np); } else if (!rp) { - cgen(lp); + cgen(lp, np); } else { Node *p, *q; if (lp->complex > rp->complex) p = lp, q = rp; else p = rp, q = lp; - cgen(p); - cgen(q); + cgen(p, np); + cgen(q, np); } - assert(lp && lp->op == REG || rp && rp->op == REG); switch (np->op) { case OADD: switch (np->type->size) { @@ -208,10 +134,12 @@ cgen(Node *np) rp = np->right; } else if (lp->u.reg != A) { /* TODO: Move A to variable */ - emit(PUSH, AF); - emit(LD, A, lp->u.reg); + code(PUSH, AF); + code(LD, A, lp->u.reg); } - emit(ADD, A, rp->u.reg); + code(ADD, A, rp->u.reg); + np->op = REG; + np->u.reg = A; break; case 2: if (rp->u.reg == HL || rp->u.reg == IY) { @@ -220,62 +148,88 @@ cgen(Node *np) rp = np->right; } else if (lp->u.reg != HL && lp->u.reg != IY) { /* TODO: Move HL to variable */ - emit(PUSH, HL); - emit(LD, H, upper[lp->u.reg]); - emit(LD, L, lower[lp->u.reg]); + code(PUSH, HL); + code(LD, H, upper[lp->u.reg]); + code(LD, L, lower[lp->u.reg]); } - emit(ADD, lp->u.reg, rp->u.reg); + code(ADD, lp->u.reg, rp->u.reg); + np->op = REG; + np->u.reg = lp->u.reg; break; case 4: case 8: abort(); } break; + case OASSIG: + switch (np->type->size) { + case 1: + switch (lp->op) { + case AUTO: + code(LDX, IX, lp->u.sym->u.v.off, rp->u.reg); + break; + case REG: + case MEM: + default: + abort(); + } + break; + default: + abort(); + } + break; default: abort(); } } +static Node * +applycgen(Node *np) +{ + cgen(np, NULL); + return NULL; +} + void -generate(Symbol *sym, Node *list[]) +generate(Symbol *fun) { extern char odebug; - Node *np; - char frame = sym->u.f.locals != 0 || odebug; + char frame = fun->u.f.locals != 0 || odebug; - emit(ADDR, sym->name); + code(ADDR, fun->name); if (frame) { - emit(PUSH, IX); - emit(LD, IX, SP); - emit(LDI, HL, -sym->u.f.locals); - emit(ADD, HL, SP); - emit(LD, SP, HL); + code(PUSH, IX); + code(LD, IX, SP); + code(LDI, HL, -fun->u.f.locals); + code(ADD, HL, SP); + code(LD, SP, HL); } - while (np = *list++) - cgen(np); + apply(fun->u.f.body, applycgen); if (frame) { - emit(LD, SP, IX); - emit(POP, IX); - emit(RET); + code(LD, SP, IX); + code(POP, IX); + code(RET); } } /* + * This is strongly influenced by + * http://plan9.bell-labs.com/sys/doc/compiler.ps * calculate addresability as follows * AUTO => 11 value+fp * REGISTER => 13 register * STATIC => 12 (value) * CONST => 20 $value */ -static void -xaddable(Node *np) +Node * +genaddable(Node *np) { Node *lp, *rp; if (!np) - return; + return np; np->complex = 0; np->addable = 0; @@ -296,14 +250,14 @@ xaddable(Node *np) break; default: if (lp) - xaddable(lp); + genaddable(lp); if (rp) - xaddable(rp); + genaddable(rp); break; } if (np->addable > 10) - return; + return np; if (lp) np->complex = lp->complex; if (rp) { @@ -316,15 +270,5 @@ xaddable(Node *np) } if (np->complex == 0) ++np->complex; - return; + return np; } - -void -genaddable(Node *list[]) -{ - Node *np; - - while (np = *list++) - xaddable(np); -} - diff --git a/cc2/code.c b/cc2/code.c @@ -0,0 +1,69 @@ + +#include <stdarg.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> + +#include <cc.h> +#include "cc2.h" + + +static char *opnames[] = { + [PUSH] = "PUSH", [POP] = "POP", [LD] = "LD", [ADD] = "ADD", + [RET] = "RET" , [ADDI]= "ADD", [LDI] = "LD", [ADDX] = "ADD", + [ADCX] = "ADC" , [LDX] = "LD" , [LDFX] = "LD" +}; + +static char *regnames[] = { + [AF] = "AF", [HL] = "HL", [DE] = "DE", [BC] = "BC", [IX] = "IX", + [IY] = "IY", [SP] = "SP", [A] = "A", [F] = "F", [B] = "B", + [C] = "C", [D] = "D", [E] = "E", [H] = "H", [L] = "L", + [IXL]= "IXL",[IXH]= "IXH",[IYL]= "IYL",[IYH]= "IYH", [I] = "I" +}; + +static char *opfmt[] = { + [RET] = "\to", + [PUSH] = "\to\tr", + [POP] = "\to\tr", + [ADD] = "\to\tr,r", + [LD] = "\to\tr,r", + [ADDI] = "\to\tr,i", + [LDI] = "\to\tr,i", + [ADDX] = "\to\tr,(r+i)", + [ADCX] = "\to\tr,(r+i)", + [LDFX] = "\to\tr,(r+i)", + [LDX] = "\to\t(r+i),r", + [ADDR] = "a:" +}; + +void +code(char op, ...) +{ + va_list va; + char *cp, c; + + va_start(va, op); + for (cp = opfmt[op]; c = *cp; ++cp) { + switch (c) { + case 'o': + fputs(opnames[op], stdout); + break; + case 'r': + fputs(regnames[va_arg(va, int)], stdout); + break; + case 'i': + printf("%d", va_arg(va, int)); + break; + case 'a': + fputs(va_arg(va, char *), stdout); + break; + default: + putchar(c); + break; + } + } + putchar('\n'); + + va_end(va); +} diff --git a/cc2/main.c b/cc2/main.c @@ -9,8 +9,6 @@ #include "cc2.h" #include "error.h" -extern void parse(void); - char odebug; void @@ -30,5 +28,11 @@ error(unsigned nerror, ...) int main(void) { - parse(); + Symbol *fun; + + while (!feof(stdin) && (fun = parse())) { + apply(fun->u.f.body, optimize); + apply(fun->u.f.body, genaddable); + generate(fun); + } } diff --git a/cc2/optm.c b/cc2/optm.c @@ -0,0 +1,43 @@ + +#include <stddef.h> +#include <stdint.h> + +#include <cc.h> +#include "cc2.h" + + +#include <stdio.h> + +static Node * +optcasts(Node *np, Type *tp) +{ + if (!np) + return NULL; + +repeat: + switch (np->op) { + case OCAST: + /* TODO: be careful with the sign */ + if (np->type->c_int && np->type->size >= tp->size) { + np = np->left; + goto repeat; + } + break; + case OASSIG: + tp = np->type; + break; + default: + np->type = tp; + } + + np->left = optcasts(np->left, tp); + np->right = optcasts(np->right, tp); + return np; +} + +Node * +optimize(Node *np) +{ + np = optcasts(np, np->type); + return np; +} diff --git a/cc2/parser.c b/cc2/parser.c @@ -20,12 +20,13 @@ enum { }; static Symbol *curfun; -static Node *stack[NR_STACKSIZ], **stackp = stack; -static Node *listexp[NR_EXPRESSIONS], **listp = listexp; -static Node nodepool[NR_NODEPOOL], *newp = nodepool; +static Node *stack[NR_STACKSIZ], **stackp; +static Node *listexp[NR_EXPRESSIONS], **listp; +static Node nodepool[NR_NODEPOOL], *newp; Type l_int8 = { + .letter = L_INT8, .size = 1, .align = 2, .sign = 1, @@ -33,6 +34,7 @@ Type l_int8 = { }; Type l_int16 = { + .letter = L_INT16, .size = 2, .align = 2, .sign = 1, @@ -40,6 +42,7 @@ Type l_int16 = { }; Type l_int32 = { + .letter = L_INT32, .size = 4, .align = 4, .sign = 1, @@ -47,6 +50,7 @@ Type l_int32 = { }; Type l_int64 = { + .letter = L_INT64, .size = 8, .align = 8, .sign = 1, @@ -54,29 +58,60 @@ Type l_int64 = { }; Type l_uint8 = { + .letter = L_UINT8, .size = 1, .align = 2, .c_int = 1, }; Type l_uint16 = { + .letter = L_UINT16, .size = 2, .align = 2, .c_int = 1, }; Type l_uint32 = { + .letter = L_UINT32, .size = 4, .align = 4, .c_int = 1, }; Type l_uint64 = { + .letter = L_UINT64, .size = 8, .align = 8, .c_int = 1, }; + +static void +prnode(Node *np) +{ + if (np->left) + prnode(np->left); + if (np->right) + prnode(np->right); + fprintf(stderr, "\t%c%c", np->op, np->type->letter); +} + +void +prtree(Node *np) +{ + prnode(np); + putc('\n', stderr); +} + +void +apply(Node *list[], Node *(*fun)(Node *)) +{ + Node *np; + + while (np = *list) + *list++ = (*fun)(np); +} + static Symbol * parameter(char *num) { @@ -390,17 +425,6 @@ deflabel(char *token) sym->u.l.addr = listp - listexp; } -static void -endfunction(char *token) -{ - if (!curfun) - error(ESYNTAX); - listp = NULL; - genaddable(listexp); - generate(curfun, listexp); - curfun = NULL; -} - static Symbol * declaration(uint8_t t, char class, char *token) { @@ -444,7 +468,7 @@ globdcl(char *token) sym->type = FUN; curfun = sym; - listp = listexp; + sym->u.f.body = listp = listexp; newp = nodepool; } @@ -464,7 +488,7 @@ localdcl(char *token) sym->u.v.off = 1-curfun->u.f.locals; } -void +Symbol * parse(void) { void (*fun)(char *tok); @@ -472,6 +496,11 @@ parse(void) int c; char line[MAXLINE]; + curfun = NULL; + stackp = stack; + listp = listexp; + newp = nodepool; + for (;;) { switch (c = getchar()) { case 'L': @@ -493,10 +522,15 @@ parse(void) fun = globdcl; break; case '}': - fun = endfunction; - break; + if (!curfun) + error(ESYNTAX); + return curfun; case EOF: - goto found_eof; + if (ferror(stdin)) + error(EFERROR, strerror(errno)); + if (curfun) + goto syntax_error; + return NULL; case '\n': continue; default: @@ -514,11 +548,10 @@ parse(void) } found_eof: - if (ferror(stdin)) - error(EFERROR, strerror(errno)); - if (!curfun) - return; + + if (!curfun) + return curfun; syntax_error: error(ESYNTAX); }