diff options
Diffstat (limited to 'll.cpp')
-rw-r--r-- | ll.cpp | 114 |
1 files changed, 93 insertions, 21 deletions
@@ -129,14 +129,28 @@ struct AST { virtual bool evaluatable() const { return true; } }; -/// Numeric literals, e.g. "1.0". -struct ASTNumber : public AST { - ASTNumber(double val) : _val(val) {} +/// Definition, e.g. (def x 2) or (def (square y) (* y y)) +struct ASTDefinition : public AST { + ASTDefinition(const string& n, AST* v) : _name(n), _val(v) {} virtual Value* Codegen(CEnv& cenv); private: - double _val; + string _name; + AST* _val; +}; + + +/// Primitive (builtin function) +struct ASTPrimitive : public AST { + ASTPrimitive(Instruction::BinaryOps o, vector<AST*>& a) + : _op(o), _args(a) {} + virtual Value* Codegen(CEnv& cenv); +private: + Instruction::BinaryOps _op; + AST* _lhs; + vector<AST*> _args; }; + /// Variable reference (i.e. symbol), e.g. "a". struct ASTVariable : public AST { ASTVariable(const string& name) : _name(name) {} @@ -145,6 +159,14 @@ private: string _name; }; +/// Numeric literal, e.g. "1.0". +struct ASTNumber : public AST { + ASTNumber(double val) : _val(val) {} + virtual Value* Codegen(CEnv& cenv); +private: + double _val; +}; + /// Function call, e.g. "(func arg1 arg2)". struct ASTCall : public AST { ASTCall(const string& f, vector<AST*>& a) : _func(f), _args(a) {} @@ -194,6 +216,10 @@ private: * Parser - Transform S-Expressions into AST nodes * ***************************************************************************/ +#define SPECIAL_IF "if" +#define SPECIAL_DEFINE "def" +#define SPECIAL_FOREIGN "foreign" + static const std::string& head(const SExp& exp) { static const std::string empty = ""; @@ -224,7 +250,7 @@ static AST* parseNumberExpr(const SExp& exp) /// ifexpr ::= ("if" expression expression expression) static AST* parseIfExpr(const SExp& exp) { - assert(head(exp) == "if"); + assert(head(exp) == SPECIAL_IF); list<SExp>::const_iterator i = exp.list.begin(); ++i; @@ -245,6 +271,14 @@ static AST* parseCallExpr(const SExp& exp) vector<AST*> params; for (++i; i != exp.list.end(); ++i) params.push_back(parseExpression(*i)); + + if (name.length() == 1) { + switch (name[0]) { + case '+': return new ASTPrimitive(Instruction::Add, params); + case '-': return new ASTPrimitive(Instruction::Sub, params); + case '*': return new ASTPrimitive(Instruction::Mul, params); + } + } return new ASTCall(name, params); } @@ -267,22 +301,27 @@ static ASTPrototype* parsePrototype(bool foreign, const SExp& exp) } /// definition ::= ("def" prototype expression) -static ASTFunction* parseDefinition(const SExp& exp) +static AST* parseDefinition(const SExp& exp) { - assert(head(exp) == "def"); + assert(head(exp) == SPECIAL_DEFINE); list<SExp>::const_iterator i = exp.list.begin(); ++i; - ASTPrototype* proto = parsePrototype(false, *i++); - AST* body = parseExpression(*i++); - - return new ASTFunction(proto, body); + if (i->type == SExp::LIST) { + ASTPrototype* proto = parsePrototype(false, *i++); + AST* body = parseExpression(*i++); + return new ASTFunction(proto, body); + } else { + const string& name = i->atom; + AST* value = parseExpression(*++i); + return new ASTDefinition(name, value); + } } /// foreign ::= ("foreign" prototype expression) static ASTPrototype* parseForeign(const SExp& exp) { - assert(head(exp) == "foreign"); + assert(head(exp) == SPECIAL_FOREIGN); list<SExp>::const_iterator i = exp.list.begin(); ++i; @@ -293,11 +332,13 @@ static AST* parseExpression(const SExp& exp) { if (exp.type == SExp::LIST) { const string& form = head(exp); - if (form == "if") { + if (exp.list.empty()) { + return NULL; + } else if (form == SPECIAL_IF) { return parseIfExpr(exp); - } else if (form == "def") { + } else if (form == SPECIAL_DEFINE) { return parseDefinition(exp); - } else if (form == "foreign") { + } else if (form == SPECIAL_FOREIGN) { return parseForeign(exp); } else { return parseCallExpr(exp); @@ -324,7 +365,7 @@ struct CEnv { // Set up the optimizer pipeline. // Register info about how the target lays out data structures. fpm.add(new TargetData(*target)); - // Do simple "peephole" and bit-twiddline optimizations. + // Do simple "peephole" and bit-twiddling optimizations. fpm.add(createInstructionCombiningPass()); // Reassociate expressions. fpm.add(createReassociatePass()); @@ -348,10 +389,20 @@ Value* ASTNumber::Codegen(CEnv& cenv) Value* ASTVariable::Codegen(CEnv& cenv) { map<string, Value*>::const_iterator v = cenv.env.find(_name); - if (v == cenv.env.end()) throw SyntaxError("Undefined identifier"); + if (v == cenv.env.end()) + throw SyntaxError((string("Undefined symbol '") + _name + "'").c_str()); return v->second; } +Value* ASTDefinition::Codegen(CEnv& cenv) +{ + map<string, Value*>::const_iterator v = cenv.env.find(_name); + if (v != cenv.env.end()) throw SyntaxError("Symbol redefinition"); + Value* valCode = _val->Codegen(cenv); + cenv.env[_name] = valCode; + return valCode; +} + Value* ASTCall::Codegen(CEnv& cenv) { // Look up the name in the global module table. @@ -450,8 +501,6 @@ Function* ASTPrototype::Funcgen(CEnv& cenv) Function* ASTFunction::Funcgen(CEnv& cenv) { - cenv.env.clear(); - Function* f = _proto->Funcgen(cenv); // Create a new basic block to start insertion into. @@ -472,6 +521,25 @@ Function* ASTFunction::Funcgen(CEnv& cenv) return 0; // Never reached } +Value* ASTPrimitive::Codegen(CEnv& cenv) +{ + vector<Value*> params; + for (vector<AST*>::const_iterator a = _args.begin(); a != _args.end(); ++a) + params.push_back((*a)->Codegen(cenv)); + + switch (params.size()) { + case 0: + throw SyntaxError("Primitive expects at least 1 argument\n"); + case 1: + return params[0]; + default: + Value* val = cenv.builder.CreateBinOp(_op, params[0], params[1]); + for (size_t i = 2; i < params.size(); ++i) + val = cenv.builder.CreateBinOp(_op, val, params[i]); + return val; + } +} + /*************************************************************************** * REPL - Interactively compile, optimise, and execute code * @@ -484,9 +552,13 @@ static void repl(CEnv& cenv, ExecutionEngine* engine) std::cout << "> "; std::cout.flush(); SExp exp = readExpression(std::cin); + if (exp.type == SExp::LIST && exp.list.empty()) + break; try { AST* ast = parseExpression(exp); + if (!ast) + continue; if (ast->evaluatable()) { ASTPrototype* proto = new ASTPrototype(false, "", vector<string>()); ASTFunction* func = new ASTFunction(proto, ast); @@ -494,6 +566,7 @@ static void repl(CEnv& cenv, ExecutionEngine* engine) void* fp = engine->getPointerToFunction(code); double (*f)() = (double (*)())fp; std::cout << f() << endl; + code->eraseFromParent(); } else { Value* code = ast->Codegen(cenv); std::cout << "Generated code:" << endl; @@ -515,8 +588,7 @@ main() { Module* module = new Module("interactive"); ExecutionEngine* engine = ExecutionEngine::create(module); - - CEnv cenv(module, engine->getTargetData()); + CEnv cenv(module, engine->getTargetData()); repl(cenv, engine); |