diff --git a/lib.nas b/lib.nas index a094a7a..c1b031d 100644 --- a/lib.nas +++ b/lib.nas @@ -26,8 +26,7 @@ var setsize=func(vector,size) } var system=func(str) { - __builtin_system(str); - return; + return __builtin_system(str); } var input=func() { diff --git a/main.cpp b/main.cpp index d572a35..4951747 100644 --- a/main.cpp +++ b/main.cpp @@ -1,24 +1,19 @@ #include "nasal.h" -nasal_lexer lexer; -nasal_parse parse; -nasal_import import; -std::string file="null"; -nasal_codegen codegen; -nasal_vm vm; +nasal_vm vm; void help() { std::cout - <<">> [\"file\"] input file name. \n" - <<">> [help ] show help. \n" - <<">> [clear ] clear the screen. \n" - <<">> [lex ] view tokens. \n" - <<">> [ast ] view abstract syntax tree. \n" - <<">> [code ] view byte code. \n" - <<">> [exec ] execute program on bytecode vm. \n" - <<">> [logo ] print logo of nasal . \n" - <<">> [exit ] quit nasal interpreter. \n"; + <<">> [\"file\"] input file name. \n" + <<">> [help ] show help. \n" + <<">> [clear] clear the screen. \n" + <<">> [lex ] view tokens. \n" + <<">> [ast ] view abstract syntax tree. \n" + <<">> [code ] view byte code. \n" + <<">> [exec ] execute program on bytecode vm.\n" + <<">> [logo ] print logo of nasal . \n" + <<">> [exit ] quit nasal interpreter. \n"; return; } @@ -39,8 +34,12 @@ void die(std::string stage,std::string filename) return; } -void execute(std::string& command) +void execute(std::string& file,std::string& command) { + nasal_lexer lexer; + nasal_parse parse; + nasal_import import; + nasal_codegen codegen; lexer.openfile(file); lexer.scanner(); if(lexer.get_error()) @@ -95,12 +94,13 @@ void execute(std::string& command) int main() { std::string command; + std::string file="null"; #ifdef _WIN32 // use chcp 65001 to use unicode io system("chcp 65001"); system("cls"); #else - system("clear"); + int rs=system("clear");// avoid annoying warning of high version gcc/g++ #endif logo(); std::cout<<">> Nasal interpreter ver 6.5 efficient gc test .\n"; @@ -120,7 +120,7 @@ int main() #ifdef _WIN32 system("cls"); #else - system("clear"); + int rs=system("clear"); #endif } else if(command=="logo") @@ -128,7 +128,7 @@ int main() else if(command=="exit") break; else if(command=="lex" || command=="ast" || command=="code" || command=="exec") - execute(command); + execute(file,command); else file=command; } diff --git a/nasal_builtin.h b/nasal_builtin.h index 7d618a0..4eaa9e6 100644 --- a/nasal_builtin.h +++ b/nasal_builtin.h @@ -172,14 +172,15 @@ nasal_val* builtin_setsize(std::vector& local_scope,nasal_gc& gc) nasal_val* builtin_system(std::vector& local_scope,nasal_gc& gc) { + nasal_val* ret_addr=gc.gc_alloc(vm_num); nasal_val* str_addr=local_scope[1]; if(str_addr->type!=vm_str) { builtin_err("system","\"str\" must be string"); return nullptr; } - system(str_addr->ptr.str->data()); - return gc.nil_addr; + ret_addr->ptr.num=(double)system(str_addr->ptr.str->data()); + return ret_addr; } nasal_val* builtin_input(std::vector& local_scope,nasal_gc& gc) diff --git a/nasal_codegen.h b/nasal_codegen.h index 6f0111f..56a933b 100644 --- a/nasal_codegen.h +++ b/nasal_codegen.h @@ -54,7 +54,8 @@ enum op_code op_callv, // call vec[index] op_callvi, // call vec[immediate] (used in multi-assign/multi-define) op_callh, // call hash.label - op_callf, // call function(parameters) + op_callfv, // call function(vector as parameters) + op_callfh, // call function(hash as parameters) op_callb, // call builtin-function op_slcbegin, // begin of slice like: vec[1,2,3:6,0,-1] op_slcend, // end of slice @@ -124,7 +125,8 @@ struct {op_callv, "callv "}, {op_callvi, "callvi"}, {op_callh, "callh "}, - {op_callf, "callf "}, + {op_callfv, "callfv"}, + {op_callfh, "callfh"}, {op_callb, "callb "}, {op_slcbegin, "slcbeg"}, {op_slcend, "slcend"}, @@ -509,12 +511,18 @@ void nasal_codegen::call_vec(nasal_ast& ast) void nasal_codegen::call_func(nasal_ast& ast) { if(!ast.get_children().size()) - gen(op_newv,0); + gen(op_callfv,0); else if(ast.get_children()[0].get_type()==ast_hashmember) + { hash_gen(ast); + gen(op_callfh,0); + } else - vec_gen(ast); - gen(op_callf,0); + { + for(auto& node:ast.get_children()) + calc_gen(node); + gen(op_callfv,ast.get_children().size()); + } return; } diff --git a/nasal_gc.h b/nasal_gc.h index 22e4feb..8c326a9 100644 --- a/nasal_gc.h +++ b/nasal_gc.h @@ -12,21 +12,22 @@ enum nasal_type vm_type_size }; +// change parameters here to make your own efficient gc +// better set bigger number on vm_num and vm_vec const int increment[vm_type_size]= { - 8, // vm_nil,in fact it is not in use + 0, // vm_nil,in fact it is not in use 65536,// vm_num - 512, // vm_str + 256, // vm_str 16, // vm_func - 128, // vm_vec - 16 // vm_hash + 2048, // vm_vec + 8 // vm_hash }; -struct nasal_vec; -struct nasal_hash; -struct nasal_func; -struct nasal_scop; -struct nasal_val; +struct nasal_vec; //24 bytes +struct nasal_hash;//56 bytes +struct nasal_func;//120 bytes +struct nasal_val; // 16 bytes struct nasal_vec { @@ -61,8 +62,10 @@ struct nasal_func struct nasal_val { - bool collected; - bool mark; +#define GC_UNCOLLECTED 0 +#define GC_FOUND 1 +#define GC_COLLECTED 2 + uint8_t mark; uint16_t type; union { @@ -202,15 +205,13 @@ void nasal_func::clear() /*functions of nasal_val*/ nasal_val::nasal_val() { - collected=true; - mark=false; + mark=GC_COLLECTED; type=vm_nil; return; } nasal_val::nasal_val(int val_type) { - collected=true; - mark=false; + mark=GC_COLLECTED; type=val_type; switch(type) { @@ -252,16 +253,16 @@ std::string nasal_val::to_string() struct nasal_gc { #define STACK_MAX_DEPTH (65536<<4) - nasal_val* zero_addr; // reserved address of nasal_val,type vm_num, 0 - nasal_val* one_addr; // reserved address of nasal_val,type vm_num, 1 - nasal_val* nil_addr; // reserved address of nasal_val,type vm_nil + nasal_val* zero_addr; // reserved address of nasal_val,type vm_num, 0 + nasal_val* one_addr; // reserved address of nasal_val,type vm_num, 1 + nasal_val* nil_addr; // reserved address of nasal_val,type vm_nil nasal_val* val_stack[STACK_MAX_DEPTH]; - nasal_val** stack_top; // stack top - std::vector num_addrs; // reserved address for const vm_num - std::vector str_addrs; // reserved address for const vm_str - std::vector slice_stack; // slice stack for vec[val,val,val:val] - std::vector memory; // gc memory - std::queue free_list[vm_type_size]; // gc free list + nasal_val** stack_top; // stack top + std::vector num_addrs; // reserved address for const vm_num + std::vector str_addrs; // reserved address for const vm_str + std::vector slice_stack; // slice stack for vec[val,val,val:val] + std::vector memory; // gc memory + std::queue free_list[vm_type_size]; // gc free list std::vector global; std::list > local; void mark(); @@ -290,7 +291,7 @@ void nasal_gc::mark() nasal_val* tmp=bfs.front(); bfs.pop(); if(!tmp || tmp->mark) continue; - tmp->mark=true; + tmp->mark=GC_FOUND; if(tmp->type==vm_vec) for(auto i:tmp->ptr.vec->elems) bfs.push(i); @@ -311,21 +312,20 @@ void nasal_gc::sweep() { for(auto i:memory) { - if(!i->collected && !i->mark) + if(i->mark==GC_UNCOLLECTED) { switch(i->type) { - case vm_nil: break; - case vm_num: i->ptr.num=0; break; case vm_str: i->ptr.str->clear(); break; case vm_vec: i->ptr.vec->elems.clear(); break; case vm_hash:i->ptr.hash->elems.clear();break; case vm_func:i->ptr.func->clear(); break; } free_list[i->type].push(i); - i->collected=true; + i->mark=GC_COLLECTED; } - i->mark=false; + else if(i->mark==GC_FOUND) + i->mark=GC_UNCOLLECTED; } return; } @@ -338,6 +338,7 @@ void nasal_gc::gc_init(std::vector& nums,std::vector& strs) memory.push_back(tmp); free_list[i].push(tmp); } + stack_top=val_stack; // set stack_top to val_stack zero_addr=new nasal_val(vm_num); // init constant 0 @@ -349,21 +350,21 @@ void nasal_gc::gc_init(std::vector& nums,std::vector& strs) nil_addr=new nasal_val(vm_nil); // init nil *val_stack=nil_addr; // the first space will not store any values,but gc checks - // init constant numbers + num_addrs.resize(nums.size()); for(int i=0;iptr.num=nums[i]; - num_addrs.push_back(tmp); + num_addrs[i]=tmp; } - // init constant strings + str_addrs.resize(strs.size()); for(int i=0;iptr.str=strs[i]; - str_addrs.push_back(tmp); + str_addrs[i]=tmp; } return; } @@ -405,7 +406,7 @@ nasal_val* nasal_gc::gc_alloc(int type) free_list[type].push(tmp); } nasal_val* ret=free_list[type].front(); - ret->collected=false; + ret->mark=GC_UNCOLLECTED; free_list[type].pop(); return ret; } @@ -423,7 +424,7 @@ nasal_val* nasal_gc::builtin_alloc(int type) free_list[type].push(tmp); } nasal_val* ret=free_list[type].front(); - ret->collected=false; + ret->mark=GC_UNCOLLECTED; free_list[type].pop(); return ret; } diff --git a/nasal_vm.h b/nasal_vm.h index bbb9a17..37c87a2 100644 --- a/nasal_vm.h +++ b/nasal_vm.h @@ -14,7 +14,7 @@ private: std::vector str_table; // symbols used in process std::vector exec_code; // byte codes store here std::stack addr_stack; // stack for mem_call - nasal_gc gc; //garbage collector + nasal_gc gc; // garbage collector void die(std::string); bool condition(nasal_val*); @@ -69,7 +69,8 @@ private: void opr_callv(); void opr_callvi(); void opr_callh(); - void opr_callf(); + void opr_callfv(); + void opr_callfh(); void opr_callb(); void opr_slcbegin(); void opr_slcend(); @@ -101,6 +102,7 @@ void nasal_vm::init( std::vector& exec) { gc.gc_init(nums,strs); + gc.val_stack[STACK_MAX_DEPTH-1]=nullptr; str_table=strs; // get constant strings & symbols exec_code=exec; // get bytecodes loop_mark=true; // set loop mark to true @@ -135,7 +137,7 @@ bool nasal_vm::condition(nasal_val* val_addr) std::string& str=*val_addr->ptr.str; double number=str2num(str); if(std::isnan(number)) - return str.length(); + return !str.empty(); return number; } return false; @@ -211,19 +213,21 @@ void nasal_vm::opr_newf() { nasal_val* val=gc.gc_alloc(vm_func); val->ptr.func->entry=exec_code[pc].num; - if(!gc.local.empty()) - val->ptr.func->closure=gc.local.back();// local contains 'me' - else + if(gc.local.empty()) val->ptr.func->closure.push_back(gc.nil_addr);// me + else + val->ptr.func->closure=gc.local.back();// local contains 'me' *(++stack_top)=val; return; } void nasal_vm::opr_vapp() { - nasal_val* vec=*(stack_top-exec_code[pc].num); - for(nasal_val** i=stack_top-exec_code[pc].num+1;i<=stack_top;++i) - vec->ptr.vec->elems.push_back(*i); - stack_top-=exec_code[pc].num; + nasal_val** begin=stack_top-exec_code[pc].num+1; + auto& vec=begin[-1]->ptr.vec->elems;// stack_top-exec_code[pc].num stores the vector + vec.resize(exec_code[pc].num); + for(int i=0;iptr.str); if(std::isnan(number)) - new_val=val->ptr.str->length()?gc.zero_addr:gc.one_addr; + new_val=val->ptr.str->empty()?gc.one_addr:gc.zero_addr; else new_val=number?gc.zero_addr:gc.one_addr; } @@ -526,8 +530,7 @@ void nasal_vm::opr_findex() void nasal_vm::opr_feach() { std::vector& ref=(*stack_top)->ptr.vec->elems; - ++counter.top(); - if(counter.top()>=ref.size()) + if(++counter.top()>=ref.size()) { pc=exec_code[pc].num-1; return; @@ -635,73 +638,89 @@ void nasal_vm::opr_callh() *stack_top=res; return; } -void nasal_vm::opr_callf() +void nasal_vm::opr_callfv() { // get parameter list and function value - nasal_val* para_addr=*stack_top; - nasal_val* func_addr=*(stack_top-1); + int args_size=exec_code[pc].num; + nasal_val** vec=stack_top-args_size+1; + nasal_val* func_addr=*(vec-1); if(func_addr->type!=vm_func) { - die("callf: called a value that is not a function"); + die("callfv: called a value that is not a function"); return; } // push new local scope - gc.local.push_back(func_addr->ptr.func->closure); + auto& ref_func=*func_addr->ptr.func; + gc.local.push_back(ref_func.closure); // load parameters - nasal_func& ref_func=*func_addr->ptr.func; - std::vector& ref_default=ref_func.default_para; - std::vector& ref_closure=gc.local.back(); - std::unordered_map& ref_keys=ref_func.key_table; - - if(para_addr->type==vm_vec) + auto& ref_default=ref_func.default_para; + auto& ref_closure=gc.local.back(); + auto& ref_keys=ref_func.key_table; + + int offset=ref_func.offset; + int para_size=ref_keys.size(); + // load arguments + if(args_size& args=para_addr->ptr.vec->elems; - int args_size=args.size(); - int para_size=ref_keys.size(); - for(int i=0;i=args_size) - { - if(!ref_default[i]) - { - die("callf: lack argument(s)"); - return; - } - ref_closure[i+ref_func.offset]=ref_default[i]; - } - else - ref_closure[i+ref_func.offset]=args[i]; - } - if(ref_func.dynpara>=0) - { - nasal_val* vec_addr=gc.gc_alloc(vm_vec); - for(int i=para_size;iptr.vec->elems.push_back(args[i]); - ref_closure[para_size+ref_func.offset]=vec_addr; - } + // if the first default value is not nullptr,then values after it are not nullptr + die("callfv: lack argument(s)"); + return; } - else + // if args_size>para_size,for 0 to args_size will cause corruption + for(int i=0;i=args_size)?ref_default[i]:vec[i]; + // load dynamic argument if args_size>=para_size + if(ref_func.dynpara>=0) { - std::unordered_map& ref_hash=para_addr->ptr.hash->elems; - if(ref_func.dynpara>=0) + nasal_val* vec_addr=gc.gc_alloc(vm_vec); + for(int i=para_size;iptr.vec->elems.push_back(vec[i]); + ref_closure[para_size+offset]=vec_addr; + } + + stack_top-=args_size;// pop arguments + ret.push(pc); + pc=ref_func.entry-1; + return; +} +void nasal_vm::opr_callfh() +{ + // get parameter list and function value + std::unordered_map& ref_hash=(*stack_top)->ptr.hash->elems; + nasal_val* func_addr=*(stack_top-1); + if(func_addr->type!=vm_func) + { + die("callfh: called a value that is not a function"); + return; + } + // push new local scope + auto& ref_func=*func_addr->ptr.func; + gc.local.push_back(ref_func.closure); + // load parameters + auto& ref_default=ref_func.default_para; + auto& ref_closure=gc.local.back(); + auto& ref_keys=ref_func.key_table; + + if(ref_func.dynpara>=0) + { + die("callfh: special call cannot use dynamic argument"); + return; + } + int offset=ref_func.offset; + for(auto& i:ref_keys) + { + if(ref_hash.count(i.first)) + ref_closure[i.second+offset]=ref_hash[i.first]; + else if(ref_default[i.second]) + ref_closure[i.second+offset]=ref_default[i.second]; + else { - die("callf: special call cannot use dynamic argument"); + die("callfh: lack argument(s): \""+i.first+"\""); return; } - for(auto& i:ref_keys) - { - if(ref_hash.count(i.first)) - ref_closure[i.second+ref_func.offset]=ref_hash[i.first]; - else if(ref_default[i.second]) - ref_closure[i.second+ref_func.offset]=ref_default[i.second]; - else - { - die("callf: lack argument(s): \""+i.first+"\""); - return; - } - } } - --stack_top; + + --stack_top;// pop hash ret.push(pc); pc=ref_func.entry-1; return; @@ -920,7 +939,8 @@ void nasal_vm::run() &nasal_vm::opr_callv, &nasal_vm::opr_callvi, &nasal_vm::opr_callh, - &nasal_vm::opr_callf, + &nasal_vm::opr_callfv, + &nasal_vm::opr_callfh, &nasal_vm::opr_callb, &nasal_vm::opr_slcbegin, &nasal_vm::opr_slcend, @@ -934,7 +954,7 @@ void nasal_vm::run() }; clock_t begin_time=clock(); // main loop - for(pc=0;loop_mark;++pc) + for(pc=0;loop_mark&&!gc.val_stack[STACK_MAX_DEPTH-1];++pc) (this->*opr_table[exec_code[pc].op])(); float total_time=((double)(clock()-begin_time))/CLOCKS_PER_SEC; std::cout<<">> [vm] process exited after "<0.0005) } cnt+=1; show+=1; - if(show==300) + if(show==350) { show=0; print('epoch ',cnt,':',error,'\r'); diff --git a/test/fib.nas b/test/fib.nas index d06371a..06818cf 100644 --- a/test/fib.nas +++ b/test/fib.nas @@ -5,4 +5,5 @@ var fib=func(x) return fib(x-1)+fib(x-2); } for(var i=0;i<31;i+=1) - print(fib(i),'\n'); \ No newline at end of file + print(fib(i),'\n'); + \ No newline at end of file