diff --git a/LX-LLVM.vcxproj b/LX-LLVM.vcxproj index 1fb1e60..b747bea 100644 --- a/LX-LLVM.vcxproj +++ b/LX-LLVM.vcxproj @@ -140,7 +140,6 @@ - diff --git a/LX-LLVM.vcxproj.filters b/LX-LLVM.vcxproj.filters index db15802..87e8a8f 100644 --- a/LX-LLVM.vcxproj.filters +++ b/LX-LLVM.vcxproj.filters @@ -16,9 +16,6 @@ Common - - Common - diff --git a/Main.cpp b/Main.cpp index e0d91ef..2fcc0f2 100644 --- a/Main.cpp +++ b/Main.cpp @@ -56,9 +56,6 @@ int main(int argc, char** argv) // Turns the tokens into an AST LX::FileAST AST = LX::TurnTokensIntoAbstractSyntaxTree(tokens, log.get()); - // Turns the AST into something - LX::GenerateIR(AST); - // Returns success return 0; } diff --git a/Parser/Parser.vcxproj b/Parser/Parser.vcxproj index c5ffbbe..f78fa36 100644 --- a/Parser/Parser.vcxproj +++ b/Parser/Parser.vcxproj @@ -132,8 +132,6 @@ - - diff --git a/Parser/Parser.vcxproj.filters b/Parser/Parser.vcxproj.filters index 9159eb8..b9b222e 100644 --- a/Parser/Parser.vcxproj.filters +++ b/Parser/Parser.vcxproj.filters @@ -14,14 +14,8 @@ Source Files - - Source Files - Source Files - - Source Files - \ No newline at end of file diff --git a/Parser/src/AST-LLVM.cpp b/Parser/src/AST-LLVM.cpp deleted file mode 100644 index 0ba3f17..0000000 --- a/Parser/src/AST-LLVM.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include - -#include -#include - -namespace LX::AST -{ - llvm::Value* NumberLiteral::GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) - { - // Converts the string to it's int equivalent - // Will eventually need to do floating point stuff here as well - int number = std::stoi(m_Number); - - // Returns it as a llvm value (if valid) - llvm::Value* out = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), number, true); - ThrowIf(out == nullptr); - return out; - } - - llvm::Value* Operation::GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) - { - // Gets the IR for both sides of the operation - llvm::Value* lhs = m_Lhs->GenIR(context, module, builder); - llvm::Value* rhs = m_Rhs->GenIR(context, module, builder); - - // If either side is null then return null to prevent invalid IR // - if (lhs == nullptr || rhs == nullptr) - { - ThrowIf(true); - return nullptr; - } - - // Will eventually get the correct operator but for now everything is add - llvm::Value* out = builder.CreateAdd(lhs, rhs); - ThrowIf(out == nullptr); - return out; - } - - llvm::Value* ReturnStatement::GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) - { - if (m_Val == nullptr) - { - ThrowIf(true); - return nullptr; - } - - else - { - llvm::Value* out = builder.CreateRet(m_Val->GenIR(context, module, builder)); - ThrowIf(out == nullptr); - return out; - } - } -} diff --git a/Parser/src/GenIR.cpp b/Parser/src/GenIR.cpp deleted file mode 100644 index ae8d646..0000000 --- a/Parser/src/GenIR.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include - -#include - -namespace LX -{ - void GenerateIR(FileAST& ast) - { - // Generates stuff // - - llvm::LLVMContext context; - llvm::IRBuilder<> builder(context); - - { - std::unique_ptr module = std::make_unique("add_ints", context); - - // Defines main function // - - llvm::FunctionType* funcType = llvm::FunctionType::get(llvm::Type::getInt32Ty(context), false); - llvm::Function* mainFunc = llvm::Function::Create(funcType, llvm::Function::ExternalLinkage, "main", module.get()); - llvm::BasicBlock* entry = llvm::BasicBlock::Create(context, "entry", mainFunc); - builder.SetInsertPoint(entry); - - // Loops over AST to generate IR // - - for (auto& node : ast.functions[0].body) - { - switch (node->m_Type) - { - case AST::Node::RETURN_STATEMENT: - { - node->GenIR(context, *module, builder); - break; - } - - default: - { - break; - } - } - } - - if (entry->getTerminator() == nullptr) - { - builder.CreateRet(llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 0, true)); - } - - // Verification of the IR // - - if (llvm::verifyFunction(*mainFunc, &llvm::errs()) || llvm::verifyModule(*module, &llvm::errs())) - { - std::cerr << "Error: IR generation failed" << std::endl; - return; - } - - // Outputs the IR to the console // - - module->print(llvm::outs(), nullptr); - - } // <- Crashes here - - std::cout << "Finished generating IR" << std::endl; - } -} diff --git a/build-test/Log.txt b/build-test/Log.txt index e69de29..8e6fb47 100644 --- a/build-test/Log.txt +++ b/build-test/Log.txt @@ -0,0 +1,17 @@ + +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +Started lexing file +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +Token::FUNCTION +Token::IDENTIFIER: main +Unknown: 3 +Token::NUMBER_LITERAL: 3 +Token::ADD +Token::NUMBER_LITERAL: 4 + +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +Started parsing tokens +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +AST length: 1 diff --git a/build-test/tmp b/build-test/tmp new file mode 100644 index 0000000..0ef5127 --- /dev/null +++ b/build-test/tmp @@ -0,0 +1,261 @@ +/* File 0 */ + +namespace LX::AST +{ + // Base node that everything else inherits from + struct Node + { + // Enum for storing the type of node // + // Used so a pointer to Node can be used and then turned into it's true type // + enum NodeType + { + // General Nodes // + + IDENTIFIER, + NUMBER_LITERAL, + OPERATION, + + // Control flow Nodes // + + RETURN_STATEMENT, + + // If an error happened somewhere // + UNDEFINED = -1 + }; + + // Constructor to set the node type // + Node(NodeType type) + : m_Type(type) + {} + + // Virtual destructor because of polymorphism // + virtual ~Node() = default; + + // Function for generating LLVN IR (Intermediate representation) // + virtual llvm::Value* GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) = 0; + + // Function for generating C/C++ code (Currently not implemented) // + //virtual void GenC() = 0; + + // The type of the node // + const NodeType m_Type; + }; + + class NumberLiteral : public Node + { + public: + // Constructor to set values and automatically set type + NumberLiteral(std::string num); + + // Function for generating LLVN IR (Intermediate representation) // + llvm::Value* GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) override; + + private: + // The number it stores + // Yes the number is stored as a string + // It's horrible I know + std::string m_Number; + }; + + // + class Operation : public Node + { + public: + // Constructor to set values and automatically set type + Operation(std::unique_ptr lhs, Token::TokenType op, std::unique_ptr rhs); + + // Function for generating LLVN IR (Intermediate representation) // + llvm::Value* GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) override; + + private: + // The sides of the operation + // Unary operations are handled by a different class + std::unique_ptr m_Lhs, m_Rhs; + + // The operation to be applied to the two sides + Token::TokenType m_Operand; + }; + + // + class ReturnStatement : public Node + { + public: + // Constructor to set values and automatically set type + ReturnStatement(std::unique_ptr val); + + // Function for generating LLVN IR (Intermediate representation) // + llvm::Value* GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) override; + + private: + // What it is returning (can be null) + std::unique_ptr m_Val; + }; +} + +namespace LX +{ + struct IRGenerationError {}; + + struct FunctionDefinition + { + FunctionDefinition() + : body{} + {} + + std::vector> body; + }; + + struct FileAST + { + FileAST() + : functions{} + {} + + std::vector functions; + }; + + FileAST TurnTokensIntoAbstractSyntaxTree(std::vector& tokens, std::ofstream* log); + + void GenerateIR(FileAST& ast); +} + +/* File 1 */ + +#include + +#include +#include + +namespace LX::AST +{ + llvm::Value* NumberLiteral::GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) + { + // Converts the string to it's int equivalent + // Will eventually need to do floating point stuff here as well + int number = std::stoi(m_Number); + + // Returns it as a llvm value (if valid) + llvm::Value* out = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), number, true); + ThrowIf(out == nullptr); + return out; + } + + llvm::Value* Operation::GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) + { + // Gets the IR for both sides of the operation + llvm::Value* lhs = m_Lhs->GenIR(context, module, builder); + llvm::Value* rhs = m_Rhs->GenIR(context, module, builder); + + // If either side is null then return null to prevent invalid IR // + if (lhs == nullptr || rhs == nullptr) + { + ThrowIf(true); + return nullptr; + } + + // Will eventually get the correct operator but for now everything is add + llvm::Value* out = builder.CreateAdd(lhs, rhs); + ThrowIf(out == nullptr); + return out; + } + + llvm::Value* ReturnStatement::GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) + { + if (m_Val == nullptr) + { + ThrowIf(true); + return nullptr; + } + + else + { + llvm::Value* out = builder.CreateRet(m_Val->GenIR(context, module, builder)); + ThrowIf(out == nullptr); + return out; + } + } +} + +/* File 2 */ + +#include + +#include + +namespace LX +{ + void GenerateIR(FileAST& ast) + { + // Generates stuff // + + llvm::LLVMContext context; + llvm::IRBuilder<> builder(context); + + { + std::unique_ptr module = std::make_unique("add_ints", context); + + // Defines main function // + + llvm::FunctionType* funcType = llvm::FunctionType::get(llvm::Type::getInt32Ty(context), false); + llvm::Function* mainFunc = llvm::Function::Create(funcType, llvm::Function::ExternalLinkage, "main", module.get()); + llvm::BasicBlock* entry = llvm::BasicBlock::Create(context, "entry", mainFunc); + builder.SetInsertPoint(entry); + + // Loops over AST to generate IR // + + for (auto& node : ast.functions[0].body) + { + switch (node->m_Type) + { + case AST::Node::RETURN_STATEMENT: + { + node->GenIR(context, *module, builder); + break; + } + + default: + { + break; + } + } + } + + if (entry->getTerminator() == nullptr) + { + builder.CreateRet(llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 0, true)); + } + + // Verification of the IR // + + if (llvm::verifyFunction(*mainFunc, &llvm::errs()) || llvm::verifyModule(*module, &llvm::errs())) + { + std::cerr << "Error: IR generation failed" << std::endl; + return; + } + + // Outputs the IR to the console // + + module->print(llvm::outs(), nullptr); + + } // <- Crashes here + + std::cout << "Finished generating IR" << std::endl; + } +} + + +/* Output */ + +; ModuleID = 'add_ints' +source_filename = "add_ints" + +define i32 @main() { +entry: + ret i32 7 +} +Finished generating IR + +/* AST */ + +func main + return 3 + 4 diff --git a/build-test/x.cpp b/build-test/x.cpp new file mode 100644 index 0000000..0356300 --- /dev/null +++ b/build-test/x.cpp @@ -0,0 +1,622 @@ +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Verifier.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Lexer +//===----------------------------------------------------------------------===// + +// The lexer returns tokens [0-255] if it is an unknown character, otherwise one +// of these for known things. +enum Token { + tok_eof = -1, + + // commands + tok_def = -2, + tok_extern = -3, + + // primary + tok_identifier = -4, + tok_number = -5 +}; + +static std::string IdentifierStr; // Filled in if tok_identifier +static double NumVal; // Filled in if tok_number + +/// gettok - Return the next token from standard input. +static int gettok() { + static int LastChar = ' '; + + // Skip any whitespace. + while (isspace(LastChar)) + LastChar = getchar(); + + if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]* + IdentifierStr = LastChar; + while (isalnum((LastChar = getchar()))) + IdentifierStr += LastChar; + + if (IdentifierStr == "def") + return tok_def; + if (IdentifierStr == "extern") + return tok_extern; + return tok_identifier; + } + + if (isdigit(LastChar) || LastChar == '.') { // Number: [0-9.]+ + std::string NumStr; + do { + NumStr += LastChar; + LastChar = getchar(); + } while (isdigit(LastChar) || LastChar == '.'); + + NumVal = strtod(NumStr.c_str(), nullptr); + return tok_number; + } + + if (LastChar == '#') { + // Comment until end of line. + do + LastChar = getchar(); + while (LastChar != EOF && LastChar != '\n' && LastChar != '\r'); + + if (LastChar != EOF) + return gettok(); + } + + // Check for end of file. Don't eat the EOF. + if (LastChar == EOF) + return tok_eof; + + // Otherwise, just return the character as its ascii value. + int ThisChar = LastChar; + LastChar = getchar(); + return ThisChar; +} + +//===----------------------------------------------------------------------===// +// Abstract Syntax Tree (aka Parse Tree) +//===----------------------------------------------------------------------===// + +namespace { + +/// ExprAST - Base class for all expression nodes. +class ExprAST { +public: + virtual ~ExprAST() = default; + + virtual Value *codegen() = 0; +}; + +/// NumberExprAST - Expression class for numeric literals like "1.0". +class NumberExprAST : public ExprAST { + double Val; + +public: + NumberExprAST(double Val) : Val(Val) {} + + Value *codegen() override; +}; + +/// VariableExprAST - Expression class for referencing a variable, like "a". +class VariableExprAST : public ExprAST { + std::string Name; + +public: + VariableExprAST(const std::string &Name) : Name(Name) {} + + Value *codegen() override; +}; + +/// BinaryExprAST - Expression class for a binary operator. +class BinaryExprAST : public ExprAST { + char Op; + std::unique_ptr LHS, RHS; + +public: + BinaryExprAST(char Op, std::unique_ptr LHS, + std::unique_ptr RHS) + : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} + + Value *codegen() override; +}; + +/// CallExprAST - Expression class for function calls. +class CallExprAST : public ExprAST { + std::string Callee; + std::vector> Args; + +public: + CallExprAST(const std::string &Callee, + std::vector> Args) + : Callee(Callee), Args(std::move(Args)) {} + + Value *codegen() override; +}; + +/// PrototypeAST - This class represents the "prototype" for a function, +/// which captures its name, and its argument names (thus implicitly the number +/// of arguments the function takes). +class PrototypeAST { + std::string Name; + std::vector Args; + +public: + PrototypeAST(const std::string &Name, std::vector Args) + : Name(Name), Args(std::move(Args)) {} + + Function *codegen(); + const std::string &getName() const { return Name; } +}; + +/// FunctionAST - This class represents a function definition itself. +class FunctionAST { + std::unique_ptr Proto; + std::unique_ptr Body; + +public: + FunctionAST(std::unique_ptr Proto, + std::unique_ptr Body) + : Proto(std::move(Proto)), Body(std::move(Body)) {} + + Function *codegen(); +}; + +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// Parser +//===----------------------------------------------------------------------===// + +/// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current +/// token the parser is looking at. getNextToken reads another token from the +/// lexer and updates CurTok with its results. +static int CurTok; +static int getNextToken() { return CurTok = gettok(); } + +/// BinopPrecedence - This holds the precedence for each binary operator that is +/// defined. +static std::map BinopPrecedence; + +/// GetTokPrecedence - Get the precedence of the pending binary operator token. +static int GetTokPrecedence() { + if (!isascii(CurTok)) + return -1; + + // Make sure it's a declared binop. + int TokPrec = BinopPrecedence[CurTok]; + if (TokPrec <= 0) + return -1; + return TokPrec; +} + +/// LogError* - These are little helper functions for error handling. +std::unique_ptr LogError(const char *Str) { + fprintf(stderr, "Error: %s\n", Str); + return nullptr; +} + +std::unique_ptr LogErrorP(const char *Str) { + LogError(Str); + return nullptr; +} + +static std::unique_ptr ParseExpression(); + +/// numberexpr ::= number +static std::unique_ptr ParseNumberExpr() { + auto Result = std::make_unique(NumVal); + getNextToken(); // consume the number + return std::move(Result); +} + +/// parenexpr ::= '(' expression ')' +static std::unique_ptr ParseParenExpr() { + getNextToken(); // eat (. + auto V = ParseExpression(); + if (!V) + return nullptr; + + if (CurTok != ')') + return LogError("expected ')'"); + getNextToken(); // eat ). + return V; +} + +/// identifierexpr +/// ::= identifier +/// ::= identifier '(' expression* ')' +static std::unique_ptr ParseIdentifierExpr() { + std::string IdName = IdentifierStr; + + getNextToken(); // eat identifier. + + if (CurTok != '(') // Simple variable ref. + return std::make_unique(IdName); + + // Call. + getNextToken(); // eat ( + std::vector> Args; + if (CurTok != ')') { + while (true) { + if (auto Arg = ParseExpression()) + Args.push_back(std::move(Arg)); + else + return nullptr; + + if (CurTok == ')') + break; + + if (CurTok != ',') + return LogError("Expected ')' or ',' in argument list"); + getNextToken(); + } + } + + // Eat the ')'. + getNextToken(); + + return std::make_unique(IdName, std::move(Args)); +} + +/// primary +/// ::= identifierexpr +/// ::= numberexpr +/// ::= parenexpr +static std::unique_ptr ParsePrimary() { + switch (CurTok) { + default: + return LogError("unknown token when expecting an expression"); + case tok_identifier: + return ParseIdentifierExpr(); + case tok_number: + return ParseNumberExpr(); + case '(': + return ParseParenExpr(); + } +} + +/// binoprhs +/// ::= ('+' primary)* +static std::unique_ptr ParseBinOpRHS(int ExprPrec, + std::unique_ptr LHS) { + // If this is a binop, find its precedence. + while (true) { + int TokPrec = GetTokPrecedence(); + + // If this is a binop that binds at least as tightly as the current binop, + // consume it, otherwise we are done. + if (TokPrec < ExprPrec) + return LHS; + + // Okay, we know this is a binop. + int BinOp = CurTok; + getNextToken(); // eat binop + + // Parse the primary expression after the binary operator. + auto RHS = ParsePrimary(); + if (!RHS) + return nullptr; + + // If BinOp binds less tightly with RHS than the operator after RHS, let + // the pending operator take RHS as its LHS. + int NextPrec = GetTokPrecedence(); + if (TokPrec < NextPrec) { + RHS = ParseBinOpRHS(TokPrec + 1, std::move(RHS)); + if (!RHS) + return nullptr; + } + + // Merge LHS/RHS. + LHS = + std::make_unique(BinOp, std::move(LHS), std::move(RHS)); + } +} + +/// expression +/// ::= primary binoprhs +/// +static std::unique_ptr ParseExpression() { + auto LHS = ParsePrimary(); + if (!LHS) + return nullptr; + + return ParseBinOpRHS(0, std::move(LHS)); +} + +/// prototype +/// ::= id '(' id* ')' +static std::unique_ptr ParsePrototype() { + if (CurTok != tok_identifier) + return LogErrorP("Expected function name in prototype"); + + std::string FnName = IdentifierStr; + getNextToken(); + + if (CurTok != '(') + return LogErrorP("Expected '(' in prototype"); + + std::vector ArgNames; + while (getNextToken() == tok_identifier) + ArgNames.push_back(IdentifierStr); + if (CurTok != ')') + return LogErrorP("Expected ')' in prototype"); + + // success. + getNextToken(); // eat ')'. + + return std::make_unique(FnName, std::move(ArgNames)); +} + +/// definition ::= 'def' prototype expression +static std::unique_ptr ParseDefinition() { + getNextToken(); // eat def. + auto Proto = ParsePrototype(); + if (!Proto) + return nullptr; + + if (auto E = ParseExpression()) + return std::make_unique(std::move(Proto), std::move(E)); + return nullptr; +} + +/// toplevelexpr ::= expression +static std::unique_ptr ParseTopLevelExpr() { + if (auto E = ParseExpression()) { + // Make an anonymous proto. + auto Proto = std::make_unique("__anon_expr", + std::vector()); + return std::make_unique(std::move(Proto), std::move(E)); + } + return nullptr; +} + +/// external ::= 'extern' prototype +static std::unique_ptr ParseExtern() { + getNextToken(); // eat extern. + return ParsePrototype(); +} + +//===----------------------------------------------------------------------===// +// Code Generation +//===----------------------------------------------------------------------===// + +static std::unique_ptr TheContext; +static std::unique_ptr TheModule; +static std::unique_ptr> Builder; +static std::map NamedValues; + +Value *LogErrorV(const char *Str) { + LogError(Str); + return nullptr; +} + +Value *NumberExprAST::codegen() { + return ConstantFP::get(*TheContext, APFloat(Val)); +} + +Value *VariableExprAST::codegen() { + // Look this variable up in the function. + Value *V = NamedValues[Name]; + if (!V) + return LogErrorV("Unknown variable name"); + return V; +} + +Value *BinaryExprAST::codegen() { + Value *L = LHS->codegen(); + Value *R = RHS->codegen(); + if (!L || !R) + return nullptr; + + switch (Op) { + case '+': + return Builder->CreateFAdd(L, R, "addtmp"); + case '-': + return Builder->CreateFSub(L, R, "subtmp"); + case '*': + return Builder->CreateFMul(L, R, "multmp"); + case '<': + L = Builder->CreateFCmpULT(L, R, "cmptmp"); + // Convert bool 0/1 to double 0.0 or 1.0 + return Builder->CreateUIToFP(L, Type::getDoubleTy(*TheContext), "booltmp"); + default: + return LogErrorV("invalid binary operator"); + } +} + +Value *CallExprAST::codegen() { + // Look up the name in the global module table. + Function *CalleeF = TheModule->getFunction(Callee); + if (!CalleeF) + return LogErrorV("Unknown function referenced"); + + // If argument mismatch error. + if (CalleeF->arg_size() != Args.size()) + return LogErrorV("Incorrect # arguments passed"); + + std::vector ArgsV; + for (unsigned i = 0, e = Args.size(); i != e; ++i) { + ArgsV.push_back(Args[i]->codegen()); + if (!ArgsV.back()) + return nullptr; + } + + return Builder->CreateCall(CalleeF, ArgsV, "calltmp"); +} + +Function *PrototypeAST::codegen() { + // Make the function type: double(double,double) etc. + std::vector Doubles(Args.size(), Type::getDoubleTy(*TheContext)); + FunctionType *FT = + FunctionType::get(Type::getDoubleTy(*TheContext), Doubles, false); + + Function *F = + Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); + + // Set names for all arguments. + unsigned Idx = 0; + for (auto &Arg : F->args()) + Arg.setName(Args[Idx++]); + + return F; +} + +Function *FunctionAST::codegen() { + // First, check for an existing function from a previous 'extern' declaration. + Function *TheFunction = TheModule->getFunction(Proto->getName()); + + if (!TheFunction) + TheFunction = Proto->codegen(); + + if (!TheFunction) + return nullptr; + + // Create a new basic block to start insertion into. + BasicBlock *BB = BasicBlock::Create(*TheContext, "entry", TheFunction); + Builder->SetInsertPoint(BB); + + // Record the function arguments in the NamedValues map. + NamedValues.clear(); + for (auto &Arg : TheFunction->args()) + NamedValues[std::string(Arg.getName())] = &Arg; + + if (Value *RetVal = Body->codegen()) { + // Finish off the function. + Builder->CreateRet(RetVal); + + // Validate the generated code, checking for consistency. + verifyFunction(*TheFunction); + + return TheFunction; + } + + // Error reading body, remove function. + TheFunction->eraseFromParent(); + return nullptr; +} + +//===----------------------------------------------------------------------===// +// Top-Level parsing and JIT Driver +//===----------------------------------------------------------------------===// + +static void InitializeModule() { + // Open a new context and module. + TheContext = std::make_unique(); + TheModule = std::make_unique("my cool jit", *TheContext); + + // Create a new builder for the module. + Builder = std::make_unique>(*TheContext); +} + +static void HandleDefinition() { + if (auto FnAST = ParseDefinition()) { + if (auto *FnIR = FnAST->codegen()) { + fprintf(stderr, "Read function definition:"); + FnIR->print(errs()); + fprintf(stderr, "\n"); + } + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +static void HandleExtern() { + if (auto ProtoAST = ParseExtern()) { + if (auto *FnIR = ProtoAST->codegen()) { + fprintf(stderr, "Read extern: "); + FnIR->print(errs()); + fprintf(stderr, "\n"); + } + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +static void HandleTopLevelExpression() { + // Evaluate a top-level expression into an anonymous function. + if (auto FnAST = ParseTopLevelExpr()) { + if (auto *FnIR = FnAST->codegen()) { + fprintf(stderr, "Read top-level expression:"); + FnIR->print(errs()); + fprintf(stderr, "\n"); + + // Remove the anonymous expression. + FnIR->eraseFromParent(); + } + } else { + // Skip token for error recovery. + getNextToken(); + } +} + +/// top ::= definition | external | expression | ';' +static void MainLoop() { + while (true) { + fprintf(stderr, "ready> "); + switch (CurTok) { + case tok_eof: + return; + case ';': // ignore top-level semicolons. + getNextToken(); + break; + case tok_def: + HandleDefinition(); + break; + case tok_extern: + HandleExtern(); + break; + default: + HandleTopLevelExpression(); + break; + } + } +} + +//===----------------------------------------------------------------------===// +// Main driver code. +//===----------------------------------------------------------------------===// + +int main() { + // Install standard binary operators. + // 1 is lowest precedence. + BinopPrecedence['<'] = 10; + BinopPrecedence['+'] = 20; + BinopPrecedence['-'] = 20; + BinopPrecedence['*'] = 40; // highest. + + // Prime the first token. + fprintf(stderr, "ready> "); + getNextToken(); + + // Make the module, which holds all the code. + InitializeModule(); + + // Run the main "interpreter loop" now. + MainLoop(); + + // Print out all of the generated code. + TheModule->print(errs(), nullptr); + + return 0; +} diff --git a/common/LLVM.h b/common/LLVM.h deleted file mode 100644 index bccd7cc..0000000 --- a/common/LLVM.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -// Helper file for including all neccesarry parts of LLVM // -#ifdef _MSC_VER - - // Disables all warnings as LLVM files have a lot of Data-loss casts that won't cause issues // - #pragma warning(push) - #pragma warning(disable : 4244) - #pragma warning(disable : 4267) - #pragma warning(disable : 4624) - #pragma warning(disable : 4800) - - // Includes the LLVM files // - - #include - #include - #include - #include - - // Re-enables all warnings // - #pragma warning(pop) - -#else - #error This code only works with MSVC / VS22 -#endif // _MSC_VER diff --git a/common/Parser.h b/common/Parser.h index 1d62caf..c88a997 100644 --- a/common/Parser.h +++ b/common/Parser.h @@ -2,7 +2,6 @@ // Lexer foward declares fstream components so we can use them here // #include -#include #include @@ -54,9 +53,6 @@ namespace LX::AST // Virtual destructor because of polymorphism // virtual ~Node() = default; - // Function for generating LLVN IR (Intermediate representation) // - virtual llvm::Value* GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) = 0; - // Function for generating C/C++ code (Currently not implemented) // //virtual void GenC() = 0; @@ -70,9 +66,6 @@ namespace LX::AST // Constructor to set values and automatically set type NumberLiteral(std::string num); - // Function for generating LLVN IR (Intermediate representation) // - llvm::Value* GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) override; - private: // The number it stores // Yes the number is stored as a string @@ -87,9 +80,6 @@ namespace LX::AST // Constructor to set values and automatically set type Operation(std::unique_ptr lhs, Token::TokenType op, std::unique_ptr rhs); - // Function for generating LLVN IR (Intermediate representation) // - llvm::Value* GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) override; - private: // The sides of the operation // Unary operations are handled by a different class @@ -106,9 +96,6 @@ namespace LX::AST // Constructor to set values and automatically set type ReturnStatement(std::unique_ptr val); - // Function for generating LLVN IR (Intermediate representation) // - llvm::Value* GenIR(llvm::LLVMContext& context, llvm::Module& module, llvm::IRBuilder<>& builder) override; - private: // What it is returning (can be null) std::unique_ptr m_Val; @@ -138,6 +125,4 @@ namespace LX }; FileAST TurnTokensIntoAbstractSyntaxTree(std::vector& tokens, std::ofstream* log); - - void GenerateIR(FileAST& ast); }