From 17a0c9d902f4d619499d3cd3b2405c936dfbe9e7 Mon Sep 17 00:00:00 2001 From: Mid <> Date: Sat, 14 Dec 2024 18:13:33 +0200 Subject: [PATCH] update --- src/ast.c | 114 ++++++++++- src/ast.h | 22 ++- src/cg.c | 471 +++++++++++++++++++++++++++++++++++++-------- src/dumberdowner.c | 381 +++++++++++++++++++++++------------- src/dumberdowner.h | 3 +- src/lexer.c | 23 +++ src/lexer.h | 7 +- src/ntc.c | 9 +- src/parse.c | 169 ++++++++-------- src/types.c | 2 + src/types.h | 1 + src/vartable.h | 1 + src/x86.h | 6 +- 13 files changed, 904 insertions(+), 305 deletions(-) diff --git a/src/ast.c b/src/ast.c index 0a7aa5b..64db50c 100644 --- a/src/ast.c +++ b/src/ast.c @@ -10,6 +10,74 @@ const char *AST_KIND_STR[] = { AST_KINDS(GEN_STRI) }; +void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud, void(*handler)(AST**, AST*, AST*, AST*, AST*, void*)) { + handler(nptr, stmt, stmtPrev, chu, tlc, ud); + + AST *n = *nptr; + + if(n->nodeKind == AST_CHUNK) { + AST *sPrev = NULL; + AST **s = &n->chunk.statementFirst; + while(*s) { + generic_visitor(s, *s, sPrev, n, tlc, ud, handler); + + sPrev = *s; + s = &sPrev->statement.next; + } + } else if(n->nodeKind == AST_STMT_ASSIGN) { + generic_visitor(&n->stmtAssign.what, stmt, stmtPrev, chu, tlc, ud, handler); + generic_visitor(&n->stmtAssign.to, stmt, stmtPrev, chu, tlc, ud, handler); + } else if(n->nodeKind == AST_STMT_IF) { + generic_visitor(&n->stmtIf.expression, stmt, stmtPrev, chu, tlc, ud, handler); + generic_visitor(&n->stmtIf.then, stmt, stmtPrev, chu, tlc, ud, handler); + } else if(n->nodeKind == AST_STMT_LOOP) { + generic_visitor(&n->stmtLoop.body, stmt, stmtPrev, chu, tlc, ud, handler); + } else if(n->nodeKind == AST_STMT_BREAK) { + } else if(n->nodeKind == AST_STMT_CONTINUE) { + } else if(n->nodeKind == AST_STMT_EXT_ALIGN) { + } else if(n->nodeKind == AST_STMT_DECL) { + if(n->stmtDecl.expression) { + generic_visitor(&n->stmtDecl.expression, stmt, stmtPrev, chu, tlc, ud, handler); + } + } else if(n->nodeKind == AST_STMT_EXPR) { + generic_visitor(&n->stmtExpr.expr, stmt, stmtPrev, chu, tlc, ud, handler); + } else if(n->nodeKind == AST_STMT_EXT_ORG) { + } else if(n->nodeKind == AST_STMT_EXT_SECTION) { + } else if(n->nodeKind == AST_STMT_RETURN) { + if(n->stmtReturn.val) { + generic_visitor(&n->stmtReturn.val, stmt, stmtPrev, chu, tlc, ud, handler); + } + } else if(n->nodeKind == AST_EXPR_BINARY_OP) { + generic_visitor(&n->exprBinOp.operands[0], stmt, stmtPrev, chu, tlc, ud, handler); + generic_visitor(&n->exprBinOp.operands[1], stmt, stmtPrev, chu, tlc, ud, handler); + } else if(n->nodeKind == AST_EXPR_CALL) { + generic_visitor(&n->exprCall.what, stmt, stmtPrev, chu, tlc, ud, handler); + + for(size_t i = 0; i < n->exprCall.what->expression.type->function.argCount; i++) { + generic_visitor(&n->exprCall.args[i], stmt, stmtPrev, chu, tlc, ud, handler); + } + } else if(n->nodeKind == AST_EXPR_CAST) { + generic_visitor(&n->exprCast.what, stmt, stmtPrev, chu, tlc, ud, handler); + } else if(n->nodeKind == AST_EXPR_FUNC) { + generic_visitor(&n->exprFunc.chunk, NULL, NULL, n->exprFunc.chunk, n->exprFunc.chunk, ud, handler); + } else if(n->nodeKind == AST_EXPR_UNARY_OP) { + generic_visitor(&n->exprUnOp.operand, stmt, stmtPrev, chu, tlc, ud, handler); + } else if(n->nodeKind == AST_EXPR_VAR) { + } else if(n->nodeKind == AST_EXPR_STACK_POINTER) { + } else if(n->nodeKind == AST_EXPR_PRIMITIVE) { + } else if(n->nodeKind == AST_EXPR_STRING_LITERAL) { + } else if(n->nodeKind == AST_EXPR_ARRAY) { + assert(n->expression.type->type == TYPE_TYPE_ARRAY); + assert(n->expression.type->array.length != 0); + + for(size_t i = 0; i < n->expression.type->array.length; i++) { + generic_visitor(&n->exprArray.items[i], stmt, stmtPrev, chu, tlc, ud, handler); + } + } else { + abort(); + } +} + AST *ast_expression_optimize(AST *ast) { return ast; } @@ -344,7 +412,7 @@ static char *cat(char *a, const char *b) { return a; } -__attribute__((format(printf, 1, 2))) static char *malp(const char *fmt, ...) { +__attribute__((format(printf, 1, 2))) char *malp(const char *fmt, ...) { va_list v1, v2; va_start(v1, fmt); va_copy(v2, v1); @@ -442,6 +510,18 @@ static char *ast_dumpe(AST *e) { case BINOP_NEQUAL: op = "!="; break; + case BINOP_LESS: + op = "<"; + break; + case BINOP_GREATER: + op = ">"; + break; + case BINOP_LEQUAL: + op = "<="; + break; + case BINOP_GEQUAL: + op = ">="; + break; default: abort(); } @@ -476,6 +556,19 @@ static char *ast_dumpe(AST *e) { out = out2; } + return out; + } else if(e->nodeKind == AST_EXPR_CALL) { + char *w = ast_dumpe(e->exprCall.what); + char *out = malp("%s(", w); + free(w); + size_t argCount = e->exprCall.what->expression.type->function.argCount; + for(size_t i = 0; i < argCount; i++) { + char *a = ast_dumpe(e->exprCall.args[i]); + char *out2 = malp(i == argCount - 1 ? "%s%s)" : "%s%s, ", out, a); + free(a); + free(out); + out = out2; + } return out; } @@ -497,12 +590,19 @@ static char *ast_dumps(AST *s) { return r; } } else if(s->nodeKind == AST_STMT_ASSIGN) { - char *a = ast_dumpe(s->stmtAssign.what); - char *b = ast_dumpe(s->stmtAssign.to); - char *r = malp("%s = %s;\n", a, b); - free(a); - free(b); - return r; + if(s->stmtAssign.to) { + char *a = ast_dumpe(s->stmtAssign.what); + char *b = ast_dumpe(s->stmtAssign.to); + char *r = malp("%s = %s;\n", a, b); + free(a); + free(b); + return r; + } else { + char *a = ast_dumpe(s->stmtAssign.what); + char *r = malp("%s = ; /* fake def */\n", a); + free(a); + return r; + } } else if(s->nodeKind == AST_STMT_LOOP) { char *inner = ast_dump(s->stmtLoop.body); char *c = malp("loop {\n%s}\n", inner); diff --git a/src/ast.h b/src/ast.h index d3a76a0..025aea1 100644 --- a/src/ast.h +++ b/src/ast.h @@ -57,17 +57,22 @@ typedef enum ENUMPAK { BINOP_BITWISE_OR = 3, BINOP_BITWISE_XOR = 4, BINOP_SIMPLES = 5, + BINOP_MUL = 5, BINOP_DIV = 6, BINOP_EQUAL = 7, BINOP_NEQUAL = 8, + BINOP_LESS = 9, + BINOP_GREATER = 10, + BINOP_LEQUAL = 11, + BINOP_GEQUAL = 12, BINOP_WTF = 999, } BinaryOp; static inline int binop_is_comparison(BinaryOp op) { - return op == BINOP_EQUAL || op == BINOP_NEQUAL; + return op == BINOP_EQUAL || op == BINOP_NEQUAL || op == BINOP_LESS || op == BINOP_GREATER || op == BINOP_LEQUAL || op == BINOP_GEQUAL; } static inline BinaryOp binop_comp_opposite(BinaryOp op) { @@ -75,6 +80,14 @@ static inline BinaryOp binop_comp_opposite(BinaryOp op) { return BINOP_NEQUAL; } else if(op == BINOP_NEQUAL) { return BINOP_EQUAL; + } else if(op == BINOP_LESS) { + return BINOP_GEQUAL; + } else if(op == BINOP_GREATER) { + return BINOP_LEQUAL; + } else if(op == BINOP_LEQUAL) { + return BINOP_GREATER; + } else if(op == BINOP_GEQUAL) { + return BINOP_LESS; } return BINOP_WTF; } @@ -187,6 +200,9 @@ typedef struct { union AST *statementLast; size_t stackReservation; + + /* NULL unless this is a top-level chunk belonging to a function */ + Type *functionType; } ASTChunk; typedef struct { @@ -293,6 +309,8 @@ typedef union AST { #pragma pack(pop) +void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud, void(*handler)(AST**, AST*, AST*, AST*, AST*, void*)); + AST *ast_expression_optimize(AST*); int ast_expression_equal(AST*, AST*); @@ -304,4 +322,6 @@ char *ast_dump(AST *tlc); AST *ast_deep_copy(AST*); +__attribute__((format(printf, 1, 2))) char *malp(const char *fmt, ...); + #endif diff --git a/src/cg.c b/src/cg.c index 41c2742..0d2c9c5 100644 --- a/src/cg.c +++ b/src/cg.c @@ -10,9 +10,9 @@ #define REGS 4 static const char *regs[][3] = { [COLOR_EAX] = {"al", "ax", "eax"}, - [COLOR_EBX] = {"bl", "bx", "ebx"}, [COLOR_ECX] = {"cl", "cx", "ecx"}, [COLOR_EDX] = {"dl", "dx", "edx"}, + [COLOR_EBX] = {"bl", "bx", "ebx"}, {"fu", "fk", "fck"} }; @@ -25,6 +25,10 @@ typedef struct { size_t loopStackStart[LOOPSTACKSIZE]; size_t loopStackEnd[LOOPSTACKSIZE]; size_t loopStackIdx; + + int isFunction; + + AST *tlc; } CGState; static const char *direct(int size) { @@ -93,11 +97,15 @@ static const char *xj(BinaryOp op) { switch(op) { case BINOP_EQUAL: return "e"; case BINOP_NEQUAL: return "ne"; + case BINOP_LESS: return "b"; + case BINOP_GREATER: return "a"; + case BINOP_LEQUAL: return "be"; + case BINOP_GEQUAL: return "ae"; default: return "wtf"; } } -static const char *xop_sz(AST *e, int sz) { +static const char *xop_sz(AST *tlc, AST *e, int sz) { #define XOPBUFS 16 #define XOPBUFSZ 24 static char bufs[XOPBUFS][XOPBUFSZ]; @@ -106,7 +114,7 @@ static const char *xop_sz(AST *e, int sz) { char *ret = bufs[bufidx]; if(e->nodeKind == AST_EXPR_STACK_POINTER) { - snprintf(ret, XOPBUFSZ, "esp"); + snprintf(ret, XOPBUFSZ, "esp", tlc->chunk.stackReservation); } else if(e->nodeKind == AST_EXPR_VAR) { VarTableEntry *v = e->exprVar.thing; @@ -127,6 +135,11 @@ static const char *xop_sz(AST *e, int sz) { spec(sz), e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, xv_sz(e->exprUnOp.operand->exprBinOp.operands[1]->exprVar.thing, 4)); + } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL) { + snprintf(ret, XOPBUFSZ, "%s [%s + %i]", + spec(sz), + e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, + e->exprUnOp.operand->exprBinOp.operands[1]->exprPrim.val); } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operator == BINOP_MUL && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[0]->nodeKind == AST_EXPR_PRIMITIVE && e->exprUnOp.operand->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) { snprintf(ret, XOPBUFSZ, "%s [%s + %i * %s]", spec(sz), @@ -138,7 +151,7 @@ static const char *xop_sz(AST *e, int sz) { } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_VAR) { snprintf(ret, XOPBUFSZ, "%s [%s]", spec(sz), xv_sz(e->exprUnOp.operand->exprVar.thing, 4)); } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF && e->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && e->exprUnOp.operand->exprBinOp.operator == UNOP_DEREF && e->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_STACK_POINTER && e->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE) { - snprintf(ret, XOPBUFSZ, "[esp + %i]", e->exprUnOp.operand->exprBinOp.operands[1]->exprPrim.val); + snprintf(ret, XOPBUFSZ, "[esp + %i]", e->exprUnOp.operand->exprBinOp.operands[1]->exprPrim.val + tlc->chunk.stackReservation); } else { return NULL; } @@ -148,8 +161,8 @@ static const char *xop_sz(AST *e, int sz) { return ret; } -static const char *xop(AST *e) { - return xop_sz(e, type_size(e->expression.type)); +static const char *xop(AST *tlc, AST *e) { + return xop_sz(tlc, e, type_size(e->expression.type)); } void cg_chunk(CGState *cg, AST *a) { @@ -211,7 +224,10 @@ void cg_chunk(CGState *cg, AST *a) { assert(s->stmtDecl.expression->nodeKind == AST_EXPR_FUNC); - cg_go(s->stmtDecl.expression->exprFunc.chunk); + dumben_go(s->stmtDecl.expression->exprFunc.chunk); + while(!cg_go(s->stmtDecl.expression->exprFunc.chunk)) { + dumben_go(s->stmtDecl.expression->exprFunc.chunk); + } } else abort(); putchar('\n'); @@ -221,7 +237,7 @@ void cg_chunk(CGState *cg, AST *a) { } } - } else if(s->nodeKind == AST_STMT_ASSIGN && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_CALL) { + } else if(s->nodeKind == AST_STMT_ASSIGN && s->stmtAssign.to && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_CALL) { AST *e = s->stmtAssign.to; @@ -233,7 +249,7 @@ void cg_chunk(CGState *cg, AST *a) { size_t argSize = 0; for(int i = argCount - 1; i >= 0; i--) { - printf("push %s\n", xop_sz(e->exprCall.args[i], 4)); + printf("push %s\n", xop_sz(cg->tlc, e->exprCall.args[i], 4)); argSize += (type_size(e->exprCall.args[i]->expression.type) + 3) & ~3; } @@ -249,7 +265,7 @@ void cg_chunk(CGState *cg, AST *a) { } else if(s->nodeKind == AST_STMT_ASSIGN) { - if(is_xop(s->stmtAssign.what) == XOP_NOT_MEM && is_xop(s->stmtAssign.to) == XOP_NOT_MEM && !strcmp(xop(s->stmtAssign.what), xop(s->stmtAssign.to))) { + if(s->stmtAssign.to && is_xop(s->stmtAssign.what) == XOP_NOT_MEM && is_xop(s->stmtAssign.to) == XOP_NOT_MEM && !strcmp(xop(cg->tlc, s->stmtAssign.what), xop(cg->tlc, s->stmtAssign.to))) { // It's a noop } else if(s->stmtAssign.to) { if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprBinOp.operands[0]) && (s->stmtAssign.to->exprBinOp.operator == BINOP_ADD || s->stmtAssign.to->exprBinOp.operator == BINOP_SUB) && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && s->stmtAssign.to->exprBinOp.operands[1]->exprPrim.val == 1) { @@ -257,11 +273,11 @@ void cg_chunk(CGState *cg, AST *a) { // inc or dec static const char *instrs[] = {"inc", "dec"}; - printf("%s %s %s\n", instrs[s->stmtAssign.to->exprBinOp.operator == BINOP_SUB], specexpr(s->stmtAssign.what), xop(s->stmtAssign.what)); + printf("%s %s\n", instrs[s->stmtAssign.to->exprBinOp.operator == BINOP_SUB], xop(cg->tlc, s->stmtAssign.what)); } else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprBinOp.operands[0]) && s->stmtAssign.to->exprBinOp.operator < BINOP_SIMPLES) { - printf("%s %s, %s\n", BINOP_SIMPLE_INSTRS[s->stmtAssign.to->exprBinOp.operator], xop(s->stmtAssign.what), xop(s->stmtAssign.to->exprBinOp.operands[1])); + printf("%s %s, %s\n", BINOP_SIMPLE_INSTRS[s->stmtAssign.to->exprBinOp.operator], xop(cg->tlc, s->stmtAssign.what), xop(cg->tlc, s->stmtAssign.to->exprBinOp.operands[1])); } else if(s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_ADD && s->stmtAssign.to->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && s->stmtAssign.to->exprBinOp.operands[0]->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) { @@ -286,18 +302,18 @@ void cg_chunk(CGState *cg, AST *a) { } else if(is_xop(s->stmtAssign.what) != NULL && s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_NEGATE && ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprUnOp.operand)) { - printf("neg %s\n", xop(s->stmtAssign.what)); + printf("neg %s\n", xop(cg->tlc, s->stmtAssign.what)); } else if(is_xop(s->stmtAssign.what) && s->stmtAssign.to->nodeKind == AST_EXPR_CAST) { - printf("movzx %s, %s\n", xop(s->stmtAssign.what), xop(s->stmtAssign.to->exprCast.what)); + printf("movzx %s, %s\n", xop(cg->tlc, s->stmtAssign.what), xop(cg->tlc, s->stmtAssign.to->exprCast.what)); } else { if(is_xop(s->stmtAssign.to) == XOP_MEM && type_size(s->stmtAssign.what->expression.type) != type_size(s->stmtAssign.to->expression.type)) { - printf("movzx %s, %s\n", xop_sz(s->stmtAssign.what, 4), xop_sz(s->stmtAssign.to, type_size(s->stmtAssign.what->expression.type))); + printf("movzx %s, %s\n", xop_sz(cg->tlc, s->stmtAssign.what, 4), xop_sz(cg->tlc, s->stmtAssign.to, type_size(s->stmtAssign.what->expression.type))); } else { - printf("mov %s, %s\n", xop(s->stmtAssign.what), xop_sz(s->stmtAssign.to, type_size(s->stmtAssign.what->expression.type))); + printf("mov %s, %s\n", xop(cg->tlc, s->stmtAssign.what), xop_sz(cg->tlc, s->stmtAssign.to, type_size(s->stmtAssign.what->expression.type))); } } @@ -336,7 +352,7 @@ void cg_chunk(CGState *cg, AST *a) { size_t lbl = nextLocalLabel++; - printf("cmp %s, %s\n", xop(s->stmtIf.expression->exprBinOp.operands[0]), xop(s->stmtIf.expression->exprBinOp.operands[1])); + printf("cmp %s, %s\n", xop(cg->tlc, s->stmtIf.expression->exprBinOp.operands[0]), xop(cg->tlc, s->stmtIf.expression->exprBinOp.operands[1])); printf("j%s .L%lu\n", xj(binop_comp_opposite(s->stmtIf.expression->exprBinOp.operator)), lbl); cg_chunk(cg, s->stmtIf.then); @@ -351,45 +367,131 @@ void cg_chunk(CGState *cg, AST *a) { assert(s->stmtReturn.val->exprVar.thing->data.var.color == COLOR_EAX); } + if(a->chunk.stackReservation) { + printf("add esp, %lu\n", a->chunk.stackReservation); + } + printf("ret\n"); + } else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_VAR) { + + /* Loop guard, probably. */ + } else abort(); s = s->statement.next; } +} + +struct Spill2StackState { + AST *targetTLC; + VarTableEntry *target; +}; + +struct Spill2VarState { + VarTableEntry *target; +}; + +static void spill2var_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { + static size_t vidx = 0; - if(a->chunk.stackReservation) { - printf("add esp, %lu\n", a->chunk.stackReservation); + struct Spill2VarState *this = ud; + + AST *a = *aptr; + + if(a->nodeKind == AST_STMT_ASSIGN && a->stmtAssign.to->nodeKind == AST_EXPR_CALL) { + assert(a->stmtAssign.what->nodeKind == AST_EXPR_VAR && a->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR); + + if(a->stmtAssign.what->exprVar.thing == this->target) { + + VarTableEntry *new = calloc(1, sizeof(*new)); + new->kind = VARTABLEENTRY_VAR; + new->type = a->stmtAssign.what->exprVar.thing->type; + new->data.var.name = malp("$s2v_%lu", vidx++); + + tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * (++tlc->chunk.varCount)); + tlc->chunk.vars[tlc->chunk.varCount - 1] = new; + + ASTExprVar *ev0 = calloc(1, sizeof(*ev0)); + ev0->nodeKind = AST_EXPR_VAR; + ev0->type = new->type; + ev0->thing = a->stmtAssign.what->exprVar.thing; + + ASTExprVar *ev1 = calloc(1, sizeof(*ev1)); + ev1->nodeKind = AST_EXPR_VAR; + ev1->type = new->type; + ev1->thing = new; + + ASTStmtAssign *ass = calloc(1, sizeof(*ass)); + ass->nodeKind = AST_STMT_ASSIGN; + ass->what = (AST*) ev0; + ass->to = (AST*) ev1; + + a->stmtAssign.what->exprVar.thing = new; + + ass->next = a->statement.next; + a->statement.next = (AST*) ass; + + if(!ass->next) { + chunk->chunk.statementLast = (AST*) ass; + } + + } + } + + if(a->nodeKind == AST_STMT_RETURN && a->stmtReturn.val && a->stmtReturn.val->nodeKind == AST_EXPR_VAR && a->stmtReturn.val->exprVar.thing == this->target) { + + VarTableEntry *new = calloc(1, sizeof(*new)); + new->kind = VARTABLEENTRY_VAR; + new->type = a->stmtReturn.val->exprVar.thing->type; + new->data.var.name = malp("$s2v_%lu", vidx++); + + tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * (++tlc->chunk.varCount)); + tlc->chunk.vars[tlc->chunk.varCount - 1] = new; + + ASTExprVar *ev0 = calloc(1, sizeof(*ev0)); + ev0->nodeKind = AST_EXPR_VAR; + ev0->type = new->type; + ev0->thing = a->stmtReturn.val->exprVar.thing; + + ASTExprVar *ev1 = calloc(1, sizeof(*ev1)); + ev1->nodeKind = AST_EXPR_VAR; + ev1->type = new->type; + ev1->thing = new; + + ASTStmtAssign *ass = calloc(1, sizeof(*ass)); + ass->nodeKind = AST_STMT_ASSIGN; + ass->what = (AST*) ev1; + ass->to = (AST*) ev0; + + stmt->stmtReturn.val->exprVar.thing = new; + + ass->next = stmt; + + if(stmtPrev) { + stmtPrev->statement.next = (AST*) ass; + } else { + chunk->chunk.statementFirst = (AST*) ass; + } } } -// MUST FIRST CALL with *aptr == tlc SO stackReservation IS UPDATED!! -static void spill_pass(AST *tlc, AST **aptr, VarTableEntry *vte) { +static void spill2stack_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { + struct Spill2StackState *this = ud; + + if(tlc != this->targetTLC) { + // Don't do anything. + return; + } + AST *a = *aptr; - if(a->nodeKind == AST_CHUNK) { - for(AST **s = &a->chunk.statementFirst; *s; s = &((*s)->statement.next)) { - spill_pass(tlc, s, vte); - } - - tlc->chunk.stackReservation += 4; - } else if(a->nodeKind == AST_STMT_IF) { - spill_pass(tlc, &a->stmtIf.expression, vte); - spill_pass(tlc, &a->stmtIf.then, vte); - } else if(a->nodeKind == AST_STMT_LOOP) { - spill_pass(tlc, &a->stmtLoop.body, vte); - } else if(a->nodeKind == AST_STMT_ASSIGN) { - spill_pass(tlc, &a->stmtAssign.what, vte); - - if(a->stmtAssign.to) { - spill_pass(tlc, &a->stmtAssign.to, vte); - } - } else if(a->nodeKind == AST_STMT_EXPR) { - spill_pass(tlc, &a->stmtExpr.expr, vte); + if(a == tlc) { + a->chunk.stackReservation += 4; } else if(a->nodeKind == AST_EXPR_VAR) { - if(a->exprVar.thing == vte) { - // FINALLY SPILL + if(a->exprVar.thing == this->target) { + // DO THE SPILL ASTExprStackPointer *rsp = malloc(sizeof(*rsp)); rsp->nodeKind = AST_EXPR_STACK_POINTER; @@ -416,31 +518,6 @@ static void spill_pass(AST *tlc, AST **aptr, VarTableEntry *vte) { *aptr = (AST*) deref; } - } else if(a->nodeKind == AST_EXPR_BINARY_OP) { - spill_pass(tlc, &a->exprBinOp.operands[0], vte); - spill_pass(tlc, &a->exprBinOp.operands[1], vte); - } else if(a->nodeKind == AST_EXPR_UNARY_OP) { - spill_pass(tlc, &a->exprUnOp.operand, vte); - } else if(a->nodeKind == AST_EXPR_CALL) { - spill_pass(tlc, &a->exprCall.what, vte); - - for(size_t p = 0; p < a->exprCall.what->expression.type->function.argCount; p++) { - spill_pass(tlc, &a->exprCall.args[p], vte); - } - } else if(a->nodeKind == AST_EXPR_PRIMITIVE) { - } else if(a->nodeKind == AST_EXPR_STRING_LITERAL) { - } else if(a->nodeKind == AST_EXPR_CAST) { - spill_pass(tlc, &a->exprCast.what, vte); - } else if(a->nodeKind == AST_EXPR_STACK_POINTER) { - } else if(a->nodeKind == AST_STMT_BREAK) { - } else if(a->nodeKind == AST_STMT_CONTINUE) { - } else if(a->nodeKind == AST_STMT_EXT_ALIGN) { - } else if(a->nodeKind == AST_STMT_EXT_ORG) { - } else if(a->nodeKind == AST_STMT_EXT_SECTION) { - } else if(a->nodeKind == AST_STMT_DECL) { - assert(a->stmtDecl.thing->kind != VARTABLEENTRY_VAR || a->stmtDecl.expression); - } else { - abort(); } } @@ -451,6 +528,223 @@ static int ud_empty(VarTableEntry *a) { return !a->data.var.usedefFirst; } +static void precolor_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { + AST *n = *nptr; + + if(n == tlc) { + for(size_t i = 0; i < n->chunk.varCount; i++) { + n->chunk.vars[i]->data.var.color = -1; + n->chunk.vars[i]->data.var.precolored = false; + } + } + + if(n->nodeKind == AST_STMT_RETURN) { + if(n->stmtReturn.val) { + assert(n->stmtReturn.val->nodeKind == AST_EXPR_VAR && n->stmtReturn.val->exprVar.thing->kind == VARTABLEENTRY_VAR); + + VarTableEntry *vte = n->stmtReturn.val->exprVar.thing; + + assert(!vte->data.var.precolored); + + vte->data.var.color = COLOR_EAX; + vte->data.var.precolored = true; + } + } else if(n->nodeKind == AST_STMT_ASSIGN && n->stmtAssign.to->nodeKind == AST_EXPR_CALL) { + assert(n->stmtAssign.what->nodeKind == AST_EXPR_VAR && n->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR); + + VarTableEntry *vte = n->stmtAssign.what->exprVar.thing; + + assert(!vte->data.var.precolored); + + vte->data.var.color = COLOR_EAX; + vte->data.var.precolored = true; + } +} + +typedef VarTableEntry *Adjacency[2]; + +static bool var_collision(AST *tlc, VarTableEntry *v1, VarTableEntry *v2) { + /* 1D intersection test */ + return !ud_empty(v1) && !ud_empty(v2) && ( + (ast_stmt_is_after(tlc, v1->data.var.usedefFirst->stmt, v2->data.var.usedefFirst->stmt) == 1 + && ast_stmt_is_after(tlc, v2->data.var.usedefLast->stmt, v1->data.var.usedefFirst->stmt) == 1) + || + (ast_stmt_is_after(tlc, v1->data.var.usedefLast->stmt, v2->data.var.usedefFirst->stmt) == 1 + && ast_stmt_is_after(tlc, v2->data.var.usedefLast->stmt, v1->data.var.usedefLast->stmt) == 1) + ); +} + +static VarTableEntry *get_precolor_spill_candidate(AST *tlc) { + Adjacency *adjs = NULL; + size_t adjCount = 0; + + for(size_t i = 0; i < tlc->chunk.varCount; i++) { + tlc->chunk.vars[i]->data.var.degree = 0; + + for(size_t j = 0; j < tlc->chunk.varCount; j++) { + + if( tlc->chunk.vars[i]->data.var.precolored + && tlc->chunk.vars[j]->data.var.precolored + && tlc->chunk.vars[i]->data.var.color == tlc->chunk.vars[j]->data.var.color + && var_collision(tlc, tlc->chunk.vars[i], tlc->chunk.vars[j])) { + + adjs = realloc(adjs, sizeof(*adjs) * ++adjCount); + + adjs[adjCount - 1][0] = tlc->chunk.vars[i]; + adjs[adjCount - 1][1] = tlc->chunk.vars[j]; + } + + } + } + + if(adjCount == 0) { + return NULL; + } + + for(size_t a = 0; a < adjCount; a++) { + adjs[a][0]->data.var.degree++; + adjs[a][1]->data.var.degree++; + } + + VarTableEntry *maxdeg = tlc->chunk.vars[0]; + + for(size_t v = 1; v < tlc->chunk.varCount; v++) { + if(maxdeg->data.var.degree < tlc->chunk.vars[v]->data.var.degree) { + maxdeg = tlc->chunk.vars[v]; + } + } + + free(adjs); + + return maxdeg; +} + +struct CalleeSavedState { + AST *targetTLC; + VarTableEntry *ebxuser; + + // To make sure we don't process the same return statement to infinity + AST *lastProcessedReturn; +}; + +static void callee_saved_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { + struct CalleeSavedState *this = ud; + + AST *n = *nptr; + + if(tlc != this->targetTLC) { + // Don't do anything. + return; + } + + if(n == tlc) { + // Function entry + + ASTExprStackPointer *stk = calloc(1, sizeof(*stk)); + stk->nodeKind = AST_EXPR_STACK_POINTER; + stk->type = primitive_parse("u32"); + + ASTExprPrimitive *offset = calloc(1, sizeof(*offset)); + offset->nodeKind = AST_EXPR_PRIMITIVE; + offset->type = primitive_parse("u32"); + offset->val = tlc->chunk.stackReservation; + + ASTExprBinaryOp *sum = calloc(1, sizeof(*sum)); + sum->nodeKind = AST_EXPR_BINARY_OP; + sum->type = offset->type; + sum->operator = BINOP_ADD; + sum->operands[0] = (AST*) stk; + sum->operands[1] = (AST*) offset; + + ASTExprUnaryOp *deref = calloc(1, sizeof(*deref)); + deref->nodeKind = AST_EXPR_UNARY_OP; + deref->type = offset->type; + deref->operator = UNOP_DEREF; + deref->operand = (AST*) sum; + + ASTExprVar *ev = calloc(1, sizeof(*ev)); + ev->nodeKind = AST_EXPR_VAR; + ev->type = this->ebxuser->type; + ev->thing = this->ebxuser; + + ASTStmtAssign *assign = calloc(1, sizeof(*assign)); + assign->nodeKind = AST_STMT_ASSIGN; + assign->what = (AST*) deref; + assign->to = (AST*) ev; + + assign->next = tlc->chunk.statementFirst; + tlc->chunk.statementFirst = (AST*) assign; + + assert(tlc->chunk.statementLast != NULL); + + tlc->chunk.stackReservation += 4; + + } else if(n->nodeKind == AST_STMT_RETURN && n != this->lastProcessedReturn) { + // Function exit + + this->lastProcessedReturn = n; + + ASTExprStackPointer *stk = calloc(1, sizeof(*stk)); + stk->nodeKind = AST_EXPR_STACK_POINTER; + stk->type = primitive_parse("u32"); + + ASTExprPrimitive *offset = calloc(1, sizeof(*offset)); + offset->nodeKind = AST_EXPR_PRIMITIVE; + offset->type = primitive_parse("u32"); + offset->val = tlc->chunk.stackReservation; + + ASTExprBinaryOp *sum = calloc(1, sizeof(*sum)); + sum->nodeKind = AST_EXPR_BINARY_OP; + sum->type = offset->type; + sum->operator = BINOP_ADD; + sum->operands[0] = (AST*) stk; + sum->operands[1] = (AST*) offset; + + ASTExprUnaryOp *deref = calloc(1, sizeof(*deref)); + deref->nodeKind = AST_EXPR_UNARY_OP; + deref->type = offset->type; + deref->operator = UNOP_DEREF; + deref->operand = (AST*) sum; + + ASTExprVar *ev = calloc(1, sizeof(*ev)); + ev->nodeKind = AST_EXPR_VAR; + ev->type = this->ebxuser->type; + ev->thing = this->ebxuser; + + ASTStmtAssign *assign = calloc(1, sizeof(*assign)); + assign->nodeKind = AST_STMT_ASSIGN; + assign->what = (AST*) ev; + assign->to = (AST*) deref; + assign->next = stmt; + + if(stmtPrev) { + stmtPrev->statement.next = (AST*) assign; + } else { + tlc->chunk.statementFirst = (AST*) assign; + } + + } +} + +static void callee_saved(AST *tlc) { + VarTableEntry *ebxuser = NULL; + + for(size_t v = 0; v < tlc->chunk.varCount; v++) { + if(tlc->chunk.vars[v]->data.var.color == COLOR_EBX) { + ebxuser = tlc->chunk.vars[v]; + break; + } + } + + if(ebxuser) { + struct CalleeSavedState state; + state.targetTLC = tlc; + state.ebxuser = ebxuser; + + generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, callee_saved_visitor); + } +} + /* Welsh-Powell graph coloring */ static int comparator(const void *A, const void *B) { VarTableEntry *const *a = A; @@ -458,9 +752,20 @@ static int comparator(const void *A, const void *B) { return ((*a)->data.var.degree * (*a)->data.var.priority) - ((*b)->data.var.degree * (*b)->data.var.priority); } int cg_go(AST *a) { - typedef VarTableEntry *Adjacency[2]; - - ast_usedef_reset(a); + do { + generic_visitor(&a, NULL, NULL, a, a, NULL, precolor_visitor); + + ast_usedef_reset(a); + + VarTableEntry *vte = get_precolor_spill_candidate(a); + if(vte) { + struct Spill2VarState state; + memset(&state, 0, sizeof(state)); + state.target = vte; + + generic_visitor(&a, NULL, NULL, a, a, &state, spill2var_visitor); + } else break; + } while(true); size_t adjCount = 0; Adjacency *adjs = calloc(adjCount, sizeof(*adjs)); @@ -469,8 +774,11 @@ int cg_go(AST *a) { for(size_t vi = 0; vi < a->chunk.varCount; vi++) { vars[vi]->data.var.priority = 1; - //vars[vi]->data.var.color = 0; vars[vi]->data.var.degree = 0; + + if(!vars[vi]->data.var.precolored) { + vars[vi]->data.var.color = -1; + } } for(size_t v1i = 0; v1i < a->chunk.varCount; v1i++) { @@ -480,14 +788,7 @@ int cg_go(AST *a) { VarTableEntry *v1 = vars[v1i]; VarTableEntry *v2 = vars[v2i]; - /* 1D intersection test */ - if(!ud_empty(v1) && !ud_empty(v2) && ( - (ast_stmt_is_after(a, v1->data.var.usedefFirst->stmt, v2->data.var.usedefFirst->stmt) == 1 - && ast_stmt_is_after(a, v2->data.var.usedefLast->stmt, v1->data.var.usedefFirst->stmt) == 1) - || - (ast_stmt_is_after(a, v1->data.var.usedefLast->stmt, v2->data.var.usedefFirst->stmt) == 1 - && ast_stmt_is_after(a, v2->data.var.usedefLast->stmt, v1->data.var.usedefLast->stmt) == 1) - )) { + if(var_collision(a, v1, v2)) { VarTableEntry *min = v1 < v2 ? v1 : v2; VarTableEntry *max = v1 < v2 ? v2 : v1; @@ -546,13 +847,23 @@ nextColor:; if(lastColor >= 4) { // Spill node with highest degree - spill_pass(a, &a, vars[a->chunk.varCount - 1]); + struct Spill2StackState state; + memset(&state, 0, sizeof(state)); + state.target = vars[a->chunk.varCount - 1]; + + generic_visitor(&a, NULL, NULL, a, a, &state, spill2stack_visitor); return 0; } + if(a->chunk.functionType) { + callee_saved(a); + } + CGState cg; memset(&cg, 0, sizeof(cg)); + cg.tlc = a; + cg.isFunction = !!a->chunk.functionType; cg_chunk(&cg, a); diff --git a/src/dumberdowner.c b/src/dumberdowner.c index 5a53c9d..61d910c 100644 --- a/src/dumberdowner.c +++ b/src/dumberdowner.c @@ -12,17 +12,21 @@ // architecture. #include"x86.h" +#include /* Split away complex expression into a new local variable */ static AST *varify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) { - VarTableEntry *vte = malloc(sizeof(*vte)); + static size_t vidx = 0; + + VarTableEntry *vte = calloc(1, sizeof(*vte)); vte->kind = VARTABLEENTRY_VAR; vte->type = e->expression.type; - vte->data.var.color = 0; + vte->data.var.color = -1; + vte->data.var.precolored = false; vte->data.var.degree = 0; vte->data.var.priority = 0; vte->data.var.reachingDefs = NULL; - vte->data.var.name = strdup("googoo"); + vte->data.var.name = malp("$dumb%lu", vidx++); // Add to var array tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * (++tlc->chunk.varCount)); @@ -62,149 +66,268 @@ static AST *xopify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) { return varify(tlc, chunk, stmtPrev, stmt, e); } -static int dumben_chunk(AST *tlc, AST *chu) { - AST *sPrev = NULL; - AST *s = chu->chunk.statementFirst; +static bool is_incomplete_mul(AST *stmt) { + if(stmt->nodeKind != AST_STMT_ASSIGN) { + return false; + } - int effective = 0; + if(stmt->stmtAssign.what->nodeKind != AST_EXPR_VAR) { + + } - while(s) { + return true; +} + +struct DumbenState { + int effective; +}; + +static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud) { + struct DumbenState *this = ud; - if(s->nodeKind == AST_STMT_IF) { - - AST *e = s->stmtIf.expression; - - if(e->nodeKind == AST_EXPR_BINARY_OP && binop_is_comparison(e->exprBinOp.operator)) { - - if(is_xop(e->exprBinOp.operands[0]) == XOP_NOT_XOP) { - e->exprBinOp.operands[0] = xopify(tlc, chu, sPrev, s, e->exprBinOp.operands[0]); - effective = 1; - } - - if(is_xop(e->exprBinOp.operands[1]) == XOP_NOT_XOP) { - e->exprBinOp.operands[1] = xopify(tlc, chu, sPrev, s, e->exprBinOp.operands[1]); - effective = 1; - } - - if(is_xop(e->exprBinOp.operands[0]) == XOP_MEM && is_xop(e->exprBinOp.operands[1]) == XOP_MEM) { - // Can't have two mems; put one in var - - e->exprBinOp.operands[1] = varify(tlc, chu, sPrev, s, e->exprBinOp.operands[1]); - effective = 1; - } - - } else { - - s->stmtIf.expression = varify(tlc, chu, sPrev, s, e); - effective = 1; - + AST *s = *nptr; + + if(s->nodeKind == AST_STMT_IF) { + + AST *e = s->stmtIf.expression; + + if(e->nodeKind == AST_EXPR_BINARY_OP && binop_is_comparison(e->exprBinOp.operator)) { + + if(is_xop(e->exprBinOp.operands[0]) == XOP_NOT_XOP) { + e->exprBinOp.operands[0] = xopify(tlc, chu, stmtPrev, s, e->exprBinOp.operands[0]); + this->effective = 1; } - effective |= dumben_chunk(tlc, s->stmtIf.then); - - } else if(s->nodeKind == AST_STMT_LOOP) { - - effective |= dumben_chunk(tlc, s->stmtLoop.body); - - } else if(s->nodeKind == AST_STMT_ASSIGN) { - - if(ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to) && sPrev) { - // Remove this statement from AST - sPrev->statement.next = s->statement.next; - effective = 1; - } else { - - if(s->stmtAssign.what->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.what->exprUnOp.operator == UNOP_DEREF - && s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_DEREF) { - - s->stmtAssign.to = varify(tlc, chu, sPrev, s, s->stmtAssign.to); - effective = 1; - } else if(s->stmtAssign.what && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_CALL) { - ASTExprCall *call = &s->stmtAssign.to->exprCall; - - int argCount = call->what->expression.type->function.argCount; - - for(int i = 0; i < argCount; i++) { - if(is_xop(call->args[i]) == XOP_NOT_XOP) { - call->args[i] = xopify(tlc, chu, sPrev, s, call->args[i]); - effective = 1; - } - } - } else if(s->stmtAssign.to && s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_NEGATE && !ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprUnOp.operand)) { - // Turn this: - // a = -b - // into - // a = b - // a = -a - - AST *ev[2] = { - ast_deep_copy(s->stmtAssign.what), - ast_deep_copy(s->stmtAssign.what) - }; - - AST *negation = s->stmtAssign.to; - - s->stmtAssign.to = negation->exprUnOp.operand; - negation->exprUnOp.operand = ev[0]; - - AST *assign2 = malloc(sizeof(ASTStmtAssign)); - assign2->nodeKind = AST_STMT_ASSIGN; - assign2->stmtAssign.what = ev[1]; - assign2->stmtAssign.to = negation; - - assign2->statement.next = s->statement.next; - s->statement.next = assign2; - - effective = 1; - } else if(is_xop(s->stmtAssign.to) == XOP_NOT_XOP) { - if(s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_DEREF) { - s->stmtAssign.to->exprUnOp.operand = varify(tlc, chu, sPrev, s, s->stmtAssign.to->exprUnOp.operand); - - effective = 1; - } else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator < BINOP_SIMPLES && !ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprBinOp.operands[0])) { - // Turn this: - // a = b op c - // into - // a = b - // a = a op c - - AST *assign2 = malloc(sizeof(ASTStmtAssign)); - assign2->nodeKind = AST_STMT_ASSIGN; - assign2->stmtAssign.what = ast_deep_copy(s->stmtAssign.what); - assign2->stmtAssign.to = s->stmtAssign.to->exprBinOp.operands[0]; - - sPrev->statement.next = assign2; - assign2->statement.next = s; - - s->stmtAssign.to->exprBinOp.operands[0] = ast_deep_copy(s->stmtAssign.what); - - effective = 1; - } else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && !is_xop(s->stmtAssign.to->exprBinOp.operands[0])) { - s->stmtAssign.to->exprBinOp.operands[0] = xopify(tlc, chu, sPrev, s, s->stmtAssign.to->exprBinOp.operands[0]); - effective = 1; - } else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && !is_xop(s->stmtAssign.to->exprBinOp.operands[1])) { - s->stmtAssign.to->exprBinOp.operands[1] = xopify(tlc, chu, sPrev, s, s->stmtAssign.to->exprBinOp.operands[1]); - effective = 1; - } - } + if(is_xop(e->exprBinOp.operands[1]) == XOP_NOT_XOP) { + e->exprBinOp.operands[1] = xopify(tlc, chu, stmtPrev, s, e->exprBinOp.operands[1]); + this->effective = 1; } + if(is_xop(e->exprBinOp.operands[0]) == XOP_MEM && is_xop(e->exprBinOp.operands[1]) == XOP_MEM) { + // Can't have two mems; put one in var + + e->exprBinOp.operands[1] = varify(tlc, chu, stmtPrev, s, e->exprBinOp.operands[1]); + this->effective = 1; + } + + } else { + + s->stmtIf.expression = varify(tlc, chu, stmtPrev, s, e); + this->effective = 1; + + } + + } else if(s->nodeKind == AST_STMT_LOOP) { + + } else if(s->nodeKind == AST_STMT_RETURN) { + + // ret specifically returns in eax always, so it needs to be in a var + if(s->stmtReturn.val && (!is_xop(s->stmtReturn.val) || s->stmtReturn.val->nodeKind == AST_EXPR_PRIMITIVE)) { + + s->stmtReturn.val = varify(tlc, chu, stmtPrev, s, s->stmtReturn.val); + this->effective = 1; + + } + + } else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_CALL) { + + // Turn this: + // f(x); + // into: + // a = f(x); + + // So `a` would be colored as `eax` + + s->stmtExpr.expr = varify(tlc, chu, stmtPrev, s, s->stmtExpr.expr); + + // Purge this statement entirely, otherwise it'd be + // a = f(x); + // a; + if(stmtPrev) { + assert(stmtPrev->statement.next->statement.next == s); + stmtPrev->statement.next->statement.next = s->statement.next; + } else { + assert(chu->chunk.statementFirst->statement.next = s); + chu->chunk.statementFirst->statement.next = s->statement.next; + } + + } else if(s->nodeKind == AST_STMT_ASSIGN) { + + if(ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to) && stmtPrev) { + // NOP; remove this statement from AST + stmtPrev->statement.next = s->statement.next; + this->effective = 1; + } else { + + if(s->stmtAssign.what->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.what->exprUnOp.operator == UNOP_DEREF + && s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_DEREF) { + + s->stmtAssign.to = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to); + this->effective = 1; + } else if(s->stmtAssign.what && s->stmtAssign.what->nodeKind == AST_EXPR_VAR && s->stmtAssign.what->exprVar.thing->kind == VARTABLEENTRY_VAR && s->stmtAssign.to->nodeKind == AST_EXPR_CALL) { + ASTExprCall *call = &s->stmtAssign.to->exprCall; + + int argCount = call->what->expression.type->function.argCount; + + for(int i = 0; i < argCount; i++) { + if(is_xop(call->args[i]) == XOP_NOT_XOP) { + call->args[i] = xopify(tlc, chu, stmtPrev, s, call->args[i]); + this->effective = 1; + } + } + } else if(s->stmtAssign.to && s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_NEGATE && !ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprUnOp.operand)) { + // Turn this: + // a = -b + // into + // a = b + // a = -a + + AST *ev[2] = { + ast_deep_copy(s->stmtAssign.what), + ast_deep_copy(s->stmtAssign.what) + }; + + AST *negation = s->stmtAssign.to; + + s->stmtAssign.to = negation->exprUnOp.operand; + negation->exprUnOp.operand = ev[0]; + + AST *assign2 = malloc(sizeof(ASTStmtAssign)); + assign2->nodeKind = AST_STMT_ASSIGN; + assign2->stmtAssign.what = ev[1]; + assign2->stmtAssign.to = negation; + + assign2->statement.next = s->statement.next; + s->statement.next = assign2; + + this->effective = 1; + } else if(is_xop(s->stmtAssign.to) == XOP_NOT_XOP) { + if(s->stmtAssign.to->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.to->exprUnOp.operator == UNOP_DEREF) { + s->stmtAssign.to->exprUnOp.operand = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprUnOp.operand); + + this->effective = 1; + } else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator == BINOP_MUL) { + + if(s->stmtAssign.what->nodeKind != AST_EXPR_VAR) { + s->stmtAssign.what = varify(tlc, chu, stmtPrev, s, s->stmtAssign.what); + this->effective = 1; + } + + /*if(!(s->statement.next && s->statement.next->nodeKind == AST_STMT_ASSIGN && s->statement.next->stmtAssign.)) { + + }*/ + + // TODO: implement multiplication + + } else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && s->stmtAssign.to->exprBinOp.operator < BINOP_SIMPLES && !ast_expression_equal(s->stmtAssign.what, s->stmtAssign.to->exprBinOp.operands[0])) { + // Turn this: + // a = b op c + // into + // a = b + // a = a op c + + AST *assign2 = malloc(sizeof(ASTStmtAssign)); + assign2->nodeKind = AST_STMT_ASSIGN; + assign2->stmtAssign.what = ast_deep_copy(s->stmtAssign.what); + assign2->stmtAssign.to = s->stmtAssign.to->exprBinOp.operands[0]; + + if(stmtPrev) { + stmtPrev->statement.next = assign2; + } else { + chu->chunk.statementFirst = assign2; + } + assign2->statement.next = s; + + s->stmtAssign.to->exprBinOp.operands[0] = ast_deep_copy(s->stmtAssign.what); + + this->effective = 1; + } else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && !is_xop(s->stmtAssign.to->exprBinOp.operands[0])) { + s->stmtAssign.to->exprBinOp.operands[0] = xopify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprBinOp.operands[0]); + this->effective = 1; + } else if(s->stmtAssign.to->nodeKind == AST_EXPR_BINARY_OP && !is_xop(s->stmtAssign.to->exprBinOp.operands[1])) { + s->stmtAssign.to->exprBinOp.operands[1] = xopify(tlc, chu, stmtPrev, s, s->stmtAssign.to->exprBinOp.operands[1]); + this->effective = 1; + } + } } - sPrev = s; - s = s->statement.next; } +} + +static void pre_dumb_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) { + AST *n = *nptr; - return effective; + if(n == tlc) { + if(tlc->chunk.functionType) { + size_t argCount = n->chunk.functionType->function.argCount; + + // First argCount vtes in list are the arguments + for(size_t i = 0; i < argCount; i++) { + VarTableEntry *vte = n->chunk.vars[i]; + + ASTExprStackPointer *stck = calloc(1, sizeof(*stck)); + stck->nodeKind = AST_EXPR_STACK_POINTER; + stck->type = type_pointer_wrap(vte->type); + + ASTExprPrimitive *offset = calloc(1, sizeof(*offset)); + offset->nodeKind = AST_EXPR_PRIMITIVE; + offset->type = primitive_parse("u32"); + offset->val = 4 + i * 4; + + ASTExprBinaryOp *sum = calloc(1, sizeof(*sum)); + sum->nodeKind = AST_EXPR_BINARY_OP; + sum->type = stck->type; + sum->operands[0] = (AST*) stck; + sum->operands[1] = (AST*) offset; + sum->operator = BINOP_ADD; + + ASTExprUnaryOp *deref = calloc(1, sizeof(*deref)); + deref->nodeKind = AST_EXPR_UNARY_OP; + deref->type = vte->type; + deref->operand = (AST*) sum; + deref->operator = UNOP_DEREF; + + ASTExprVar *evar = calloc(1, sizeof(*evar)); + evar->nodeKind = AST_EXPR_VAR; + evar->type = vte->type; + evar->thing = vte; + + ASTStmtAssign *ass = calloc(1, sizeof(*ass)); + ass->nodeKind = AST_STMT_ASSIGN; + ass->next = NULL; + ass->what = (AST*) evar; + ass->to = (AST*) deref; + ass->next = n->chunk.statementFirst; + + if(n->chunk.statementFirst) { + n->chunk.statementFirst = ass; + } else { + assert(!n->chunk.statementLast); + n->chunk.statementFirst = n->chunk.statementLast = ass; + } + } + } + } +} + +void dumben_pre(AST *tlc) { + generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, pre_dumb_visitor); } void dumben_go(AST* tlc) { size_t i = 0; while(1) { - fprintf(stderr, "// Dumbing down %lu...\n", i++); + fprintf(stderr, "; Dumbing down %lu...\n", i++); - int successful = dumben_chunk(tlc, tlc); + struct DumbenState state; + memset(&state, 0, sizeof(state)); - if(!successful) break; + generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, dumben_visitor); + + int successful = state.effective; + + if(!successful) { + break; + } } } diff --git a/src/dumberdowner.h b/src/dumberdowner.h index 5ce3b85..ae44e44 100644 --- a/src/dumberdowner.h +++ b/src/dumberdowner.h @@ -2,4 +2,5 @@ #include"ast.h" -void dumben_go(AST* a); \ No newline at end of file +void dumben_pre(AST *tlc); +void dumben_go(AST* tlc); diff --git a/src/lexer.c b/src/lexer.c index 04e8f52..e60799f 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -39,6 +39,11 @@ char *TOKEN_NAMES[] = { "'!'", "'continue'", "'return'", + "'->'", + "'<='", + "'>='", + "'<'", + "'>'", }; static int isAlpha(int c) { @@ -118,6 +123,10 @@ Token nct_tokenize(FILE *f) { return tok; } else if(c == '-') { tok.type = TOKEN_MINUS; + int c = nextc(f); + if(c == '>') { + tok.type = TOKEN_ARROW; + } else ungetc(c, f); return tok; } else if(c == '*') { tok.type = TOKEN_STAR; @@ -150,6 +159,20 @@ Token nct_tokenize(FILE *f) { tok.type = TOKEN_EXCLAMATION_EQUALS; } else ungetc(c, f); return tok; + } else if(c == '<') { + tok.type = TOKEN_LESS; + int c = nextc(f); + if(c == '=') { + tok.type = TOKEN_LEQUAL; + } else ungetc(c, f); + return tok; + } else if(c == '>') { + tok.type = TOKEN_GREATER; + int c = nextc(f); + if(c == '=') { + tok.type = TOKEN_GEQUAL; + } else ungetc(c, f); + return tok; } else if(c == '/') { int c = nextc(f); if(c == '*') { /* This is a comment; skip. */ diff --git a/src/lexer.h b/src/lexer.h index 11819d3..8ced7b9 100644 --- a/src/lexer.h +++ b/src/lexer.h @@ -38,7 +38,12 @@ typedef enum { TOKEN_EXCLAMATION_EQUALS, TOKEN_EXCLAMATION, TOKEN_CONTINUE, - TOKEN_RETURN + TOKEN_RETURN, + TOKEN_ARROW, + TOKEN_LEQUAL, + TOKEN_GEQUAL, + TOKEN_LESS, + TOKEN_GREATER, } TokenKind; typedef struct { diff --git a/src/ntc.c b/src/ntc.c index 59d141a..1770f09 100644 --- a/src/ntc.c +++ b/src/ntc.c @@ -37,17 +37,20 @@ int main(int argc_, char **argv_) { free(tokens); - fputs("/* === Original AST === */\n", stderr); + fputs("; === Original AST ===\n", stderr); fputs(ast_dump(chunk), stderr); fputc('\n', stderr); + dumben_pre(chunk); dumben_go(chunk); - fputs("\n/* === Dumbified === */\n", stderr); + fputs("\n; === Dumbified ===\n", stderr); fputs(ast_dump(chunk), stderr); fputc('\n', stderr); - while(!cg_go(chunk)); + while(!cg_go(chunk)) { + dumben_go(chunk); + } return 0; } diff --git a/src/parse.c b/src/parse.c index 6b397a5..5cc3a99 100644 --- a/src/parse.c +++ b/src/parse.c @@ -41,6 +41,13 @@ typedef struct { VarTable *loopScope; size_t guardedVarCount; ASTExprVar **guardedVars; + + // Used for generating statements that load & store arguments + int isInFunction; + + // Skim mode disables parsing function definitions + // This is needed to automatically forward-declare symbols + int skimMode; } Parser; static Token get(Parser *P) { @@ -111,27 +118,6 @@ static ASTExprPrimitive *parse_prim(Parser *P) { return ret; } -/*static void newusedef(Parser *P, VarTableEntry *v, AST *expr) { - ReachingDefs *defs = v->data.var.reachingDefs; - - while(defs) { - for(size_t i = 0; i < defs->defCount; i++) { - P->udsToAdd = realloc(P->udsToAdd, sizeof(*P->udsToAdd) * (++P->udsToAddCount)); - P->udsToAdd[P->udsToAddCount - 1].ud.def = defs->defs[i]; - P->udsToAdd[P->udsToAddCount - 1].ud.use = expr; - P->udsToAdd[P->udsToAddCount - 1].ud.stmt = NULL; // set by pushstmt - P->udsToAdd[P->udsToAddCount - 1].ud.next = NULL; - P->udsToAdd[P->udsToAddCount - 1].to = v; - } - - if(defs->excludeParent) { - break; - } - - defs = defs->parent; - } -}*/ - static AST *exprvar(Parser *P, VarTableEntry *v) { AST *a = malloc(sizeof(ASTExprVar)); a->nodeKind = AST_EXPR_VAR; @@ -237,12 +223,12 @@ AST *nct_cast_expr(AST *what, Type *to) { abort(); } -ASTChunk *nct_parse_chunk(Parser*, int, int); +ASTChunk *nct_parse_chunk(Parser*, int, int, VarTable*, Type *ft); Type *nct_parse_typename(Parser *P); AST *nct_parse_expression(Parser *P, int lOP) { if(lOP == 0) { - // Test if this is an anonymous function + // Test if this is an anonymous function Type *ft = nct_parse_typename(P); if(ft) { assert(ft->type == TYPE_TYPE_FUNCTION); @@ -251,11 +237,23 @@ AST *nct_parse_expression(Parser *P, int lOP) { e->nodeKind = AST_EXPR_FUNC; e->type = ft; - maybe(P, TOKEN_SQUIGGLY_L); + if(P->skimMode) { + // In skim mode, it won't be parsed normally anyway + } else { + expect(P, TOKEN_ARROW); + + expect(P, TOKEN_SQUIGGLY_L); + + P->isInFunction++; + + e->chunk = (AST*) nct_parse_chunk(P, 1, 0, vartable_new(P->scope), ft); + e->chunk->chunk.functionType = ft; + + P->isInFunction--; + + expect(P, TOKEN_SQUIGGLY_R); + } - e->chunk = (AST*) nct_parse_chunk(P, 1, 0); - - maybe(P, TOKEN_SQUIGGLY_R); return (AST*) e; } @@ -274,7 +272,15 @@ AST *nct_parse_expression(Parser *P, int lOP) { return (AST*) ret; } - return exprvar(P, vartable_find(P->scope, get(P).content)); + Token varname = get(P); + + VarTableEntry *vte = vartable_find(P->scope, varname.content); + + if(!vte) { + stahp(varname.row, varname.column, "Unknown variable %s", varname.content); + } + + return exprvar(P, vte); } else if(peek(P, 0).type == TOKEN_STRING) { ASTExprStringLiteral *ret = malloc(sizeof(*ret)); ret->nodeKind = AST_EXPR_STRING_LITERAL; @@ -348,15 +354,6 @@ AST *nct_parse_expression(Parser *P, int lOP) { stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Only function types may be called."); } - VarTableEntry *tempo = calloc(1, sizeof(*tempo)); - tempo->kind = VARTABLEENTRY_VAR; - tempo->type = ret->expression.type->function.ret; - tempo->data.var.name = "$temp"; - tempo->data.var.color = COLOR_EAX; - - P->topLevel->vars = realloc(P->topLevel->vars, sizeof(*P->topLevel->vars) * (++P->topLevel->varCount)); - P->topLevel->vars[P->topLevel->varCount - 1] = tempo; - ASTExprCall *call = malloc(sizeof(*call)); call->nodeKind = AST_EXPR_CALL; call->type = ret->expression.type->function.ret; @@ -378,15 +375,11 @@ AST *nct_parse_expression(Parser *P, int lOP) { } } - ASTStmtAssign *assign = calloc(1, sizeof(*assign)); - assign->nodeKind = AST_STMT_ASSIGN; - assign->what = exprvar(P, tempo); - assign->to = call; + if(argCount != call->what->expression.type->function.argCount) { + stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Mismatched number of arguments"); + } - pushstat(P, assign); - - ret = exprvar(P, tempo); - /* TODO: Check argument count. */ + ret = (AST*) call; } else if(maybe(P, TOKEN_SQUAREN_L)) { ASTExprUnaryOp *ref = malloc(sizeof(*ref)); ref->nodeKind = AST_EXPR_UNARY_OP; @@ -524,11 +517,15 @@ AST *nct_parse_expression(Parser *P, int lOP) { } else if(lOP == 0) { AST *ret = nct_parse_expression(P, lOP + 1); - if(peek(P, 0).type == TOKEN_DOUBLE_EQUALS || peek(P, 0).type == TOKEN_EXCLAMATION_EQUALS) { + if(peek(P, 0).type == TOKEN_DOUBLE_EQUALS || peek(P, 0).type == TOKEN_EXCLAMATION_EQUALS || peek(P, 0).type == TOKEN_LESS || peek(P, 0).type == TOKEN_GREATER || peek(P, 0).type == TOKEN_LEQUAL || peek(P, 0).type == TOKEN_GEQUAL) { while(1) { BinaryOp op; if(maybe(P, TOKEN_DOUBLE_EQUALS)) op = BINOP_EQUAL; else if(maybe(P, TOKEN_EXCLAMATION_EQUALS)) op = BINOP_NEQUAL; + else if(maybe(P, TOKEN_LESS)) op = BINOP_LESS; + else if(maybe(P, TOKEN_GREATER)) op = BINOP_GREATER; + else if(maybe(P, TOKEN_LEQUAL)) op = BINOP_LEQUAL; + else if(maybe(P, TOKEN_GEQUAL)) op = BINOP_GEQUAL; else break; ASTExprBinaryOp *astop = malloc(sizeof(*astop)); @@ -588,7 +585,7 @@ Type *nct_parse_typename(Parser *P) { ret = (Type*) ptr; } else if(maybe(P, TOKEN_PAREN_L)) { - TypeFunction *fun = malloc(sizeof(*fun)); + TypeFunction *fun = calloc(1, sizeof(*fun)); fun->type = TYPE_TYPE_FUNCTION; fun->ret = ret; fun->argCount = 0; @@ -597,12 +594,18 @@ Type *nct_parse_typename(Parser *P) { if(!maybe(P, TOKEN_PAREN_R)) { while(1) { fun->argCount++; - fun->args = realloc(fun->args, sizeof(Type*) * fun->argCount); + fun->args = realloc(fun->args, sizeof(*fun->args) * fun->argCount); + fun->argNames = realloc(fun->argNames, sizeof(*fun->argNames) * fun->argCount); + if((fun->args[fun->argCount - 1] = nct_parse_typename(P)) == NULL) { free(fun); goto backtrack; } + if(peek(P, 0).type == TOKEN_IDENTIFIER) { + fun->argNames[fun->argCount - 1] = get(P).content; + } + if(maybe(P, TOKEN_PAREN_R)) { break; } else expect(P, TOKEN_COMMA); @@ -669,11 +672,10 @@ static AST *parse_declaration(Parser *P) { AST *ret = NULL; if(maybe(P, TOKEN_EQUALS) || (peek(P, 0).type == TOKEN_SEMICOLON && !isExternal && !isLocal)) { - /*if(isExternal || isLocal) { - fputs("'local' and 'extern' keywords are to be used for symbol declaration only.\n", stderr); - abort(); + if(isExternal || isLocal) { + stahp(name.row, name.column, "'local' and 'extern' keywords are to be used for symbol declaration only."); return NULL; - }*/ + } entry->kind = VARTABLEENTRY_VAR; entry->data.var.priority = 1; @@ -736,7 +738,11 @@ static AST *parse_declaration(Parser *P) { vartable_set(P->scope, name.content, entry); - expect(P, TOKEN_SEMICOLON); + if(P->skimMode) { + // In skim mode parsing is not done normally + } else { + expect(P, TOKEN_SEMICOLON); + } return ret; backtrack: @@ -759,7 +765,7 @@ void nct_parse_statement(Parser *P) { pushstat(P, ret); expect(P, TOKEN_SQUIGGLY_L); - ret->then = (AST*) nct_parse_chunk(P, 0, 0); + ret->then = (AST*) nct_parse_chunk(P, 0, 0, NULL, NULL); expect(P, TOKEN_SQUIGGLY_R); return; } else if(maybe(P, TOKEN_LOOP)) { @@ -774,7 +780,7 @@ void nct_parse_statement(Parser *P) { } expect(P, TOKEN_SQUIGGLY_L); - ret->body = (AST*) nct_parse_chunk(P, 0, 1); + ret->body = (AST*) nct_parse_chunk(P, 0, 1, NULL, NULL); expect(P, TOKEN_SQUIGGLY_R); pushstat(P, ret); @@ -824,25 +830,7 @@ void nct_parse_statement(Parser *P) { ret->next = NULL; if(!maybe(P, TOKEN_SEMICOLON)) { - AST *expr = nct_parse_expression(P, 0); - - VarTableEntry *tempo = calloc(1, sizeof(*tempo)); - tempo->kind = VARTABLEENTRY_VAR; - tempo->type = expr->expression.type; - tempo->data.var.name = "$temp"; - tempo->data.var.color = COLOR_EAX; - - P->topLevel->vars = realloc(P->topLevel->vars, sizeof(*P->topLevel->vars) * (++P->topLevel->varCount)); - P->topLevel->vars[P->topLevel->varCount - 1] = tempo; - - ASTStmtAssign *assign = malloc(sizeof(*assign)); - assign->nodeKind = AST_STMT_ASSIGN; - assign->what = exprvar(P, tempo); - assign->to = expr; - - ret->val = exprvar(P, tempo); - - pushstat(P, assign); + ret->val = nct_parse_expression(P, 0); expect(P, TOKEN_SEMICOLON); } @@ -941,7 +929,7 @@ void nct_parse_statement(Parser *P) { } } -ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) { +ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, VarTable *toplevelParent, Type *ft) { AST *ret = calloc(1, sizeof(ASTChunk)); ret->nodeKind = AST_CHUNK; ret->chunk.statementFirst = ret->chunk.statementLast = NULL; @@ -952,7 +940,9 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) { AST *oldChunk = (AST*) P->currentChunk; P->currentChunk = &ret->chunk; - P->scope = vartable_new(P->scope); + VarTable *oldScope = P->scope; + + P->scope = isTopLevel ? toplevelParent : vartable_new(oldScope); ASTChunk *oldTopLevel = P->topLevel; if(isTopLevel) { @@ -963,8 +953,9 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) { /* Find all symbol names and struct types ahead of time. Searches for colons as those can only mean symbol declarations */ + P->skimMode++; { - size_t oldIdx = P->i; + intmax_t oldIdx = P->i; while(1) { TokenKind k = get(P).type; @@ -985,7 +976,7 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) { /* Move back to beginning of declaration. */ do { P->i--; - } while(P->i >= 0 && P->tokens[P->i].type != TOKEN_SEMICOLON && P->tokens[P->i].type != TOKEN_SQUIGGLY_R); + } while(P->i >= oldIdx && P->tokens[P->i].type != TOKEN_SEMICOLON && P->tokens[P->i].type != TOKEN_SQUIGGLY_R && P->tokens[P->i].type != TOKEN_SQUIGGLY_L); P->i++; AST *d = parse_declaration(P); @@ -996,6 +987,24 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) { } P->i = oldIdx; } + P->skimMode--; + + /* Arguments */ + if(ft && isTopLevel) { + VarTableEntry **vtes = alloca(sizeof(*vtes) * ft->function.argCount); + + for(int i = ft->function.argCount - 1; i >= 0; i--) { + VarTableEntry *vte = calloc(1, sizeof(*vte)); + vte->kind = VARTABLEENTRY_VAR; + vte->type = ft->function.args[i]; + vte->data.var.name = ft->function.argNames[i]; + vte->data.var.color = -1; + + vartable_set(toplevelParent, vte->data.var.name, vte); + + vtes[i] = vte; + } + } /* Now actual parsing. */ @@ -1023,7 +1032,7 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize) { } } - P->scope = P->scope->parent; + P->scope = oldScope; P->currentChunk = oldChunk; @@ -1038,5 +1047,5 @@ AST *nct_parse(Token *tokens) { Parser P; memset(&P, 0, sizeof(P)); P.tokens = tokens; - return (AST*) nct_parse_chunk(&P, 1, 0); + return (AST*) nct_parse_chunk(&P, 1, 0, vartable_new(NULL), NULL); } diff --git a/src/types.c b/src/types.c index 5702a17..ee7668b 100644 --- a/src/types.c +++ b/src/types.c @@ -130,6 +130,8 @@ int type_equal(Type *O, Type *T) { if(!type_equal(O->function.args[i], T->function.args[i])) { return 0; } + + // Don't compare argument names } return 1; diff --git a/src/types.h b/src/types.h index ed2b0c4..9916adf 100644 --- a/src/types.h +++ b/src/types.h @@ -39,6 +39,7 @@ typedef struct TypeFunction { union Type *ret; + char **argNames; union Type **args; size_t argCount; } TypeFunction; diff --git a/src/vartable.h b/src/vartable.h index ea81eed..fb71681 100644 --- a/src/vartable.h +++ b/src/vartable.h @@ -53,6 +53,7 @@ typedef struct VarTableEntry { // a more advanced approach would be to use weights for different colors (e.g. multipliers "should" be in eax) uint8_t priority; int16_t color, degree; + bool precolored; // Used during parsing diff --git a/src/x86.h b/src/x86.h index 8518169..6890205 100644 --- a/src/x86.h +++ b/src/x86.h @@ -1,9 +1,9 @@ #pragma once #define COLOR_EAX 0 -#define COLOR_EBX 1 -#define COLOR_ECX 2 -#define COLOR_EDX 3 +#define COLOR_ECX 1 +#define COLOR_EDX 2 +#define COLOR_EBX 3 // Can expression be expressed as a single x86 operand? #define XOP_NOT_XOP 0