├── Hana ├── hana.h ├── config.in ├── CodeGen │ ├── Return.cpp │ ├── UnaryOperator.h │ ├── Return.h │ ├── Range.h │ ├── CompareOperator.h │ ├── Assignment.h │ ├── Conditional.h │ ├── BinaryOperator.h │ ├── WhileLoop.h │ ├── MethodCall.h │ ├── ClassDeclaration.h │ ├── UnaryOperator.cpp │ ├── FunctionDeclaration.h │ ├── Range.cpp │ ├── Declaration.h │ ├── Conditional.cpp │ ├── Array.h │ ├── WhileLoop.cpp │ ├── Declaration.cpp │ ├── CompareOperator.cpp │ ├── Assignment.cpp │ ├── ClassDeclaration.cpp │ ├── MethodCall.cpp │ ├── BinaryOperator.cpp │ ├── Array.cpp │ ├── FunctionDeclaration.cpp │ ├── CodeGenContext.h │ └── CodeGenContext.cpp ├── Lib │ ├── Stlib.h │ └── Stlib.cpp ├── Visitor │ ├── VisitorPrettyPrint.h │ ├── VisitorSyntaxCheck.h │ ├── Visitor.h │ ├── VisitorSyntaxCheck.cpp │ └── VisitorPrettyPrint.cpp ├── Utils │ ├── GetOpt.h │ └── GetOpt.cpp ├── Ast │ ├── AstNode.cpp │ └── AstNode.h ├── hana.cpp ├── CMakeLists.txt ├── tokens.l └── parser.y ├── .gitignore ├── Samples ├── require.hana ├── wloop.hana ├── wrong_extension.huh ├── test.hana ├── require_this.hana ├── array.hana ├── class.hana ├── fibo.hana └── calc.hana ├── CMakeLists.txt ├── README.md └── LICENSE /Hana/hana.h: -------------------------------------------------------------------------------- 1 | #ifndef MAIN_H 2 | #define MAIN_H 3 | #endif 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.vscode 2 | *.output 3 | build/ 4 | *.idea/ 5 | *.llvm 6 | Hana/config.h 7 | doxygen-awesome-css/ 8 | Doxyfile 9 | cmake-build-debug/ 10 | -------------------------------------------------------------------------------- /Samples/require.hana: -------------------------------------------------------------------------------- 1 | require require_this.hana 2 | 3 | writeint(value) 4 | 5 | sayHi() 6 | 7 | cat myCat 8 | 9 | myCat._init("mio", 2) 10 | myCat._sayMeow() 11 | 12 | 13 | -------------------------------------------------------------------------------- /Hana/config.in: -------------------------------------------------------------------------------- 1 | #if !defined(CONFIG_H) 2 | #define CONFIG_H 3 | 4 | #define MAJOR_VER ${VER_MAJ} 5 | #define MINOR_VER ${VER_MIN} 6 | #define REVISION_VER ${VER_REV} 7 | #endif -------------------------------------------------------------------------------- /Samples/wloop.hana: -------------------------------------------------------------------------------- 1 | -- Use wloop for while loop 2 | 3 | int j = 1 4 | 5 | wloop j<=10 6 | writeint(j) 7 | j = j + 1 8 | 9 | boolean x = j>=10 10 | if x 11 | writeln("\'j\' is greater than 10") 12 | else 13 | writeln("\'j\' is less than 10") -------------------------------------------------------------------------------- /Samples/wrong_extension.huh: -------------------------------------------------------------------------------- 1 | --[[ 2 | This is multiline comment ahahaha! 3 | --]] 4 | 5 | --Working! 6 | let s1 = read() 7 | let s2 = read() 8 | 9 | let value = compstr(s1,s2) 10 | write("%d", value) 11 | 12 | --let s = read() 13 | --write("%s", read()) 14 | --writeln() -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | project(Hana) 4 | 5 | set(LLVM_ROOT "/home/sylvee/.local") 6 | 7 | set(CMAKE_VERBOSE_MAKEFILE ON) 8 | set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) 9 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 10 | 11 | set(CMAKE_MODULE_PATH "${Hana_SOURCE_DIR}/cmake") 12 | 13 | add_subdirectory(Hana) -------------------------------------------------------------------------------- /Samples/test.hana: -------------------------------------------------------------------------------- 1 | 2 | block cat 3 | string name 4 | int age 5 | block _init(string name, int age) 6 | self.name = name 7 | self.age = age 8 | block _getname() : string 9 | return self.name 10 | block _getage() : int 11 | return self.age 12 | block _sayhi() 13 | writeln("Meow, I am %s, %d years old.", self.name, self.age) 14 | return 15 | 16 | 17 | cat myCat 18 | 19 | myCat._init("mio", 2) 20 | myCat._sayhi() 21 | 22 | -------------------------------------------------------------------------------- /Samples/require_this.hana: -------------------------------------------------------------------------------- 1 | -- This file is required by 'require.hana' 2 | 3 | let value = 10 4 | value = value + 40 5 | 6 | block sayHi() 7 | writeln("Hi from \'require_this.hana\'") 8 | 9 | -- Can also create a block class and require it in 'require.hana' 10 | 11 | block cat 12 | string name 13 | int age 14 | block _init(string name, int age) 15 | self.name = name 16 | self.age = age 17 | block _geName() : string 18 | return self.name 19 | block _getAge() : int 20 | return self.age 21 | block _sayMeow() 22 | writeln("Meow, I am %s, %d years old.", self.name, self.age) 23 | 24 | -------------------------------------------------------------------------------- /Hana/CodeGen/Return.cpp: -------------------------------------------------------------------------------- 1 | #include "Return.h" 2 | #include "CodeGenContext.h" 3 | #include "parser.hpp" 4 | 5 | using namespace std; 6 | using namespace llvm; 7 | 8 | namespace hana 9 | { 10 | 11 | Value *Return::codeGen(CodeGenContext &context) 12 | { 13 | if (retExpr) 14 | { 15 | Value *ret = retExpr->codeGen(context); 16 | if (ret == nullptr) 17 | return nullptr; 18 | return ReturnInst::Create(context.getGlobalContext(), ret, context.currentBlock()); 19 | } 20 | else 21 | { 22 | return ReturnInst::Create(context.getGlobalContext(), 0, context.currentBlock()); 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Samples/array.hana: -------------------------------------------------------------------------------- 1 | -- List Implementation in Hana 2 | 3 | let orbs = [15,20,10,5] 4 | int second = orbs[1] 5 | writeint(second) 6 | 7 | -- Lsits can contain different datatypes 8 | 9 | let void = ["Sataou", 8, true, false, 4+12] 10 | writeln("[%s, %d, %d, %d, %d]", void[0], void[1], void[2], void[3], void[4]) 11 | 12 | -- Insertion using << 13 | 14 | void << "Hana" 15 | writeln("%s", void[5]) 16 | 17 | -- List in list 18 | 19 | let inside = ["Hi", "I", "am", "inside", "the", "void"] 20 | void << inside 21 | writeln("%s from the void!", void[6][0]) 22 | 23 | -- Concat lists 24 | 25 | let concat = void + inside 26 | writeln("%d %d %s %s", concat[1], concat[3], concat[7], concat[12]) 27 | -------------------------------------------------------------------------------- /Hana/CodeGen/UnaryOperator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Ast/AstNode.h" 4 | 5 | namespace hana 6 | { 7 | /*! Represents a unary operator. */ 8 | class UnaryOperator : public Expression 9 | { 10 | public: 11 | explicit UnaryOperator(int op, Expression *rhs) : op(op), rhs(rhs) {} 12 | virtual ~UnaryOperator() { delete rhs; } 13 | 14 | llvm::Value *codeGen(CodeGenContext &context) override; 15 | NodeType getType() override { return NodeType::expression; } 16 | std::string toString() override; 17 | void Accept(Visitor &v) override { v.VisitUnaryOperator(this); } 18 | 19 | Expression *getRHS() { return rhs; } 20 | 21 | private: 22 | int op{0}; 23 | Expression *rhs; 24 | }; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Samples/class.hana: -------------------------------------------------------------------------------- 1 | --[[ Classes can be created by the same keyword 'block' --]] 2 | 3 | block Player 4 | string name 5 | int lvl 6 | block init(string name, int lvl) 7 | self.name = name 8 | self.lvl = lvl 9 | block getlvl() : int 10 | return self.lvl 11 | block getname() : string 12 | return self.name 13 | block bonus(int inc) 14 | self.lvl = self.lvl + inc 15 | block punish(int dec) 16 | self.lvl = self.lvl - dec 17 | 18 | Player py 19 | 20 | py.init("Sataou", 25) 21 | 22 | writeln("Name: %s (Lvl: %d)", py.getname(), py.getlvl()) 23 | 24 | py.punish(5) 25 | writeln("Lvl after punishing: %d", py.getlvl()) 26 | 27 | py.bonus(20) 28 | writeln("Lvl after reward: %d", py.getlvl()) 29 | 30 | -------------------------------------------------------------------------------- /Hana/CodeGen/Return.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Ast/AstNode.h" 3 | 4 | namespace hana 5 | { 6 | 7 | /*! Represents a return statement. */ 8 | class Return : public Statement 9 | { 10 | public: 11 | Return(YYLTYPE loc, Expression *expr = nullptr) : retExpr(expr), location(loc) {} 12 | virtual ~Return() { delete retExpr; } 13 | 14 | llvm::Value *codeGen(CodeGenContext &context) override; 15 | NodeType getType() override { return NodeType::expression; } 16 | std::string toString() override { return "return statement "; } 17 | void Accept(Visitor &v) override { v.VisitReturnStatement(this); } 18 | 19 | Expression *getRetExpression() { return retExpr; } 20 | YYLTYPE &getLocation() { return location; } 21 | 22 | private: 23 | Expression *retExpr{nullptr}; 24 | YYLTYPE location; 25 | }; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Hana/CodeGen/Range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Ast/AstNode.h" 3 | 4 | namespace hana 5 | { 6 | 7 | /*! Represents a range */ 8 | class Range : public Expression 9 | { 10 | public: 11 | explicit Range(Expression *begin, Expression *end, YYLTYPE loc) : begin(begin), end(end), location(loc) {} 12 | virtual ~Range() = default; 13 | llvm::Value *codeGen(CodeGenContext &context) override; 14 | NodeType getType() override { return NodeType::range; } 15 | std::string toString() override { return "range"; } 16 | void Accept(Visitor &v) override { v.VisitRange(this); } 17 | 18 | YYLTYPE getLocation() const { return location; } 19 | 20 | private: 21 | Expression *begin{nullptr}; 22 | Expression *end{nullptr}; 23 | YYLTYPE location; 24 | friend class VisitorSyntaxCheck; 25 | friend class VisitorPrettyPrint; 26 | }; 27 | 28 | } // namespace hana 29 | -------------------------------------------------------------------------------- /Hana/CodeGen/CompareOperator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Ast/AstNode.h" 3 | 4 | namespace hana 5 | { 6 | 7 | /*! Represents a compare operator == != > < >= <= */ 8 | class CompOperator : public Expression 9 | { 10 | public: 11 | explicit CompOperator(Expression *lhs, int op, Expression *rhs) : op(op), lhs(lhs), rhs(rhs) {} 12 | virtual ~CompOperator() 13 | { 14 | delete lhs; 15 | delete rhs; 16 | } 17 | 18 | llvm::Value *codeGen(CodeGenContext &context) override; 19 | NodeType getType() override { return NodeType::expression; } 20 | std::string toString() override; 21 | void Accept(Visitor &v) override { v.VisitCompOperator(this); } 22 | 23 | int getOperator() const { return op; } 24 | Expression *getLHS() { return lhs; } 25 | Expression *getRHS() { return rhs; } 26 | 27 | private: 28 | int op{0}; 29 | Expression *lhs{nullptr}; 30 | Expression *rhs{nullptr}; 31 | }; 32 | 33 | } // namespace hana 34 | -------------------------------------------------------------------------------- /Hana/CodeGen/Assignment.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Ast/AstNode.h" 3 | 4 | namespace hana 5 | { 6 | 7 | /*! Represents an assigment. */ 8 | class Assignment : public Statement 9 | { 10 | public: 11 | explicit Assignment(Identifier *lhs, Expression *rhs, YYLTYPE loc) : lhs(lhs), rhs(rhs), location(loc) {} 12 | virtual ~Assignment() 13 | { 14 | delete lhs; 15 | delete rhs; 16 | } 17 | 18 | llvm::Value *codeGen(CodeGenContext &context) override; 19 | NodeType getType() override { return NodeType::expression; } 20 | std::string toString() override 21 | { 22 | std::stringstream s; 23 | s << "assignment for " << lhs->getStructName() << "::" << lhs->getName(); 24 | return s.str(); 25 | } 26 | void Accept(Visitor &v) override { v.VisitAssigment(this); } 27 | 28 | Expression *getExpression() { return rhs; } 29 | 30 | private: 31 | Identifier *lhs{nullptr}; 32 | Expression *rhs{nullptr}; 33 | YYLTYPE location; 34 | }; 35 | 36 | } // namespace hana 37 | -------------------------------------------------------------------------------- /Samples/fibo.hana: -------------------------------------------------------------------------------- 1 | --[[ Fibonacci Series using Hana --]] 2 | 3 | -- Using Recursion 4 | 5 | block recfibonacci(let n) : int 6 | if n <= 1 7 | return n 8 | else 9 | let f1 = recfibonacci(n - 1) 10 | let f2 = recfibonacci(n - 2) 11 | return f1 + f2 12 | 13 | block itrfibonacci(let n) : int 14 | if n == 0 15 | return n 16 | if n == 1 17 | return n 18 | int prevPrev = 0 19 | int prev = 1 20 | int currNumber 21 | 22 | int i = 1 23 | wloop i < n 24 | i = i + 1 25 | currNumber = prevPrev + prev 26 | prevPrev = prev 27 | prev = currNumber 28 | return currNumber 29 | 30 | 31 | writeln("[*] Fibonacci in Hana") 32 | write("-- Enter a Number: ") 33 | let num = readint() 34 | 35 | let itrres = itrfibonacci(num) 36 | let recres = recfibonacci(num) 37 | 38 | write("-- Recursive Fibonacci Result: ") 39 | writeint(itrres) 40 | 41 | write("-- Iterative Fibonacci Result: ") 42 | writeint(recres) -------------------------------------------------------------------------------- /Hana/CodeGen/Conditional.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Ast/AstNode.h" 3 | 4 | namespace hana 5 | { 6 | 7 | /*! Represents a conditional statement. */ 8 | class Conditional : public Statement 9 | { 10 | public: 11 | explicit Conditional(Expression *op, Expression *thenExpr, Expression *elseExpr = nullptr) : cmpOp((CompOperator *)op), thenExpr(thenExpr), elseExpr(elseExpr) 12 | { 13 | } 14 | virtual ~Conditional(); 15 | 16 | llvm::Value *codeGen(CodeGenContext &context) override; 17 | NodeType getType() override { return NodeType::expression; } 18 | std::string toString() override { return "conditional "; } 19 | void Accept(Visitor &v) override { v.VisitConditional(this); } 20 | 21 | CompOperator *getCompOperator() { return cmpOp; } 22 | Expression *getThen() { return thenExpr; } 23 | Expression *getElse() { return elseExpr; } 24 | 25 | private: 26 | CompOperator *cmpOp{nullptr}; 27 | Expression *thenExpr{nullptr}; 28 | Expression *elseExpr{nullptr}; 29 | }; 30 | 31 | } // namespace hana 32 | -------------------------------------------------------------------------------- /Hana/CodeGen/BinaryOperator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Ast/AstNode.h" 4 | 5 | namespace hana 6 | { 7 | /*! Represents a binary operators + - * / */ 8 | class BinaryOp : public Expression 9 | { 10 | public: 11 | BinaryOp(Expression *lhs, int op, Expression *rhs, YYLTYPE loc) : op(op), lhs(lhs), rhs(rhs), location(loc) {} 12 | virtual ~BinaryOp() 13 | { 14 | delete lhs; 15 | delete rhs; 16 | } 17 | 18 | llvm::Value *codeGen(CodeGenContext &context) override; 19 | NodeType getType() override { return NodeType::expression; } 20 | std::string toString() override; 21 | void Accept(Visitor &v) override { v.VisitBinaryOp(this); } 22 | 23 | Expression *getLHS() { return lhs; } 24 | Expression *getRHS() { return rhs; } 25 | int getOperator() const { return op; } 26 | 27 | private: 28 | llvm::Value *codeGenAddList(llvm::Value *rhsValue, llvm::Value *lhsValue, CodeGenContext &context); 29 | 30 | int op{0}; 31 | Expression *lhs{nullptr}; 32 | Expression *rhs{nullptr}; 33 | YYLTYPE location; 34 | }; 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Hana/CodeGen/WhileLoop.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Ast/AstNode.h" 3 | 4 | namespace hana 5 | { 6 | /*! Represents a while loop. */ 7 | class WhileLoop : public Statement 8 | { 9 | public: 10 | explicit WhileLoop(Expression *expr, Block *loopBlock, Block *elseBlock = nullptr) : condition(expr), loopBlock(loopBlock), elseBlock(elseBlock) {} 11 | virtual ~WhileLoop() 12 | { 13 | delete condition; 14 | delete loopBlock; 15 | delete elseBlock; 16 | } 17 | 18 | llvm::Value *codeGen(CodeGenContext &context) override; 19 | NodeType getType() override { return NodeType::expression; } 20 | std::string toString() override { return "while loop "; } 21 | void Accept(Visitor &v) override { v.VisitWhileLoop(this); } 22 | 23 | Expression *getCondition() { return condition; } 24 | Block *getLoopBlock() { return loopBlock; } 25 | Block *getElseBlock() { return elseBlock; } 26 | 27 | private: 28 | Expression *condition{nullptr}; 29 | Block *loopBlock{nullptr}; 30 | Block *elseBlock{nullptr}; 31 | }; 32 | 33 | } // namespace hana 34 | -------------------------------------------------------------------------------- /Hana/CodeGen/MethodCall.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Ast/AstNode.h" 3 | 4 | namespace hana 5 | { 6 | 7 | /*! Represents a method call. */ 8 | class MethodCall : public Statement 9 | { 10 | public: 11 | explicit MethodCall(Identifier *id, ExpressionList *arguments, YYLTYPE loc) : id(id), arguments(arguments), location(loc) {} 12 | virtual ~MethodCall() 13 | { 14 | for (auto i : *arguments) 15 | { 16 | delete i; 17 | } 18 | arguments->clear(); 19 | delete arguments; 20 | delete id; 21 | } 22 | 23 | llvm::Value *codeGen(CodeGenContext &context) override; 24 | NodeType getType() override { return NodeType::expression; } 25 | std::string toString() override 26 | { 27 | std::stringstream s; 28 | s << "method call: " << id->getStructName() << "." << id->getName(); 29 | return s.str(); 30 | } 31 | void Accept(Visitor &v) override { v.VisitMethodCall(this); } 32 | 33 | ExpressionList *getArguments() { return arguments; } 34 | 35 | private: 36 | std::string getTypeNameOfFirstArg(CodeGenContext &context); 37 | 38 | Identifier *id{nullptr}; 39 | ExpressionList *arguments{nullptr}; 40 | YYLTYPE location; 41 | }; 42 | 43 | } // namespace hana 44 | -------------------------------------------------------------------------------- /Hana/CodeGen/ClassDeclaration.h: -------------------------------------------------------------------------------- 1 | #ifndef ClassDeclaration_h__ 2 | #define ClassDeclaration_h__ 3 | 4 | #include 5 | #include 6 | 7 | #include "Ast/AstNode.h" 8 | 9 | namespace hana 10 | { 11 | 12 | class ClassDeclaration : public Statement 13 | { 14 | public: 15 | explicit ClassDeclaration(Identifier *id, Block *block) : id(id), block(block) {} 16 | virtual ~ClassDeclaration() 17 | { 18 | delete id; 19 | delete block; 20 | } 21 | llvm::Value *codeGen(CodeGenContext &context) override; 22 | NodeType getType() override { return NodeType::klass; } 23 | std::string toString() override 24 | { 25 | std::stringstream s; 26 | s << "Class: " << id->getName(); 27 | return s.str(); 28 | } 29 | void Accept(Visitor &v) override { v.VisitClassDeclaration(this); } 30 | Block *getBlock() { return block; } 31 | Identifier *getIdentifier() { return id; } 32 | 33 | private: 34 | void removeVarDeclStatements(); 35 | void constructStructFields(std::vector &StructTy_fields, CodeGenContext &context); 36 | void addVarsToClassAttributes(CodeGenContext &context); 37 | 38 | Identifier *id{nullptr}; 39 | Block *block{nullptr}; 40 | }; 41 | 42 | } 43 | #endif // ClassDeclaration_h__ 44 | -------------------------------------------------------------------------------- /Hana/CodeGen/UnaryOperator.cpp: -------------------------------------------------------------------------------- 1 | #include "UnaryOperator.h" 2 | #include "CodeGenContext.h" 3 | #include "parser.hpp" 4 | 5 | using namespace std; 6 | using namespace llvm; 7 | 8 | namespace hana 9 | { 10 | 11 | Value *UnaryOperator::codeGen(CodeGenContext &context) 12 | { 13 | Instruction::BinaryOps instr; 14 | switch (op) 15 | { 16 | case TNOT: 17 | instr = Instruction::Xor; 18 | break; 19 | default: // TODO user defined operator 20 | Node::printError("Unknown uni operator."); 21 | context.addError(); 22 | return nullptr; 23 | } 24 | 25 | Value *rhsValue = rhs->codeGen(context); 26 | if (!rhsValue->getType()->isIntegerTy()) 27 | { 28 | Node::printError("Right hand side of uni operator must be an integer type."); 29 | context.addError(); 30 | return nullptr; 31 | } 32 | Value *lhsValue = ConstantInt::get(IntegerType::get(context.getGlobalContext(), context.getGenericIntegerType()->getIntegerBitWidth()), StringRef("-1"), 10); 33 | return BinaryOperator::Create(instr, lhsValue, rhsValue, "unarytmp", context.currentBlock()); 34 | } 35 | 36 | std::string UnaryOperator::toString() 37 | { 38 | std::stringstream s; 39 | s << "unary operation "; 40 | switch (op) 41 | { 42 | case TNOT: 43 | s << "not"; 44 | break; 45 | default: // TODO user defined operator 46 | s << "unknown"; 47 | } 48 | return s.str(); 49 | } 50 | 51 | } // namespace hana 52 | -------------------------------------------------------------------------------- /Hana/Lib/Stlib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(_MSC_VER) 4 | #define DECLSPEC __declspec(dllexport) 5 | #else 6 | #define DECLSPEC 7 | #endif 8 | 9 | /* 10 | *! Some Stl functions for Hana 11 | */ 12 | 13 | /** 14 | * TODO ... 15 | * 16 | */ 17 | // extern "C" DECLSPEC int read(char* fmt, ...); -> Not Working! 18 | 19 | /*! Calculates a sinus. 20 | */ 21 | extern "C" DECLSPEC double sinus(double val); 22 | 23 | extern "C" DECLSPEC int compstr(char *str1, char *str2); 24 | 25 | extern "C" DECLSPEC char *read(); 26 | 27 | extern "C" DECLSPEC int readint(); 28 | 29 | extern "C" DECLSPEC double readflt(); 30 | 31 | // extern "C" DECLSPEC int 32 | /*! Prints an integer value. 33 | * \param[in] val Integer value to be printed. 34 | * \return Always one FIXME 35 | */ 36 | extern "C" DECLSPEC int writeint(int val); 37 | 38 | /*! Prints a double value. 39 | * \param[in] val Double value to be printed. 40 | * \return Always one FIXME 41 | */ 42 | extern "C" DECLSPEC double writeflt(double val); 43 | 44 | /*! Built in write function 45 | * it works like the C printf function and uses the same format string definition. 46 | * \param[in] str The format string. 47 | */ 48 | extern "C" DECLSPEC void write(char *str, ...); 49 | 50 | /*! Prints formated string like printf but with a CR/'New line' 51 | * \param[in] str The format string. 52 | */ 53 | extern "C" DECLSPEC void writeln(char *str, ...); 54 | -------------------------------------------------------------------------------- /Samples/calc.hana: -------------------------------------------------------------------------------- 1 | --[[ Calculator program for Hana --]] 2 | 3 | block info() 4 | writeln("[*] Simple Calculator in Hana") 5 | writeln("-- Please select an option:") 6 | writeln("-- 1 : Addition") 7 | writeln("-- 2 : Subtract") 8 | writeln("-- 3 : Multiply") 9 | writeln("-- 4 : Division") 10 | writeln("-- 5 : Sine") 11 | return 12 | 13 | block Add(double x, double y) 14 | double sum = x + y 15 | write("%s", "Output: ") 16 | writeflt(sum) 17 | return 18 | 19 | block Sub(double x, double y) 20 | double sub = x - y 21 | write("%s", "Output: ") 22 | writeflt(sub) 23 | return 24 | 25 | block Mul(double x, double y) 26 | double mul = x * y 27 | write("%s", "Output: ") 28 | writeflt(mul) 29 | return 30 | 31 | block Div(int x, int y) 32 | let div = x/y 33 | writeln("Output: %d", div) 34 | return 35 | 36 | block Sin(double x) 37 | double sine = sinus(x) 38 | write("%s", "Output: ") 39 | writeflt(sine) 40 | return 41 | 42 | block calculator() 43 | info() 44 | let opt = readint() 45 | if opt==1 46 | Add(readflt(),readflt()) 47 | if opt==2 48 | Sub(readflt(),readflt()) 49 | if opt==3 50 | Mul(readflt(),readflt()) 51 | if opt==4 52 | Div(readint(),readint()) 53 | if opt==5 54 | Sin(readflt()) 55 | return 56 | 57 | calculator() -------------------------------------------------------------------------------- /Hana/CodeGen/FunctionDeclaration.h: -------------------------------------------------------------------------------- 1 | #ifndef FUNCTION_DECLARATION_H 2 | #define FUNCTION_DECLARATION_H 3 | 4 | #include "Ast/AstNode.h" 5 | 6 | namespace hana 7 | { 8 | 9 | class FunctionDeclaration : public Statement 10 | { 11 | public: 12 | FunctionDeclaration(const FunctionDeclaration &other); 13 | FunctionDeclaration(Identifier *type, Identifier *id, VariableList *arguments, Block *block, YYLTYPE loc); 14 | FunctionDeclaration(Identifier *id, VariableList *arguments, Block *block, YYLTYPE loc); 15 | virtual ~FunctionDeclaration(); 16 | 17 | llvm::Value *codeGen(CodeGenContext &context) override; 18 | NodeType getType() override { return NodeType::function; } 19 | std::string toString() override; 20 | void Accept(Visitor &v) override { v.VisitFunctionDeclaration(this); } 21 | Identifier *getId() const { return id; } 22 | VariableList *getParameter() const { return arguments; } 23 | Block *getBody() const { return block; } 24 | Identifier *getRetType() const { return type; } 25 | bool isTemplated() const { return hasTemplateParameter; } 26 | YYLTYPE getlocation() { return location; } 27 | 28 | private: 29 | void checkForTemplateParameter(); 30 | std::string buildFunctionName(llvm::Type *retType, std::vector argTypes); 31 | friend class ClassDeclaration; 32 | Identifier *type{nullptr}; 33 | Identifier *id{nullptr}; 34 | VariableList *arguments{nullptr}; 35 | Block *block{nullptr}; 36 | bool hasTemplateParameter{false}; 37 | bool isaCopy{false}; 38 | YYLTYPE location; 39 | }; 40 | 41 | } // namespace hana 42 | #endif // FUNCTION_DECLARATION_H 43 | -------------------------------------------------------------------------------- /Hana/Visitor/VisitorPrettyPrint.h: -------------------------------------------------------------------------------- 1 | #ifndef VisitorPrettyPrint_h__ 2 | #define VisitorPrettyPrint_h__ 3 | #include 4 | #include 5 | 6 | #include "Visitor.h" 7 | 8 | namespace hana 9 | { 10 | 11 | class VisitorPrettyPrint : public Visitor 12 | { 13 | int indent{0}; 14 | std::ostream &out; 15 | 16 | public: 17 | VisitorPrettyPrint(std::ostream &outs) : out(outs) {} 18 | virtual ~VisitorPrettyPrint() {} 19 | void VisitExpression(Expression *expr); 20 | void VisitInteger(Integer *expr); 21 | void VisitDouble(Double *expr); 22 | void VisitString(String *expr); 23 | void VisitBoolean(Boolean *expr); 24 | void VisitIdentifier(Identifier *expr); 25 | void VisitUnaryOperator(UnaryOperator *expr); 26 | void VisitBinaryOp(BinaryOp *expr); 27 | void VisitCompOperator(CompOperator *expr); 28 | void VisitBlock(Block *expr); 29 | void VisitStatement(Statement *stmt); 30 | void VisitReturnStatement(Return *retstmt); 31 | void VisitFunctionDeclaration(FunctionDeclaration *fndecl); 32 | void VisitExpressionStatement(ExpressionStatement *expr); 33 | void VisitAssigment(Assignment *expr); 34 | void VisitMethodCall(MethodCall *expr); 35 | void VisitVariablenDeclaration(VariableDeclaration *expr); 36 | void VisitConditional(Conditional *expr); 37 | void VisitWhileLoop(WhileLoop *expr); 38 | void VisitClassDeclaration(ClassDeclaration *expr); 39 | void VisitArray(Array *expr); 40 | void VisitArrayAccess(ArrayAccess *expr); 41 | void VisitArrayAddElement(ArrayAddElement *expr); 42 | void VisitRange(Range *expr); 43 | }; 44 | 45 | } 46 | #endif // VisitorPrettyPrint_h__ 47 | -------------------------------------------------------------------------------- /Hana/Visitor/VisitorSyntaxCheck.h: -------------------------------------------------------------------------------- 1 | #ifndef VisitorSyntaxCheck_h__ 2 | #define VisitorSyntaxCheck_h__ 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Visitor.h" 8 | struct YYLTYPE; 9 | 10 | namespace hana 11 | { 12 | 13 | class VisitorSyntaxCheck : public Visitor 14 | { 15 | int syntaxErrors{0}; 16 | std::vector ReturnStatementLocations; 17 | std::unordered_set TypeNames{"int", "double", "string", "boolean", "var"}; 18 | 19 | public: 20 | VisitorSyntaxCheck() = default; 21 | virtual ~VisitorSyntaxCheck() = default; 22 | void VisitExpression(Expression *expr); 23 | void VisitInteger(Integer *expr); 24 | void VisitDouble(Double *expr); 25 | void VisitString(String *expr); 26 | void VisitBoolean(Boolean *expr); 27 | void VisitIdentifier(Identifier *expr); 28 | void VisitUnaryOperator(UnaryOperator *expr); 29 | void VisitBinaryOp(BinaryOp *expr); 30 | void VisitCompOperator(CompOperator *expr); 31 | void VisitBlock(Block *expr); 32 | void VisitStatement(Statement *stmt); 33 | void VisitReturnStatement(Return *retstmt); 34 | void VisitFunctionDeclaration(FunctionDeclaration *fndecl); 35 | void VisitExpressionStatement(ExpressionStatement *expr); 36 | void VisitAssigment(Assignment *expr); 37 | void VisitMethodCall(MethodCall *expr); 38 | void VisitVariablenDeclaration(VariableDeclaration *expr); 39 | void VisitConditional(Conditional *expr); 40 | void VisitWhileLoop(WhileLoop *expr); 41 | void VisitClassDeclaration(ClassDeclaration *expr); 42 | void VisitArray(Array *expr); 43 | void VisitArrayAccess(ArrayAccess *expr); 44 | void VisitArrayAddElement(ArrayAddElement *expr); 45 | void VisitRange(Range *expr); 46 | 47 | bool hasErrors() { return syntaxErrors != 0; } 48 | }; 49 | 50 | } 51 | #endif // VisitorSyntaxCheck_h__ 52 | -------------------------------------------------------------------------------- /Hana/CodeGen/Range.cpp: -------------------------------------------------------------------------------- 1 | #include "Range.h" 2 | #include "Assignment.h" 3 | #include "Declaration.h" 4 | #include "Array.h" 5 | #include "BinaryOperator.h" 6 | #include "CompareOperator.h" 7 | #include "WhileLoop.h" 8 | #include "CodeGenContext.h" 9 | #include "parser.hpp" 10 | 11 | using namespace std; 12 | using namespace llvm; 13 | 14 | namespace hana 15 | { 16 | 17 | llvm::Value *Range::codeGen(CodeGenContext &context) 18 | { 19 | // var l = [lhs] 20 | // var n = lhs 21 | // while n < end 22 | // n += 1 23 | // l << n 24 | // return l 25 | 26 | YYLTYPE loc = {0, 0, 0, 0}; 27 | Block tmp_code; 28 | auto rc = context.findVariable("tmp_l"); 29 | if (rc) 30 | { 31 | context.deleteVariable("tmp_l"); 32 | } 33 | rc = context.findVariable("tmp_n"); 34 | if (rc) 35 | { 36 | context.deleteVariable("tmp_n"); 37 | } 38 | // var l = [lhs] 39 | ExpressionList exprs; 40 | exprs.push_back(begin); 41 | auto l = new Array(&exprs, loc); 42 | auto vardecl = new VariableDeclaration(new Identifier("tmp_l", loc), l, loc); 43 | tmp_code.statements.push_back(vardecl); 44 | // var n = lhs 45 | auto vardecl_n = new VariableDeclaration(new Identifier("tmp_n", loc), this->begin, loc); 46 | tmp_code.statements.push_back(vardecl_n); 47 | // while loop 48 | auto while_block = new Block(); 49 | auto assgn = new Assignment(new Identifier("tmp_n", loc), new BinaryOp(new Identifier("tmp_n", loc), TPLUS, new Integer(1), loc), loc); 50 | auto l_plus_n = new ArrayAddElement(new Identifier("tmp_l", loc), new Identifier("tmp_n", loc), loc); 51 | while_block->statements.push_back(assgn); 52 | while_block->statements.push_back(l_plus_n); 53 | auto cond = new CompOperator(new Identifier("tmp_n", loc), TCLE, this->end); 54 | auto wl = new WhileLoop(cond, while_block); 55 | tmp_code.statements.push_back(wl); 56 | tmp_code.codeGen(context); 57 | #if !defined(LLVM_NO_DUMP) 58 | context.getModule()->dump(); 59 | #endif 60 | rc = context.findVariable("tmp_l"); 61 | return rc; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /Hana/CodeGen/Declaration.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Ast/AstNode.h" 3 | 4 | namespace hana 5 | { 6 | 7 | /*! Represents a variable declaration. */ 8 | class VariableDeclaration : public Statement 9 | { 10 | public: 11 | VariableDeclaration(Identifier *type, Identifier *id, YYLTYPE loc) : type(type), id(id), assignmentExpr(nullptr), location(loc) {} 12 | VariableDeclaration(Identifier *type, Identifier *id, Expression *assignmentExpr, YYLTYPE loc) 13 | : type(type), id(id), assignmentExpr(assignmentExpr), location(loc) 14 | { 15 | } 16 | VariableDeclaration(Identifier *id, YYLTYPE loc) 17 | : type(new Identifier("var", loc)), id(id), assignmentExpr(nullptr), location(loc) 18 | { 19 | } 20 | VariableDeclaration(Identifier *id, Expression *assignmentExpr, YYLTYPE loc) 21 | : type(new Identifier("var", loc)), id(id), assignmentExpr(assignmentExpr), location(loc) 22 | { 23 | } 24 | virtual ~VariableDeclaration() 25 | { 26 | delete assignmentExpr; 27 | delete id; 28 | delete type; 29 | } 30 | 31 | llvm::Value *codeGen(CodeGenContext &context) override; 32 | NodeType getType() override { return NodeType::variable; } 33 | virtual std::string toString() override 34 | { 35 | std::stringstream s; 36 | s << "Variable declaration for " << id->getName() << " of type " << (type ? type->getName() : "TBD"); 37 | return s.str(); 38 | } 39 | void Accept(Visitor &v) override { v.VisitVariablenDeclaration(this); } 40 | 41 | const Identifier &getIdentifierOfVariable() const { return *id; } 42 | virtual const Identifier &getIdentifierOfVariablenType() const { return *type; } 43 | virtual std::string getVariablenTypeName() const { return type->getName(); } 44 | std::string getVariablenName() const { return id->getName(); } 45 | bool hasAssignmentExpr() const { return assignmentExpr != nullptr; } 46 | Expression *getAssignment() const { return assignmentExpr; } 47 | YYLTYPE &getLocation() { return location; } 48 | 49 | protected: 50 | Identifier *type{nullptr}; 51 | Identifier *id{nullptr}; 52 | Expression *assignmentExpr{nullptr}; 53 | YYLTYPE location; 54 | }; 55 | 56 | } // namespace hana 57 | -------------------------------------------------------------------------------- /Hana/Visitor/Visitor.h: -------------------------------------------------------------------------------- 1 | #ifndef Visitor_h__ 2 | #define Visitor_h__ 3 | 4 | namespace hana 5 | { 6 | class Expression; 7 | class Statement; 8 | class Return; 9 | class FunctionDeclaration; 10 | class Conditional; 11 | class Integer; 12 | class Double; 13 | class String; 14 | class Boolean; 15 | class Identifier; 16 | class UnaryOperator; 17 | class BinaryOp; 18 | class CompOperator; 19 | class Block; 20 | class ExpressionStatement; 21 | class Assignment; 22 | class MethodCall; 23 | class VariableDeclaration; 24 | class Conditional; 25 | class WhileLoop; 26 | class ClassDeclaration; 27 | class Array; 28 | class ArrayAccess; 29 | class ArrayAddElement; 30 | class Range; 31 | 32 | class Visitor 33 | { 34 | public: 35 | virtual void VisitExpression(Expression *expr) = 0; 36 | virtual void VisitInteger(Integer *expr) = 0; 37 | virtual void VisitDouble(Double *expr) = 0; 38 | virtual void VisitString(String *expr) = 0; 39 | virtual void VisitBoolean(Boolean *expr) = 0; 40 | virtual void VisitIdentifier(Identifier *expr) = 0; 41 | virtual void VisitUnaryOperator(UnaryOperator *expr) = 0; 42 | virtual void VisitBinaryOp(BinaryOp *expr) = 0; 43 | virtual void VisitCompOperator(CompOperator *expr) = 0; 44 | virtual void VisitBlock(Block *expr) = 0; 45 | virtual void VisitStatement(Statement *stmt) = 0; 46 | virtual void VisitReturnStatement(Return *retstmt) = 0; 47 | virtual void VisitFunctionDeclaration(FunctionDeclaration *fndecl) = 0; 48 | virtual void VisitExpressionStatement(ExpressionStatement *expr) = 0; 49 | virtual void VisitAssigment(Assignment *expr) = 0; 50 | virtual void VisitMethodCall(MethodCall *expr) = 0; 51 | virtual void VisitVariablenDeclaration(VariableDeclaration *expr) = 0; 52 | virtual void VisitConditional(Conditional *expr) = 0; 53 | virtual void VisitWhileLoop(WhileLoop *expr) = 0; 54 | virtual void VisitClassDeclaration(ClassDeclaration *expr) = 0; 55 | virtual void VisitArray(Array *expr) = 0; 56 | virtual void VisitArrayAccess(ArrayAccess *expr) = 0; 57 | virtual void VisitArrayAddElement(ArrayAddElement *expr) = 0; 58 | virtual void VisitRange(Range *expr) = 0; 59 | }; 60 | 61 | } 62 | #endif // Visitor_h__ 63 | -------------------------------------------------------------------------------- /Hana/Lib/Stlib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "Stlib.h" 14 | 15 | char *copycs(const char *arr, long n) 16 | { 17 | char *heap_arr = (char *)malloc(sizeof(char) * n); 18 | memcpy(heap_arr, arr, n * sizeof(char)); 19 | return heap_arr; 20 | } 21 | 22 | extern "C" DECLSPEC char *read() 23 | { 24 | std::string strtmp; 25 | std::getline(std::cin, strtmp); 26 | char *tmp = copycs(strtmp.c_str(), (int)strtmp.size() + 1); 27 | return tmp; 28 | } 29 | 30 | extern "C" DECLSPEC int readint() 31 | { 32 | std::string strtmp; 33 | std::getline(std::cin, strtmp); 34 | char *tmp = copycs(strtmp.c_str(), (int)strtmp.size() + 1); 35 | int val = std::atoi(tmp); 36 | return val; 37 | } 38 | 39 | extern "C" DECLSPEC double readflt() 40 | { 41 | std::string strtmp; 42 | std::getline(std::cin, strtmp); 43 | char *tmp = copycs(strtmp.c_str(), (int)strtmp.size() + 1); 44 | char *stopString; 45 | double val = std::strtod(tmp, &stopString); 46 | // Implement something to print Error if it has string ... 47 | return val; 48 | } 49 | 50 | // For comparing two Strings 51 | extern "C" DECLSPEC int compstr(char *str1, char *str2) 52 | { 53 | if (!std::strcmp(str1, str2)) 54 | return 1; 55 | return 0; 56 | } 57 | 58 | extern "C" DECLSPEC int writeint(int val) 59 | { 60 | std::cout << val << "\n"; 61 | return 1; 62 | } 63 | 64 | extern "C" DECLSPEC double writeflt(double val) 65 | { 66 | std::cout << val << "\n"; 67 | return 1.; 68 | } 69 | 70 | extern "C" DECLSPEC void write(char *str, ...) 71 | { 72 | va_list argp; 73 | va_start(argp, str); 74 | vprintf(str, argp); 75 | va_end(argp); 76 | } 77 | 78 | extern "C" DECLSPEC void writeln(char *str, ...) 79 | { 80 | char *outstr; 81 | va_list argp; 82 | va_start(argp, str); 83 | outstr = (char *)malloc(strlen(str) + 2); 84 | strcpy(outstr, str); 85 | strcat(outstr, "\n"); 86 | vprintf(outstr, argp); 87 | va_end(argp); 88 | free(outstr); 89 | } 90 | 91 | extern "C" DECLSPEC double sinus(double val) 92 | { 93 | return std::sin(val); 94 | } 95 | -------------------------------------------------------------------------------- /Hana/CodeGen/Conditional.cpp: -------------------------------------------------------------------------------- 1 | #include "Conditional.h" 2 | #include "CompareOperator.h" 3 | #include "CodeGenContext.h" 4 | #include "parser.hpp" 5 | 6 | using namespace std; 7 | using namespace llvm; 8 | 9 | namespace hana 10 | { 11 | 12 | Conditional::~Conditional() 13 | { 14 | delete cmpOp; 15 | delete thenExpr; 16 | delete elseExpr; 17 | } 18 | 19 | Value *Conditional::codeGen(CodeGenContext &context) 20 | { 21 | Value *comp = cmpOp->codeGen(context); 22 | if (comp == nullptr) 23 | { 24 | Node::printError("** [Err] Code generation for compare operator of the conditional statement failed."); 25 | context.addError(); 26 | return nullptr; 27 | } 28 | if (!comp->getType()->isIntegerTy(1)) 29 | { 30 | Node::printError("** [Err] If condition doesn't result in a boolean expression."); 31 | context.addError(); 32 | return nullptr; 33 | } 34 | 35 | Function *function = context.currentBlock()->getParent(); 36 | BasicBlock *thenBlock = BasicBlock::Create(context.getGlobalContext(), "then", function); 37 | BasicBlock *elseBlock = BasicBlock::Create(context.getGlobalContext(), "else"); 38 | BasicBlock *mergeBlock = BasicBlock::Create(context.getGlobalContext(), "merge"); 39 | BranchInst::Create(thenBlock, elseBlock, comp, context.currentBlock()); 40 | 41 | bool needMergeBlock = false; 42 | 43 | context.newScope(thenBlock, ScopeType::CodeBlock); 44 | Value *thenValue = thenExpr->codeGen(context); 45 | if (thenValue == nullptr) 46 | { 47 | Node::printError("Missing else block of the conditional statement."); 48 | context.addError(); 49 | return nullptr; 50 | } 51 | if (context.currentBlock()->getTerminator() == nullptr) 52 | { 53 | BranchInst::Create(mergeBlock, context.currentBlock()); 54 | needMergeBlock = true; 55 | } 56 | 57 | function->getBasicBlockList().push_back(elseBlock); 58 | context.endScope(); 59 | 60 | context.newScope(elseBlock); 61 | Value *elseValue = nullptr; 62 | if (elseExpr != nullptr) 63 | { 64 | elseValue = elseExpr->codeGen(context); 65 | } 66 | 67 | if (context.currentBlock()->getTerminator() == nullptr) 68 | { 69 | BranchInst::Create(mergeBlock, context.currentBlock()); 70 | needMergeBlock = true; 71 | } 72 | context.endScope(); 73 | if (needMergeBlock) 74 | { 75 | function->getBasicBlockList().push_back(mergeBlock); 76 | context.setInsertPoint(mergeBlock); 77 | } 78 | 79 | return mergeBlock; // dummy return, for now 80 | } 81 | 82 | } // namespace hana 83 | -------------------------------------------------------------------------------- /Hana/CodeGen/Array.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Ast/AstNode.h" 4 | 5 | namespace hana 6 | { 7 | /*! Represents an array */ 8 | class Array : public Expression 9 | { 10 | public: 11 | Array(YYLTYPE loc) : location(loc) {} 12 | Array(ExpressionList *exprs, YYLTYPE loc) : exprList(exprs), location(loc) {} 13 | virtual ~Array() = default; 14 | 15 | llvm::Value *codeGen(CodeGenContext &context) override; 16 | NodeType getType() override { return NodeType::list; } 17 | std::string toString() override { return "array"; } 18 | void Accept(Visitor &v) override { v.VisitArray(this); } 19 | 20 | YYLTYPE getLocation() const { return location; } 21 | ExpressionList *getExpressions() const { return exprList; } 22 | 23 | private: 24 | ExpressionList *exprList = nullptr; 25 | YYLTYPE location; 26 | }; 27 | 28 | /*! Represents an array element access */ 29 | class ArrayAccess : public Expression 30 | { 31 | public: 32 | ArrayAccess(Identifier *id, long long index, YYLTYPE loc) : variable(id), index(index), location(loc) {} 33 | ArrayAccess(Expression *id, long long index, YYLTYPE loc) : other(id), index(index), location(loc) {} 34 | virtual ~ArrayAccess() = default; 35 | 36 | llvm::Value *codeGen(CodeGenContext &context) override; 37 | NodeType getType() override { return NodeType::list; } 38 | std::string toString() override { return "array-element-access"; } 39 | void Accept(Visitor &v) override { v.VisitArrayAccess(this); } 40 | 41 | YYLTYPE getLocation() const { return location; } 42 | 43 | private: 44 | Identifier *variable{nullptr}; 45 | long long index{0}; 46 | YYLTYPE location; 47 | Expression *other{nullptr}; 48 | friend class VisitorSyntaxCheck; 49 | friend class VisitorPrettyPrint; 50 | }; 51 | 52 | /*! Represents adding an element to the array. */ 53 | class ArrayAddElement : public Statement 54 | { 55 | public: 56 | ArrayAddElement(Identifier *ident, Expression *expr, YYLTYPE loc) : ident(ident), expr(expr), location(loc) {} 57 | virtual ~ArrayAddElement() = default; 58 | 59 | llvm::Value *codeGen(CodeGenContext &context) override; 60 | NodeType getType() override { return NodeType::list; } 61 | std::string toString() override { return "list add element"; } 62 | void Accept(Visitor &v) override { v.VisitArrayAddElement(this); } 63 | 64 | YYLTYPE getLocation() const { return location; } 65 | Expression *getExpression() const { return expr; } 66 | 67 | private: 68 | Expression *expr{nullptr}; 69 | Identifier *ident{nullptr}; 70 | YYLTYPE location; 71 | friend class VisitorSyntaxCheck; 72 | friend class VisitorPrettyPrint; 73 | }; 74 | 75 | } // namespace hana 76 | -------------------------------------------------------------------------------- /Hana/Utils/GetOpt.h: -------------------------------------------------------------------------------- 1 | /* GetOpt - getopt as a c++ class. 2 | * 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 Klaus Beyer 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | #if !defined(GETOPT_H) 25 | #define GETOPT_H 26 | 27 | #include 28 | #include 29 | 30 | class GetOpt 31 | { 32 | public: 33 | GetOpt(int argc, char *argv[], const std::string optstring, const std::string filename = ""); 34 | std::string get() { return optionArgument; } 35 | std::string error() { return errorText; } 36 | size_t getIndex() { return index; } 37 | void reset() { index = 1; }; 38 | char operator()(); 39 | std::vector getRemainingArguments(); 40 | 41 | class iterator 42 | { 43 | public: 44 | iterator(GetOpt *getopt) : getopt(getopt), position(1u){}; 45 | iterator(int pos) : position(pos){}; 46 | iterator &operator++() 47 | { 48 | ++position; 49 | return *this; 50 | } // prefix 51 | bool operator!=(iterator rhs) 52 | { 53 | return position != rhs.getopt->argCount; 54 | } 55 | char operator*(); 56 | 57 | private: 58 | size_t position{0}; 59 | GetOpt *getopt{nullptr}; 60 | }; 61 | iterator begin() { return iterator(this); } 62 | iterator end() { return iterator(this); } 63 | friend class iterator; 64 | 65 | private: 66 | std::string optionArgument; /* Global argument pointer. */ 67 | size_t index{0}; /* Global argv index. */ 68 | size_t argCount{0}; 69 | std::string optionString; 70 | std::string errorText; 71 | std::vector argStrings; 72 | }; 73 | 74 | #endif /* GETOPT_H */ 75 | -------------------------------------------------------------------------------- /Hana/CodeGen/WhileLoop.cpp: -------------------------------------------------------------------------------- 1 | #include "WhileLoop.h" 2 | #include "CodeGenContext.h" 3 | #include "parser.hpp" 4 | 5 | using namespace std; 6 | using namespace llvm; 7 | 8 | namespace hana 9 | { 10 | 11 | Value *WhileLoop::codeGen(CodeGenContext &context) 12 | { 13 | Function *function = context.currentBlock()->getParent(); 14 | BasicBlock *firstCondBlock = BasicBlock::Create(context.getGlobalContext(), "firstcond", function); 15 | BasicBlock *condBB = BasicBlock::Create(context.getGlobalContext(), "cond"); 16 | BasicBlock *loopBB = BasicBlock::Create(context.getGlobalContext(), "loop"); 17 | BasicBlock *elseBB = BasicBlock::Create(context.getGlobalContext(), "else"); 18 | BasicBlock *mergeBB = BasicBlock::Create(context.getGlobalContext(), "merge"); 19 | BranchInst::Create(firstCondBlock, context.currentBlock()); 20 | context.newScope(firstCondBlock); 21 | Value *firstCondValue = this->condition->codeGen(context); 22 | if (firstCondValue == nullptr) 23 | { 24 | Node::printError("Missing condition in while loop."); 25 | context.addError(); 26 | return nullptr; 27 | } 28 | if (!firstCondValue->getType()->isIntegerTy(1)) 29 | { 30 | Node::printError("While condition doesn't result in a boolean expression."); 31 | context.addError(); 32 | return nullptr; 33 | } 34 | BranchInst::Create(loopBB, elseBB, firstCondValue, context.currentBlock()); 35 | 36 | function->getBasicBlockList().push_back(condBB); 37 | context.endScope(); 38 | context.newScope(condBB); 39 | Value *condValue = this->condition->codeGen(context); 40 | if (condValue == nullptr) 41 | { 42 | Node::printError("Code gen for condition expression in while loop failed."); 43 | context.addError(); 44 | return nullptr; 45 | } 46 | BranchInst::Create(loopBB, mergeBB, condValue, context.currentBlock()); 47 | 48 | function->getBasicBlockList().push_back(loopBB); 49 | context.endScope(); 50 | context.newScope(loopBB); 51 | Value *loopValue = this->loopBlock->codeGen(context); 52 | if (loopValue == nullptr) 53 | { 54 | Node::printError("Code gen for loop value in while loop failed."); 55 | context.addError(); 56 | return nullptr; 57 | } 58 | BranchInst::Create(condBB, context.currentBlock()); 59 | 60 | function->getBasicBlockList().push_back(elseBB); 61 | context.endScope(); 62 | context.newScope(elseBB); 63 | if (this->elseBlock != nullptr) 64 | { 65 | Value *elseValue = this->elseBlock->codeGen(context); 66 | if (elseValue == nullptr) 67 | { 68 | Node::printError("Code gen for else block in while loop failed."); 69 | context.addError(); 70 | return nullptr; 71 | } 72 | } 73 | BranchInst::Create(mergeBB, context.currentBlock()); 74 | function->getBasicBlockList().push_back(mergeBB); 75 | context.endScope(); 76 | context.setInsertPoint(mergeBB); 77 | return mergeBB; 78 | } 79 | 80 | } // namespace hana 81 | -------------------------------------------------------------------------------- /Hana/CodeGen/Declaration.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if defined(_MSC_VER) 4 | #pragma warning(push, 0) 5 | #endif 6 | #include "llvm/Transforms/Utils/Cloning.h" 7 | #if defined(_MSC_VER) 8 | #pragma warning(pop) 9 | #endif 10 | 11 | #include "Declaration.h" 12 | #include "Assignment.h" 13 | #include "CodeGenContext.h" 14 | #include "parser.hpp" 15 | 16 | using namespace std; 17 | using namespace llvm; 18 | 19 | namespace hana 20 | { 21 | 22 | Value *VariableDeclaration::codeGen(CodeGenContext &context) 23 | { 24 | Value *val = nullptr; 25 | if (context.findVariable(id->getName())) 26 | { 27 | Node::printError(location, " Variable '" + id->getName() + "' already exists!\n"); 28 | context.addError(); 29 | return nullptr; 30 | } 31 | 32 | Type *ty = context.typeOf(*type); 33 | if (ty->isStructTy() && ty->getStructName() == "var") 34 | { 35 | // It is a var declaration, postpone type until assignment. 36 | context.locals()[id->getName()] = nullptr; 37 | } 38 | else if (ty->isStructTy() && context.getScopeType() != ScopeType::FunctionDeclaration) 39 | { 40 | // It is really a declaration of a class type which we put always onto the heap. 41 | AllocaInst *alloc = new AllocaInst(ty, 0, id->getName().c_str(), context.currentBlock()); 42 | context.locals()[id->getName()] = alloc; 43 | val = alloc; 44 | context.varStruct = val; // Indicates that a variable of a class is declared 45 | } 46 | else 47 | { 48 | if (ty->isStructTy()) 49 | { 50 | // It is a declaration of a class type in a function declaration as a formal parameter. 51 | // Therefor a pointer reference is needed. 52 | ty = PointerType::get(ty, 0); 53 | } 54 | AllocaInst *alloc = new AllocaInst(ty, 0, id->getName().c_str(), context.currentBlock()); 55 | context.locals()[id->getName()] = alloc; 56 | val = alloc; 57 | } 58 | context.setVarType(type->getName(), id->getName()); 59 | 60 | if (assignmentExpr != nullptr) 61 | { 62 | Assignment assn(id, assignmentExpr, location); 63 | assn.codeGen(context); 64 | // they are already deleted by assn. 65 | id = nullptr; 66 | assignmentExpr = nullptr; 67 | } 68 | else if (context.varStruct) 69 | { 70 | // The variable gets nothing assigned so 71 | // auto assign defaults (member assignments) on classes ctor call. 72 | auto stmts = context.getKlassInitCode(type->getName()); 73 | for (auto assign : stmts) 74 | { 75 | assign->codeGen(context); 76 | } 77 | 78 | // Generate function call to the ctor, if exists. 79 | Function *fn = context.getModule()->getFunction("__init__%" + type->getName()); 80 | if (fn != nullptr) 81 | { 82 | std::vector args; 83 | args.push_back(context.varStruct); 84 | (void)CallInst::Create(fn, args, "", context.currentBlock()); 85 | } 86 | context.varStruct = nullptr; 87 | } 88 | return val; 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /Hana/Ast/AstNode.cpp: -------------------------------------------------------------------------------- 1 | #include "AstNode.h" 2 | #include "CodeGen/CodeGenContext.h" 3 | #include "parser.hpp" 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | using namespace llvm; 9 | 10 | namespace hana 11 | { 12 | Value *Integer::codeGen(CodeGenContext &context) 13 | { 14 | return ConstantInt::get(context.getGenericIntegerType(), value, true); 15 | } 16 | 17 | Value *Double::codeGen(CodeGenContext &context) 18 | { 19 | return ConstantFP::get(Type::getDoubleTy(context.getGlobalContext()), value); 20 | } 21 | 22 | Value *String::codeGen(CodeGenContext &context) 23 | { 24 | // generate the type for the global var 25 | ArrayType *ArrayTy_0 = ArrayType::get( 26 | IntegerType::get(context.getGlobalContext(), 8), value.size() + 1); 27 | // create global var which holds the constant string. 28 | GlobalVariable *gvar_array__str = 29 | new GlobalVariable(*context.getModule(), 30 | /*Type=*/ArrayTy_0, 31 | /*isConstant=*/true, GlobalValue::PrivateLinkage, 32 | /*Initializer=*/0, // has initializer, specified below 33 | ".str"); 34 | gvar_array__str->setAlignment(MaybeAlign(1)); 35 | // create the contents for the string global. 36 | Constant *const_array_str = 37 | ConstantDataArray::getString(context.getGlobalContext(), value); 38 | // Initialize the global with the string 39 | gvar_array__str->setInitializer(const_array_str); 40 | 41 | // generate access pointer to the string 42 | std::vector const_ptr_8_indices; 43 | ConstantInt *const_int = ConstantInt::get(context.getGlobalContext(), 44 | APInt(64, StringRef("0"), 10)); 45 | const_ptr_8_indices.push_back(const_int); 46 | const_ptr_8_indices.push_back(const_int); 47 | Constant *const_ptr_8 = ConstantExpr::getGetElementPtr( 48 | ArrayTy_0, gvar_array__str, const_ptr_8_indices); 49 | return const_ptr_8; 50 | } 51 | 52 | Value *Boolean::codeGen(CodeGenContext &context) 53 | { 54 | return ConstantInt::get(Type::getInt1Ty(context.getGlobalContext()), boolVal); 55 | } 56 | 57 | Value *Identifier::codeGen(CodeGenContext &context) 58 | { 59 | if (structName.empty()) 60 | { 61 | // A usual stack variable 62 | AllocaInst *alloc = context.findVariable(name); 63 | if (alloc != nullptr) 64 | { 65 | return new LoadInst(alloc, name, false, context.currentBlock()); 66 | } 67 | } 68 | else 69 | { 70 | // get this ptr of struct/class etc... 71 | // it is a stack variable which is a reference to a class object 72 | AllocaInst *alloc = context.findVariable(structName); 73 | if (alloc != nullptr) 74 | { 75 | std::string klassName = context.getType(structName); 76 | Instruction *ptr = context.getKlassVarAccessInst(klassName, name, alloc); 77 | return new LoadInst(ptr, name, false, context.currentBlock()); 78 | } 79 | } 80 | Node::printError(location, 81 | "** [Err] Undeclared variable" + structName + " :: " + name); 82 | context.addError(); 83 | return nullptr; 84 | } 85 | 86 | Value *Block::codeGen(CodeGenContext &context) 87 | { 88 | Value *last = nullptr; 89 | for (auto s : statements) 90 | { 91 | last = s->codeGen(context); 92 | } 93 | return last; 94 | } 95 | 96 | Value *ExpressionStatement::codeGen(CodeGenContext &context) 97 | { 98 | return expression->codeGen(context); 99 | } 100 | 101 | } // namespace hana 102 | -------------------------------------------------------------------------------- /Hana/CodeGen/CompareOperator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "CompareOperator.h" 4 | #include "CodeGenContext.h" 5 | #include "parser.hpp" 6 | 7 | using namespace std; 8 | using namespace llvm; 9 | 10 | namespace hana 11 | { 12 | 13 | Value *CompOperator::codeGen(CodeGenContext &context) 14 | { 15 | Value *rhsVal = rhs->codeGen(context); 16 | if (rhsVal == nullptr) 17 | return nullptr; 18 | Value *lhsVal = lhs->codeGen(context); 19 | if (lhsVal == nullptr) 20 | return nullptr; 21 | if ((lhsVal->getType() != Type::getDoubleTy(context.getGlobalContext())) && (lhsVal->getType() != context.getGenericIntegerType())) 22 | { 23 | Node::printError("Left hand side of compare expression isn't a value type (number)"); 24 | context.addError(); 25 | return nullptr; 26 | } 27 | if ((rhsVal->getType() != Type::getDoubleTy(context.getGlobalContext())) && (rhsVal->getType() != context.getGenericIntegerType())) 28 | { 29 | Node::printError("Right hand side of compare expression isn't a value type (number)"); 30 | context.addError(); 31 | return nullptr; 32 | } 33 | if (rhsVal->getType() != lhsVal->getType()) 34 | { 35 | // since we only support double and int, always cast to double in case of different types. 36 | auto cinstr = CastInst::getCastOpcode(rhsVal, true, Type::getDoubleTy(context.getGlobalContext()), true); 37 | rhsVal = CastInst::Create(cinstr, rhsVal, Type::getDoubleTy(context.getGlobalContext()), "castdb", context.currentBlock()); 38 | cinstr = CastInst::getCastOpcode(lhsVal, true, Type::getDoubleTy(context.getGlobalContext()), true); 39 | lhsVal = CastInst::Create(cinstr, lhsVal, Type::getDoubleTy(context.getGlobalContext()), "castdb", context.currentBlock()); 40 | } 41 | 42 | bool isDouble = rhsVal->getType() == Type::getDoubleTy(context.getGlobalContext()); 43 | Instruction::OtherOps oinstr = isDouble ? Instruction::FCmp : Instruction::ICmp; 44 | 45 | CmpInst::Predicate predicate; 46 | switch (op) 47 | { 48 | case TCGE: 49 | predicate = isDouble ? CmpInst::FCMP_OGE : CmpInst::ICMP_SGE; 50 | break; 51 | case TCGT: 52 | predicate = isDouble ? CmpInst::FCMP_OGT : CmpInst::ICMP_SGT; 53 | break; 54 | case TCLT: 55 | predicate = isDouble ? CmpInst::FCMP_OLT : CmpInst::ICMP_SLT; 56 | break; 57 | case TCLE: 58 | predicate = isDouble ? CmpInst::FCMP_OLE : CmpInst::ICMP_SLE; 59 | break; 60 | case TCEQ: 61 | predicate = isDouble ? CmpInst::FCMP_OEQ : CmpInst::ICMP_EQ; 62 | break; 63 | case TCNE: 64 | predicate = isDouble ? CmpInst::FCMP_ONE : CmpInst::ICMP_NE; 65 | break; 66 | default: 67 | Node::printError("Unknown compare operator."); 68 | context.addError(); 69 | return nullptr; 70 | } 71 | 72 | return CmpInst::Create(oinstr, predicate, lhsVal, rhsVal, "cmptmp", context.currentBlock()); 73 | } 74 | 75 | std::string CompOperator::toString() 76 | { 77 | std::stringstream s; 78 | s << "compare operation "; 79 | switch (op) 80 | { 81 | case TCGE: 82 | s << ">="; 83 | break; 84 | case TCGT: 85 | s << ">"; 86 | break; 87 | case TCLT: 88 | s << "<"; 89 | break; 90 | case TCLE: 91 | s << "<="; 92 | break; 93 | case TCEQ: 94 | s << "=="; 95 | break; 96 | case TCNE: 97 | s << "!="; 98 | break; 99 | default: 100 | s << "unknown"; 101 | } 102 | return s.str(); 103 | } 104 | 105 | } // namespace hana 106 | -------------------------------------------------------------------------------- /Hana/CodeGen/Assignment.cpp: -------------------------------------------------------------------------------- 1 | #include "Assignment.h" 2 | #include "CodeGenContext.h" 3 | #include "parser.hpp" 4 | 5 | using namespace std; 6 | using namespace llvm; 7 | 8 | namespace hana 9 | { 10 | 11 | Value *Assignment::codeGen(CodeGenContext &context) 12 | { 13 | Value *value = rhs->codeGen(context); 14 | if (value == nullptr) 15 | { 16 | Node::printError(location, " Assignment expression results in nothing"); 17 | context.addError(); 18 | return nullptr; 19 | } 20 | 21 | AllocaInst *var = nullptr; 22 | if (lhs->getStructName().empty()) 23 | { 24 | var = context.findVariable(lhs->getName()); 25 | if (var == nullptr) 26 | { 27 | /* In this case the type deductions takes place. This is an assignment with the var keyword. */ 28 | Type *ty = value->getType(); 29 | var = new AllocaInst(ty, 0, lhs->getName().c_str(), context.currentBlock()); 30 | context.locals()[lhs->getName()] = var; 31 | auto className = context.findClassNameByType(ty); 32 | if (!className.empty()) 33 | { 34 | context.setVarType(className, lhs->getName()); 35 | } 36 | } 37 | } 38 | else 39 | { 40 | AllocaInst *varStruct = context.findVariable(lhs->getStructName()); 41 | if (varStruct == nullptr) 42 | { 43 | // Check if the assignment is coming from a class member initialization. 44 | // In that case the context varStruct is set, which points to the member variable. 45 | if (context.varStruct == nullptr) 46 | { 47 | Node::printError(location, "undeclared variable '" + lhs->getName() + "'"); 48 | context.addError(); 49 | return nullptr; 50 | } 51 | varStruct = dyn_cast(context.varStruct); 52 | if (varStruct == nullptr) 53 | { 54 | Node::printError(location, "undeclared class of variable '" + lhs->getStructName() + "." + lhs->getName() + "'"); 55 | context.addError(); 56 | return nullptr; 57 | } 58 | std::string klassName = lhs->getStructName(); 59 | Instruction *ptr = context.getKlassVarAccessInst(klassName, lhs->getName(), varStruct); 60 | return new StoreInst(value, ptr, false, context.currentBlock()); 61 | } 62 | std::string klassName = context.getType(lhs->getStructName()); 63 | Instruction *ptr = context.getKlassVarAccessInst(klassName, lhs->getName(), varStruct); 64 | return new StoreInst(value, ptr, false, context.currentBlock()); 65 | } 66 | Type *varType = var->getType()->getElementType(); 67 | 68 | if (value->getType()->getTypeID() == varType->getTypeID()) 69 | { 70 | // same type but different bit size. 71 | if (value->getType()->getScalarSizeInBits() > varType->getScalarSizeInBits()) 72 | { 73 | value = CastInst::CreateTruncOrBitCast(value, varType, "cast", context.currentBlock()); 74 | } 75 | else if (value->getType()->getScalarSizeInBits() < varType->getScalarSizeInBits()) 76 | { 77 | value = CastInst::CreateZExtOrBitCast(value, varType, "cast", context.currentBlock()); 78 | } 79 | } 80 | else if (value->getType() != varType) 81 | { 82 | std::stringstream msg; 83 | msg << " Assignment of incompatible types " << varType->getTypeID() << "(" << varType->getScalarSizeInBits() << ") = " << value->getType()->getTypeID() 84 | << "(" << value->getType()->getScalarSizeInBits() << "). Is a cast missing? "; 85 | Node::printError(location, msg.str()); 86 | context.addError(); 87 | return nullptr; 88 | } 89 | 90 | return new StoreInst(value, var, false, context.currentBlock()); 91 | } 92 | 93 | } // namespace hana 94 | -------------------------------------------------------------------------------- /Hana/CodeGen/ClassDeclaration.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if defined(_MSC_VER) 4 | #pragma warning(push, 0) 5 | #endif 6 | #include "llvm/Transforms/Utils/Cloning.h" 7 | #if defined(_MSC_VER) 8 | #pragma warning(pop) 9 | #endif 10 | 11 | #include "Assignment.h" 12 | #include "Ast/AstNode.h" 13 | #include "ClassDeclaration.h" 14 | #include "CodeGenContext.h" 15 | #include "Declaration.h" 16 | #include "parser.hpp" 17 | 18 | using namespace std; 19 | using namespace llvm; 20 | 21 | namespace hana 22 | { 23 | 24 | Value *ClassDeclaration::codeGen(CodeGenContext &context) 25 | { 26 | std::vector StructTy_fields; 27 | context.newKlass(id->getName()); 28 | constructStructFields(StructTy_fields, context); 29 | auto classTy = StructType::create(context.getGlobalContext(), StructTy_fields, 30 | std::string("class.") + id->getName(), 31 | /*isPacked=*/false); 32 | addVarsToClassAttributes(context); 33 | removeVarDeclStatements(); 34 | Value *retval = block->codeGen(context); 35 | context.endKlass(); 36 | context.addClassType(id->getName(), classTy); 37 | return retval; 38 | } 39 | 40 | void ClassDeclaration::constructStructFields( 41 | std::vector &StructTy_fields, CodeGenContext &context) 42 | { 43 | // Get all variables and put them in the struct vector. 44 | for (auto statement : block->statements) 45 | { 46 | if (statement->getType() == NodeType::variable) 47 | { 48 | // Type Definitions 49 | #if defined(HANA_NO_RTTI) 50 | VariableDeclaration *vardecl = (VariableDeclaration *)statement; 51 | #else 52 | VariableDeclaration *vardecl = 53 | dynamic_cast(statement); 54 | #endif 55 | StructTy_fields.push_back( 56 | context.typeOf(vardecl->getIdentifierOfVariablenType())); 57 | } 58 | } 59 | } 60 | 61 | void ClassDeclaration::addVarsToClassAttributes(CodeGenContext &context) 62 | { 63 | int index = 0; 64 | for (auto statement : block->statements) 65 | { 66 | if (statement->getType() == NodeType::variable) 67 | { 68 | std::string klassName = this->id->getName(); 69 | // Type Definitions 70 | #if defined(HANA_NO_RTTI) 71 | VariableDeclaration *vardecl = (VariableDeclaration *)statement; 72 | #else 73 | VariableDeclaration *vardecl = 74 | dynamic_cast(statement); 75 | #endif 76 | std::string varName = vardecl->getVariablenName(); 77 | context.klassAddVariableAccess(varName, index++); 78 | if (vardecl->hasAssignmentExpr()) 79 | { 80 | // Call the assignments when class is instantiated. 81 | // Copy it to a place, so that it can be execute at the init time of the 82 | // class. 83 | auto assignmentExpr = vardecl->getAssignment(); 84 | auto ident = vardecl->getIdentifierOfVariable(); 85 | Identifier *newident = 86 | new Identifier(klassName, ident.getName(), ident.getLocation()); 87 | 88 | auto assn = 89 | new Assignment(newident, assignmentExpr, vardecl->getLocation()); 90 | context.addKlassInitCode(klassName, assn); 91 | } 92 | } 93 | } 94 | } 95 | 96 | void ClassDeclaration::removeVarDeclStatements() 97 | { 98 | auto new_end = std::remove_if( 99 | begin(block->statements), end(block->statements), 100 | [](Statement *statement) -> bool 101 | { 102 | return statement->getType() == NodeType::variable ? true : false; 103 | }); 104 | block->statements.erase(new_end, end(block->statements)); 105 | } 106 | 107 | } // namespace hana 108 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Hana

2 | Hana is an elegant, clean and minimalistic interpreted programming language inspired from lua, python and javascript <3 3 | 4 | ⚠️ *WIP ...* 5 | 6 | *For now Doxygen docs* - [🌸 Hana Documentation](https://syylvette.github.io/Hana/) 7 | 8 |

Deps

9 | 10 |
    11 |
  • Cmake >= 3.12
  • 12 |
  • Flex
  • 13 |
  • Bison
  • 14 |
  • LLVM (version 10.0.1)
  • 15 |
16 | 17 |

Building the interpreter

18 | 19 | ``` 20 | git clone https://github.com/syylvette/Hana.git 21 | cd Hana 22 | mkdir Build && cd Build 23 | cmake .. && make 24 | 25 | ## Generates a binary 'hana' in Build/Hana directory 26 | ./hana -h ## Lists the usage 27 | ``` 28 | Builiding the binary might take few minutes depending on your Pc. 29 |
30 | You can also get the binary from Releases, but it will probably only work on Arch or Arch other based distros, 31 | as the binary was built on Arch linux with x86 architecture. 32 |
33 | 34 | 35 |

Usage

36 | 37 |

Create a hana file

38 | 39 | ```py 40 | touch hello.hana && vim hello.hana 41 | ``` 42 | 43 | ```py 44 | writeln("Hello World!") 45 | ``` 46 | 47 |

Run

48 | 49 | Using the hana interpreter 50 | ```py 51 | hana hello.hana 52 | ``` 53 | 54 |

Output

55 | 56 | ``` 57 | Hello World! 58 | ``` 59 | 60 |

Documentation

61 | 62 |

General

63 | 64 |

hana -h Opens the Hana help menu.

65 | 66 |

Variables

67 |

Variables can be decluwuared using the keyword let or by using their types int double string boolean.

68 | 69 | ```py 70 | let baka = 99 71 | string tehe = "hahahah" 72 | int chan = 25 73 | let baka = baka + 1 74 | let chan = chan * 2 75 | 76 | writeln(tehe) 77 | writeln("%d", baka) 78 | writeln("%d", chan) -- Basically just a scanf alias 79 | ``` 80 | 81 |

Output

82 | 83 | ``` 84 | hahahah 85 | 100 86 | 50 87 | ``` 88 | 89 |

Conditionals

90 | 91 | ```py 92 | if《condition》 93 | 《statements》 94 | else《condition》 95 | 《statements》 96 | 97 | -- No else if supported now 98 | ``` 99 | 100 |

Comments

101 | 102 | ```py 103 | -- Single line comment, inspired from lua! 104 | ``` 105 | 106 | ```py 107 | --[[ 108 | Multi 109 | Line 110 | Comment 111 | --]] 112 | ``` 113 | 114 | 115 |

Loops

116 | 117 | ```py 118 | let c = 5 119 | while c > 0 120 | writeln("UwU") 121 | c = c - 1 122 | else 123 | writeln("Boom") 124 | ``` 125 | 126 |

Output

127 | 128 | ``` 129 | UwU 130 | UwU 131 | UwU 132 | UwU 133 | UwU 134 | Boom 135 | ``` 136 | 137 |

Functions/Classes

138 | 139 | Function are created by ```block()``` keyword. 140 | Classes can also be created by same keyword ```block```. 141 | 142 | ```py 143 | block funcName(《parameters》) : 《returnType》 144 | 《statements》 145 | return 《nothing/something》 146 | ``` 147 | Refer ```Testing``` for more examples ~ 148 | 149 | --- 150 | 151 | 152 | > README [Credit](https://github.com/virejdasani/pythOwO)
153 | > Reference Language [Kaleidoscope](https://llvm.org/docs/tutorial/)
154 | > Other References [ghaiklor/llvm-kaleidoscope](https://github.com/ghaiklor/llvm-kaleidoscope)
155 | > Guide https://gnuu.org/2009/09/18/writing-your-own-toy-compiler/ 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /Hana/hana.cpp: -------------------------------------------------------------------------------- 1 | #include "hana.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "config.h" 8 | #include "CodeGen/CodeGenContext.h" 9 | #include "Ast/AstNode.h" 10 | #include "Utils/GetOpt.h" 11 | 12 | extern int yyparse(); 13 | 14 | extern int yylex_destroy(); 15 | 16 | extern FILE *yyin; 17 | extern hana::Block *programBlock; 18 | extern std::stack fileNames; 19 | extern std::vector libPaths; 20 | extern int parsing_error; 21 | 22 | void usage(); 23 | 24 | // Works with path since checking from behind 25 | bool ExtCheck(std::string &str) 26 | { 27 | int i = str.length() - 1; 28 | while (str[i] != '.' && i >= 0) 29 | { 30 | i--; 31 | } 32 | std::string temp = ""; 33 | for (int j = i + 1; j < str.length(); j++) 34 | { 35 | temp += str[j]; 36 | } 37 | if (temp == "hana") 38 | return 1; 39 | return 0; 40 | } 41 | 42 | int main(int argc, char **argv) 43 | { 44 | std::string fileName; 45 | if (argc == 1) 46 | { 47 | // If no argument passed 48 | std::cout << "Hana version " << MAJOR_VER << "." << MINOR_VER << "." << REVISION_VER << "\n"; 49 | std::cout << "Please enter the file name or path to execute, Use 'hana -h' for more information.\n"; 50 | exit(0); 51 | } 52 | 53 | libPaths.push_back("./"); // current path 54 | bool verbose = false; 55 | bool quiet = false; 56 | bool debug = false; 57 | GetOpt getopt(argc, argv, "hvqdr:"); 58 | for (auto opt : getopt) 59 | { 60 | switch (opt) 61 | { 62 | case 'h': 63 | usage(); 64 | return 1; 65 | case 'v': 66 | verbose = true; 67 | break; 68 | case 'q': 69 | quiet = true; 70 | break; 71 | case 'd': 72 | debug = true; 73 | break; 74 | case 'r': 75 | { 76 | std::stringstream ss(getopt.get()); 77 | std::string item; 78 | while (std::getline(ss, item, '|')) 79 | { 80 | std::replace(std::begin(item), std::end(item), '\\', '/'); 81 | if (item[item.size()] != '/') 82 | { 83 | item += '/'; 84 | } 85 | libPaths.push_back(item); 86 | } 87 | } 88 | break; 89 | case EOF: 90 | break; 91 | default: 92 | std::cout << getopt.error() << "\n"; 93 | usage(); 94 | return 1; 95 | } 96 | } 97 | 98 | if (!quiet) 99 | { 100 | std::cout << "\n========================\n"; 101 | std::cout << " Hana version " << MAJOR_VER << "." << MINOR_VER << "." << REVISION_VER << "\n"; 102 | std::cout << "========================\n"; 103 | } 104 | auto files = getopt.getRemainingArguments(); 105 | assert(files.size() == 1); 106 | fileName = files[0]; // Currently only one file is supported. 107 | 108 | bool flag = ExtCheck(fileName); 109 | if (!flag) 110 | { 111 | std::cout << "** Invalid File Extension, Hana files must have a format of .hana\n\n"; 112 | exit(0); 113 | } 114 | 115 | yyin = fopen(fileName.c_str(), "r+"); 116 | if (yyin == nullptr) 117 | { 118 | std::cout << "File " << fileName << "not found. Abort" << std::endl; 119 | return -1; 120 | } 121 | 122 | fileNames.push(""); // Add the empty file name after last EOF. 123 | fileNames.push(fileName); // Add the top level file name. 124 | if (yyparse() || parsing_error) 125 | { 126 | yylex_destroy(); 127 | return 1; 128 | } 129 | 130 | if (programBlock == nullptr) 131 | { 132 | std::cout << "Parsing " << fileName << "failed. Abort" << std::endl; 133 | } 134 | else 135 | { 136 | std::ostringstream devNull; 137 | hana::CodeGenContext context(quiet ? devNull : std::cout); 138 | context.verbose = verbose; 139 | context.debug = debug; 140 | if (verbose) 141 | context.printCodeGeneration(*programBlock, std::cout); 142 | if (context.preProcessing(*programBlock)) 143 | { 144 | if (context.generateCode(*programBlock)) 145 | { 146 | context.runCode(); 147 | } 148 | } 149 | } 150 | 151 | if (yyin != nullptr) 152 | fclose(yyin); 153 | delete programBlock; 154 | yylex_destroy(); 155 | return 0; 156 | } 157 | 158 | void usage() 159 | { 160 | std::cout << "Hana version " << MAJOR_VER << "." << MINOR_VER << "." << REVISION_VER << "\n"; 161 | std::cout << "Usage:\n"; 162 | std::cout << "hana -h -q -v -d -r Path1|Path2|...\n"; 163 | std::cout << "\t-h => Help menu.\n"; 164 | std::cout << "\t-q => Quiet Mode, displays no output.\n"; 165 | std::cout << "\t-v => Verbose mode, displays more information.\n"; 166 | std::cout << "\t-d => Debug mode, basically skips code optimization step.\n"; 167 | std::cout << "\t-r => Require other Hana files, seperated by the pipe '|'.\n"; 168 | } 169 | -------------------------------------------------------------------------------- /Hana/CodeGen/MethodCall.cpp: -------------------------------------------------------------------------------- 1 | #include "MethodCall.h" 2 | #include "CodeGenContext.h" 3 | #include "parser.hpp" 4 | #include "FunctionDeclaration.h" 5 | #include "Declaration.h" 6 | 7 | using namespace std; 8 | using namespace llvm; 9 | 10 | namespace hana 11 | { 12 | 13 | Value *MethodCall::codeGen(CodeGenContext &context) 14 | { 15 | std::string functionName = id->getName(); 16 | if (!id->getStructName().empty()) 17 | { 18 | std::string className = context.getType(id->getStructName()); 19 | functionName += "%" + className; 20 | } 21 | 22 | Function *function = context.getModule()->getFunction(functionName); 23 | if (function == nullptr) 24 | { 25 | // see if it is a added function to the class like function(classname param,...) 26 | functionName = id->getName(); 27 | function = context.getModule()->getFunction(functionName); 28 | if (function == nullptr) 29 | { 30 | // May be it is a class function, but called like a function w/o class prefix 31 | // like: class.function() -> function(class parameter) 32 | functionName = id->getName() + "%" + getTypeNameOfFirstArg(context); 33 | function = context.getModule()->getFunction(functionName); 34 | 35 | if (function == nullptr) 36 | { 37 | // Or it is a function w/ template parameter which will be generated when the parameter types are known. 38 | auto funcdecl = context.getTemplateFunction(id->getName()); 39 | if (funcdecl == nullptr) 40 | { 41 | Node::printError(location, " no such function '" + id->getName() + "'"); 42 | context.addError(); 43 | return nullptr; 44 | } 45 | } 46 | } 47 | } 48 | 49 | std::vector args; 50 | if (!id->getStructName().empty()) 51 | { 52 | // This a class method call, so put the class object onto the stack in order the function has 53 | // access via a local alloca 54 | Value *val = context.findVariable(id->getStructName()); 55 | assert(val != nullptr); 56 | args.push_back(val); 57 | } 58 | else 59 | { 60 | // Check if first parameter is a class object, means variable of a class and a method of this class 61 | // exists. Then call this method. 62 | // Since it is possible to call a class.method(arguments) 63 | // like method(class, arguments). 64 | if (arguments->size() && arguments->front()->getType() == NodeType::identifier) 65 | { 66 | Identifier *ident = (Identifier *)*(arguments->begin()); 67 | // Check if it is a var of class type... 68 | std::string typeName = context.getType(ident->getName()); 69 | AllocaInst *alloca = context.findVariable(ident->getName()); 70 | if (alloca != nullptr) 71 | { 72 | if (alloca->getType()->getElementType()->isStructTy()) 73 | { 74 | args.push_back(alloca); 75 | delete ident; 76 | arguments->erase(begin(*arguments)); 77 | } 78 | } 79 | } 80 | } 81 | 82 | // Put all parameter values onto the stack. 83 | for (auto expr : *arguments) 84 | { 85 | auto arg = expr->codeGen(context); 86 | if (arg == nullptr) 87 | { 88 | return nullptr; 89 | } 90 | args.push_back(arg); 91 | } 92 | 93 | if (function == nullptr) 94 | { 95 | // Generate the template function, according to the given parameter types. 96 | context.setGenerateTemplatedFunction(true); 97 | auto funcdeclTemplate = context.getTemplateFunction(id->getName()); 98 | auto funcdecl = new FunctionDeclaration(*funcdeclTemplate); 99 | auto funcparams = funcdecl->getParameter(); 100 | for (auto i = 0u; i < funcparams->size(); ++i) 101 | { 102 | auto fparam = funcparams->at(i); 103 | // Exchange the var parameter with the type of the real used type by the call. 104 | if (fparam->getIdentifierOfVariablenType().getName() == "var") 105 | { 106 | auto actualType = new Identifier(context.typeNameOf(args[i]->getType()), fparam->getLocation()); 107 | auto identifier = new Identifier(fparam->getIdentifierOfVariable()); 108 | auto substitudeParam = new VariableDeclaration(actualType, identifier, fparam->getLocation()); 109 | funcparams->at(i) = substitudeParam; 110 | delete fparam; 111 | } 112 | } 113 | // Instantiate the function with the now known parameter types. 114 | function = dyn_cast(funcdecl->codeGen(context)); 115 | context.setGenerateTemplatedFunction(false); 116 | delete funcdecl; 117 | } 118 | 119 | return CallInst::Create(function, args, "", context.currentBlock()); 120 | } 121 | 122 | std::string MethodCall::getTypeNameOfFirstArg(CodeGenContext &context) 123 | { 124 | if (arguments->size() && arguments->front()->getType() == NodeType::identifier) 125 | { 126 | Identifier *ident = static_cast(*(arguments->begin())); 127 | // Check if it is a var of class type... 128 | return context.getType(ident->getName()); 129 | } 130 | return ""; 131 | } 132 | 133 | } // namespace hana 134 | -------------------------------------------------------------------------------- /Hana/CodeGen/BinaryOperator.cpp: -------------------------------------------------------------------------------- 1 | #include "CodeGen/BinaryOperator.h" 2 | #include "CodeGen/CodeGenContext.h" 3 | #include "CodeGen/Array.h" 4 | #include "parser.hpp" 5 | 6 | using namespace std; 7 | using namespace llvm; 8 | 9 | namespace hana 10 | { 11 | 12 | Value *BinaryOp::codeGen(CodeGenContext &context) 13 | { 14 | Value *rhsValue = rhs->codeGen(context); 15 | Value *lhsValue = lhs->codeGen(context); 16 | if ((rhsValue == nullptr) || (lhsValue == nullptr)) 17 | { 18 | return nullptr; 19 | } 20 | auto Ty = rhsValue->getType(); 21 | if (Ty->isPointerTy() && Ty->getPointerElementType()->isStructTy()) 22 | { 23 | // A class or list object is added. 24 | return codeGenAddList(rhsValue, lhsValue, context); 25 | } 26 | 27 | if (rhsValue->getType() != lhsValue->getType()) 28 | { 29 | // since we only support double and int, always cast to double in case of different types. 30 | auto doubleTy = Type::getDoubleTy(context.getGlobalContext()); 31 | auto cinstr = CastInst::getCastOpcode(rhsValue, true, doubleTy, true); 32 | rhsValue = CastInst::Create(cinstr, rhsValue, doubleTy, "castdb", context.currentBlock()); 33 | cinstr = CastInst::getCastOpcode(lhsValue, true, doubleTy, true); 34 | lhsValue = CastInst::Create(cinstr, lhsValue, doubleTy, "castdb", context.currentBlock()); 35 | } 36 | 37 | bool isDoubleTy = rhsValue->getType()->isFloatingPointTy(); 38 | if (isDoubleTy && (op == TAND || op == TOR)) 39 | { 40 | Node::printError(location, "Binary operation (AND,OR) on floating point value is not supported. Is a cast missing?"); 41 | context.addError(); 42 | return nullptr; 43 | } 44 | 45 | Instruction::BinaryOps instr; 46 | switch (op) 47 | { 48 | case TPLUS: 49 | isDoubleTy ? instr = Instruction::FAdd : instr = Instruction::Add; 50 | break; 51 | case TMINUS: 52 | isDoubleTy ? instr = Instruction::FSub : instr = Instruction::Sub; 53 | break; 54 | case TMUL: 55 | isDoubleTy ? instr = Instruction::FMul : instr = Instruction::Mul; 56 | break; 57 | case TDIV: 58 | isDoubleTy ? instr = Instruction::FDiv : instr = Instruction::SDiv; 59 | break; 60 | case TAND: 61 | instr = Instruction::And; 62 | break; 63 | case TOR: 64 | instr = Instruction::Or; 65 | break; 66 | default: 67 | Node::printError(location, "Unknown binary operator."); 68 | context.addError(); 69 | return nullptr; 70 | } 71 | return BinaryOperator::Create(instr, lhsValue, rhsValue, "mathtmp", context.currentBlock()); 72 | } 73 | 74 | std::string BinaryOp::toString() 75 | { 76 | std::stringstream s; 77 | s << "binary operation "; 78 | switch (op) 79 | { 80 | case TPLUS: 81 | s << "+"; 82 | break; 83 | case TMINUS: 84 | s << "-"; 85 | break; 86 | case TMUL: 87 | s << "*"; 88 | break; 89 | case TDIV: 90 | s << "/"; 91 | break; 92 | case TAND: 93 | s << "and"; 94 | break; 95 | case TOR: 96 | s << "or"; 97 | break; 98 | default: 99 | s << "unknown"; 100 | } 101 | return s.str(); 102 | } 103 | 104 | llvm::Value *BinaryOp::codeGenAddList(llvm::Value *rhsValue, llvm::Value *lhsValue, CodeGenContext &context) 105 | { 106 | auto rhsTy = rhsValue->getType()->getPointerElementType(); 107 | auto lhsTy = lhsValue->getType()->getPointerElementType(); 108 | if (!lhsTy->isStructTy()) 109 | { 110 | Node::printError(location, "First operand is not of a list type."); 111 | return nullptr; 112 | } 113 | if (!rhsTy->isStructTy()) 114 | { 115 | Node::printError(location, "Second operand is not of a list type."); 116 | return nullptr; 117 | } 118 | 119 | if (getLHS()->getType() != NodeType::identifier) 120 | { 121 | Node::printError(location, "First operand must be an identifier."); 122 | return nullptr; 123 | } 124 | if (getRHS()->getType() != NodeType::identifier) 125 | { 126 | Node::printError(location, "Second operand must be an identifier."); 127 | return nullptr; 128 | } 129 | if (op != TPLUS) 130 | { 131 | Node::printError(location, "Only operator addition is currently supported."); 132 | return nullptr; 133 | } 134 | 135 | // Construct a new list with the contents of the both. 136 | auto rhsCount = rhsTy->getNumContainedTypes(); 137 | auto lhsCount = lhsTy->getNumContainedTypes(); 138 | ExpressionList exprList; 139 | for (unsigned int i = 0; i < lhsCount; ++i) 140 | { 141 | auto id = (Identifier *)this->getLHS(); 142 | ArrayAccess *access = new ArrayAccess(id, i, id->getLocation()); 143 | exprList.push_back(access); 144 | } 145 | for (unsigned int i = 0; i < rhsCount; ++i) 146 | { 147 | auto id = (Identifier *)this->getRHS(); 148 | ArrayAccess *access = new ArrayAccess(id, i, id->getLocation()); 149 | exprList.push_back(access); 150 | } 151 | auto list = new Array(&exprList, location); 152 | auto newList = list->codeGen(context); 153 | return newList; 154 | } 155 | 156 | } // namespace hana 157 | -------------------------------------------------------------------------------- /Hana/CodeGen/Array.cpp: -------------------------------------------------------------------------------- 1 | #include "Array.h" 2 | #include "Assignment.h" 3 | #include "CodeGenContext.h" 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | using namespace llvm; 9 | 10 | namespace hana 11 | { 12 | 13 | llvm::Value *Array::codeGen(CodeGenContext &context) 14 | { 15 | using ValueList = std::vector; 16 | using TypeList = std::vector; 17 | ValueList values; 18 | TypeList types; 19 | for (auto e : *exprList) 20 | { 21 | auto code = e->codeGen(context); 22 | values.push_back(code); 23 | types.push_back(code->getType()); 24 | } 25 | StructType *str = StructType::create(context.getGlobalContext(), makeArrayRef(types), "list"); 26 | auto alloc_str = new AllocaInst(str, 0, "alloc_list", context.currentBlock()); 27 | std::vector ptr_indices; 28 | ConstantInt *const_int32_0 = ConstantInt::get(context.getModule()->getContext(), APInt(32, 0)); 29 | for (int index = 0; index < values.size(); ++index) 30 | { 31 | ptr_indices.clear(); 32 | ptr_indices.push_back(const_int32_0); 33 | ConstantInt *const_int32 = ConstantInt::get(context.getModule()->getContext(), APInt(32, index)); 34 | ptr_indices.push_back(const_int32); 35 | Instruction *ptr = GetElementPtrInst::Create(alloc_str->getType()->getElementType(), alloc_str, ptr_indices, "", context.currentBlock()); 36 | new StoreInst(values[index], ptr, context.currentBlock()); 37 | } 38 | return alloc_str; 39 | } 40 | 41 | llvm::Value *ArrayAccess::codeGen(CodeGenContext &context) 42 | { 43 | AllocaInst *var = nullptr; 44 | Type *var_type = nullptr; 45 | Type *var_struct_type = nullptr; 46 | if (other != nullptr) 47 | { 48 | auto tmp = other->codeGen(context); 49 | var = new AllocaInst(tmp->getType(), 0, "tmp_alloc_list_other", context.currentBlock()); 50 | new StoreInst(tmp, var, context.currentBlock()); 51 | var_type = var->getAllocatedType(); 52 | var_struct_type = var->getAllocatedType()->getContainedType(0); 53 | } 54 | else 55 | { 56 | var = context.findVariable(variable->getName()); 57 | if (var == nullptr) 58 | { 59 | Node::printError(location, "unknown variable " + variable->getName()); 60 | return nullptr; 61 | } 62 | var_type = var->getAllocatedType(); 63 | var_struct_type = var_type->getContainedType(0); 64 | } 65 | if (var_struct_type == nullptr) 66 | { 67 | Node::printError(location, "Type mismatch: variable " + variable->getName() + " must have type list but has type " + context.getType(variable->getName())); 68 | context.addError(); 69 | return nullptr; 70 | } 71 | if (var_struct_type->getTypeID() != StructType::StructTyID) 72 | { 73 | Node::printError(location, "Type mismatch: variable " + variable->getName() + " must have type list but has type " + context.getType(variable->getName())); 74 | context.addError(); 75 | return nullptr; 76 | } 77 | if (var_struct_type->getNumContainedTypes() <= index) 78 | { 79 | Node::printError(location, variable->getName() + " : index out of range (with index(zero based) = " + std::to_string(index) + " and size = " + std::to_string(var_struct_type->getNumContainedTypes()) + ")"); 80 | context.addError(); 81 | return nullptr; 82 | } 83 | std::vector ptr_indices; 84 | ConstantInt *const_int32_0 = ConstantInt::get(context.getModule()->getContext(), APInt(32, 0)); 85 | ConstantInt *const_int32 = ConstantInt::get(context.getModule()->getContext(), APInt(32, index)); 86 | ptr_indices.push_back(const_int32_0); 87 | ptr_indices.push_back(const_int32); 88 | auto val = new LoadInst(var, "load_var", context.currentBlock()); 89 | Instruction *ptr = GetElementPtrInst::Create(var_struct_type, val, ptr_indices, "get_struct_element", context.currentBlock()); 90 | auto value = new LoadInst(ptr, "load_ptr_struct", context.currentBlock()); 91 | return value; 92 | } 93 | 94 | llvm::Value *ArrayAddElement::codeGen(CodeGenContext &context) 95 | { 96 | YYLTYPE loc = {0, 0, 0, 0}; 97 | Block tmp_code; 98 | ExpressionList members; 99 | auto orgVarType = context.getType(ident->getName()); 100 | auto tmpVarName = ident->getName() + "_tmp"; 101 | context.renameVariable(ident->getName(), tmpVarName); 102 | auto var = context.findVariable(tmpVarName); 103 | if (var == nullptr) 104 | { 105 | Node::printError(location, "unknown variable " + ident->getName()); 106 | return nullptr; 107 | } 108 | auto var_type = var->getAllocatedType(); 109 | auto var_struct_type = var_type->getContainedType(0); 110 | auto count = var_struct_type->getNumContainedTypes(); 111 | Identifier tmpIdent(tmpVarName, loc); 112 | for (decltype(count) i = 0; i < count; ++i) 113 | { 114 | members.push_back(new ArrayAccess(&tmpIdent, i, loc)); 115 | } 116 | members.push_back(this->getExpression()); 117 | auto newList = new Array(&members, loc); 118 | // Restore type name, since the rename has destroyed it and the assign doesn't set it. 119 | // The type name is only set while declaration. 120 | context.setVarType(orgVarType, ident->getName()); 121 | Assignment assgn(ident, newList, loc); 122 | auto value = assgn.codeGen(context); 123 | context.deleteVariable(tmpVarName); 124 | return value; 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /Hana/Visitor/VisitorSyntaxCheck.cpp: -------------------------------------------------------------------------------- 1 | #include "VisitorSyntaxCheck.h" 2 | #include "Ast/AstNode.h" 3 | #include "CodeGen/FunctionDeclaration.h" 4 | #include "CodeGen/ClassDeclaration.h" 5 | #include "CodeGen/Return.h" 6 | #include "CodeGen/FunctionDeclaration.h" 7 | #include "CodeGen/ClassDeclaration.h" 8 | #include "CodeGen/Conditional.h" 9 | #include "CodeGen/UnaryOperator.h" 10 | #include "CodeGen/BinaryOperator.h" 11 | #include "CodeGen/Assignment.h" 12 | #include "CodeGen/MethodCall.h" 13 | #include "CodeGen/Declaration.h" 14 | #include "CodeGen/WhileLoop.h" 15 | #include "CodeGen/Array.h" 16 | #include "CodeGen/Range.h" 17 | 18 | namespace hana 19 | { 20 | 21 | void VisitorSyntaxCheck::VisitExpression(Expression *expr) { (void)expr; } 22 | 23 | void VisitorSyntaxCheck::VisitStatement(Statement *stmt) { (void)stmt; } 24 | 25 | void VisitorSyntaxCheck::VisitReturnStatement(Return *retstmt) 26 | { 27 | ReturnStatementLocations.push_back(retstmt->getLocation()); 28 | } 29 | 30 | void VisitorSyntaxCheck::VisitFunctionDeclaration(FunctionDeclaration *fndecl) 31 | { 32 | ReturnStatementLocations.clear(); 33 | 34 | auto body = fndecl->getBody(); 35 | for (auto stmt : body->statements) 36 | { 37 | stmt->Accept(*this); 38 | } 39 | auto retType = fndecl->getRetType(); 40 | if (ReturnStatementLocations.size() > 1 && retType->getName() == "var") 41 | { 42 | Node::printError(fndecl->getlocation(), "Too many return statement in function '" + fndecl->getId()->getName() + "()' for return type deduction.\nThe possible statements are:"); 43 | std::stringstream s; 44 | for (auto loc : ReturnStatementLocations) 45 | { 46 | s << " " << loc.file_name << ":" << loc.first_line << ":" << loc.first_column << " return ...\n"; 47 | } 48 | Node::printError(s.str()); 49 | syntaxErrors++; 50 | } 51 | } 52 | 53 | void VisitorSyntaxCheck::VisitConditional(Conditional *cmp) 54 | { 55 | if (cmp->getThen()) 56 | { 57 | cmp->getThen()->Accept(*this); 58 | } 59 | if (cmp->getElse()) 60 | { 61 | cmp->getElse()->Accept(*this); 62 | } 63 | } 64 | 65 | void VisitorSyntaxCheck::VisitInteger(Integer *expr) { (void)expr; } 66 | 67 | void VisitorSyntaxCheck::VisitDouble(Double *expr) { (void)expr; } 68 | 69 | void VisitorSyntaxCheck::VisitString(String *expr) { (void)expr; } 70 | 71 | void VisitorSyntaxCheck::VisitBoolean(Boolean *expr) { (void)expr; } 72 | 73 | void VisitorSyntaxCheck::VisitIdentifier(Identifier *expr) { (void)expr; } 74 | 75 | void VisitorSyntaxCheck::VisitUnaryOperator(UnaryOperator *expr) { (void)expr; } 76 | 77 | void VisitorSyntaxCheck::VisitBinaryOp(BinaryOp *expr) { (void)expr; } 78 | 79 | void VisitorSyntaxCheck::VisitCompOperator(CompOperator *expr) { (void)expr; } 80 | 81 | void VisitorSyntaxCheck::VisitBlock(Block *expr) 82 | { 83 | for (auto stmt : expr->statements) 84 | { 85 | stmt->Accept(*this); 86 | } 87 | } 88 | 89 | void VisitorSyntaxCheck::VisitExpressionStatement(ExpressionStatement *expr) { (void)expr; } 90 | 91 | void VisitorSyntaxCheck::VisitAssigment(Assignment *expr) { (void)expr; } 92 | 93 | void VisitorSyntaxCheck::VisitMethodCall(MethodCall *expr) { (void)expr; } 94 | 95 | void VisitorSyntaxCheck::VisitVariablenDeclaration(VariableDeclaration *expr) 96 | { 97 | if (TypeNames.count(expr->getVariablenTypeName()) == 0) 98 | { 99 | Node::printError(expr->getLocation(), "Unknown type for decalration of " + expr->getVariablenName()); 100 | ++syntaxErrors; 101 | } 102 | } 103 | 104 | void VisitorSyntaxCheck::VisitWhileLoop(WhileLoop *expr) { (void)expr; } 105 | 106 | void VisitorSyntaxCheck::VisitClassDeclaration(ClassDeclaration *expr) 107 | { 108 | TypeNames.emplace(expr->getIdentifier()->getName()); 109 | } 110 | void VisitorSyntaxCheck::VisitArray(Array *expr) 111 | { 112 | auto listexprs = expr->getExpressions(); 113 | 114 | for (auto exp : *listexprs) 115 | { 116 | exp->Accept(*this); 117 | } 118 | } 119 | 120 | void VisitorSyntaxCheck::VisitArrayAccess(ArrayAccess *expr) 121 | { 122 | if (expr->other != nullptr) 123 | { 124 | expr->other->Accept(*this); 125 | } 126 | } 127 | 128 | void VisitorSyntaxCheck::VisitArrayAddElement(ArrayAddElement *expr) { (void)expr; } 129 | 130 | void VisitorSyntaxCheck::VisitRange(Range *expr) 131 | { 132 | switch (expr->begin->getType()) 133 | { 134 | case NodeType::decimal: 135 | break; 136 | case NodeType::integer: 137 | break; 138 | case NodeType::expression: 139 | break; 140 | case NodeType::list: 141 | break; 142 | case NodeType::variable: 143 | break; 144 | default: 145 | Node::printError("Expression " + expr->begin->toString() + " not allowed in a range definition."); 146 | ++syntaxErrors; 147 | } 148 | switch (expr->end->getType()) 149 | { 150 | case NodeType::decimal: 151 | break; 152 | case NodeType::integer: 153 | break; 154 | case NodeType::expression: 155 | break; 156 | case NodeType::list: 157 | break; 158 | case NodeType::variable: 159 | break; 160 | default: 161 | Node::printError("Expression " + expr->begin->toString() + " not allowed in a range definition."); 162 | ++syntaxErrors; 163 | } 164 | 165 | if (expr->begin != nullptr) 166 | { 167 | expr->begin->Accept(*this); 168 | } 169 | if (expr->end != nullptr) 170 | { 171 | expr->end->Accept(*this); 172 | } 173 | } 174 | 175 | } 176 | -------------------------------------------------------------------------------- /Hana/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | project(Hana) 4 | 5 | message(STATUS "======================") 6 | message(STATUS "[*] BUILDING Hana ...") 7 | message(STATUS "======================") 8 | 9 | macro(replace_flags flag newflag) 10 | FOREACH(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE) 11 | IF(${flag_var} MATCHES ${flag}) 12 | STRING(REGEX REPLACE "${flag}" "${newflag}" ${flag_var} "${${flag_var}}") 13 | ENDIF() 14 | ENDFOREACH(flag_var) 15 | endmacro() 16 | 17 | set(CMAKE_VERBOSE_MAKEFILE ON) 18 | set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) 19 | set(CMAKE_MODULE_PATH "${Hana_SOURCE_DIR}/cmake") 20 | 21 | FIND_PACKAGE(FLEX) 22 | FIND_PACKAGE(BISON) 23 | 24 | if($ENV{LLVM_ROOT}) 25 | set(LLVM_ROOT $ENV{LLVM_ROOT}) 26 | endif() 27 | 28 | find_package(LLVM PATHS "${LLVM_ROOT}/lib/cmake/llvm" "$ENV{ProgramFiles}/lib/cmake/llvm") 29 | 30 | if(LLVM_FOUND) 31 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${LLVM_DIR}") 32 | else() 33 | message(FATAL_ERROR "LLVM installation not found. Set LLVM_ROOT to the installation root path.") 34 | endif() 35 | 36 | include(LLVMConfig) 37 | message(STATUS "Found LLVM Package Version:${LLVM_PACKAGE_VERSION}") 38 | message(STATUS "LLVM Built type : ${LLVM_BUILD_TYPE}") 39 | string(REGEX MATCH "[0-9]+\\.[0-9]+" LLVM_VER ${LLVM_PACKAGE_VERSION}) 40 | 41 | llvm_map_components_to_libnames(REQ_LLVM_LIBRARIES mcjit interpreter native ipo) # JIT Support 42 | 43 | set(HANA_SOURCES 44 | hana.cpp 45 | Lib/Stlib.cpp 46 | Ast/AstNode.cpp 47 | CodeGen/Array.cpp 48 | CodeGen/Declaration.cpp 49 | CodeGen/FunctionDeclaration.cpp 50 | CodeGen/ClassDeclaration.cpp 51 | CodeGen/CodeGenContext.cpp 52 | Visitor/VisitorSyntaxCheck.cpp 53 | Visitor/VisitorPrettyPrint.cpp 54 | tokens.l 55 | parser.y 56 | Utils/GetOpt.cpp 57 | CodeGen/Range.cpp 58 | CodeGen/BinaryOperator.cpp 59 | CodeGen/UnaryOperator.cpp 60 | CodeGen/CompareOperator.cpp 61 | CodeGen/Return.cpp 62 | CodeGen/WhileLoop.cpp 63 | CodeGen/Conditional.cpp 64 | CodeGen/Assignment.cpp 65 | CodeGen/MethodCall.cpp 66 | ) 67 | 68 | set(HANA_HEADERS 69 | Lib/Stlib.h 70 | Ast/AstNode.h 71 | CodeGen/Array.h 72 | CodeGen/Declaration.h 73 | CodeGen/FunctionDeclaration.h 74 | CodeGen/ClassDeclaration.h 75 | CodeGen/CodeGenContext.h 76 | Visitor/Visitor.h 77 | Visitor/VisitorSyntaxCheck.h 78 | Visitor/VisitorPrettyPrint.h 79 | Utils/GetOpt.h 80 | CodeGen/BinaryOperator.h 81 | CodeGen/UnaryOperator.h 82 | CodeGen/CompareOperator.h 83 | CodeGen/Range.h 84 | CodeGen/Return.h 85 | CodeGen/WhileLoop.h 86 | CodeGen/Conditional.h 87 | CodeGen/Assignment.h 88 | CodeGen/MethodCall.h 89 | ) 90 | 91 | if(MSVC) 92 | source_group(Header\ Files FILES ${HANA_HEADERS}) 93 | source_group(Source\ Files FILES ${HANA_SOURCES}) 94 | endif() 95 | 96 | set(VER_MAJ 1) 97 | set(VER_MIN 1) 98 | set(VER_REV 2) 99 | 100 | configure_file(config.in ${Hana_SOURCE_DIR}/config.h) 101 | 102 | BISON_TARGET(Parser parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp COMPILE_FLAGS --report=solved COMPILE_FLAGS --feature=fixit) 103 | FLEX_TARGET(Scanner tokens.l ${CMAKE_CURRENT_BINARY_DIR}/tokens.cpp) 104 | ADD_FLEX_BISON_DEPENDENCY(Scanner Parser) 105 | 106 | add_executable(hana ${HANA_SOURCES} ${HANA_HEADERS} ${BISON_Parser_OUTPUTS} ${FLEX_Scanner_OUTPUTS}) 107 | 108 | # Compiler-dependent and build-depended flags: 109 | if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) 110 | target_compile_options(hana PRIVATE -Wall) 111 | elseif(MSVC) 112 | replace_flags("/MDd" "/MTd") 113 | replace_flags("/MD" "/MT") 114 | target_compile_options(hana PRIVATE /W4 /permissive-) 115 | target_compile_definitions(hana PRIVATE YY_NO_UNISTD_H) 116 | target_compile_definitions(hana PRIVATE _SCL_SECURE_NO_WARNINGS) 117 | target_compile_definitions(hana PRIVATE _CRT_SECURE_NO_WARNINGS) 118 | target_compile_definitions(hana PRIVATE _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS) 119 | set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/tokens.cpp PROPERTIES COMPILE_DEFINITIONS __STDC_VERSION__=199901L) 120 | endif() 121 | 122 | # Debug or release ? 123 | target_compile_definitions(hana PRIVATE $<$:_DEBUG>) 124 | 125 | # Add the compiler definitions of LLVM 126 | if(MSVC) 127 | # In order to use it with target_compile_definitions we have to replace the -D 128 | # with a semicolon otherwise they are not correctly populated to MSVC and the 129 | # IntelliSense is broken (command line error). 130 | string(REPLACE "-D" ";" LLVM_DEFINITIONS ${LLVM_DEFINITIONS}) 131 | endif() 132 | 133 | target_compile_definitions(hana PRIVATE ${LLVM_DEFINITIONS}) 134 | 135 | if("${LLVM_BUILD_TYPE}" MATCHES "Release|RelWithDebInfo|MinSizeRel") 136 | target_compile_definitions(hana PRIVATE LLVM_NO_DUMP) 137 | endif() 138 | 139 | if(NOT LLVM_ENABLE_RTTI) 140 | target_compile_definitions(hana PRIVATE HANA_NO_RTTI) 141 | 142 | if(MSVC) 143 | target_compile_options(hana PRIVATE /GR-) 144 | else() 145 | target_compile_options(hana PRIVATE -fno-rtti) 146 | endif() 147 | endif() 148 | 149 | if(LLVM_ENABLE_EH AND CMAKE_COMPILER_IS_GNUCXX) 150 | target_compile_options(hana PRIVATE -fexceptions) 151 | endif() 152 | 153 | # Add additional include search directories. 154 | target_include_directories(hana PRIVATE ${Hana_SOURCE_DIR} ${LLVM_INCLUDE_DIRS}) 155 | target_include_directories(hana PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) 156 | 157 | target_compile_features(hana PRIVATE cxx_std_17) 158 | 159 | # Finally, we link the LLVM libraries to our executable: 160 | target_link_libraries(hana ${REQ_LLVM_LIBRARIES}) 161 | -------------------------------------------------------------------------------- /Hana/Utils/GetOpt.cpp: -------------------------------------------------------------------------------- 1 | /* GetOpt - getopt as a c++ class. 2 | * 3 | * The MIT License (MIT) 4 | * 5 | * Copyright (c) 2015 Klaus Beyer 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | #include // EOF const 26 | #include 27 | #include 28 | #include 29 | 30 | #include "GetOpt.h" 31 | 32 | static std::string removeLeftWhiteSpaces(std::string text) 33 | { 34 | std::string newtext; 35 | auto pos = text.find_first_not_of(" \t\n"); 36 | if (pos != std::string::npos) 37 | { 38 | newtext = text.substr(pos, text.length() - pos); 39 | } 40 | else 41 | { 42 | newtext = text; 43 | } 44 | return newtext; 45 | } 46 | 47 | GetOpt::GetOpt(int argc, char *argv[], const std::string optstring, const std::string filename) 48 | : index(1u), optionString(optstring) 49 | { 50 | 51 | // Put cmd line options into front, they win over the file options. 52 | for (int i = 0; i < argc; ++i) 53 | { 54 | argStrings.push_back(argv[i]); 55 | } 56 | 57 | if (!filename.empty()) 58 | { 59 | std::ifstream file; 60 | file.open(filename); 61 | std::string line; 62 | while (getline(file, line)) 63 | { 64 | if (line[0] == '-') 65 | { 66 | // Remove spaces between option and its argument. 67 | if (line[2] == ' ') 68 | { 69 | auto arg = line.substr(2); 70 | line = line.substr(0, 2) + removeLeftWhiteSpaces(arg); 71 | } 72 | } 73 | auto found = std::count_if(std::begin(argStrings), std::end(argStrings), [line](auto s) 74 | { return line == s; }); 75 | if (found == 0) 76 | { 77 | argStrings.push_back(line); 78 | } 79 | } 80 | } 81 | 82 | argCount = argStrings.size(); 83 | } 84 | 85 | char GetOpt::operator()() 86 | { 87 | optionArgument.clear(); 88 | errorText.clear(); 89 | 90 | // Is first character of option string a ':' 91 | if (optionString[0] == ':') 92 | { 93 | errorText = argStrings[0] + std::string(": missing option argument in ") + optionString + "\n"; 94 | optionString.erase(0, 1); 95 | return ':'; 96 | } 97 | 98 | // Is end of argument list? 99 | if (index >= argCount) 100 | { 101 | return EOF; 102 | } 103 | 104 | // Is a non option argument reached? 105 | if (argStrings[index][0] != '-') 106 | { 107 | if (argStrings[index][1] == '\0') 108 | return EOF; 109 | if (index == argCount - 1) 110 | { 111 | return EOF; 112 | } 113 | std::rotate(argStrings.begin() + index, argStrings.begin() + index + 1, argStrings.end()); 114 | --argCount; 115 | return this->operator()(); 116 | } 117 | 118 | // Is end of argument list reached? 119 | if (argStrings[index][0] == '-' && argStrings[index][1] == '-') 120 | { 121 | index++; 122 | return EOF; 123 | } 124 | 125 | auto scan = argStrings[index]; 126 | index++; 127 | 128 | // Skip '-' 129 | // Is current character in the option string 130 | char c = scan[1]; 131 | auto place = optionString.find_first_of(c); 132 | if (place == std::string::npos || c == ':') 133 | { 134 | errorText = argStrings[0] + std::string(": unknown option -") + c + "\n"; 135 | return '?'; 136 | } 137 | 138 | // Check if an additional argument is needed. 139 | place++; 140 | if (optionString[place] == ':') 141 | { 142 | place++; 143 | bool argIsOptional = optionString[place] == ':'; 144 | // Check if no space is between option and its argument. 145 | if (scan[2] != '\0') 146 | { 147 | optionArgument = scan.substr(2); 148 | } 149 | else if (index < argCount) 150 | { 151 | if (argStrings[index][0] != '-') 152 | { 153 | optionArgument = argStrings[index]; 154 | index++; 155 | } 156 | else if (!argIsOptional) 157 | { 158 | errorText = argStrings[0] + std::string(": option requires argument -") + c + "\n"; 159 | return ':'; 160 | } 161 | } 162 | else if (!argIsOptional) 163 | { 164 | errorText = argStrings[0] + std::string(": option requires argument -") + c + "\n"; 165 | return ':'; 166 | } 167 | } 168 | return c; 169 | } 170 | 171 | std::vector GetOpt::getRemainingArguments() 172 | { 173 | std::vector args(argStrings.begin() + index, argStrings.end()); 174 | return args; 175 | } 176 | 177 | char GetOpt::iterator::operator*() 178 | { 179 | auto ret = getopt->operator()(); 180 | if (ret == EOF) 181 | { 182 | position = getopt->argCount - 1; // Set iterator to the end 183 | } 184 | else 185 | { 186 | position = getopt->index - 1; // In case index has advanced more than one position. 187 | } 188 | 189 | return ret; 190 | } 191 | -------------------------------------------------------------------------------- /Hana/Ast/AstNode.h: -------------------------------------------------------------------------------- 1 | #ifndef INC_ASTNODE_H 2 | #define INC_ASTNODE_H 3 | 4 | #include "hana.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #if defined(_MSC_VER) 12 | #pragma warning(push, 0) 13 | #endif 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #if defined(_MSC_VER) 20 | #pragma warning(pop) 21 | #endif 22 | 23 | #include "Visitor/Visitor.h" 24 | 25 | struct YYLTYPE 26 | { 27 | int first_line{0}; 28 | int first_column{0}; 29 | int last_line{0}; 30 | int last_column{0}; 31 | std::string file_name; 32 | }; 33 | 34 | namespace hana 35 | { 36 | 37 | class CodeGenContext; 38 | 39 | using StatementList = std::vector; 40 | using ExpressionList = std::vector; 41 | using VariableList = std::vector; 42 | 43 | /*! Type of the AST node */ 44 | enum class NodeType 45 | { 46 | expression, 47 | variable, 48 | klass, 49 | function, 50 | integer, 51 | decimal, 52 | string, 53 | boolean, 54 | identifier, 55 | list, 56 | range 57 | }; 58 | 59 | /*! Base class of all nodes */ 60 | class Node 61 | { 62 | public: 63 | virtual ~Node() = default; 64 | 65 | /*! Code generation for this node 66 | * \param[in] context The context of the code gen run. 67 | * \return Generated code as LLVM value. 68 | */ 69 | virtual llvm::Value *codeGen(CodeGenContext &context) = 0; 70 | 71 | /*! Returns the type of the node. */ 72 | virtual NodeType getType() = 0; 73 | 74 | /*! Returns the textual representation. */ 75 | virtual std::string toString() { return "node"; } 76 | 77 | /*! Accept a visitor. */ 78 | virtual void Accept(Visitor &v) = 0; 79 | 80 | /*! Prints the found parsing error. 81 | * \param[in] location file, line, col information. 82 | * \param[in] msg The message to print. 83 | */ 84 | static void printError(YYLTYPE location, std::string msg) 85 | { 86 | std::cerr << location.file_name << ": Line " << location.first_line 87 | << " Column " << location.first_column << "-" 88 | << location.last_column << " :" << msg << std::endl; 89 | } 90 | 91 | /*! Prints an error message where no source location is available. 92 | * \param[in] msg The message to print. 93 | */ 94 | static void printError(std::string msg) { std::cerr << msg << std::endl; } 95 | }; 96 | 97 | /*! Represents an expression. */ 98 | class Expression : public Node 99 | { 100 | public: 101 | virtual ~Expression() = default; 102 | std::string toString() override { return "Expression"; } 103 | void Accept(Visitor &v) override { v.VisitExpression(this); } 104 | }; 105 | 106 | /*! Represents a statement. */ 107 | class Statement : public Expression 108 | { 109 | public: 110 | virtual ~Statement() = default; 111 | NodeType getType() override { return NodeType::expression; } 112 | std::string toString() override { return "Statement"; } 113 | void Accept(Visitor &v) override { v.VisitStatement(this); } 114 | }; 115 | 116 | /*! Represents an integer. */ 117 | class Integer : public Expression 118 | { 119 | public: 120 | explicit Integer(long long value) : value(value) {} 121 | virtual ~Integer() = default; 122 | llvm::Value *codeGen(CodeGenContext &context) override; 123 | NodeType getType() override { return NodeType::integer; } 124 | std::string toString() override 125 | { 126 | std::stringstream s; 127 | s << "integer: " << value; 128 | return s.str(); 129 | } 130 | void Accept(Visitor &v) override { v.VisitInteger(this); } 131 | 132 | private: 133 | long long value{0}; 134 | }; 135 | 136 | /*! Represents a double. */ 137 | class Double : public Expression 138 | { 139 | public: 140 | explicit Double(double value) : value(value) {} 141 | virtual ~Double() = default; 142 | llvm::Value *codeGen(CodeGenContext &context) override; 143 | NodeType getType() override { return NodeType::decimal; } 144 | std::string toString() override 145 | { 146 | std::stringstream s; 147 | s << "double: " << value; 148 | return s.str(); 149 | } 150 | void Accept(Visitor &v) override { v.VisitDouble(this); } 151 | 152 | private: 153 | double value{0.}; 154 | }; 155 | 156 | /*! Represents a string. */ 157 | class String : public Expression 158 | { 159 | public: 160 | explicit String(const std::string &value) : value(value) {} 161 | virtual ~String() = default; 162 | llvm::Value *codeGen(CodeGenContext &context) override; 163 | NodeType getType() override { return NodeType::string; } 164 | std::string toString() override 165 | { 166 | std::stringstream s; 167 | s << "string: '" << value << "'"; 168 | return s.str(); 169 | } 170 | void Accept(Visitor &v) override { v.VisitString(this); } 171 | 172 | private: 173 | std::string value; 174 | }; 175 | 176 | /*! Represents a boolean. */ 177 | class Boolean : public Expression 178 | { 179 | public: 180 | explicit Boolean(int const value) : boolVal(value) {} 181 | virtual ~Boolean() = default; 182 | llvm::Value *codeGen(CodeGenContext &context) override; 183 | NodeType getType() override { return NodeType::boolean; } 184 | std::string toString() override 185 | { 186 | std::stringstream s; 187 | s << "boolean: " << (boolVal == 1 ? "true" : "false"); 188 | return s.str(); 189 | } 190 | void Accept(Visitor &v) override { v.VisitBoolean(this); } 191 | 192 | private: 193 | int boolVal{0}; 194 | }; 195 | 196 | /*! Represents an identifier. */ 197 | class Identifier : public Expression 198 | { 199 | public: 200 | Identifier(const std::string &name, YYLTYPE loc) 201 | : name(name), location(loc) {} 202 | Identifier(const std::string &structName, const std::string &name, 203 | YYLTYPE loc) 204 | : name(name), structName(structName), location(loc) {} 205 | Identifier(const Identifier &id) 206 | : name(id.name), structName(id.structName), location(id.location) {} 207 | virtual ~Identifier() = default; 208 | 209 | llvm::Value *codeGen(CodeGenContext &context) override; 210 | NodeType getType() override { return NodeType::identifier; } 211 | std::string toString() override 212 | { 213 | std::stringstream s; 214 | s << "identifier reference: " << structName << "::" << name; 215 | return s.str(); 216 | } 217 | void Accept(Visitor &v) override { v.VisitIdentifier(this); } 218 | 219 | std::string getName() const { return name; } 220 | std::string getStructName() const { return structName; } 221 | YYLTYPE getLocation() const { return location; } 222 | 223 | private: 224 | std::string name; 225 | std::string structName; 226 | YYLTYPE location; 227 | }; 228 | 229 | /*! Represents a block */ 230 | class Block : public Expression 231 | { 232 | public: 233 | StatementList statements; 234 | 235 | Block() = default; 236 | virtual ~Block() 237 | { 238 | for (auto i : statements) 239 | { 240 | delete i; 241 | } 242 | statements.clear(); 243 | } 244 | 245 | llvm::Value *codeGen(CodeGenContext &context) override; 246 | NodeType getType() override { return NodeType::expression; } 247 | std::string toString() override { return "block "; } 248 | void Accept(Visitor &v) override { v.VisitBlock(this); } 249 | }; 250 | 251 | /*! Represents a expression statement. */ 252 | class ExpressionStatement : public Statement 253 | { 254 | public: 255 | explicit ExpressionStatement(Expression *expression) 256 | : expression(expression) {} 257 | virtual ~ExpressionStatement() { delete expression; } 258 | 259 | llvm::Value *codeGen(CodeGenContext &context) override; 260 | NodeType getType() override { return NodeType::expression; } 261 | Expression *getExpression() { return expression; } 262 | std::string toString() override { return "expression statement "; } 263 | void Accept(Visitor &v) override { v.VisitExpressionStatement(this); } 264 | 265 | private: 266 | Expression *expression{nullptr}; 267 | }; 268 | 269 | } // namespace hana 270 | 271 | #endif 272 | -------------------------------------------------------------------------------- /Hana/Visitor/VisitorPrettyPrint.cpp: -------------------------------------------------------------------------------- 1 | #include "VisitorPrettyPrint.h" 2 | #include "Ast/AstNode.h" 3 | #include "CodeGen/Return.h" 4 | #include "CodeGen/FunctionDeclaration.h" 5 | #include "CodeGen/ClassDeclaration.h" 6 | #include "CodeGen/Conditional.h" 7 | #include "CodeGen/UnaryOperator.h" 8 | #include "CodeGen/BinaryOperator.h" 9 | #include "CodeGen/Assignment.h" 10 | #include "CodeGen/MethodCall.h" 11 | #include "CodeGen/Declaration.h" 12 | #include "CodeGen/WhileLoop.h" 13 | #include "CodeGen/Array.h" 14 | #include "CodeGen/CompareOperator.h" 15 | #include "CodeGen/Range.h" 16 | 17 | namespace hana 18 | { 19 | 20 | static inline std::string indent_spaces(size_t indent) 21 | { 22 | return std::string(indent * 2u, ' '); 23 | } 24 | 25 | void VisitorPrettyPrint::VisitExpression(Expression *expr) 26 | { 27 | out << indent_spaces(indent) << "Create " << expr->toString() << std::endl; 28 | } 29 | 30 | void VisitorPrettyPrint::VisitStatement(Statement *stmt) 31 | { 32 | out << indent_spaces(indent) << "Create " << stmt->toString() << std::endl; 33 | } 34 | 35 | void VisitorPrettyPrint::VisitReturnStatement(Return *retstmt) 36 | { 37 | out << indent_spaces(indent) << "Create " << retstmt->toString() << std::endl; 38 | if (retstmt->getRetExpression() != nullptr) 39 | { 40 | ++indent; 41 | retstmt->getRetExpression()->Accept(*this); 42 | --indent; 43 | } 44 | } 45 | 46 | void VisitorPrettyPrint::VisitFunctionDeclaration(FunctionDeclaration *fndecl) 47 | { 48 | out << indent_spaces(indent) << "Create " << fndecl->toString() << std::endl; 49 | ++indent; 50 | auto parameter = fndecl->getParameter(); 51 | if (parameter->size()) 52 | { 53 | out << indent_spaces(indent) << "Parameters :" << std::endl; 54 | ++indent; 55 | for (auto decl : *parameter) 56 | { 57 | out << indent_spaces(indent) << decl->getVariablenTypeName() << " " << decl->getVariablenName() << std::endl; 58 | } 59 | --indent; 60 | } 61 | 62 | auto body = fndecl->getBody(); 63 | for (auto stmt : body->statements) 64 | { 65 | stmt->Accept(*this); 66 | } 67 | --indent; 68 | } 69 | 70 | void VisitorPrettyPrint::VisitConditional(Conditional *cmp) 71 | { 72 | out << indent_spaces(indent) << "Create " << cmp->toString() << std::endl; 73 | ++indent; 74 | cmp->getCompOperator()->Accept(*this); 75 | if (cmp->getThen()) 76 | { 77 | cmp->getThen()->Accept(*this); 78 | } 79 | if (cmp->getElse()) 80 | { 81 | cmp->getElse()->Accept(*this); 82 | } 83 | --indent; 84 | } 85 | 86 | void VisitorPrettyPrint::VisitInteger(Integer *expr) 87 | { 88 | out << indent_spaces(indent) << "Create " << expr->toString() << std::endl; 89 | } 90 | 91 | void VisitorPrettyPrint::VisitDouble(Double *expr) 92 | { 93 | out << indent_spaces(indent) << "Create " << expr->toString() << std::endl; 94 | } 95 | 96 | void VisitorPrettyPrint::VisitString(String *expr) 97 | { 98 | out << indent_spaces(indent) << "Create " << expr->toString() << std::endl; 99 | } 100 | 101 | void VisitorPrettyPrint::VisitBoolean(Boolean *expr) 102 | { 103 | out << indent_spaces(indent) << "Create " << expr->toString() << std::endl; 104 | } 105 | 106 | void VisitorPrettyPrint::VisitIdentifier(Identifier *expr) 107 | { 108 | out << indent_spaces(indent) << "Create " << expr->toString() << std::endl; 109 | } 110 | 111 | void VisitorPrettyPrint::VisitUnaryOperator(UnaryOperator *expr) 112 | { 113 | out << indent_spaces(indent) << "Create " << expr->toString() << std::endl; 114 | ++indent; 115 | expr->getRHS()->Accept(*this); 116 | --indent; 117 | } 118 | 119 | void VisitorPrettyPrint::VisitBinaryOp(BinaryOp *expr) 120 | { 121 | out << indent_spaces(indent) << "Create " << expr->toString() << std::endl; 122 | ++indent; 123 | expr->getLHS()->Accept(*this); 124 | expr->getRHS()->Accept(*this); 125 | --indent; 126 | } 127 | 128 | void VisitorPrettyPrint::VisitCompOperator(CompOperator *expr) 129 | { 130 | out << indent_spaces(indent) << "Create " << expr->toString() << std::endl; 131 | expr->getLHS()->Accept(*this); 132 | expr->getRHS()->Accept(*this); 133 | } 134 | 135 | void VisitorPrettyPrint::VisitBlock(Block *expr) 136 | { 137 | out << indent_spaces(indent) << "Create " << expr->toString() << std::endl; 138 | ++indent; 139 | for (auto stmt : expr->statements) 140 | { 141 | stmt->Accept(*this); 142 | } 143 | --indent; 144 | out << indent_spaces(indent) << "End " << expr->toString() << std::endl; 145 | } 146 | 147 | void VisitorPrettyPrint::VisitExpressionStatement(ExpressionStatement *expr) 148 | { 149 | out << indent_spaces(indent) << "Create " << expr->toString() << std::endl; 150 | ++indent; 151 | expr->getExpression()->Accept(*this); 152 | --indent; 153 | } 154 | 155 | void VisitorPrettyPrint::VisitAssigment(Assignment *expr) 156 | { 157 | out << indent_spaces(indent) << "Create " << expr->toString() << std::endl; 158 | ++indent; 159 | expr->getExpression()->Accept(*this); 160 | --indent; 161 | } 162 | 163 | void VisitorPrettyPrint::VisitMethodCall(MethodCall *expr) 164 | { 165 | out << indent_spaces(indent) << "Create " << expr->toString() << std::endl; 166 | ++indent; 167 | auto args = expr->getArguments(); 168 | if (args->size()) 169 | { 170 | out << indent_spaces(indent) << "Arguments are:\n"; 171 | for (auto arg : *args) 172 | { 173 | arg->Accept(*this); 174 | } 175 | } 176 | --indent; 177 | } 178 | 179 | void VisitorPrettyPrint::VisitVariablenDeclaration(VariableDeclaration *expr) 180 | { 181 | out << indent_spaces(indent) << "Create " << expr->toString() << std::endl; 182 | if (expr->hasAssignmentExpr()) 183 | { 184 | ++indent; 185 | expr->getAssignment()->Accept(*this); 186 | --indent; 187 | } 188 | } 189 | 190 | void VisitorPrettyPrint::VisitWhileLoop(WhileLoop *expr) 191 | { 192 | out << indent_spaces(indent) << "Create " << expr->toString() << std::endl; 193 | ++indent; 194 | expr->getCondition()->Accept(*this); 195 | out << indent_spaces(indent) << "Create Loop Body" << std::endl; 196 | expr->getLoopBlock()->Accept(*this); 197 | auto elseBlock = expr->getElseBlock(); 198 | if (elseBlock) 199 | { 200 | out << indent_spaces(indent) << "Create Else Body" << std::endl; 201 | elseBlock->Accept(*this); 202 | } 203 | --indent; 204 | } 205 | 206 | void VisitorPrettyPrint::VisitClassDeclaration(ClassDeclaration *expr) 207 | { 208 | out << indent_spaces(indent) << "Create " << expr->toString() << std::endl; 209 | ++indent; 210 | auto block = expr->getBlock(); 211 | if (block) 212 | { 213 | block->Accept(*this); 214 | } 215 | --indent; 216 | } 217 | 218 | void VisitorPrettyPrint::VisitArray(Array *expr) 219 | { 220 | out << indent_spaces(indent) << "Create array " << expr->toString() << std::endl; 221 | ++indent; 222 | for (auto e : *expr->getExpressions()) 223 | { 224 | e->Accept(*this); 225 | } 226 | --indent; 227 | } 228 | 229 | void VisitorPrettyPrint::VisitArrayAccess(ArrayAccess *expr) 230 | { 231 | out << indent_spaces(indent) << "Create " << expr->toString() << " to element " << expr->index << std::endl; 232 | ++indent; 233 | if (expr->other != nullptr) 234 | { 235 | expr->other->Accept(*this); 236 | } 237 | --indent; 238 | } 239 | 240 | void VisitorPrettyPrint::VisitArrayAddElement(ArrayAddElement *expr) 241 | { 242 | out << indent_spaces(indent) << "Create " << expr->toString() << " of " << expr->getExpression()->toString() << " to array " << expr->ident->getName() << std::endl; 243 | ++indent; 244 | if (expr->getExpression()) 245 | { 246 | expr->getExpression()->Accept(*this); 247 | } 248 | --indent; 249 | } 250 | 251 | void VisitorPrettyPrint::VisitRange(Range *expr) 252 | { 253 | out << indent_spaces(indent) << "Create " << expr->toString() << std::endl; 254 | ++indent; 255 | if (expr->begin != nullptr) 256 | { 257 | expr->begin->Accept(*this); 258 | } 259 | if (expr->end != nullptr) 260 | { 261 | expr->end->Accept(*this); 262 | } 263 | --indent; 264 | } 265 | 266 | } 267 | -------------------------------------------------------------------------------- /Hana/tokens.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include 4 | #include "Ast/AstNode.h" 5 | #include "parser.hpp" 6 | #define SAVE_TOKEN yylval.string = new std::string(yytext, yyleng) 7 | #define SAVE_INTEGER yylval.integer = std::stoll(std::string(yytext, yyleng)) 8 | #define SAVE_NUMBER yylval.number = std::stod(std::string(yytext, yyleng)) 9 | #define SAVE_BOOLEAN yylval.boolean = std::string(yytext, yyleng) == "true" ? 1 : 0 10 | #define TOKEN(t) (yylval.token = t) 11 | 12 | #ifdef _MSC_VER 13 | int isatty(int) {return 0;}; 14 | #endif 15 | 16 | extern "C" int yywrap() { return 1; } 17 | 18 | int yycolumn = 1; 19 | 20 | #define YYERROR_VERBOSE 1 21 | int yyerror(char const * s ) 22 | { 23 | printf("ERROR %s in '%s' at line %d col %d\n", s, yytext, yylineno, yycolumn); 24 | printf(" parsed %s %d.%d-%d.%d\n", yylloc.file_name.c_str(), yylloc.first_line, yylloc.first_column, yylloc.last_line, yylloc.last_column); 25 | return 1; 26 | } 27 | 28 | std::string g_str; 29 | 30 | /* Globals to track current indentation */ 31 | int current_line_indent = 0; /* Indentation of the current line */ 32 | int indent_level = 0; /* Indentation level passed to the parser */ 33 | std::stack curr_indents; 34 | int first_time = 1 ; 35 | 36 | int parsing_error = 0; 37 | 38 | std::stack fileNames; 39 | std::stack lineNo; 40 | std::vector libPaths; 41 | 42 | #define YY_USER_ACTION do { \ 43 | if( yylloc.last_line < yylineno ) yycolumn = 1 ; \ 44 | yylloc.first_line = yylloc.last_line = yylineno; \ 45 | yylloc.first_column = yycolumn; yylloc.last_column = yycolumn + (int)yyleng - 1; \ 46 | yycolumn += (int)yyleng; \ 47 | yylloc.file_name = fileNames.top(); \ 48 | } while(0) ; 49 | 50 | %} 51 | 52 | %option yylineno 53 | 54 | %x indent 55 | %s normal 56 | %x str qstr 57 | %x comment 58 | %x req 59 | 60 | dig [0-9] 61 | num1 [-+]?{dig}+\.([eE][-+]?{dig}+)? 62 | num2 [-+]?{dig}*\.{dig}+([eE][-+]?{dig}+)? 63 | number {num1}|{num2} 64 | 65 | %% 66 | 67 | if( first_time ) { 68 | first_time = 0; 69 | curr_indents.push(0); 70 | lineNo.push(yylineno); 71 | BEGIN indent; 72 | } 73 | 74 | 75 | require BEGIN(req); 76 | [ \t]* /* Rm Whitespace */ 77 | [^ \t\n\r]+ { /* Get Filename */ 78 | std::string fileName = yytext; 79 | std::size_t pos = fileName.find(".hana"); 80 | if( pos == std::string::npos ) { 81 | fileName += ".hana"; 82 | } 83 | for( auto libpath : libPaths ) { 84 | yyin = fopen( (libpath + fileName).c_str() , "r" ); 85 | if( yyin ) 86 | break; 87 | } 88 | if ( ! yyin ) { 89 | printf( "%s in %s line %d\n", (std::string("Failed to load import file ") + fileName).c_str(), fileNames.top().c_str(), yylineno ); 90 | parsing_error = 1; 91 | yyterminate(); 92 | } else { 93 | fileNames.push(yytext); 94 | lineNo.push(yylineno); 95 | yylineno = yycolumn = 1; 96 | yylloc.first_line = yylloc.first_column = yylloc.last_line = yylloc.last_column = 1; 97 | yypush_buffer_state(yy_create_buffer( yyin, YY_BUF_SIZE )); 98 | } 99 | BEGIN(normal); 100 | } 101 | 102 | 103 | \-\-\[\[ BEGIN(comment); 104 | \-\-\]\].* BEGIN(normal); 105 | .* ;/* Eat */ 106 | \n ;/* Eat */ 107 | 108 | \" g_str = ""; BEGIN(str); 109 | ' g_str = ""; BEGIN(qstr); 110 | 111 | \" { BEGIN(normal); 112 | yylval.string = new std::string(g_str); 113 | return TSTR; 114 | } 115 | ' { BEGIN(normal); 116 | yylval.string = new std::string(g_str); 117 | return TSTR; 118 | } 119 | 120 | \\n g_str += "\n"; 121 | \\t g_str += "\t"; 122 | \\r g_str += "\r"; 123 | \\\" g_str += "\""; 124 | \\\' g_str += "'"; 125 | 126 | \\(.|\n) g_str += yytext[1]; 127 | 128 | [^\\\"]+ g_str += std::string(yytext); 129 | [^\\']+ g_str += std::string(yytext); 130 | 131 | " " { current_line_indent++; } 132 | "\t" { current_line_indent = (current_line_indent + 8) & ~7; } 133 | "\n" { current_line_indent = 0; yycolumn = 1;/*ignoring blank line */ } 134 | "\r" { current_line_indent = 0; yycolumn = 1;/*ignoring blank line */ } 135 | . { 136 | unput(*yytext); 137 | yycolumn--; 138 | if (current_line_indent > curr_indents.top()) { 139 | curr_indents.push(current_line_indent); 140 | return TOKEN(INDENT); 141 | } else if (current_line_indent < curr_indents.top()) { 142 | curr_indents.pop(); 143 | return TOKEN(UNINDENT); 144 | } else { 145 | BEGIN(normal); 146 | } 147 | } 148 | 149 | "\n" { current_line_indent = 0; BEGIN( indent); yycolumn = 1; } 150 | <> { 151 | if( curr_indents.size() > 1 ) { 152 | curr_indents.pop(); 153 | return TOKEN(UNINDENT); 154 | } 155 | if(lineNo.size() > 1 ) { 156 | yypop_buffer_state(); 157 | fileNames.pop(); 158 | yylineno = lineNo.top(); 159 | lineNo.pop(); 160 | } else { 161 | yyterminate(); 162 | } 163 | } 164 | 165 | 166 | \r /* Ignore Carriage return */ 167 | "if" return TOKEN(TIF); 168 | "else" return TOKEN(TELSE); 169 | "return" return TOKEN(TRETURN); 170 | "not" return TOKEN(TNOT); 171 | "and" return TOKEN(TAND); 172 | "or" return TOKEN(TOR); 173 | "block" return TOKEN(TDEF); 174 | "let" return TOKEN(TVAR); 175 | "wloop" return TOKEN(TWHILE); 176 | "true" SAVE_BOOLEAN; return TBOOL; 177 | "false" SAVE_BOOLEAN; return TBOOL; 178 | --.* /* Single line comment */ 179 | [ \t\n] /* Ignore */; 180 | [a-zA-Z_][a-zA-Z0-9_&%\$\?\-]* SAVE_TOKEN; return TIDENTIFIER; 181 | -?[0-9]+ SAVE_INTEGER; return TINTEGER; 182 | {number} SAVE_NUMBER; return TDOUBLE; 183 | "->" return TOKEN(TRANGE); 184 | "::" return TOKEN(TRANGE); 185 | "=" return '='; 186 | "==" return TOKEN(TCEQ); 187 | "!=" return TOKEN(TCNE); 188 | "<<" return TOKEN(TLTLT); 189 | "<" return TOKEN(TCLT); 190 | "<=" return TOKEN(TCLE); 191 | ">" return TOKEN(TCGT); 192 | ">=" return TOKEN(TCGE); 193 | "(" return '('; 194 | ")" return ')'; 195 | "." return '.'; 196 | "," return ','; 197 | "+" return TOKEN(TPLUS); 198 | "-" return TOKEN(TMINUS); 199 | "*" return TOKEN(TMUL); 200 | "/" return TOKEN(TDIV); 201 | ":" return ':'; 202 | "[" return '['; 203 | "]" return ']'; 204 | . printf("[*] Error: At line %d, len %d Unknown token '%s' !\n", yylineno, yyleng, yytext); yyterminate(); 205 | 206 | %% 207 | -------------------------------------------------------------------------------- /Hana/parser.y: -------------------------------------------------------------------------------- 1 | %code requires { 2 | 3 | # define YYLTYPE_IS_DECLARED 1 4 | 5 | } 6 | 7 | %{ 8 | #include "Ast/AstNode.h" 9 | #include "CodeGen/FunctionDeclaration.h" 10 | #include "CodeGen/ClassDeclaration.h" 11 | #include "CodeGen/Return.h" 12 | #include "CodeGen/FunctionDeclaration.h" 13 | #include "CodeGen/ClassDeclaration.h" 14 | #include "CodeGen/Conditional.h" 15 | #include "CodeGen/UnaryOperator.h" 16 | #include "CodeGen/BinaryOperator.h" 17 | #include "CodeGen/CompareOperator.h" 18 | #include "CodeGen/Assignment.h" 19 | #include "CodeGen/MethodCall.h" 20 | #include "CodeGen/Declaration.h" 21 | #include "CodeGen/WhileLoop.h" 22 | #include "CodeGen/Array.h" 23 | #include "CodeGen/Range.h" 24 | 25 | #include 26 | #include 27 | hana::Block *programBlock; /* Root node of our final AST */ 28 | 29 | extern int yylex(); 30 | int yyerror(char const * s ); 31 | #define YYERROR_VERBOSE 32 | #define YYDEBUG 1 33 | 34 | extern std::stack fileNames; 35 | 36 | # define YYLLOC_DEFAULT(Current, Rhs, N) \ 37 | do \ 38 | if (N) \ 39 | { \ 40 | (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ 41 | (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ 42 | (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ 43 | (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ 44 | (Current).file_name = fileNames.top(); \ 45 | } \ 46 | else \ 47 | { \ 48 | (Current).first_line = (Current).last_line = \ 49 | YYRHSLOC (Rhs, 0).last_line; \ 50 | (Current).first_column = (Current).last_column = \ 51 | YYRHSLOC (Rhs, 0).last_column; \ 52 | (Current).file_name = fileNames.top(); \ 53 | } \ 54 | while (0) 55 | 56 | %} 57 | 58 | /* Represents the many different ways we can access our data */ 59 | %union { 60 | hana::Node *node; 61 | hana::Block *block; 62 | hana::Expression *expr; 63 | hana::Statement *stmt; 64 | hana::Identifier *ident; 65 | hana::VariableDeclaration *var_decl; 66 | std::vector *varvec; 67 | std::vector *exprvec; 68 | std::string *string; 69 | long long integer; 70 | double number; 71 | int boolean; 72 | int token; 73 | } 74 | 75 | /* Define our terminal symbols (tokens). This should 76 | match our tokens.l lex file. We also define the node type 77 | they represent. 78 | */ 79 | %token TIDENTIFIER TSTR 80 | %token TINTEGER 81 | %token TDOUBLE 82 | %token TBOOL 83 | %token TCEQ TCNE TCLT TCLE TCGT TCGE 84 | %token TLTLT "<<" 85 | %token TRANGE 86 | %token TPLUS TMINUS TMUL TDIV 87 | %token TNOT TAND TOR 88 | %token TIF TELSE TWHILE 89 | %token TDEF TRETURN TVAR 90 | %token INDENT UNINDENT 91 | 92 | /* Define the type of node our nonterminal symbols represent. 93 | The types refer to the %union declaration above. Ex: when 94 | we call an ident (defined by union type ident) we are really 95 | calling an (Identifier*). It makes the compiler happy. 96 | */ 97 | %type ident 98 | %type literals expr boolean_expr binop_expr unaryop_expr array_expr array_access range_expr 99 | %type func_decl_args 100 | %type call_args array_elemets_expr 101 | %type program stmts block 102 | %type stmt var_decl func_decl conditional return while class_decl array_add_element 103 | %type comparison 104 | 105 | /* Operator precedence for mathematical operators */ 106 | %left TPLUS TMINUS 107 | %left TMUL TDIV 108 | %left TAND TNOT 109 | 110 | %start program 111 | %debug 112 | %verbose 113 | %locations /* track locations: @n of component N; @$ of entire range */ 114 | /* 115 | %define parse.lac full 116 | %define lr.type ielr 117 | */ 118 | 119 | %% 120 | 121 | program : %empty { programBlock = new hana::Block(); } 122 | | stmts { programBlock = $1; } 123 | ; 124 | 125 | stmts : stmt { $$ = new hana::Block(); $$->statements.push_back($1); } 126 | | stmts stmt { $1->statements.push_back($2); } 127 | ; 128 | 129 | stmt : var_decl 130 | | func_decl 131 | | class_decl 132 | | conditional 133 | | return 134 | | while 135 | | array_add_element 136 | | expr { $$ = new hana::ExpressionStatement($1); } 137 | ; 138 | 139 | block : INDENT stmts UNINDENT { $$ = $2; } 140 | | INDENT UNINDENT { $$ = new hana::Block(); } 141 | ; 142 | 143 | conditional : TIF expr block TELSE block {$$ = new hana::Conditional($2,$3,$5);} 144 | | TIF expr block {$$ = new hana::Conditional($2,$3);} 145 | ; 146 | 147 | while : TWHILE expr block TELSE block {$$ = new hana::WhileLoop($2,$3,$5);} 148 | | TWHILE expr block {$$ = new hana::WhileLoop($2,$3);} 149 | ; 150 | 151 | var_decl : ident ident { $$ = new hana::VariableDeclaration($1, $2, @$); } 152 | | ident ident '=' expr { $$ = new hana::VariableDeclaration($1, $2, $4, @$); } 153 | | TVAR ident { $$ = new hana::VariableDeclaration($2, @$); } 154 | | TVAR ident '=' expr { $$ = new hana::VariableDeclaration($2, $4, @$); } 155 | ; 156 | 157 | func_decl : TDEF ident '(' func_decl_args ')' ':' ident block { $$ = new hana::FunctionDeclaration($7, $2, $4, $8, @$); } 158 | | TDEF ident '(' func_decl_args ')' block { $$ = new hana::FunctionDeclaration($2, $4, $6, @$); } 159 | ; 160 | 161 | func_decl_args : %empty { $$ = new hana::VariableList(); } 162 | | var_decl { $$ = new hana::VariableList(); $$->push_back($1); } 163 | | func_decl_args ',' var_decl { $1->push_back($3); } 164 | ; 165 | 166 | class_decl: TDEF ident block {$$ = new hana::ClassDeclaration($2, $3); } 167 | ; 168 | 169 | return : TRETURN { $$ = new hana::Return(@$); } 170 | | TRETURN expr { $$ = new hana::Return(@$, $2); } 171 | ; 172 | 173 | expr : ident '=' expr { $$ = new hana::Assignment($1, $3, @$); } 174 | | ident '(' call_args ')' { $$ = new hana::MethodCall($1, $3, @$); } 175 | | ident { $$ = $1; } 176 | | literals 177 | | boolean_expr 178 | | binop_expr 179 | | unaryop_expr 180 | | '(' expr ')' { $$ = $2; } 181 | | range_expr 182 | | array_expr 183 | | array_access 184 | ; 185 | 186 | ident : TIDENTIFIER { $$ = new hana::Identifier(*$1, @1); delete $1; } 187 | | TIDENTIFIER '.' TIDENTIFIER { $$ = new hana::Identifier(*$1,*$3, @$); delete $1; delete $3;} 188 | ; 189 | 190 | literals : TINTEGER { $$ = new hana::Integer($1); } 191 | | TDOUBLE { $$ = new hana::Double($1); } 192 | | TSTR { $$ = new hana::String(*$1); delete $1; } 193 | | TBOOL { $$ = new hana::Boolean($1); } 194 | ; 195 | 196 | /* have to write it explicit to have the right operator precedence */ 197 | binop_expr : expr TAND expr { $$ = new hana::BinaryOp($1, $2, $3, @$); } 198 | | expr TOR expr { $$ = new hana::BinaryOp($1, $2, $3, @$); } 199 | | expr TPLUS expr { $$ = new hana::BinaryOp($1, $2, $3, @$); } 200 | | expr TMINUS expr { $$ = new hana::BinaryOp($1, $2, $3, @$); } 201 | | expr TMUL expr { $$ = new hana::BinaryOp($1, $2, $3, @$); } 202 | | expr TDIV expr { $$ = new hana::BinaryOp($1, $2, $3, @$); } 203 | ; 204 | 205 | unaryop_expr : TNOT expr { $$ = new hana::UnaryOperator($1, $2); } 206 | ; 207 | 208 | boolean_expr : expr comparison expr { $$ = new hana::CompOperator($1, $2, $3); } 209 | ; 210 | 211 | call_args : %empty { $$ = new hana::ExpressionList(); } 212 | | expr { $$ = new hana::ExpressionList(); $$->push_back($1); } 213 | | call_args ',' expr { $1->push_back($3); } 214 | ; 215 | 216 | comparison : TCEQ | TCNE | TCLT | TCLE | TCGT | TCGE 217 | ; 218 | 219 | array_elemets_expr: %empty {$$ = new hana::ExpressionList(); } 220 | | expr {$$ = new hana::ExpressionList(); $$->push_back($1);} 221 | | array_elemets_expr ',' expr {$$->push_back($3); } 222 | ; 223 | 224 | array_expr : '[' array_elemets_expr ']' {$$ = new hana::Array($2, @$);} 225 | ; 226 | 227 | array_add_element: ident "<<" expr { $$ = new hana::ArrayAddElement($1, $3, @$); } 228 | ; 229 | 230 | array_access: ident '[' TINTEGER ']' { $$ = new hana::ArrayAccess($1, $3, @$); } 231 | | array_access '[' TINTEGER ']' { $$ = new hana::ArrayAccess($1, $3, @$); } 232 | ; 233 | 234 | range_expr : '[' expr TRANGE expr ']' {$$ = new hana::Range($2, $4, @$);} 235 | ; 236 | 237 | %% 238 | -------------------------------------------------------------------------------- /Hana/CodeGen/FunctionDeclaration.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if defined(_MSC_VER) 4 | #pragma warning(push, 0) 5 | #endif 6 | 7 | #include "llvm/Transforms/Utils/Cloning.h" 8 | 9 | #if defined(_MSC_VER) 10 | #pragma warning(pop) 11 | #endif 12 | 13 | #include "CodeGenContext.h" 14 | #include "parser.hpp" 15 | #include "FunctionDeclaration.h" 16 | #include "Declaration.h" 17 | 18 | using namespace std; 19 | using namespace llvm; 20 | 21 | namespace hana 22 | { 23 | 24 | FunctionDeclaration::FunctionDeclaration(const FunctionDeclaration &other) 25 | { 26 | type = new Identifier(*other.type); 27 | id = new Identifier(*other.id); 28 | arguments = new VariableList(); 29 | for (auto arg : *other.arguments) 30 | { 31 | arguments->push_back(new VariableDeclaration(new Identifier(arg->getVariablenTypeName(), arg->getLocation()), new Identifier(arg->getVariablenName(), arg->getLocation()), arg->getLocation())); 32 | } 33 | block = other.block; 34 | location = other.location; 35 | isaCopy = true; // Quick hack, a copy contains the origin block and shouldn't be deleted. 36 | } 37 | 38 | FunctionDeclaration::FunctionDeclaration(Identifier *type, Identifier *id, VariableList *arguments, Block *block, YYLTYPE loc) 39 | : type(type), id(id), arguments(arguments), block(block), location(loc) 40 | { 41 | checkForTemplateParameter(); 42 | } 43 | 44 | FunctionDeclaration::FunctionDeclaration(Identifier *id, VariableList *arguments, Block *block, YYLTYPE loc) 45 | : type(new Identifier("var", loc)), id(id), arguments(arguments), block(block), location(loc) 46 | { 47 | checkForTemplateParameter(); 48 | } 49 | 50 | FunctionDeclaration::~FunctionDeclaration() 51 | { 52 | for (auto i : *arguments) 53 | { 54 | delete i; 55 | } 56 | delete type; 57 | delete id; 58 | delete arguments; 59 | if (!isaCopy) 60 | { // Don't delete the origin block 61 | delete block; 62 | } 63 | } 64 | 65 | void FunctionDeclaration::checkForTemplateParameter() 66 | { 67 | auto found = std::find_if(std::begin(*arguments), std::end(*arguments), [](auto vardecl) 68 | { return vardecl->getVariablenTypeName() == "var"; }); 69 | if (found != std::end(*arguments)) 70 | { 71 | hasTemplateParameter = true; 72 | } 73 | } 74 | 75 | Value *FunctionDeclaration::codeGen(CodeGenContext &context) 76 | { 77 | if (hasTemplateParameter && !context.codeGenTheTemplatedFunction()) 78 | { 79 | // This function declaration has at least one unknown parameter type. 80 | // Postpone the creation until they are known (call). 81 | context.addTemplateFunction(id->getName(), this); 82 | return nullptr; 83 | } 84 | 85 | vector argTypes; 86 | if (!context.getKlassName().empty()) 87 | { 88 | // add the self pointer of the class as first argument.. 89 | Type *self_ty = context.typeOf(context.getKlassName()); 90 | argTypes.push_back(PointerType::get(self_ty, 0)); 91 | } 92 | 93 | for (auto varDecl : *arguments) 94 | { 95 | Type *ty = context.typeOf(varDecl->getIdentifierOfVariablenType()); 96 | if (ty->isStructTy()) 97 | { 98 | ty = PointerType::get(ty, 0); 99 | } 100 | argTypes.push_back(ty); 101 | } 102 | 103 | // TODO check return type if it is a structure type !!! May be it should be a ptr to the structure! 104 | FunctionType *ftype = FunctionType::get(context.typeOf(*type), argTypes, false); 105 | std::string functionName = id->getName(); 106 | if (type->getName() == "var") 107 | { 108 | functionName += "_del"; 109 | } 110 | if (!context.getKlassName().empty()) 111 | { 112 | functionName += "%" + context.getKlassName(); 113 | } 114 | Function *function = Function::Create(ftype, GlobalValue::InternalLinkage, functionName.c_str(), context.getModule()); 115 | BasicBlock *bblock = BasicBlock::Create(context.getGlobalContext(), "entry", function, 0); 116 | context.newScope(bblock, ScopeType::FunctionDeclaration); 117 | 118 | // Put the parameter onto the stack in order to be accessed in the function. 119 | Function::arg_iterator actualArgs = function->arg_begin(); 120 | // First check if a elf ptr has to be put as first argument. 121 | if (!context.getKlassName().empty()) 122 | { 123 | actualArgs->setName("this"); 124 | // Value* ptr_this = actualArgs++; 125 | Type *self_ty = context.typeOf(context.getKlassName()); 126 | Type *self_ptr_ty = PointerType::get(self_ty, 0); 127 | AllocaInst *alloca = new AllocaInst(self_ptr_ty, 0, "self_addr", context.currentBlock()); 128 | new StoreInst(&(*actualArgs) /*ptr_this*/, alloca, context.currentBlock()); 129 | context.locals()["self"] = alloca; 130 | ++actualArgs; 131 | } 132 | // Now the remaining arguments 133 | for (auto varDecl : *arguments) 134 | { 135 | AllocaInst *alloca = llvm::dyn_cast(varDecl->codeGen(context)); 136 | std::string valName = varDecl->getVariablenName(); 137 | // TODO a struct is coming as struct alloca, but needed to be a pointer to a struct alloca. 138 | if (alloca) 139 | { 140 | if (alloca->getAllocatedType()->isPointerTy()) 141 | { 142 | valName += "_addr"; 143 | } 144 | actualArgs->setName(valName); 145 | new StoreInst(&(*actualArgs), alloca, context.currentBlock()); 146 | } 147 | ++actualArgs; 148 | } 149 | 150 | // Generate the function body. 151 | auto blockValue = block->codeGen(context); 152 | if (blockValue == nullptr) 153 | { 154 | Node::printError(location, " " + id->getStructName() + "::" + id->getName() + "(): Function block returns nothing"); 155 | context.addError(); 156 | return nullptr; 157 | } 158 | auto retTy = blockValue->getType(); 159 | 160 | // If the function doesn't have a return type and doesn't have a return statement, make a ret void. 161 | // Obsolete default is var. 162 | if (type->getName() == "void") 163 | { 164 | if (context.currentBlock()->getTerminator() == nullptr) 165 | { 166 | ReturnInst::Create(context.getGlobalContext(), 0, context.currentBlock()); 167 | } 168 | } 169 | 170 | // If the now return instruction is generated so far ... 171 | if (context.currentBlock()->getTerminator() == nullptr) 172 | { 173 | if (type->getName() == "var" && !retTy->isVoidTy()) 174 | { 175 | // Generate one according to the value of the function body. 176 | ReturnInst::Create(context.getGlobalContext(), blockValue, context.currentBlock()); 177 | } 178 | else 179 | { 180 | // Or a ret void. 181 | ReturnInst::Create(context.getGlobalContext(), 0, context.currentBlock()); 182 | } 183 | } 184 | 185 | if (type->getName() == "var") 186 | { 187 | if (retTy->isLabelTy() || retTy->isMetadataTy()) 188 | { 189 | context.endScope(); 190 | Node::printError(location, "** [ERR] Function w/ var return type and multiple return statements are not supported: " + id->getName() + "(...)"); 191 | context.addError(); 192 | return nullptr; 193 | } 194 | 195 | // Now create the a new function (the real one) since we know the return type now. 196 | auto terminator = context.currentBlock()->getTerminator(); 197 | auto retInstr = dyn_cast(terminator); 198 | auto retval = retInstr->getReturnValue(); 199 | Type *retValTy = nullptr; 200 | if (retval == nullptr) 201 | { 202 | // The return instruction has no operand and no type it is a ret void. 203 | retValTy = Type::getVoidTy(context.getGlobalContext()); 204 | } 205 | else 206 | { 207 | retValTy = retval->getType(); 208 | } 209 | 210 | std::string functionNameNew = id->getName(); 211 | if (context.codeGenTheTemplatedFunction()) 212 | { 213 | // Now all types are known, check if this type of function already exist 214 | auto constructedFctName = buildFunctionName(retValTy, argTypes); 215 | auto fct = context.getModule()->getFunction(constructedFctName); 216 | if (fct != nullptr) 217 | { 218 | // Yes, take that one and remove the newly generated. 219 | function->eraseFromParent(); 220 | context.endScope(); 221 | return fct; 222 | } 223 | functionNameNew = constructedFctName; 224 | } 225 | 226 | FunctionType *ftypeNew = FunctionType::get(retValTy, argTypes, false); 227 | if (!context.getKlassName().empty()) 228 | { 229 | functionNameNew += "%" + context.getKlassName(); 230 | } 231 | 232 | Function *functionNew = Function::Create(ftypeNew, GlobalValue::InternalLinkage, functionNameNew, context.getModule()); 233 | 234 | // Create a value map for all arguments to be mapped to the new function. 235 | ValueToValueMapTy VMap; 236 | Function::arg_iterator DestI = functionNew->arg_begin(); 237 | 238 | for (Function::const_arg_iterator J = function->arg_begin(); J != function->arg_end(); ++J) 239 | { 240 | DestI->setName(J->getName()); // Copy name of argument to the argument of the new function. 241 | VMap[&*J] = &*DestI++; // Map the value 242 | } 243 | 244 | // Clone the function to the new (real) function w/ the correct return type. 245 | SmallVector Returns; // Ignore returns cloned. 246 | CloneFunctionInto(functionNew, function, VMap, false, Returns); 247 | 248 | // Remove the old one. 249 | function->eraseFromParent(); 250 | 251 | function = functionNew; 252 | } 253 | 254 | context.endScope(); 255 | return function; 256 | } 257 | 258 | std::string FunctionDeclaration::toString() 259 | { 260 | std::stringstream s; 261 | s << "function declaration: " << id->getName(); 262 | return s.str(); 263 | } 264 | 265 | std::string FunctionDeclaration::buildFunctionName(llvm::Type *retType, std::vector argTypes) 266 | { 267 | std::string constructedName = id->getName() + "_"; 268 | constructedName += std::to_string(retType->getTypeID()); 269 | for (auto t : argTypes) 270 | { 271 | constructedName += "_" + std::to_string(t->getTypeID()); 272 | } 273 | return constructedName; 274 | } 275 | 276 | } 277 | -------------------------------------------------------------------------------- /Hana/CodeGen/CodeGenContext.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "config.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #if defined(_MSC_VER) 11 | #pragma warning(push, 0) 12 | #endif 13 | 14 | #include "llvm/IR/Module.h" 15 | #include "llvm/IR/Function.h" 16 | #include "llvm/IR/Type.h" 17 | #include "llvm/IR/DerivedTypes.h" 18 | #include "llvm/IR/LLVMContext.h" 19 | #include "llvm/IR/LegacyPassManager.h" 20 | #include "llvm/IR/Instructions.h" 21 | #include "llvm/IR/CallingConv.h" 22 | #include "llvm/IR/Verifier.h" 23 | #include "llvm/IR/IRBuilder.h" 24 | #include "llvm/Support/TargetSelect.h" 25 | #include "llvm/ExecutionEngine/GenericValue.h" 26 | #include "llvm/ExecutionEngine/MCJIT.h" 27 | #include "llvm/Support/raw_ostream.h" 28 | #include 29 | 30 | #if defined(_MSC_VER) 31 | #pragma warning(pop) 32 | #endif 33 | 34 | #include "Ast/AstNode.h" 35 | 36 | namespace hana 37 | { 38 | ///< Used to keep track the context of a code block. 39 | enum class ScopeType 40 | { 41 | Class, 42 | FunctionDeclaration, 43 | CodeBlock, 44 | }; 45 | 46 | ///< Maps a variable name to its alloca instruction. 47 | using ValueNames = std::map; 48 | ///< Maps a variable name of a class definition to its position in the llvm structure type. 49 | using KlassValueNames = std::map; 50 | ///< Maps a class name to its attributes (member variables). 51 | using KlassAttributes = std::map; 52 | ///< Maps a variable name to its type name. 53 | using VariableTypeMap = std::map; 54 | ///< A set of assignments to hold the init code of class members 55 | using KlassInitCodeAssign = std::set; 56 | ///< Maps the init code to the class name. 57 | using KlassInitCode = std::map; 58 | 59 | ///< context of a scoped code block of expressions. 60 | class CodeGenBlock 61 | { 62 | public: 63 | CodeGenBlock(llvm::BasicBlock *bb) { bblock = bb; } 64 | ~CodeGenBlock() {} 65 | void setCodeBlock(llvm::BasicBlock *bb) { bblock = bb; } 66 | llvm::BasicBlock *currentBlock() { return bblock; } 67 | ValueNames &getValueNames() { return locals; } 68 | VariableTypeMap &getTypeMap() { return types; } 69 | 70 | private: 71 | llvm::BasicBlock *bblock{nullptr}; 72 | ValueNames locals; 73 | VariableTypeMap types; 74 | }; 75 | 76 | ///! The context of the current compiling process. 77 | class CodeGenContext 78 | { 79 | public: 80 | llvm::Value *varStruct{nullptr}; ///< Hold the alloc of the structure variable (class object). TODO move it to a better place. 81 | bool verbose{false}; ///< Verbose output 82 | bool debug{false}; ///< Dump the generated LLVM byte code. 83 | 84 | CodeGenContext(std::ostream &outs); 85 | ~CodeGenContext() { llvm::llvm_shutdown(); } 86 | 87 | llvm::Module *getModule() const { return module; } 88 | 89 | llvm::LLVMContext &getGlobalContext() { return llvmContext; } 90 | 91 | /*! Enters a new scope (block) 92 | * \param[in] bb The basic block containing of the new scope. If nullptr then a new block is created. 93 | * \param[in] scopeType Type of scope @see ScopeType 94 | */ 95 | void newScope(llvm::BasicBlock *bb = nullptr, ScopeType scopeType = ScopeType::CodeBlock); 96 | 97 | /*! Leaves current scope, the previous one will be active now.*/ 98 | void endScope(); 99 | 100 | /*! Return the current scope type. */ 101 | ScopeType getScopeType() { return currentScopeType; } 102 | 103 | /*! Set the LLVM block where to put the next instructions. */ 104 | void setInsertPoint(llvm::BasicBlock *bblock) { setCurrentBlock(bblock); } 105 | 106 | /*! Get the current insert block. */ 107 | llvm::BasicBlock *getInsertPoint() { return currentBlock(); } 108 | 109 | /*! Compile the AST into a module */ 110 | bool generateCode(class Block &root); 111 | 112 | /*! Executes the AST by running the main function */ 113 | llvm::GenericValue runCode(); 114 | 115 | /*! Prints how the code will be generated */ 116 | void printCodeGeneration(class Block &root, std::ostream &outs); 117 | 118 | /*! Get the local variable names (of current scope). */ 119 | ValueNames &locals() { return codeBlocks.front()->getValueNames(); } 120 | 121 | /*! Set type of a variable in current scope. 122 | * \param[in] varTypeName Variable type name. 123 | * \param[in] varName Variable name. 124 | */ 125 | void setVarType(std::string varTypeName, std::string varName) { codeBlocks.front()->getTypeMap()[varName] = varTypeName; } 126 | 127 | /*! Get the type of a variable name. 128 | * \param[in] varName the name of the variable to be looked up. 129 | * \return The name of the type. 130 | */ 131 | std::string getType(std::string varName); 132 | 133 | /*! Searches a variable name in all known locals of the current code block. 134 | * If not found it looks in the current class block, too. 135 | * \param[in] varName variable name 136 | * \return The alloca instruction 137 | */ 138 | llvm::AllocaInst *findVariable(std::string varName); 139 | 140 | /*! Deletes a variable name in all known locals of the current code block. 141 | * 142 | * \param[in] varName variable name 143 | */ 144 | void deleteVariable(std::string varName); 145 | 146 | /*! Renames a variable in all known locals of the current code block. 147 | * 148 | * \param[in] oldVarName The variable o rename 149 | * \param[in] newVarName The new name fo the variable 150 | */ 151 | void renameVariable(std::string oldVarName, std::string newVarName); 152 | 153 | /*! Returns the current code block. */ 154 | llvm::BasicBlock *currentBlock() { return codeBlocks.front()->currentBlock(); } 155 | 156 | /*! Runs the optimizer over all function */ 157 | void optimize(); 158 | 159 | /*! Creates a new class block scope. */ 160 | void newKlass(std::string name); 161 | 162 | /*! Closes a class block scope */ 163 | void endKlass(); 164 | 165 | /*! Adds a class member variable name and its index to the list of the 166 | * class attributes map. Since the access to the corresponding llvm structure 167 | * goes via the index into this structure. 168 | * \param[in] name Variable name of the current class. 169 | * \param[in] index into the llvm structure of this class. 170 | * 171 | */ 172 | void klassAddVariableAccess(std::string name, int index); 173 | 174 | /*! Returns the load/getelementptr instruction to access a class member. 175 | * \param[in] klass The class name 176 | * \param[in] name Class member name 177 | * \param[in] this_ptr The alloca instruction to be used for the getelementptr instruction. 178 | * \return Instruction pointer. 179 | * \remark Is used to access the elements via the alloca where the ptr to the ref of the class object is stored. 180 | * Means that the ref is stored in a local (stack) variable. 181 | */ 182 | llvm::Instruction *getKlassVarAccessInst(std::string klass, std::string name, llvm::AllocaInst *this_ptr); 183 | 184 | /*! Returns the currently processed class definition. */ 185 | std::string getKlassName() { return klassName; } 186 | 187 | /*! Returns an LLVM type based on the identifier */ 188 | llvm::Type *typeOf(const class Identifier &type); 189 | 190 | /*! Returns an LLVM type based on the name */ 191 | llvm::Type *typeOf(const std::string &name); 192 | 193 | /*! Returns type name based on LLVM Type */ 194 | std::string typeNameOf(llvm::Type *type); 195 | 196 | /*! Store the init code of the class to be used while creation. */ 197 | void addKlassInitCode(std::string name, Assignment *assign); 198 | 199 | /*! Returns the class init code */ 200 | KlassInitCodeAssign &getKlassInitCode(std::string name); 201 | 202 | /*! Check if a name is a class */ 203 | bool isClass(const std::string &name) { return classAttributes.find(name) != std::end(classAttributes); } 204 | 205 | /*! Associate a LLVM type with a class name. */ 206 | void addClassType(const std::string &name, llvm::Type *ty) { classTypeMap.emplace(name, ty); } 207 | 208 | /*! Look up a class name of a given LLVM type. */ 209 | std::string findClassNameByType(llvm::Type *ty); 210 | 211 | /*! Returns the LLVM integer type used by hana. */ 212 | llvm::Type *getGenericIntegerType(); 213 | 214 | /*! Preprocess the AST generated by the parser. 215 | * \param[in] root The root block of the AST. 216 | * \return true on success. 217 | */ 218 | bool preProcessing(class Block &root); 219 | 220 | /*! Increments the error counter. */ 221 | void addError() { ++errors; } 222 | 223 | /*! Add a function which has var arguments and has to be generated later at call time. 224 | * \param[in] name Function name. 225 | * \param[in] funcDecl Function declaration node. 226 | */ 227 | void addTemplateFunction(const std::string &name, FunctionDeclaration *funcDecl) { templatedFunctionDeclarations[name] = funcDecl; } 228 | 229 | /*! Returns the function declaration of the 'template' function. 230 | * \param[in] name Function name. 231 | * \note Does return nullptr if name is not found. 232 | */ 233 | FunctionDeclaration *getTemplateFunction(const std::string &name); 234 | 235 | /*! Start/End of generating a template function (args with type var). 236 | * \param[in] setFlag true: begin of generation. false: end of generation. 237 | */ 238 | void setGenerateTemplatedFunction(bool setFlag) { generateTemplatedFunction = setFlag; } 239 | 240 | /*! Returns true if a template function is to be generated otherwise false. */ 241 | bool codeGenTheTemplatedFunction() const { return generateTemplatedFunction; } 242 | 243 | private: 244 | void setCurrentBlock(llvm::BasicBlock *block) { codeBlocks.front()->setCodeBlock(block); } 245 | 246 | /*! Setup up the built in functions and types: 247 | */ 248 | void setupBuiltIns(); 249 | 250 | std::list codeBlocks; ///< List of all code blocks 251 | CodeGenBlock *self{nullptr}; ///< The current code block. 252 | std::string klassName; ///< The current class definition block 253 | llvm::Function *mainFunction{nullptr}; ///< main function 254 | llvm::Module *module{nullptr}; ///< llvm module ... 255 | llvm::LLVMContext llvmContext; ///< and context 256 | KlassAttributes classAttributes; ///< List of attributes a class 257 | KlassInitCode classInitCode; ///< The init code (statements) for each class 258 | std::map classTypeMap; ///< Maps a class name to its LLVM struct type 259 | int errors{0}; ///< Count of errors while code gen. 260 | ScopeType currentScopeType{ScopeType::CodeBlock}; 261 | std::ostream &outs; 262 | struct buildin_info_t 263 | { 264 | llvm::Function *f{nullptr}; 265 | void *addr{nullptr}; 266 | }; 267 | std::vector builtins; 268 | llvm::Type *intType{nullptr}; 269 | llvm::Type *doubleType{nullptr}; 270 | llvm::Type *stringType{nullptr}; 271 | llvm::Type *boolType{nullptr}; 272 | llvm::Type *voidType{nullptr}; 273 | llvm::Type *varType{nullptr}; 274 | std::map llvmTypeMap; 275 | std::map templatedFunctionDeclarations; 276 | bool generateTemplatedFunction{false}; 277 | }; 278 | 279 | } 280 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Hana/CodeGen/CodeGenContext.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "Ast/AstNode.h" 4 | #include "CodeGenContext.h" 5 | #include "parser.hpp" 6 | #include "llvm/Support/DynamicLibrary.h" 7 | #include "llvm/Analysis/Passes.h" 8 | #include "llvm/IR/LegacyPassManager.h" 9 | #include "llvm/Transforms/Scalar.h" 10 | #include "llvm/Transforms/IPO/PassManagerBuilder.h" 11 | #include "llvm/ExecutionEngine/Interpreter.h" 12 | #include "llvm/ExecutionEngine/MCJIT.h" 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "Lib/Stlib.h" 19 | #include "Visitor/VisitorSyntaxCheck.h" 20 | #include "Visitor/VisitorPrettyPrint.h" 21 | 22 | using namespace std; 23 | using namespace llvm; 24 | 25 | #if defined(_MSC_VER) 26 | #if defined(_M_X64) 27 | #define UseInt64 28 | #else 29 | #define UseInt32 30 | #endif 31 | #endif 32 | 33 | #if defined(__GNUC__) 34 | #if defined(__x86_64) 35 | #define UseInt64 36 | #else 37 | #define UseInt32 38 | #endif 39 | #endif 40 | 41 | namespace hana 42 | { 43 | 44 | CodeGenContext::CodeGenContext(std::ostream &outs) : outs(outs) 45 | { 46 | llvm::InitializeNativeTarget(); 47 | llvm::InitializeNativeTargetAsmParser(); 48 | llvm::InitializeNativeTargetAsmPrinter(); 49 | module = new llvm::Module("hana", llvmContext); 50 | } 51 | 52 | #define MAKE_LLVM_EXTERNAL_NAME(a) #a 53 | 54 | void CodeGenContext::setupBuiltIns() 55 | { 56 | intType = getGenericIntegerType(); 57 | doubleType = Type::getDoubleTy(getGlobalContext()); 58 | stringType = Type::getInt8PtrTy(getGlobalContext()); 59 | boolType = Type::getInt1Ty(getGlobalContext()); 60 | voidType = Type::getVoidTy(getGlobalContext()); 61 | varType = StructType::create(getGlobalContext(), "var"); 62 | llvmTypeMap["int"] = intType; 63 | llvmTypeMap["double"] = doubleType; 64 | llvmTypeMap["string"] = stringType; 65 | llvmTypeMap["boolean"] = boolType; 66 | llvmTypeMap["void"] = voidType; 67 | llvmTypeMap["var"] = varType; 68 | 69 | std::vector argTypesTwoStrings(2, stringType); 70 | FunctionType *ft = FunctionType::get(getGenericIntegerType(), argTypesTwoStrings, false); 71 | Function *f = Function::Create(ft, Function::ExternalLinkage, MAKE_LLVM_EXTERNAL_NAME(compstr), getModule()); 72 | Function::arg_iterator i = f->arg_begin(); 73 | if (i != f->arg_end()) 74 | i->setName("format_str"); 75 | builtins.push_back({f, (int *)compstr}); 76 | 77 | std::vector argTypesOneInt(1, intType); 78 | ft = FunctionType::get(intType, argTypesOneInt, false); 79 | f = Function::Create(ft, Function::ExternalLinkage, MAKE_LLVM_EXTERNAL_NAME(writeint), getModule()); 80 | // Function::arg_iterator i = f->arg_begin(); // Already defined in the above function 81 | if (i != f->arg_end()) 82 | i->setName("val"); 83 | builtins.push_back({f, (void *)writeint}); 84 | 85 | std::vector argTypesOneDouble(1, Type::getDoubleTy(getGlobalContext())); 86 | ft = FunctionType::get(Type::getDoubleTy(getGlobalContext()), argTypesOneDouble, false); 87 | f = Function::Create(ft, Function::ExternalLinkage, MAKE_LLVM_EXTERNAL_NAME(writeflt), getModule()); 88 | i = f->arg_begin(); 89 | if (i != f->arg_end()) 90 | i->setName("val"); 91 | builtins.push_back({f, (void *)writeflt}); 92 | 93 | ft = FunctionType::get(Type::getDoubleTy(getGlobalContext()), argTypesOneDouble, false); 94 | f = Function::Create(ft, Function::ExternalLinkage, MAKE_LLVM_EXTERNAL_NAME(sinus), getModule()); 95 | i = f->arg_begin(); 96 | if (i != f->arg_end()) 97 | i->setName("val"); 98 | builtins.push_back({f, (void *)sinus}); 99 | 100 | std::vector argTypesInt8Ptr(1, Type::getInt8PtrTy(getGlobalContext())); 101 | ft = FunctionType::get(Type::getVoidTy(getGlobalContext()), argTypesInt8Ptr, true); 102 | f = Function::Create(ft, Function::ExternalLinkage, MAKE_LLVM_EXTERNAL_NAME(write), getModule()); 103 | i = f->arg_begin(); 104 | if (i != f->arg_end()) 105 | i->setName("format_str"); 106 | builtins.push_back({f, (void *)write}); 107 | 108 | ft = FunctionType::get(Type::getVoidTy(getGlobalContext()), argTypesInt8Ptr, true); 109 | f = Function::Create(ft, Function::ExternalLinkage, MAKE_LLVM_EXTERNAL_NAME(writeln), getModule()); 110 | i = f->arg_begin(); 111 | if (i != f->arg_end()) 112 | i->setName("format_str"); 113 | builtins.push_back({f, (void *)writeln}); 114 | 115 | ft = FunctionType::get(Type::getInt8PtrTy(getGlobalContext()), false); 116 | f = Function::Create(ft, Function::ExternalLinkage, MAKE_LLVM_EXTERNAL_NAME(read), getModule()); 117 | builtins.push_back({f, (string *)read}); 118 | 119 | ft = FunctionType::get(intType, false); 120 | f = Function::Create(ft, Function::ExternalLinkage, MAKE_LLVM_EXTERNAL_NAME(readint), getModule()); 121 | builtins.push_back({f, (int *)readint}); 122 | 123 | ft = FunctionType::get(doubleType, false); 124 | f = Function::Create(ft, Function::ExternalLinkage, MAKE_LLVM_EXTERNAL_NAME(readflt), getModule()); 125 | builtins.push_back({f, (double *)readflt}); 126 | } 127 | 128 | bool CodeGenContext::generateCode(Block &root) 129 | { 130 | outs << ":: Generating code...\n"; 131 | 132 | /* Create the top level interpreter function to call as entry */ 133 | vector argTypes; 134 | FunctionType *ftype = FunctionType::get(Type::getVoidTy(getGlobalContext()), argTypes, false); 135 | mainFunction = Function::Create(ftype, GlobalValue::InternalLinkage, "main", getModule()); 136 | BasicBlock *bblock = BasicBlock::Create(getGlobalContext(), "entry", mainFunction, 0); 137 | setupBuiltIns(); 138 | /* Push a new variable/block context */ 139 | newScope(bblock); 140 | root.codeGen(*this); /* emit byte code for the top level block */ 141 | if (errors) 142 | { 143 | outs << "** Compilation error(s). Aborted.\n"; 144 | return false; 145 | } 146 | if (currentBlock()->getTerminator() == nullptr) 147 | { 148 | ReturnInst::Create(getGlobalContext(), 0, currentBlock()); 149 | } 150 | endScope(); 151 | 152 | outs << ":: Code generated.\n"; 153 | 154 | outs << ":: Verifying... "; 155 | if (verifyModule(*getModule())) 156 | { 157 | outs << "** Error constructing function!\n"; 158 | #if !defined(LLVM_NO_DUMP) 159 | module->dump(); 160 | #endif 161 | return false; 162 | } 163 | outs << "Done.\n"; 164 | 165 | if (!debug) 166 | { 167 | optimize(); 168 | } 169 | #if !defined(LLVM_NO_DUMP) // Only the debug build of LLVM has a dump() method. 170 | /* Print the byte code in a human-readable format 171 | * to see if our program compiled properly 172 | */ 173 | if (verbose) 174 | module->dump(); 175 | #endif 176 | return true; 177 | } 178 | 179 | GenericValue CodeGenContext::runCode() 180 | { 181 | outs << ":: Running code...\n\n"; 182 | std::string err; 183 | ExecutionEngine *ee = EngineBuilder(std::unique_ptr(module)).setErrorStr(&err).setEngineKind(EngineKind::JIT).create(); 184 | assert(ee); 185 | for (auto info : builtins) 186 | { 187 | ee->addGlobalMapping(info.f, info.addr); 188 | } 189 | 190 | ee->finalizeObject(); 191 | vector noargs; 192 | GenericValue v = ee->runFunction(mainFunction, noargs); 193 | outs << "\n[END] Code executed successfully :)\n\n"; 194 | delete ee; 195 | return v; 196 | } 197 | 198 | void CodeGenContext::printCodeGeneration(class Block &root, std::ostream &outstream) 199 | { 200 | VisitorPrettyPrint visitor(outstream); 201 | root.Accept(visitor); 202 | } 203 | 204 | void CodeGenContext::optimize() 205 | { 206 | outs << ":: Optimizing code...\n"; 207 | legacy::FunctionPassManager fpm(getModule()); 208 | PassManagerBuilder builder; 209 | builder.OptLevel = 3; 210 | builder.populateFunctionPassManager(fpm); 211 | for (auto &fn : getModule()->getFunctionList()) 212 | { 213 | fpm.run(fn); 214 | } 215 | fpm.run(*mainFunction); 216 | } 217 | 218 | void CodeGenContext::newScope(BasicBlock *bb, ScopeType scopeType) 219 | { 220 | currentScopeType = scopeType; 221 | if (bb == nullptr) 222 | { 223 | bb = llvm::BasicBlock::Create(getGlobalContext(), "scope"); 224 | } 225 | codeBlocks.push_front(new CodeGenBlock(bb)); 226 | } 227 | 228 | void CodeGenContext::endScope() 229 | { 230 | CodeGenBlock *top = codeBlocks.front(); 231 | codeBlocks.pop_front(); 232 | delete top; 233 | currentScopeType = ScopeType::CodeBlock; 234 | } 235 | 236 | AllocaInst *CodeGenContext::findVariable(std::string varName) 237 | { 238 | if (currentScopeType == ScopeType::FunctionDeclaration) 239 | { 240 | // Only look in current scope, since outer scope isn't valid while in function declaration. 241 | auto &names = locals(); 242 | if (names.find(varName) != names.end()) 243 | { 244 | return names[varName]; 245 | } 246 | return nullptr; 247 | } 248 | 249 | // Travers from inner to outer scope (block) to find the variable. 250 | for (auto &cb : codeBlocks) 251 | { 252 | auto &names = cb->getValueNames(); 253 | if (names.find(varName) != names.end()) 254 | { 255 | return names[varName]; 256 | } 257 | } 258 | 259 | // If we are in a class then check the calls variables, too. 260 | if (self) 261 | { 262 | ValueNames &vnames = self->getValueNames(); 263 | if (vnames.find(varName) != vnames.end()) 264 | { 265 | return vnames[varName]; 266 | } 267 | } 268 | return nullptr; 269 | } 270 | 271 | void CodeGenContext::deleteVariable(std::string varName) 272 | { 273 | ValueNames &names = locals(); 274 | auto &typeMap = codeBlocks.front()->getTypeMap(); 275 | if (names.find(varName) != names.end()) 276 | { 277 | names.erase(varName); 278 | if (typeMap.count(varName)) 279 | { 280 | typeMap.erase(varName); 281 | } 282 | } 283 | } 284 | 285 | void CodeGenContext::renameVariable(std::string oldVarName, std::string newVarName) 286 | { 287 | ValueNames &names = locals(); 288 | if (names.find(oldVarName) != names.end()) 289 | { 290 | auto value = names[oldVarName]; 291 | names.erase(oldVarName); 292 | names[newVarName] = value; 293 | auto &typeMap = codeBlocks.front()->getTypeMap(); 294 | if (typeMap.count(oldVarName)) 295 | { 296 | auto val = typeMap[oldVarName]; 297 | typeMap.erase(oldVarName); 298 | typeMap[newVarName] = val; 299 | } 300 | } 301 | } 302 | 303 | void CodeGenContext::newKlass(std::string name) 304 | { 305 | self = codeBlocks.front(); 306 | klassName = name; 307 | classAttributes[klassName] = KlassValueNames(); 308 | } 309 | 310 | void CodeGenContext::endKlass() 311 | { 312 | self = nullptr; 313 | klassName = ""; 314 | } 315 | 316 | void 317 | CodeGenContext::klassAddVariableAccess(std::string name, int index) { classAttributes[klassName][name] = index; } 318 | 319 | Instruction *CodeGenContext::getKlassVarAccessInst(std::string klass, std::string name, AllocaInst *this_ptr) 320 | { 321 | assert(classAttributes.find(klass) != classAttributes.end()); 322 | int index = classAttributes[klass][name]; 323 | std::vector ptr_indices; 324 | ConstantInt *const_int32_0 = ConstantInt::get(getModule()->getContext(), APInt(32, 0)); 325 | ConstantInt *const_int32 = ConstantInt::get(getModule()->getContext(), APInt(32, index)); 326 | ptr_indices.push_back(const_int32_0); 327 | ptr_indices.push_back(const_int32); 328 | if (this_ptr->getType()->getElementType()->isPointerTy()) 329 | { 330 | // since the alloc is a ptr to ptr 331 | Value *val = new LoadInst(this_ptr, "", false, currentBlock()); 332 | return GetElementPtrInst::Create(val->getType()->getPointerElementType(), val, ptr_indices, "", 333 | currentBlock()); 334 | } 335 | Instruction *ptr = GetElementPtrInst::Create(this_ptr->getType()->getElementType(), this_ptr, ptr_indices, "", 336 | currentBlock()); 337 | return ptr; 338 | } 339 | 340 | std::string CodeGenContext::getType(std::string varName) 341 | { 342 | if (varName == "self") 343 | { 344 | return klassName; 345 | } 346 | for (auto &cb : codeBlocks) 347 | { 348 | auto iter = cb->getTypeMap().find(varName); 349 | if (iter != std::end(cb->getTypeMap())) 350 | { 351 | return cb->getTypeMap()[varName]; 352 | } 353 | } 354 | return std::string(""); 355 | } 356 | 357 | Type *CodeGenContext::typeOf(const Identifier &type) { return typeOf(type.getName()); } 358 | 359 | Type *CodeGenContext::typeOf(const std::string &name) 360 | { 361 | if (llvmTypeMap.count(name) != 0) 362 | { 363 | return llvmTypeMap[name]; 364 | } 365 | 366 | llvm::Type *ty = getModule()->getTypeByName("class." + name); 367 | if (ty != nullptr) 368 | { 369 | return ty; 370 | } 371 | return voidType; 372 | } 373 | 374 | std::string CodeGenContext::typeNameOf(llvm::Type *type) 375 | { 376 | switch (type->getTypeID()) 377 | { 378 | case llvm::Type::TypeID::DoubleTyID: 379 | return "double"; 380 | case llvm::Type::TypeID::IntegerTyID: 381 | if (type == llvm::Type::getInt1Ty(getGlobalContext())) 382 | return "boolean"; 383 | return "int"; 384 | case llvm::Type::TypeID::VoidTyID: 385 | return "void"; 386 | default: 387 | return "void"; 388 | } 389 | } 390 | 391 | void CodeGenContext::addKlassInitCode(std::string name, Assignment *assign) { classInitCode[name].insert(assign); } 392 | 393 | KlassInitCodeAssign &CodeGenContext::getKlassInitCode(std::string name) { return classInitCode[name]; } 394 | 395 | std::string CodeGenContext::findClassNameByType(llvm::Type *ty) 396 | { 397 | auto found = std::find_if(std::begin(classTypeMap), std::end(classTypeMap), 398 | [&](auto kv) 399 | { return kv.second == ty; }); 400 | if (found != std::end(classTypeMap)) 401 | { 402 | return found->first; 403 | } 404 | return ""; 405 | } 406 | 407 | llvm::Type *CodeGenContext::getGenericIntegerType() 408 | { 409 | #if defined(UseInt64) 410 | return Type::getInt64Ty(getGlobalContext()); 411 | #else 412 | return Type::getInt32Ty(getGlobalContext()); 413 | #endif 414 | } 415 | 416 | bool CodeGenContext::preProcessing(Block &root) 417 | { 418 | VisitorSyntaxCheck visitor; 419 | root.Accept(visitor); 420 | return !visitor.hasErrors(); 421 | } 422 | 423 | FunctionDeclaration *CodeGenContext::getTemplateFunction(const std::string &name) 424 | { 425 | if (templatedFunctionDeclarations.count(name) > 0) 426 | { 427 | return templatedFunctionDeclarations[name]; 428 | } 429 | return nullptr; 430 | } 431 | 432 | } 433 | --------------------------------------------------------------------------------