summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortomsmeding <tom.smeding@gmail.com>2017-02-10 23:35:02 +0100
committertomsmeding <tom.smeding@gmail.com>2017-02-10 23:35:02 +0100
commitca45da0925cabc3bbf0d22d5d23ccb9a25d8e228 (patch)
treeb96cb309d210e62deccdebfcc5646cfa2f3cb384
parent269f28df980f34895c3c7181140963b4a86a1afc (diff)
Preliminary 'compiling'
-rw-r--r--ast.cpp6
-rw-r--r--ast.h4
-rw-r--r--evaluate.cpp170
-rw-r--r--evaluate.h91
-rw-r--r--main.cpp5
-rw-r--r--parser.cpp33
-rw-r--r--test.squig1
7 files changed, 292 insertions, 18 deletions
diff --git a/ast.cpp b/ast.cpp
index b57b5ef..e1abf81 100644
--- a/ast.cpp
+++ b/ast.cpp
@@ -45,7 +45,7 @@ ostream& operator<<(ostream &os,Site site){
ScopeDef::ScopeDef():type(Type::direct){}
-ScopeDef::ScopeDef(Type type,const StatementList &body,const vector<Expression> &args)
+ScopeDef::ScopeDef(Type type,const StatementList &body,const vector<Name> &args)
:type(type),body(body),args(args){}
/*ScopeDef::ScopeDef(Type type,const StatementList &body,const vector<Name> &nameargs)
:type(type),body(body){
@@ -67,10 +67,10 @@ ostream& operator<<(ostream &os,const ScopeDef &scope){
if(scope.args.size()!=0){
os<<'(';
bool first=true;
- for(const Expression &ex : scope.args){
+ for(const Name &name : scope.args){
if(!first)os<<", ";
else first=false;
- os<<ex;
+ os<<name;
}
os<<')';
}
diff --git a/ast.h b/ast.h
index 3eec1a3..c681d52 100644
--- a/ast.h
+++ b/ast.h
@@ -37,12 +37,12 @@ public:
Type type;
StatementList body;
- vector<Expression> args;
+ vector<Name> args;
Site site;
ScopeDef();
- ScopeDef(Type type,const StatementList &body,const vector<Expression> &args);
+ ScopeDef(Type type,const StatementList &body,const vector<Name> &args);
// ScopeDef(Type type,const StatementList &body,const vector<Name> &args);
};
diff --git a/evaluate.cpp b/evaluate.cpp
index ebfb773..550fc49 100644
--- a/evaluate.cpp
+++ b/evaluate.cpp
@@ -5,12 +5,31 @@
using namespace std;
+ExecutionError::ExecutionError(const string &what_arg)
+ :runtime_error(what_arg){}
+ExecutionError::ExecutionError(const char *what_arg)
+ :runtime_error(what_arg){}
+
+CompilationError::CompilationError(const string &what_arg)
+ :runtime_error(what_arg){}
+CompilationError::CompilationError(const char *what_arg)
+ :runtime_error(what_arg){}
+CompilationError::CompilationError(Site site,const string &what_arg)
+ :runtime_error(site.filename+":"+to_string(site.lnum)+":"+to_string(site.linex)+": "+what_arg){}
+
+
+Value::Value()
+ :type(Type::nil){}
Value::Value(double numval)
:type(Type::number),numval(numval){}
Value::Value(const string &strval)
:type(Type::string),strval(strval){}
-Value::Value(ScopeVal *scope)
- :type(Type::scope),scope(scope){}
+Value::Value(ScopeVal *scopeval)
+ :type(Type::scope),scopeval(scopeval){}
+
+
+ScopeVal::ScopeVal(const ScopeDef &scopeDef)
+ :scopeDef(scopeDef){}
namespace A {
@@ -51,9 +70,152 @@ namespace A {
it->second.count--;
}
}
+
+ void unref_all(){
+ for(const pair<void*,CollItem> &p : collection){
+ p.second.deleter(p.first);
+ }
+ }
+}
+
+
+Assembly::Instruction::Instruction(Type type):type(type){
+ if(type==Type::pushnum||type==Type::pushstr||type==Type::pushscope||
+ type==Type::create||type==Type::store||type==Type::load||type==Type::call){
+ throw runtime_error("Instruction(type) called with invalid type "+to_string((int)type));
+ }
+}
+Assembly::Instruction::Instruction(Type type,double num):type(type),num(num){
+ if(type!=Type::pushnum){
+ throw runtime_error("Instruction(type,num) called with invalid type "+to_string((int)type));
+ }
+}
+Assembly::Instruction::Instruction(Type type,const string &arg):type(type){
+ if(type==Type::pushstr){
+ str=arg;
+ } else if(type==Type::create||type==Type::store||type==Type::load){
+ name=arg;
+ } else {
+ throw runtime_error("Instruction(type,string) called with invalid type "+to_string((int)type));
+ }
+}
+Assembly::Instruction::Instruction(Type type,ScopeDef *scope):type(type),scope(scope){
+ if(type!=Type::pushscope){
+ throw runtime_error("Instruction(type,scope) called with invalid type "+to_string((int)type));
+ }
+}
+Assembly::Instruction::Instruction(Type type,int nargs):type(type),nargs(nargs){
+ if(type!=Type::call){
+ throw runtime_error("Instruction(type,nargs) called with invalid type "+to_string((int)type));
+ }
+}
+
+void Assembly::codegen(const StatementList &stl){
+ for(const Statement &stmt : stl){
+ codegen(stmt);
+ }
+}
+
+void Assembly::codegen(const Statement &stmt){
+ switch(stmt.type){
+ case Statement::Type::create:
+ codegen(stmt.expr);
+ listing.emplace_back(Instruction::Type::create,stmt.dstvar);
+ break;
+
+ case Statement::Type::assign:
+ codegen(stmt.expr);
+ listing.emplace_back(Instruction::Type::store,stmt.dstvar);
+ break;
+
+ case Statement::Type::expression:
+ codegen(stmt.expr);
+ listing.emplace_back(Instruction::Type::pop);
+ break;
+ }
+}
+
+void Assembly::codegen(const Expression &expr){
+ switch(expr.type){
+ case Expression::Type::binop:
+ codegen(expr.args[0]);
+ codegen(expr.args[1]);
+ if(expr.name=="+")listing.emplace_back(Instruction::Type::add);
+ else if(expr.name=="-")listing.emplace_back(Instruction::Type::sub);
+ else if(expr.name=="*")listing.emplace_back(Instruction::Type::mul);
+ else if(expr.name=="/")listing.emplace_back(Instruction::Type::div);
+ else if(expr.name=="%")listing.emplace_back(Instruction::Type::mod);
+ else throw runtime_error("Unknown binop name '"+expr.name+"'");
+ break;
+
+ case Expression::Type::unop:
+ throw runtime_error("No unary operators known?");
+
+ case Expression::Type::call:
+ case Expression::Type::dive:
+ if(expr.name=="nil"){
+ if(expr.args.size()!=0||expr.type==Expression::Type::dive){
+ if(expr.type==Expression::Type::call)throw CompilationError(expr.site,"Cannot call nil");
+ else throw CompilationError(expr.site,"Cannot dive into nil");
+ }
+ listing.emplace_back(Instruction::Type::pushnil);
+ break;
+ }
+ listing.emplace_back(Instruction::Type::load,expr.name);
+ for(const Expression &arg : expr.args){
+ codegen(arg);
+ }
+ if(expr.args.size()!=0){
+ listing.emplace_back(Instruction::Type::call,(int)expr.args.size());
+ }
+ if(expr.type==Expression::Type::dive){
+ listing.emplace_back(Instruction::Type::enter);
+ assert(expr.scope.type==ScopeDef::Type::direct);
+ codegen(expr.scope.body);
+ listing.emplace_back(Instruction::Type::leave);
+ }
+ break;
+
+ case Expression::Type::number:
+ listing.emplace_back(Instruction::Type::pushnum,expr.numval);
+ break;
+
+ case Expression::Type::string:
+ listing.emplace_back(Instruction::Type::pushstr,expr.strval);
+ break;
+
+ case Expression::Type::scope:
+ listing.emplace_back(Instruction::Type::pushscope,new ScopeDef(expr.scope));
+ break;
+ }
+}
+
+Assembly::Assembly(const StatementList &stl){
+ codegen(stl);
}
-void evaluateSTL(const StatementList &stl){
- ;
+ostream& operator<<(ostream &os,const Assembly &as){
+ for(const Assembly::Instruction &ins : as.listing){
+ switch(ins.type){
+ case Assembly::Instruction::Type::pushnil: os<<"pushnil\n"; break;
+ case Assembly::Instruction::Type::pushnum: os<<"pushnum "<<ins.num<<"\n"; break;
+ case Assembly::Instruction::Type::pushstr: os<<"pushstr "<<ins.str<<"\n"; break;
+ case Assembly::Instruction::Type::pushscope: os<<"pushscope "<<*ins.scope<<"\n"; break;
+ case Assembly::Instruction::Type::pop: os<<"pop\n"; break;
+ case Assembly::Instruction::Type::swap: os<<"swap\n"; break;
+ case Assembly::Instruction::Type::add: os<<"add\n"; break;
+ case Assembly::Instruction::Type::sub: os<<"sub\n"; break;
+ case Assembly::Instruction::Type::mul: os<<"mul\n"; break;
+ case Assembly::Instruction::Type::div: os<<"div\n"; break;
+ case Assembly::Instruction::Type::mod: os<<"mod\n"; break;
+ case Assembly::Instruction::Type::create: os<<"create "<<ins.name<<"\n"; break;
+ case Assembly::Instruction::Type::store: os<<"store "<<ins.name<<"\n"; break;
+ case Assembly::Instruction::Type::load: os<<"load "<<ins.name<<"\n"; break;
+ case Assembly::Instruction::Type::enter: os<<"enter\n"; break;
+ case Assembly::Instruction::Type::leave: os<<"leave\n"; break;
+ case Assembly::Instruction::Type::call: os<<"call "<<ins.nargs<<"\n"; break;
+ }
+ }
+ return os;
}
diff --git a/evaluate.h b/evaluate.h
index 9c50b24..50166cd 100644
--- a/evaluate.h
+++ b/evaluate.h
@@ -1,5 +1,6 @@
#pragma once
+#include <iostream>
#include <string>
#include <unordered_map>
#include "ast.h"
@@ -7,29 +8,48 @@
using namespace std;
+class CompilationError : public runtime_error{
+public:
+ explicit CompilationError(const string &what_arg);
+ explicit CompilationError(const char *what_arg);
+ CompilationError(Site site,const string &what_arg);
+};
+
+class ExecutionError : public runtime_error{
+public:
+ explicit ExecutionError(const string &what_arg);
+ explicit ExecutionError(const char *what_arg);
+};
+
+
class ScopeVal;
class Value{
public:
enum class Type{
- number,
- string,
- scope,
+ nil,
+ number, // numval
+ string, // strval
+ scope, // scopeval
};
Type type;
double numval;
string strval;
- ScopeVal *scope;
+ ScopeVal *scopeval;
+ Value();
Value(double numval);
Value(const string &strval);
- Value(ScopeVal *scope);
+ Value(ScopeVal *scopeval);
};
class ScopeVal{
public:
+ ScopeDef scopeDef;
unordered_map<string,Value> values;
+
+ ScopeVal(const ScopeDef &scopeDef);
};
@@ -41,7 +61,66 @@ namespace A {
template <typename T>
void unref(T *value);
+ void unref_all();
+
}
-void evaluateSTL(const StatementList &stl);
+class Assembly{
+ class Instruction{
+ public:
+ enum class Type{ // Effect on the value stack is given
+ pushnil, // [ -> nil]
+ pushnum, // [ -> this.num]
+ pushstr, // [ -> this.str]
+ pushscope, // [ -> this.scope]
+ pop, // [x -> ]
+ swap, // [x,y -> y,x]
+ add, // [x,y -> x+y]
+ sub, // [x,y -> x-y]
+ mul, // [x,y -> x*y]
+ div, // [x,y -> x/y]
+ mod, // [x,y -> x%y]
+ create, // [value -> ] Creates binding this.name in the top scope
+ store, // [value -> ] Stores in the first scope to contain a this.name binding
+ load, // [ -> value] Retrieves from the first scope to contain a this.name binding
+ enter, // [scope -> ] Pushes the given scope on the scope stack
+ leave, // [ -> ] Pops from the scope stack
+ call, // [scope,arg,...,arg -> scope] Pops this.nargs arguments and replaces for names from scope.scopeDef.args
+ };
+
+ Type type;
+ double num;
+ string str;
+ ScopeDef *scope;
+ string name;
+ int nargs;
+
+ Instruction(Type type);
+ Instruction(Type type,double num); // pushnum
+ Instruction(Type type,const string &str); // pushstr, create, store, load
+ Instruction(Type type,ScopeDef *scope); // pushscope
+ Instruction(Type type,int nargs); // call
+ };
+
+ vector<Instruction> listing;
+
+ void codegen(const StatementList &stl);
+ void codegen(const Statement &stmt);
+ void codegen(const Expression &expr);
+
+public:
+ Assembly(const StatementList &stl);
+
+ friend ostream& operator<<(ostream &os,const Assembly &as);
+};
+
+ostream& operator<<(ostream &os,const Assembly &as);
+
+
+class Context{
+ vector<ScopeVal> sstack;
+
+public:
+ void evaluate(const Assembly &as);
+};
diff --git a/main.cpp b/main.cpp
index f8b9681..98dbec9 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,6 +1,7 @@
#include <iostream>
#include <fstream>
#include <cstring>
+#include "evaluate.h"
#include "parser.h"
using namespace std;
@@ -43,6 +44,8 @@ int main(int argc,char **argv){
cerr<<e.what()<<endl;
return 1;
}
- cout<<stl<<endl;
+ // cout<<stl<<endl;
+ Assembly as(stl);
+ cout<<as<<flush;
return 0;
}
diff --git a/parser.cpp b/parser.cpp
index 764776c..fb9bf47 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -366,6 +366,35 @@ static vector<Expression> parseArgumentList(Tokeniser &tokeniser){
return args;
}
+static vector<Name> parseArgumentNameList(Tokeniser &tokeniser){
+ if(tokeniser.eof())throw ParseError(tokeniser.site(),"Expected argument name list but found EOF");
+ Token tok=tokeniser.get();
+ if(tok.type!=Token::Type::symbol||tok.str!="("){
+ throw ParseError(tok.site,"Expected argument name list but found '"+tok.str+"'");
+ }
+ tokeniser.advance();
+ vector<Name> args;
+ while(true){
+ tok=tokeniser.get();
+ if(tok.type!=Token::Type::word){
+ throw ParseError(tok.site,"Expected argument name but found something else");
+ }
+ Name name=tok.str;
+ tokeniser.advance();
+ if(tokeniser.eof()){
+ throw ParseError(tokeniser.site(),"Expected ')' or ',' after argument name but found EOF");
+ }
+ tok=tokeniser.get();
+ if(tok.type!=Token::Type::symbol||(tok.str!=")"&&tok.str!=",")){
+ throw ParseError(tok.site,"Expected ')' or ',' after argument name but found something else");
+ }
+ tokeniser.advance();
+ args.push_back(name);
+ if(tok.str==")")break;
+ }
+ return args;
+}
+
static Expression parseAtom(Tokeniser &tokeniser){
if(tokeniser.eof())throw ParseError(tokeniser.site(),"Expected atom but found EOF");
Token tok=tokeniser.get();
@@ -456,7 +485,7 @@ static Expression parseAtom(Tokeniser &tokeniser){
else if(tok.str!="{"){
throw ParseError(tok.site,"Unexpected token '"+tok.str+"' in expression atom position");
} else sctype=ScopeDef::Type::direct;
- vector<Expression> args;
+ vector<Name> args;
if(sctype!=ScopeDef::Type::direct){
tokeniser.advance();
if(tokeniser.eof()){
@@ -467,7 +496,7 @@ static Expression parseAtom(Tokeniser &tokeniser){
throw ParseError(tok2.site,"Expected '(' or '{' after '"+tok.str+"'");
}
if(tok2.type==Token::Type::symbol&&tok2.str=="("){
- args=parseArgumentList(tokeniser);
+ args=parseArgumentNameList(tokeniser);
}
}
// DEBUG<<"args: "<<args<<endl;
diff --git a/test.squig b/test.squig
new file mode 100644
index 0000000..1e83fb2
--- /dev/null
+++ b/test.squig
@@ -0,0 +1 @@
+a := 1