Initial commit
authorluke <luke_lau@icloud.com>
Sun, 11 Feb 2018 07:49:17 +0000 (02:49 -0500)
committerluke <luke_lau@icloud.com>
Sun, 11 Feb 2018 07:50:47 +0000 (02:50 -0500)
14 files changed:
.gitignore [new file with mode: 0644]
Kaleidoscope.xcodeproj/project.pbxproj
Kaleidoscope.xcodeproj/xcuserdata/luke.xcuserdatad/xcschemes/Kaleidoscope.xcscheme
Kaleidoscope/ast.cpp [new file with mode: 0644]
Kaleidoscope/ast.hpp [new file with mode: 0644]
Kaleidoscope/codegen.cpp [new file with mode: 0644]
Kaleidoscope/codegen.hpp [new file with mode: 0644]
Kaleidoscope/lexer.cpp [new file with mode: 0644]
Kaleidoscope/lexer.h [new file with mode: 0644]
Kaleidoscope/main.cpp [deleted file]
Kaleidoscope/makefile [new file with mode: 0644]
Kaleidoscope/shared.h [new file with mode: 0644]
Kaleidoscope/stdlib.cpp [new file with mode: 0644]
Kaleidoscope/stdlib.hpp [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..6f79b2b
--- /dev/null
@@ -0,0 +1,2 @@
+Kaleidoscope/bin
+*.xcodeproj/xcuserdata/
index 09e6486daa184f0e1650093930e0324c99ed2840..01ca27d0cbc63346fd7259f4338019ed12948e46 100644 (file)
@@ -7,7 +7,10 @@
        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 */
        };
index ce3e8d2aaee01b6246e05a2b258f16e58541ba49..0042e6421750a8f9d30d9f2d124a4ff706287ea0 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "0820"
+   LastUpgradeVersion = "0930"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/Kaleidoscope/ast.cpp b/Kaleidoscope/ast.cpp
new file mode 100644 (file)
index 0000000..19f5101
--- /dev/null
@@ -0,0 +1,6 @@
+#include "ast.hpp"
+
+std::unique_ptr<ExprAST> LogError(const char *Str) {
+       fprintf(stderr, "LogError: %s\n", Str);
+       return nullptr;
+}
diff --git a/Kaleidoscope/ast.hpp b/Kaleidoscope/ast.hpp
new file mode 100644 (file)
index 0000000..34a5225
--- /dev/null
@@ -0,0 +1,79 @@
+#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);
diff --git a/Kaleidoscope/codegen.cpp b/Kaleidoscope/codegen.cpp
new file mode 100644 (file)
index 0000000..c185a3e
--- /dev/null
@@ -0,0 +1,156 @@
+#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;
+}
diff --git a/Kaleidoscope/codegen.hpp b/Kaleidoscope/codegen.hpp
new file mode 100644 (file)
index 0000000..300282a
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void InitializeModuleAndPassManager(void);
+
+void PrintModule();
+
+extern std::map<std::string, std::unique_ptr<PrototypeAST>> functionProtos;
diff --git a/Kaleidoscope/lexer.cpp b/Kaleidoscope/lexer.cpp
new file mode 100644 (file)
index 0000000..ac75490
--- /dev/null
@@ -0,0 +1,352 @@
+#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;
+}
diff --git a/Kaleidoscope/lexer.h b/Kaleidoscope/lexer.h
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/Kaleidoscope/main.cpp b/Kaleidoscope/main.cpp
deleted file mode 100644 (file)
index 1e6814a..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-//
-//  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;
-}
diff --git a/Kaleidoscope/makefile b/Kaleidoscope/makefile
new file mode 100644 (file)
index 0000000..aee7f4b
--- /dev/null
@@ -0,0 +1,2 @@
+all:
+       clang++ -g `llvm-config --cxxflags --ldflags --system-libs --libs core mcjit native passes interpreter` -o bin/kaleidoscope *.cpp
diff --git a/Kaleidoscope/shared.h b/Kaleidoscope/shared.h
new file mode 100644 (file)
index 0000000..b92baf0
--- /dev/null
@@ -0,0 +1,14 @@
+//
+//  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 */
diff --git a/Kaleidoscope/stdlib.cpp b/Kaleidoscope/stdlib.cpp
new file mode 100644 (file)
index 0000000..08ccfd8
--- /dev/null
@@ -0,0 +1,20 @@
+//
+//  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;
+}
diff --git a/Kaleidoscope/stdlib.hpp b/Kaleidoscope/stdlib.hpp
new file mode 100644 (file)
index 0000000..012512c
--- /dev/null
@@ -0,0 +1,14 @@
+//
+//  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 */