diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..099df14 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 ValKmjolnir + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 07798ec..41cc79e 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,17 @@ [Nasal](http://wiki.flightgear.org/Nasal_scripting_language) is a script language that used in [FlightGear](https://www.flightgear.org/). +The interpreter is totally rewritten by ValKmjolnir using C++(standard c++11) without reusing the code in Andy Ross's nasal interpreter(https://github.com/andyross/nasal). But we really appreciate that Andy created this amazing programming language and his interpreter project. + The interpreter is still in development(now it works well --2021/2/15). We really need your support! Also,i am a member of [FGPRC](https://www.fgprc.org/), welcome to join us! +(2021/5/4) Now this project uses MIT license.Edit it if you want, use this project to learn or create more interesting things(But don't forget me XD). + # Why Writing Nasal Interpreter -Nasal is a script language first used in Flightgear. +Nasal is a script language first used in Flightgear, created by Andy Ross(https://github.com/andyross). But in last summer holiday, members in FGPRC told me that it is hard to debug with nasal-console in Flightgear, especially when checking syntax errors. @@ -379,22 +383,18 @@ nasal_val* builtin_print(std::vector& local_scope,nasal_gc& gc) // because local_scope[0] is reserved for value 'me' nasal_val* vector_value=local_scope[1]; // main process - // also check number of arguments and type here,if get a type error,use builtin_err and return nullptr - nasal_vec& ref_vec=vector_value->get_vector(); - int size=ref_vec.size(); - for(int i=0;iget_type()) + // also check number of arguments and type here + // if get a type error,use builtin_err and return nullptr + for(auto i:vec_addr->ptr.vec->elems) + switch(i->type) { - case vm_nil: std::cout<<"nil"; break; - case vm_num: std::cout<get_number(); break; - case vm_str: std::cout<get_string(); break; - case vm_vec: tmp->get_vector().print(); break; - case vm_hash: tmp->get_hash().print(); break; - case vm_func: std::cout<<"func(...){...}"; break; + case vm_nil: std::cout<<"nil"; break; + case vm_num: std::cout<ptr.num; break; + case vm_str: std::cout<<*i->ptr.str; break; + case vm_vec: i->ptr.vec->print(); break; + case vm_hash: i->ptr.hash->print(); break; + case vm_func: std::cout<<"func(...){...}"; break; } - } // if a nasal value is not in use,use gc::del_reference to delete it // generate return value,use gc::gc_alloc(type) to make a new value // or use reserved reference gc.nil_addr/gc.one_addr/gc.zero_addr diff --git a/main.cpp b/main.cpp index 068870c..ca12527 100644 --- a/main.cpp +++ b/main.cpp @@ -102,8 +102,10 @@ int main() #endif logo(); std::cout<<">> Nasal interpreter ver 6.0 .\n"; - std::cout<<">> Code: https://github.com/ValKmjolnir/Nasal-Interpreter\n"; - std::cout<<">> Info: http://wiki.flightgear.org/Nasal_scripting_language\n"; + std::cout<<">> Code: https://github.com/ValKmjolnir/Nasal-Interpreter\n"; + std::cout<<">> Code: https://gitee.com/valkmjolnir/Nasal-Interpreter\n"; + std::cout<<">> Thanks: https://github.com/andyross/nasal\n"; + std::cout<<">> Info: http://wiki.flightgear.org/Nasal_scripting_language\n"; std::cout<<">> Input \"help\" to get help .\n"; while(1) { diff --git a/nasal_builtin.h b/nasal_builtin.h index 7aaa4e4..ed27d0e 100644 --- a/nasal_builtin.h +++ b/nasal_builtin.h @@ -119,21 +119,16 @@ nasal_val* builtin_print(std::vector& local_scope,nasal_gc& gc) // local_scope[0] is reserved for 'me' nasal_val* vec_addr=local_scope[1]; // main process - std::vector& ref_vec=vec_addr->ptr.vec->elems; - int size=ref_vec.size(); - for(int i=0;itype) + for(auto i:vec_addr->ptr.vec->elems) + switch(i->type) { case vm_nil: std::cout<<"nil"; break; - case vm_num: std::cout<ptr.num; break; - case vm_str: std::cout<<*tmp->ptr.str; break; - case vm_vec: tmp->ptr.vec->print(); break; - case vm_hash: tmp->ptr.hash->print(); break; + case vm_num: std::cout<ptr.num; break; + case vm_str: std::cout<<*i->ptr.str; break; + case vm_vec: i->ptr.vec->print(); break; + case vm_hash: i->ptr.hash->print(); break; case vm_func: std::cout<<"func(...){...}"; break; } - } // generate return value return gc.nil_addr; } @@ -147,10 +142,8 @@ nasal_val* builtin_append(std::vector& local_scope,nasal_gc& gc) return nullptr; } std::vector& ref_vec=vec_addr->ptr.vec->elems; - std::vector& ref_elems=elem_addr->ptr.vec->elems; - int size=ref_elems.size(); - for(int i=0;iptr.vec->elems) + ref_vec.push_back(i); return gc.nil_addr; } nasal_val* builtin_setsize(std::vector& local_scope,nasal_gc& gc) @@ -173,14 +166,7 @@ nasal_val* builtin_setsize(std::vector& local_scope,nasal_gc& gc) builtin_err("setsize","\"size\" must be greater than -1"); return nullptr; } - std::vector& ref_vec=vec_addr->ptr.vec->elems; - int vec_size=ref_vec.size(); - if(numvec_size) - for(int i=vec_size;iptr.vec->elems.resize(num,gc.nil_addr); return gc.nil_addr; } @@ -285,7 +271,6 @@ nasal_val* builtin_split(std::vector& local_scope,nasal_gc& gc) std::string source=*string_val_addr->ptr.str; int delimeter_len=delimeter.length(); int source_len=source.length(); - nasal_val* ret_addr=gc.gc_alloc(vm_vec); std::vector& ref_vec=ret_addr->ptr.vec->elems; std::string tmp=""; @@ -674,11 +659,10 @@ nasal_val* builtin_getkeys(std::vector& local_scope,nasal_gc& gc) } nasal_val* ret_addr=gc.gc_alloc(vm_vec); std::vector& ref_vec=ret_addr->ptr.vec->elems; - std::unordered_map& ref_hash=hash_addr->ptr.hash->elems; - for(auto iter=ref_hash.begin();iter!=ref_hash.end();++iter) + for(auto iter:hash_addr->ptr.hash->elems) { nasal_val* str_addr=gc.gc_alloc(vm_str); - *str_addr->ptr.str=iter->first; + *str_addr->ptr.str=iter.first; ref_vec.push_back(str_addr); } return ret_addr; @@ -687,7 +671,7 @@ nasal_val* builtin_import(std::vector& local_scope,nasal_gc& gc) { // this function is used in preprocessing. // this function will return nothing when running. - builtin_err("import","cannot use import when running"); + builtin_err("import","must use this function in global scope"); return nullptr; } nasal_val* builtin_die(std::vector& local_scope,nasal_gc& gc) diff --git a/nasal_codegen.h b/nasal_codegen.h index 3809803..ca58065 100644 --- a/nasal_codegen.h +++ b/nasal_codegen.h @@ -3,44 +3,44 @@ enum op_code { - op_nop, - op_intg, - op_intl, - op_loadg, - op_loadl, - op_pnum, - op_pone, - op_pzero, - op_pnil, - op_pstr, - op_newv, - op_newh, - op_newf, - op_vapp, - op_happ, - op_para, - op_defpara, - op_dynpara, - op_unot, - op_usub, - op_add, - op_sub, - op_mul, - op_div, - op_lnk, - op_addeq, - op_subeq, - op_muleq, - op_diveq, - op_lnkeq, - op_meq, - op_eq, - op_neq, - op_less, - op_leq, - op_grt, - op_geq, - op_pop, + op_nop, // do nothing and end the vm main loop + op_intg, // global scope size + op_intl, // local scope size + op_loadg, // load global symbol value + op_loadl, // load local symbol value + op_pnum, // push constant number to the stack + op_pone, // push 1 to the stack + op_pzero, // push 0 to the stack + op_pnil, // push constant nil to the stack + op_pstr, // push constant string to the stack + op_newv, // push new vector to the stack + op_newh, // push new hash to the stack + op_newf, // push new function to the stack + op_vapp, // vector append + op_happ, // hash append + op_para, // normal parameter + op_defpara, // default parameter + op_dynpara, // dynamic parameter + op_unot, // ! + op_usub, // - + op_add, // + + op_sub, // - + op_mul, // * + op_div, // / + op_lnk, // ~ + op_addeq, // += + op_subeq, // -= + op_muleq, // *= + op_diveq, // /= + op_lnkeq, // ~= + op_meq, // = + op_eq, // == + op_neq, // != + op_less, // < + op_leq, // <= + op_grt, // > + op_geq, // >= + op_pop, // pop a value from stack op_jmp, // jump 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 @@ -256,15 +256,15 @@ void nasal_codegen::add_sym(std::string name) { if(local.empty()) { - for(int i=0;isize();++j) - if((*i)[j]==name) + for(int j=0;jsize(); + cnt+=i.size(); } return index; } @@ -337,22 +337,20 @@ void nasal_codegen::str_gen(nasal_ast& ast) void nasal_codegen::vec_gen(nasal_ast& ast) { - int size=ast.get_children().size(); gen(op_newv,0); - for(int i=0;isecond]=i->first; - for(auto i=string_table.begin();i!=string_table.end();++i) - str_res_table[i->second]=i->first; + for(auto i:number_table) + num_res_table[i.second]=i.first; + for(auto i:string_table) + str_res_table[i.second]=i.first; return; } @@ -1124,10 +1113,10 @@ void nasal_codegen::print_op(int index) void nasal_codegen::print_byte_code() { - for(int i=0;itype) + switch(i->type) { case vm_nil: std::cout<<"nil"; break; - case vm_num: std::cout<ptr.num; break; - case vm_str: std::cout<<*tmp->ptr.str; break; - case vm_vec: tmp->ptr.vec->print(); break; - case vm_hash: tmp->ptr.hash->print(); break; + case vm_num: std::cout<ptr.num; break; + case vm_str: std::cout<<*i->ptr.str; break; + case vm_vec: i->ptr.vec->print(); break; + case vm_hash: i->ptr.hash->print(); break; case vm_func: std::cout<<"func(...){...}"; break; } - std::cout<<",]"[i==size-1]; + std::cout<<','; } + std::cout<<']'; return; } @@ -126,18 +124,13 @@ nasal_val* nasal_hash::get_val(std::string& key) { nasal_val* val_addr=elems["parents"]; if(val_addr->type==vm_vec) - { - std::vector& vec_ref=val_addr->ptr.vec->elems; - int size=vec_ref.size(); - for(int i=0;iptr.vec->elems) { - nasal_val* tmp=vec_ref[i]; - if(tmp->type==vm_hash) - ret_addr=tmp->ptr.hash->get_val(key); + if(i->type==vm_hash) + ret_addr=i->ptr.hash->get_val(key); if(ret_addr) return ret_addr; } - } } return nullptr; } @@ -150,18 +143,13 @@ nasal_val** nasal_hash::get_mem(std::string& key) { nasal_val* val_addr=elems["parents"]; if(val_addr->type==vm_vec) - { - std::vector& vec_ref=val_addr->ptr.vec->elems; - int size=vec_ref.size(); - for(int i=0;iptr.vec->elems) { - nasal_val* tmp=vec_ref[i]; - if(tmp->type==vm_hash) - mem_addr=tmp->ptr.hash->get_mem(key); + if(i->type==vm_hash) + mem_addr=i->ptr.hash->get_mem(key); if(mem_addr) return mem_addr; } - } } return nullptr; } @@ -175,13 +163,10 @@ bool nasal_hash::check_contain(std::string& key) if(val_addr->type==vm_vec) { bool result=false; - std::vector& vec_ref=val_addr->ptr.vec->elems; - int size=vec_ref.size(); - for(int i=0;iptr.vec->elems) { - nasal_val* tmp=vec_ref[i]; - if(tmp->type==vm_hash) - result=tmp->ptr.hash->check_contain(key); + if(i->type==vm_hash) + result=i->ptr.hash->check_contain(key); if(result) return true; } @@ -192,15 +177,10 @@ bool nasal_hash::check_contain(std::string& key) void nasal_hash::print() { std::cout<<'{'; - if(!elems.size()) + for(auto i:elems) { - std::cout<<'}'; - return; - } - for(auto i=elems.begin();i!=elems.end();++i) - { - std::cout<first<<':'; - nasal_val* tmp=i->second; + std::cout<type) { case vm_nil: std::cout<<"nil"; break; @@ -322,13 +302,13 @@ struct nasal_gc void nasal_gc::mark() { std::queue bfs; - for(auto i=global.begin();i!=global.end();++i) - bfs.push(*i); - for(auto i=local.begin();i!=local.end();++i) - for(auto j=i->begin();j!=i->end();++j) - bfs.push(*j); - for(auto i=slice_stack.begin();i!=slice_stack.end();++i) - bfs.push(*i); + for(auto i:global) + bfs.push(i); + for(auto i:local) + for(auto j:i) + bfs.push(j); + for(auto i:slice_stack) + bfs.push(i); for(nasal_val** i=val_stack;i<=stack_top;++i) bfs.push(*i); while(!bfs.empty()) @@ -338,40 +318,31 @@ void nasal_gc::mark() if(!tmp || tmp->mark) continue; tmp->mark=true; if(tmp->type==vm_vec) - { - std::vector& vec=tmp->ptr.vec->elems; - for(auto i=vec.begin();i!=vec.end();++i) - bfs.push(*i); - } + for(auto i:tmp->ptr.vec->elems) + bfs.push(i); else if(tmp->type==vm_hash) - { - std::unordered_map& hash=tmp->ptr.hash->elems; - for(auto i=hash.begin();i!=hash.end();++i) - bfs.push(i->second); - } + for(auto i:tmp->ptr.hash->elems) + bfs.push(i.second); else if(tmp->type==vm_func) { - std::vector& cls=tmp->ptr.func->closure; - std::vector& def=tmp->ptr.func->default_para; - for(auto i=cls.begin();i!=cls.end();++i) - bfs.push(*i); - for(auto i=def.begin();i!=def.end();++i) - bfs.push(*i); + for(auto i:tmp->ptr.func->closure) + bfs.push(i); + for(auto i:tmp->ptr.func->default_para) + bfs.push(i); } } return; } void nasal_gc::sweep() { - int size=memory.size(); - for(int i=0;imark) + if(!i->mark) { - memory[i]->clear(); - free_list.push(memory[i]); + i->clear(); + free_list.push(i); } - memory[i]->mark=false; + i->mark=false; } return; } @@ -414,11 +385,8 @@ void nasal_gc::gc_init(std::vector& nums,std::vector& strs) } void nasal_gc::gc_clear() { - for(int i=0;iclear(); - delete memory[i]; - } + for(auto i:memory) + delete i; memory.clear(); while(!free_list.empty()) free_list.pop(); @@ -429,11 +397,11 @@ void nasal_gc::gc_clear() delete nil_addr; delete one_addr; delete zero_addr; - for(int i=0;ierr_tok_size) + continue; + // the last expression can be recognized without semi else if(need_semi_check(root.get_children().back()) && tok_list[ptr].type!=tok_eof) - { - // the last expression can be recognized without semi die(error_line,"expected \";\""); - } } if(!error_token.size()) return; - int sameline=error_token[0].line; - for(int i=0;i err_lines; + err_lines.push_back(error_token[0].line); + for(auto tok:error_token) + if(err_lines.back()!=tok.line) + err_lines.push_back(tok.line); + ++error; + std::cout<<">> [parse] error tokens in line"; + for(auto line:err_lines) + std::cout<<' '<err_tok_size) + continue; + // the last expression can be recognized without semi else if(need_semi_check(node.get_children().back()) && tok_list[ptr].type!=tok_rbrace) - { - // the last expression can be recognized without semi die(error_line,"expected \";\""); - } } match(tok_rbrace,"expected \'}\' when generating expressions"); } diff --git a/nasal_vm.h b/nasal_vm.h index 928a5eb..e5f3be1 100644 --- a/nasal_vm.h +++ b/nasal_vm.h @@ -108,7 +108,6 @@ void nasal_vm::init( void nasal_vm::clear() { gc.gc_clear(); - while(!addr_stack.empty()) addr_stack.pop(); while(!ret.empty())