diff --git a/ast/ast_dumper.h b/ast/ast_dumper.h index 25a26e4..cb9bcb9 100644 --- a/ast/ast_dumper.h +++ b/ast/ast_dumper.h @@ -74,4 +74,9 @@ public: bool visit_continue_expr(continue_expr*) override; bool visit_break_expr(break_expr*) override; bool visit_return_expr(return_expr*) override; + +public: + void dump(code_block* root) { + root->accept(this); + } }; \ No newline at end of file diff --git a/ast/nasal_new_codegen.cpp b/ast/nasal_new_codegen.cpp new file mode 100644 index 0000000..84b8848 --- /dev/null +++ b/ast/nasal_new_codegen.cpp @@ -0,0 +1 @@ +#include "nasal_new_codegen.h" \ No newline at end of file diff --git a/ast/nasal_new_codegen.h b/ast/nasal_new_codegen.h new file mode 100644 index 0000000..7b9637e --- /dev/null +++ b/ast/nasal_new_codegen.h @@ -0,0 +1 @@ +#pragma once \ No newline at end of file diff --git a/ast/nasal_new_main.cpp b/ast/nasal_new_main.cpp index 395d2d9..75fbf95 100644 --- a/ast/nasal_new_main.cpp +++ b/ast/nasal_new_main.cpp @@ -6,6 +6,7 @@ #include "nasal_new_import.h" #include "ast_visitor.h" #include "ast_dumper.h" +#include "optimizer.h" #include #include @@ -93,11 +94,13 @@ void execute( ld.link(parse, file, cmd&VM_DETAIL).chkerr(); if (cmd&VM_AST) { auto dumper = new ast_dumper(); - dumper->visit_code_block(parse.tree()); + dumper->dump(parse.tree()); } // optimizer does simple optimization on ast - // optimize(parse.tree()); + auto opt = new optimizer; + opt->do_optimization(parse.tree()); + delete opt; // code generator gets parser's ast and import file list to generate code // gen.compile(parse, ld).chkerr(); diff --git a/ast/nasal_new_opcode.cpp b/ast/nasal_new_opcode.cpp new file mode 100644 index 0000000..bbe9ef5 --- /dev/null +++ b/ast/nasal_new_opcode.cpp @@ -0,0 +1,86 @@ +#include "nasal_new_opcode.h" + +void codestream::set( + const f64* numbuff, + const std::string* strbuff, + const std::string* filelist=nullptr +) { + nums=numbuff; + strs=strbuff; + files=filelist; +} + +void codestream::dump(std::ostream& out) const { + using std::setw; + using std::setfill; + using std::hex; + using std::dec; + auto op=code.op; + auto num=code.num; + out<>16)&0xff)<<" " + <>8)&0xff)<<" " + <";break; + case op_upval: case op_mupval: + case op_loadu: + out<>16)&0xffff) + <<"[0x"<<(num&0xffff)<<"]"< + +enum op_code_type:u8 { + op_exit, // stop the virtual machine + op_intg, // global scope size, set stack top + op_intl, // local scope size + op_loadg, // load global value + op_loadl, // load local value + op_loadu, // load upvalue + op_pnum, // push constant number to the stack + op_pnil, // push constant nil to the stack + op_pstr, // push constant std::string to the stack + op_newv, // push new vector with initial values from stack + op_newh, // push new hash to the stack + op_newf, // push new function to the stack + op_happ, // hash append + op_para, // normal parameter + op_deft, // default parameter + op_dyn, // dynamic parameter + op_lnot, // ! logical negation + op_usub, // - negation + op_bnot, // ~ bitwise not static_cast + op_btor, // | bitwise or + op_btxor, // ^ bitwise xor + op_btand, // & bitwise and + op_add, // + + op_sub, // - + op_mul, // * + op_div, // / + op_lnk, // ~ + op_addc, // + const + op_subc, // - const + op_mulc, // * const + op_divc, // / const + op_lnkc, // ~ const + op_addeq, // += maybe pop stack top + op_subeq, // -= maybe pop stack top + op_muleq, // *= maybe pop stack top + op_diveq, // /= maybe pop stack top + op_lnkeq, // ~= maybe pop stack top + op_btandeq,// &= maybe pop stack top + op_btoreq, // |= maybe pop stack top + op_btxoreq,// ^= maybe pop stack top + op_addeqc, // += const don't pop stack top + op_subeqc, // -= const don't pop stack top + op_muleqc, // *= const don't pop stack top + op_diveqc, // /= const don't pop stack top + op_lnkeqc, // ~= const don't pop stack top + op_addecp, // += const and pop stack top + op_subecp, // -= const and pop stack top + op_mulecp, // *= const and pop stack top + op_divecp, // /= const and pop stack top + op_lnkecp, // ~= concat const std::string and pop stack top + op_meq, // = maybe pop stack top + op_eq, // == + op_neq, // != + op_less, // < + op_leq, // <= + op_grt, // > + op_geq, // >= + op_lessc, // < const + op_leqc, // <= const + op_grtc, // > const + op_geqc, // >= const + op_pop, // pop a value out of stack top + op_jmp, // jump absolute address with no condition + op_jt, // used in operator and/or,jmp when condition is true and DO NOT POP + op_jf, // used in conditional/loop,jmp when condition is false and POP STACK + op_cnt, // add counter for forindex/foreach + op_findex, // index counter on the top of forindex_stack plus 1 + op_feach, // index counter on the top of forindex_stack plus 1 and get the value in vector + op_callg, // get value in global scope + op_calll, // get value in local scope + op_upval, // get value in closure, high 16 as the index of upval, low 16 as the index of local + op_callv, // call vec[index] + op_callvi, // call vec[immediate] (used in multi-assign/multi-define) + op_callh, // call hash.label + op_callfv, // call function(vector as parameters) + op_callfh, // call function(hash as parameters) + op_callb, // call builtin-function + op_slcbeg, // begin of slice like: vec[1,2,3:6,0,-1] + op_slcend, // end of slice + op_slc, // slice like vec[1] + op_slc2, // slice like vec[nil:10] + op_mcallg, // get memory space of value in global scope + op_mcalll, // get memory space of value in local scope + op_mupval, // get memory space of value in closure + op_mcallv, // get memory space of vec[index] + op_mcallh, // get memory space of hash.label + op_ret // return +}; + +const char* opname[]={ + "exit ","intg ","intl ","loadg ", + "loadl ","loadu ","pnum ","pnil ", + "pstr ","newv ","newh ","newf ", + "happ ","para ","def ","dyn ", + "lnot ","usub ","bnot ","btor ", + "btxor ","btand ","add ","sub ", + "mult ","div ","lnk ","addc ", + "subc ","multc ","divc ","lnkc ", + "addeq ","subeq ","muleq ","diveq ", + "lnkeq ","bandeq","boreq ","bxoreq", + "addeqc","subeqc","muleqc","diveqc", + "lnkeqc","addecp","subecp","mulecp", + "divecp","lnkecp","meq ","eq ", + "neq ","less ","leq ","grt ", + "geq ","lessc ","leqc ","grtc ", + "geqc ","pop ","jmp ","jt ", + "jf ","cnt ","findx ","feach ", + "callg ","calll ","upval ","callv ", + "callvi","callh ","callfv","callfh", + "callb ","slcbeg","slcend","slc ", + "slc2 ","mcallg","mcalll","mupval", + "mcallv","mcallh","ret " +}; + +struct opcode { + u8 op; // opcode + u16 fidx; // source code file index + u32 num; // immediate num + u32 line; // location line of source code + opcode() = default; + opcode(const opcode&) = default; + opcode& operator=(const opcode&) = default; +}; + +class codestream { +private: + opcode code; + const u32 index; + inline static const f64* nums = nullptr; + inline static const std::string* strs = nullptr; + inline static const std::string* files = nullptr; +public: + codestream(const opcode& c, const u32 i): code(c), index(i) {} + static void set(const f64*, const std::string*, const std::string*); + void dump(std::ostream&) const; +}; + +std::ostream& operator<<(std::ostream&, const codestream&); \ No newline at end of file diff --git a/ast/optimizer.cpp b/ast/optimizer.cpp new file mode 100644 index 0000000..1d4ca56 --- /dev/null +++ b/ast/optimizer.cpp @@ -0,0 +1,21 @@ +#include "optimizer.h" + +void const_string(binary_operator* node) { + +} + +void const_number(binary_operator* node) { + +} + +bool optimizer::visit_binary_operator(binary_operator* node) { + return true; +} + +bool optimizer::visit_unary_operator(unary_operator* node) { + return true; +} + +void optimizer::do_optimization(code_block* root) { + root->accept(this); +} \ No newline at end of file diff --git a/ast/optimizer.h b/ast/optimizer.h new file mode 100644 index 0000000..b26dabd --- /dev/null +++ b/ast/optimizer.h @@ -0,0 +1,83 @@ +#pragma once + +#include + +#include "nasal_new_ast.h" +#include "ast_visitor.h" + +class optimizer:public ast_visitor { +private: + void const_string(binary_operator*); + void const_number(binary_operator*); + +public: + bool visit_binary_operator(binary_operator*) override; + bool visit_unary_operator(unary_operator*) override; + +public: + void do_optimization(code_block*); +}; + +// void const_str(ast& root) { +// auto& vec=root.child(); +// root.set_str(vec[0].str()+vec[1].str()); +// root.child().clear(); +// root.set_type(ast_str); +// } + +// void const_num(ast& root) { +// auto& vec=root.child(); +// f64 res=0; +// switch(root.type()) { +// case ast_add: res=vec[0].num()+vec[1].num(); break; +// case ast_sub: res=vec[0].num()-vec[1].num(); break; +// case ast_mult: res=vec[0].num()*vec[1].num(); break; +// case ast_div: res=vec[0].num()/vec[1].num(); break; +// case ast_less: res=vec[0].num()vec[1].num(); break; +// case ast_geq: res=vec[0].num()>=vec[1].num();break; +// case ast_bitor: res=i32(vec[0].num())|i32(vec[1].num()); break; +// case ast_bitxor: res=i32(vec[0].num())^i32(vec[1].num()); break; +// case ast_bitand: res=i32(vec[0].num())&i32(vec[1].num()); break; +// } +// // inf and nan will cause number hashmap error in codegen +// if (std::isinf(res) || std::isnan(res)) { +// return; +// } +// root.set_num(res); +// root.child().clear(); +// root.set_type(ast_num); +// } + +// void calc_const(ast& root) { +// auto& vec=root.child(); +// for(auto& i:vec) { +// calc_const(i); +// } +// if (vec.size()==1 && root.type()==ast_neg && vec[0].type()==ast_num) { +// f64 res=-vec[0].num(); +// root.set_num(res); +// root.child().clear(); +// root.set_type(ast_num); +// return; +// } +// if (vec.size()!=2) { +// return; +// } +// if (root.type()!=ast_add && root.type()!=ast_sub && +// root.type()!=ast_mult && root.type()!=ast_div && +// root.type()!=ast_link && root.type()!=ast_less && +// root.type()!=ast_leq && root.type()!=ast_grt && +// root.type()!=ast_geq && root.type()!=ast_bitor && +// root.type()!=ast_bitxor && root.type()!=ast_bitand) { +// return; +// } +// if (root.type()==ast_link && +// vec[0].type()==ast_str && vec[1].type()==ast_str) { +// const_str(root); +// } else if (root.type()!=ast_link && +// vec[0].type()==ast_num && vec[1].type()==ast_num) { +// const_num(root); +// } +// } \ No newline at end of file diff --git a/makefile b/makefile index 52fbc9c..89209bb 100644 --- a/makefile +++ b/makefile @@ -81,7 +81,10 @@ NASAL_NEW_AST=\ nasal_new_lexer.o\ nasal_new_ast.o\ nasal_new_builtin.o\ + nasal_new_codegen.o\ + nasal_new_opcode.o\ nasal_new_parse.o\ + optimizer.o\ ast_visitor.o\ ast_dumper.o\ nasal_new_main.o @@ -115,9 +118,18 @@ nasal_new_ast.o: ast/nasal_new_ast.h ast/nasal_new_ast.cpp nasal_new_builtin.o: ast/nasal_new_builtin.h ast/nasal_new_builtin.cpp $(CXX) -std=$(STD) -c -O3 ast/nasal_new_builtin.cpp -fno-exceptions -fPIC -o nasal_new_builtin.o -I . +nasal_new_codegen.o: ast/nasal_new_codegen.h ast/nasal_new_codegen.cpp + $(CXX) -std=$(STD) -c -O3 ast/nasal_new_codegen.cpp -fno-exceptions -fPIC -o nasal_new_codegen.o -I . + +nasal_new_opcode.o: ast/nasal_new_opcode.h ast/nasal_new_opcode.cpp + $(CXX) -std=$(STD) -c -O3 ast/nasal_new_opcode.cpp -fno-exceptions -fPIC -o nasal_new_opcode.o -I . + nasal_new_parse.o: ast/nasal_new_parse.h ast/nasal_new_parse.cpp ast/nasal_new_ast.h $(CXX) -std=$(STD) -c -O3 ast/nasal_new_parse.cpp -fno-exceptions -fPIC -o nasal_new_parse.o -I . +optimizer.o: ast/optimizer.h ast/optimizer.cpp ast/nasal_new_ast.h + $(CXX) -std=$(STD) -c -O3 ast/optimizer.cpp -fno-exceptions -fPIC -o optimizer.o -I . + ast_visitor.o: ast/nasal_new_ast.h ast/ast_visitor.h ast/ast_visitor.cpp $(CXX) -std=$(STD) -c -O3 ast/ast_visitor.cpp -fno-exceptions -fPIC -o ast_visitor.o -I .