parametrize your mom?

This commit is contained in:
Mid 2025-05-03 09:59:30 +03:00
parent 2c6033e501
commit 56c10daaa7
16 changed files with 1156 additions and 214 deletions

147
src/ast.c
View File

@ -10,8 +10,8 @@ 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);
void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud, GenericVisitorHandler preHandler, GenericVisitorHandler postHandler) {
if(preHandler) preHandler(nptr, stmt, stmtPrev, chu, tlc, ud);
AST *n = *nptr;
@ -19,51 +19,51 @@ void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, v
AST *sPrev = NULL;
AST **s = &n->chunk.statementFirst;
while(*s) {
generic_visitor(s, *s, sPrev, n, tlc, ud, handler);
generic_visitor(s, *s, sPrev, n, tlc, ud, preHandler, postHandler);
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.what, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
if(n->stmtAssign.to) {
generic_visitor(&n->stmtAssign.to, stmt, stmtPrev, chu, tlc, ud, handler);
generic_visitor(&n->stmtAssign.to, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
}
} 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);
generic_visitor(&n->stmtIf.expression, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
generic_visitor(&n->stmtIf.then, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
} else if(n->nodeKind == AST_STMT_LOOP) {
generic_visitor(&n->stmtLoop.body, stmt, stmtPrev, chu, tlc, ud, handler);
generic_visitor(&n->stmtLoop.body, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
} 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);
generic_visitor(&n->stmtDecl.expression, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
}
} else if(n->nodeKind == AST_STMT_EXPR) {
generic_visitor(&n->stmtExpr.expr, stmt, stmtPrev, chu, tlc, ud, handler);
generic_visitor(&n->stmtExpr.expr, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
} 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);
generic_visitor(&n->stmtReturn.val, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
}
} 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);
generic_visitor(&n->exprBinOp.operands[0], stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
generic_visitor(&n->exprBinOp.operands[1], stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
} else if(n->nodeKind == AST_EXPR_CALL) {
generic_visitor(&n->exprCall.what, stmt, stmtPrev, chu, tlc, ud, handler);
generic_visitor(&n->exprCall.what, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
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);
generic_visitor(&n->exprCall.args[i], stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
}
} else if(n->nodeKind == AST_EXPR_CAST) {
generic_visitor(&n->exprCast.what, stmt, stmtPrev, chu, tlc, ud, handler);
generic_visitor(&n->exprCast.what, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
} else if(n->nodeKind == AST_EXPR_FUNC) {
generic_visitor(&n->exprFunc.chunk, NULL, NULL, n->exprFunc.chunk, n->exprFunc.chunk, ud, handler);
generic_visitor(&n->exprFunc.chunk, NULL, NULL, n->exprFunc.chunk, n->exprFunc.chunk, ud, preHandler, postHandler);
} else if(n->nodeKind == AST_EXPR_UNARY_OP) {
generic_visitor(&n->exprUnOp.operand, stmt, stmtPrev, chu, tlc, ud, handler);
generic_visitor(&n->exprUnOp.operand, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
} else if(n->nodeKind == AST_EXPR_VAR) {
} else if(n->nodeKind == AST_EXPR_STACK_POINTER) {
} else if(n->nodeKind == AST_EXPR_PRIMITIVE) {
@ -73,18 +73,16 @@ void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, v
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);
generic_visitor(&n->exprArray.items[i], stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
}
} else if(n->nodeKind == AST_EXPR_EXT_SALLOC) {
} else if(n->nodeKind == AST_EXPR_DOT) {
generic_visitor(&n->exprDot.a, stmt, stmtPrev, chu, tlc, ud, handler);
generic_visitor(&n->exprDot.a, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
} else {
abort();
}
}
AST *ast_expression_optimize(AST *ast) {
return ast;
if(postHandler) postHandler(nptr, stmt, stmtPrev, chu, tlc, ud);
}
int ast_expression_equal(AST *a, AST *b) {
@ -100,9 +98,11 @@ int ast_expression_equal(AST *a, AST *b) {
return a->exprBinOp.operator == b->exprBinOp.operator && ast_expression_equal(a->exprBinOp.operands[0], b->exprBinOp.operands[0]) && ast_expression_equal(a->exprBinOp.operands[1], b->exprBinOp.operands[1]);
} else if(a->nodeKind == AST_EXPR_STACK_POINTER) {
return 1;
} else if(a->nodeKind == AST_EXPR_CAST) {
return ast_expression_equal(a->exprCast.what, b->exprCast.what) && type_equal(a->exprCast.to, b->exprCast.to) && a->exprCast.reinterpretation == b->exprCast.reinterpretation;
} else {
stahp_node(a, "ast_expression_equal: unhandled %s", AST_KIND_STR[a->nodeKind]);
}
return 0;
}
// This function may return three values: YES (1), NO (0) or UNKNOWN (-1).
@ -231,7 +231,7 @@ static void adduse(VarTableEntry *vte, AST *use, AST *whole) {
if(!rd) return;
for(size_t d = 0; d < rd->defCount; d++) {
UseDef *ud = malloc(sizeof(*ud));
UseDef *ud = calloc(1, sizeof(*ud));
ud->def = rd->defs[d];
ud->use = use;
ud->stmt = whole;
@ -277,7 +277,7 @@ static void mergedefs(VarTableEntry *vte) {
static void pushdefs(VarTableEntry *vte) {
assert(vte->kind == VARTABLEENTRY_VAR);
ReachingDefs *rdefs = malloc(sizeof(*rdefs));
ReachingDefs *rdefs = calloc(1, sizeof(*rdefs));
rdefs->defCount = 0;
rdefs->defs = NULL;
rdefs->excludeParent = 0;
@ -455,6 +455,20 @@ char *type_to_string(Type *t) {
return r;
} else if(t->type == TYPE_TYPE_RECORD) {
return malp("%s", t->record.name);
} else if(t->type == TYPE_TYPE_GENERIC) {
return malp("%s", t->generic.paramName);
} else if(t->type == TYPE_TYPE_ARRAY) {
char *of = type_to_string(t->array.of);
char *len = NULL;
if(t->array.lengthIsGeneric) {
len = malp("");
} else {
len = malp("%i", t->array.length);
}
char *r = malp("%s[%s]", of, len);
free(of);
free(len);
return r;
}
return strdup("@unimp");
@ -552,6 +566,11 @@ static char *ast_dumpe(AST *e) {
} else if(e->nodeKind == AST_EXPR_FUNC) {
char *out = NULL;
if(type_is_generic(e->expression.type)) {
out = malp("(generic)");
return out;
}
{
char *rettype = type_to_string(e->expression.type->function.ret);
out = malp("%s(", rettype);
@ -660,6 +679,8 @@ static char *ast_dumps(AST *s) {
}
return malp("%s; /* loop guard */\n", name);
} else if(s->nodeKind == AST_STMT_EXPR) {
return ast_dumpe(s->stmtExpr.expr);
} else if(s->nodeKind == AST_STMT_RETURN) {
if(s->stmtReturn.val) {
char *e = ast_dumpe(s->stmtReturn.val);
@ -677,7 +698,7 @@ static char *ast_dumps(AST *s) {
char *ast_dump(AST *tlc) {
AST *stmt = tlc->chunk.statementFirst;
char *ret = NULL;
char *ret = strdup("");
#define CAT(s) do { char *b = s; ret = cat(ret, (b)); free(b); } while(0)
@ -712,15 +733,15 @@ AST *ast_cast_expr(AST *what, Type *to) {
/* Only exists at parse-time, hence not part of type system and is handled separately */
if(what->nodeKind == AST_EXPR_STRING_LITERAL) {
if(to->type == TYPE_TYPE_ARRAY && type_equal(primitive_parse("u8"), to->array.of) && to->array.length == what->exprStrLit.length) {
ASTExprArray *ret = malloc(sizeof(*ret));
ASTExprArray *ret = calloc(1, sizeof(*ret));
ret->nodeKind = AST_EXPR_ARRAY;
ret->items = malloc(sizeof(*ret->items) * to->array.length);
ret->items = calloc(to->array.length, sizeof(*ret->items));
ret->type = to;
for(int i = 0; i < to->array.length; i++) {
uint8_t bajt = what->exprStrLit.data[i];
ASTExprPrimitive *item = malloc(sizeof(*item));
ASTExprPrimitive *item = calloc(1, sizeof(*item));
item->nodeKind = AST_EXPR_PRIMITIVE;
item->type = to->array.of;
item->val = bajt;
@ -731,10 +752,10 @@ AST *ast_cast_expr(AST *what, Type *to) {
return (AST*) ret;
} 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");
stahp_node(what, "Size mismatch between string literal and target type");
}
ASTExprPrimitive *ret = malloc(sizeof(*ret));
ASTExprPrimitive *ret = calloc(1, sizeof(*ret));
ret->nodeKind = AST_EXPR_PRIMITIVE;
ret->type = to;
memcpy(&ret->val, what->exprStrLit.data, sizeof(ret->val));
@ -742,6 +763,12 @@ AST *ast_cast_expr(AST *what, Type *to) {
} else abort();
}
// Make sure an unparametrized generic int parameter hasn't sneaked its way in
while(what->nodeKind == AST_EXPR_VAR && what->exprVar.thing->kind == VARTABLEENTRY_CEXPR && what->exprVar.thing->data.cexpr.concrete) {
what = what->exprVar.thing->data.cexpr.concrete;
}
assert(!(what->nodeKind == AST_EXPR_VAR && what->exprVar.thing->kind == VARTABLEENTRY_CEXPR));
if(type_equal(what->expression.type, to)) return what;
if(!type_is_castable(what->expression.type, to)) {
@ -749,7 +776,7 @@ AST *ast_cast_expr(AST *what, Type *to) {
}
if(what->nodeKind == AST_EXPR_PRIMITIVE && (to->type == TYPE_TYPE_PRIMITIVE || to->type == TYPE_TYPE_POINTER)) {
ASTExprPrimitive *ret = malloc(sizeof(*ret));
ASTExprPrimitive *ret = calloc(1, sizeof(*ret));
ret->nodeKind = AST_EXPR_PRIMITIVE;
ret->type = to;
@ -761,7 +788,7 @@ AST *ast_cast_expr(AST *what, Type *to) {
return (AST*) ret;
} else {
ASTExprCast *ret = malloc(sizeof(*ret));
ASTExprCast *ret = calloc(1, sizeof(*ret));
ret->nodeKind = AST_EXPR_CAST;
ret->type = to;
ret->what = what;
@ -770,7 +797,7 @@ AST *ast_cast_expr(AST *what, Type *to) {
}
fail:
stahp(0, 0, "Cannot cast type %s into %s", type_to_string(what->expression.type), type_to_string(to));
stahp_node(what, "Cannot cast type %s into %s", type_to_string(what->expression.type), type_to_string(to));
}
struct Spill2StackState {
@ -795,23 +822,23 @@ static void spill2stack_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk
if(a->exprVar.thing == this->target) {
// DO THE SPILL
ASTExprStackPointer *rsp = malloc(sizeof(*rsp));
ASTExprStackPointer *rsp = calloc(1, sizeof(*rsp));
rsp->nodeKind = AST_EXPR_STACK_POINTER;
rsp->type = primitive_parse("u32");
ASTExprPrimitive *offset = malloc(sizeof(*offset));
ASTExprPrimitive *offset = calloc(1, sizeof(*offset));
offset->nodeKind = AST_EXPR_PRIMITIVE;
offset->type = rsp->type;
offset->val = -this->stackGrowth; // This will be affected by the other part of this pass, so we must reverse
ASTExprBinaryOp *bop = malloc(sizeof(*bop));
ASTExprBinaryOp *bop = calloc(1, sizeof(*bop));
bop->nodeKind = AST_EXPR_BINARY_OP;
bop->type = rsp->type;
bop->operator = BINOP_ADD;
bop->operands[0] = (AST*) rsp;
bop->operands[1] = (AST*) offset;
ASTExprUnaryOp *deref = malloc(sizeof(*deref));
ASTExprUnaryOp *deref = calloc(1, sizeof(*deref));
deref->nodeKind = AST_EXPR_UNARY_OP;
deref->type = a->expression.type;
deref->operator = UNOP_DEREF;
@ -829,8 +856,11 @@ static void spill2stack_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk
}
void ast_spill_to_stack(AST *tlc, VarTableEntry *vte) {
assert(vte != NULL);
assert(tlc->nodeKind == AST_CHUNK);
assert(vte != NULL);
assert(vte->kind == VARTABLEENTRY_VAR);
fprintf(stderr, "Spilling %s to stack...\n", vte->data.var.name);
struct Spill2StackState state;
memset(&state, 0, sizeof(state));
@ -838,5 +868,36 @@ void ast_spill_to_stack(AST *tlc, VarTableEntry *vte) {
state.targetTLC = tlc;
state.stackGrowth = (type_size(vte->type) + 7) & ~7;
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, spill2stack_visitor);
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, spill2stack_visitor, NULL);
}
static void typecheck_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
AST *a = *aptr;
if(a->nodeKind == AST_EXPR_CALL) {
if(a->exprCall.what->expression.type != TYPE_TYPE_FUNCTION) {
stahp_node(a, "Only function types may be called.");
}
} else if(a->nodeKind == AST_EXPR_BINARY_OP) {
if(!type_is_number(a->exprBinOp.operands[0]) || !type_is_number(a->exprBinOp.operands[1])) {
stahp_node(a, "Operands must be numbers.");
}
if(type_size(a->exprBinOp.operands[0]->expression.type) < type_size(a->exprBinOp.operands[1]->expression.type)) {
a->exprBinOp.operands[0] = ast_cast_expr(a->exprBinOp.operands[0], a->exprBinOp.operands[1]->expression.type);
}
if(type_size(a->exprBinOp.operands[1]->expression.type) < type_size(a->exprBinOp.operands[0]->expression.type)) {
a->exprBinOp.operands[1] = ast_cast_expr(a->exprBinOp.operands[1], a->exprBinOp.operands[0]->expression.type);
}
if(!a->exprBinOp.type) {
a->exprBinOp.type = a->exprBinOp.operands[0]->expression.type;
}
} else if(a->nodeKind == AST_EXPR_UNARY_OP) {
}
}
void ast_type_check(AST *tlc, VarTableEntry *vte) {
generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, NULL, typecheck_visitor);
}

View File

@ -111,6 +111,12 @@ union AST;
typedef struct {
ASTKind nodeKind;
uint16_t row;
uint16_t col;
} ASTBase;
typedef struct {
ASTBase;
Type *type;
} ASTExpr;
@ -163,10 +169,15 @@ typedef struct {
ASTExpr;
union AST *chunk;
// Necessary for when the parser jumps to a generic function
Token *rangeTokens;
size_t startTokI;
size_t endTokI;
} ASTExprFunc;
typedef struct {
ASTKind nodeKind;
ASTBase;
size_t size;
} ASTType;
@ -185,7 +196,7 @@ typedef struct {
} ASTTypePointer;
typedef struct {
ASTKind nodeKind;
ASTBase;
union AST *next;
} ASTStmt;
@ -198,12 +209,16 @@ typedef struct {
} ASTStmtDecl;
typedef struct {
ASTKind nodeKind;
ASTBase;
/* Flattened variable array for global register allocation */
size_t varCount;
VarTableEntry **vars;
/* extern symbol array */
size_t externCount;
VarTableEntry **externs;
union AST *statementFirst;
union AST *statementLast;
@ -301,7 +316,7 @@ typedef struct {
} ASTStmtReturn;
typedef union AST {
ASTKind nodeKind;
ASTBase;
ASTChunk chunk;
ASTStmt statement;
@ -332,9 +347,9 @@ 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*));
typedef void(*GenericVisitorHandler)(AST**, AST*, AST*, AST*, AST*, void*);
void generic_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *tlc, void *ud, GenericVisitorHandler preHandler, GenericVisitorHandler postHandler);
AST *ast_expression_optimize(AST*);
int ast_expression_equal(AST*, AST*);
int ast_stmt_is_after(const AST *chunk, const AST *s1, const AST *s2);
@ -349,6 +364,8 @@ AST *ast_cast_expr(AST *what, Type *to);
void ast_spill_to_stack(AST *tlc, VarTableEntry *vte);
void ast_typecheck(AST *tlc);
__attribute__((format(printf, 1, 2))) char *malp(const char *fmt, ...);
#endif

View File

@ -120,6 +120,10 @@ static AST *is_field_access(AST *e) {
return e;
}
if(e->nodeKind == AST_EXPR_BINARY_OP && e->exprBinOp.operator == BINOP_ADD && e->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE && e->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR && e->exprBinOp.operands[0]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
return e;
}
return NULL;
}
@ -131,7 +135,8 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) {
char *ret = bufs[bufidx];
if(e->nodeKind == AST_EXPR_CAST && e->exprCast.what->expression.type->type == TYPE_TYPE_POINTER && e->exprCast.to->type == TYPE_TYPE_POINTER) {
//if(e->nodeKind == AST_EXPR_CAST && e->exprCast.what->expression.type->type == TYPE_TYPE_POINTER && e->exprCast.to->type == TYPE_TYPE_POINTER) {
if(e->nodeKind == AST_EXPR_CAST) {
e = e->exprCast.what;
}
@ -154,10 +159,22 @@ static const char *xop_sz(AST *tlc, AST *e, int sz) {
xv_sz(p->exprBinOp.operands[1]->exprVar.thing, 4));
} else if(is_field_access(e)) {
e = is_field_access(e);
snprintf(ret, XOPBUFSZ, "%s [%s + %i]",
spec(sz),
e->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
e->exprBinOp.operands[1]->exprPrim.val);
if(e->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP) {
assert(e->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF);
snprintf(ret, XOPBUFSZ, "%s [%s + %i]",
spec(sz),
e->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->data.symbol.name,
e->exprBinOp.operands[1]->exprPrim.val);
} else {
assert(e->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR);
snprintf(ret, XOPBUFSZ, "%s [%s + %i]",
spec(sz),
regs[e->exprBinOp.operands[0]->exprVar.thing->data.var.color][2],
e->exprBinOp.operands[1]->exprPrim.val);
}
} else if(p->nodeKind == AST_EXPR_BINARY_OP && p->exprBinOp.operator == BINOP_ADD && p->exprBinOp.operands[0]->nodeKind == AST_EXPR_UNARY_OP && p->exprBinOp.operands[1]->nodeKind == AST_EXPR_BINARY_OP && p->exprBinOp.operands[0]->exprUnOp.operator == UNOP_REF && p->exprBinOp.operands[0]->exprUnOp.operand->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[0]->exprUnOp.operand->exprVar.thing->kind == VARTABLEENTRY_SYMBOL && p->exprBinOp.operands[1]->exprBinOp.operator == BINOP_MUL && p->exprBinOp.operands[1]->exprBinOp.operands[1]->nodeKind == AST_EXPR_VAR && p->exprBinOp.operands[1]->exprBinOp.operands[0]->nodeKind == AST_EXPR_PRIMITIVE && p->exprBinOp.operands[1]->exprBinOp.operands[1]->exprVar.thing->kind == VARTABLEENTRY_VAR) {
snprintf(ret, XOPBUFSZ, "%s [%s + %i * %s]",
spec(sz),
@ -238,7 +255,9 @@ void cg_chunk(CGState *cg, AST *a) {
VarTableEntry *v = s->stmtDecl.thing;
if(v->data.symbol.isExternal) {
printf("extern %s\n", v->data.symbol.name);
// Do nothing.
// All external symbols are handled at once in the top-level chunk.
//printf("extern %s\n", v->data.symbol.name);
} else {
if(!v->data.symbol.isLocal) {
printf("global %s\n", v->data.symbol.name);
@ -265,9 +284,14 @@ void cg_chunk(CGState *cg, AST *a) {
assert(s->stmtDecl.expression->nodeKind == AST_EXPR_FUNC);
dumben_go(s->stmtDecl.expression->exprFunc.chunk);
while(!cg_go(s->stmtDecl.expression->exprFunc.chunk)) {
// Generic functions have non-NULL code blocks
if(!type_is_generic(s->stmtDecl.expression->expression.type)) {
dumben_go(s->stmtDecl.expression->exprFunc.chunk);
while(!cg_go(s->stmtDecl.expression->exprFunc.chunk)) {
dumben_go(s->stmtDecl.expression->exprFunc.chunk);
}
}
} else abort();
@ -375,7 +399,7 @@ void cg_chunk(CGState *cg, AST *a) {
printf("neg %s\n", xop(cg->tlc, s->stmtAssign.what));
} else if(is_xop(s->stmtAssign.what) && s->stmtAssign.to->nodeKind == AST_EXPR_CAST) {
} else if(is_xop(s->stmtAssign.what) && s->stmtAssign.to->nodeKind == AST_EXPR_CAST && type_size(s->stmtAssign.what->expression.type) > type_size(s->stmtAssign.to->expression.type)) {
printf("movzx %s, %s\n", xop(cg->tlc, s->stmtAssign.what), xop(cg->tlc, s->stmtAssign.to->exprCast.what));
@ -448,7 +472,15 @@ void cg_chunk(CGState *cg, AST *a) {
/* Loop guard, probably. */
} else abort();
} else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_UNARY_OP && s->stmtExpr.expr->exprUnOp.operator == UNOP_DEREF && s->stmtExpr.expr->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && s->stmtExpr.expr->exprUnOp.operand->exprBinOp.operator == BINOP_ADD && s->stmtExpr.expr->exprUnOp.operand->exprBinOp.operands[0]->nodeKind == AST_EXPR_STACK_POINTER && s->stmtExpr.expr->exprUnOp.operand->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE) {
/* Loop guard for a spilled variable, probably. */
} else {
stahp_node(s, "Unknown statement caught by code generator.");
}
s = s->statement.next;
}
@ -801,7 +833,7 @@ static void callee_saved(AST *tlc) {
state.targetTLC = tlc;
state.ebxuser = ebxuser;
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, callee_saved_visitor);
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, callee_saved_visitor, NULL);
}
}
@ -812,6 +844,15 @@ 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) {
assert(a->nodeKind == AST_CHUNK);
for(size_t e = 0; e < a->chunk.externCount; e++) {
assert(a->chunk.externs[e]->kind == VARTABLEENTRY_SYMBOL);
assert(a->chunk.externs[e]->data.symbol.isExternal);
printf("extern %s\n", a->chunk.externs[e]->data.symbol.name);
}
ast_usedef_reset(a);
size_t adjCount = 0;

View File

@ -42,13 +42,13 @@ static AST *varify(AST *tlc, AST *chunk, AST *stmtPrev, AST *stmt, AST *e) {
ASTExprVar *ev[2];
for(int i = 0; i < 2; i++) {
ev[i] = malloc(sizeof(ASTExprVar));
ev[i] = calloc(1, sizeof(ASTExprVar));
ev[i]->nodeKind = AST_EXPR_VAR;
ev[i]->type = e->expression.type;
ev[i]->thing = vte;
}
ASTStmtAssign *assign = malloc(sizeof(*assign));
ASTStmtAssign *assign = calloc(1, sizeof(*assign));
assign->nodeKind = AST_STMT_ASSIGN;
assign->what = (AST*) ev[0];
assign->to = e;
@ -187,6 +187,12 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *
s->stmtAssign.to = varify(tlc, chu, stmtPrev, s, s->stmtAssign.to);
this->effective = 1;
} else if(s->stmtAssign.what->nodeKind == AST_EXPR_UNARY_OP && s->stmtAssign.what->exprUnOp.operator == UNOP_DEREF && !is_xop(s->stmtAssign.what)) {
s->stmtAssign.what->exprUnOp.operand = varify(tlc, chu, stmtPrev, s, s->stmtAssign.what->exprUnOp.operand);
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;
@ -215,7 +221,7 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *
s->stmtAssign.to = negation->exprUnOp.operand;
negation->exprUnOp.operand = ev[0];
AST *assign2 = malloc(sizeof(ASTStmtAssign));
AST *assign2 = calloc(1, sizeof(ASTStmtAssign));
assign2->nodeKind = AST_STMT_ASSIGN;
assign2->stmtAssign.what = ev[1];
assign2->stmtAssign.to = negation;
@ -291,7 +297,7 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *
// a = b
// a = a op c
AST *assign2 = malloc(sizeof(ASTStmtAssign));
AST *assign2 = calloc(1, 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];
@ -458,13 +464,19 @@ static void denoop_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST
*nptr = n->exprBinOp.operands[0];
*success = true;
} else if(n->nodeKind == AST_EXPR_CAST && n->exprCast.what->expression.type->type == TYPE_TYPE_POINTER && n->exprCast.to->type == TYPE_TYPE_POINTER) {
// Turn (x as A*) into x, since all pointer types are identical in Nectar's AST
*nptr = n->exprCast.what;
*success = true;
}
}
void dumben_pre(AST *tlc) {
generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, pre_dumb_visitor);
generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, decompose_symbol_record_field_access);
generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, pre_dumb_visitor, NULL);
generic_visitor(&tlc, NULL, NULL, tlc, tlc, NULL, decompose_symbol_record_field_access, NULL);
for(size_t t = 0; t < tlc->chunk.varCount; t++) {
if(tlc->chunk.vars[t]->type->type == TYPE_TYPE_RECORD) {
@ -475,7 +487,7 @@ void dumben_pre(AST *tlc) {
bool success;
do {
success = false;
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &success, denoop_visitor);
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &success, denoop_visitor, NULL);
} while(success);
}
@ -492,7 +504,7 @@ void dumben_go(AST* tlc) {
struct DumbenState state;
memset(&state, 0, sizeof(state));
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, dumben_visitor);
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, dumben_visitor, NULL);
int successful = state.effective;

View File

@ -48,6 +48,7 @@ char *TOKEN_NAMES[] = {
"'record'",
"'.'",
"'as'",
"'use'",
};
static int isAlpha(int c) {
@ -290,6 +291,10 @@ Token nct_tokenize(FILE *f) {
free(content);
tok.type = TOKEN_AS;
return tok;
} else if(!strcmp(content, "use")) {
free(content);
tok.type = TOKEN_USE;
return tok;
}
tok.type = TOKEN_IDENTIFIER;
@ -319,7 +324,7 @@ Token nct_tokenize(FILE *f) {
while(c = nextc(f), (isNum(c) || (base > 10 && c >= 'A' && c < ('A' + base - 10)))) {
if(i == 31) {
stahp(1, 6180, "Numbers have a maximum size of 31.");
stahp_token(&tok, "Numbers have a maximum size of 31.");
}
content[i++] = c;

View File

@ -48,9 +48,10 @@ typedef enum {
TOKEN_RECORD,
TOKEN_DOT,
TOKEN_AS,
TOKEN_USE,
} TokenKind;
typedef struct {
typedef struct Token {
TokenKind type;
int row, column;

File diff suppressed because it is too large Load Diff

View File

@ -3,17 +3,45 @@
#include<stdarg.h>
#include<stdio.h>
#include<stdlib.h>
#include"ast.h"
#include"lexer.h"
static void stahp_va(int row, int column, const char *error, va_list l) {
fprintf(stderr, "error %i:%i: ", row, column);
vfprintf(stderr, error, l);
fputc('\n', stderr);
}
/* Abort immediately on first error (for now) */
void stahp(int row, int column, const char *error, ...) {
va_list l;
va_start(l, error);
fprintf(stderr, "error %i:%i: ", row, column);
vfprintf(stderr, error, l);
fputc('\n', stderr);
stahp_va(row, column, error, l);
va_end(l);
exit(1);
}
}
void stahp_node(union AST *node, const char *error, ...) {
va_list l;
va_start(l, error);
stahp_va(node->row, node->col, error, l);
va_end(l);
exit(1);
}
void stahp_token(struct Token *tok, const char *error, ...) {
va_list l;
va_start(l, error);
stahp_va(tok->row, tok->column, error, l);
va_end(l);
exit(1);
}

View File

@ -5,6 +5,11 @@
#define __attribute__(x)
#endif
union AST;
struct Token;
void __attribute__((noreturn)) stahp(int, int, const char*, ...);
void __attribute__((noreturn)) stahp_node(union AST*, const char*, ...);
void __attribute__((noreturn)) stahp_token(struct Token*, const char*, ...);
#endif

View File

@ -4,6 +4,8 @@
#include<stdlib.h>
#include<string.h>
#include<stdint.h>
#include"ast.h"
#include"reporting.h"
#include"ntc.h"
@ -20,7 +22,7 @@ Type *primitive_parse(const char *src) {
}
}
TypePrimitive *ret = malloc(sizeof(*ret));
TypePrimitive *ret = calloc(1, sizeof(*ret));
ret->type = TYPE_TYPE_PRIMITIVE;
ret->src = strdup(src);
@ -100,7 +102,16 @@ size_t type_size(Type *t) {
} else if(t->type == TYPE_TYPE_ARRAY) {
return type_size(t->array.of) * t->array.length;
} else if(t->type == TYPE_TYPE_RECORD) {
return t->record.size;
size_t max = 0;
for(size_t f = 0; f < t->record.fieldCount; f++) {
size_t end = t->record.fieldOffsets[f] + type_size(t->record.fieldTypes[f]);
if(max < end) {
max = end;
}
}
return max;
}
abort();
@ -123,7 +134,19 @@ int type_equal(Type *O, Type *T) {
} else if(O->type == TYPE_TYPE_POINTER) {
return type_equal(O->pointer.of, T->pointer.of);
} else if(O->type == TYPE_TYPE_ARRAY) {
return type_equal(O->array.of, T->array.of) && O->array.length == T->array.length;
if(!type_equal(O->array.of, T->array.of)) {
return 0;
}
if(O->array.lengthIsGeneric != T->array.lengthIsGeneric) {
return 0;
}
if(O->array.lengthIsGeneric) {
return O->array.lengthGenericParamIdx == T->array.lengthGenericParamIdx && !strcmp(O->array.lengthGenericParamName, T->array.lengthGenericParamName);
} else {
return O->array.length == T->array.length;
}
} else if(O->type == TYPE_TYPE_FUNCTION) {
if(!type_equal(O->function.ret, T->function.ret)) {
return 0;
@ -151,7 +174,7 @@ int type_equal(Type *O, Type *T) {
/* TODO: cache */
Type *type_pointer_wrap(Type *t) {
TypePointer *ret = malloc(sizeof(*ret));
TypePointer *ret = calloc(1, sizeof(*ret));
ret->type = TYPE_TYPE_POINTER;
ret->of = t;
return (Type*) ret;
@ -182,3 +205,180 @@ int type_is_castable(Type *from, Type *to) {
return 0;
}
bool type_is_generic(Type *t) {
if(t->type == TYPE_TYPE_GENERIC) {
return true;
} else if(t->type == TYPE_TYPE_FUNCTION) {
if(type_is_generic(t->function.ret)) {
return true;
}
for(int i = 0; i < t->function.argCount; i++) {
if(type_is_generic(t->function.args[i])) {
return true;
}
}
} else if(t->type == TYPE_TYPE_RECORD) {
for(int i = 0; i < t->record.fieldCount; i++) {
if(type_is_generic(t->record.fieldTypes[i])) {
return true;
}
}
} else if(t->type == TYPE_TYPE_POINTER) {
return type_is_generic(t->pointer.of);
} else if(t->type == TYPE_TYPE_ARRAY) {
return type_is_generic(t->array.of) || t->array.lengthIsGeneric;
}
return false;
}
static void *parametrization_get_by_index(Parametrization *list, size_t idx) {
for(size_t i = 0; list && i < idx; i++) {
list = list->next;
}
return list ? list->param : NULL;
}
static void parametrization_set_by_index(Parametrization **list, size_t idx, void *param) {
if(*list == NULL) {
*list = calloc(1, sizeof(Parametrization));
}
for(size_t i = 1; i <= idx; i++) {
if((*list)->next == NULL) {
(*list)->next = calloc(1, sizeof(Parametrization));
}
list = &(*list)->next;
}
(*list)->param = param;
}
Type *type_parametrize(Type *t, Parametrizations *parametrizations, Parametrizations *renames) {
if(t->type == TYPE_TYPE_RECORD) {
t = type_shallow_copy(t);
for(size_t f = 0; f < t->record.fieldCount; f++) {
t->record.fieldTypes[f] = type_parametrize(t->record.fieldTypes[f], parametrizations, renames);
}
if(!type_is_generic(t)) {
// Now that everything is concrete we may set the field offsets
size_t nextOffset = 0;
for(size_t f = 0; f < t->record.fieldCount; f++) {
t->record.fieldOffsets[f] = nextOffset;
nextOffset += type_size(t->record.fieldTypes[f]);
}
}
} else if(t->type == TYPE_TYPE_FUNCTION) {
t = type_shallow_copy(t);
t->function.ret = type_parametrize(t->function.ret, parametrizations, renames);
for(size_t i = 0; i < t->function.argCount; i++) {
t->function.args[i] = type_parametrize(t->function.args[i], parametrizations, renames);
}
} else if(t->type == TYPE_TYPE_GENERIC) {
Type *newt = parametrization_get_by_index(parametrizations->typeParams, t->generic.paramIdx);
if(renames) {
parametrization_set_by_index(&renames->typeParams, t->generic.paramIdx, t);
}
if(newt) {
return newt;
}
} else if(t->type == TYPE_TYPE_POINTER) {
t = type_shallow_copy(t);
t->pointer.of = type_parametrize(t->pointer.of, parametrizations, renames);
} else if(t->type == TYPE_TYPE_ARRAY) {
t = type_shallow_copy(t);
t->array.of = type_parametrize(t->array.of, parametrizations, renames);
if(t->array.lengthIsGeneric) {
AST *n = parametrization_get_by_index(parametrizations->intParams, t->array.lengthGenericParamIdx);
if(n) {
while(n->nodeKind == AST_EXPR_VAR && n->exprVar.thing->kind == VARTABLEENTRY_CEXPR && n->exprVar.thing->data.cexpr.concrete) {
n = n->exprVar.thing->data.cexpr.concrete;
}
if(n->nodeKind == AST_EXPR_PRIMITIVE) {
t->array.length = n->exprPrim.val;
t->array.lengthIsGeneric = false;
} else if(n->nodeKind == AST_EXPR_VAR && n->exprVar.thing->kind == VARTABLEENTRY_CEXPR) {
t->array.lengthGenericParamIdx = n->exprVar.thing->data.cexpr.paramIdx;
t->array.lengthGenericParamName = n->exprVar.thing->data.cexpr.paramName;
t->array.lengthIsGeneric = true;
} else {
stahp_node(n, "Invalid parametrization expression.");
}
}
parametrization_set_by_index(&renames->intParams, t->array.lengthGenericParamIdx, t->array.lengthGenericParamName);
}
}
return t;
}
Type *type_shallow_copy(Type *t) {
if(t->type == TYPE_TYPE_PRIMITIVE) {
Type *n = calloc(1, sizeof(TypePrimitive));
memcpy(n, t, sizeof(TypePrimitive));
return n;
} else if(t->type == TYPE_TYPE_POINTER) {
Type *n = calloc(1, sizeof(TypePointer));
memcpy(n, t, sizeof(TypePointer));
return n;
} else if(t->type == TYPE_TYPE_ARRAY) {
Type *n = calloc(1, sizeof(TypeArray));
memcpy(n, t, sizeof(TypeArray));
return n;
} else if(t->type == TYPE_TYPE_GENERIC) {
Type *n = calloc(1, sizeof(TypeGeneric));
memcpy(n, t, sizeof(TypeGeneric));
return n;
} else if(t->type == TYPE_TYPE_FUNCTION) {
Type *n = calloc(1, sizeof(TypeFunction));
n->type = TYPE_TYPE_FUNCTION;
n->function.ret = t->function.ret;
n->function.argCount = t->function.argCount;
n->function.argNames = calloc(n->function.argCount, sizeof(*n->function.argNames));
memcpy(n->function.argNames, t->function.argNames, n->function.argCount * sizeof(*n->function.argNames));
n->function.args = calloc(n->function.argCount, sizeof(*n->function.args));
memcpy(n->function.args, t->function.args, n->function.argCount * sizeof(*n->function.args));
return n;
} else if(t->type == TYPE_TYPE_RECORD) {
Type *n = calloc(1, sizeof(TypeRecord));
n->type = TYPE_TYPE_RECORD;
n->record.name = strdup(t->record.name);
n->record.fieldCount = t->record.fieldCount;
n->record.fieldNames = calloc(n->record.fieldCount, sizeof(*n->record.fieldNames));
memcpy(n->record.fieldNames, t->record.fieldNames, n->record.fieldCount * sizeof(*n->record.fieldNames));
n->record.fieldTypes = calloc(n->record.fieldCount, sizeof(*n->record.fieldTypes));
memcpy(n->record.fieldTypes, t->record.fieldTypes, n->record.fieldCount * sizeof(*n->record.fieldTypes));
n->record.fieldOffsets = calloc(n->record.fieldCount, sizeof(*n->record.fieldOffsets));
memcpy(n->record.fieldOffsets, t->record.fieldOffsets, n->record.fieldCount * sizeof(*n->record.fieldOffsets));
return n;
}
abort();
}

View File

@ -3,9 +3,10 @@
#include<stddef.h>
#include<stdint.h>
#include<stdbool.h>
typedef enum {
TYPE_TYPE_PRIMITIVE, TYPE_TYPE_RECORD, TYPE_TYPE_POINTER, TYPE_TYPE_FUNCTION, TYPE_TYPE_ARRAY, TYPE_TYPE_ERROR
TYPE_TYPE_PRIMITIVE, TYPE_TYPE_RECORD, TYPE_TYPE_POINTER, TYPE_TYPE_FUNCTION, TYPE_TYPE_ARRAY, TYPE_TYPE_GENERIC, TYPE_TYPE_ERROR
} TypeType;
union Type;
@ -48,7 +49,12 @@ typedef struct TypeArray {
TypeType type;
union Type *of;
size_t length; /* 0 means unknown */
intmax_t length;
bool lengthIsGeneric;
char *lengthGenericParamName;
size_t lengthGenericParamIdx;
} TypeArray;
typedef struct TypeRecord {
@ -56,14 +62,19 @@ typedef struct TypeRecord {
char *name;
size_t size;
union Type **fieldTypes;
size_t *fieldOffsets;
char **fieldNames;
size_t fieldCount;
} TypeRecord;
typedef struct TypeGeneric {
TypeType type;
char *paramName;
size_t paramIdx;
} TypeGeneric;
typedef union Type {
TypeType type;
@ -72,6 +83,7 @@ typedef union Type {
TypeFunction function;
TypeArray array;
TypeRecord record;
TypeGeneric generic;
} Type;
extern Type TYPE_ERROR;
@ -90,4 +102,21 @@ int type_is_number(Type *t);
char *type_to_string(Type*);
typedef struct Parametrization {
void *param;
struct Parametrization *next;
} Parametrization;
typedef struct {
Parametrization *typeParams;
Parametrization *intParams;
} Parametrizations;
Type *type_parametrize(Type *target, Parametrizations *parametrizations, Parametrizations *renames);
Type *type_shallow_copy(Type *t);
bool type_is_generic(Type *t);
#endif

View File

@ -2,6 +2,9 @@
#define NCTREF_UTILS_H
#include<stddef.h>
#include<stdbool.h>
#include<errno.h>
#include<stdlib.h>
inline static size_t djb2(const char *str) {
size_t hash = 5381;
@ -14,4 +17,25 @@ inline static size_t djb2(const char *str) {
return hash;
}
inline static bool unstupid_strtol(const char *str, char **endptr, int base, long *result) {
errno = 0;
char *endptr2 = NULL;
*result = strtol(str, &endptr2, base);
if(endptr2 == str) {
return false;
}
if(errno == ERANGE) {
return false;
}
if(endptr) {
*endptr = endptr2;
}
return true;
}
#endif

View File

@ -31,7 +31,7 @@ void reachingdefs_set(struct ReachingDefs *this, union AST *def) {
}
VarTable *vartable_new(VarTable *parent) {
VarTable *ret = malloc(sizeof(*ret));
VarTable *ret = calloc(1, sizeof(*ret));
ret->parent = parent;
ret->count = 0;
ret->names = NULL;
@ -70,7 +70,7 @@ VarTableEntry *vartable_set(VarTable *this, const char *name, VarTableEntry *e)
return e;
}
void vartable_new_reachingdefs_for_all_vars(VarTable *this) {
/*void vartable_new_reachingdefs_for_all_vars(VarTable *this) {
for(size_t i = 0; i < this->count; i++) {
if(this->data[i]->kind == VARTABLEENTRY_VAR) {
this->data[i]->data.var.reachingDefs = reachingdefs_push(this->data[i]->data.var.reachingDefs);
@ -92,11 +92,33 @@ void vartable_coalesce_reachingdefs_for_all_vars(VarTable *this) {
if(this->parent) {
vartable_coalesce_reachingdefs_for_all_vars(this->parent);
}
}*/
VarTable *vartable_merge(VarTable *child) {
VarTable *parent = child->parent;
parent->names = realloc(parent->names, sizeof(*parent->names) * (parent->count + child->count));
parent->data = realloc(parent->data, sizeof(*parent->data) * (parent->count + child->count));
for(size_t i = 0; i < child->count; i++) {
child->data[i]->owner = parent;
parent->names[parent->count] = child->names[i];
parent->data[parent->count] = child->data[i];
parent->count++;
}
free(child->names);
free(child->data);
free(child);
return parent;
}
void vte_precolor(VarTableEntry *vte, int color) {
assert(vte->kind == VARTABLEENTRY_VAR);
assert(!vte->data.var.precolored);
assert(vte->kind == VARTABLEENTRY_VAR && "vte must be var");
assert(!vte->data.var.precolored && "already precolored");
vte->data.var.precolored = true;
vte->data.var.color = color;

View File

@ -4,8 +4,11 @@
#include"types.h"
#include<stdbool.h>
struct Token;
union AST;
typedef enum {
VARTABLEENTRY_SYMBOL, VARTABLEENTRY_VAR, VARTABLEENTRY_TYPE
VARTABLEENTRY_SYMBOL, VARTABLEENTRY_VAR, VARTABLEENTRY_TYPE, VARTABLEENTRY_CEXPR
} VarTableEntryKind;
union AST;
@ -41,6 +44,12 @@ typedef struct VarTableEntry {
char isLocal;
char isExternal;
const char *name;
struct {
struct Token *rangeTokens;
size_t startTokI;
size_t endTokI;
} genfunc;
} symbol;
struct {
// For debugging
@ -67,6 +76,15 @@ typedef struct VarTableEntry {
struct {
Type *ptr;
} type;
struct {
// cexpr is used for expression parametization as opposed to type parametrization
// I don't like the idea of having a special VarTableEntry kind for these, but all other places were worse
const char *paramName;
size_t paramIdx;
// If the cexpr has been parametrized (as opposed to just being a symbol), this field will be non-NULL
union AST *concrete;
} cexpr;
};
} data;
} VarTableEntry;
@ -84,8 +102,10 @@ VarTableEntry *vartable_get(VarTable*, const char*);
VarTableEntry *vartable_find(VarTable*, const char*);
VarTableEntry *vartable_set(VarTable*, const char*, VarTableEntry*);
void vartable_new_reachingdefs_for_all_vars(VarTable*);
void vartable_coalesce_reachingdefs_for_all_vars(VarTable*);
VarTable *vartable_merge(VarTable *child);
//void vartable_new_reachingdefs_for_all_vars(VarTable*);
//void vartable_coalesce_reachingdefs_for_all_vars(VarTable*);
void vte_precolor(VarTableEntry *vte, int color);

View File

@ -35,8 +35,13 @@ static inline int is_xop(AST *e) {
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) {
} 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) ||
(c->nodeKind == AST_EXPR_BINARY_OP && c->exprBinOp.operator == BINOP_ADD && c->exprBinOp.operands[0]->nodeKind == AST_EXPR_VAR)) {
if(c->exprBinOp.operands[1]->nodeKind == AST_EXPR_PRIMITIVE) {
return XOP_MEM;
} else 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;

View File

@ -1,8 +1,9 @@
u16 a = 12;
u16 b = a & 6;
u16 c = b ^ a | 3;
u16 d = 11 * c;
u16 o = 5;
u16 d = o * 2;
if(a) {
if(a == 0) {
u16 e = b + c + d;
}
}