shithub: scc

Download patch

ref: 8d3c95abbdf285aa5a820607c5d4c32ab3dff70d
parent: b09facc71149bd600d32d2c063c762e78340bda9
author: Roberto E. Vargas Caballero <[email protected]>
date: Thu Apr 24 13:30:34 EDT 2014

Add switch statement

--- a/cc1.h
+++ b/cc1.h
@@ -231,7 +231,9 @@
 	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 *),
--- a/code.c
+++ b/code.c
@@ -235,6 +235,29 @@
 		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)
 {
--- 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 @@
 	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 @@
 	case BREAK:    Break(lbreak); break;
 	case CONTINUE: Continue(lcont); break;
 	case GOTO:     Goto(); break;
+	case SWITCH:   Switch(lcont); break;
 	case IDEN:
 		if (ahead() == ':') {
 			Label();