diff options
[IPL/T] Overhauled how functions are handled, added list type
1 files changed, 115 insertions, 50 deletions
| -rw-r--r-- | Year 2/Implementation of Programming Languages/Transpiler/src/LLVMVisitor/LLVMVisitor.cpp | 165 |
diff --git a/Year 2/Implementation of Programming Languages/Transpiler/src/LLVMVisitor/LLVMVisitor.cpp b/Year 2/Implementation of Programming Languages/Transpiler/src/LLVMVisitor/LLVMVisitor.cpp index 1fce314..98af7f8 100644 --- a/Year 2/Implementation of Programming Languages/Transpiler/src/LLVMVisitor/LLVMVisitor.cpp +++ b/Year 2/Implementation of Programming Languages/Transpiler/src/LLVMVisitor/LLVMVisitor.cpp @@ -2,80 +2,145 @@ #include <vector> #include "LLVMVisitor.h" -LLVMVisitor::LLVMVisitor(const char* fileName) : outFile(std::ofstream(fileName)), greg("@v"), lreg("%v") { - if (!outFile.is_open()) - throw std::runtime_error("Couldn't open file for writing!"); - // outFile << "define i32 @main() {\n"; +LLVMRet LLVMVisitor::f_defun(const std::vector<Value*>& args) { + Name* fname = static_cast<Name*>(args[0]); + List* fargs = static_cast<List*>(args[1]); + + /* Transform into IR of structure + * define @name(T arg1, T arg2) { + * ... + * ret T %reg + * } + */ + + lreg.reset(); + + LLVMRet funcRet; + unsigned outbodySize = outBuf.size(); + for (unsigned i = 2; i < args.size(); i++) { + funcRet = args[i]->Visit(*this); + } + + std::map<std::string, LLVMRet> locals; + outFile << "define " << funcRet.type << " @" << fname->get_value() << "("; + + for (Value* v : fargs->get_value()) { + std::string name = "%_" + static_cast<Name*>(v)->get_value(); + // TODO: figure out argument type, based on usage + outFile << "i32 " << name; + locals.insert({ name, { "i32", name } }); + if (v != fargs->get_value().back()) + outFile << ", "; + } + outFile << ") {\n"; + + for (unsigned i = outbodySize; i < outBuf.size(); i++) { + outFile << outBuf[i]; + } + while (outbodySize < outBuf.size()) { + outBuf.pop_back(); + } + + outFile << "\tret " << funcRet << "\n}\n\n"; + return { funcRet.type, "@" + fname->get_value() }; } -void LLVMVisitor::finalizeFile() { - // outFile << "ret i32 0\n}\n"; +LLVMRet LLVMVisitor::nameAsVar(const Name* name, std::map<std::string, LLVMRet>& locals) { + auto asLoc = locals.find("%_" + name->get_value()); + if (asLoc != locals.end()) + return asLoc->second; + + auto asVar = vars_user.find("@" + name->get_value()); + if (asVar != vars_user.end()) + return asVar->second; + + auto asFunc = funcs_user.find("@" + name->get_value()); + if (asFunc != funcs_user.end()) + return asFunc->second; + + // TODO: try to figure out type (f_defun) + LLVMRet newLocal = { "i32", "%_" + name->get_value() }; + locals.insert({ newLocal.addr, newLocal }); + return newLocal; } -std::string LLVMVisitor::Visit(const Integer& vint) { - return std::to_string(vint.get_value()); +LLVMRet LLVMVisitor::aritop(const std::string name, const std::vector<Value*>& args, unsigned astart) { + LLVMRet leftRet = args[astart]->Visit(*this); + LLVMRet rightRet = (args.size() - astart > 2) ? aritop(name, args, astart+1) + : args[astart+1]->Visit(*this); + + Register r = lreg++; + outBuf.push_back(*r + " = " + ((leftRet.type == "double") ? "f" : "") + name + " " + leftRet.toStr() + ", " + rightRet.addr + "\n"); + + return { leftRet.type, *r }; } -std::string LLVMVisitor::Visit(const Float& vfloat) { - return std::to_string(vfloat.get_value()); +LLVMRet LLVMVisitor::f_add(const std::vector<Value*>& args) { + return aritop("add", args); } -std::string LLVMVisitor::Visit(const Name& vname) { - return vname.get_value(); +LLVMRet LLVMVisitor::f_sub(const std::vector<Value*>& args) { + return aritop("sub", args); } -std::string LLVMVisitor::Visit(const Funcall& vfuncall) { - if (std::find(gfuncs.begin(), gfuncs.end(), vfuncall) == gfuncs.end()) - throw std::runtime_error("Function doesn't exist!"); +LLVMRet LLVMVisitor::Visit(const Funcall& vfuncall) { + // Direct functions generate their own LLVM IR + auto directFuncIt = funcs_direct.find(vfuncall.get_funname()); + if (directFuncIt != funcs_direct.end()) + return directFuncIt->second(*this, vfuncall.get_args()); - std::vector<std::string> pargs; + auto userFuncIt = funcs_user.find(vfuncall.get_funname()); + if (userFuncIt == funcs_user.end()) + throw std::runtime_error("Function isn't defined!"); + + /* Transform into IR of structure: + * %0 = call T @func(T %a1, T %a2) + */ + + std::vector<LLVMRet> pargs; for (Value* arg : vfuncall.get_args()) pargs.push_back(arg->Visit(*this)); std::string valReg = *(lreg++); - outFile << valReg << " = call i32 " << vfuncall.get_funname() << "("; - for (std::string arg : pargs) - outFile << "i32 " << arg << ", "; - outFile << ")\n"; - return valReg; + std::string out = valReg + " = call " + userFuncIt->second.toStr() + "("; + for (LLVMRet& arg : pargs) { + out += arg.toStr(); + if (arg.addr != pargs.back().addr) + out += ", "; + } + outBuf.push_back(out += ")\n"); + return { userFuncIt->second.type, valReg }; } -void f_add(std::string reg, Value::T_Primitive ty, std::string first, std::string second, std::ofstream& of) { - of << reg << " = "; - switch(ty) { - case Value::T_integer: of << "add i32"; break; - case Value::T_float: of << "fadd double"; break; - default: throw std::runtime_error("Invalid type for function!"); - } - of << " " << first << ", " << second << "\n"; +LLVMVisitor::LLVMVisitor(const char* fileName) : outFile(std::ofstream(fileName)), greg("@v"), lreg("%v"), funcs_direct(), funcs_user(), vars_user(), outBuf() { + if (!outFile.is_open()) + throw std::runtime_error("Couldn't open file for writing!"); + + funcs_direct.insert({"+", &LLVMVisitor::f_add}); + funcs_direct.insert({"-", &LLVMVisitor::f_sub}); + funcs_direct.insert({"defun", &LLVMVisitor::f_defun}); } -void f_sub(std::string reg, Value::T_Primitive ret, std::string first, std::string second, std::ofstream& of) { - of << reg << " = "; - switch(ret) { - case Value::T_integer: of << "sub i32"; break; - case Value::T_float: of << "fsub double"; break; - default: throw std::runtime_error("Invalid type for function!"); +void LLVMVisitor::insertMain() { + outFile << "define i32 @main() {\n"; + for (std::string& codeline : outBuf) { + outFile << codeline; } - of << " " << first << ", " << second << "\n"; + outFile << "ret i32 0\n}\n"; } -std::string LLVMVisitor::rightAssoc(BiFout f, const BuiltInFunction& bfun, unsigned i) { - std::string leftArg = bfun.get_args()[i]->Visit(*this); - std::string rightArg; - if (bfun.get_args().size() - 2 == i) - rightArg = bfun.get_args()[i+1]->Visit(*this); - else - rightArg = rightAssoc(f, bfun, i+1); +LLVMRet LLVMVisitor::Visit(const Integer& vint) { + return { "i32", std::to_string(vint.get_value()) }; +} - std::string valRegister = *(lreg++); - f(valRegister, bfun.RetType(), leftArg, rightArg, outFile); - return valRegister; +LLVMRet LLVMVisitor::Visit(const Float& vfloat) { + return { "double", std::to_string(vfloat.get_value()) }; } -std::string LLVMVisitor::Visit(const BuiltInFunction& bfun) { - if (bfun.get_name() == "+") return rightAssoc(f_add, bfun); - if (bfun.get_name() == "-") return rightAssoc(f_sub, bfun); +LLVMRet LLVMVisitor::Visit(const Name& vname) { + return { "name", vname.get_value() }; +} - return ""; +LLVMRet LLVMVisitor::Visit(const List& vlist) { + return { "", "" }; // TODO } |
