Skip to content
Open
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
parser
parser.hpp
parser.cpp
tokens.cpp
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ parser.hpp: parser.cpp
tokens.cpp: tokens.l parser.hpp
lex -o $@ $^

parser: parser.cpp codegen.cpp main.cpp tokens.cpp
g++ -o $@ `llvm-config --libs core jit native --cxxflags --ldflags` *.cpp
parser: parser.cpp codegen.cpp main.cpp tokens.cpp slot.cpp
llvm-g++ -o $@ -DDEBUG `llvm-config --libs core jit native --cxxflags --ldflags` *.cpp
179 changes: 170 additions & 9 deletions codegen.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,91 @@
#include "node.h"
#include "codegen.h"
#include "parser.hpp"
#include "types.h"
#include <stdarg.h>

using namespace std;

static const StructType *ObjectType;
static const StructType *StringType;
static const PointerType *ObjectType_p;
static const PointerType *StringType_p;

static const PointerType *GenericPointerType = PointerType::get(IntegerType::get(8), 0);

object (*objalloc)() = NULL;

const StructType* CodeGenContext::addStructType(char *name, size_t numArgs, ...)
{
std::vector<const Type*> fields;
PATypeHolder fwdType = OpaqueType::get();
fields.push_back(PointerType::get(fwdType, 0));
fields.push_back(GenericPointerType);

va_list list;
va_start(list, numArgs);
for (int i = 0; i < numArgs; i++) {
fields.push_back(va_arg(list, const Type*));
}
va_end(list);

StructType *stype = StructType::get(fields, false);
cast<OpaqueType>(fwdType.get())->refineAbstractTypeTo(stype);
module->addTypeName(name, stype);
return cast<StructType>(fwdType.get());
}

FunctionType* CodeGenContext::functionType(const Type* retType, bool varargs, size_t numArgs, ...)
{
std::vector<const Type*> args;
va_list list;
va_start(list, numArgs);
for (int i = 0; i < numArgs; i++) {
args.push_back(va_arg(list, const Type*));
}
va_end(list);

return FunctionType::get(retType, args, varargs);
}

Function* CodeGenContext::addExternalFunction(char *name, FunctionType *fType)
{
Function *f = Function::Create(fType, GlobalValue::ExternalLinkage, name, module);
f->setCallingConv(CallingConv::C);
return f;
}

Function* CodeGenContext::addFunction(char *name, FunctionType *fType, void (^block)(BasicBlock *))
{
Function *f = Function::Create(fType, GlobalValue::InternalLinkage, name, module);
f->setCallingConv(CallingConv::C);
if (block) block(BasicBlock::Create("entry", f, 0));
return f;
}

/* Compile the AST into a module */
void CodeGenContext::generateCode(NBlock& root)
{
std::cout << "Generating code...\n";

ObjectType = addStructType("object", 1, GenericPointerType);
ObjectType_p = PointerType::get(ObjectType, 0);
StringType = addStructType("string", 3, GenericPointerType, GenericPointerType, Type::Int64Ty);
StringType_p = PointerType::get(ObjectType, 0);

/* Create objalloc function */
objallocFunction = addFunction("objalloc", functionType(ObjectType_p, false, 0), ^(BasicBlock *blk) {
ReturnInst::Create(new MallocInst(ObjectType, "", blk), blk);
});

/* Create refs to putSlot, getSlot and newobj */
putSlotFunction = addExternalFunction("putSlot",
functionType(Type::VoidTy, false, 3, ObjectType_p, GenericPointerType, ObjectType_p));
getSlotFunction = addExternalFunction("getSlot",
functionType(ObjectType_p, false, 3, ObjectType_p, GenericPointerType, Type::Int32Ty));
newobjFunction = addExternalFunction("newobj",
functionType(ObjectType_p, false, 1, ObjectType_p));

/* Create the top level interpreter function to call as entry */
vector<const Type*> argTypes;
FunctionType *ftype = FunctionType::get(Type::VoidTy, argTypes, false);
Expand All @@ -17,6 +94,8 @@ void CodeGenContext::generateCode(NBlock& root)

/* Push a new variable/block context */
pushBlock(bblock);
cObject = new GlobalVariable(ObjectType, true,
GlobalValue::InternalLinkage, 0, "class.Object", module);
root.codeGen(*this); /* emit bytecode for the toplevel block */
ReturnInst::Create(bblock);
popBlock();
Expand All @@ -35,6 +114,7 @@ GenericValue CodeGenContext::runCode() {
std::cout << "Running code...\n";
ExistingModuleProvider *mp = new ExistingModuleProvider(module);
ExecutionEngine *ee = ExecutionEngine::create(mp, false);
objalloc = (object (*)())ee->getPointerToFunction(objallocFunction);
vector<GenericValue> noargs;
GenericValue v = ee->runFunction(mainFunction, noargs);
std::cout << "Code was run.\n";
Expand All @@ -50,9 +130,48 @@ static const Type *typeOf(const NIdentifier& type)
else if (type.name.compare("double") == 0) {
return Type::FP128Ty;
}
else if (type.name.compare("object") == 0) {
return ObjectType_p;
}
return Type::VoidTy;
}

static Value* getStringConstant(const string& str, CodeGenContext& context)
{
Constant *n = ConstantArray::get(str.c_str(), true);
GlobalVariable *g = new GlobalVariable(n->getType(), true,
GlobalValue::InternalLinkage, 0, str.c_str(), context.module);
g->setInitializer(n);
std::vector<Constant*> ptr;
ptr.push_back(ConstantInt::get(Type::Int32Ty, 0));
ptr.push_back(ConstantInt::get(Type::Int32Ty, 0));
return ConstantExpr::getGetElementPtr(g, &ptr[0], ptr.size());
}

static Value* resolveReference(NReference& ref, CodeGenContext& context, bool ignoreLast = false)
{
Value *curValue = ref.refs.front()->codeGen(context);
IdentifierList::const_iterator it;
for (it = ref.refs.begin() + 1; it != ref.refs.end(); it++) {
NIdentifier& ident = **it;
if (ignoreLast && it == ref.refs.end() - 1) return curValue;

std::cout << "Next ident " << ident.name << endl;
Value *ch = getStringConstant(ident.name, context);

std::vector<Value*> params;
params.push_back(curValue);
params.push_back(ch);
params.push_back(ConstantInt::get(Type::Int32Ty, 1));
std::cout << "About to call " << typeid(curValue).name() << " :: " << typeid(ch).name() << std::endl;
CallInst *call = CallInst::Create(context.getSlotFunction,
params.begin(), params.end(), "", context.currentBlock());
call->setCallingConv(CallingConv::C);
curValue = call;
}
return curValue;
}

/* -- Code Generation -- */

Value* NInteger::codeGen(CodeGenContext& context)
Expand All @@ -69,16 +188,45 @@ Value* NDouble::codeGen(CodeGenContext& context)

Value* NIdentifier::codeGen(CodeGenContext& context)
{
std::cout << "Creating identifier reference: " << name << endl;
std::cout << "Creating identifier: " << name << endl;
if (name.compare("null") == 0) {
return ConstantPointerNull::get(ObjectType_p);
}
if (context.locals().find(name) == context.locals().end()) {
std::cerr << "undeclared variable " << name << endl;
return NULL;
std::cout << "Instantiating object " << name << endl;
std::vector<Value*> args;
args.push_back(ConstantPointerNull::get(ObjectType_p));
CallInst *call = CallInst::Create(context.newobjFunction, args.begin(),
args.end(), "", context.currentBlock());
return context.locals()[name] = call;
}
return new LoadInst(context.locals()[name], "", false, context.currentBlock());
}

Value* NString::codeGen(CodeGenContext& context)
{
std::cout << "Creating string: " << value << endl;
std::vector<Value*> args;
args.push_back(ConstantPointerNull::get(ObjectType_p));
return CallInst::Create(context.newobjFunction, args.begin(),
args.end(), "", context.currentBlock());
}

Value* NReference::codeGen(CodeGenContext& context)
{
if (refs.size() == 1) {
NIdentifier *ident = refs.front();
std::cout << "Creating reference: " << ident->name << endl;
return ident->codeGen(context);
}

std::cout << "Creating reference" << endl;
return resolveReference(*this, context);
}

Value* NMethodCall::codeGen(CodeGenContext& context)
{
NIdentifier& id = *ref.refs.front();
Function *function = context.module->getFunction(id.name.c_str());
if (function == NULL) {
std::cerr << "no such function " << id.name << endl;
Expand Down Expand Up @@ -114,12 +262,23 @@ Value* NBinaryOperator::codeGen(CodeGenContext& context)

Value* NAssignment::codeGen(CodeGenContext& context)
{
std::cout << "Creating assignment for " << lhs.name << endl;
if (context.locals().find(lhs.name) == context.locals().end()) {
std::cerr << "undeclared variable " << lhs.name << endl;
return NULL;
std::cout << "Creating assignment " << endl;
if (lhs.refs.size() == 1) {
return new StoreInst(rhs.codeGen(context), context.locals()[lhs.refs.front()->name], false, context.currentBlock());
}
else {
Value *value = resolveReference(lhs, context, true);
Value *sym = getStringConstant(lhs.refs.back()->name, context);

std::vector<Value*> params;
params.push_back(value);
params.push_back(sym);
params.push_back(rhs.codeGen(context));
CallInst *call = CallInst::Create(context.putSlotFunction,
params.begin(), params.end(), "", context.currentBlock());
call->setCallingConv(CallingConv::C);
return call;
}
return new StoreInst(rhs.codeGen(context), context.locals()[lhs.name], false, context.currentBlock());
}

Value* NBlock::codeGen(CodeGenContext& context)
Expand All @@ -146,14 +305,16 @@ Value* NVariableDeclaration::codeGen(CodeGenContext& context)
AllocaInst *alloc = new AllocaInst(typeOf(type), id.name.c_str(), context.currentBlock());
context.locals()[id.name] = alloc;
if (assignmentExpr != NULL) {
NAssignment assn(id, *assignmentExpr);
NReference ref(id);
NAssignment assn(ref, *assignmentExpr);
assn.codeGen(context);
}
return alloc;
}

Value* NFunctionDeclaration::codeGen(CodeGenContext& context)
{
std::cout << id.name << endl;
vector<const Type*> argTypes;
VariableList::const_iterator it;
for (it = arguments.begin(); it != arguments.end(); it++) {
Expand Down
9 changes: 9 additions & 0 deletions codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,18 @@ class CodeGenContext {
Function *mainFunction;

public:
Value *cObject;
Module *module;
Function *objallocFunction;
Function *putSlotFunction;
Function *getSlotFunction;
Function *newobjFunction;
CodeGenContext() { module = new Module("main"); }

const StructType* addStructType(char *name, size_t numArgs, ...);
FunctionType* functionType(const Type* retType, bool varargs, size_t numArgs, ...);
Function* addExternalFunction(char *name, FunctionType *ftype);
Function *addFunction(char *name, FunctionType *ftype, void (^block)(BasicBlock *));
void generateCode(NBlock& root);
GenericValue runCode();
std::map<std::string, Value*>& locals() { return blocks.top()->locals; }
Expand Down
29 changes: 23 additions & 6 deletions node.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ class CodeGenContext;
class NStatement;
class NExpression;
class NVariableDeclaration;
class NIdentifier;

typedef std::vector<NStatement*> StatementList;
typedef std::vector<NExpression*> ExpressionList;
typedef std::vector<NIdentifier*> IdentifierList;
typedef std::vector<NVariableDeclaration*> VariableList;

class Node {
Expand Down Expand Up @@ -44,13 +46,28 @@ class NIdentifier : public NExpression {
virtual llvm::Value* codeGen(CodeGenContext& context);
};

class NString : public NExpression {
public:
std::string value;
NString(const std::string& value) : value(value) { }
virtual llvm::Value* codeGen(CodeGenContext& context);
};

class NReference : public NExpression {
public:
IdentifierList refs;
NReference() { }
NReference(NIdentifier& id) { refs.push_back(&id); }
virtual llvm::Value* codeGen(CodeGenContext& context);
};

class NMethodCall : public NExpression {
public:
const NIdentifier& id;
const NReference& ref;
ExpressionList arguments;
NMethodCall(const NIdentifier& id, ExpressionList& arguments) :
id(id), arguments(arguments) { }
NMethodCall(const NIdentifier& id) : id(id) { }
NMethodCall(const NReference& ref, ExpressionList& arguments) :
ref(ref), arguments(arguments) { }
NMethodCall(const NReference& ref) : ref(ref) { }
virtual llvm::Value* codeGen(CodeGenContext& context);
};

Expand All @@ -66,9 +83,9 @@ class NBinaryOperator : public NExpression {

class NAssignment : public NExpression {
public:
NIdentifier& lhs;
NReference& lhs;
NExpression& rhs;
NAssignment(NIdentifier& lhs, NExpression& rhs) :
NAssignment(NReference& lhs, NExpression& rhs) :
lhs(lhs), rhs(rhs) { }
virtual llvm::Value* codeGen(CodeGenContext& context);
};
Expand Down
19 changes: 13 additions & 6 deletions parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
NStatement *stmt;
NIdentifier *ident;
NVariableDeclaration *var_decl;
std::vector<NVariableDeclaration*> *varvec;
std::vector<NExpression*> *exprvec;
VariableList *varvec;
NReference *ref;
ExpressionList *exprvec;
std::string *string;
int token;
}
Expand All @@ -24,7 +25,7 @@
match our tokens.l lex file. We also define the node type
they represent.
*/
%token <string> TIDENTIFIER TINTEGER TDOUBLE
%token <string> TIDENTIFIER TINTEGER TDOUBLE TSTRING
%token <token> TCEQ TCNE TCLT TCLE TCGT TCGE TEQUAL
%token <token> TLPAREN TRPAREN TLBRACE TRBRACE TCOMMA TDOT
%token <token> TPLUS TMINUS TMUL TDIV
Expand All @@ -35,6 +36,7 @@
calling an (NIdentifier*). It makes the compiler happy.
*/
%type <ident> ident
%type <ref> ref
%type <expr> numeric expr
%type <varvec> func_decl_args
%type <exprvec> call_args
Expand Down Expand Up @@ -77,6 +79,9 @@ func_decl_args : /*blank*/ { $$ = new VariableList(); }
| var_decl { $$ = new VariableList(); $$->push_back($<var_decl>1); }
| func_decl_args TCOMMA var_decl { $1->push_back($<var_decl>3); }
;

ref : ident { $$ = new NReference(); $$->refs.push_back($1); }
| ref TDOT ident { $1->refs.push_back($3); }

ident : TIDENTIFIER { $$ = new NIdentifier(*$1); delete $1; }
;
Expand All @@ -85,12 +90,14 @@ numeric : TINTEGER { $$ = new NInteger(atol($1->c_str())); delete $1; }
| TDOUBLE { $$ = new NDouble(atof($1->c_str())); delete $1; }
;

expr : ident TEQUAL expr { $$ = new NAssignment(*$<ident>1, *$3); }
| ident TLPAREN call_args TRPAREN { $$ = new NMethodCall(*$1, *$3); delete $3; }
| ident { $<ident>$ = $1; }
expr : ref TEQUAL expr { $$ = new NAssignment(*$1, *$3); }
| ref TLPAREN call_args TRPAREN { $$ = new NMethodCall(*$1, *$3); delete $3; }
| ref { $<ref>$ = $1; }
| numeric
| TSTRING { $$ = new NString(*$1); }
| expr comparison expr { $$ = new NBinaryOperator(*$1, $2, *$3); }
| TLPAREN expr TRPAREN { $$ = $2; }
| block
;

call_args : /*blank*/ { $$ = new ExpressionList(); }
Expand Down
Loading