add tips
This commit is contained in:
parent
de305d26ad
commit
4f3ddf803a
|
@ -58,6 +58,12 @@ Use these commands to get help:
|
|||
|
||||
> ./nasal -h | -help
|
||||
|
||||
If your system is Windows and you want to output unicode,please use this command before running nasal interpreter:
|
||||
|
||||
> chcp 65001
|
||||
|
||||
The interpreter's interactive mode will do this automatically,so you don't need to run this command if you use the interactive interpreter.
|
||||
|
||||
## Parser
|
||||
|
||||
LL(k) parser.
|
||||
|
|
3
main.cpp
3
main.cpp
|
@ -19,6 +19,9 @@ void help_interact()
|
|||
void help_cmd()
|
||||
{
|
||||
std::cout
|
||||
#ifdef _WIN32
|
||||
<<"use command \'chcp 65001\' if want to use unicode.\n"
|
||||
#endif
|
||||
<<"nasal | use interactive interpreter.\n"
|
||||
<<"nasal -h -help | get help.\n"
|
||||
<<"nasal -v -version | get version of nasal interpreter.\n"
|
||||
|
|
|
@ -181,8 +181,6 @@ private:
|
|||
int local_find(std::string&);
|
||||
int global_find(std::string&);
|
||||
void gen(unsigned char,unsigned int);
|
||||
void pop_gen();
|
||||
void nil_gen();
|
||||
void num_gen(nasal_ast&);
|
||||
void str_gen(nasal_ast&);
|
||||
void vec_gen(nasal_ast&);
|
||||
|
@ -304,20 +302,6 @@ void nasal_codegen::gen(unsigned char op,unsigned int index)
|
|||
return;
|
||||
}
|
||||
|
||||
void nasal_codegen::pop_gen()
|
||||
{
|
||||
opcode op(op_pop,0);
|
||||
exec_code.push_back(op);
|
||||
return;
|
||||
}
|
||||
|
||||
void nasal_codegen::nil_gen()
|
||||
{
|
||||
opcode op(op_pnil,0);
|
||||
exec_code.push_back(op);
|
||||
return;
|
||||
}
|
||||
|
||||
void nasal_codegen::num_gen(nasal_ast& ast)
|
||||
{
|
||||
double num=ast.get_num();
|
||||
|
@ -422,7 +406,7 @@ void nasal_codegen::func_gen(nasal_ast& ast)
|
|||
|
||||
if(!block.get_children().size() || block.get_children().back().get_type()!=ast_ret)
|
||||
{
|
||||
nil_gen();
|
||||
gen(op_pnil,0);
|
||||
gen(op_ret,0);
|
||||
}
|
||||
exec_code[jmp_ptr].num=exec_code.size();
|
||||
|
@ -591,14 +575,16 @@ void nasal_codegen::single_def(nasal_ast& ast)
|
|||
}
|
||||
void nasal_codegen::multi_def(nasal_ast& ast)
|
||||
{
|
||||
int size=ast.get_children()[0].get_children().size();
|
||||
auto& ids=ast.get_children()[0].get_children();
|
||||
int size=ids.size();
|
||||
if(ast.get_children()[1].get_type()==ast_multi_scalar)
|
||||
{
|
||||
auto& vals=ast.get_children()[1].get_children();
|
||||
for(int i=0;i<size;++i)
|
||||
{
|
||||
std::string& str=ast.get_children()[0].get_children()[i].get_str();
|
||||
calc_gen(vals[i]);
|
||||
std::string& str=ids[i].get_str();
|
||||
add_sym(str);
|
||||
calc_gen(ast.get_children()[1].get_children()[i]);
|
||||
if(local.empty())
|
||||
gen(op_loadg,global_find(str));
|
||||
else
|
||||
|
@ -611,14 +597,14 @@ void nasal_codegen::multi_def(nasal_ast& ast)
|
|||
for(int i=0;i<size;++i)
|
||||
{
|
||||
gen(op_callvi,i);
|
||||
std::string& str=ast.get_children()[0].get_children()[i].get_str();
|
||||
std::string& str=ids[i].get_str();
|
||||
add_sym(str);
|
||||
if(local.empty())
|
||||
gen(op_loadg,global_find(str));
|
||||
else
|
||||
gen(op_loadl,local_find(str));
|
||||
}
|
||||
pop_gen();
|
||||
gen(op_pop,0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -643,7 +629,7 @@ void nasal_codegen::multi_assign_gen(nasal_ast& ast)
|
|||
{
|
||||
mcall(ast.get_children()[0].get_children()[i]);
|
||||
gen(op_meq,0);
|
||||
pop_gen();
|
||||
gen(op_pop,0);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -654,20 +640,18 @@ void nasal_codegen::multi_assign_gen(nasal_ast& ast)
|
|||
gen(op_callvi,i);
|
||||
mcall(ast.get_children()[0].get_children()[i]);
|
||||
gen(op_meq,0);
|
||||
pop_gen();
|
||||
gen(op_pop,0);
|
||||
}
|
||||
pop_gen();
|
||||
gen(op_pop,0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void nasal_codegen::conditional_gen(nasal_ast& ast)
|
||||
{
|
||||
int size=ast.get_children().size();
|
||||
std::vector<int> jmp_label;
|
||||
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_if || tmp.get_type()==ast_elsif)
|
||||
{
|
||||
calc_gen(tmp.get_children()[0]);
|
||||
|
@ -676,7 +660,7 @@ void nasal_codegen::conditional_gen(nasal_ast& ast)
|
|||
block_gen(tmp.get_children()[1]);
|
||||
jmp_label.push_back(exec_code.size());
|
||||
// without 'else' the last condition doesn't need to jmp
|
||||
if(i!=size-1)
|
||||
if(&tmp!=&ast.get_children().back())
|
||||
gen(op_jmp,0);
|
||||
exec_code[ptr].num=exec_code.size();
|
||||
}
|
||||
|
@ -686,8 +670,8 @@ void nasal_codegen::conditional_gen(nasal_ast& ast)
|
|||
break;
|
||||
}
|
||||
}
|
||||
for(std::vector<int>::iterator i=jmp_label.begin();i!=jmp_label.end();++i)
|
||||
exec_code[*i].num=exec_code.size();
|
||||
for(auto i:jmp_label)
|
||||
exec_code[i].num=exec_code.size();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -765,7 +749,7 @@ void nasal_codegen::for_gen(nasal_ast& ast)
|
|||
case ast_less:
|
||||
case ast_geq:
|
||||
case ast_grt:
|
||||
case ast_trino:calc_gen(ast.get_children()[0]);pop_gen();break;
|
||||
case ast_trino:calc_gen(ast.get_children()[0]);gen(op_pop,0);break;
|
||||
}
|
||||
int jmp_place=exec_code.size();
|
||||
if(ast.get_children()[1].get_type()==ast_null)
|
||||
|
@ -789,7 +773,7 @@ void nasal_codegen::for_gen(nasal_ast& ast)
|
|||
case ast_neg:case ast_not:
|
||||
case ast_add:case ast_sub:case ast_mult:case ast_div:case ast_link:
|
||||
case ast_cmpeq:case ast_neq:case ast_leq:case ast_less:case ast_geq:case ast_grt:
|
||||
case ast_trino:calc_gen(ast.get_children()[2]);pop_gen();break;
|
||||
case ast_trino:calc_gen(ast.get_children()[2]);gen(op_pop,0);break;
|
||||
}
|
||||
gen(op_jmp,jmp_place);
|
||||
exec_code[label_exit].num=exec_code.size();
|
||||
|
@ -816,14 +800,14 @@ void nasal_codegen::forindex_gen(nasal_ast& ast)
|
|||
{
|
||||
mcall(ast.get_children()[0]);
|
||||
gen(op_meq,0);
|
||||
pop_gen();
|
||||
gen(op_pop,0);
|
||||
}
|
||||
|
||||
block_gen(ast.get_children()[2]);
|
||||
gen(op_jmp,ptr);
|
||||
exec_code[ptr].num=exec_code.size();
|
||||
load_continue_break(exec_code.size()-1,exec_code.size());
|
||||
pop_gen();// pop vector
|
||||
gen(op_pop,0);// pop vector
|
||||
gen(op_cntpop,0);
|
||||
return;
|
||||
}
|
||||
|
@ -846,14 +830,14 @@ void nasal_codegen::foreach_gen(nasal_ast& ast)
|
|||
{
|
||||
mcall(ast.get_children()[0]);
|
||||
gen(op_meq,0);
|
||||
pop_gen();
|
||||
gen(op_pop,0);
|
||||
}
|
||||
|
||||
block_gen(ast.get_children()[2]);
|
||||
gen(op_jmp,ptr);
|
||||
exec_code[ptr].num=exec_code.size();
|
||||
load_continue_break(exec_code.size()-1,exec_code.size());
|
||||
pop_gen();// pop vector
|
||||
gen(op_pop,0);// pop vector
|
||||
gen(op_cntpop,0);
|
||||
return;
|
||||
}
|
||||
|
@ -864,13 +848,13 @@ void nasal_codegen::or_gen(nasal_ast& ast)
|
|||
int l1=exec_code.size();
|
||||
gen(op_jt,0);
|
||||
|
||||
pop_gen();
|
||||
gen(op_pop,0);
|
||||
calc_gen(ast.get_children()[1]);
|
||||
int l2=exec_code.size();
|
||||
gen(op_jt,0);
|
||||
|
||||
pop_gen();
|
||||
nil_gen();
|
||||
gen(op_pop,0);
|
||||
gen(op_pnil,0);
|
||||
|
||||
exec_code[l1].num=exec_code[l2].num=exec_code.size();
|
||||
return;
|
||||
|
@ -883,14 +867,14 @@ void nasal_codegen::and_gen(nasal_ast& ast)
|
|||
|
||||
int lfalse=exec_code.size();
|
||||
gen(op_jmp,0);
|
||||
pop_gen();// jt jumps here
|
||||
gen(op_pop,0);// jt jumps here
|
||||
|
||||
calc_gen(ast.get_children()[1]);
|
||||
gen(op_jt,exec_code.size()+3);
|
||||
|
||||
exec_code[lfalse].num=exec_code.size();
|
||||
pop_gen();
|
||||
nil_gen();
|
||||
gen(op_pop,0);
|
||||
gen(op_pnil,0);
|
||||
//jt jumps here
|
||||
return;
|
||||
}
|
||||
|
@ -913,14 +897,14 @@ void nasal_codegen::calc_gen(nasal_ast& ast)
|
|||
{
|
||||
switch(ast.get_type())
|
||||
{
|
||||
case ast_nil: nil_gen(); break;
|
||||
case ast_num: num_gen(ast); break;
|
||||
case ast_str: str_gen(ast); break;
|
||||
case ast_id: call_id(ast); break;
|
||||
case ast_vec: vec_gen(ast); break;
|
||||
case ast_hash: hash_gen(ast);break;
|
||||
case ast_func: func_gen(ast);break;
|
||||
case ast_call: call_gen(ast);break;
|
||||
case ast_nil: gen(op_pnil,0); break;
|
||||
case ast_num: num_gen(ast); break;
|
||||
case ast_str: str_gen(ast); break;
|
||||
case ast_id: call_id(ast); break;
|
||||
case ast_vec: vec_gen(ast); break;
|
||||
case ast_hash: hash_gen(ast); break;
|
||||
case ast_func: func_gen(ast); break;
|
||||
case ast_call: call_gen(ast); break;
|
||||
case ast_equal:
|
||||
calc_gen(ast.get_children()[1]);
|
||||
mcall(ast.get_children()[0]);
|
||||
|
@ -1009,7 +993,7 @@ void nasal_codegen::block_gen(nasal_ast& ast)
|
|||
case ast_grt:
|
||||
case ast_or:
|
||||
case ast_and:
|
||||
case ast_trino:calc_gen(tmp);pop_gen();break;
|
||||
case ast_trino:calc_gen(tmp);gen(op_pop,0);break;
|
||||
case ast_ret:ret_gen(tmp);break;
|
||||
}
|
||||
return;
|
||||
|
@ -1030,7 +1014,7 @@ void nasal_codegen::ret_gen(nasal_ast& ast)
|
|||
if(ast.get_children().size())
|
||||
calc_gen(ast.get_children()[0]);
|
||||
else
|
||||
nil_gen();
|
||||
gen(op_pnil,0);
|
||||
gen(op_ret,0);
|
||||
return;
|
||||
}
|
||||
|
@ -1082,7 +1066,7 @@ void nasal_codegen::main_progress(nasal_ast& ast)
|
|||
case ast_grt:
|
||||
case ast_or:
|
||||
case ast_and:
|
||||
case ast_trino:calc_gen(tmp);pop_gen();break;
|
||||
case ast_trino:calc_gen(tmp);gen(op_pop,0);break;
|
||||
}
|
||||
}
|
||||
gen(op_nop,0);
|
||||
|
|
|
@ -271,10 +271,8 @@ void nasal_parse::check_memory_reachable(nasal_ast& node)
|
|||
{
|
||||
if(node.get_children()[0].get_type()!=ast_id)
|
||||
die(node.get_line(),"cannot get the memory of a temporary data");
|
||||
int size=node.get_children().size();
|
||||
for(int i=0;i<size;++i)
|
||||
for(auto& tmp:node.get_children())
|
||||
{
|
||||
nasal_ast& tmp=node.get_children()[i];
|
||||
if(tmp.get_type()==ast_callf)
|
||||
die(tmp.get_line(),"cannot get the memory of function-returned value");
|
||||
if(tmp.get_type()==ast_callv && (tmp.get_children().size()>1 || tmp.get_children()[0].get_type()==ast_subvec))
|
||||
|
@ -419,41 +417,40 @@ nasal_ast nasal_parse::args_gen()
|
|||
match(tok_rcurve,"expected \')\' after parameter list");
|
||||
|
||||
std::string args_format="func(";
|
||||
int node_child_size=node.get_children().size();
|
||||
for(int i=0;i<node_child_size;++i)
|
||||
for(auto& tmp:node.get_children())
|
||||
{
|
||||
switch(node.get_children()[i].get_type())
|
||||
switch(tmp.get_type())
|
||||
{
|
||||
case ast_id: args_format+="val";break;
|
||||
case ast_id: args_format+="val";break;
|
||||
case ast_default_arg: args_format+="val=scalar";break;
|
||||
case ast_dynamic_id: args_format+="val...";break;
|
||||
}
|
||||
args_format+=",)"[i==node_child_size-1];
|
||||
args_format+=",)"[&tmp==&node.get_children().back()];
|
||||
}
|
||||
bool checked_default_val=false,checked_dynamic_ids=false;
|
||||
for(int i=0;i<node_child_size;++i)
|
||||
for(auto& tmp:node.get_children())
|
||||
{
|
||||
if(node.get_children()[i].get_type()==ast_default_arg)
|
||||
if(tmp.get_type()==ast_default_arg)
|
||||
checked_default_val=true;
|
||||
else if(node.get_children()[i].get_type()==ast_dynamic_id)
|
||||
else if(tmp.get_type()==ast_dynamic_id)
|
||||
checked_dynamic_ids=true;
|
||||
if(checked_default_val && node.get_children()[i].get_type()!=ast_default_arg)
|
||||
die(node.get_children()[i].get_line(),"must use default arguments until the end of argument list: "+args_format);
|
||||
if(checked_dynamic_ids && i!=node_child_size-1)
|
||||
die(node.get_children()[i].get_line(),"dynamic identifier must be the end of argument list: "+args_format);
|
||||
if(checked_default_val && tmp.get_type()!=ast_default_arg)
|
||||
die(tmp.get_line(),"must use default parameters after using it once: "+args_format);
|
||||
if(checked_dynamic_ids && &tmp!=&node.get_children().back())
|
||||
die(tmp.get_line(),"dynamic parameter must be the end: "+args_format);
|
||||
}
|
||||
std::unordered_map<std::string,bool> argname_table;
|
||||
for(int i=0;i<node_child_size;++i)
|
||||
for(auto& tmp:node.get_children())
|
||||
{
|
||||
std::string new_name;
|
||||
switch(node.get_children()[i].get_type())
|
||||
switch(tmp.get_type())
|
||||
{
|
||||
case ast_dynamic_id:
|
||||
case ast_id:new_name=node.get_children()[i].get_str();break;
|
||||
case ast_default_arg:new_name=node.get_children()[i].get_children()[0].get_str();break;
|
||||
case ast_id:new_name=tmp.get_str();break;
|
||||
case ast_default_arg:tmp.get_children()[0].get_str();break;
|
||||
}
|
||||
if(argname_table.find(new_name)!=argname_table.end())
|
||||
die(node.get_children()[i].get_line(),"argument name should not repeat");
|
||||
if(argname_table.count(new_name))
|
||||
die(tmp.get_line(),"parameter's name repeats: "+new_name);
|
||||
else
|
||||
argname_table[new_name]=true;
|
||||
}
|
||||
|
@ -464,9 +461,9 @@ nasal_ast nasal_parse::expr()
|
|||
nasal_ast node(tok_list[ptr].line,ast_null);
|
||||
int tok_type=tok_list[ptr].type;
|
||||
if((tok_type==tok_break || tok_type==tok_continue) && !in_loop)
|
||||
die(error_line,"cannot use break/continue outside loop");
|
||||
die(error_line,"use break/continue in the loop");
|
||||
if(tok_type==tok_ret && !in_function)
|
||||
die(error_line,"cannot use return outside function");
|
||||
die(error_line,"use return in the function");
|
||||
switch(tok_type)
|
||||
{
|
||||
case tok_nil:
|
||||
|
|
Loading…
Reference in New Issue