From b8c3bf57d15f57dddc04283a8467435242b2d3fb Mon Sep 17 00:00:00 2001 From: CPunch Date: Mon, 26 Jul 2021 14:50:08 -0500 Subject: [PATCH] Added for loops, bug fixes and misc. refactoring - Added a nice wrapper for compileExpression, compileVoidExpression() which does some optimizations and leaves nothing on the stack - TOKEN_FOR, NODE_STATE_FOR were added to the lexer, parser & compiler --- main.uxc | 8 +++--- src/main.c | 2 ++ src/uasm.c | 79 +++++++++++++++++++++++++++++++++++++++------------- src/ulex.c | 1 + src/ulex.h | 1 + src/uparse.c | 33 +++++++++++++++++++++- src/uparse.h | 8 ++++++ 7 files changed, 107 insertions(+), 25 deletions(-) diff --git a/main.uxc b/main.uxc index 79c70ba..cb3a12d 100644 --- a/main.uxc +++ b/main.uxc @@ -1,5 +1,5 @@ -int i = 0; -while (i < 10) { +int i; +for (i = 0; i < 10; i = i + 1) prntint i; - i = i + 1; -} \ No newline at end of file + +prntint 0xFFFF; \ No newline at end of file diff --git a/src/main.c b/src/main.c index ca8544d..6951e89 100755 --- a/src/main.c +++ b/src/main.c @@ -54,5 +54,7 @@ int main(int argc, const char *argv[]) { /* clean up */ UP_freeTree((UASTNode*)tree); free(src); + + printf("Compiled successfully! Wrote generated uxntal to %s\n", out); return 0; } \ No newline at end of file diff --git a/src/uasm.c b/src/uasm.c index a18b64c..61ce1c2 100755 --- a/src/uasm.c +++ b/src/uasm.c @@ -262,8 +262,10 @@ void defineSubLbl(UCompState *state, int subLblID) { fprintf(state->out, "&lbl%d\n", subLblID); } +/* expects TYPE_BOOL at the top of the stack */ void jmpCondSub(UCompState *state, int subLblID) { fprintf(state->out, ",&lbl%d JCN\n", subLblID); + state->pushed -= SIZE_BOOL; } void jmpSub(UCompState *state, int subLblID) { @@ -384,6 +386,19 @@ UVarType compileExpression(UCompState *state, UASTNode *node) { return lType; } +/* compile an expression without leaving anything on the stack */ +void compileVoidExpression(UCompState *state, UASTNode *node) { + int savedPushed = state->pushed; + + if (node->type == NODE_ASSIGN) + compileAssignment(state, node, 0); + else + compileExpression(state, node); + + /* clean the stack */ + pop(state, state->pushed - savedPushed); +} + void compilePrintInt(UCompState *state, UASTNode *node) { compileExpression(state, node->left); fwrite(";print-decimal JSR2 #20 .Console/char DEO\n", 42, 1, state->out); @@ -422,20 +437,19 @@ void compileIf(UCompState *state, UASTNode *node) { UVarType type = compileExpression(state, node->left); if (!tryTypeCast(state, type, TYPE_BOOL)) - cErrorNode(state, (UASTNode*)ifNode, "Cannot cast type '%s' to type '%s'", getTypeName(type), getTypeName(TYPE_BOOL)); + cErrorNode(state, (UASTNode*)node->left, "Cannot cast type '%s' to type '%s'", getTypeName(type), getTypeName(TYPE_BOOL)); - state->pushed -= SIZE_BOOL; if (ifNode->elseBlock) { int tmpJmp = jmpID; - /* write comparison jump, if the flag is equal to true, skip the else statements */ + /* write comparison jump, if the flag is equal to true, jump to the true block */ jmpCondSub(state, tmpJmp); compileAST(state, ifNode->elseBlock); - jmpCondSub(state, jmpID = newLbl(state)); + jmpSub(state, jmpID = newLbl(state)); /* skip the true block */ /* true block */ defineSubLbl(state, tmpJmp); compileAST(state, ifNode->block); } else { - /* write comparison jump, if the flag is not equal to true, skip the true statements */ + /* write comparison jump, if the flag is not equal to true, skip the true block */ fprintf(state->out, "#01 NEQ "); jmpCondSub(state, jmpID); compileAST(state, ifNode->block); @@ -445,7 +459,7 @@ void compileIf(UCompState *state, UASTNode *node) { } void compileWhile(UCompState *state, UASTNode *node) { - UASTWhileNode *ifNode = (UASTWhileNode*)node; + UASTWhileNode *whileNode = (UASTWhileNode*)node; int loopStart = newLbl(state); int loopExit = newLbl(state); @@ -454,14 +468,47 @@ void compileWhile(UCompState *state, UASTNode *node) { UVarType type = compileExpression(state, node->left); if (!tryTypeCast(state, type, TYPE_BOOL)) - cErrorNode(state, (UASTNode*)ifNode, "Cannot cast type '%s' to type '%s'", getTypeName(type), getTypeName(TYPE_BOOL)); + cErrorNode(state, node, "Cannot cast type '%s' to type '%s'", getTypeName(type), getTypeName(TYPE_BOOL)); /* write comparison jump, if the flag is not equal to true, exit the loop */ fprintf(state->out, "#01 NEQ "); jmpCondSub(state, loopExit); - state->pushed -= SIZE_BOOL; - compileAST(state, ifNode->block); + compileAST(state, whileNode->block); + + /* jump back to the start of the loop */ + jmpSub(state, loopStart); + defineSubLbl(state, loopExit); +} + +void compileFor(UCompState *state, UASTNode *node) { + UVarType type; + UASTForNode *forNode = (UASTForNode*)node; + int loopEntry = newLbl(state); + int loopStart = newLbl(state); + int loopExit = newLbl(state); + + /* compile initalizer */ + compileVoidExpression(state, node->left); + jmpSub(state, loopEntry); /* on entry, we skip the iterator */ + + /* compile iterator */ + defineSubLbl(state, loopStart); + compileVoidExpression(state, forNode->iter); + + /* compile conditional */ + defineSubLbl(state, loopEntry); + type = compileExpression(state, forNode->cond); + + if (!tryTypeCast(state, type, TYPE_BOOL)) + cErrorNode(state, node, "Cannot cast type '%s' to type '%s'", getTypeName(type), getTypeName(TYPE_BOOL)); + + /* write comparison jump, if the flag is not equal to true, exit the loop */ + fprintf(state->out, "#01 NEQ "); + jmpCondSub(state, loopExit); + + /* finally, compile loop block */ + compileAST(state, forNode->block); /* jump back to the start of the loop */ jmpSub(state, loopStart); @@ -471,26 +518,18 @@ void compileWhile(UCompState *state, UASTNode *node) { void compileAST(UCompState *state, UASTNode *node) { /* STATE nodes hold the expression in node->left, and the next expression in node->right */ while (node) { - int startPushed = state->pushed; - switch(node->type) { + switch(node->type) { /* these functions should NOT leave any values on the stack */ case NODE_STATE_PRNT: compilePrintInt(state, node); break; case NODE_STATE_DECLARE_VAR: compileDeclaration(state, node); break; - case NODE_STATE_EXPR: - if (node->left->type == NODE_ASSIGN) - compileAssignment(state, node->left, 0); - else - compileExpression(state, node->left); - break; + case NODE_STATE_EXPR: compileVoidExpression(state, node->left); break; case NODE_STATE_SCOPE: compileScope(state, node); break; case NODE_STATE_IF: compileIf(state, node); break; case NODE_STATE_WHILE: compileWhile(state, node); break; + case NODE_STATE_FOR: compileFor(state, node); break; default: cError(state, "unknown statement node!! [%d]\n", node->type); } - /* clean the stack */ - pop(state, state->pushed - startPushed); - /* move to the next statement */ node = node->right; } diff --git a/src/ulex.c b/src/ulex.c index 9a403e9..9b6ea93 100755 --- a/src/ulex.c +++ b/src/ulex.c @@ -13,6 +13,7 @@ UReservedWord reservedWords[] = { {TOKEN_VOID, "void", 4}, {TOKEN_BOOL, "bool", 4}, {TOKEN_WHILE, "while", 5}, + {TOKEN_FOR, "for", 3}, {TOKEN_PRINTINT, "prntint", 7}, {TOKEN_IF, "if", 2}, {TOKEN_ELSE, "else", 4}, diff --git a/src/ulex.h b/src/ulex.h index 71d5a65..dbcdb14 100755 --- a/src/ulex.h +++ b/src/ulex.h @@ -11,6 +11,7 @@ typedef enum { TOKEN_IF, TOKEN_ELSE, TOKEN_WHILE, + TOKEN_FOR, /* literals */ TOKEN_IDENT, diff --git a/src/uparse.c b/src/uparse.c index cb0dde1..b5da7e8 100755 --- a/src/uparse.c +++ b/src/uparse.c @@ -224,6 +224,7 @@ ParseRule ruleTable[] = { {NULL, NULL, PREC_NONE}, /* TOKEN_IF */ {NULL, NULL, PREC_NONE}, /* TOKEN_ELSE */ {NULL, NULL, PREC_NONE}, /* TOKEN_WHILE */ + {NULL, NULL, PREC_NONE}, /* TOKEN_FOR */ /* literals */ {identifer, NULL, PREC_LITERAL}, /* TOKEN_IDENT */ @@ -373,7 +374,34 @@ UASTNode* whileStatement(UParseState *state) { if (!match(state, TOKEN_RIGHT_PAREN)) error(state, "Expected ')' to end while conditional!"); - /* parse the true block */ + /* parse the loop block */ + node->block = statement(state); + return (UASTNode*)node; +} + +UASTNode* forStatement(UParseState *state) { + UASTForNode *node = (UASTForNode*)newBaseNode(state, state->previous, sizeof(UASTForNode), NODE_STATE_FOR, NULL, NULL); + + if (!match(state, TOKEN_LEFT_PAREN)) + error(state, "Expected '(' to start for initalizer!"); + + /* set the initalizer */ + node->_node.left = expression(state); + + if (!match(state, TOKEN_COLON)) + error(state, "Expected ';' to start for conditional!"); + + node->cond = expression(state); + + if (!match(state, TOKEN_COLON)) + error(state, "Expected ';' to start for iterator!"); + + node->iter = expression(state); + + if (!match(state, TOKEN_RIGHT_PAREN)) + error(state, "Expected ')' to end for iterator!"); + + /* parse the loop block */ node->block = statement(state); return (UASTNode*)node; } @@ -404,6 +432,8 @@ UASTNode* statement(UParseState *state) { return ifStatement(state); } else if (match(state, TOKEN_WHILE)) { return whileStatement(state); + } else if (match(state, TOKEN_FOR)) { + return forStatement(state); } else { UToken tkn = state->previous; /* no statement match was found, just parse the expression */ @@ -437,6 +467,7 @@ void printNode(UASTNode *node) { case NODE_STATE_DECLARE_VAR: printf("NVAR"); break; case NODE_STATE_IF: printf("IF"); break; case NODE_STATE_WHILE: printf("WHIL"); break; + case NODE_STATE_FOR: printf("FOR"); break; case NODE_VAR: printf("VAR[%d]", ((UASTVarNode*)node)->var); break; case NODE_STATE_EXPR: printf("EXPR"); break; default: break; diff --git a/src/uparse.h b/src/uparse.h index 862c7c2..8cb94ea 100755 --- a/src/uparse.h +++ b/src/uparse.h @@ -35,6 +35,7 @@ typedef enum { NODE_STATE_EXPR, NODE_STATE_IF, NODE_STATE_WHILE, + NODE_STATE_FOR, /* scopes are different, node->left holds the statement tree for the scope, node->right holds the next statement */ NODE_STATE_SCOPE, } UASTNodeType; @@ -99,6 +100,13 @@ typedef struct { UASTNode *block; } UASTWhileNode; +typedef struct { + COMMON_NODE_HEADER; + UASTNode *cond; + UASTNode *iter; + UASTNode *block; +} UASTForNode; + typedef struct { /* lexer related info */ ULexState lstate;