aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2009-01-23 08:46:30 +0000
committerDavid Robillard <d@drobilla.net>2009-01-23 08:46:30 +0000
commit604c0089d95a25764925636915d268bf5b591b15 (patch)
treebf289927e2042ebc467e82e710f909588298cf2c
parent024e2e32c22804f1bd95b64c17192b02a5541843 (diff)
downloadresp-604c0089d95a25764925636915d268bf5b591b15.tar.gz
resp-604c0089d95a25764925636915d268bf5b591b15.tar.bz2
resp-604c0089d95a25764925636915d268bf5b591b15.zip
Arithmetic.
git-svn-id: http://svn.drobilla.net/resp/llvm-lisp@5 ad02d1e2-f140-0410-9f75-f8b11f17cedd
-rw-r--r--ll.cpp114
1 files changed, 93 insertions, 21 deletions
diff --git a/ll.cpp b/ll.cpp
index 8a4ceb5..41820e3 100644
--- a/ll.cpp
+++ b/ll.cpp
@@ -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);