intermediate language generation
This commit is contained in:
parent
529e491ab6
commit
0d5baf46a3
|
@ -1,38 +1,163 @@
|
||||||
#include <emit.hh>
|
#include <emit.hh>
|
||||||
#include <iostream>
|
#include <vector>
|
||||||
|
|
||||||
namespace xlang {
|
namespace xlang {
|
||||||
|
|
||||||
EmitListener::EmitListener(std::string_view outputfile) : output{outputfile} {}
|
class EmitFunctionVisitor : public xlangBaseVisitor {};
|
||||||
|
|
||||||
void EmitListener::enterFile(xlangParser::FileContext *ctx) {
|
EmitVisitor::EmitVisitor(std::string_view outputfile) : output{outputfile} {}
|
||||||
output << "data $printformat = { b \"%ld\\n\", b 0 }" << std::endl;
|
|
||||||
(void)ctx;
|
std::any EmitVisitor::visitFile(xlangParser::FileContext *ctx) {
|
||||||
|
output << "data $printformat = { b \"%d\\n\", b 0 }" << std::endl;
|
||||||
|
visitChildren(ctx);
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitListener::enterFunction(xlangParser::FunctionContext *ctx) {
|
std::any EmitVisitor::visitFunction(xlangParser::FunctionContext *ctx) {
|
||||||
output << std::endl
|
output << std::endl
|
||||||
<< "export function w $" << ctx->Identifier()->getSymbol()->getText()
|
<< "export function w $" << ctx->Identifier()->getSymbol()->getText()
|
||||||
<< "()" << std::endl
|
<< "(";
|
||||||
<< "{" << std::endl
|
if (auto arg_list = ctx->argumentList()) {
|
||||||
<< "@start" << std::endl;
|
for (const auto arg : arg_list->Identifier()) {
|
||||||
|
output << "w %_" << arg->getSymbol()->getText() << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output << ")" << std::endl << "{" << std::endl << "@start" << std::endl;
|
||||||
|
blockcount = 0;
|
||||||
|
visitChildren(ctx);
|
||||||
|
output << " ret 0" << std::endl;
|
||||||
|
output << "}" << std::endl;
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitListener::exitFunction(xlangParser::FunctionContext *ctx) {
|
std::any EmitVisitor::visitBlock(xlangParser::BlockContext *ctx) {
|
||||||
output << " ret 0" << std::endl << "}" << std::endl;
|
output << "@block" << blockcount++ << std::endl;
|
||||||
(void)ctx;
|
visitChildren(ctx);
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitListener::exitStatement(xlangParser::StatementContext *ctx) {
|
std::any EmitVisitor::visitStatement(xlangParser::StatementContext *ctx) {
|
||||||
|
if (auto identifier = ctx->Identifier()) {
|
||||||
|
tmpcount = 0;
|
||||||
|
visitChildren(ctx);
|
||||||
|
output << " %_" << identifier->getSymbol()->getText() << " = w copy %t"
|
||||||
|
<< tmpcount - 1 << std::endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (ctx->If()) {
|
||||||
|
int block = blockcount;
|
||||||
|
output << "@ifexpr" << block << std::endl;
|
||||||
|
tmpcount = 0;
|
||||||
|
visitExpr(ctx->expr());
|
||||||
|
output << " jnz %t" << tmpcount - 1 << ", @block" << block << ", @ifelse"
|
||||||
|
<< block << std::endl;
|
||||||
|
visitBlock(ctx->block(0));
|
||||||
|
output << "@ifelse" << block << std::endl;
|
||||||
|
if (ctx->Else()) {
|
||||||
|
visitBlock(ctx->block(1));
|
||||||
|
}
|
||||||
|
output << "@ifend" << block << std::endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (ctx->While()) {
|
||||||
|
int block = blockcount;
|
||||||
|
output << "@whileexpr" << block << std::endl;
|
||||||
|
tmpcount = 0;
|
||||||
|
visitExpr(ctx->expr());
|
||||||
|
output << " jnz %t" << tmpcount - 1 << ", @block" << block << ", @whileend"
|
||||||
|
<< block << std::endl;
|
||||||
|
visitBlock(ctx->block(0));
|
||||||
|
output << " jmp @whileexpr" << block << std::endl;
|
||||||
|
output << "@whileend" << block << std::endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (ctx->Return()) {
|
||||||
|
tmpcount = 0;
|
||||||
|
visitChildren(ctx);
|
||||||
|
output << " ret %t" << tmpcount - 1 << std::endl;
|
||||||
|
output << "@dead" << blockcount++ << std::endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
if (ctx->Print()) {
|
if (ctx->Print()) {
|
||||||
output << " call $printf(l $printformat, ..., w %v)" << std::endl;
|
tmpcount = 0;
|
||||||
|
visitChildren(ctx);
|
||||||
|
output << " call $printf(l $printformat, ..., w %t" << tmpcount - 1 << ")"
|
||||||
|
<< std::endl;
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
// unreachable
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitListener::exitFactor(xlangParser::FactorContext *ctx) {
|
#define OPERATOR(Operator, visitLeft, left, visitRight, right, ssa_op) \
|
||||||
if (auto integer = ctx->Integer()) {
|
if (ctx->Operator()) { \
|
||||||
output << " %v = w copy " << integer->getSymbol()->getText() << std::endl;
|
visitLeft(ctx->left); \
|
||||||
|
int l = tmpcount - 1; \
|
||||||
|
visitRight(ctx->right); \
|
||||||
|
output << " %t" << tmpcount << " = w " ssa_op " %t" << l << ", %t" \
|
||||||
|
<< tmpcount - 1 << std::endl; \
|
||||||
|
tmpcount++; \
|
||||||
|
return {}; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::any EmitVisitor::visitExpr(xlangParser::ExprContext *ctx) {
|
||||||
|
OPERATOR(Less, visitSum, sum(0), visitSum, sum(1), "csltw");
|
||||||
|
OPERATOR(LessEqual, visitSum, sum(0), visitSum, sum(1), "cslew");
|
||||||
|
OPERATOR(Greater, visitSum, sum(0), visitSum, sum(1), "csgtw");
|
||||||
|
OPERATOR(GreaterEqual, visitSum, sum(0), visitSum, sum(1), "csgew");
|
||||||
|
OPERATOR(Equal, visitSum, sum(0), visitSum, sum(1), "ceqw");
|
||||||
|
OPERATOR(NotEqual, visitSum, sum(0), visitSum, sum(1), "cnew");
|
||||||
|
visitSum(ctx->sum(0));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::any EmitVisitor::visitSum(xlangParser::SumContext *ctx) {
|
||||||
|
OPERATOR(Plus, visitSum, sum(), visitTerm, term(), "add");
|
||||||
|
OPERATOR(Minus, visitSum, sum(), visitTerm, term(), "sub");
|
||||||
|
visitTerm(ctx->term());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::any EmitVisitor::visitTerm(xlangParser::TermContext *ctx) {
|
||||||
|
OPERATOR(Mul, visitTerm, term(), visitFactor, factor(), "mul");
|
||||||
|
OPERATOR(Div, visitTerm, term(), visitFactor, factor(), "div");
|
||||||
|
visitFactor(ctx->factor());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::any EmitVisitor::visitFactor(xlangParser::FactorContext *ctx) {
|
||||||
|
if (auto integer = ctx->Integer()) {
|
||||||
|
output << " %t" << tmpcount++ << " = w copy "
|
||||||
|
<< integer->getSymbol()->getText() << std::endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (auto identifier = ctx->Identifier()) {
|
||||||
|
if (ctx->LeftParen()) {
|
||||||
|
std::vector<int> args;
|
||||||
|
if (auto expr_list = ctx->exprList()) {
|
||||||
|
for (auto expr : expr_list->expr()) {
|
||||||
|
visitExpr(expr);
|
||||||
|
args.push_back(tmpcount - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output << " %t" << tmpcount++ << " = w call $"
|
||||||
|
<< identifier->getSymbol()->getText() << "(";
|
||||||
|
for (auto arg : args) {
|
||||||
|
output << "w %t" << arg << ", ";
|
||||||
|
}
|
||||||
|
output << ")" << std::endl;
|
||||||
|
} else {
|
||||||
|
output << " %t" << tmpcount++ << " = w copy %_"
|
||||||
|
<< identifier->getSymbol()->getText() << std::endl;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (auto sum = ctx->sum()) {
|
||||||
|
visitSum(sum);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
// unreachable
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace xlang
|
} // namespace xlang
|
||||||
|
|
|
@ -2,21 +2,26 @@
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <xlangBaseListener.h>
|
#include <xlangBaseVisitor.h>
|
||||||
|
|
||||||
namespace xlang {
|
namespace xlang {
|
||||||
|
|
||||||
class EmitListener : public xlangBaseListener {
|
class EmitVisitor : public xlangBaseVisitor {
|
||||||
std::ofstream output;
|
std::ofstream output;
|
||||||
|
int blockcount;
|
||||||
|
int tmpcount;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EmitListener(std::string_view outputfile);
|
EmitVisitor(std::string_view outputfile);
|
||||||
|
|
||||||
void enterFile(xlangParser::FileContext *ctx) override;
|
std::any visitFile(xlangParser::FileContext *ctx) override;
|
||||||
void enterFunction(xlangParser::FunctionContext *ctx) override;
|
std::any visitFunction(xlangParser::FunctionContext *ctx) override;
|
||||||
void exitFunction(xlangParser::FunctionContext *ctx) override;
|
std::any visitBlock(xlangParser::BlockContext *ctx) override;
|
||||||
void exitStatement(xlangParser::StatementContext *ctx) override;
|
std::any visitStatement(xlangParser::StatementContext *ctx) override;
|
||||||
void exitFactor(xlangParser::FactorContext *ctx) override;
|
std::any visitExpr(xlangParser::ExprContext *ctx) override;
|
||||||
|
std::any visitSum(xlangParser::SumContext *ctx) override;
|
||||||
|
std::any visitTerm(xlangParser::TermContext *ctx) override;
|
||||||
|
std::any visitFactor(xlangParser::FactorContext *ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace xlang
|
} // namespace xlang
|
||||||
|
|
|
@ -43,7 +43,7 @@ int main(int argc, char **argv) {
|
||||||
xlang::xlangParser parser{&tokens};
|
xlang::xlangParser parser{&tokens};
|
||||||
auto *tree = parser.file();
|
auto *tree = parser.file();
|
||||||
|
|
||||||
xlang::EmitListener emit{outputfile};
|
xlang::EmitVisitor emit{outputfile};
|
||||||
antlr4::tree::ParseTreeWalker::DEFAULT.walk(&emit, tree);
|
emit.visitFile(tree);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,13 +11,19 @@ statement : Identifier Assign expr Semicolon
|
||||||
| Print expr Semicolon
|
| Print expr Semicolon
|
||||||
| expr Semicolon
|
| expr Semicolon
|
||||||
;
|
;
|
||||||
expr : sum ((Less|LessEqual|Greater|GreaterEqual|Equal|NotEqual) sum)*;
|
expr : sum ((Less|LessEqual|Greater|GreaterEqual|Equal|NotEqual) sum)
|
||||||
sum : term ((Plus|Minus) term)*;
|
| sum
|
||||||
term : factor ((Mul|Div) factor)*;
|
;
|
||||||
|
sum : sum ((Plus|Minus) term)
|
||||||
|
| term
|
||||||
|
;
|
||||||
|
term : term ((Mul|Div) factor)
|
||||||
|
| factor
|
||||||
|
;
|
||||||
factor : Integer
|
factor : Integer
|
||||||
| Identifier
|
| Identifier
|
||||||
| Identifier LeftParen exprList? RightParen
|
| Identifier LeftParen exprList? RightParen
|
||||||
| LeftParen expr RightParen
|
| LeftParen sum RightParen
|
||||||
;
|
;
|
||||||
exprList : expr (Comma expr)*;
|
exprList : expr (Comma expr)*;
|
||||||
|
|
||||||
|
@ -45,7 +51,7 @@ Div : '/';
|
||||||
Comma : ',';
|
Comma : ',';
|
||||||
Semicolon : ';';
|
Semicolon : ';';
|
||||||
|
|
||||||
Identifier : [a-zA-Z][a-zA-Z0-9]*;
|
Identifier : [_a-zA-Z][_a-zA-Z0-9]*;
|
||||||
Integer : [0-9]+;
|
Integer : [0-9]+;
|
||||||
|
|
||||||
Comment : '//' ~[\n]* '\n' -> skip;
|
Comment : '//' ~[\n]* '\n' -> skip;
|
||||||
|
|
18
test/fib.x
18
test/fib.x
|
@ -1,10 +1,20 @@
|
||||||
main() {
|
main() {
|
||||||
// print 5th fibonacci number
|
i = 0;
|
||||||
print fib(5);
|
while i < 10 {
|
||||||
return 0;
|
print fib_rec(i);
|
||||||
|
print fib_iter(i);
|
||||||
|
i = i + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fib(n) {
|
fib_rec(n) {
|
||||||
|
if n < 2 {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return fib_rec(n - 1) + fib_rec(n - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
fib_iter(n) {
|
||||||
x0 = 1;
|
x0 = 1;
|
||||||
x1 = 1;
|
x1 = 1;
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
Loading…
Reference in a new issue