parametrize your mom?
This commit is contained in:
parent
2c6033e501
commit
56c10daaa7
147
src/ast.c
147
src/ast.c
@ -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);
|
||||
}
|
||||
|
29
src/ast.h
29
src/ast.h
@ -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
|
||||
|
63
src/cg.c
63
src/cg.c
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
711
src/parse.c
711
src/parse.c
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
208
src/types.c
208
src/types.c
@ -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();
|
||||
}
|
||||
|
37
src/types.h
37
src/types.h
@ -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
|
||||
|
24
src/utils.h
24
src/utils.h
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user