nctref/src/ast/ast.c

341 lines
12 KiB
C

#include"ast.h"
#include<stdint.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<stdarg.h>
#include"ntc.h"
#include"reporting.h"
#include"utils.h"
#include"x86/arch.h"
const char *AST_KIND_STR[] = { AST_KINDS(GEN_STRI) };
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;
if(n->nodeKind == AST_CHUNK) {
AST *sPrev = NULL;
AST **s = &n->chunk.statementFirst;
while(*s) {
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, preHandler, postHandler);
if(n->stmtAssign.to) {
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, preHandler, postHandler);
generic_visitor(&n->stmtIf.then, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
if(n->stmtIf.elss) {
generic_visitor(&n->stmtIf.elss, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
}
} else if(n->nodeKind == AST_STMT_LOOP) {
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, preHandler, postHandler);
}
} else if(n->nodeKind == AST_STMT_EXPR) {
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, preHandler, postHandler);
}
} else if(n->nodeKind == AST_EXPR_BINARY_OP) {
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, preHandler, postHandler);
for(size_t i = 0; i < n->exprCall.what->expression.type->pointer.of->function.argCount; i++) {
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, preHandler, postHandler);
} else if(n->nodeKind == AST_EXPR_FUNC) {
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, preHandler, postHandler);
} else if(n->nodeKind == AST_EXPR_VAR) {
} else if(n->nodeKind == AST_EXPR_STACK_POINTER) {
} else if(n->nodeKind == AST_EXPR_PRIMITIVE) {
} else if(n->nodeKind == AST_EXPR_STRING_LITERAL) {
} else if(n->nodeKind == AST_EXPR_ARRAY) {
assert(n->expression.type->type == TYPE_TYPE_ARRAY);
assert(n->expression.type->array.length != 0);
for(size_t i = 0; i < n->expression.type->array.length; i++) {
generic_visitor(&n->exprArray.items[i], stmt, stmtPrev, chu, tlc, ud, 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, preHandler, postHandler);
} else if(n->nodeKind == AST_EXPR_EXT_SIZEOF) {
if(n->exprExtSizeOf.ofExpr) {
generic_visitor(&n->exprExtSizeOf.ofExpr, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
}
} else if(n->nodeKind == AST_STMT_JUMP) {
if(n->stmtJump.condition) {
generic_visitor(&n->stmtJump.condition, stmt, stmtPrev, chu, tlc, ud, preHandler, postHandler);
}
} else if(n->nodeKind == AST_STMT_LABEL) {
} else if(n->nodeKind == AST_EXPR_NULL) {
} else {
stahp_node(n, "generic_visitor: unhandled %s", AST_KIND_STR[n->nodeKind]);
}
if(postHandler) postHandler(nptr, stmt, stmtPrev, chu, tlc, ud);
}
int ast_expression_equal(AST *a, AST *b) {
if(a->nodeKind != b->nodeKind) return 0;
if(a->nodeKind == AST_EXPR_PRIMITIVE) {
return a->exprPrim.val == b->exprPrim.val;
} else if(a->nodeKind == AST_EXPR_VAR) {
return a->exprVar.thing == b->exprVar.thing;
} else if(a->nodeKind == AST_EXPR_UNARY_OP) {
return a->exprUnOp.operator == b->exprUnOp.operator && ast_expression_equal(a->exprUnOp.operand, b->exprUnOp.operand);
} else if(a->nodeKind == AST_EXPR_BINARY_OP) {
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]);
}
}
// This function may return three values: YES (1), NO (0) or UNKNOWN (-1).
// ... Ew
int ast_stmt_is_after(const AST *chunk, const AST *s1, const AST *s2) {
const AST *s = chunk->chunk.statementFirst;
while(1) {
if(s && s->nodeKind == AST_STMT_LOOP) {
int i = ast_stmt_is_after(s->stmtLoop.body, s1, s2);
if(i == 1 || (i == 0 && s1 != NULL)) {
return i;
}
}
if(s == s1) {
return 0;
}
if(s == s2) {
return 1;
}
if(!s) break;
if(s->nodeKind == AST_STMT_IF) {
int i = ast_stmt_is_after(s->stmtIf.then, s1, s2);
if(i == 1 || (i == 0 && s1 != NULL)) {
return i;
}
if(s->stmtIf.elss) {
i = ast_stmt_is_after(s->stmtIf.elss, s1, s2);
if(i == 1 || (i == 0 && s1 != NULL)) {
return i;
}
}
}
s = s->statement.next;
}
return -1;
}
AST *ast_get_label_by_name(AST *tlc, const char *name) {
for(AST *s = tlc->chunk.statementFirst; s; s = s->statement.next) {
if(s->nodeKind == AST_STMT_LABEL && !strcmp(s->stmtLabel.name, name)) {
return s;
}
}
stahp(0, 0, "Label %s not found", name);
}
static void *memdup(void *a, size_t len) {
void *r = malloc(len);
memcpy(r, a, len);
return r;
}
/*
* WARNING: Just because you deep copy an AST node, does not mean
* ast_expression_equal will return true! This matters for example with
* function calls (a function call is not equal to itself).
*/
AST *ast_deep_copy(AST *src) {
if(src->nodeKind == AST_EXPR_VAR) {
return memdup(src, sizeof(ASTExprVar));
} else if(src->nodeKind == AST_EXPR_PRIMITIVE) {
return memdup(src, sizeof(ASTExprPrimitive));
} else if(src->nodeKind == AST_EXPR_VAR) {
return memdup(src, sizeof(ASTExprVar));
} else if(src->nodeKind == AST_EXPR_UNARY_OP) {
ASTExprUnaryOp *n = memdup(src, sizeof(ASTExprUnaryOp));
n->operand = ast_deep_copy(n->operand);
return n;
}
abort();
}
AST *ast_cast_expr(AST *what, Type *to) {
if(what == NULL) {
stahp(0, 0, "NULL what passed to ast_cast_expr");
goto fail;
}
/* 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 || to->array.length == -1)) {
ASTExprArray *ret = calloc(1, sizeof(*ret));
ret->nodeKind = AST_EXPR_ARRAY;
ret->items = calloc(what->exprStrLit.length, sizeof(*ret->items));
ret->type = to;
// If this declaration is of an unknown-length array type (eg u8[?]) then update the length
if(to->array.length == -1) {
to->array.length = what->exprStrLit.length;
}
for(int i = 0; i < what->exprStrLit.length; i++) {
uint8_t bajt = what->exprStrLit.data[i];
ASTExprPrimitive *item = calloc(1, sizeof(*item));
item->nodeKind = AST_EXPR_PRIMITIVE;
item->type = to->array.of;
item->val = bajt;
ret->items[i] = (AST*) item;
}
return (AST*) ret;
} else if(to->type == TYPE_TYPE_PRIMITIVE) {
if(to->primitive.width != what->exprStrLit.length * 8) {
stahp_node(what, "Size mismatch between string literal and target type");
}
ASTExprPrimitive *ret = calloc(1, sizeof(*ret));
ret->nodeKind = AST_EXPR_PRIMITIVE;
ret->type = to;
ret->val = 0;
memcpy(&ret->val, what->exprStrLit.data, what->exprStrLit.length);
return (AST*) ret;
} else abort();
}
bool copy = false;
// Make sure an unparametrized generic int parameter hasn't sneaked its way in
while(what->nodeKind == AST_EXPR_VAR && what->exprVar.thing->kind == SCOPEITEM_CEXPR && what->exprVar.thing->data.cexpr.concrete) {
what = what->exprVar.thing->data.cexpr.concrete;
copy = true;
}
assert(!(what->nodeKind == AST_EXPR_VAR && what->exprVar.thing->kind == SCOPEITEM_CEXPR));
if(copy) {
what = ast_deep_copy(what);
}
if(type_equal(what->expression.type, to)) return what;
if(!type_is_castable(what->expression.type, to)) {
goto fail;
}
if(what->nodeKind == AST_EXPR_PRIMITIVE && (to->type == TYPE_TYPE_PRIMITIVE || to->type == TYPE_TYPE_POINTER)) {
ASTExprPrimitive *ret = calloc(1, sizeof(*ret));
ret->nodeKind = AST_EXPR_PRIMITIVE;
ret->type = to;
if(to->type == TYPE_TYPE_PRIMITIVE) {
ret->val = what->exprPrim.val & ((1UL << to->primitive.width) - 1);
} else {
ret->val = what->exprPrim.val & ((1UL << (8 * type_size(to))) - 1);
}
return (AST*) ret;
} else {
ASTExprCast *ret = calloc(1, sizeof(*ret));
ret->nodeKind = AST_EXPR_CAST;
ret->type = to;
ret->what = what;
ret->to = to;
return (AST*) ret;
}
fail:
stahp_node(what, "Cannot cast type %s into %s", type_to_string(what->expression.type), type_to_string(to));
}
struct ReferencesStackState {
bool yes;
};
static void references_stack_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
AST *n = *nptr;
if(n->nodeKind == AST_EXPR_STACK_POINTER) {
((struct ReferencesStackState*) ud)->yes = true;
}
}
bool ast_references_stack(AST *a) {
struct ReferencesStackState state = {};
generic_visitor(&a, NULL, NULL, NULL, NULL, &state, references_stack_visitor, NULL);
return state.yes;
}
struct IsScopeItemReferenced {
bool yes;
ScopeItem *si;
};
static void is_scopeitem_referenced_visitor(AST **aptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *tlc, void *ud) {
struct IsScopeItemReferenced *state = ud;
AST *n = *aptr;
if(n->nodeKind == AST_EXPR_UNARY_OP) {
if(n->exprUnOp.operand->nodeKind == AST_EXPR_VAR && n->exprUnOp.operator == UNOP_REF && n->exprUnOp.operand->exprVar.thing == state->si) {
state->yes = true;
}
}
}
bool ast_is_scopeitem_referenced(AST *tlc, ScopeItem *si) {
struct IsScopeItemReferenced state = {.si = si};
generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, NULL, is_scopeitem_referenced_visitor);
return state.yes;
}
ScopeItem *ast_tlc_new_var(AST *tlc, char *name, Type *itstype) {
ScopeItem *vte = calloc(1, sizeof(*vte));
vte->kind = SCOPEITEM_VAR;
vte->type = itstype;
vte->data.var.color = -1;
vte->data.var.precolored = false;
vte->data.var.degree = 0;
vte->data.var.priority = 0;
vte->data.var.name = name;
// 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;
return vte;
}