From a1077f7c03f1b922986b9c3611ce44e0f713b9ce Mon Sep 17 00:00:00 2001 From: Mid <245600-midn@users.noreply.gitlab.com> Date: Tue, 13 Feb 2024 21:33:49 +0200 Subject: [PATCH] Oh who gives a fuck? --- src/ast.c | 8 -- src/ast.h | 22 +++- src/cg.c | 45 +++++++- src/dumberdowner.c | 249 +++++++++++++++++++++++++++++++++++++++++++++ src/dumberdowner.h | 5 + src/ntc.c | 3 + src/parse.c | 136 +++++++++++++++++++++++-- src/types.c | 2 +- src/types.h | 1 + src/vartable.c | 1 + src/vartable.h | 1 + tests/bf.nct | 6 +- 12 files changed, 447 insertions(+), 32 deletions(-) create mode 100644 src/dumberdowner.c create mode 100644 src/dumberdowner.h diff --git a/src/ast.c b/src/ast.c index 642892b..aaa69b7 100644 --- a/src/ast.c +++ b/src/ast.c @@ -4,14 +4,6 @@ #include #include -int BINOP_COMMUTATIVE[] = { - [BINOP_ADD] = 1, - [BINOP_SUB] = 0, - [BINOP_MUL] = 1, - [BINOP_DIV] = 0 -}; - - AST *ast_expression_optimize(AST *ast) { return ast; } diff --git a/src/ast.h b/src/ast.h index 920aeea..52b413e 100644 --- a/src/ast.h +++ b/src/ast.h @@ -5,7 +5,20 @@ #include"lexer.h" #include"vartable.h" -typedef enum { +// VISITORS APPEAR IN varify_change_usedefs,ast_expr_is_equal,ast_stmt_is_after, +// dumben_chunk, cg_go, loop_second_pass AND OTHERS +// +// THEY ***MUST*** BE CHANGED ACCORDINGLY IF AST IS ALTERED + +#pragma pack(push, 1) + +#ifdef __GNUC__ +#define ENUMPAK __attribute__((packed)) +#else +#define ENUMPAK +#endif + +typedef enum ENUMPAK { AST_CHUNK, AST_STMT_DECL, AST_TYPE_IDENTIFIER, @@ -29,7 +42,7 @@ typedef enum { AST_STMT_EXT_SECTION, } ASTKind; -typedef enum { +typedef enum ENUMPAK { BINOP_ADD = 0, BINOP_SUB = 1, BINOP_BITWISE_AND = 2, @@ -44,7 +57,6 @@ typedef enum { BINOP_WTF = 999, } BinaryOp; -extern int BINOP_COMMUTATIVE[]; static inline int binop_is_comparison(BinaryOp op) { return op == BINOP_EQUAL || op == BINOP_NEQUAL; @@ -59,7 +71,7 @@ static inline BinaryOp binop_comp_opposite(BinaryOp op) { return BINOP_WTF; } -typedef enum { +typedef enum ENUMPAK { UNOP_DEREF = 0, UNOP_NEGATE = 1, UNOP_BITWISE_NOT = 2, @@ -251,6 +263,8 @@ typedef union AST { ASTStmtExtSection stmtExtSection; } AST; +#pragma pack(pop) + AST *ast_expression_optimize(AST*); int ast_expression_equal(AST*, AST*); diff --git a/src/cg.c b/src/cg.c index 758e04f..ddd7ce7 100644 --- a/src/cg.c +++ b/src/cg.c @@ -12,7 +12,7 @@ static const char *BINOP_SIMPLE_INSTRS[] = {[BINOP_ADD] = "add", [BINOP_SUB] = " static size_t nextLocalLabel = 0; -#define LOOPSTACKSIZE 64 +#define LOOPSTACKSIZE 96 static size_t loopStackStart[LOOPSTACKSIZE]; static size_t loopStackEnd[LOOPSTACKSIZE]; static size_t loopStackIdx; @@ -37,6 +37,16 @@ static const char *spec(int size) { abort(); } +static int log_size(int size) { + switch(size) { + case 1: return 0; + case 2: return 1; + case 4: return 2; + case 8: return 3; + } + abort(); +} + static const char *specexpr(AST *e) { return spec(type_size(e->expression.type)); } @@ -54,7 +64,7 @@ static const char *xv(VarTableEntry *v) { #ifdef DEBUG snprintf(ret, XVBUFSZ, "@%i", v->data.var.color); #else - snprintf(ret, XVBUFSZ, "%s", regs[v->data.var.color][2]); + snprintf(ret, XVBUFSZ, "%s", regs[v->data.var.color][log_size(type_size(v->type))]); #endif bufidx = (bufidx + 1) % XVBUFS; @@ -87,7 +97,7 @@ static const char *xop(AST *e) { snprintf(ret, XOPBUFSZ, "[%s]", v->data.symbol.name); } else abort(); } else if(e->nodeKind == AST_EXPR_PRIMITIVE) { - snprintf(ret, XOPBUFSZ, "%i", e->exprPrim.val); + snprintf(ret, XOPBUFSZ, "%s %i", specexpr(e), e->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_VAR && 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]->exprVar.thing->kind == VARTABLEENTRY_VAR) { snprintf(ret, XOPBUFSZ, "[%s + %s]", e->exprUnOp.operand->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name, @@ -124,6 +134,16 @@ void cg_chunk(AST *a) { printf("org %lu\n", s->stmtExtOrg.val); + } else if(s->nodeKind == AST_STMT_EXT_ALIGN) { + + uint32_t val = s->stmtExtAlign.val; + if((val & (val - 1))) { + // nasm does not support non-PoT alignments, so pad manually + printf("times ($ - $$ + %u) / %u * %u - ($ - $$) db 0\n", val - 1, val, val); + } else { + printf("align %u\n", val); + } + } else if(s->nodeKind == AST_STMT_DECL && s->stmtDecl.thing->kind == VARTABLEENTRY_SYMBOL) { VarTableEntry *v = s->stmtDecl.thing; @@ -135,9 +155,26 @@ void cg_chunk(AST *a) { } if(s->stmtDecl.expression) { - puts("A"); + printf("%s:", v->data.symbol.name); + if(v->type->type == TYPE_TYPE_PRIMITIVE) { + + assert(s->stmtDecl.expression->nodeKind == AST_EXPR_PRIMITIVE); + + printf("%s %i", direct(type_size(v->type)), s->stmtDecl.expression->exprPrim.val); + + } else if(v->type->type == TYPE_TYPE_ARRAY && v->type->array.of->type == TYPE_TYPE_PRIMITIVE) { + + printf("%s ", direct(type_size(v->type->array.of))); + for(size_t i = 0; i < v->type->array.length; i++) { + printf("%i,", s->stmtDecl.expression->exprArray.items[i]->exprPrim.val); + } + + } else printf("A"); + putchar('\n'); } else { + printf("%s resb %lu\n", v->data.symbol.name, type_size(s->stmtDecl.thing->type)); + } } } else if(s->nodeKind == AST_STMT_ASSIGN) { diff --git a/src/dumberdowner.c b/src/dumberdowner.c new file mode 100644 index 0000000..52b7d28 --- /dev/null +++ b/src/dumberdowner.c @@ -0,0 +1,249 @@ +#include"dumberdowner.h" + +#include +#include + +// This is the dumbing down pass. +// +// Complex expressions are to be "broken down" into simpler ones until the AST +// can be trivially translated to the target architecture. +// +// This pass, along with CG is strictly dependent on x86 and will fail for +// any other architecture. + +// Can expression be expressed as a single x86 operand? +#define XOP_NOT_XOP 0 +#define XOP_NOT_MEM 1 +#define XOP_MEM 2 +static int is_xop(AST *e) { + if(e->nodeKind == AST_EXPR_PRIMITIVE) { + return XOP_NOT_MEM; + } else if(e->nodeKind == AST_EXPR_VAR) { + return e->exprVar.thing->kind == VARTABLEENTRY_VAR ? XOP_NOT_MEM : XOP_MEM; + } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_REF && e->exprUnOp.operand->nodeKind == AST_EXPR_VAR && e->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL) { + return XOP_NOT_MEM; + } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_DEREF) { + AST *c = e->exprUnOp.operand; + + if(c->nodeKind == AST_EXPR_VAR && c->exprVar.thing->kind == VARTABLEENTRY_VAR) { + return XOP_MEM; + } else if(c->nodeKind == AST_EXPR_BINARY_OP && c->exprBinOp.operator == BINOP_ADD && c->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && c->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && c->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR) { + if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR) { + return XOP_MEM; + } else if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_BINARY_OP && c->exprBinOp.operands[1]->exprBinOp.operator == BINOP_MUL && c->exprBinOp.operands[1]->exprBinOp.operands[0]->nodeKind == AST_EXPR_PRIMITIVE && c->exprBinOp.operands[1]->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR) { + int scale = c->exprBinOp.operands[1]->exprBinOp.operands[0]->exprPrim.val; + + if(scale == 1 || scale == 2 || scale == 4 || scale == 8) { + return XOP_MEM; + } + } + } + } + + return XOP_NOT_XOP; +} + +static void varify_change_usedefs(AST *e, AST *oldStmt, AST *newStmt) { + if(e->nodeKind == AST_EXPR_VAR) { + if(e->exprVar.thing->kind != VARTABLEENTRY_VAR) { + return; + } + + UseDef *swapWithPrev = NULL; + UseDef *swapWith = NULL; + + UseDef *udPrev = NULL; + UseDef *ud = e->exprVar.thing->data.var.usedefFirst; + while(ud && ud->use != e) { + if(ud->stmt == oldStmt && !swapWith) { + swapWithPrev = udPrev; + swapWith = ud; + } + + udPrev = ud; + ud = ud->next; + } + + if(ud) { + assert(ud->stmt == oldStmt); + ud->stmt = newStmt; + + // We must make sure all newStmt usedefs are before the oldStmt ones, so swap + if(swapWith) { + assert(!!swapWithPrev + !!udPrev != 0); + + if(swapWithPrev) { + swapWithPrev->next = ud; + } else { + e->exprVar.thing->data.var.usedefFirst = ud; + } + + if(udPrev) { + udPrev->next = swapWith; + } else { + e->exprVar.thing->data.var.usedefFirst = swapWith; + } + + UseDef *temp = ud->next; + ud->next = swapWith->next; + swapWith->next = temp; + + assert(!!ud->next + !!swapWith->next != 0); + if(!swapWith->next) { + e->exprVar.thing->data.var.usedefLast = swapWith; + } + if(!ud->next) { + e->exprVar.thing->data.var.usedefLast = ud; + } + } + } + } else if(e->nodeKind == AST_EXPR_BINARY_OP) { + varify_change_usedefs(e->exprBinOp.operands[0], oldStmt, newStmt); + varify_change_usedefs(e->exprBinOp.operands[1], oldStmt, newStmt); + } else if(e->nodeKind == AST_EXPR_UNARY_OP) { + varify_change_usedefs(e->exprUnOp.operand, oldStmt, newStmt); + } else if(e->nodeKind == AST_EXPR_CALL) { + varify_change_usedefs(e->exprCall.what, oldStmt, newStmt); + + int argCount = e->exprCall.what->expression.type->function.argCount; + for(int i = 0; i < argCount; i++) { + varify_change_usedefs(e->exprCall.args[i], oldStmt, newStmt); + } + } else if(e->nodeKind == AST_EXPR_ARRAY) { + int sz = e->exprArray.type->array.length; + for(int i = 0; i < sz; i++) { + varify_change_usedefs(e->exprArray.items[i], oldStmt, newStmt); + } + } else if(e->nodeKind == AST_EXPR_CAST) { + varify_change_usedefs(e->exprCast.what, oldStmt, newStmt); + } +} + +/* 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)); + vte->kind = VARTABLEENTRY_VAR; + vte->type = e->expression.type; + vte->data.var.color = 0; + vte->data.var.degree = 0; + vte->data.var.priority = 0; + vte->data.var.reachingDefs = NULL; + + // Add to var array + tlc->chunk.vars = realloc(tlc->chunk.vars, sizeof(*tlc->chunk.vars) * (++tlc->chunk.varCount)); + tlc->chunk.vars[tlc->chunk.varCount - 1] = vte; + + // Alter AST + + ASTExprVar *ev[2]; + for(int i = 0; i < 2; i++) { + ev[i] = malloc(sizeof(ASTExprVar)); + ev[i]->nodeKind = AST_EXPR_VAR; + ev[i]->type = e->expression.type; + ev[i]->thing = vte; + } + + ASTStmtAssign *assign = malloc(sizeof(*assign)); + assign->nodeKind = AST_STMT_ASSIGN; + assign->what = (AST*) ev[0]; + assign->to = e; + + if(stmtPrev) { + stmtPrev->statement.next = (AST*) assign; + } else { + chunk->chunk.statementFirst = (AST*) assign; + } + assign->next = stmt; + + // Assemble ud-chain + + UseDef *ud[2]; + + ud[0] = malloc(sizeof(UseDef)); + ud[0]->stmt = (AST*) assign; + ud[0]->use = assign->what; + ud[0]->def = (AST*) assign; + ud[0]->next = ud[1]; + + ud[1] = malloc(sizeof(UseDef)); + ud[1]->stmt = stmt; + ud[1]->use = (AST*) ev[1]; + ud[1]->def = (AST*) assign; + ud[1]->next = NULL; + + vte->data.var.usedefFirst = ud[0]; + vte->data.var.usedefLast = ud[1]; + + // Correct the ud-chain of variables used in varified expression `e` + + varify_change_usedefs(e, stmt, (AST*) assign); + + return (AST*) ev[1]; +} + +static AST *xopify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) { + return varify(tlc, chunk, stmtPrev, stmt, e); +} + +static void dumben_chunk(AST *tlc, AST *chu) { + AST *sPrev = NULL; + AST *s = chu->chunk.statementFirst; + + while(s) { + + 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]); + } + + if(is_xop(e->exprBinOp.operands[1]) == XOP_NOT_XOP) { + e->exprBinOp.operands[1] = xopify(tlc, chu, sPrev, s, e->exprBinOp.operands[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]); + } + + } + + dumben_chunk(tlc, s->stmtIf.then); + + } else if(s->nodeKind == AST_STMT_LOOP) { + + dumben_chunk(tlc, s->stmtLoop.body); + + } else if(s->nodeKind == AST_STMT_ASSIGN) { + + 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); + } + + } else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_CALL) { + + int argCount = s->stmtExpr.expr->exprCall.what->expression.type->function.argCount; + + for(int i = 0; i < argCount; i++) { + if(is_xop(s->stmtExpr.expr->exprCall.args[i]) == XOP_NOT_XOP) { + s->stmtExpr.expr->exprCall.args[i] = xopify(tlc, chu, sPrev, s, s->stmtExpr.expr->exprCall.args[i]); + } + } + + } + + sPrev = s; + s = s->statement.next; + } +} + +void dumben_go(AST* tlc) { + dumben_chunk(tlc, tlc); +} \ No newline at end of file diff --git a/src/dumberdowner.h b/src/dumberdowner.h new file mode 100644 index 0000000..5ce3b85 --- /dev/null +++ b/src/dumberdowner.h @@ -0,0 +1,5 @@ +#pragma once + +#include"ast.h" + +void dumben_go(AST* a); \ No newline at end of file diff --git a/src/ntc.c b/src/ntc.c index cc56f0d..105809f 100644 --- a/src/ntc.c +++ b/src/ntc.c @@ -7,6 +7,7 @@ #include"ntc.h" #include"reporting.h" #include"cg.h" +#include"dumberdowner.h" static int argc; static char **argv; @@ -36,6 +37,8 @@ int main(int argc_, char **argv_) { free(tokens); + dumben_go(chunk); + cg_go(chunk); return 0; diff --git a/src/parse.c b/src/parse.c index b605036..2b884be 100644 --- a/src/parse.c +++ b/src/parse.c @@ -9,6 +9,21 @@ #include #include +#ifndef __GNUC__ +static inline int __builtin_clzl(unsigned long x) { + unsigned long n = 32; + unsigned long y; + + y = x >>16; if (y != 0) { n = n -16; x = y; } + y = x >> 8; if (y != 0) { n = n - 8; x = y; } + y = x >> 4; if (y != 0) { n = n - 4; x = y; } + y = x >> 2; if (y != 0) { n = n - 2; x = y; } + y = x >> 1; if (y != 0) return n - 2; + + return n - x; +} +#endif + typedef struct { UseDef ud; VarTableEntry *to; @@ -75,6 +90,11 @@ static void pushstat(Parser *P, void *a) { memcpy(ud, &P->udsToAdd[i].ud, sizeof(*ud)); ud->stmt = a; + /*if(ud->stmt->nodeKind == AST_STMT_ASSIGN && ud->stmt->stmtAssign.what == ud->use) { + // Forget. The x in `x = y` is not a use of x. + continue; + }*/ + if(to->data.var.usedefFirst) { to->data.var.usedefLast->next = ud; to->data.var.usedefLast = ud; @@ -96,7 +116,6 @@ static void pushstat(Parser *P, void *a) { static ASTExprPrimitive *parse_prim(Parser *P) { ASTExprPrimitive *ret = malloc(sizeof(*ret)); ret->nodeKind = AST_EXPR_PRIMITIVE; - ret->type = (Type*) primitive_parse("s16"); Token tok = get(P); @@ -109,17 +128,32 @@ static ASTExprPrimitive *parse_prim(Parser *P) { ret->val = strtol(str, NULL, base); + // Smallest integer type to store number + char buf[8]; + snprintf(buf, sizeof(buf), "s%i", ret->val ? (64 - __builtin_clzl(ret->val - 1)) : 1); + ret->type = (Type*) primitive_parse(buf); + return ret; } static void newusedef(Parser *P, VarTableEntry *v, AST *expr) { - for(size_t i = 0; i < v->data.var.reachingDefs->defCount; i++) { - P->udsToAdd = realloc(P->udsToAdd, sizeof(*P->udsToAdd) * (++P->udsToAddCount)); - P->udsToAdd[P->udsToAddCount - 1].ud.def = v->data.var.reachingDefs->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; + 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; } } @@ -159,10 +193,14 @@ AST *nct_cast_expr(AST *what, Type *to) { } return (AST*) ret; - } else if(to->type == TYPE_TYPE_PRIMITIVE && to->primitive.width == 32) { + } else if(to->type == TYPE_TYPE_PRIMITIVE) { + if(to->primitive.width != what->exprStrLit.length * 8) { + stahp(0, 0, "Size mismatch between string literal and target type"); + } + ASTExprPrimitive *ret = malloc(sizeof(*ret)); ret->nodeKind = AST_EXPR_PRIMITIVE; - ret->type = primitive_parse("u32"); + ret->type = to; memcpy(&ret->val, what->exprStrLit.data, sizeof(ret->val)); return (AST*) ret; } else abort(); @@ -181,6 +219,9 @@ AST *nct_cast_expr(AST *what, Type *to) { ret->val = what->exprPrim.val & (((int64_t) 1 << to->primitive.width) - 1); return (AST*) ret; } else { + // Silently fail :) + return what; + ASTExprCast *ret = malloc(sizeof(*ret)); ret->nodeKind = AST_EXPR_CAST; ret->type = to; @@ -629,6 +670,77 @@ backtrack: return NULL; } +/* Imagine the following pseudocode: + x = ... + while ... { + (do something with x) + x = ... + } + The second definition of x reaches the code *before* it. + Therefore we must go over the loop body a second time with known reaching definitions and add the necessary usedefs.*/ +static void loop_second_pass(AST *a) { + if(a->nodeKind == AST_CHUNK) { + for(AST *s = a->chunk.statementFirst; s; s = s->statement.next) { + loop_second_pass(s); + } + } else if(a->nodeKind == AST_STMT_IF) { + loop_second_pass(a->stmtIf.expression); + loop_second_pass(a->stmtIf.then); + } else if(a->nodeKind == AST_STMT_LOOP) { + loop_second_pass(a->stmtLoop.body); + } else if(a->nodeKind == AST_STMT_ASSIGN) { + loop_second_pass(a->stmtAssign.what); + loop_second_pass(a->stmtAssign.to); + + /* TODO: Per-variable flag.to cease additional usedefs after assignment? + It is okay to have too many usedefs, so this isn't high priority.*/ + } else if(a->nodeKind == AST_STMT_EXPR) { + loop_second_pass(a->stmtExpr.expr); + } else if(a->nodeKind == AST_EXPR_VAR) { + UseDef *udPrev = NULL; + UseDef *ud = a->exprVar.thing->data.var.usedefFirst; + while(ud && ud->use != a) { + udPrev = ud; + ud = ud->next; + } + + if(ud) { + ReachingDefs *defs = a->exprVar.thing->data.var.reachingDefs; + while(defs) { + for(size_t i = 0; i < defs->defCount; i++) { + UseDef *newud = calloc(1, sizeof(*newud)); + memcpy(newud, ud, sizeof(*ud)); + newud->def = defs->defs[i]; + + udPrev->next = newud; + newud->next = ud; + ud = newud; + } + + if(defs->excludeParent) { + break; + } + + defs = defs->parent; + } + } + } else if(a->nodeKind == AST_EXPR_BINARY_OP) { + loop_second_pass(a->exprBinOp.operands[0]); + loop_second_pass(a->exprBinOp.operands[1]); + } else if(a->nodeKind == AST_EXPR_UNARY_OP) { + loop_second_pass(a->exprUnOp.operand); + } else if(a->nodeKind == AST_EXPR_CAST) { + loop_second_pass(a->exprCast.what); + } else if(a->nodeKind == AST_EXPR_CALL) { + loop_second_pass(a->exprCall.what); + + size_t argCount = a->exprCall.what->expression.type->function.argCount; + for(size_t i = 0; i < argCount; i++) { + loop_second_pass(a->exprCall.args[i]); + } + } +} + ASTChunk *nct_parse_chunk(Parser*, int, int); void nct_parse_statement(Parser *P) { if(maybe(P, TOKEN_IF)) { @@ -657,6 +769,8 @@ void nct_parse_statement(Parser *P) { ret->body = (AST*) nct_parse_chunk(P, 0, 1); expect(P, TOKEN_SQUIGGLY_R); + loop_second_pass(ret->body); + pushstat(P, ret); return; } else if(maybe(P, TOKEN_BREAK)) { @@ -745,7 +859,7 @@ void nct_parse_statement(Parser *P) { ret->nodeKind = AST_STMT_ASSIGN; ret->next = NULL; ret->what = e; - ret->to = nct_parse_expression(P, 0);//nct_cast_expr(nct_parse_expression(P, 0), ret->what->expression.type); + ret->to = nct_cast_expr(nct_parse_expression(P, 0), ret->what->expression.type); if(ret->what->nodeKind == AST_EXPR_VAR) { reachingdefs_set(ret->what->exprVar.thing->data.var.reachingDefs, (AST*) ret); diff --git a/src/types.c b/src/types.c index fd4fc59..d390f40 100644 --- a/src/types.c +++ b/src/types.c @@ -22,7 +22,7 @@ Type *primitive_parse(const char *src) { TypePrimitive *ret = malloc(sizeof(*ret)); ret->type = TYPE_TYPE_PRIMITIVE; - ret->src = src; + ret->src = strdup(src); if(*src == 'n') { src++; diff --git a/src/types.h b/src/types.h index ba3170a..8136fdc 100644 --- a/src/types.h +++ b/src/types.h @@ -62,6 +62,7 @@ typedef union Type { extern Type TYPE_ERROR; Type *primitive_parse(const char*); +Type *primitive_make(uint16_t width); size_t type_size(Type*); int type_equal(Type*, Type*); diff --git a/src/vartable.c b/src/vartable.c index 8d2b59a..fab5e34 100644 --- a/src/vartable.c +++ b/src/vartable.c @@ -26,6 +26,7 @@ void reachingdefs_set(struct ReachingDefs *this, union AST *def) { this->defCount = 1; this->defs = realloc(this->defs, sizeof(*this->defs) * this->defCount); this->defs[0] = def; + this->excludeParent = 1; } VarTable *vartable_new(VarTable *parent) { diff --git a/src/vartable.h b/src/vartable.h index e47c557..30dd4a0 100644 --- a/src/vartable.h +++ b/src/vartable.h @@ -20,6 +20,7 @@ typedef struct ReachingDefs { size_t defCount; union AST **defs; + int excludeParent; struct ReachingDefs *parent; } ReachingDefs; struct ReachingDefs *reachingdefs_push(struct ReachingDefs*); diff --git a/tests/bf.nct b/tests/bf.nct index 96e965c..0feb166 100644 --- a/tests/bf.nct +++ b/tests/bf.nct @@ -30,12 +30,10 @@ loop { data[dataPtr] = data[dataPtr] - 1; } if(code[codePtr] == 46) { - u32 z = &data + dataPtr; - write(1, z, 1); + write(1, &data + dataPtr, 1); } if(code[codePtr] == 44) { - u32 z = &data + dataPtr; - read(0, z, 1); + read(0, &data + dataPtr, 1); } if(code[codePtr] == 91) { if(data[dataPtr] == 0) {