--- /dev/null
+Kaleidoscope/bin
+*.xcodeproj/xcuserdata/
objects = {
/* Begin PBXBuildFile section */
- A38E77AA1E3961F000AFF10F /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A38E77A91E3961F000AFF10F /* main.cpp */; };
+ A307FE90202C077F009FFBF2 /* codegen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A307FE8E202C077E009FFBF2 /* codegen.cpp */; };
+ A3081B0620301A4D00205DAB /* stdlib.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A3081B0420301A4D00205DAB /* stdlib.cpp */; };
+ A38E77B11E39621900AFF10F /* lexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A38E77B01E39621900AFF10F /* lexer.cpp */; };
+ A3C5D8EE1FF1C877000A4385 /* ast.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A3C5D8EC1FF1C877000A4385 /* ast.cpp */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ A307FE8E202C077E009FFBF2 /* codegen.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = codegen.cpp; sourceTree = "<group>"; };
+ A307FE8F202C077F009FFBF2 /* codegen.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = codegen.hpp; sourceTree = "<group>"; };
+ A3081B03202FCA9500205DAB /* shared.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = shared.h; sourceTree = "<group>"; };
+ A3081B0420301A4D00205DAB /* stdlib.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = stdlib.cpp; sourceTree = "<group>"; };
+ A3081B0520301A4D00205DAB /* stdlib.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = stdlib.hpp; sourceTree = "<group>"; };
+ A32DD46F1E396FB7001EF2C0 /* lexer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = lexer.h; sourceTree = "<group>"; };
A38E77A61E3961F000AFF10F /* Kaleidoscope */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Kaleidoscope; sourceTree = BUILT_PRODUCTS_DIR; };
- A38E77A91E3961F000AFF10F /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
+ A38E77B01E39621900AFF10F /* lexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lexer.cpp; sourceTree = "<group>"; };
+ A3C5D8EC1FF1C877000A4385 /* ast.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ast.cpp; sourceTree = "<group>"; };
+ A3C5D8ED1FF1C877000A4385 /* ast.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ast.hpp; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ A3081B0720301E6200205DAB /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
A38E779D1E3961EF00AFF10F = {
isa = PBXGroup;
children = (
A38E77A81E3961F000AFF10F /* Kaleidoscope */,
A38E77A71E3961F000AFF10F /* Products */,
+ A3081B0720301E6200205DAB /* Frameworks */,
);
sourceTree = "<group>";
};
A38E77A81E3961F000AFF10F /* Kaleidoscope */ = {
isa = PBXGroup;
children = (
- A38E77A91E3961F000AFF10F /* main.cpp */,
+ A3081B0420301A4D00205DAB /* stdlib.cpp */,
+ A3081B0520301A4D00205DAB /* stdlib.hpp */,
+ A3081B03202FCA9500205DAB /* shared.h */,
+ A38E77B01E39621900AFF10F /* lexer.cpp */,
+ A32DD46F1E396FB7001EF2C0 /* lexer.h */,
+ A3C5D8EC1FF1C877000A4385 /* ast.cpp */,
+ A3C5D8ED1FF1C877000A4385 /* ast.hpp */,
+ A307FE8E202C077E009FFBF2 /* codegen.cpp */,
+ A307FE8F202C077F009FFBF2 /* codegen.hpp */,
);
path = Kaleidoscope;
sourceTree = "<group>";
A38E779E1E3961EF00AFF10F /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0820;
+ LastUpgradeCheck = 0930;
ORGANIZATIONNAME = "Luke Lau";
TargetAttributes = {
A38E77A51E3961EF00AFF10F = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- A38E77AA1E3961F000AFF10F /* main.cpp in Sources */,
+ A307FE90202C077F009FFBF2 /* codegen.cpp in Sources */,
+ A3081B0620301A4D00205DAB /* stdlib.cpp in Sources */,
+ A3C5D8EE1FF1C877000A4385 /* ast.cpp in Sources */,
+ A38E77B11E39621900AFF10F /* lexer.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
A38E77AE1E3961F000AFF10F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
DEVELOPMENT_TEAM = 7R888D749H;
+ HEADER_SEARCH_PATHS = /usr/local/opt/llvm/include;
+ LIBRARY_SEARCH_PATHS = (
+ /usr/local/opt/llvm/lib,
+ /usr/local/Cellar/llvm/5.0.1/lib,
+ );
+ OTHER_LDFLAGS = (
+ "-lz",
+ "-ltermcap",
+ "-lc++",
+ "-lLLVMCore",
+ "-lLLVMSupport",
+ "-lLLVMTransformUtils",
+ "-lLLVMBitReader",
+ "-lLLVMAnalysis",
+ "-lLLVMDemangle",
+ );
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
A38E77AF1E3961F000AFF10F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
DEVELOPMENT_TEAM = 7R888D749H;
+ HEADER_SEARCH_PATHS = /usr/local/opt/llvm/include;
+ LIBRARY_SEARCH_PATHS = (
+ /usr/local/opt/llvm/lib,
+ /usr/local/Cellar/llvm/5.0.1/lib,
+ );
+ OTHER_LDFLAGS = (
+ "-lz",
+ "-ltermcap",
+ "-lc++",
+ "-lLLVMCore",
+ "-lLLVMSupport",
+ "-lLLVMTransformUtils",
+ "-lLLVMBitReader",
+ "-lLLVMAnalysis",
+ "-lLLVMDemangle",
+ );
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
A38E77AF1E3961F000AFF10F /* Release */,
);
defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "0820"
+ LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
--- /dev/null
+#include "ast.hpp"
+
+std::unique_ptr<ExprAST> LogError(const char *Str) {
+ fprintf(stderr, "LogError: %s\n", Str);
+ return nullptr;
+}
--- /dev/null
+#include <string>
+#include <vector>
+#include "llvm/IR/Value.h"
+#include "llvm/IR/Function.h"
+
+using namespace llvm;
+
+class ExprAST {
+public:
+ virtual ~ExprAST() = default;
+ virtual Value *codegen() = 0;
+};
+
+class NumberExprAST: public ExprAST {
+ double Val;
+
+public:
+ NumberExprAST(double Val): Val(Val) {}
+ virtual Value *codegen();
+};
+
+class VariableExprAST: public ExprAST {
+ std::string Name;
+
+public:
+ VariableExprAST(const std::string &Name): Name(Name) {}
+ virtual Value *codegen();
+};
+
+class BinaryExprAST: public ExprAST {
+ char Op;
+ std::unique_ptr<ExprAST> LHS, RHS;
+
+public:
+ BinaryExprAST(char op, std::unique_ptr<ExprAST> LHS,
+ std::unique_ptr<ExprAST> RHS)
+ : Op(op), LHS(std::move(LHS)), RHS(std::move(RHS)) {}
+ virtual Value *codegen();
+};
+
+class CallExprAST: public ExprAST {
+ std::string Callee;
+ std::vector<std::unique_ptr<ExprAST>> Args;
+
+public:
+ CallExprAST(std::string &Callee, std::vector<std::unique_ptr<ExprAST>> Args)
+ : Callee(Callee), Args(std::move(Args)) {}
+ virtual Value *codegen();
+};
+
+/*
+ Captures the prototype for a function
+ which is basically its name and arguments
+ */
+class PrototypeAST {
+ std::string Name;
+ std::vector<std::string> Args;
+
+public:
+ virtual ~PrototypeAST() = default;
+ PrototypeAST(std::string Name, std::vector<std::string> Args)
+ : Name(Name), Args(std::move(Args)) {}
+
+ const std::string &getName() const { return Name; }
+ virtual Function *codegen();
+};
+
+class FunctionAST {
+ std::unique_ptr<PrototypeAST> Prototype;
+ std::unique_ptr<ExprAST> Body;
+
+public:
+ virtual ~FunctionAST() = default;
+ FunctionAST(std::unique_ptr<PrototypeAST> Prototype, std::unique_ptr<ExprAST> Body)
+ : Prototype(std::move(Prototype)), Body(std::move(Body)) {}
+ virtual Function *codegen();
+};
+
+std::unique_ptr<ExprAST> LogError(const char *Str);
--- /dev/null
+#include <iostream>
+#include <llvm/Passes/PassBuilder.h>
+#include <llvm/IR/LLVMContext.h>
+#include <llvm/IR/IRBuilder.h>
+#include <llvm/IR/Verifier.h>
+#include <llvm/IR/PassManager.h>
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Scalar/Reassociate.h"
+#include "llvm/Transforms/Scalar/GVN.h"
+#include <llvm/Transforms/Scalar/DCE.h>
+#include <llvm/Transforms/Scalar/SimplifyCFG.h>
+#include <llvm/Transforms/InstCombine/InstCombine.h>
+#include <llvm/Transforms/IPO/PassManagerBuilder.h>
+#include <llvm/Analysis/OptimizationDiagnosticInfo.h>
+#include <llvm/Analysis/MemorySSA.h>
+#include <llvm/Analysis/PostDominators.h>
+#include "ast.hpp"
+#include "codegen.hpp"
+#include "shared.h"
+
+using namespace llvm;
+
+static LLVMContext TheContext;
+static IRBuilder<> Builder(TheContext);
+static AnalysisManager<int, int> TheAM;
+static std::map<std::string, Value *> NamedValues;
+static std::unique_ptr<FunctionPassManager> TheFPM;
+static std::unique_ptr<FunctionAnalysisManager> TheFAM;
+
+void InitializeModuleAndPassManager(void) {
+ TheModule = llvm::make_unique<Module>("Kaleidoscope jit", TheContext);
+
+ TheFPM = make_unique<FunctionPassManager>();
+ TheFAM = make_unique<FunctionAnalysisManager>();
+
+ PassBuilder PB;
+ PB.registerFunctionAnalyses(*TheFAM);
+
+ TheFPM->addPass(InstCombinePass());
+ TheFPM->addPass(ReassociatePass());
+ TheFPM->addPass(SimplifyCFGPass());
+ TheFPM->addPass(GVNHoistPass());
+ TheFPM->addPass(GVNSinkPass());
+}
+
+void PrintModule() {
+ TheModule->print(errs(), nullptr);
+}
+
+std::map<std::string, std::unique_ptr<PrototypeAST>> functionProtos;
+
+Function *getFunction(std::string name) {
+ if (auto *func = TheModule->getFunction(name))
+ return func;
+
+ auto iterator = functionProtos.find(name);
+ if (iterator != functionProtos.end())
+ return iterator->second->codegen();
+
+ return nullptr;
+}
+
+Value *LogErrorV(const char *Str) {
+ LogError(Str);
+ return nullptr;
+}
+
+Value *NumberExprAST::codegen() {
+ return ConstantFP::get(TheContext, APFloat(Val));
+}
+
+Value *VariableExprAST::codegen() {
+ Value *V = NamedValues[Name];
+ if (!V)
+ 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/1.0
+ return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp");
+ default:
+ return LogErrorV("Invalid binary operator");
+ }
+}
+
+Value *CallExprAST::codegen() {
+ Function *CalleeF = getFunction(Callee);
+ if (!CalleeF)
+ return LogErrorV("Unknown function referenced");
+
+ if (CalleeF->arg_size() != Args.size())
+ return LogErrorV("Incorrect number of arguments passed");
+
+ std::vector<Value *> ArgsV;
+ for (unsigned long 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() {
+ std::vector<Type*> Doubles(Args.size(), Type::getDoubleTy(TheContext));
+
+ FunctionType *FT = FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false);
+ Function *func = Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get());
+
+ unsigned i = 0;
+ for (auto &arg : func->args())
+ arg.setName(Args[i++]);
+
+ return func;
+}
+
+Function *FunctionAST::codegen() {
+ //Transfer ownership but keep a reference
+ auto &P = *Prototype;
+ functionProtos[Prototype->getName()] = std::move(Prototype);
+
+ Function *func = getFunction(P.getName());
+
+ if (!func) return nullptr;
+
+ BasicBlock *bb = BasicBlock::Create(TheContext, "entry", func);
+ Builder.SetInsertPoint(bb);
+
+ NamedValues.clear();
+ for (auto &arg: func->args())
+ NamedValues[arg.getName()] = &arg;
+
+ if (Value *retVal = Body->codegen()) {
+ Builder.CreateRet(retVal);
+ verifyFunction(*func);
+ TheFPM->run(*func, *TheFAM);
+ return func;
+ }
+
+ func->eraseFromParent();
+ return nullptr;
+}
--- /dev/null
+#include <stdio.h>
+
+void InitializeModuleAndPassManager(void);
+
+void PrintModule();
+
+extern std::map<std::string, std::unique_ptr<PrototypeAST>> functionProtos;
--- /dev/null
+#include <cstdio>
+#include <cctype>
+#include <cstdlib>
+#include <string>
+#include <map>
+#include <iostream>
+#include <iomanip>
+#include <llvm/ADT/STLExtras.h>
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/ExecutionEngine/ExecutionEngine.h>
+#include <llvm/ExecutionEngine/GenericValue.h>
+#include <llvm/Support/TargetSelect.h>
+//Needed to force linking interpreter
+#include <llvm/ExecutionEngine/MCJIT.h>
+#include "lexer.h"
+#include "ast.hpp"
+#include "codegen.hpp"
+#include "shared.h"
+
+static std::unique_ptr<ExprAST> ParseBinOpRHS(int ExprPrec,
+ std::unique_ptr<ExprAST> LHS);
+static std::unique_ptr<ExprAST> ParseExpression();
+
+static ExecutionEngine* TheEngine;
+
+std::unique_ptr<Module> TheModule;
+
+constexpr auto ANON_EXPR_FUNC_NAME = "__anon_expr";
+
+enum Token {
+ tok_eof = -1,
+
+ tok_def = -2,
+ tok_extern = -3,
+
+ tok_identifier = -4,
+ tok_number = -5,
+};
+
+static std::string IdentifierStr;
+static double NumVal;
+
+///Returns the next token from stdin
+static int gettok() {
+ static int LastChar = ' ';
+
+ while(isspace(LastChar))
+ LastChar = getchar();
+
+ if(isalpha(LastChar)) {
+ 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 == '.') {
+ std::string NumStr;
+ do {
+ NumStr += LastChar;
+ LastChar = getchar();
+ } while (isdigit(LastChar) || LastChar == '.');
+
+ NumVal = strtod(NumStr.c_str(), 0);
+ return tok_number;
+ }
+
+ if(LastChar == '#') {
+ //Coment until the end of the line
+ do
+ LastChar = getchar();
+ while(LastChar != EOF && LastChar != '\n' && LastChar != 'r');
+
+ if(LastChar != EOF)
+ return gettok();
+ }
+
+ //Check for end of file
+ if(LastChar == EOF)
+ return tok_eof;
+
+ int ThisChar = LastChar;
+ LastChar = getchar();
+ return ThisChar;
+}
+
+
+static int CurTok;
+static int getNextToken() {
+ return CurTok = gettok();
+}
+
+std::unique_ptr<PrototypeAST> LogErrorP(const char *Str) {
+ LogError(Str);
+ return nullptr;
+}
+
+static std::unique_ptr<ExprAST> ParseNumberExpr() {
+ auto Result = llvm::make_unique<NumberExprAST>(NumVal);
+ getNextToken(); // consume the number
+ return std::move(Result);
+}
+
+static std::unique_ptr<ExprAST> ParseParenExpr() {
+ getNextToken();
+ auto V = ParseExpression();
+ if (!V)
+ return nullptr;
+
+ if (CurTok != ')')
+ return LogError("expected ')'");
+ getNextToken();
+ return V;
+}
+
+static std::unique_ptr<ExprAST> ParseIdentifierExpr() {
+ std::string IdName = IdentifierStr;
+
+ getNextToken();
+
+ if (CurTok != '(')
+ return llvm::make_unique<VariableExprAST>(IdName);
+
+ // call a function
+ getNextToken();
+ std::vector<std::unique_ptr<ExprAST>> 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();
+ }
+ }
+
+ getNextToken();
+ return llvm::make_unique<CallExprAST>(IdName, std::move(Args));
+}
+
+static std::unique_ptr<ExprAST> ParsePrimary() {
+ switch (CurTok) {
+ default:
+ return LogError("Unknown token when expected an expression");
+ case tok_identifier:
+ return ParseIdentifierExpr();
+ case tok_number:
+ return ParseNumberExpr();
+ case '(':
+ return ParseParenExpr();
+ }
+}
+
+static std::map<char, int> BinopPrecedence;
+
+static int GetTokPrecedence() {
+ if (!isascii(CurTok))
+ return -1;
+
+ int TokPrec = BinopPrecedence[CurTok];
+ if (TokPrec <= 0) return -1;
+ return TokPrec;
+}
+
+static std::unique_ptr<ExprAST> ParseExpression() {
+ auto LHS = ParsePrimary();
+ if (!LHS)
+ return nullptr;
+ return ParseBinOpRHS(0, std::move(LHS));
+}
+
+static std::unique_ptr<ExprAST> ParseBinOpRHS(int ExprPrec,
+ std::unique_ptr<ExprAST> LHS) {
+ while (true) {
+ int TokPrec = GetTokPrecedence();
+ if (TokPrec < ExprPrec)
+ return LHS;
+
+ int BinOp = CurTok;
+ getNextToken(); // eat binop
+
+ auto RHS = ParsePrimary();
+ if (!RHS)
+ return nullptr;
+
+ int NextPrec = GetTokPrecedence();
+ if (TokPrec < NextPrec) {
+ RHS = ParseBinOpRHS(TokPrec + 1, std::move(RHS));
+ if (!RHS)
+ return nullptr;
+ }
+
+ LHS = llvm::make_unique<BinaryExprAST>(BinOp, std::move(LHS), std::move(RHS));
+ }
+}
+
+static std::unique_ptr<PrototypeAST> 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<std::string> ArgNames;
+ while (getNextToken() == tok_identifier)
+ ArgNames.push_back(IdentifierStr);
+ if (CurTok != ')')
+ return LogErrorP("Expected ')' in prototype");
+
+ getNextToken(); // eat ')'
+
+ return llvm::make_unique<PrototypeAST>(FnName, std::move(ArgNames));
+}
+
+static std::unique_ptr<FunctionAST> ParseDefinition() {
+ getNextToken();
+ auto Proto = ParsePrototype();
+ if (!Proto) return nullptr;
+
+ if (auto E = ParseExpression())
+ return llvm::make_unique<FunctionAST>(std::move(Proto), std::move(E));
+ return nullptr;
+}
+
+static std::unique_ptr<PrototypeAST> ParseExtern() {
+ getNextToken();
+ return ParsePrototype();
+}
+
+static std::unique_ptr<FunctionAST> ParseTopLevelExpr() {
+ if (auto e = ParseExpression()) {
+ // make an anonymous prototype
+ auto proto = llvm::make_unique<PrototypeAST>(ANON_EXPR_FUNC_NAME, std::vector<std::string>());
+ return llvm::make_unique<FunctionAST>(std::move(proto), std::move(e));
+ }
+ return nullptr;
+}
+
+static void HandleDefinition() {
+ if (auto def = ParseDefinition()) {
+ if (auto gen = def->codegen()) {
+ std::cerr << "Read function defintion:";
+ gen->print(errs());
+ std::cerr << "\n";
+
+ TheEngine->addModule(std::move(TheModule));
+ InitializeModuleAndPassManager();
+ }
+ }
+ else
+ getNextToken(); // skip token for error recovery
+}
+
+static void HandleExtern() {
+ if (auto externProto = ParseExtern()) {
+ if (auto gen = externProto->codegen()) {
+ std::cerr << "Read an extern:\n";
+ gen->print(errs());
+ std::cerr << "\n";
+ functionProtos[externProto->getName()] = std::move(externProto);
+ }
+ }
+ else
+ getNextToken(); // skip token for error recovery
+}
+
+static void HandleTopLevelExpr() {
+ if (auto expr = ParseTopLevelExpr()) {
+ if (auto gen = expr->codegen()) {
+ gen->print(errs());
+
+ auto module = TheModule.get();
+ TheEngine->addModule(std::move(TheModule));
+ InitializeModuleAndPassManager();
+
+ auto func = TheEngine->FindFunctionNamed(ANON_EXPR_FUNC_NAME);
+ GenericValue gv = TheEngine->runFunction(func, std::vector<GenericValue>());
+ std::cerr << "Evaluated to " << std::fixed << std::setw(5) << gv.DoubleVal << std::endl;
+
+ TheEngine->removeModule(module);
+ }
+ }
+ else
+ getNextToken(); // skip token for error recovery
+}
+
+void mainLoop() {
+ while (true) {
+ fprintf(stderr, "ready> ");
+ switch(CurTok) {
+ case tok_eof:
+ return;
+ case ';':
+ getNextToken();
+ break;
+ case tok_def:
+ HandleDefinition();
+ break;
+ case tok_extern:
+ HandleExtern();
+ break;
+ default:
+ HandleTopLevelExpr();
+ break;
+ }
+ }
+}
+
+int main() {
+ InitializeNativeTarget();
+ InitializeNativeTargetAsmPrinter();
+ InitializeNativeTargetAsmParser();
+
+ BinopPrecedence['<'] = 10;
+ BinopPrecedence['+'] = 20;
+ BinopPrecedence['-'] = 20;
+ BinopPrecedence['*'] = 40;
+
+ InitializeModuleAndPassManager();
+
+ std::string engineError;
+ TheEngine = EngineBuilder(std::move(TheModule)).setErrorStr(&engineError).create();
+ if (!engineError.empty())
+ std::cout << engineError << "\n";
+
+ InitializeModuleAndPassManager();
+
+ // prime the first token
+ std::cerr << "ready> ";
+ getNextToken();
+
+ mainLoop();
+
+ PrintModule();
+
+
+ return 0;
+}
+++ /dev/null
-//
-// main.cpp
-// Kaleidoscope
-//
-// Created by Luke Lau on 25/01/2017.
-// Copyright © 2017 Luke Lau. All rights reserved.
-//
-
-#include <iostream>
-
-int main(int argc, const char * argv[]) {
- // insert code here...
- std::cout << "Hello, World!\n";
- return 0;
-}
--- /dev/null
+all:
+ clang++ -g `llvm-config --cxxflags --ldflags --system-libs --libs core mcjit native passes interpreter` -o bin/kaleidoscope *.cpp
--- /dev/null
+//
+// shared.h
+// Kaleidoscope
+//
+// Created by Luke Lau on 10/02/2018.
+// Copyright © 2018 Luke Lau. All rights reserved.
+//
+
+#ifndef shared_h
+#define shared_h
+
+extern std::unique_ptr<Module> TheModule;
+
+#endif /* shared_h */
--- /dev/null
+//
+// stdlib.cpp
+// Kaleidoscope
+//
+// Created by Luke Lau on 11/02/2018.
+// Copyright © 2018 Luke Lau. All rights reserved.
+//
+
+#include "stdlib.hpp"
+
+#ifdef LLVM_ON_WIN32
+#define DLLEXPORT __declspec(dllexport)
+#else
+#define DLLEXPORT
+#endif
+
+extern "C" DLLEXPORT double putchard(double X) {
+ fputc((char)X, stderr);
+ return 0;
+}
--- /dev/null
+//
+// stdlib.hpp
+// Kaleidoscope
+//
+// Created by Luke Lau on 11/02/2018.
+// Copyright © 2018 Luke Lau. All rights reserved.
+//
+
+#ifndef stdlib_hpp
+#define stdlib_hpp
+
+#include <stdio.h>
+
+#endif /* stdlib_hpp */