From ca45da0925cabc3bbf0d22d5d23ccb9a25d8e228 Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Fri, 10 Feb 2017 23:35:02 +0100 Subject: Preliminary 'compiling' --- ast.cpp | 6 +-- ast.h | 4 +- evaluate.cpp | 170 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- evaluate.h | 91 +++++++++++++++++++++++++++++--- main.cpp | 5 +- parser.cpp | 33 +++++++++++- test.squig | 1 + 7 files changed, 292 insertions(+), 18 deletions(-) create mode 100644 test.squig 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 &args) +ScopeDef::ScopeDef(Type type,const StatementList &body,const vector &args) :type(type),body(body),args(args){} /*ScopeDef::ScopeDef(Type type,const StatementList &body,const vector &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< args; + vector args; Site site; ScopeDef(); - ScopeDef(Type type,const StatementList &body,const vector &args); + ScopeDef(Type type,const StatementList &body,const vector &args); // ScopeDef(Type type,const StatementList &body,const vector &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 &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 "< #include #include #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 values; + + ScopeVal(const ScopeDef &scopeDef); }; @@ -41,7 +61,66 @@ namespace A { template 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 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 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 #include #include +#include "evaluate.h" #include "parser.h" using namespace std; @@ -43,6 +44,8 @@ int main(int argc,char **argv){ cerr< parseArgumentList(Tokeniser &tokeniser){ return args; } +static vector 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 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 args; + vector 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: "<