From e9ff1c6fbbbac9ece2604876ab589ac282360446 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Mon, 15 Nov 2021 15:08:03 -0800 Subject: Feat: added if/else branching and switch statement Unsure about my modification to the language. I found the parsing of the case body within switches to be odd - specifically that it parses liberally and then checks that it has case -> cmd structuring while it walks the code. This means the language is more permissive than the semantics. I modified it to be more explicit, but at the cost of having to end each case statement with a semicolon. I wanted a colon, but this is a valid word character and thus will be lexed as part of the word. --- src/cmd/rc/code.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 75 insertions(+), 8 deletions(-) (limited to 'src/cmd/rc/code.c') diff --git a/src/cmd/rc/code.c b/src/cmd/rc/code.c index 786f284..7077a0e 100644 --- a/src/cmd/rc/code.c +++ b/src/cmd/rc/code.c @@ -38,12 +38,14 @@ storepc(int a) interpreter.code[a].i = interpreter.i; } +void yyerror(const char *msg); + static void walk(Tree *node) { - Tree *n; - int addr1, addr2; + Tree *n, *c; + int addr1, addr2, addr3; if(!node) return; @@ -127,6 +129,7 @@ walk(Tree *node) case Tbang: walk(node->child[0]); emitf(Xbang); + break; case Tword: emitf(Xword); @@ -164,17 +167,78 @@ walk(Tree *node) node = n; break; /* control structures */ + case Tif: + walk(node->child[0]); // condition + emitf(Xtrue); + addr1 = emiti(0); + walk(node->child[1]); // if body + if(!node->child[2]) // no else + storepc(addr1); + else{ + emitf(Xgoto); + addr2 = emiti(0); + storepc(addr1); + walk(node->child[2]); + storepc(addr2); + } + break; + + case Tswitch: + /* NOTE: + * there are 3 addresses to store + * 1. addr1 = address to next case + * 2. addr2 = address to jump end instruction + * 3. addr3 = address of switch end + */ + emitf(Xmark); + walk(node->child[0]); // word we match to + emitf(Xgoto); // next case + addr1 = emiti(0); + addr2 = emitf(Xgoto); // switch end + addr3 = emiti(0); + storepc(addr1); + + // XXX: anyway to make this explicit in parser? + if(!(n = node->child[1])) + yyerror("empty switch statement"); + + emitcase: + if(!n) + goto donecase; + else if(n->type == ';'){ + c = n->child[0]; + n = n->child[1]; + }else if(n->type == Tcase){ + c = n; + n = nil; + }else + panicf("bad node type %d\n", n->type); + + emitf(Xmark); + walk(c->child[0]); // words + emitf(Xcase); + addr1 = emiti(0); // next case + walk(c->child[1]); // commands + emitf(Xgoto); + emiti(addr2); + storepc(addr1); + + goto emitcase; + donecase: + storepc(addr3); + break; + case Twhile: - addr1 = interpreter.i; // head of loop + addr1 = interpreter.i; // head of loop walk(node->child[0]); - if(addr1 == interpreter.i) - fatal("TODO"); + if(addr1 == interpreter.i) // empty condition => while(true) + emitf(Xsettrue); emitf(Xtrue); - addr2 = emiti(0); // goto end of loop + addr2 = emiti(0); // goto end of loop walk(node->child[1]); emitf(Xgoto); - emiti(addr1); // goto top of loop + emiti(addr1); // goto top of loop storepc(addr2); break; @@ -184,7 +248,10 @@ walk(Tree *node) walk(node->child[1]); // emitf(Xglob) }else{ // for(X) - fatal("TODO"); + emitf(Xmark); + emitf(Xword); + emits(strdup("*")); + emitf(Xdollar); } emitf(Xmark); // null initial value for Xlocal emitf(Xmark); -- cgit v1.2.1