diff --git a/README.md b/README.md index 056c7ad..d19331b 100644 --- a/README.md +++ b/README.md @@ -36,11 +36,11 @@ MUST USE -O2/-O3 if want to optimize the interpreter! Also remember to use g++ and clang++. -> g++|clang++ -std=c++11 -O2 main.cpp -o nasal.exe +> g++ | clang++ -std=c++11 -O2 main.cpp -o nasal.exe Or use this in linux/macOS/Unix -> g++|clang++ -std=c++11 -O2 main.cpp -o nasal +> g++ | clang++ -std=c++11 -O2 main.cpp -o nasal ## How to Use? @@ -54,11 +54,11 @@ Input this command to run scripts directly: Use these commands to get version of interpreter: -> ./nasal -v | -version +> ./nasal -v | --version Use these commands to get help: -> ./nasal -h | -help +> ./nasal -h | --help If your system is Windows and you want to output unicode,please use this command before running nasal interpreter: diff --git a/main.cpp b/main.cpp index 0086a4b..514dbdc 100644 --- a/main.cpp +++ b/main.cpp @@ -5,7 +5,6 @@ void help_interact() std::cout <<">> [ ] input a file name to execute. \n" <<">> [help ] show help. \n" - <<">> [lex ] view tokens. \n" <<">> [ast ] view abstract syntax tree. \n" <<">> [code ] view byte code. \n" <<">> [exec ] execute program on bytecode vm.\n" @@ -65,13 +64,7 @@ void execute(std::string& file,std::string& command) die("lexer",file); return; } - if(command=="lex") - { - lexer.print_token(); - return; - } parse.set_toklist(lexer.get_token_list()); - lexer.get_token_list().clear(); parse.main_process(); if(parse.get_error()) { @@ -83,8 +76,8 @@ void execute(std::string& file,std::string& command) parse.get_root().print_ast(0); return; } - import.link(parse.get_root()); - parse.get_root().clear(); + // first used file is itself + import.link(parse.get_root(),file); if(import.get_error()) { die("import",file); @@ -103,7 +96,8 @@ void execute(std::string& file,std::string& command) } vm.init( codegen.get_str_table(), - codegen.get_num_table() + codegen.get_num_table(), + import.get_file() ); vm.run(codegen.get_exec_code()); vm.clear(); @@ -128,7 +122,7 @@ void interact() logo(); else if(command=="exit") return; - else if(command=="lex" || command=="ast" || command=="code" || command=="exec") + else if(command=="ast" || command=="code" || command=="exec") execute(file,command); else file=command; diff --git a/nasal_ast.h b/nasal_ast.h index 7051346..9ca8157 100644 --- a/nasal_ast.h +++ b/nasal_ast.h @@ -5,6 +5,7 @@ enum ast_node { ast_null=0, ast_root,ast_block, + ast_file, // ast_file is only used to store which file the subtree is on,codegen will generate nothing ast_nil,ast_num,ast_str,ast_id,ast_func,ast_hash,ast_vec, ast_hashmember,ast_call,ast_callh,ast_callv,ast_callf,ast_subvec, ast_args,ast_default_arg,ast_dynamic_id, @@ -27,6 +28,7 @@ const char* ast_name[]= { "null", "root","block", + "file", "nil","num","str","id","func","hash","vec", "hashmember","call","callh","callv","callf","subvec", "args","deflt_arg","dyn_id", @@ -131,7 +133,7 @@ void nasal_ast::print_ast(int depth) std::cout<&,nasal_gc&); nasal_val* builtin_cmp(std::vector&,nasal_gc&); nasal_val* builtin_chr(std::vector&,nasal_gc&); -void builtin_err(const char* func_name,std::string info) -{ - std::cout<<">> [vm] "<> [vm] "< number_table; @@ -316,7 +320,7 @@ int nasal_codegen::global_find(std::string& name) void nasal_codegen::gen(uint8_t op,uint32_t num,uint32_t line) { - exec_code.push_back({op,num,line}); + exec_code.push_back({op,fileindex,num,line}); return; } @@ -1136,6 +1140,7 @@ void nasal_codegen::main_progress(nasal_ast& ast) error=0; in_foreach=0; in_forindex=0; + fileindex=0; number_table.clear(); string_table.clear(); @@ -1149,6 +1154,7 @@ void nasal_codegen::main_progress(nasal_ast& ast) switch(tmp.get_type()) { case ast_null:case ast_nil:case ast_num:case ast_str:case ast_func:break; + case ast_file:fileindex=tmp.get_num();break; case ast_def:def_gen(tmp);break; case ast_multi_assign:multi_assign_gen(tmp);break; case ast_conditional:conditional_gen(tmp);break; diff --git a/nasal_import.h b/nasal_import.h index a6652da..f83fc74 100644 --- a/nasal_import.h +++ b/nasal_import.h @@ -4,21 +4,22 @@ class nasal_import { private: - int error; - nasal_lexer import_lex; - nasal_parse import_par; - nasal_ast import_ast; + int error; + nasal_lexer import_lex; + nasal_parse import_par; + nasal_ast import_ast; std::vector filename_table; - void die(std::string&,const char*); - bool check_import(nasal_ast&); - bool check_exist(std::string&); - void linker(nasal_ast&,nasal_ast&&); + void die(std::string&,const char*); + bool check_import(nasal_ast&); + bool check_exist(std::string&); + void linker(nasal_ast&,nasal_ast&&); nasal_ast file_import(nasal_ast&); - nasal_ast load(nasal_ast&); + nasal_ast load(nasal_ast&,uint16_t); public: - int get_error(){return error;} - void link(nasal_ast&); + int get_error(){return error;} + void link(nasal_ast&,std::string&); nasal_ast& get_root(){return import_ast;} + std::vector& get_file(){return filename_table;} }; void nasal_import::die(std::string& filename,const char* error_stage) @@ -91,7 +92,6 @@ nasal_ast nasal_import::file_import(nasal_ast& node) return tmp; } import_par.set_toklist(import_lex.get_token_list()); - import_lex.get_token_list().clear(); import_par.main_process(); if(import_par.get_error()) { @@ -99,30 +99,34 @@ nasal_ast nasal_import::file_import(nasal_ast& node) return tmp; } tmp=std::move(import_par.get_root()); - import_par.get_root().clear(); // check if tmp has 'import' - return load(tmp); + return load(tmp,filename_table.size()-1); } -nasal_ast nasal_import::load(nasal_ast& root) +nasal_ast nasal_import::load(nasal_ast& root,uint16_t fileindex) { nasal_ast new_root(0,ast_root); for(auto& i:root.get_children()) if(check_import(i)) linker(new_root,file_import(i)); // add root to the back of new_root + nasal_ast file_head(0,ast_file); + file_head.set_num(fileindex); + new_root.add_child(std::move(file_head)); linker(new_root,std::move(root)); return new_root; } -void nasal_import::link(nasal_ast& root) +void nasal_import::link(nasal_ast& root,std::string& self) { // initializing error=0; filename_table.clear(); + filename_table.push_back(self); import_ast.clear(); // scan root and import files,then generate a new ast and return to import_ast - import_ast=load(root); + // the main file's index is 0 + import_ast=load(root,0); return; } diff --git a/nasal_vm.h b/nasal_vm.h index b13c9a4..3cb3b0d 100644 --- a/nasal_vm.h +++ b/nasal_vm.h @@ -15,7 +15,10 @@ private: std::vector imm; // immediate number nasal_val** mem_addr; // used for mem_call nasal_gc gc; // garbage collector - + /* values used for debug */ + std::vector bytecode; // bytecode + std::vector files; // files + void die(std::string); bool condition(nasal_val*); void opr_intg(); @@ -97,19 +100,22 @@ public: nasal_vm():stack_top(gc.stack_top){}; void init( std::vector&, - std::vector&); + std::vector&, + std::vector&); void clear(); void run(std::vector&); }; void nasal_vm::init( std::vector& strs, - std::vector& nums) + std::vector& nums, + std::vector& filenames) { gc.gc_init(nums,strs); gc.val_stack[STACK_MAX_DEPTH-1]=nullptr; num_table=nums; // get constant numbers str_table=strs; // get constant strings & symbols + files=filenames;// get filenames for debugger return; } void nasal_vm::clear() @@ -126,7 +132,22 @@ void nasal_vm::clear() } void nasal_vm::die(std::string str) { - printf(">> [vm] 0x%.8x: %s\n",pc,str.c_str()); + printf(">> [vm] error: %s\ntrace back:\n",str.c_str()); + // add error pc into ret_stack + ret.push(pc); + // trace back will use ret_stack + while(!ret.empty()) + { + uint32_t point=ret.top(); + ret.pop(); + printf( + "\tpc 0x%.8x: %s 0x%.8x (%s line %d)\n", + point, + code_table[bytecode[point].op].name, + bytecode[point].num, + files[bytecode[point].fidx].c_str(), + bytecode[point].line); + } gc.val_stack[STACK_MAX_DEPTH-1]=(nasal_val*)0xffff; return; } @@ -735,7 +756,8 @@ inline void nasal_vm::opr_callfh() inline void nasal_vm::opr_callb() { (++stack_top)[0]=(*builtin_func[imm[pc]].func)(gc.local.back(),gc); - gc.val_stack[STACK_MAX_DEPTH-1]=(stack_top[0]?nullptr:(nasal_val*)0xffff); + if(!stack_top[0]) + die("native function error."); return; } inline void nasal_vm::opr_slcbegin() @@ -898,6 +920,8 @@ void nasal_vm::run(std::vector& exec) &&slcend, &&slc, &&slc2, &&mcallg, &&mcalll, &&mcallv, &&mcallh, &&ret }; + + bytecode=exec; std::vector code; for(auto& i:exec) { @@ -912,7 +936,7 @@ void nasal_vm::run(std::vector& exec) nop: if(canary[0] && canary[0]!=(nasal_val*)0xffff) - std::cout<<">> [vm] stack overflow.\n"; + die("stack overflow"); std::cout<<">> [vm] process exited after "<<((double)(clock()-begin))/CLOCKS_PER_SEC<<"s.\n"; // debug // for(int i=0;i<15;++i) @@ -933,80 +957,80 @@ nop: //#define exec_opnodie(op,num) {op();++count[num];goto *code[++pc];} #define exec_opnodie(op,num) {op();goto *code[++pc];} -intg: exec_opnodie(opr_intg ,op_intg); -intl: exec_opnodie(opr_intl ,op_intl); -offset: exec_opnodie(opr_offset ,op_offset); -loadg: exec_opnodie(opr_loadg ,op_loadg); -loadl: exec_opnodie(opr_loadl ,op_loadl); -pnum: exec_operand(opr_pnum ,op_pnum); -pone: exec_operand(opr_pone ,op_pone); -pzero: exec_operand(opr_pzero ,op_pzero); -pnil: exec_operand(opr_pnil ,op_pnil); -pstr: exec_operand(opr_pstr ,op_pstr); -newv: exec_operand(opr_newv ,op_newv); -newh: exec_operand(opr_newh ,op_newh); -newf: exec_operand(opr_newf ,op_newf); -happ: exec_opnodie(opr_happ ,op_happ); -para: exec_opnodie(opr_para ,op_para); -defpara: exec_opnodie(opr_defpara ,op_defpara); -dynpara: exec_opnodie(opr_dynpara ,op_dynpara); -unot: exec_operand(opr_unot ,op_unot); -usub: exec_opnodie(opr_usub ,op_usub); -add: exec_opnodie(opr_add ,op_add); -sub: exec_opnodie(opr_sub ,op_sub); -mul: exec_opnodie(opr_mul ,op_mul); -div: exec_opnodie(opr_div ,op_div); -lnk: exec_opnodie(opr_lnk ,op_lnk); -addc: exec_opnodie(opr_addc ,op_addc); -subc: exec_opnodie(opr_subc ,op_subc); -mulc: exec_opnodie(opr_mulc ,op_mulc); -divc: exec_opnodie(opr_divc ,op_divc); -lnkc: exec_opnodie(opr_lnkc ,op_lnkc); -addeq: exec_opnodie(opr_addeq ,op_addeq); -subeq: exec_opnodie(opr_subeq ,op_subeq); -muleq: exec_opnodie(opr_muleq ,op_muleq); -diveq: exec_opnodie(opr_diveq ,op_diveq); -lnkeq: exec_opnodie(opr_lnkeq ,op_lnkeq); -addeqc: exec_opnodie(opr_addeqc ,op_addeqc); -subeqc: exec_opnodie(opr_subeqc ,op_subeqc); -muleqc: exec_opnodie(opr_muleqc ,op_muleqc); -diveqc: exec_opnodie(opr_diveqc ,op_diveqc); -lnkeqc: exec_opnodie(opr_lnkeqc ,op_lnkeqc); -meq: exec_opnodie(opr_meq ,op_meq); -eq: exec_opnodie(opr_eq ,op_eq); -neq: exec_opnodie(opr_neq ,op_neq); -less: exec_opnodie(opr_less ,op_less); -leq: exec_opnodie(opr_leq ,op_leq); -grt: exec_opnodie(opr_grt ,op_grt); -geq: exec_opnodie(opr_geq ,op_geq); -lessc: exec_opnodie(opr_lessc ,op_lessc); -leqc: exec_opnodie(opr_leqc ,op_leqc); -grtc: exec_opnodie(opr_grtc ,op_grtc); -geqc: exec_opnodie(opr_geqc ,op_geqc); -pop: exec_opnodie(opr_pop ,op_pop); -jmp: exec_opnodie(opr_jmp ,op_jmp); -jt: exec_opnodie(opr_jt ,op_jt); -jf: exec_opnodie(opr_jf ,op_jf); -counter: exec_operand(opr_counter ,op_cnt); -cntpop: exec_opnodie(opr_cntpop ,op_cntpop); -findex: exec_opnodie(opr_findex ,op_findex); -feach: exec_opnodie(opr_feach ,op_feach); -callg: exec_opnodie(opr_callg ,op_callg); -calll: exec_opnodie(opr_calll ,op_calll); -callv: exec_operand(opr_callv ,op_callv); -callvi: exec_operand(opr_callvi ,op_callvi); -callh: exec_operand(opr_callh ,op_callh); -callfv: exec_operand(opr_callfv ,op_callfv); -callfh: exec_operand(opr_callfh ,op_callfh); -callb: exec_operand(opr_callb ,op_callb); +intg: exec_opnodie(opr_intg ,op_intg ); +intl: exec_opnodie(opr_intl ,op_intl ); +offset: exec_opnodie(opr_offset ,op_offset ); +loadg: exec_opnodie(opr_loadg ,op_loadg ); +loadl: exec_opnodie(opr_loadl ,op_loadl ); +pnum: exec_operand(opr_pnum ,op_pnum ); +pone: exec_operand(opr_pone ,op_pone ); +pzero: exec_operand(opr_pzero ,op_pzero ); +pnil: exec_operand(opr_pnil ,op_pnil ); +pstr: exec_operand(opr_pstr ,op_pstr ); +newv: exec_operand(opr_newv ,op_newv ); +newh: exec_operand(opr_newh ,op_newh ); +newf: exec_operand(opr_newf ,op_newf ); +happ: exec_opnodie(opr_happ ,op_happ ); +para: exec_opnodie(opr_para ,op_para ); +defpara: exec_opnodie(opr_defpara ,op_defpara ); +dynpara: exec_opnodie(opr_dynpara ,op_dynpara ); +unot: exec_operand(opr_unot ,op_unot ); +usub: exec_opnodie(opr_usub ,op_usub ); +add: exec_opnodie(opr_add ,op_add ); +sub: exec_opnodie(opr_sub ,op_sub ); +mul: exec_opnodie(opr_mul ,op_mul ); +div: exec_opnodie(opr_div ,op_div ); +lnk: exec_opnodie(opr_lnk ,op_lnk ); +addc: exec_opnodie(opr_addc ,op_addc ); +subc: exec_opnodie(opr_subc ,op_subc ); +mulc: exec_opnodie(opr_mulc ,op_mulc ); +divc: exec_opnodie(opr_divc ,op_divc ); +lnkc: exec_opnodie(opr_lnkc ,op_lnkc ); +addeq: exec_opnodie(opr_addeq ,op_addeq ); +subeq: exec_opnodie(opr_subeq ,op_subeq ); +muleq: exec_opnodie(opr_muleq ,op_muleq ); +diveq: exec_opnodie(opr_diveq ,op_diveq ); +lnkeq: exec_opnodie(opr_lnkeq ,op_lnkeq ); +addeqc: exec_opnodie(opr_addeqc ,op_addeqc ); +subeqc: exec_opnodie(opr_subeqc ,op_subeqc ); +muleqc: exec_opnodie(opr_muleqc ,op_muleqc ); +diveqc: exec_opnodie(opr_diveqc ,op_diveqc ); +lnkeqc: exec_opnodie(opr_lnkeqc ,op_lnkeqc ); +meq: exec_opnodie(opr_meq ,op_meq ); +eq: exec_opnodie(opr_eq ,op_eq ); +neq: exec_opnodie(opr_neq ,op_neq ); +less: exec_opnodie(opr_less ,op_less ); +leq: exec_opnodie(opr_leq ,op_leq ); +grt: exec_opnodie(opr_grt ,op_grt ); +geq: exec_opnodie(opr_geq ,op_geq ); +lessc: exec_opnodie(opr_lessc ,op_lessc ); +leqc: exec_opnodie(opr_leqc ,op_leqc ); +grtc: exec_opnodie(opr_grtc ,op_grtc ); +geqc: exec_opnodie(opr_geqc ,op_geqc ); +pop: exec_opnodie(opr_pop ,op_pop ); +jmp: exec_opnodie(opr_jmp ,op_jmp ); +jt: exec_opnodie(opr_jt ,op_jt ); +jf: exec_opnodie(opr_jf ,op_jf ); +counter: exec_operand(opr_counter ,op_cnt ); +cntpop: exec_opnodie(opr_cntpop ,op_cntpop ); +findex: exec_opnodie(opr_findex ,op_findex ); +feach: exec_opnodie(opr_feach ,op_feach ); +callg: exec_opnodie(opr_callg ,op_callg ); +calll: exec_opnodie(opr_calll ,op_calll ); +callv: exec_operand(opr_callv ,op_callv ); +callvi: exec_operand(opr_callvi ,op_callvi ); +callh: exec_operand(opr_callh ,op_callh ); +callfv: exec_operand(opr_callfv ,op_callfv ); +callfh: exec_operand(opr_callfh ,op_callfh ); +callb: exec_operand(opr_callb ,op_callb ); slcbegin:exec_operand(opr_slcbegin,op_slcbegin); -slcend: exec_opnodie(opr_slcend ,op_slcend); -slc: exec_operand(opr_slc ,op_slc); -slc2: exec_operand(opr_slc2 ,op_slc2); -mcallg: exec_opnodie(opr_mcallg ,op_mcallg); -mcalll: exec_opnodie(opr_mcalll ,op_mcalll); -mcallv: exec_operand(opr_mcallv ,op_mcallv); -mcallh: exec_operand(opr_mcallh ,op_mcallh); -ret: exec_opnodie(opr_ret ,op_ret); +slcend: exec_opnodie(opr_slcend ,op_slcend ); +slc: exec_operand(opr_slc ,op_slc ); +slc2: exec_operand(opr_slc2 ,op_slc2 ); +mcallg: exec_opnodie(opr_mcallg ,op_mcallg ); +mcalll: exec_opnodie(opr_mcalll ,op_mcalll ); +mcallv: exec_operand(opr_mcallv ,op_mcallv ); +mcallh: exec_operand(opr_mcallh ,op_mcallh ); +ret: exec_opnodie(opr_ret ,op_ret ); } #endif \ No newline at end of file