xlang/bootstrap/emit.cc

285 lines
8.5 KiB
C++

#include <emit.hh>
#include <vector>
namespace xlang {
std::string EmitVisitor::tmp() {
last = "%t" + std::to_string(tmpcount++);
return last;
}
EmitVisitor::EmitVisitor(std::string_view outputfile) : output{outputfile} {}
std::any EmitVisitor::visitFile(xlangParser::FileContext *ctx) {
output << "data $printformat = { b \"%d\\n\", b 0 }" << std::endl;
visitChildren(ctx);
return {};
}
std::any EmitVisitor::visitFunction(xlangParser::FunctionContext *ctx) {
output << std::endl
<< "export function w $" << ctx->Identifier()->getSymbol()->getText()
<< "(";
if (auto param_list = ctx->parameterList()) {
for (auto param : param_list->parameter()) {
output << "w %_" << param->Identifier()->getSymbol()->getText() << ", ";
}
}
output << ")" << std::endl << "{" << std::endl << "@start" << std::endl;
blockcount = 0;
visitChildren(ctx);
output << " ret 0" << std::endl;
output << "}" << std::endl;
return {};
}
std::any EmitVisitor::visitStatement(xlangParser::StatementContext *ctx) {
if (ctx->If()) {
int block = blockcount++;
output << "@if" << block << "_expr" << std::endl;
tmpcount = 0;
visitExpr(ctx->expr(0));
output << " jnz " << last << ", @if" << block << "_then, @if" << block
<< "_else" << std::endl;
output << "@if" << block << "_then" << std::endl;
visitBlock(ctx->block(0));
output << " jmp @if" << block << "_end" << std::endl;
output << "@if" << block << "_else" << std::endl;
if (ctx->Else()) {
visitBlock(ctx->block(1));
}
output << "@if" << block << "_end" << std::endl;
return {};
}
if (ctx->While()) {
int block = blockcount++;
loopstack.push_back(block);
output << "@loop" << block << "_continue" << std::endl;
output << "@loop" << block << "_expr" << std::endl;
tmpcount = 0;
visitExpr(ctx->expr(0));
output << " jnz " << last << ", @loop" << block << "_body, @loop" << block
<< "_end" << std::endl;
output << "@loop" << block << "_body" << std::endl;
visitBlock(ctx->block(0));
output << " jmp @loop" << block << "_expr" << std::endl;
output << "@loop" << block << "_end" << std::endl;
loopstack.pop_back();
return {};
}
if (ctx->For()) {
int block = blockcount++;
loopstack.push_back(block);
tmpcount = 0;
visitExpr(ctx->expr(0));
output << "@loop" << block << "_expr" << std::endl;
tmpcount = 0;
visitExpr(ctx->expr(1));
output << " jnz " << last << ", @loop" << block << "_body, @loop" << block
<< "_end" << std::endl;
output << "@loop" << block << "_body" << std::endl;
visitBlock(ctx->block(0));
output << "@loop" << block << "_continue" << std::endl;
tmpcount = 0;
visitExpr(ctx->expr(2));
output << " jmp @loop" << block << "_expr" << std::endl;
output << "@loop" << block << "_end" << std::endl;
loopstack.pop_back();
return {};
}
if (ctx->Break()) {
if (auto integer = ctx->Integer()) {
auto num = stoul(integer->getSymbol()->getText());
output << " jmp @loop" << *(loopstack.end() - num) << "_end"
<< std::endl;
} else {
output << " jmp @loop" << loopstack.back() << "_end" << std::endl;
}
output << "@dead" << blockcount++ << std::endl;
return {};
}
if (ctx->Continue()) {
if (auto integer = ctx->Integer()) {
auto num = stoul(integer->getSymbol()->getText());
output << " jmp @loop" << *(loopstack.end() - num) << "_continue"
<< std::endl;
} else {
output << " jmp @loop" << loopstack.back() << "_continue" << std::endl;
}
output << "@dead" << blockcount++ << std::endl;
return {};
}
if (ctx->Return()) {
tmpcount = 0;
visitExpr(ctx->expr(0));
output << " ret " << last << std::endl;
output << "@dead" << blockcount++ << std::endl;
return {};
}
if (ctx->Print()) {
tmpcount = 0;
visitExpr(ctx->expr(0));
output << " call $printf(l $printformat, ..., w " << last << ")"
<< std::endl;
return {};
}
visitExpr(ctx->expr(0));
return {};
}
std::any EmitVisitor::visitExpr(xlangParser::ExprContext *ctx) {
if (auto op = ctx->assignmentOp()) {
auto name = ctx->Identifier()->getSymbol()->getText();
if (op->Define() || op->Assign()) {
visitExpr(ctx->expr());
output << " %_" << name << " = w copy " << last << std::endl;
last = "%_" + name;
return {};
}
if (op->Increment()) {
visitExpr(ctx->expr());
output << " %_" << name << " = w add %_" << name << ", " << last
<< std::endl;
last = "%_" + name;
return {};
}
if (op->Decrement()) {
visitExpr(ctx->expr());
output << " %_" << name << " = w sub %_" << name << ", " << last
<< std::endl;
last = "%_" + name;
return {};
}
}
visitBooleanExpr(ctx->booleanExpr());
return {};
}
#define OPERATOR(Operator, ssa_op) \
if (op->Operator()) { \
output << " " << tmp() << " = w " ssa_op " " << left << ", " << right \
<< std::endl; \
}
std::any EmitVisitor::visitBooleanExpr(xlangParser::BooleanExprContext *ctx) {
visitComparisonExpr(ctx->comparisonExpr(0));
for (size_t i = 0, n = ctx->booleanOp().size(); i < n; i++) {
std::string left = last;
visitComparisonExpr(ctx->comparisonExpr(i + 1));
std::string right = last;
auto op = ctx->booleanOp(i);
OPERATOR(And, "and");
OPERATOR(Or, "or");
OPERATOR(Xor, "xor");
}
return {};
}
std::any EmitVisitor::visitComparisonExpr(
xlangParser::ComparisonExprContext *ctx) {
if (ctx->Not()) {
visitComparisonExpr(ctx->comparisonExpr());
std::string b = last;
output << " " << tmp() << " = w xor 1, " << b << std::endl;
return {};
}
if (ctx->True()) {
last = "1";
return {};
}
if (ctx->False()) {
last = "0";
return {};
}
visitAdditiveExpr(ctx->additiveExpr(0));
if (auto op = ctx->comparisonOp()) {
std::string left = last;
visitAdditiveExpr(ctx->additiveExpr(1));
std::string right = last;
OPERATOR(Less, "csltw");
OPERATOR(LessEqual, "cslew");
OPERATOR(Greater, "csgtw");
OPERATOR(GreaterEqual, "csgew");
OPERATOR(Equal, "ceqw");
OPERATOR(NotEqual, "cnew");
}
return {};
}
std::any EmitVisitor::visitAdditiveExpr(xlangParser::AdditiveExprContext *ctx) {
visitMultiplicativeExpr(ctx->multiplicativeExpr(0));
for (size_t i = 0, n = ctx->additiveOp().size(); i < n; i++) {
std::string left = last;
visitMultiplicativeExpr(ctx->multiplicativeExpr(i + 1));
std::string right = last;
auto op = ctx->additiveOp(i);
OPERATOR(Plus, "add");
OPERATOR(Minus, "sub");
OPERATOR(BitAnd, "and");
OPERATOR(BitOr, "or");
OPERATOR(BitXor, "xor");
OPERATOR(ShiftLeft, "shl");
OPERATOR(ShiftRight, "shr");
}
return {};
}
std::any EmitVisitor::visitMultiplicativeExpr(
xlangParser::MultiplicativeExprContext *ctx) {
visitFactor(ctx->factor(0));
for (size_t i = 0, n = ctx->multiplicativeOp().size(); i < n; i++) {
std::string left = last;
visitFactor(ctx->factor(i + 1));
std::string right = last;
auto op = ctx->multiplicativeOp(i);
OPERATOR(Mul, "mul");
OPERATOR(Div, "div");
OPERATOR(Rem, "rem");
}
return {};
}
std::any EmitVisitor::visitFactor(xlangParser::FactorContext *ctx) {
if (ctx->Minus()) {
visitFactor(ctx->factor());
std::string f = last;
output << " " << tmp() << " = w neg " << f << std::endl;
return {};
}
if (ctx->BitNot()) {
visitFactor(ctx->factor());
std::string f = last;
output << " " << tmp() << " = w xor -1, " << f << std::endl;
return {};
}
if (auto integer = ctx->Integer()) {
last = integer->getSymbol()->getText();
return {};
}
if (auto identifier = ctx->Identifier()) {
auto name = identifier->getSymbol()->getText();
if (ctx->LeftParen()) {
std::vector<std::string> args;
if (auto arg_list = ctx->argumentList()) {
for (auto expr : arg_list->expr()) {
visitExpr(expr);
args.emplace_back(last);
}
}
output << " " << tmp() << " = w call $" << name << "(";
for (auto arg : args) {
output << "w " << arg << ", ";
}
output << ")" << std::endl;
return {};
} else {
last = "%_" + name;
return {};
}
}
visitExpr(ctx->expr());
return {};
}
} // namespace xlang