From ed02bbc9be268313250f2593a8d90b406a8fd57d Mon Sep 17 00:00:00 2001 From: cozis Date: Sat, 13 Aug 2022 17:42:37 +0200 Subject: [PATCH] refactorin' (incapsulated CodegenContext from codegen.c) --- src/lib/compiler/codegen.c | 605 ++++++++++++++-------------------- src/lib/compiler/codegenctx.c | 137 ++++++++ src/lib/compiler/codegenctx.h | 22 ++ src/lib/compiler/compile.c | 4 +- src/lib/compiler/parse.c | 2 +- src/lib/noja.c | 1 - src/lib/utils/labellist.h | 2 +- 7 files changed, 412 insertions(+), 361 deletions(-) create mode 100644 src/lib/compiler/codegenctx.c create mode 100644 src/lib/compiler/codegenctx.h diff --git a/src/lib/compiler/codegen.c b/src/lib/compiler/codegen.c index 834133d..c9588cb 100644 --- a/src/lib/compiler/codegen.c +++ b/src/lib/compiler/codegen.c @@ -44,105 +44,13 @@ */ #include -#include #include #include #include "../utils/defs.h" +#include "codegenctx.h" #include "compile.h" #include "ASTi.h" -typedef struct { - Error *error; - BPAlloc *alloc; - ExeBuilder *builder; - bool own_alloc; - jmp_buf env; -} CodegenContext; - -typedef Promise Label; - -static void setLabel(Label *label, long long int value) -{ - Promise *promise = (Promise*) label; - Promise_Resolve(promise, &value, sizeof(value)); -} - -static void setLabelHere(Label *label, CodegenContext *ctx) -{ - long long int value = ExeBuilder_InstrCount(ctx->builder); - setLabel(label, value); -} - -static void freeLabel(Label *label) -{ - Promise *promise = (Promise*) label; - Promise_Free(promise); -} - -static void okNowJump(CodegenContext *ctx) -{ - longjmp(ctx->env, 1); -} - -static void reportErrorAndJump_(CodegenContext *ctx, const char *file, - const char *func, int line, bool internal, - const char *format, ...) -{ - va_list args; - va_start(args, format); - _Error_Report2(ctx->error, internal, file, func, line, format, args); - va_end(args); - - okNowJump(ctx); -} - -#define reportErrorAndJump(ctx, int, fmt, ...) \ - reportErrorAndJump_(ctx, __FILE__, __func__, __LINE__, int, fmt, ## __VA_ARGS__) - -static void freeCodegenContext(CodegenContext *ctx) -{ - if(ctx->own_alloc) - BPAlloc_Free(ctx->alloc); -} - -static bool setOrcatchJump(CodegenContext *ctx) -{ - bool jumped = setjmp(ctx->env); - return jumped; -} - -static bool initCodegenContext(CodegenContext *ctx, Error *error, BPAlloc *alloc) -{ - if(alloc == NULL) { - alloc = BPAlloc_Init(-1); - if(alloc == NULL) { - Error_Report(error, 1, "No memory"); - return false; - } - ctx->own_alloc = true; - } else { - ctx->own_alloc = false; - } - - ExeBuilder *builder = ExeBuilder_New(alloc); - if(builder == NULL) { - if(ctx->own_alloc) - BPAlloc_Free(alloc); - return false; - } - - ctx->error = error; - ctx->alloc = alloc; - ctx->builder = builder; - return true; -} - -static void emitInstr(CodegenContext *ctx, Opcode opcode, Operand *opv, int opc, int off, int len) -{ - if(!ExeBuilder_Append(ctx->builder, ctx->error, opcode, opv, opc, off, len)) - okNowJump(ctx); -} - static void emitInstr_POP(CodegenContext *ctx, long long int op0, int off, int len) @@ -150,7 +58,7 @@ static void emitInstr_POP(CodegenContext *ctx, Operand opv[1] = { { .type = OPTP_INT, .as_int = op0 } }; - emitInstr(ctx, OPCODE_POP, opv, 1, off, len); + CodegenContext_EmitInstr(ctx, OPCODE_POP, opv, 1, off, len); } static void emitInstr_POP1(CodegenContext *ctx, int off, int len) @@ -163,7 +71,7 @@ static void emitInstr_ASS(CodegenContext *ctx, const char *name, int off, int le Operand opv[] = { { .type = OPTP_STRING, .as_string = name }, }; - emitInstr(ctx, OPCODE_ASS, opv, 1, off, len); + CodegenContext_EmitInstr(ctx, OPCODE_ASS, opv, 1, off, len); } static void emitInstr_RETURN(CodegenContext *ctx, @@ -173,27 +81,27 @@ static void emitInstr_RETURN(CodegenContext *ctx, Operand opv[1] = { { .type = OPTP_INT, .as_int = op0 } }; - emitInstr(ctx, OPCODE_RETURN, opv, 1, off, len); + CodegenContext_EmitInstr(ctx, OPCODE_RETURN, opv, 1, off, len); } static void emitInstr_JUMP(CodegenContext *ctx, - Promise *op0, + Label *op0, int off, int len) { Operand opv[1] = { - { .type = OPTP_PROMISE, .as_promise = op0 } + { .type = OPTP_PROMISE, .as_promise = Label_ToPromise(op0) } }; - emitInstr(ctx, OPCODE_JUMP, opv, 1, off, len); + CodegenContext_EmitInstr(ctx, OPCODE_JUMP, opv, 1, off, len); } static void emitInstr_JUMPIFNOTANDPOP(CodegenContext *ctx, - Promise *op0, + Label *op0, int off, int len) { Operand opv[1] = { - { .type = OPTP_PROMISE, .as_promise = op0 } + { .type = OPTP_PROMISE, .as_promise = Label_ToPromise(op0) } }; - emitInstr(ctx, OPCODE_JUMPIFNOTANDPOP, opv, 1, off, len); + CodegenContext_EmitInstr(ctx, OPCODE_JUMPIFNOTANDPOP, opv, 1, off, len); } static void emitInstr_JUMPIFANDPOP(CodegenContext *ctx, @@ -203,18 +111,7 @@ static void emitInstr_JUMPIFANDPOP(CodegenContext *ctx, Operand opv[1] = { { .type = OPTP_INT, .as_int = op0 } }; - emitInstr(ctx, OPCODE_JUMPIFANDPOP, opv, 1, off, len); -} - -static Label *newLabel(CodegenContext *ctx) -{ - Promise *promise = Promise_New(ctx->alloc, sizeof(long long int)); - if(promise != NULL) - return promise; - - reportErrorAndJump(ctx, 1, "No memory"); - UNREACHABLE; - return NULL; // For the compiler warning. + CodegenContext_EmitInstr(ctx, OPCODE_JUMPIFANDPOP, opv, 1, off, len); } static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break); @@ -262,26 +159,26 @@ static void emitInstrForFuncCallNode(CodegenContext *ctx, CallExprNode *expr, Operand ops[2]; ops[0] = (Operand) { .type = OPTP_INT, .as_int = expr->argc }; ops[1] = (Operand) { .type = OPTP_INT, .as_int = returns }; - emitInstr(ctx, OPCODE_CALL, ops, 2, expr->base.base.offset, expr->base.base.length); + CodegenContext_EmitInstr(ctx, OPCODE_CALL, ops, 2, expr->base.base.offset, expr->base.base.length); } static void emitInstrForFuncNode(CodegenContext *ctx, FunctionNode *func) { - Label *label_func = newLabel(ctx); - Label *label_jump = newLabel(ctx); + Label *label_func = Label_New(ctx); + Label *label_jump = Label_New(ctx); // Push function. { Operand ops[2] = { - { .type = OPTP_PROMISE, .as_promise = label_func }, + { .type = OPTP_PROMISE, .as_promise = Label_ToPromise(label_func) }, { .type = OPTP_INT, .as_int = func->argc }, }; - emitInstr(ctx, OPCODE_PUSHFUN, ops, 2, func->base.offset, func->base.length); + CodegenContext_EmitInstr(ctx, OPCODE_PUSHFUN, ops, 2, func->base.offset, func->base.length); } emitInstr_ASS(ctx, func->name, func->base.offset, func->base.length); // Assign variable emitInstr_POP1(ctx, func->base.offset, func->base.length); // Pop function object emitInstr_JUMP(ctx, label_jump, func->base.offset, func->base.length); // Jump after the function code - setLabelHere(label_func, ctx); // This is the function code index. + Label_SetHere(label_func, ctx); // This is the function code index. // Compile the function body. { @@ -305,10 +202,10 @@ static void emitInstrForFuncNode(CodegenContext *ctx, FunctionNode *func) } // This is the first index after the function code. - setLabelHere(label_jump, ctx); + Label_SetHere(label_jump, ctx); - freeLabel(label_func); - freeLabel(label_jump); + Label_Free(label_func); + Label_Free(label_jump); } static void emitInstrForIfElseNode(CodegenContext *ctx, IfElseNode *ifelse, Label *label_break) @@ -316,30 +213,30 @@ static void emitInstrForIfElseNode(CodegenContext *ctx, IfElseNode *ifelse, Labe emitInstrForNode(ctx, ifelse->condition, label_break); if(ifelse->false_branch) { - Label *label_else = newLabel(ctx); - Label *label_done = newLabel(ctx); + Label *label_else = Label_New(ctx); + Label *label_done = Label_New(ctx); emitInstr_JUMPIFNOTANDPOP(ctx, label_else, ifelse->base.offset, ifelse->base.length); emitInstrForNode(ctx, ifelse->true_branch, label_break); if(ifelse->true_branch->kind == NODE_EXPR) emitInstr_POP(ctx, 1, ifelse->true_branch->offset, 0); emitInstr_JUMP(ctx, label_done, ifelse->base.offset, ifelse->base.length); - setLabelHere(label_else, ctx); + Label_SetHere(label_else, ctx); emitInstrForNode(ctx, ifelse->false_branch, label_break); if(ifelse->false_branch->kind == NODE_EXPR) emitInstr_POP1(ctx, ifelse->false_branch->offset, 0); - setLabelHere(label_done, ctx); - freeLabel(label_else); - freeLabel(label_done); + Label_SetHere(label_done, ctx); + Label_Free(label_else); + Label_Free(label_done); } else { - Label *label_done = newLabel(ctx); + Label *label_done = Label_New(ctx); emitInstr_JUMPIFNOTANDPOP(ctx, label_done, ifelse->base.offset, ifelse->base.length); emitInstrForNode(ctx, ifelse->true_branch, label_break); if(ifelse->true_branch->kind == NODE_EXPR) emitInstr_POP1(ctx, ifelse->true_branch->offset, 0); - setLabelHere(label_done, ctx); - freeLabel(label_done); + Label_SetHere(label_done, ctx); + Label_Free(label_done); } } @@ -355,7 +252,7 @@ static void flattenTupleTree(CodegenContext *ctx, ExprNode *root, ExprNode *tupl if(max == *count) { - reportErrorAndJump(ctx, 0, "Static buffer is too small"); + CodegenContext_ReportErrorAndJump(ctx, 0, "Static buffer is too small"); UNREACHABLE; } @@ -383,7 +280,7 @@ static void emitInstrForAssignmentNode(CodegenContext *ctx, OperExprNode *asgn, if(((ExprNode*) rop)->kind == EXPR_CALL) emitInstrForFuncCallNode(ctx, (CallExprNode*) rop, label_break, count); else { - reportErrorAndJump(ctx, 0, "Assigning to %d variables only 1 value", count); + CodegenContext_ReportErrorAndJump(ctx, 0, "Assigning to %d variables only 1 value", count); UNREACHABLE; } } @@ -406,12 +303,12 @@ static void emitInstrForAssignmentNode(CodegenContext *ctx, OperExprNode *asgn, Node *set = ((IndexSelectionExprNode*) tuple_item)->set; emitInstrForNode(ctx, set, label_break); emitInstrForNode(ctx, idx, label_break); - emitInstr(ctx, OPCODE_INSERT2, NULL, 0, tuple_item->base.offset, tuple_item->base.length); + CodegenContext_EmitInstr(ctx, OPCODE_INSERT2, NULL, 0, tuple_item->base.offset, tuple_item->base.length); break; } default: - reportErrorAndJump(ctx, 0, "Assigning to something that it can't be assigned to"); + CodegenContext_ReportErrorAndJump(ctx, 0, "Assigning to something that it can't be assigned to"); UNREACHABLE; } @@ -420,6 +317,202 @@ static void emitInstrForAssignmentNode(CodegenContext *ctx, OperExprNode *asgn, } } +static void emitInstrForWhileLoopNode(CodegenContext *ctx, WhileNode *loop, Label *label_break) +{ + /* + * start: + * + * JUMPIFNOTANDPOP end + * + * JUMP start + * end: + */ + + Label *label_start = Label_New(ctx); + Label *label_end = Label_New(ctx); + Label_SetHere(label_start, ctx); + emitInstrForNode(ctx, loop->condition, label_break); + emitInstr_JUMPIFNOTANDPOP(ctx, label_end, loop->condition->offset, loop->condition->length); + emitInstrForNode(ctx, loop->body, label_end); + if(loop->body->kind == NODE_EXPR) + emitInstr_POP1(ctx, loop->body->offset, 0); + emitInstr_JUMP(ctx, label_start, loop->base.offset, loop->base.length); + Label_SetHere(label_end, ctx); + Label_Free(label_start); + Label_Free(label_end); +} + +static void emitInstrForDoWhileLoopNode(CodegenContext *ctx, DoWhileNode *loop, Label *label_break) +{ + /* + * start: + * + * + * JUMPIFANDPOP start + */ + + Label *label_end = Label_New(ctx); + long long int start = CodegenContext_InstrCount(ctx); + emitInstrForNode(ctx, loop->body, label_end); + if(loop->body->kind == NODE_EXPR) + emitInstr_POP1(ctx, loop->body->offset, 0); + emitInstrForNode(ctx, loop->condition, label_break); + emitInstr_JUMPIFANDPOP(ctx, start, loop->condition->offset, loop->condition->length); + Label_SetHere(label_end, ctx); + Label_Free(label_end); +} + +static void emitInstrForExprNode(CodegenContext *ctx, ExprNode *expr, Label *label_break) +{ + switch(expr->kind) + { + case EXPR_PAIR: + CodegenContext_ReportErrorAndJump(ctx, 0, "Tuple outside of assignment or return statement"); + UNREACHABLE; + return; // For the compiler warning. + + case EXPR_NOT: + case EXPR_POS: + case EXPR_NEG: + case EXPR_ADD: + case EXPR_SUB: + case EXPR_MUL: + case EXPR_DIV: + case EXPR_EQL: + case EXPR_NQL: + case EXPR_LSS: + case EXPR_LEQ: + case EXPR_GRT: + case EXPR_GEQ: + case EXPR_AND: + case EXPR_OR: + { + OperExprNode *oper = (OperExprNode*) expr; + for(Node *operand = oper->head; operand; operand = operand->next) + emitInstrForNode(ctx, operand, label_break); + CodegenContext_EmitInstr(ctx, exprkind_to_opcode(expr->kind), NULL, 0, expr->base.offset, expr->base.length); + return; + } + + case EXPR_ASS: + emitInstrForAssignmentNode(ctx, (OperExprNode*) expr, label_break); + return; + + case EXPR_INT: + { + IntExprNode *p = (IntExprNode*) expr; + Operand op = { .type = OPTP_INT, .as_int = p->val }; + CodegenContext_EmitInstr(ctx, OPCODE_PUSHINT, &op, 1, expr->base.offset, expr->base.length); + return; + } + + case EXPR_FLOAT: + { + FloatExprNode *p = (FloatExprNode*) expr; + Operand op = { .type = OPTP_FLOAT, .as_float = p->val }; + CodegenContext_EmitInstr(ctx, OPCODE_PUSHFLT, &op, 1, expr->base.offset, expr->base.length); + return; + } + + case EXPR_STRING: + { + StringExprNode *p = (StringExprNode*) expr; + Operand op = { .type = OPTP_STRING, .as_string = p->val }; + CodegenContext_EmitInstr(ctx, OPCODE_PUSHSTR, &op, 1, expr->base.offset, expr->base.length); + return; + } + + case EXPR_IDENT: + { + IdentExprNode *p = (IdentExprNode*) expr; + Operand op = { .type = OPTP_STRING, .as_string = p->val }; + CodegenContext_EmitInstr(ctx, OPCODE_PUSHVAR, &op, 1, expr->base.offset, expr->base.length); + return; + } + + case EXPR_LIST: + { + // PUSHLST + // PUSHINT + // + // INSERT + + ListExprNode *l = (ListExprNode*) expr; + + Operand op; + + op = (Operand) { .type = OPTP_INT, .as_int = l->itemc }; + CodegenContext_EmitInstr(ctx, OPCODE_PUSHLST, &op, 1, expr->base.offset, expr->base.length); + + Node *item = l->items; + int i = 0; + + while(item) + { + op = (Operand) { .type = OPTP_INT, .as_int = i }; + CodegenContext_EmitInstr(ctx, OPCODE_PUSHINT, &op, 1, item->offset, item->length); + emitInstrForNode(ctx, item, label_break); + CodegenContext_EmitInstr(ctx, OPCODE_INSERT, NULL, 0, item->offset, item->length); + i += 1; + item = item->next; + } + return; + } + + case EXPR_MAP: + { + MapExprNode *m = (MapExprNode*) expr; + + Operand op; + + op = (Operand) { .type = OPTP_INT, .as_int = m->itemc }; + CodegenContext_EmitInstr(ctx, OPCODE_PUSHMAP, &op, 1, expr->base.offset, expr->base.length); + + Node *key = m->keys; + Node *item = m->items; + + while(item) + { + emitInstrForNode(ctx, key, label_break); + emitInstrForNode(ctx, item, label_break); + CodegenContext_EmitInstr(ctx, OPCODE_INSERT, NULL, 0, item->offset, item->length); + key = key->next; + item = item->next; + } + return; + } + + case EXPR_CALL: + emitInstrForFuncCallNode(ctx, (CallExprNode*) expr, label_break, 1); + return; + + case EXPR_SELECT: + { + IndexSelectionExprNode *sel = (IndexSelectionExprNode*) expr; + emitInstrForNode(ctx, sel->set, label_break); + emitInstrForNode(ctx, sel->idx, label_break); + CodegenContext_EmitInstr(ctx, OPCODE_SELECT, NULL, 0, expr->base.offset, expr->base.length); + return; + } + + case EXPR_NONE: + CodegenContext_EmitInstr(ctx, OPCODE_PUSHNNE, NULL, 0, expr->base.offset, expr->base.length); + return; + + case EXPR_TRUE: + CodegenContext_EmitInstr(ctx, OPCODE_PUSHTRU, NULL, 0, expr->base.offset, expr->base.length); + return; + + case EXPR_FALSE: + CodegenContext_EmitInstr(ctx, OPCODE_PUSHFLS, NULL, 0, expr->base.offset, expr->base.length); + return; + + default: + UNREACHABLE; + break; + } +} + static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break) { assert(node != NULL); @@ -427,161 +520,12 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break switch(node->kind) { case NODE_EXPR: - { - ExprNode *expr = (ExprNode*) node; - switch(expr->kind) - { - case EXPR_PAIR: - reportErrorAndJump(ctx, 0, "Tuple outside of assignment or return statement"); - UNREACHABLE; - return; // For the compiler warning. - - case EXPR_NOT: - case EXPR_POS: - case EXPR_NEG: - case EXPR_ADD: - case EXPR_SUB: - case EXPR_MUL: - case EXPR_DIV: - case EXPR_EQL: - case EXPR_NQL: - case EXPR_LSS: - case EXPR_LEQ: - case EXPR_GRT: - case EXPR_GEQ: - case EXPR_AND: - case EXPR_OR: - { - OperExprNode *oper = (OperExprNode*) expr; - for(Node *operand = oper->head; operand; operand = operand->next) - emitInstrForNode(ctx, operand, label_break); - emitInstr(ctx, exprkind_to_opcode(expr->kind), NULL, 0, node->offset, node->length); - return; - } - - case EXPR_ASS: - emitInstrForAssignmentNode(ctx, (OperExprNode*) expr, label_break); - return; - - case EXPR_INT: - { - IntExprNode *p = (IntExprNode*) expr; - Operand op = { .type = OPTP_INT, .as_int = p->val }; - emitInstr(ctx, OPCODE_PUSHINT, &op, 1, node->offset, node->length); - return; - } - - case EXPR_FLOAT: - { - FloatExprNode *p = (FloatExprNode*) expr; - Operand op = { .type = OPTP_FLOAT, .as_float = p->val }; - emitInstr(ctx, OPCODE_PUSHFLT, &op, 1, node->offset, node->length); - return; - } - - case EXPR_STRING: - { - StringExprNode *p = (StringExprNode*) expr; - Operand op = { .type = OPTP_STRING, .as_string = p->val }; - emitInstr(ctx, OPCODE_PUSHSTR, &op, 1, node->offset, node->length); - return; - } - - case EXPR_IDENT: - { - IdentExprNode *p = (IdentExprNode*) expr; - Operand op = { .type = OPTP_STRING, .as_string = p->val }; - emitInstr(ctx, OPCODE_PUSHVAR, &op, 1, node->offset, node->length); - return; - } - - case EXPR_LIST: - { - // PUSHLST - // PUSHINT - // - // INSERT - - ListExprNode *l = (ListExprNode*) node; - - Operand op; - - op = (Operand) { .type = OPTP_INT, .as_int = l->itemc }; - emitInstr(ctx, OPCODE_PUSHLST, &op, 1, node->offset, node->length); - - Node *item = l->items; - int i = 0; - - while(item) - { - op = (Operand) { .type = OPTP_INT, .as_int = i }; - emitInstr(ctx, OPCODE_PUSHINT, &op, 1, item->offset, item->length); - emitInstrForNode(ctx, item, label_break); - emitInstr(ctx, OPCODE_INSERT, NULL, 0, item->offset, item->length); - i += 1; - item = item->next; - } - return; - } - - case EXPR_MAP: - { - MapExprNode *m = (MapExprNode*) node; - - Operand op; - - op = (Operand) { .type = OPTP_INT, .as_int = m->itemc }; - emitInstr(ctx, OPCODE_PUSHMAP, &op, 1, node->offset, node->length); - - Node *key = m->keys; - Node *item = m->items; - - while(item) - { - emitInstrForNode(ctx, key, label_break); - emitInstrForNode(ctx, item, label_break); - emitInstr(ctx, OPCODE_INSERT, NULL, 0, item->offset, item->length); - key = key->next; - item = item->next; - } - return; - } - - case EXPR_CALL: - emitInstrForFuncCallNode(ctx, (CallExprNode*) expr, label_break, 1); - return; - - case EXPR_SELECT: - { - IndexSelectionExprNode *sel = (IndexSelectionExprNode*) expr; - emitInstrForNode(ctx, sel->set, label_break); - emitInstrForNode(ctx, sel->idx, label_break); - emitInstr(ctx, OPCODE_SELECT, NULL, 0, node->offset, node->length); - return; - } - - case EXPR_NONE: - emitInstr(ctx, OPCODE_PUSHNNE, NULL, 0, node->offset, node->length); - return; - - case EXPR_TRUE: - emitInstr(ctx, OPCODE_PUSHTRU, NULL, 0, node->offset, node->length); - return; - - case EXPR_FALSE: - emitInstr(ctx, OPCODE_PUSHFLS, NULL, 0, node->offset, node->length); - return; - - default: - UNREACHABLE; - break; - } - return; - } + emitInstrForExprNode(ctx, (ExprNode*) node, label_break); + return; case NODE_BREAK: if(label_break == NULL) - reportErrorAndJump(ctx, 0, "Break not inside a loop"); + CodegenContext_ReportErrorAndJump(ctx, 0, "Break not inside a loop"); emitInstr_JUMP(ctx, label_break, node->offset, node->length); return; @@ -590,54 +534,12 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break return; case NODE_WHILE: - { - WhileNode *whl = (WhileNode*) node; - - /* - * start: - * - * JUMPIFNOTANDPOP end - * - * JUMP start - * end: - */ - - Label *label_start = newLabel(ctx); - Label *label_end = newLabel(ctx); - setLabelHere(label_start, ctx); - emitInstrForNode(ctx, whl->condition, label_break); - emitInstr_JUMPIFNOTANDPOP(ctx, label_end, whl->condition->offset, whl->condition->length); - emitInstrForNode(ctx, whl->body, label_end); - if(whl->body->kind == NODE_EXPR) - emitInstr_POP1(ctx, whl->body->offset, 0); - emitInstr_JUMP(ctx, label_start, node->offset, node->length); - setLabelHere(label_end, ctx); - freeLabel(label_start); - freeLabel(label_end); - return; - } + emitInstrForWhileLoopNode(ctx, (WhileNode*) node, label_break); + return; case NODE_DOWHILE: - { - DoWhileNode *dowhl = (DoWhileNode*) node; - /* - * start: - * - * - * JUMPIFANDPOP start - */ - - Label *label_end = newLabel(ctx); - long long int start = ExeBuilder_InstrCount(ctx->builder); - emitInstrForNode(ctx, dowhl->body, label_end); - if(dowhl->body->kind == NODE_EXPR) - emitInstr_POP1(ctx, dowhl->body->offset, 0); - emitInstrForNode(ctx, dowhl->condition, label_break); - emitInstr_JUMPIFANDPOP(ctx, start, dowhl->condition->offset, dowhl->condition->length); - setLabelHere(label_end, ctx); - freeLabel(label_end); - return; - } + emitInstrForDoWhileLoopNode(ctx, (DoWhileNode*) node, label_break); + return; case NODE_COMP: { @@ -680,17 +582,6 @@ static void emitInstrForNode(CodegenContext *ctx, Node *node, Label *label_break UNREACHABLE; } -static Executable *makeExecutableAndFreeCodegenContext(CodegenContext *ctx, Source *src) -{ - Executable *exe = ExeBuilder_Finalize(ctx->builder, ctx->error); - if(exe == NULL) - okNowJump(ctx); - - Executable_SetSource(exe, src); - freeCodegenContext(ctx); - return exe; -} - /* Symbol: codegen * * Serializes an AST into bytecode format. @@ -716,17 +607,19 @@ Executable *codegen(AST *ast, BPAlloc *alloc, Error *error) assert(ast != NULL); assert(error != NULL); - CodegenContext ctx; - if(!initCodegenContext(&ctx, error, alloc)) - return NULL; - - bool jumped = setOrcatchJump(&ctx); - if(jumped) { - freeCodegenContext(&ctx); + CodegenContext *ctx = CodegenContext_New(error, alloc); + if(ctx == NULL) { + Error_Report(error, 1, "No memory"); return NULL; } - emitInstrForNode(&ctx, ast->root, NULL); - emitInstr_RETURN(&ctx, 0, Source_GetSize(ast->src), 0); - return makeExecutableAndFreeCodegenContext(&ctx, ast->src); -} \ No newline at end of file + bool jumped = CodegenContext_SetOrCatchJump(ctx); + if(jumped) { + CodegenContext_Free(ctx); + return NULL; + } + + emitInstrForNode(ctx, ast->root, NULL); + emitInstr_RETURN(ctx, 0, Source_GetSize(ast->src), 0); + return CodegenContext_MakeExecutableAndFree(ctx, ast->src); +} diff --git a/src/lib/compiler/codegenctx.c b/src/lib/compiler/codegenctx.c new file mode 100644 index 0000000..7426184 --- /dev/null +++ b/src/lib/compiler/codegenctx.c @@ -0,0 +1,137 @@ +#include +#include +#include "../utils/defs.h" +#include "codegenctx.h" + +struct CodegenContext { + Error *error; + BPAlloc *alloc; + ExeBuilder *builder; + bool own_alloc; + jmp_buf env; +}; + +Label *Label_New(CodegenContext *ctx) +{ + Promise *promise = Promise_New(ctx->alloc, sizeof(long long int)); + if(promise != NULL) + return (Label*) promise; + + CodegenContext_ReportErrorAndJump(ctx, 1, "No memory"); + UNREACHABLE; + return NULL; // For the compiler warning. +} + +void Label_Set(Label *label, long long int value) +{ + Promise *promise = (Promise*) label; + Promise_Resolve(promise, &value, sizeof(value)); +} + +void Label_SetHere(Label *label, CodegenContext *ctx) +{ + long long int value = ExeBuilder_InstrCount(ctx->builder); + Label_Set(label, value); +} + +void Label_Free(Label *label) +{ + Promise *promise = (Promise*) label; + Promise_Free(promise); +} + +Promise *Label_ToPromise(Label *label) +{ + Promise *promise = (Promise*) label; + return promise; +} + +static void okNowJump(CodegenContext *ctx) +{ + longjmp(ctx->env, 1); +} + +void CodegenContext_ReportErrorAndJump_(CodegenContext *ctx, const char *file, + const char *func, int line, bool internal, + const char *format, ...) +{ + va_list args; + va_start(args, format); + _Error_Report2(ctx->error, internal, file, func, line, format, args); + va_end(args); + + okNowJump(ctx); +} + +_Bool CodegenContext_SetOrCatchJump(CodegenContext *ctx) +{ + bool jumped = setjmp(ctx->env); + return jumped; +} + +CodegenContext *CodegenContext_New(Error *error, BPAlloc *alloc) +{ + bool own_alloc; + if(alloc == NULL) { + alloc = BPAlloc_Init(-1); + if(alloc == NULL) { + Error_Report(error, 1, "No memory"); + return false; + } + own_alloc = true; + } else { + own_alloc = false; + } + + CodegenContext *ctx = BPAlloc_Malloc(alloc, sizeof(CodegenContext)); + if(ctx == NULL) { + if(own_alloc) + BPAlloc_Free(alloc); + Error_Report(error, 1, "No memory"); + return NULL; + } + + ExeBuilder *builder = ExeBuilder_New(alloc); + if(builder == NULL) { + if(ctx->own_alloc) + BPAlloc_Free(alloc); + return NULL; + } + + ctx->error = error; + ctx->alloc = alloc; + ctx->builder = builder; + ctx->own_alloc = own_alloc; + return ctx; +} + +int CodegenContext_InstrCount(CodegenContext *ctx) +{ + return ExeBuilder_InstrCount(ctx->builder); +} + + +void CodegenContext_Free(CodegenContext *ctx) +{ + if(ctx->own_alloc) + BPAlloc_Free(ctx->alloc); +} + +Executable *CodegenContext_MakeExecutableAndFree(CodegenContext *ctx, Source *src) +{ + Executable *exe = ExeBuilder_Finalize(ctx->builder, ctx->error); + if(exe == NULL) + okNowJump(ctx); + + if(src != NULL) + Executable_SetSource(exe, src); + + CodegenContext_Free(ctx); + return exe; +} + +void CodegenContext_EmitInstr(CodegenContext *ctx, Opcode opcode, Operand *opv, int opc, int off, int len) +{ + if(!ExeBuilder_Append(ctx->builder, ctx->error, opcode, opv, opc, off, len)) + okNowJump(ctx); +} diff --git a/src/lib/compiler/codegenctx.h b/src/lib/compiler/codegenctx.h new file mode 100644 index 0000000..3b19350 --- /dev/null +++ b/src/lib/compiler/codegenctx.h @@ -0,0 +1,22 @@ +#ifndef CODEGENCTX_H +#define CODEGENCTX_H +#include "../common/executable.h" + +typedef struct CodegenContext CodegenContext; +CodegenContext *CodegenContext_New(Error *error, BPAlloc *alloc); +void CodegenContext_EmitInstr(CodegenContext *ctx, Opcode opcode, Operand *opv, int opc, int off, int len); +_Bool CodegenContext_SetOrCatchJump(CodegenContext *ctx); +void CodegenContext_Free(CodegenContext *ctx); +Executable *CodegenContext_MakeExecutableAndFree(CodegenContext *ctx, Source *src); +void CodegenContext_ReportErrorAndJump_(CodegenContext *ctx, const char *file, const char *func, int line, bool internal, const char *format, ...); +#define CodegenContext_ReportErrorAndJump(ctx, int, fmt, ...) CodegenContext_ReportErrorAndJump_(ctx, __FILE__, __func__, __LINE__, int, fmt, ## __VA_ARGS__) +int CodegenContext_InstrCount(CodegenContext *ctx); + +typedef struct Label Label; +Label *Label_New(CodegenContext *ctx); +void Label_Set(Label *label, long long int value); +void Label_SetHere(Label *label, CodegenContext *ctx); +void Label_Free(Label *label); +Promise *Label_ToPromise(Label *label); + +#endif /* CODEGENCTX_H */ \ No newline at end of file diff --git a/src/lib/compiler/compile.c b/src/lib/compiler/compile.c index ed3d796..bbade98 100644 --- a/src/lib/compiler/compile.c +++ b/src/lib/compiler/compile.c @@ -32,10 +32,10 @@ Executable *compile(Source *src, Error *error, CompilationErrorType *errtyp) return NULL; } + // Transform the AST into bytecode. Executable *exe = codegen(ast, alloc, error); - // We're done with the AST, independently from - // the compilation result. + // We're done with the AST. BPAlloc_Free(alloc); if(exe == NULL) diff --git a/src/lib/compiler/parse.c b/src/lib/compiler/parse.c index 25538ec..4640927 100644 --- a/src/lib/compiler/parse.c +++ b/src/lib/compiler/parse.c @@ -445,7 +445,7 @@ AST *parse(Source *src, BPAlloc *alloc, Error *error) if(root == NULL) return NULL; - ast->src = src; // Not copying! Be sure to not free the source before the AST! + ast->src = src; // Not copying! Be sure not to free the source before the AST! ast->root = root; if(ast->src == NULL) diff --git a/src/lib/noja.c b/src/lib/noja.c index 784bf80..35e9e0f 100644 --- a/src/lib/noja.c +++ b/src/lib/noja.c @@ -2,7 +2,6 @@ #include #include "utils/error.h" #include "utils/source.h" -#include "compiler/parse.h" #include "compiler/compile.h" #include "assembler/assemble.h" #include "builtins/basic.h" diff --git a/src/lib/utils/labellist.h b/src/lib/utils/labellist.h index 54de80b..c9e8fca 100644 --- a/src/lib/utils/labellist.h +++ b/src/lib/utils/labellist.h @@ -10,4 +10,4 @@ void LabelList_Free(LabelList *list); bool LabelList_SetLabel(LabelList *list, const char *name, size_t name_len, long long int value); Promise *LabelList_GetLabel(LabelList *list, const char *name, size_t name_len); size_t LabelList_GetUnresolvedCount(LabelList *list); -#endif /* LABELLIST_H */ \ No newline at end of file +#endif /* LABELLIST_H */