Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

It works on my machine! #47

Merged
merged 1 commit into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
.vscode
main
test
*.swp
*.out
139 changes: 139 additions & 0 deletions compiler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#include "xos.h"

namespace xos {
Compiler::Compiler() {
TheContext = std::make_unique<LLVMContext>();
TheModule = std::make_unique<Module>("my cool jit", *TheContext);
Builder = std::make_unique<IRBuilder<>>(*TheContext);
}

Value *Compiler::LogErrorV(const char *Str) {
printf("Error: %s\n", Str);
return nullptr;
}

// Value *Compiler::NumberExprAST() {
// return ConstantFP::get(*TheContext, APInt(Val));
// }
//
// Value *Compiler::VariableExprAST() {
// // Look this variable up in the function.
// Value *V = NamedValues[Name];
// if (!V)
// return LogErrorV("Unknown variable name");
// return V;
// }
//
// Value *Compiler::BinaryExprAST() {
// 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 *Compiler::CallExprAST() {
// // 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<Value *> 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");
// }

Value *Compiler::StringExprAST(const ast::Str &str) {
return Builder->CreateGlobalStringPtr(str.getStr());
}

Value *Compiler::OutExprAST(const ast::Out &out) {
/* Dispatch call to printf. We can do this by creating another function called
* printf, similar to how we created other functions in here. Then call it
* with out string arg. This involves two things:
* 1. Create another function.
* 2. Explicit call to printf.
*
* */
FunctionType *pfFT =
FunctionType::get(Type::getInt32Ty(*TheContext),
{Type::getInt8Ty(*TheContext)->getPointerTo()}, false);
Function *pf = Function::Create(pfFT, Function::ExternalLinkage, "printf",
TheModule.get());
return Builder->CreateCall(pf, {StringExprAST(out.getExpr())});
}

Function *Compiler::PrototypeAST(const ast::Prototype &proto) {
// Make the function type: double(double,double) etc.
FunctionType *FT = FunctionType::get(Type::getVoidTy(*TheContext), {}, false);

Function *F = Function::Create(FT, Function::ExternalLinkage, proto.getName(),
TheModule.get());

// Set names for all arguments.
// unsigned Idx = 0;
// for (auto &Arg : F->args())
// Arg.setName(Args[Idx++]);

return F;
}

Function *Compiler::FunctionAST(const ast::Func &func) {
// First, check for an existing function from a previous 'extern' declaration.
Function *TheFunction = TheModule->getFunction(func.getProto().getName());

if (!TheFunction) TheFunction = PrototypeAST(func.getProto());

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 = OutExprAST(func.getBody())) {
// Finish off the function.
// Builder->CreateRet(RetVal);
Builder->CreateRetVoid();

// Validate the generated code, checking for consistency.
verifyFunction(*TheFunction);

return TheFunction;
}

// Error reading body, remove function.
TheFunction->eraseFromParent();
return nullptr;
}

void Compiler::compile(const ast::Func &funcAST) { FunctionAST(funcAST); }

} // end namespace xos
16 changes: 6 additions & 10 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,12 @@ int main(int argc, char **argv) {

std::ifstream input(argv[1]);
xos::Lexer lexer(input);
while (1) {
xos::Result<xos::Token> tok = lexer.Lex();
if (tok.hasError()) {
std::cerr << tok.getError() << std::endl;
return 1;
}
if (tok.get().getKind() == xos::Token::eof) break;
std::cout << tok.get().getVal() << " , ";
}

// xos::Result<xos::Token> tok = lexer.Lex();
xos::Parser parser(lexer);
auto func = parser.parseFunc();
xos::Compiler compiler;
compiler.compile(*func);
compiler.TheModule->dump();
std::cout << std::endl;
return 0;
}
20 changes: 14 additions & 6 deletions makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
CC ?= gcc # version?
CXX ?= g++
CPPFLAGS = -std=c++17 -Wall -Wextra -Wconversion -Werror -fno-rtti -fno-exceptions $(EXTRA_CPPFLAGS) -g
CC = gcc # version?
CXX = g++
CPPFLAGS = -std=c++17 -Wall -Wextra -Wconversion -Werror -fno-rtti -fno-exceptions -fdata-sections -ffunction-sections $(EXTRA_CPPFLAGS) -g
LLVM_CONFIG ?= /Users/alekhya/Projects/llvm/build/bin/llvm-config
LLVM_CONFIG_CXX_FLAGS = $(shell $(LLVM_CONFIG) --cxxflags)
LLVM_CONFIG_LD_FLAGS = $(shell $(LLVM_CONFIG) --ldflags)
LLVM_CONFIG_SYSTEM_LIBS = $(shell $(LLVM_CONFIG) --system-libs)
LLVM_CONFIG_LIBS = $(shell $(LLVM_CONFIG) --libs core)

CPPFLAGS := $(LLVM_CONFIG_CXX_FLAGS) $(CPPFLAGS)
LDFLAGS := $(LLVM_CONFIG_LD_FLAGS) $(LLVM_CONFIG_SYSTEM_LIBS) $(LLVM_CONFIG_LIBS) $(LDFLAGS) -Wl,-dead_strip

# Add new source files here.
SRCS = lexer.cpp parser.cpp
SRCS = lexer.cpp parser.cpp compiler.cpp
HDRS = xos.h

OBJS = $(SRCS:.cpp=.o)
Expand All @@ -15,7 +23,7 @@ TEST = test
all: $(EXE)

$(EXE): $(OBJS) main.o
$(CXX) $(CPPFLAGS) $^ -o $@
$(CXX) $(CPPFLAGS) $^ -o $@ $(LDFLAGS)

%.o: %.cpp $(HDRS)
$(CXX) $(CPPFLAGS) -c $< -o $@
Expand All @@ -27,7 +35,7 @@ test.o: test.cpp $(HDRS)
#
# $ make test GTEST_HDR=<path to include dir> GTEST_LIB=<path to lib dir>
$(TEST): test.o $(OBJS)
$(CXX) $(CPPFLAGS) $^ -o $@ -lgtest_main -lgtest -L$(GTEST_LIB)
$(CXX) $(CPPFLAGS) $^ -o $@ -lgtest_main -lgtest -L$(GTEST_LIB) $(LDFLAGS)

clean:
rm -rf $(EXE) *.o $(TEST)
Expand Down
2 changes: 1 addition & 1 deletion parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Result<ast::Func> Parser::parseFunc() {
Result<ast::Out> body = parseBody();
if (body.hasError()) return body;
return Result<ast::Func>(std::unique_ptr<ast::Prototype>(pres.Release()),
std::unique_ptr<ast::Expr>(body.Release()));
std::unique_ptr<ast::Out>(body.Release()));
}

Result<ast::Out> Parser::parseBody() {
Expand Down
2 changes: 1 addition & 1 deletion test_input.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
main( () => () )
out "Hello World"
out "Hi! I am ALIVE!"

70 changes: 52 additions & 18 deletions xos.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#ifndef XOS_H_
#define XOS_H_
#pragma once

#include <assert.h>
#include <stdint.h>
Expand All @@ -9,11 +8,22 @@
#include <cassert>
#include <iostream>
#include <istream>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <vector>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wconversion"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Value.h"
#include "llvm/IR/Verifier.h"
#pragma GCC diagnostic pop
using namespace llvm;

namespace xos {

// Just in case we ever decide to parse a file with more than 2^32 rows/cols,
Expand Down Expand Up @@ -198,26 +208,14 @@ class Prototype {
return_type_ == other.return_type_;
}

std::string getName() const { return name_; }

private:
std::string name_;
std::vector<std::string> args_;
std::string return_type_;
};

class Func {
public:
Func(std::unique_ptr<Prototype> proto, std::unique_ptr<Expr> body)
: proto_(std::move(proto)), body_(std::move(body)) {}

bool operator==(const Func &other) const {
return *proto_ == *other.proto_ && *body_ == *other.body_;
}

private:
std::unique_ptr<Prototype> proto_;
std::unique_ptr<Expr> body_;
};

class Str : public Expr {
public:
Str(const std::string &str) : str_(str) {}
Expand All @@ -238,6 +236,24 @@ class Out : public Expr {
std::unique_ptr<Str> expr_;
};

class Func {
public:
Func(std::unique_ptr<Prototype> proto, std::unique_ptr<Out> body)
: proto_(std::move(proto)), body_(std::move(body)) {}

bool operator==(const Func &other) const {
return *proto_ == *other.proto_ && *body_ == *other.body_;
}

const Prototype &getProto() const { return *proto_; }

const Out &getBody() const { return *body_; }

private:
std::unique_ptr<Prototype> proto_;
std::unique_ptr<Out> body_;
};

} // namespace ast

class Parser {
Expand All @@ -253,6 +269,24 @@ class Parser {
Lexer &lexer_;
};

} // namespace xos
class Compiler {
std::unique_ptr<LLVMContext> TheContext;
std::unique_ptr<IRBuilder<>> Builder;
std::map<std::string, Value *> NamedValues;

#endif // XOS_H_
public:
std::unique_ptr<Module> TheModule;
Compiler();
Value *LogErrorV(const char *str);
// Value *NumberExprAST();
// Value *VariableExprAST();
// Value *BinaryExprAST();
// Value *CallExprAST();
Value *StringExprAST(const ast::Str &str);
Value *OutExprAST(const ast::Out &out);
Function *PrototypeAST(const ast::Prototype &);
Function *FunctionAST(const ast::Func &func);
void compile(const ast::Func &funcAST);
};

} // namespace xos
Loading