340 lines
8.0 KiB
C
340 lines
8.0 KiB
C
#include"dump.h"
|
|
|
|
#include"ast.h"
|
|
#include"types.h"
|
|
#include<stdlib.h>
|
|
#include<stdio.h>
|
|
#include<string.h>
|
|
#include"utils.h"
|
|
|
|
char *type_to_string(Type *t) {
|
|
if(t->type == TYPE_TYPE_PRIMITIVE) {
|
|
char ret[16] = {};
|
|
int i = 0;
|
|
|
|
ret[i++] = t->primitive.isFloat ? 'f' : (t->primitive.isUnsigned ? 'u' : 'i');
|
|
snprintf(ret + i, sizeof(ret) - i, "%i", t->primitive.width);
|
|
|
|
return strdup(ret);
|
|
} else if(t->type == TYPE_TYPE_POINTER) {
|
|
char *c = type_to_string(t->pointer.of);
|
|
char *r = malp("%s*", c);
|
|
free(c);
|
|
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("%li", t->array.length);
|
|
}
|
|
char *r = malp("%s[%s]", of, len);
|
|
free(of);
|
|
free(len);
|
|
return r;
|
|
}
|
|
|
|
return strdup("@unimp");
|
|
}
|
|
|
|
static char *ast_dumpe(AST *tlc, AST *e) {
|
|
if(!e) {
|
|
return malp("(null)");
|
|
}
|
|
|
|
if(e->nodeKind == AST_EXPR_PRIMITIVE) {
|
|
return malp("%i", e->exprPrim.val);
|
|
} else if(e->nodeKind == AST_EXPR_VAR) {
|
|
ScopeItem *vte = e->exprVar.thing;
|
|
|
|
if(vte->kind == SCOPEITEM_VAR) {
|
|
return strdup(vte->data.var.name);
|
|
} else if(vte->kind == SCOPEITEM_SYMBOL) {
|
|
return strdup(vte->data.symbol.name);
|
|
} else if(vte->kind == SCOPEITEM_CEXPR) {
|
|
return ast_dumpe(tlc, vte->data.cexpr.concrete);
|
|
} else abort();
|
|
} else if(e->nodeKind == AST_EXPR_UNARY_OP) {
|
|
const char *op = NULL;
|
|
switch(e->exprUnOp.operator) {
|
|
case UNOP_REF:
|
|
op = "&";
|
|
break;
|
|
case UNOP_DEREF:
|
|
op = "*";
|
|
break;
|
|
case UNOP_BITWISE_NOT:
|
|
op = "~";
|
|
break;
|
|
case UNOP_NEGATE:
|
|
op = "-";
|
|
break;
|
|
case UNOP_NOT:
|
|
op = "!";
|
|
break;
|
|
default:
|
|
abort();
|
|
}
|
|
char *c = ast_dumpe(tlc, e->exprUnOp.operand);
|
|
char *r = malp("%s%s", op, c);
|
|
free(c);
|
|
return r;
|
|
} else if(e->nodeKind == AST_EXPR_BINARY_OP) {
|
|
char *a = ast_dumpe(tlc, e->exprBinOp.operands[0]);
|
|
char *b = ast_dumpe(tlc, e->exprBinOp.operands[1]);
|
|
const char *op;
|
|
switch(e->exprBinOp.operator) {
|
|
case BINOP_ADD:
|
|
op = "+";
|
|
break;
|
|
case BINOP_SUB:
|
|
op = "-";
|
|
break;
|
|
case BINOP_MUL:
|
|
op = "*";
|
|
break;
|
|
case BINOP_DIV:
|
|
op = "/";
|
|
break;
|
|
case BINOP_BITWISE_AND:
|
|
op = "&";
|
|
break;
|
|
case BINOP_BITWISE_OR:
|
|
op = "|";
|
|
break;
|
|
case BINOP_BITWISE_XOR:
|
|
op = "^";
|
|
break;
|
|
case BINOP_EQUAL:
|
|
op = "==";
|
|
break;
|
|
case BINOP_NEQUAL:
|
|
op = "!=";
|
|
break;
|
|
case BINOP_LESS:
|
|
op = "<";
|
|
break;
|
|
case BINOP_GREATER:
|
|
op = ">";
|
|
break;
|
|
case BINOP_LEQUAL:
|
|
op = "<=";
|
|
break;
|
|
case BINOP_GEQUAL:
|
|
op = ">=";
|
|
break;
|
|
case BINOP_MULHI:
|
|
op = "*^";
|
|
break;
|
|
case BINOP_LOGICAL_AND:
|
|
op = "&&";
|
|
break;
|
|
case BINOP_LOGICAL_OR:
|
|
op = "||";
|
|
break;
|
|
default:
|
|
abort();
|
|
}
|
|
char *r = malp("(%s %s %s)", a, op, b);
|
|
free(a);
|
|
free(b);
|
|
return r;
|
|
} else if(e->nodeKind == AST_EXPR_STACK_POINTER) {
|
|
return malp("@stack");
|
|
} 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);
|
|
free(rettype);
|
|
}
|
|
|
|
for(int i = 0; i < e->expression.type->function.argCount; i++) {
|
|
char *argtype = type_to_string(e->expression.type->function.args[i]);
|
|
char *out2 = malp(i == e->expression.type->function.argCount - 1 ? "%s%s" : "%s%s, ", out, argtype);
|
|
free(out);
|
|
free(argtype);
|
|
out = out2;
|
|
}
|
|
|
|
{
|
|
char *choonk = ast_dumpc(tlc, e->exprFunc.chunk);
|
|
char *out2 = malp("%s) {\n%s}", out, choonk);
|
|
free(out);
|
|
free(choonk);
|
|
out = out2;
|
|
}
|
|
|
|
return out;
|
|
} else if(e->nodeKind == AST_EXPR_CALL) {
|
|
char *w = ast_dumpe(tlc, e->exprCall.what);
|
|
char *out = malp("%s(", w);
|
|
free(w);
|
|
size_t argCount = e->exprCall.what->expression.type->pointer.of->function.argCount;
|
|
for(size_t i = 0; i < argCount; i++) {
|
|
char *a = ast_dumpe(tlc, e->exprCall.args[i]);
|
|
char *out2 = malp(i == argCount - 1 ? "%s%s)" : "%s%s, ", out, a);
|
|
free(a);
|
|
free(out);
|
|
out = out2;
|
|
}
|
|
return out;
|
|
} else if(e->nodeKind == AST_EXPR_EXT_SALLOC) {
|
|
char *w = type_to_string(e->exprExtSalloc.size);
|
|
char *out = malp("@salloc(%s)", w);
|
|
free(w);
|
|
return out;
|
|
} else if(e->nodeKind == AST_EXPR_CAST) {
|
|
char *a = ast_dumpe(tlc, e->exprCast.what);
|
|
char *b = type_to_string(e->exprCast.to);
|
|
char *out = malp("(%s as %s)", a, b);
|
|
free(a);
|
|
free(b);
|
|
return out;
|
|
} else if(e->nodeKind == AST_EXPR_DOT) {
|
|
char *a = ast_dumpe(tlc, e->exprDot.a);
|
|
char *out = malp(e->nodeKind == AST_EXPR_BINARY_OP ? "(%s).%s" : "%s.%s", a, e->exprDot.b);
|
|
free(a);
|
|
return out;
|
|
}
|
|
|
|
return malp("@unimp:%s", AST_KIND_STR[e->nodeKind]);
|
|
}
|
|
|
|
static char *ast_dumps(AST *tlc, AST *s) {
|
|
if(s->nodeKind == AST_STMT_ASSIGN) {
|
|
if(s->stmtAssign.to) {
|
|
char *a = ast_dumpe(tlc, s->stmtAssign.what);
|
|
char *b = ast_dumpe(tlc, s->stmtAssign.to);
|
|
char *r = malp("%s = %s;", a, b);
|
|
free(a);
|
|
free(b);
|
|
return r;
|
|
} else {
|
|
char *a = ast_dumpe(tlc, s->stmtAssign.what);
|
|
char *r = malp("%s = ; /* fake def */", a);
|
|
free(a);
|
|
return r;
|
|
}
|
|
} else if(s->nodeKind == AST_STMT_JUMP) {
|
|
char *a = ast_dumpe(tlc, s->stmtJump.condition);
|
|
char *r = malp("jump %s if %s;", s->stmtJump.label, a);
|
|
free(a);
|
|
return r;
|
|
} else if(s->nodeKind == AST_STMT_LABEL) {
|
|
return malp("@label %s;", s->stmtLabel.name);
|
|
} else if(s->nodeKind == AST_STMT_LOOP) {
|
|
char *inner = ast_dumpc(tlc, s->stmtLoop.body);
|
|
char *c = malp("loop {\n%s}", inner);
|
|
free(inner);
|
|
return c;
|
|
} else if(s->nodeKind == AST_STMT_IF) {
|
|
char *cond = ast_dumpe(tlc, s->stmtIf.expression);
|
|
char *inner = ast_dumpc(tlc, s->stmtIf.then);
|
|
char *elss = s->stmtIf.elss ? ast_dumpc(tlc, s->stmtIf.elss) : NULL;
|
|
char *c;
|
|
if(elss) {
|
|
c = malp("if(%s) {\n%s} else {\n%s}", cond, inner, elss);
|
|
free(elss);
|
|
} else {
|
|
c = malp("if(%s) {\n%s}", cond, inner);
|
|
}
|
|
free(cond);
|
|
free(inner);
|
|
return c;
|
|
} else if(s->nodeKind == AST_STMT_EXPR && s->stmtExpr.expr->nodeKind == AST_EXPR_VAR) {
|
|
const char *name;
|
|
|
|
if(s->stmtExpr.expr->exprVar.thing->kind == SCOPEITEM_VAR) {
|
|
name = s->stmtExpr.expr->exprVar.thing->data.var.name;
|
|
} else {
|
|
name = s->stmtExpr.expr->exprVar.thing->data.symbol.name;
|
|
}
|
|
|
|
return malp("%s; /* loop guard */", name);
|
|
} else if(s->nodeKind == AST_STMT_EXPR) {
|
|
return ast_dumpe(tlc, s->stmtExpr.expr);
|
|
} else if(s->nodeKind == AST_STMT_DECL) {
|
|
ScopeItem *si = s->stmtDecl.thing;
|
|
const char *name = si->kind == SCOPEITEM_VAR ? si->data.var.name : si->data.symbol.name;
|
|
|
|
char *a = type_to_string(si->type);
|
|
char *c;
|
|
if(s->stmtDecl.expression) {
|
|
char *b = ast_dumpe(tlc, s->stmtDecl.expression);
|
|
c = malp("%s %s = %s;", a, name, b);
|
|
free(b);
|
|
} else {
|
|
c = malp("%s %s;", a, name);
|
|
}
|
|
free(a);
|
|
return c;
|
|
} else if(s->nodeKind == AST_STMT_RETURN) {
|
|
if(s->stmtReturn.val) {
|
|
char *e = ast_dumpe(tlc, s->stmtReturn.val);
|
|
char *c = malp("return %s;", e);
|
|
free(e);
|
|
return c;
|
|
} else {
|
|
return malp("return;");
|
|
}
|
|
}
|
|
|
|
return malp("@unimp:%s;", AST_KIND_STR[s->nodeKind]);
|
|
}
|
|
|
|
static char *stmt_live_range_dbgs(AST *tlc, AST *stmt) {
|
|
char *ret = malp("");
|
|
for(size_t v = 0; v < tlc->chunk.varCount; v++) {
|
|
ScopeItem *si = tlc->chunk.vars[v];
|
|
|
|
if(si->data.var.liveRangeStart == stmt) {
|
|
char *ret2 = malp("%s (%s start)", ret, si->data.var.name);
|
|
free(ret);
|
|
ret = ret2;
|
|
}
|
|
|
|
if(si->data.var.liveRangeEnd == stmt) {
|
|
char *ret2 = malp("%s (%s end)", ret, si->data.var.name);
|
|
free(ret);
|
|
ret = ret2;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
char *ast_dumpc(AST *tlc, AST *chu) {
|
|
AST *stmt = chu->chunk.statementFirst;
|
|
|
|
char *ret = malp("");
|
|
|
|
while(stmt) {
|
|
char *new = ast_dumps(tlc, stmt);
|
|
char *users = stmt_live_range_dbgs(tlc, stmt);
|
|
char *ret2 = malp("%s%s%s\n", ret, new, users);
|
|
free(ret);
|
|
free(new);
|
|
free(users);
|
|
ret = ret2;
|
|
|
|
stmt = stmt->statement.next;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
char *ast_dump(AST *tlc) {
|
|
return ast_dumpc(tlc, tlc);
|
|
}
|