add license & other changes

parser recognizes syntax errors more accurately.
change some for loop to standard c++11 for(auto iter:obj)
add MIT license
change info in README.md
This commit is contained in:
Valk Richard Li 2021-05-04 17:39:24 +08:00
parent 6adb991c04
commit a463af53b7
8 changed files with 188 additions and 219 deletions

21
LICENSE Normal file
View File

@ -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.

View File

@ -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<nasal_val*>& 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;i<size;++i)
{
nasal_val* tmp=ref_vec[i];
switch(tmp->get_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<<tmp->get_number(); break;
case vm_str: std::cout<<tmp->get_string(); break;
case vm_vec: tmp->get_vector().print(); break;
case vm_hash: tmp->get_hash().print(); break;
case vm_num: std::cout<<i->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

View File

@ -103,6 +103,8 @@ int main()
logo();
std::cout<<">> Nasal interpreter ver 6.0 .\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)

View File

@ -119,21 +119,16 @@ nasal_val* builtin_print(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
// local_scope[0] is reserved for 'me'
nasal_val* vec_addr=local_scope[1];
// main process
std::vector<nasal_val*>& ref_vec=vec_addr->ptr.vec->elems;
int size=ref_vec.size();
for(int i=0;i<size;++i)
{
nasal_val* tmp=ref_vec[i];
switch(tmp->type)
for(auto i:vec_addr->ptr.vec->elems)
switch(i->type)
{
case vm_nil: std::cout<<"nil"; break;
case vm_num: std::cout<<tmp->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<<i->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<nasal_val*>& local_scope,nasal_gc& gc)
return nullptr;
}
std::vector<nasal_val*>& ref_vec=vec_addr->ptr.vec->elems;
std::vector<nasal_val*>& ref_elems=elem_addr->ptr.vec->elems;
int size=ref_elems.size();
for(int i=0;i<size;++i)
ref_vec.push_back(ref_elems[i]);
for(auto i:elem_addr->ptr.vec->elems)
ref_vec.push_back(i);
return gc.nil_addr;
}
nasal_val* builtin_setsize(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
@ -173,14 +166,7 @@ nasal_val* builtin_setsize(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
builtin_err("setsize","\"size\" must be greater than -1");
return nullptr;
}
std::vector<nasal_val*>& ref_vec=vec_addr->ptr.vec->elems;
int vec_size=ref_vec.size();
if(num<vec_size)
for(int i=num;i<vec_size;++i)
ref_vec.pop_back();
else if(num>vec_size)
for(int i=vec_size;i<num;++i)
ref_vec.push_back(gc.nil_addr);
vec_addr->ptr.vec->elems.resize(num,gc.nil_addr);
return gc.nil_addr;
}
@ -285,7 +271,6 @@ nasal_val* builtin_split(std::vector<nasal_val*>& 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<nasal_val*>& ref_vec=ret_addr->ptr.vec->elems;
std::string tmp="";
@ -674,11 +659,10 @@ nasal_val* builtin_getkeys(std::vector<nasal_val*>& local_scope,nasal_gc& gc)
}
nasal_val* ret_addr=gc.gc_alloc(vm_vec);
std::vector<nasal_val*>& ref_vec=ret_addr->ptr.vec->elems;
std::unordered_map<std::string,nasal_val*>& 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<nasal_val*>& 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<nasal_val*>& local_scope,nasal_gc& gc)

View File

@ -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;i<global.size();++i)
if(global[i]==name)
for(auto sym:global)
if(sym==name)
return;
global.push_back(name);
}
else
{
for(int i=0;i<local.back().size();++i)
if(local.back()[i]==name)
for(auto sym:local.back())
if(sym==name)
return;
local.back().push_back(name);
}
@ -275,12 +275,12 @@ int nasal_codegen::local_find(std::string& name)
{
int index=-1;
int cnt=0;
for(auto i=local.begin();i!=local.end();++i)
for(auto i:local)
{
for(int j=0;j<i->size();++j)
if((*i)[j]==name)
for(int j=0;j<i.size();++j)
if(i[j]==name)
index=cnt+j;
cnt+=i->size();
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;i<size;++i)
calc_gen(ast.get_children()[i]);
gen(op_vapp,size);
for(auto node:ast.get_children())
calc_gen(node);
gen(op_vapp,ast.get_children().size());
return;
}
void nasal_codegen::hash_gen(nasal_ast& ast)
{
int size=ast.get_children().size();
gen(op_newh,0);
for(int i=0;i<size;++i)
for(auto node:ast.get_children())
{
calc_gen(ast.get_children()[i].get_children()[1]);
std::string str=ast.get_children()[i].get_children()[0].get_str();
calc_gen(node.get_children()[1]);
std::string str=node.get_children()[0].get_str();
regist_string(str);
gen(op_happ,string_table[str]);
}
@ -375,12 +373,9 @@ void nasal_codegen::func_gen(nasal_ast& ast)
// this symbol's index will be 0
if(local.size()==1)
add_sym("me");
nasal_ast& ref_arg=ast.get_children()[0];
int arg_size=ref_arg.get_children().size();
for(int i=0;i<arg_size;++i)
// generate parameter list
for(auto tmp:ast.get_children()[0].get_children())
{
nasal_ast& tmp=ref_arg.get_children()[i];
if(tmp.get_type()==ast_id)
{
std::string str=tmp.get_str();
@ -463,7 +458,7 @@ void nasal_codegen::call_id(nasal_ast& ast)
gen(op_callg,index);
return;
}
die("cannot find symbol named \""+str+"\".",ast.get_line());
die("undefined symbol \""+str+"\".",ast.get_line());
return;
}
@ -484,10 +479,8 @@ void nasal_codegen::call_vec(nasal_ast& ast)
return;
}
gen(op_slcbegin,0);
int size=ast.get_children().size();
for(int i=0;i<size;++i)
for(auto tmp:ast.get_children())
{
nasal_ast& tmp=ast.get_children()[i];
if(tmp.get_type()!=ast_subvec)
{
calc_gen(tmp);
@ -549,7 +542,7 @@ void nasal_codegen::mcall_id(nasal_ast& ast)
gen(op_mcallg,index);
return;
}
die("cannot find symbol named \""+str+"\".",ast.get_line());
die("undefined symbol \""+str+"\".",ast.get_line());
return;
}
@ -955,10 +948,7 @@ void nasal_codegen::calc_gen(nasal_ast& ast)
void nasal_codegen::block_gen(nasal_ast& ast)
{
int size=ast.get_children().size();
for(int i=0;i<size;++i)
{
nasal_ast& tmp=ast.get_children()[i];
for(auto tmp:ast.get_children())
switch(tmp.get_type())
{
case ast_null:case ast_nil:case ast_num:case ast_str:case ast_func:break;
@ -1005,7 +995,6 @@ void nasal_codegen::block_gen(nasal_ast& ast)
case ast_trino:calc_gen(tmp);pop_gen();break;
case ast_return:ret_gen(tmp);break;
}
}
return;
}
@ -1085,10 +1074,10 @@ void nasal_codegen::main_progress(nasal_ast& ast)
exec_code[0].num=global.size();
num_res_table.resize(number_table.size());
str_res_table.resize(string_table.size());
for(auto i=number_table.begin();i!=number_table.end();++i)
num_res_table[i->second]=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;i<num_res_table.size();++i)
std::cout<<".number "<<num_res_table[i]<<'\n';
for(int i=0;i<str_res_table.size();++i)
std::cout<<".symbol "<<str_res_table[i]<<'\n';
for(auto num:num_res_table)
std::cout<<".number "<<num<<'\n';
for(auto str:str_res_table)
std::cout<<".symbol "<<str<<'\n';
int size=exec_code.size();
for(int i=0;i<size;++i)
print_op(i);

View File

@ -96,23 +96,21 @@ nasal_val** nasal_vec::get_mem(int index)
void nasal_vec::print()
{
int size=elems.size();
std::cout<<"[";
if(!size)
std::cout<<"]";
for(int i=0;i<size;++i)
std::cout<<'[';
for(auto i:elems)
{
nasal_val* tmp=elems[i];
switch(tmp->type)
switch(i->type)
{
case vm_nil: std::cout<<"nil"; break;
case vm_num: std::cout<<tmp->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<<i->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,19 +124,14 @@ nasal_val* nasal_hash::get_val(std::string& key)
{
nasal_val* val_addr=elems["parents"];
if(val_addr->type==vm_vec)
for(auto i:val_addr->ptr.vec->elems)
{
std::vector<nasal_val*>& vec_ref=val_addr->ptr.vec->elems;
int size=vec_ref.size();
for(int i=0;i<size;++i)
{
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;
}
nasal_val** nasal_hash::get_mem(std::string& key)
@ -150,19 +143,14 @@ nasal_val** nasal_hash::get_mem(std::string& key)
{
nasal_val* val_addr=elems["parents"];
if(val_addr->type==vm_vec)
for(auto i:val_addr->ptr.vec->elems)
{
std::vector<nasal_val*>& vec_ref=val_addr->ptr.vec->elems;
int size=vec_ref.size();
for(int i=0;i<size;++i)
{
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;
}
bool nasal_hash::check_contain(std::string& key)
@ -175,13 +163,10 @@ bool nasal_hash::check_contain(std::string& key)
if(val_addr->type==vm_vec)
{
bool result=false;
std::vector<nasal_val*>& vec_ref=val_addr->ptr.vec->elems;
int size=vec_ref.size();
for(int i=0;i<size;++i)
for(auto i:val_addr->ptr.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<<i->first<<':';
nasal_val* tmp=i->second;
std::cout<<i.first<<':';
nasal_val* tmp=i.second;
switch(tmp->type)
{
case vm_nil: std::cout<<"nil"; break;
@ -322,13 +302,13 @@ struct nasal_gc
void nasal_gc::mark()
{
std::queue<nasal_val*> 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<nasal_val*>& 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<std::string,nasal_val*>& 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<nasal_val*>& cls=tmp->ptr.func->closure;
std::vector<nasal_val*>& 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;i<size;++i)
for(auto i:memory)
{
if(!memory[i]->mark)
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<double>& nums,std::vector<std::string>& strs)
}
void nasal_gc::gc_clear()
{
for(int i=0;i<memory.size();++i)
{
memory[i]->clear();
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;i<num_addrs.size();++i)
delete num_addrs[i];
for(auto i:num_addrs)
delete i;
num_addrs.clear();
for(int i=0;i<str_addrs.size();++i)
delete str_addrs[i];
for(auto i:str_addrs)
delete i;
str_addrs.clear();
return;
}

View File

@ -120,24 +120,30 @@ void nasal_parse::main_process()
root.set_type(ast_root);
while(tok_list[ptr].type!=tok_eof)
{
int err_tok_size=error_token.size();
root.add_child(expr());
if(tok_list[ptr].type==tok_semi)
match(tok_semi);
else if(need_semi_check(root.get_children().back()) && tok_list[ptr].type!=tok_eof)
{
// if detect error token, avoid checking semicolon
else if(error_token.size()>err_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)
die(error_line,"expected \";\"");
}
}
if(!error_token.size())
return;
int sameline=error_token[0].line;
for(int i=0;i<error_token.size();++i)
if(sameline!=error_token[i].line)
{
die(sameline,"error tokens in this line maybe recorded because of fatal syntax errors");
sameline=error_token[i].line;
}
std::vector<int> 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<<' '<<line;
std::cout<<" maybe recorded because of fatal syntax errors."
<<"please check \'(\',\'[\',\'{\',\')\',\']\',\'}\' match or not.\n";
return;
}
nasal_ast& nasal_parse::get_root()
@ -189,15 +195,13 @@ void nasal_parse::match(int type,std::string err_info)
}
bool nasal_parse::check_comma(int* panic_set)
{
bool in_panic_set=false;
for(int i=0;panic_set[i];++i)
if(tok_list[ptr].type==panic_set[i])
{
in_panic_set=true;
die(error_line,"expected \',\' between scalars");
break;
return true;
}
return in_panic_set;
return false;
}
bool nasal_parse::check_multi_def()
{
@ -519,15 +523,17 @@ nasal_ast nasal_parse::exprs_gen()
match(tok_lbrace);
while(tok_list[ptr].type!=tok_rbrace && tok_list[ptr].type!=tok_eof)
{
int err_tok_size=error_token.size();
node.add_child(expr());
if(tok_list[ptr].type==tok_semi)
match(tok_semi);
else if(need_semi_check(node.get_children().back()) && tok_list[ptr].type!=tok_rbrace)
{
// if detect error token, avoid checking semicolon
else if(error_token.size()>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)
die(error_line,"expected \";\"");
}
}
match(tok_rbrace,"expected \'}\' when generating expressions");
}
else

View File

@ -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())