scc

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

commit 8d3c95abbdf285aa5a820607c5d4c32ab3dff70d
parent b09facc71149bd600d32d2c063c762e78340bda9
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Thu, 24 Apr 2014 17:30:34 +0200

Add switch statement

Diffstat:
Mcc1.h | 4+++-
Mcode.c | 23+++++++++++++++++++++++
Mstmt.c | 27+++++++++++++++++++++++++++
3 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/cc1.h b/cc1.h @@ -231,7 +231,9 @@ extern void emitsym(Node *), emitunary(Node *), emitbin(Node *), emitexp(Node *), emitprint(Node *), emitlabel(Symbol *), emitjump(Symbol *, Node *), - emitbloop(void), emiteloop(void); + emitbloop(void), emiteloop(void), + emitswitch(short, Node *), emitcase(Symbol *, Node *), + emitdefault(Symbol *); extern Node *node(void (*code)(Node *), diff --git a/code.c b/code.c @@ -235,6 +235,29 @@ emitjump(Symbol *sym, Node *np) emitexp(np); } +void +emitswitch(short nr, Node *np) +{ + printf("\teI\t#%0x", nr); + emitexp(np); +} + +void +emitcase(Symbol *sym, Node *np) +{ + fputs("\tw", stdout); + (*np->code)(np); + putchar('\t'); + emitlabel(sym); +} + +void +emitdefault(Symbol *sym) +{ + fputs("\tf\t", stdout); + emitlabel(sym); +} + Node * castcode(Node *child, Type *tp) { diff --git a/stmt.c b/stmt.c @@ -8,11 +8,13 @@ struct scase { int val; Symbol *label; + Node *expr; struct scase *next; }; struct caselist { short nr; + Symbol *deflabel; struct scase *head; }; @@ -199,6 +201,30 @@ Goto(void) expect(';'); } +static void +Switch(Symbol *lcont) +{ + Caselist lcase = {.nr = 0, .head = NULL, .deflabel = NULL}; + struct scase *p; + Symbol *lbreak = label(NULL, 1), *lcond = label(NULL, 1); + Node *cond; + + expect(SWITCH); + expect ('('); + cond = eval(expr()); + expect (')'); + /* TODO: check integer type */ + emitjump(lcond, NULL); + stmt(lbreak, lcont, &lcase); + emitlabel(lcond); + emitswitch(lcase.nr, cond); + for (p = lcase.head; p; p = p->next) + emitcase(p->label, p->expr); + if (lcase.deflabel) + emitdefault(lcase.deflabel); + emitlabel(lbreak); +} + void compound(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { @@ -231,6 +257,7 @@ repeat: case BREAK: Break(lbreak); break; case CONTINUE: Continue(lcont); break; case GOTO: Goto(); break; + case SWITCH: Switch(lcont); break; case IDEN: if (ahead() == ':') { Label();