From a560c53c5883000c3f7333e2d89cd9f8e1f7ce85 Mon Sep 17 00:00:00 2001 From: Pasha Bibko <156938226+PashaBibko@users.noreply.github.com> Date: Mon, 21 Apr 2025 09:50:29 +0100 Subject: [PATCH] Fixed previous commit Also allows multiple things to be added together --- Main.cpp | 10 +- Parser/Parser.vcxproj | 2 + Parser/Parser.vcxproj.filters | 6 + Parser/src/Parser.cpp | 30 +- build-test/Log.txt | 20 +- build-test/main.lx | 2 +- build-test/tmp | 261 -------------- build-test/x.cpp | 622 ---------------------------------- 8 files changed, 47 insertions(+), 906 deletions(-) delete mode 100644 build-test/tmp delete mode 100644 build-test/x.cpp diff --git a/Main.cpp b/Main.cpp index 90b8cab..39b4d26 100644 --- a/Main.cpp +++ b/Main.cpp @@ -53,16 +53,12 @@ int main(int argc, char** argv) // Create tokens out of the input file std::vectortokens = LX::LexicalAnalyze(inpFile, log.get()); - // Saves the log // - if (log != nullptr) - { - log->close(); - //log->open(argv[3]); - } - // Turns the tokens into an AST LX::FileAST AST = LX::TurnTokensIntoAbstractSyntaxTree(tokens, log.get()); + // + LX::GenerateIR(AST); + // Returns success return 0; } diff --git a/Parser/Parser.vcxproj b/Parser/Parser.vcxproj index 0e53f59..eace985 100644 --- a/Parser/Parser.vcxproj +++ b/Parser/Parser.vcxproj @@ -132,6 +132,8 @@ + + diff --git a/Parser/Parser.vcxproj.filters b/Parser/Parser.vcxproj.filters index a30c288..71e279b 100644 --- a/Parser/Parser.vcxproj.filters +++ b/Parser/Parser.vcxproj.filters @@ -17,6 +17,12 @@ Source Files + + Source Files + + + Source Files + diff --git a/Parser/src/Parser.cpp b/Parser/src/Parser.cpp index e247d0c..fd108c0 100644 --- a/Parser/src/Parser.cpp +++ b/Parser/src/Parser.cpp @@ -37,12 +37,13 @@ namespace LX // Number literals just require them to be turned into an AST node // // Note: Number literals are stored as strings because i'm a masochist // case Token::NUMBER_LITERAL: - return std::make_unique(p.tokens[p.index].contents); + return std::make_unique(p.tokens[p.index++].contents); // Default just alerts the user of an error // // TODO: Actually make this error tell the user something useful // default: std::cout << "UNKNOWN TOKEN: " << p.tokens[p.index].type << std::endl; + p.index++; return nullptr; } } @@ -53,21 +54,23 @@ namespace LX // Checks if the next token is an operator // // TODO: Add more than just add // // TODO: Make this not crash when at the end // - if (p.tokens[p.index + 1].type == Token::ADD) + if (p.index + 1 < p.len) [[likely]] { - // Parses the left hand side of the operation // - std::unique_ptr lhs = ParsePrimary(p); - p.index++; + if (p.tokens[p.index + 1].type == Token::ADD) + { + // Parses the left hand side of the operation // + std::unique_ptr lhs = ParsePrimary(p); - // Stores the operator to pass into the AST node // - Token::TokenType op = p.tokens[p.index].type; - p.index++; + // Stores the operator to pass into the AST node // + Token::TokenType op = p.tokens[p.index].type; + p.index++; - // Parses the right hand of the operation // - std::unique_ptr rhs = ParsePrimary(p); + // Parses the right hand of the operation // + std::unique_ptr rhs = ParseOperation(p); - // Returns an AST node as all of the components combined together // - return std::make_unique(std::move(lhs), op, std::move(rhs)); + // Returns an AST node as all of the components combined together // + return std::make_unique(std::move(lhs), op, std::move(rhs)); + } } // Else goes down the call stack // @@ -130,9 +133,8 @@ namespace LX // Actually parses the function std::unique_ptr node = Parse(p); - // Adds it to the vector and iterates to the next token + // Adds it to the vector func.body.push_back(std::move(node)); - p.index++; } // Goes to the next iteration of the loop // diff --git a/build-test/Log.txt b/build-test/Log.txt index 3a6985a..105c138 100644 --- a/build-test/Log.txt +++ b/build-test/Log.txt @@ -6,6 +6,24 @@ Started lexing file Token::FUNCTION Token::IDENTIFIER: main Unknown: 3 +Token::NUMBER_LITERAL: 1 +Token::ADD +Token::NUMBER_LITERAL: 2 +Token::ADD Token::NUMBER_LITERAL: 3 Token::ADD -Token::NUMBER_LITERAL: 56 +Token::NUMBER_LITERAL: 4 +Token::ADD +Token::NUMBER_LITERAL: 5 +Token::ADD +Token::NUMBER_LITERAL: 6 +Token::ADD +Token::NUMBER_LITERAL: 7 +Token::ADD +Token::NUMBER_LITERAL: 8 + +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +Started parsing tokens +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +AST length: 1 diff --git a/build-test/main.lx b/build-test/main.lx index c555ba4..468ac24 100644 --- a/build-test/main.lx +++ b/build-test/main.lx @@ -1,2 +1,2 @@ func main - return 3 + 56 + return 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 diff --git a/build-test/tmp b/build-test/tmp deleted file mode 100644 index 0ef5127..0000000 --- a/build-test/tmp +++ /dev/null @@ -1,261 +0,0 @@ -/* 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 deleted file mode 100644 index 0356300..0000000 --- a/build-test/x.cpp +++ /dev/null @@ -1,622 +0,0 @@ -#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; -}