diff options
-rw-r--r-- | ast.cpp | 6 | ||||
-rw-r--r-- | ast.h | 4 | ||||
-rw-r--r-- | evaluate.cpp | 170 | ||||
-rw-r--r-- | evaluate.h | 91 | ||||
-rw-r--r-- | main.cpp | 5 | ||||
-rw-r--r-- | parser.cpp | 33 | ||||
-rw-r--r-- | test.squig | 1 |
7 files changed, 292 insertions, 18 deletions
@@ -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<<')'; } @@ -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; } @@ -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); +}; @@ -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; } @@ -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 |