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:
M | cc1.h | | | 4 | +++- |
M | code.c | | | 23 | +++++++++++++++++++++++ |
M | stmt.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();