diff --git a/examples/bf.nct b/examples/bf.nct index a3f6944..3433a78 100644 --- a/examples/bf.nct +++ b/examples/bf.nct @@ -50,8 +50,7 @@ loop { } codePtr = codePtr + 1; } - } - if(data[dataPtr] != 0) { + } else { stckPtr = stckPtr + 1; stck[stckPtr] = codePtr; } @@ -62,8 +61,7 @@ loop { if(code[codePtr] == 93) { if(data[dataPtr] == 0) { stckPtr = stckPtr - 1; - } - if(data[dataPtr] != 0) { + } else { codePtr = stck[stckPtr]; } } @@ -72,4 +70,4 @@ loop { } codePtr = codePtr + 1; -} \ No newline at end of file +} diff --git a/examples/if.nct b/examples/if.nct index 92a2a00..89f0b3b 100644 --- a/examples/if.nct +++ b/examples/if.nct @@ -2,4 +2,6 @@ u16 x: 5; if(x != 0) { x = 2; +} else { + x = 5; } diff --git a/src/ast.c b/src/ast.c index 3a7389a..7045f25 100644 --- a/src/ast.c +++ b/src/ast.c @@ -34,6 +34,9 @@ void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, v } else if(n->nodeKind == AST_STMT_IF) { generic_visitor(&n->stmtIf.expression, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); generic_visitor(&n->stmtIf.then, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); + if(n->stmtIf.elss) { + generic_visitor(&n->stmtIf.elss, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); + } } else if(n->nodeKind == AST_STMT_LOOP) { generic_visitor(&n->stmtLoop.body, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler); } else if(n->nodeKind == AST_STMT_BREAK) { @@ -143,6 +146,13 @@ int ast_stmt_is_after(const AST *chunk, const AST *s1, const AST *s2) { if(i == 1 || (i == 0 && s1 != NULL)) { return i; } + + if(s->stmtIf.elss) { + i = ast_stmt_is_after(s->stmtIf.elss, s1, s2); + if(i == 1 || (i == 0 && s1 != NULL)) { + return i; + } + } } s = s->statement.next; @@ -656,7 +666,14 @@ static char *ast_dumps(AST *tlc, AST *s) { } else if(s->nodeKind == AST_STMT_IF) { char *cond = ast_dumpe(tlc, s->stmtIf.expression); char *inner = ast_dumpc(tlc, s->stmtIf.then); - char *c = malp("if(%s) {\n%s}", cond, inner); + char *elss = s->stmtIf.elss ? ast_dumpc(tlc, s->stmtIf.elss) : NULL; + char *c; + if(elss) { + c = malp("if(%s) {\n%s} else {\n%s}", cond, inner, elss); + free(elss); + } else { + c = malp("if(%s) {\n%s}", cond, inner); + } free(cond); free(inner); return c; @@ -1098,6 +1115,21 @@ void ast_segmented_dereference(AST *tlc) { generic_visitor(&tlc, NULL, NULL, tlc, tlc, tlc, ast_segmented_dereference_visitor, NULL); } +static void ast_patch_in_chunk(AST *chunkOuter, AST *stmtBefore, AST *chunkInner, AST *stmtAfter) { + if(chunkInner->chunk.statementFirst) { + stmtBefore->statement.next = chunkInner->chunk.statementFirst; + + for(AST *z = chunkInner->chunk.statementFirst; z; z = z->statement.next) { + if(!z->statement.next) { + z->statement.next = stmtAfter; + break; + } + } + } else { + stmtBefore->statement.next = stmtAfter; + } +} + #define LOOPSTACKSIZE 64 struct LinearizeState { size_t currentDepth; @@ -1113,38 +1145,69 @@ static void ast_linearize_visitor_pre(AST **aptr, AST *stmt, AST *stmtPrev, AST AST *a = *aptr; if(a->nodeKind == AST_STMT_IF) { - ASTExprUnaryOp *notcond = calloc(1, sizeof(*notcond)); - notcond->nodeKind = AST_EXPR_UNARY_OP; - notcond->operator = UNOP_NOT; - notcond->operand = a->stmtIf.expression; - notcond->type = a->stmtIf.expression->expression.type; - - ASTStmtJump *jump = calloc(1, sizeof(ASTStmtJump)); - jump->nodeKind = AST_STMT_JUMP; - jump->condition = (AST*) notcond; - jump->label = malp("$Lin%lu", nextLabelIdx++); - - ASTStmtLabel *label = calloc(1, sizeof(ASTStmtLabel)); - label->nodeKind = AST_STMT_LABEL; - label->name = strdup(jump->label); - - if(stmtPrev) { - stmtPrev->statement.next = (AST*) jump; - } else { - chunk->chunk.statementFirst = (AST*) jump; - } - if(a->stmtIf.then->chunk.statementFirst) { - jump->next = a->stmtIf.then->chunk.statementFirst; - for(AST *z = a->stmtIf.then->chunk.statementFirst; z; z = z->statement.next) { - if(!z->statement.next) { - z->statement.next = (AST*) label; - break; - } + if(a->stmtIf.elss == NULL) { + ASTExprUnaryOp *notcond = calloc(1, sizeof(*notcond)); + notcond->nodeKind = AST_EXPR_UNARY_OP; + notcond->operator = UNOP_NOT; + notcond->operand = a->stmtIf.expression; + notcond->type = a->stmtIf.expression->expression.type; + + ASTStmtJump *jump = calloc(1, sizeof(ASTStmtJump)); + jump->nodeKind = AST_STMT_JUMP; + jump->condition = (AST*) notcond; + jump->label = malp("$Lin%lu", nextLabelIdx++); + + ASTStmtLabel *label = calloc(1, sizeof(ASTStmtLabel)); + label->nodeKind = AST_STMT_LABEL; + label->name = strdup(jump->label); + + if(stmtPrev) { + stmtPrev->statement.next = (AST*) jump; + } else { + chunk->chunk.statementFirst = (AST*) jump; } + + ast_patch_in_chunk(chunk, (AST*) jump, a->stmtIf.then, (AST*) label); + + label->next = a->statement.next; } else { - jump->next = (AST*) label; + ASTExprUnaryOp *notcond = calloc(1, sizeof(*notcond)); + notcond->nodeKind = AST_EXPR_UNARY_OP; + notcond->operator = UNOP_NOT; + notcond->operand = a->stmtIf.expression; + notcond->type = a->stmtIf.expression->expression.type; + + ASTStmtJump *jump2Else = calloc(1, sizeof(ASTStmtJump)); + jump2Else->nodeKind = AST_STMT_JUMP; + jump2Else->condition = (AST*) notcond; + jump2Else->label = malp("$Lin%lu", nextLabelIdx++); + + ASTStmtJump *jump2End = calloc(1, sizeof(ASTStmtJump)); + jump2End->nodeKind = AST_STMT_JUMP; + jump2End->label = malp("$Lin%lu", nextLabelIdx++); + + ASTStmtLabel *labelElse = calloc(1, sizeof(ASTStmtLabel)); + labelElse->nodeKind = AST_STMT_LABEL; + labelElse->name = strdup(jump2Else->label); + + ASTStmtLabel *labelEnd = calloc(1, sizeof(ASTStmtLabel)); + labelEnd->nodeKind = AST_STMT_LABEL; + labelEnd->name = strdup(jump2End->label); + + if(stmtPrev) { + stmtPrev->statement.next = (AST*) jump2Else; + } else { + chunk->chunk.statementFirst = (AST*) jump2Else; + } + + ast_patch_in_chunk(chunk, (AST*) jump2Else, a->stmtIf.then, (AST*) jump2End); + + jump2End->next = (AST*) labelElse; + + ast_patch_in_chunk(chunk, (AST*) labelElse, a->stmtIf.elss, (AST*) labelEnd); + + labelEnd->next = a->statement.next; } - label->next = a->statement.next; } else if(a->nodeKind == AST_STMT_LOOP) { size_t startIdx = nextLabelIdx++; size_t endIdx = nextLabelIdx++; @@ -1167,17 +1230,9 @@ static void ast_linearize_visitor_pre(AST **aptr, AST *stmt, AST *stmtPrev, AST } else { chunk->chunk.statementFirst = (AST*) startLabel; } - if(a->stmtLoop.body->chunk.statementFirst) { - startLabel->next = a->stmtLoop.body->chunk.statementFirst; - for(AST *z = a->stmtLoop.body->chunk.statementFirst; z; z = z->statement.next) { - if(!z->statement.next) { - z->statement.next = (AST*) jump; - break; - } - } - } else { - startLabel->next = (AST*) jump; - } + + ast_patch_in_chunk(chunk, (AST*) startLabel, a->stmtLoop.body, (AST*) jump); + jump->next = (AST*) endLabel; endLabel->next = a->statement.next; diff --git a/src/ast.h b/src/ast.h index ce2f73f..d13984b 100644 --- a/src/ast.h +++ b/src/ast.h @@ -225,6 +225,7 @@ typedef struct { union AST *expression; union AST *then; + union AST *elss; } ASTStmtIf; typedef struct { diff --git a/src/lexer.c b/src/lexer.c index d3b2019..f0a7392 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -49,6 +49,7 @@ char *TOKEN_NAMES[] = { "'.'", "'as'", "'use'", + "'else'", }; static int isAlpha(int c) { @@ -296,6 +297,10 @@ Token nct_tokenize(FILE *f) { free(content); tok.type = TOKEN_USE; return tok; + } else if(!strcmp(content, "else")) { + free(content); + tok.type = TOKEN_ELSE; + return tok; } tok.type = TOKEN_IDENTIFIER; diff --git a/src/lexer.h b/src/lexer.h index a0485a0..4ab589d 100644 --- a/src/lexer.h +++ b/src/lexer.h @@ -49,6 +49,7 @@ typedef enum { TOKEN_DOT, TOKEN_AS, TOKEN_USE, + TOKEN_ELSE, } TokenKind; typedef struct Token { diff --git a/src/parse.c b/src/parse.c index 3185408..5ffc7f2 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1095,6 +1095,13 @@ static void nct_parse_statement(Parser *P) { expect(P, TOKEN_SQUIGGLY_L); ret->then = (AST*) nct_parse_chunk(P, 0, 0, NULL, NULL); expect(P, TOKEN_SQUIGGLY_R); + + if(maybe(P, TOKEN_ELSE)) { + expect(P, TOKEN_SQUIGGLY_L); + ret->elss = (AST*) nct_parse_chunk(P, 0, 0, NULL, NULL); + expect(P, TOKEN_SQUIGGLY_R); + } + return; } else if(maybe(P, TOKEN_LOOP)) { ASTStmtLoop *ret = alloc_node(P, sizeof(*ret));