1871 lines
56 KiB
C++
1871 lines
56 KiB
C++
#ifndef __NASAL_PARSE_H__
|
|
#define __NASAL_PARSE_H__
|
|
|
|
class nasal_parse
|
|
{
|
|
private:
|
|
/*
|
|
parse_token_stream: get detailed tokens from lexer and store them in this stack
|
|
checked_tokens : checked tokens will be stored here
|
|
this_token : changed by function get_token and push_token,and used when generating ast
|
|
error : record the number of errors occurred when generating ast
|
|
root : after generating process, the ast will be stored in root
|
|
*/
|
|
std::stack<token> parse_token_stream;
|
|
std::stack<token> checked_tokens;
|
|
token this_token;
|
|
int error;
|
|
abstract_syntax_tree root;
|
|
/* parsse_error_type: used in print_parse_error,including all types of errors*/
|
|
enum parse_error_type
|
|
{
|
|
parse_unknown_error=0, // unknown error
|
|
error_token_in_main, // when a token should not be the begin of a statement in main
|
|
error_token_in_block, // when a token should not be the begin of a statement in block
|
|
|
|
lack_semi,
|
|
lack_id,
|
|
lack_left_curve,
|
|
lack_right_curve,
|
|
lack_right_brace,
|
|
|
|
definition_lack_id, // lack identifier
|
|
definition_lack_equal, // lack '=' when not getting ';'
|
|
assignment_begin_error, // assignment begins with more than one identifier_call
|
|
multi_definition_need_curve, // lack right curve when generating 'var (id,id,id)'
|
|
|
|
multi_assignment_need_curve, // lack right curve when generating (scalar,scalar)=(scalar,scalar)
|
|
multi_assignment_need_equal, // lack '=' when generating (scalar,scalar)=(scalar,scalar)
|
|
|
|
error_begin_token_of_scalar, // in scalar_generate()
|
|
|
|
need_default_parameter, // parameters must have a default value if detected there is a default parameter before.
|
|
default_dynamic_parameter, // default parameter should not be dynamic
|
|
parameter_lack_part, // parameter lack a ')' or identifier
|
|
parameter_lack_curve, // parameter lack a ',' or ')'
|
|
|
|
special_call_func_lack_id,
|
|
special_call_func_lack_colon,
|
|
normal_call_func_has_colon, // when calling a function,normal way and special way cannot be used together
|
|
call_func_lack_comma, // lack comma when giving parameters to a function
|
|
call_hash_lack_id, // lack identifier when calling a hash
|
|
call_vector_wrong_comma, // wrong use of comma like this: id[0,4:6,7,] (the last comma is incorrect here)
|
|
call_vector_lack_bracket, // lack ']' when calling a vector
|
|
call_vector_wrong_token, // get wrong token when calling a vector
|
|
|
|
vector_gen_lack_end, // lack ',' or ')' when generating a vector
|
|
hash_gen_lack_id, // lack identifier or string when generating a hash
|
|
hash_gen_lack_colon, // lack ':' when generating a hash
|
|
hash_gen_lack_end, // lack ',' or '}' when generating a hash
|
|
|
|
ternary_operator_lack_colon, // lack ':'
|
|
};
|
|
/* print the error type and it's line*/
|
|
void print_parse_error(int,int,int);
|
|
/*
|
|
get_token and push_token are most important functions of parser
|
|
these two functions are used to get and push token
|
|
and the result will be stored in this_token
|
|
*/
|
|
void get_token();
|
|
void push_token();
|
|
/* block statements generation */
|
|
abstract_syntax_tree block_generate();
|
|
// check ';'
|
|
void check_semi();
|
|
/* check '(' confliction */
|
|
bool check_multi_assignment(); // check multi_call_id '=' multi_scalar
|
|
bool check_multi_scalar(); // check multi_scalar
|
|
bool check_var_in_curve(); // check multi_definition: (var id,id,id)
|
|
bool check_function_end(abstract_syntax_tree&); // check end of definition or '=' is a function
|
|
/*
|
|
calculation : will get elements generated by and_calculation()
|
|
and_calculation : will get elements generated by or_calculation()
|
|
or_calculation : will get elements generated by cmp_calculation()
|
|
cmp_calculation : will get elements generated by additive_calculation()
|
|
additive_calculation: will get elements generated by multive_calculation()
|
|
multive_calculation : will get elements generated by assign_calculation()(assignment <call_id> '=' <calculation>) and scalar_generate()
|
|
assign_calculation : get elements from scalar_generate()
|
|
please notice that:
|
|
if the elements begin with '!' or '-',multive_calculation() gets them from scalar_generate()
|
|
if not,multive_calculation() gets them from assign_calculation()
|
|
because '!' and '-' cannot be used with assignment together such as: -a=1
|
|
*/
|
|
abstract_syntax_tree calculation();
|
|
abstract_syntax_tree and_calculation();
|
|
abstract_syntax_tree or_calculation();
|
|
abstract_syntax_tree cmp_calculation();
|
|
abstract_syntax_tree additive_calculation();
|
|
abstract_syntax_tree multive_calculation();
|
|
abstract_syntax_tree scalar_generate();
|
|
/* normal data type generation */
|
|
abstract_syntax_tree hash_generate();
|
|
abstract_syntax_tree vector_generate();
|
|
abstract_syntax_tree function_generate();
|
|
/* return_expr() generates ebnf: <return> [<calculation>] ';' */
|
|
abstract_syntax_tree return_expr();
|
|
/* normal expressions */
|
|
abstract_syntax_tree multi_scalar_assignment();
|
|
abstract_syntax_tree definition();
|
|
abstract_syntax_tree loop_expr();
|
|
abstract_syntax_tree conditional_expr();
|
|
public:
|
|
// basic functions
|
|
void delete_all_elements()
|
|
{
|
|
// used in 'del' command in main()
|
|
while(!parse_token_stream.empty())
|
|
parse_token_stream.pop();
|
|
while(!checked_tokens.empty())
|
|
checked_tokens.pop();
|
|
root.set_clear();
|
|
return;
|
|
}
|
|
void print_detail_token();
|
|
void get_token_list(std::list<token>&);
|
|
int get_error();
|
|
abstract_syntax_tree& get_root();
|
|
/* main process of parser */
|
|
void main_generate();
|
|
};
|
|
|
|
void nasal_parse::print_detail_token()
|
|
{
|
|
// copy tokens from parse_token_stream
|
|
// so this function only works when generation hasn't begun.
|
|
std::stack<token> tmp=parse_token_stream;
|
|
// indent
|
|
std::string indent="";
|
|
int brace_cnt=0;
|
|
int line=1;
|
|
std::cout<<line<<"\t";
|
|
while((!tmp.empty()) && (tmp.top().type!=__stack_end))
|
|
{
|
|
if(tmp.top().line!=line)
|
|
{
|
|
// if line changes,print '\n' and number of line
|
|
// by using this loop,empty line will also be output
|
|
for(int i=line+1;i<tmp.top().line;++i)
|
|
std::cout<<std::endl<<i<<"\t";
|
|
line=tmp.top().line;
|
|
std::cout<<std::endl<<line<<"\t"<<indent;
|
|
}
|
|
print_parse_token(tmp.top().type);
|
|
if(tmp.top().type==__left_brace)
|
|
{
|
|
++brace_cnt;
|
|
indent+=' ';
|
|
}
|
|
else if(tmp.top().type==__right_brace)
|
|
--brace_cnt;
|
|
tmp.pop();
|
|
if((!tmp.empty()) && (tmp.top().type==__right_brace) && brace_cnt>=1)
|
|
indent.pop_back();
|
|
}
|
|
std::cout<<std::endl;
|
|
return;
|
|
}
|
|
|
|
void nasal_parse::get_token_list(std::list<token>& detail_token_stream)
|
|
{
|
|
// get detail_token_stream from lexer
|
|
// clear the parse_token_stream and checked_tokens list
|
|
while(!parse_token_stream.empty())
|
|
parse_token_stream.pop();
|
|
while(!checked_tokens.empty())
|
|
checked_tokens.pop();
|
|
// add stack_end token
|
|
token end_token;
|
|
end_token.line=detail_token_stream.back().line;
|
|
end_token.str="stack_end";
|
|
end_token.type=__stack_end;
|
|
|
|
parse_token_stream.push(end_token);
|
|
checked_tokens.push(end_token);
|
|
// clear stacks and initialize them with stack_end token
|
|
|
|
std::stack<token> backward_tmp;
|
|
// backward_tmp is used to backward detail_token_stream
|
|
// to the parse_token_stream so get_token can get token
|
|
// according to the correct subsequence.
|
|
for(std::list<token>::iterator i=detail_token_stream.begin();i!=detail_token_stream.end();++i)
|
|
backward_tmp.push(*i);
|
|
while(!backward_tmp.empty())
|
|
{
|
|
parse_token_stream.push(backward_tmp.top());
|
|
backward_tmp.pop();
|
|
}
|
|
return;
|
|
}
|
|
|
|
void nasal_parse::print_parse_error(int error_type,int line,int error_token_type=__stack_end)
|
|
{
|
|
std::cout<<">> [Parse] line "<<line<<": ";
|
|
switch(error_type)
|
|
{
|
|
case parse_unknown_error:
|
|
std::cout<<"unknown parse error.(token id: "<<error_token_type<<")."<<std::endl;break;
|
|
case error_token_in_main:
|
|
std::cout<<"statements should not begin with \'";
|
|
print_parse_token(error_token_type);
|
|
std::cout<<"\' in main scope."<<std::endl;
|
|
break;
|
|
case error_token_in_block:
|
|
std::cout<<"statements should not begin with \'";
|
|
print_parse_token(error_token_type);
|
|
std::cout<<"\' in block scope."<<std::endl;
|
|
break;
|
|
case lack_semi:
|
|
std::cout<<"expect a \';\' at the end of the statement."<<std::endl;break;
|
|
case lack_id:
|
|
std::cout<<"expect an identifier here."<<std::endl;break;
|
|
case lack_left_curve:
|
|
std::cout<<"expect a \'(\' here."<<std::endl;break;
|
|
case lack_right_curve:
|
|
std::cout<<"expect a \')\' here."<<std::endl;break;
|
|
case lack_right_brace:
|
|
std::cout<<"expect a \'}\' here."<<std::endl;break;
|
|
case definition_lack_id:
|
|
std::cout<<"expect identifier(s) after \'var\'."<<std::endl;break;
|
|
case definition_lack_equal:
|
|
std::cout<<"expect a \'=\' here but get \'";
|
|
print_parse_token(error_token_type);
|
|
std::cout<<"\' when generating definition."<<std::endl;
|
|
break;
|
|
case assignment_begin_error:
|
|
std::cout<<"assignment should begin with one identifier_call."<<std::endl;
|
|
break;
|
|
case multi_definition_need_curve:
|
|
std::cout<<"expect a \')\' here but get \'";
|
|
print_parse_token(error_token_type);
|
|
std::cout<<"\' ."<<std::endl;
|
|
break;
|
|
case multi_assignment_need_curve:
|
|
std::cout<<"expect a \')\' here but get \'";
|
|
print_parse_token(error_token_type);
|
|
std::cout<<"\' ."<<std::endl;
|
|
break;
|
|
case multi_assignment_need_equal:
|
|
std::cout<<"expect a \'=\' here but get \'";
|
|
print_parse_token(error_token_type);
|
|
std::cout<<"\' ."<<std::endl;
|
|
break;
|
|
case error_begin_token_of_scalar:
|
|
std::cout<<"expect a scalar here but get \'";
|
|
print_parse_token(error_token_type);
|
|
std::cout<<"\' ."<<std::endl;
|
|
break;
|
|
case need_default_parameter:
|
|
std::cout<<"parameters after a default parameter must have their own default values."<<std::endl;break;
|
|
case default_dynamic_parameter:
|
|
std::cout<<"dynamic parameter should not have a default value."<<std::endl;break;
|
|
case parameter_lack_part:
|
|
std::cout<<"expect a \')\' or identifier here when generating parameter_list."<<std::endl;break;
|
|
case parameter_lack_curve:
|
|
std::cout<<"expect a \')\' or \',\' here when generating parameter_list."<<std::endl;break;
|
|
case special_call_func_lack_id:
|
|
std::cout<<"expect an identifier here but get \'";
|
|
print_parse_token(error_token_type);
|
|
std::cout<<"\' when calling functions."<<std::endl;
|
|
break;
|
|
case special_call_func_lack_colon:
|
|
std::cout<<"expect an \':\' here but get \'";
|
|
print_parse_token(error_token_type);
|
|
std::cout<<"\' when calling functions."<<std::endl;
|
|
break;
|
|
case normal_call_func_has_colon:
|
|
std::cout<<"normal and special ways of calling a function are not allowed to be used together."<<std::endl;break;
|
|
case call_func_lack_comma:
|
|
std::cout<<"expect a \',\' when calling a function but get \'";
|
|
print_parse_token(error_token_type);
|
|
std::cout<<"\' ."<<std::endl;
|
|
break;
|
|
case call_hash_lack_id:
|
|
std::cout<<"expect an identifier after \'.\' ."<<std::endl;break;
|
|
case call_vector_wrong_comma:
|
|
std::cout<<"expect a scalar after \',\' but get \']\' ."<<std::endl;
|
|
break;
|
|
case call_vector_lack_bracket:
|
|
std::cout<<"expect a \']\' here but get \'";
|
|
print_parse_token(error_token_type);
|
|
std::cout<<"\' ."<<std::endl;
|
|
break;
|
|
case call_vector_wrong_token:
|
|
std::cout<<"expect \':\' or ',' or ']' here but get \'";
|
|
print_parse_token(error_token_type);
|
|
std::cout<<"\' ."<<std::endl;
|
|
break;
|
|
case vector_gen_lack_end:
|
|
std::cout<<"expect a \',\' or \')\' here but get \'";
|
|
print_parse_token(error_token_type);
|
|
std::cout<<"\' ."<<std::endl;
|
|
break;
|
|
case hash_gen_lack_id:
|
|
std::cout<<"expect an identifier or string here but get \'";
|
|
print_parse_token(error_token_type);
|
|
std::cout<<"\' ."<<std::endl;
|
|
break;
|
|
case hash_gen_lack_colon:
|
|
std::cout<<"expect a \':\' here but get \'";
|
|
print_parse_token(error_token_type);
|
|
std::cout<<"\' ."<<std::endl;
|
|
break;
|
|
case hash_gen_lack_end:
|
|
std::cout<<"expect a \',\' or \'}\' here but get \'";
|
|
print_parse_token(error_token_type);
|
|
std::cout<<"\' ."<<std::endl;
|
|
break;
|
|
case ternary_operator_lack_colon:
|
|
std::cout<<"expect a \':\' here but get \'";
|
|
print_parse_token(error_token_type);
|
|
std::cout<<"\' ."<<std::endl;
|
|
break;
|
|
default:
|
|
std::cout<<"unknown parse error.(token id: "<<error_token_type<<")."<<std::endl;break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void nasal_parse::get_token()
|
|
{
|
|
if(!parse_token_stream.empty())
|
|
{
|
|
this_token=parse_token_stream.top();
|
|
parse_token_stream.pop();
|
|
checked_tokens.push(this_token);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void nasal_parse::push_token()
|
|
{
|
|
if(!checked_tokens.empty())
|
|
{
|
|
parse_token_stream.push(checked_tokens.top());
|
|
checked_tokens.pop();
|
|
if(!checked_tokens.empty())
|
|
this_token=checked_tokens.top();
|
|
}
|
|
return;
|
|
}
|
|
|
|
int nasal_parse::get_error()
|
|
{
|
|
// if error is larger than 0,
|
|
// the process after parser will stop.
|
|
return error;
|
|
}
|
|
|
|
abstract_syntax_tree& nasal_parse::get_root()
|
|
{
|
|
return root;
|
|
}
|
|
|
|
void nasal_parse::check_semi()
|
|
{
|
|
// check if this statement has ';' as its end.
|
|
if(this_token.type==__stack_end)
|
|
{
|
|
++error;
|
|
print_parse_error(lack_semi,this_token.line,this_token.type);
|
|
return;
|
|
}
|
|
this->get_token();
|
|
if(this_token.type==__semi)
|
|
return;
|
|
else if(this_token.type==__right_brace)
|
|
{
|
|
// this make func{return 0} as correct
|
|
this->push_token();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
++error;
|
|
this->push_token();
|
|
print_parse_error(lack_semi,this_token.line,this_token.type);
|
|
this->get_token();
|
|
if(this_token.type!=__stack_end)
|
|
this->push_token();
|
|
}
|
|
return;
|
|
}
|
|
|
|
bool nasal_parse::check_multi_assignment()
|
|
{
|
|
bool ret=false;
|
|
int cnt=0;
|
|
|
|
this->get_token();
|
|
++cnt;// get '('
|
|
|
|
this->get_token();
|
|
++cnt;
|
|
if(this_token.type==__id)
|
|
{
|
|
int curve_cnt=0;
|
|
int bracket_cnt=0;
|
|
int brace_cnt=0;
|
|
while(1)
|
|
{
|
|
this->get_token();
|
|
++cnt;
|
|
// these determine statements are used with curve_cnt,bracket_cnt and brace_cnt together
|
|
// to avoid checking commas in other curves/brackets/braces such as ([0,1,2,3])
|
|
// but in multi_assignment, only things like (id[scalar],id.id[scalar]) can be recognized as multi_scalar
|
|
// if ([0,1,2,3]) and i don't use these judgements,then ([0,1,2,3]) will be recognized as multi_scalar
|
|
// but in fact ([0,1,2,3]) is not
|
|
if(this_token.type==__left_curve) ++curve_cnt;
|
|
if(this_token.type==__left_bracket) ++bracket_cnt;
|
|
if(this_token.type==__left_brace) ++brace_cnt;
|
|
if(this_token.type==__right_curve) --curve_cnt;
|
|
if(this_token.type==__right_bracket)--bracket_cnt;
|
|
if(this_token.type==__right_brace) --brace_cnt;
|
|
|
|
// if curves,brackets,braces are in pairs and this_token is comma,it is really multi_id calls
|
|
if(!curve_cnt && !bracket_cnt && !brace_cnt && this_token.type==__comma)
|
|
{
|
|
ret=true;
|
|
break;
|
|
}
|
|
// error occurred
|
|
if(curve_cnt<0 || brace_cnt<0 || brace_cnt<0)
|
|
break;
|
|
// exit when meeting stack end
|
|
if((!parse_token_stream.empty() && parse_token_stream.top().type==__stack_end) || (this_token.type==__semi))
|
|
break;
|
|
}
|
|
}
|
|
for(int i=0;i<cnt;++i)
|
|
this->push_token();
|
|
return ret;
|
|
}
|
|
|
|
bool nasal_parse::check_multi_scalar()
|
|
{
|
|
bool ret=false;
|
|
int cnt=0;
|
|
|
|
this->get_token();
|
|
++cnt;// get '('
|
|
int curve_cnt=0;
|
|
int bracket_cnt=0;
|
|
int brace_cnt=0;
|
|
while(1)
|
|
{
|
|
this->get_token();
|
|
++cnt;
|
|
// these determine statements are used with curve_cnt,bracket_cnt and brace_cnt together
|
|
// to avoid checking commas in other curves/brackets/braces
|
|
// such as (a[0,1,2],b(2,3))
|
|
if(this_token.type==__left_curve) ++curve_cnt;
|
|
if(this_token.type==__left_bracket) ++bracket_cnt;
|
|
if(this_token.type==__left_brace) ++brace_cnt;
|
|
if(this_token.type==__right_curve) --curve_cnt;
|
|
if(this_token.type==__right_bracket)--bracket_cnt;
|
|
if(this_token.type==__right_brace) --brace_cnt;
|
|
|
|
// if curves,brackets,braces are in pairs and this_token is comma,it is really multi_scalar
|
|
if(!curve_cnt && !bracket_cnt && !brace_cnt && this_token.type==__comma)
|
|
{
|
|
ret=true;
|
|
break;
|
|
}
|
|
// error occurred
|
|
if(curve_cnt<0 || brace_cnt<0 || brace_cnt<0)
|
|
break;
|
|
// exit when meeting stack end
|
|
if((!parse_token_stream.empty() && parse_token_stream.top().type==__stack_end) || (this_token.type==__semi))
|
|
break;
|
|
}
|
|
for(int i=0;i<cnt;++i)
|
|
this->push_token();
|
|
return ret;
|
|
}
|
|
|
|
bool nasal_parse::check_var_in_curve()
|
|
{
|
|
bool ret=false;
|
|
this->get_token(); // get '('
|
|
this->get_token(); // get 'var' if exists
|
|
ret=(this_token.type==__var);// check
|
|
this->push_token(); // push 'var'
|
|
this->push_token(); // push '('
|
|
return ret;
|
|
}
|
|
|
|
bool nasal_parse::check_function_end(abstract_syntax_tree& tmp)
|
|
{
|
|
if(tmp.get_node_type()==__definition || tmp.get_node_type()==__equal)
|
|
{
|
|
if(!tmp.get_children().empty())
|
|
{
|
|
// func{}()
|
|
// function
|
|
// parameters
|
|
// block <- if the last child is __normal_statement_block,then don't need semi check
|
|
// call_function
|
|
if(tmp.get_children().back().get_node_type()==__function &&
|
|
tmp.get_children().back().get_children().back().get_node_type()==__normal_statement_block)
|
|
return true;// func{}() should have a ';'
|
|
else
|
|
return check_function_end(tmp.get_children().back());// var a=b=c=d=e=f=g=func{}
|
|
}
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void nasal_parse::main_generate()
|
|
{
|
|
error=0;
|
|
// initialize error
|
|
root.set_clear();
|
|
root.set_node_line(1);
|
|
root.set_node_type(__root);
|
|
// initialize root node
|
|
while(!parse_token_stream.empty() && parse_token_stream.top().type!=__stack_end)
|
|
{
|
|
bool need_semi_check=false;
|
|
// if need_semi_check is true,this means needs check_semi()
|
|
this->get_token();
|
|
switch(this_token.type)
|
|
{
|
|
case __var:
|
|
this->push_token();
|
|
root.add_children(definition());
|
|
if((!root.get_children().empty()) && check_function_end(root.get_children().back()))
|
|
need_semi_check=false;
|
|
else
|
|
need_semi_check=true;
|
|
break;
|
|
case __nor_operator: case __sub_operator:
|
|
case __number: case __nil: case __string: case __id:
|
|
case __left_bracket: case __left_brace:
|
|
case __func:
|
|
this->push_token();
|
|
root.add_children(calculation());
|
|
// check assignment function
|
|
if((!root.get_children().empty()) && check_function_end(root.get_children().back()))
|
|
need_semi_check=false;
|
|
else
|
|
need_semi_check=true;
|
|
break;
|
|
case __left_curve:
|
|
this->push_token();
|
|
if(check_var_in_curve())
|
|
root.add_children(definition());
|
|
// multi-definition must need semi_check
|
|
else if(check_multi_assignment())
|
|
root.add_children(multi_scalar_assignment());
|
|
else
|
|
root.add_children(calculation());
|
|
need_semi_check=true;
|
|
break;
|
|
// '(' is the beginning of too many statements
|
|
// '(' var id,id,id ')'
|
|
// '(' calculation ')'
|
|
// '(' scalar,scalar,scalar ')' '=' '(' scalar,scalar,scalar ')'
|
|
case __if:
|
|
this->push_token();
|
|
root.add_children(conditional_expr());
|
|
break;
|
|
case __while: case __for: case __foreach: case __forindex:
|
|
this->push_token();
|
|
root.add_children(loop_expr());
|
|
break;
|
|
case __semi:break;
|
|
case __stack_end:break;
|
|
default:
|
|
++error;
|
|
print_parse_error(error_token_in_main,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
if(need_semi_check)
|
|
check_semi();
|
|
}
|
|
std::cout<<">> [Parse] complete generation. "<<error<<" error(s)."<<std::endl;
|
|
return;
|
|
}
|
|
|
|
abstract_syntax_tree nasal_parse::block_generate()
|
|
{
|
|
abstract_syntax_tree block_node;
|
|
abstract_syntax_tree continue_break_node;
|
|
this->get_token();
|
|
block_node.set_node_line(this_token.line);
|
|
block_node.set_node_type(__normal_statement_block);
|
|
if(this_token.type!=__left_brace)
|
|
{
|
|
// only one statement, so this doesn't need check_semi()
|
|
switch(this_token.type)
|
|
{
|
|
case __var:
|
|
this->push_token();
|
|
block_node.add_children(definition());
|
|
break;
|
|
case __nor_operator: case __sub_operator:
|
|
case __number: case __nil: case __string: case __id:
|
|
case __left_bracket: case __left_brace:
|
|
case __func:
|
|
this->push_token();
|
|
block_node.add_children(calculation());
|
|
break;
|
|
case __left_curve:
|
|
this->push_token();
|
|
if(check_var_in_curve())
|
|
block_node.add_children(definition());
|
|
// multi-definition must need semi_check
|
|
else if(check_multi_assignment())
|
|
block_node.add_children(multi_scalar_assignment());
|
|
else
|
|
block_node.add_children(calculation());
|
|
break;
|
|
// '(' is the beginning of too many statements
|
|
// '(' var id,id,id ')'
|
|
// '(' calculation ')'
|
|
// '(' scalar,scalar,scalar ')' '=' '(' scalar,scalar,scalar ')'
|
|
case __if:
|
|
this->push_token();
|
|
block_node.add_children(conditional_expr());
|
|
break;
|
|
case __while: case __for: case __foreach: case __forindex:
|
|
this->push_token();
|
|
block_node.add_children(loop_expr());
|
|
break;
|
|
case __return:
|
|
this->push_token();
|
|
block_node.add_children(return_expr());
|
|
break;
|
|
case __continue:
|
|
case __break:
|
|
continue_break_node.set_node_line(this_token.line);
|
|
continue_break_node.set_node_type(this_token.type);
|
|
block_node.add_children(continue_break_node);
|
|
break;
|
|
case __semi:this->push_token();break;
|
|
case __stack_end:break;
|
|
default:
|
|
++error;
|
|
print_parse_error(error_token_in_block,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
// thought don't need to check semi at end, a statement having a semi at its end is also right
|
|
// this statement is used to check statement having a semi at its end
|
|
this->get_token();
|
|
if(this_token.type!=__semi)
|
|
this->push_token();
|
|
}
|
|
else
|
|
{
|
|
this->get_token();
|
|
while(this_token.type!=__right_brace && !parse_token_stream.empty() && parse_token_stream.top().type!=__stack_end)
|
|
{
|
|
bool need_semi_check=false;
|
|
// if need_semi_check is true,this means needs check_semi()
|
|
switch(this_token.type)
|
|
{
|
|
case __var:
|
|
this->push_token();
|
|
block_node.get_children().push_back(definition());
|
|
if((!block_node.get_children().empty()) && check_function_end(block_node.get_children().back()))
|
|
need_semi_check=false;
|
|
else
|
|
need_semi_check=true;
|
|
break;
|
|
case __nor_operator: case __sub_operator:
|
|
case __number: case __nil: case __string: case __id:
|
|
case __left_bracket: case __left_brace:
|
|
case __func:
|
|
this->push_token();
|
|
block_node.add_children(calculation());
|
|
if((!block_node.get_children().empty()) && check_function_end(block_node.get_children().back()))
|
|
need_semi_check=false;
|
|
else
|
|
need_semi_check=true;
|
|
break;
|
|
case __left_curve:
|
|
this->push_token();
|
|
if(check_var_in_curve())
|
|
block_node.add_children(definition());
|
|
else if(check_multi_assignment())
|
|
block_node.add_children(multi_scalar_assignment());
|
|
else
|
|
block_node.add_children(calculation());
|
|
need_semi_check=true;
|
|
break;
|
|
// '(' is the beginning of too many statements
|
|
// '(' var id,id,id ')'
|
|
// '(' calculation ')'
|
|
// '(' scalar,scalar,scalar ')' '=' '(' scalar,scalar,scalar ')'
|
|
case __if:
|
|
this->push_token();
|
|
block_node.add_children(conditional_expr());
|
|
break;
|
|
case __while: case __for: case __foreach: case __forindex:
|
|
this->push_token();
|
|
block_node.add_children(loop_expr());
|
|
break;
|
|
case __return:
|
|
this->push_token();
|
|
block_node.add_children(return_expr());
|
|
need_semi_check=true;
|
|
break;
|
|
case __continue:
|
|
case __break:
|
|
continue_break_node.set_node_line(this_token.line);
|
|
continue_break_node.set_node_type(this_token.type);
|
|
block_node.add_children(continue_break_node);
|
|
need_semi_check=true;
|
|
break;
|
|
case __semi:break;
|
|
case __stack_end:break;
|
|
default:
|
|
++error;
|
|
print_parse_error(error_token_in_block,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
// the last statement can avoid semi check althought need_semi_check is true
|
|
// because check_semi will scan the next token,if this token is '}',then semi_check can be avoided
|
|
if(need_semi_check)
|
|
check_semi();
|
|
this->get_token();
|
|
}
|
|
if(this_token.type!=__right_brace)
|
|
{
|
|
++error;
|
|
print_parse_error(lack_right_brace,this_token.line,this_token.type);
|
|
}
|
|
}
|
|
return block_node;
|
|
}
|
|
|
|
abstract_syntax_tree nasal_parse::multi_scalar_assignment()
|
|
{
|
|
abstract_syntax_tree assignment_node;
|
|
abstract_syntax_tree front_multi_scalar_node;
|
|
abstract_syntax_tree back_multi_scalar_node;
|
|
this->get_token();// get '('
|
|
front_multi_scalar_node.set_node_line(this_token.line);
|
|
front_multi_scalar_node.set_node_type(__multi_scalar);
|
|
while(this_token.type!=__right_curve)
|
|
{
|
|
front_multi_scalar_node.add_children(scalar_generate());
|
|
this->get_token();
|
|
if((this_token.type!=__comma) && (this_token.type!=__right_curve))
|
|
{
|
|
++error;
|
|
print_parse_error(multi_assignment_need_curve,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
if(this_token.type==__comma)
|
|
{
|
|
this->get_token();
|
|
if(this_token.type!=__right_curve)
|
|
this->push_token();
|
|
}
|
|
}
|
|
this->get_token();
|
|
assignment_node.set_node_line(this_token.line);
|
|
assignment_node.set_node_type(this_token.type);
|
|
// only '=' is alowed in multi_assignment
|
|
if(this_token.type!=__equal)
|
|
{
|
|
++error;
|
|
print_parse_error(multi_assignment_need_equal,this_token.line,this_token.type);
|
|
}
|
|
this->get_token();
|
|
if(this_token.type!=__left_curve)
|
|
{
|
|
this->push_token();
|
|
back_multi_scalar_node=scalar_generate();
|
|
}
|
|
else
|
|
{
|
|
this->push_token();
|
|
if(check_multi_scalar())
|
|
{
|
|
this->get_token();// get '('
|
|
back_multi_scalar_node.set_node_line(this_token.line);
|
|
back_multi_scalar_node.set_node_type(__multi_scalar);
|
|
while(this_token.type!=__right_curve)
|
|
{
|
|
back_multi_scalar_node.add_children(scalar_generate());
|
|
this->get_token();
|
|
if((this_token.type!=__comma) && (this_token.type!=__right_curve))
|
|
{
|
|
++error;
|
|
print_parse_error(multi_assignment_need_curve,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
if(this_token.type==__comma)
|
|
{
|
|
this->get_token();
|
|
if(this_token.type!=__right_curve)
|
|
this->push_token();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
back_multi_scalar_node=calculation();
|
|
}
|
|
assignment_node.add_children(front_multi_scalar_node);
|
|
assignment_node.add_children(back_multi_scalar_node);
|
|
return assignment_node;
|
|
}
|
|
|
|
abstract_syntax_tree nasal_parse::calculation()
|
|
{
|
|
abstract_syntax_tree calc_node;
|
|
abstract_syntax_tree tmp_node;
|
|
calc_node=and_calculation();
|
|
this->get_token();
|
|
while(this_token.type==__or_operator)
|
|
{
|
|
tmp_node.set_clear();
|
|
tmp_node.set_node_line(this_token.line);
|
|
tmp_node.set_node_type(this_token.type);
|
|
tmp_node.add_children(calc_node);
|
|
tmp_node.add_children(and_calculation());
|
|
calc_node=tmp_node;
|
|
this->get_token();
|
|
}
|
|
|
|
// assignment must has only one identifier_call as its beginning
|
|
// if not it is a parse-error
|
|
// this block is only used for assignment check(not multi-assignment)
|
|
this->push_token();
|
|
if(calc_node.get_node_type()==__id)
|
|
{
|
|
abstract_syntax_tree assignment_node;
|
|
this->get_token();// check if this token is '=' or '+=' or '-=' or '*=' or '/=' or '~='
|
|
if((this_token.type==__equal) || (this_token.type==__add_equal) || (this_token.type==__sub_equal) || (this_token.type==__mul_equal) || (this_token.type==__div_equal) || (this_token.type==__link_equal))
|
|
{
|
|
// <scalar> ('=' | '+=' | '-=' | '*=' | '/=' | '~=') <calculation>
|
|
assignment_node.set_node_line(this_token.line);
|
|
assignment_node.set_node_type(this_token.type);
|
|
assignment_node.add_children(calc_node);
|
|
assignment_node.add_children(calculation());
|
|
calc_node=assignment_node;
|
|
}
|
|
else
|
|
this->push_token();
|
|
}
|
|
else
|
|
{
|
|
this->get_token();
|
|
if((this_token.type==__equal) || (this_token.type==__add_equal) || (this_token.type==__sub_equal) || (this_token.type==__mul_equal) || (this_token.type==__div_equal) || (this_token.type==__link_equal))
|
|
{
|
|
++error;
|
|
print_parse_error(assignment_begin_error,this_token.line);
|
|
}
|
|
this->push_token();
|
|
}
|
|
|
|
// check ternary_operator
|
|
this->get_token();
|
|
if(this_token.type==__ques_mark)
|
|
{
|
|
tmp_node.set_clear();
|
|
// <expr> '?' <expr> ';' <expr>
|
|
tmp_node.set_node_line(this_token.line);
|
|
tmp_node.set_node_type(__ques_mark);
|
|
tmp_node.add_children(calc_node);
|
|
tmp_node.add_children(calculation());
|
|
this->get_token();
|
|
if(this_token.type!=__colon)
|
|
{
|
|
++error;
|
|
print_parse_error(ternary_operator_lack_colon,this_token.line,this_token.type);
|
|
}
|
|
tmp_node.add_children(calculation());
|
|
calc_node=tmp_node;
|
|
}
|
|
else
|
|
this->push_token();
|
|
return calc_node;
|
|
}
|
|
|
|
abstract_syntax_tree nasal_parse::and_calculation()
|
|
{
|
|
abstract_syntax_tree calc_node;
|
|
abstract_syntax_tree tmp_node;
|
|
calc_node=or_calculation();
|
|
this->get_token();
|
|
while(this_token.type==__and_operator)
|
|
{
|
|
tmp_node.set_clear();
|
|
tmp_node.set_node_line(this_token.line);
|
|
tmp_node.set_node_type(this_token.type);
|
|
tmp_node.add_children(calc_node);
|
|
tmp_node.add_children(or_calculation());
|
|
calc_node=tmp_node;
|
|
this->get_token();
|
|
}
|
|
this->push_token();
|
|
return calc_node;
|
|
}
|
|
|
|
abstract_syntax_tree nasal_parse::or_calculation()
|
|
{
|
|
abstract_syntax_tree calc_node;
|
|
abstract_syntax_tree tmp_node;
|
|
calc_node=cmp_calculation();
|
|
this->get_token();
|
|
while(this_token.type==__or_operator)
|
|
{
|
|
tmp_node.set_clear();
|
|
tmp_node.set_node_line(this_token.line);
|
|
tmp_node.set_node_type(this_token.type);
|
|
tmp_node.add_children(calc_node);
|
|
tmp_node.add_children(cmp_calculation());
|
|
calc_node=tmp_node;
|
|
this->get_token();
|
|
}
|
|
this->push_token();
|
|
return calc_node;
|
|
}
|
|
|
|
abstract_syntax_tree nasal_parse::cmp_calculation()
|
|
{
|
|
abstract_syntax_tree calc_node;
|
|
abstract_syntax_tree tmp_node;
|
|
calc_node=additive_calculation();
|
|
this->get_token();
|
|
while((this_token.type==__cmp_equal) || (this_token.type==__cmp_not_equal) ||
|
|
(this_token.type==__cmp_less) || (this_token.type==__cmp_more) ||
|
|
(this_token.type==__cmp_less_or_equal) || (this_token.type==__cmp_more_or_equal)
|
|
)
|
|
{
|
|
tmp_node.set_clear();
|
|
tmp_node.set_node_line(this_token.line);
|
|
tmp_node.set_node_type(this_token.type);
|
|
tmp_node.add_children(calc_node);
|
|
tmp_node.add_children(additive_calculation());
|
|
calc_node=tmp_node;
|
|
this->get_token();
|
|
}
|
|
this->push_token();
|
|
return calc_node;
|
|
}
|
|
|
|
abstract_syntax_tree nasal_parse::additive_calculation()
|
|
{
|
|
abstract_syntax_tree calc_node;
|
|
abstract_syntax_tree tmp_node;
|
|
calc_node=multive_calculation();
|
|
this->get_token();
|
|
while((this_token.type==__add_operator) || (this_token.type==__sub_operator) || (this_token.type==__link_operator))
|
|
{
|
|
tmp_node.set_clear();
|
|
tmp_node.set_node_line(this_token.line);
|
|
tmp_node.set_node_type(this_token.type);
|
|
tmp_node.add_children(calc_node);
|
|
tmp_node.add_children(multive_calculation());
|
|
calc_node=tmp_node;
|
|
this->get_token();
|
|
}
|
|
this->push_token();
|
|
return calc_node;
|
|
}
|
|
|
|
abstract_syntax_tree nasal_parse::multive_calculation()
|
|
{
|
|
abstract_syntax_tree calc_node;
|
|
abstract_syntax_tree tmp_node;
|
|
this->get_token();
|
|
// be careful that unary calculation and assignment cannot be used together
|
|
// such as: -a=1; this is incorrect use.
|
|
if((this_token.type==__sub_operator) || (this_token.type==__nor_operator))
|
|
{
|
|
// unary calculation
|
|
calc_node.set_node_line(this_token.line);
|
|
calc_node.set_node_type(this_token.type);
|
|
calc_node.add_children(scalar_generate());
|
|
}
|
|
else
|
|
{
|
|
this->push_token();
|
|
calc_node=scalar_generate();
|
|
}
|
|
this->get_token();
|
|
while((this_token.type==__mul_operator) || (this_token.type==__div_operator))
|
|
{
|
|
tmp_node.set_clear();
|
|
tmp_node.set_node_line(this_token.line);
|
|
tmp_node.set_node_type(this_token.type);
|
|
tmp_node.add_children(calc_node);
|
|
this->get_token();
|
|
if((this_token.type==__sub_operator) || (this_token.type==__nor_operator))
|
|
{
|
|
// unary calculation
|
|
calc_node.set_clear();
|
|
calc_node.set_node_line(this_token.line);
|
|
calc_node.set_node_type(this_token.type);
|
|
calc_node.add_children(scalar_generate());
|
|
}
|
|
else
|
|
{
|
|
this->push_token();
|
|
calc_node=scalar_generate();
|
|
}
|
|
tmp_node.add_children(calc_node);
|
|
calc_node=tmp_node;
|
|
this->get_token();
|
|
}
|
|
this->push_token();
|
|
return calc_node;
|
|
}
|
|
|
|
abstract_syntax_tree nasal_parse::scalar_generate()
|
|
{
|
|
this->get_token();
|
|
abstract_syntax_tree scalar_node;
|
|
scalar_node.set_node_line(this_token.line);
|
|
|
|
switch(this_token.type)
|
|
{
|
|
case __number:scalar_node.set_node_type(__number);scalar_node.set_var_number(this_token.str);break;
|
|
case __string:scalar_node.set_node_type(__string);scalar_node.set_var_string(this_token.str);break;
|
|
case __nil:scalar_node.set_node_type(__nil);break;
|
|
case __id:scalar_node.set_node_type(__id);scalar_node.set_var_name(this_token.str);break;
|
|
case __left_curve:
|
|
scalar_node=calculation();
|
|
this->get_token();
|
|
if(this_token.type!=__right_curve)
|
|
{
|
|
++error;
|
|
print_parse_error(lack_right_curve,this_token.line);
|
|
}
|
|
break;
|
|
case __left_brace:// hash
|
|
this->push_token();
|
|
scalar_node=hash_generate();
|
|
break;
|
|
case __left_bracket:// vector
|
|
this->push_token();
|
|
scalar_node=vector_generate();
|
|
break;
|
|
case __func:
|
|
this->get_token();
|
|
if(this_token.type!=__id)
|
|
{
|
|
this->push_token();
|
|
this->push_token();
|
|
scalar_node=function_generate();
|
|
// function
|
|
}
|
|
else
|
|
{
|
|
scalar_node.set_node_type(__id);
|
|
scalar_node.set_var_name(this_token.str);
|
|
// func id
|
|
}
|
|
break;
|
|
default:
|
|
++error;
|
|
print_parse_error(error_begin_token_of_scalar,this_token.line,this_token.type);
|
|
this->push_token();
|
|
break;
|
|
}
|
|
this->get_token(); // check if there is a '(' or '[' or '{' after id
|
|
while((this_token.type==__left_curve) || (this_token.type==__left_bracket) || (this_token.type==__dot))
|
|
{
|
|
if(this_token.type==__left_curve)
|
|
{
|
|
// call function
|
|
abstract_syntax_tree call_func_node;
|
|
call_func_node.set_node_line(this_token.line);
|
|
call_func_node.set_node_type(__call_function);
|
|
this->get_token();
|
|
if(this_token.type!=__right_curve)
|
|
{
|
|
bool scalar_para=true;
|
|
// scalar_para is used to record that parameters is in normal format like f(1,2,3,4)
|
|
// if scalar_para is false ,this means parameters is in special format like f(a:1,b:2)
|
|
if(this_token.type==__id)
|
|
{
|
|
this->get_token();
|
|
if(this_token.type==__colon)
|
|
{
|
|
scalar_para=false;
|
|
this->push_token();// colon
|
|
this->push_token();// identifier
|
|
while(this_token.type!=__right_curve)
|
|
{
|
|
abstract_syntax_tree special_para_node;
|
|
abstract_syntax_tree id_node;
|
|
this->get_token();
|
|
special_para_node.set_node_line(this_token.line);
|
|
special_para_node.set_node_type(__special_parameter);
|
|
if(this_token.type!=__id)
|
|
{
|
|
++error;
|
|
print_parse_error(special_call_func_lack_id,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
id_node.set_node_line(this_token.line);
|
|
id_node.set_node_type(__id);
|
|
id_node.set_var_name(this_token.str);
|
|
special_para_node.add_children(id_node);
|
|
this->get_token();
|
|
if(this_token.type!=__colon)
|
|
{
|
|
++error;
|
|
print_parse_error(special_call_func_lack_colon,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
special_para_node.add_children(calculation());
|
|
call_func_node.add_children(special_para_node);
|
|
this->get_token();
|
|
if((this_token.type!=__comma) && (this_token.type!=__right_curve))
|
|
{
|
|
++error;
|
|
print_parse_error(call_func_lack_comma,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
if(this_token.type==__comma)
|
|
{
|
|
this->get_token();
|
|
if(this_token.type!=__right_curve)
|
|
this->push_token();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this->push_token();// not colon
|
|
this->push_token();// identifier
|
|
}
|
|
}
|
|
else
|
|
this->push_token();// if not identifier then push in
|
|
if(scalar_para)
|
|
while(this_token.type!=__right_curve)
|
|
{
|
|
call_func_node.add_children(calculation());
|
|
this->get_token();
|
|
if((this_token.type!=__comma) && (this_token.type!=__right_curve))
|
|
{
|
|
++error;
|
|
if(this_token.type==__colon)
|
|
print_parse_error(normal_call_func_has_colon,this_token.line,this_token.type);
|
|
else
|
|
print_parse_error(call_func_lack_comma,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
if(this_token.type==__comma)
|
|
{
|
|
this->get_token();
|
|
if(this_token.type!=__right_curve)
|
|
this->push_token();
|
|
}
|
|
}
|
|
}
|
|
scalar_node.add_children(call_func_node);
|
|
}
|
|
else if(this_token.type==__left_bracket)
|
|
{
|
|
abstract_syntax_tree call_vector_node;
|
|
call_vector_node.set_node_line(this_token.line);
|
|
call_vector_node.set_node_type(__call_vector);
|
|
// there are many kinds of ways to call a vector
|
|
// such as: id[0] id[0:12] id[-2:0] id[2:] id[4,3,1,5,2] id[0,2,4:6]
|
|
while(this_token.type!=__right_bracket)
|
|
{
|
|
abstract_syntax_tree tmp=calculation();
|
|
this->get_token();
|
|
if(this_token.type==__colon)
|
|
{
|
|
abstract_syntax_tree subvec_node;
|
|
subvec_node.set_node_line(this_token.line);
|
|
subvec_node.set_node_type(__sub_vector);
|
|
subvec_node.add_children(tmp);
|
|
this->get_token();
|
|
if((this_token.type!=__comma) && (this_token.type!=__right_bracket))
|
|
{
|
|
this->push_token();
|
|
subvec_node.add_children(calculation());
|
|
}
|
|
else
|
|
this->push_token();
|
|
call_vector_node.add_children(subvec_node);
|
|
}
|
|
else if(this_token.type==__comma)
|
|
{
|
|
call_vector_node.add_children(tmp);
|
|
this->get_token();
|
|
if(this_token.type==__right_bracket)
|
|
{
|
|
++error;
|
|
print_parse_error(call_vector_wrong_comma,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
else
|
|
this->push_token();
|
|
this->push_token();// push comma
|
|
}
|
|
else if(this_token.type==__right_bracket)
|
|
{
|
|
call_vector_node.add_children(tmp);
|
|
this->push_token();// push ']'
|
|
}
|
|
else
|
|
{
|
|
++error;
|
|
print_parse_error(call_vector_wrong_token,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
this->get_token();
|
|
if((this_token.type!=__comma) && (this_token.type!=__right_bracket))
|
|
{
|
|
++error;
|
|
print_parse_error(call_vector_lack_bracket,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
}
|
|
scalar_node.add_children(call_vector_node);
|
|
}
|
|
else if(this_token.type==__dot)
|
|
{
|
|
this->get_token();
|
|
if(this_token.type!=__id)
|
|
{
|
|
++error;
|
|
print_parse_error(call_hash_lack_id,this_token.line);
|
|
break;
|
|
}
|
|
abstract_syntax_tree call_hash_node;
|
|
call_hash_node.set_node_line(this_token.line);
|
|
call_hash_node.set_node_type(__call_hash);
|
|
call_hash_node.set_var_name(this_token.str);
|
|
scalar_node.add_children(call_hash_node);
|
|
}
|
|
this->get_token();
|
|
}
|
|
// call identifier/vector/hash/function
|
|
this->push_token();
|
|
return scalar_node;
|
|
}
|
|
|
|
abstract_syntax_tree nasal_parse::hash_generate()
|
|
{
|
|
this->get_token(); // get '{'
|
|
abstract_syntax_tree hash_node;
|
|
hash_node.set_node_line(this_token.line);
|
|
hash_node.set_node_type(__hash);
|
|
this->get_token();
|
|
if(this_token.type!=__right_brace)
|
|
{
|
|
this->push_token();
|
|
while(this_token.type!=__right_brace)
|
|
{
|
|
abstract_syntax_tree hash_member_node;
|
|
this->get_token();
|
|
hash_member_node.set_node_line(this_token.line);
|
|
hash_member_node.set_node_type(__hash_member);
|
|
if(this_token.type==__id || this_token.type==__string)
|
|
{
|
|
abstract_syntax_tree member_id;
|
|
member_id.set_node_line(this_token.line);
|
|
member_id.set_node_type(__id);
|
|
member_id.set_var_name(this_token.str);
|
|
hash_member_node.add_children(member_id);
|
|
}
|
|
else
|
|
{
|
|
++error;
|
|
print_parse_error(hash_gen_lack_id,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
this->get_token();
|
|
if(this_token.type!=__colon)
|
|
{
|
|
++error;
|
|
print_parse_error(hash_gen_lack_colon,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
hash_member_node.add_children(calculation());
|
|
this->get_token();
|
|
if((this_token.type!=__comma) && (this_token.type!=__right_brace))
|
|
{
|
|
++error;
|
|
print_parse_error(hash_gen_lack_end,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
if(this_token.type==__comma)
|
|
{
|
|
this->get_token();
|
|
if(this_token.type!=__right_brace)
|
|
this->push_token();
|
|
// {name:scalar,}
|
|
}
|
|
hash_node.add_children(hash_member_node);
|
|
}
|
|
}
|
|
return hash_node;
|
|
}
|
|
|
|
abstract_syntax_tree nasal_parse::vector_generate()
|
|
{
|
|
this->get_token(); // get '['
|
|
abstract_syntax_tree vector_node;
|
|
vector_node.set_node_line(this_token.line);
|
|
vector_node.set_node_type(__vector);
|
|
this->get_token();
|
|
if(this_token.type!=__right_bracket)
|
|
{
|
|
this->push_token();
|
|
while(this_token.type!=__right_bracket)
|
|
{
|
|
vector_node.add_children(calculation());
|
|
this->get_token();
|
|
if((this_token.type!=__comma) && (this_token.type!=__right_bracket))
|
|
{
|
|
++error;
|
|
print_parse_error(vector_gen_lack_end,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
if(this_token.type==__comma)
|
|
{
|
|
this->get_token();
|
|
if(this_token.type!=__right_bracket)
|
|
this->push_token();
|
|
// [0,1,2,]
|
|
}
|
|
}
|
|
}
|
|
return vector_node;
|
|
}
|
|
|
|
abstract_syntax_tree nasal_parse::function_generate()
|
|
{
|
|
abstract_syntax_tree function_node;
|
|
abstract_syntax_tree parameter_list;
|
|
this->get_token(); // get 'func'
|
|
function_node.set_node_type(__function);
|
|
function_node.set_node_line(this_token.line);
|
|
parameter_list.set_node_type(__parameters);
|
|
parameter_list.set_node_line(this_token.line);
|
|
this->get_token();
|
|
if(this_token.type==__left_curve)
|
|
{
|
|
bool has_default_para=false;
|
|
while(this_token.type!=__right_curve)
|
|
{
|
|
// check identifier
|
|
abstract_syntax_tree parameter;
|
|
this->get_token();
|
|
int parameter_type=this_token.type;
|
|
if(this_token.type==__id)
|
|
{
|
|
parameter.set_node_line(this_token.line);
|
|
parameter.set_node_type(__id);
|
|
parameter.set_var_name(this_token.str);
|
|
}
|
|
else if(this_token.type==__dynamic_id)
|
|
{
|
|
parameter.set_node_line(this_token.line);
|
|
parameter.set_node_type(__dynamic_id);
|
|
parameter.set_var_name(this_token.str);
|
|
}
|
|
else if(this_token.type==__right_curve)
|
|
{
|
|
parameter.set_node_type(__null_type);
|
|
this->push_token();
|
|
}
|
|
else
|
|
{
|
|
++error;
|
|
print_parse_error(parameter_lack_part,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
|
|
// check equal operator
|
|
this->get_token();
|
|
if(has_default_para && this_token.type!=__equal)
|
|
{
|
|
++error;
|
|
print_parse_error(need_default_parameter,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
if(this_token.type==__equal)
|
|
{
|
|
has_default_para=true;
|
|
if(parameter_type==__id)
|
|
{
|
|
abstract_syntax_tree default_parameter;
|
|
default_parameter.set_node_line(this_token.line);
|
|
default_parameter.set_node_type(__default_parameter);
|
|
default_parameter.add_children(parameter);
|
|
default_parameter.add_children(calculation());
|
|
parameter=default_parameter;
|
|
}
|
|
else
|
|
{
|
|
++error;
|
|
print_parse_error(default_dynamic_parameter,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
this->push_token();
|
|
if(parameter.get_node_type()!=__null_type)
|
|
parameter_list.add_children(parameter);
|
|
// check comma or right_curve
|
|
this->get_token();
|
|
if((this_token.type!=__right_curve) && (this_token.type!=__comma))
|
|
{
|
|
++error;
|
|
print_parse_error(parameter_lack_curve,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
if(this_token.type==__comma)
|
|
{
|
|
this->get_token();
|
|
if(this_token.type!=__right_curve)
|
|
this->push_token();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
this->push_token();
|
|
function_node.add_children(parameter_list);
|
|
function_node.add_children(block_generate());
|
|
return function_node;
|
|
}
|
|
|
|
abstract_syntax_tree nasal_parse::return_expr()
|
|
{
|
|
abstract_syntax_tree ret_node;
|
|
this->get_token();
|
|
ret_node.set_node_line(this_token.line);
|
|
ret_node.set_node_type(__return);
|
|
this->get_token();
|
|
if((this_token.type==__sub_operator) || (this_token.type==__nor_operator) ||
|
|
(this_token.type==__number) || (this_token.type==__string) || (this_token.type==__func) ||
|
|
(this_token.type==__id) || (this_token.type==__nil) ||
|
|
(this_token.type==__left_curve) || (this_token.type==__left_brace) || (this_token.type==__left_bracket)
|
|
)
|
|
{
|
|
this->push_token();
|
|
ret_node.add_children(calculation());
|
|
}
|
|
return ret_node;
|
|
}
|
|
|
|
abstract_syntax_tree nasal_parse::definition()
|
|
{
|
|
abstract_syntax_tree definition_node;
|
|
definition_node.set_node_type(__definition);
|
|
this->get_token();// get 'var' or '('
|
|
definition_node.set_node_line(this_token.line);
|
|
if(this_token.type==__left_curve)
|
|
{
|
|
this->get_token();// get 'var'
|
|
abstract_syntax_tree multi_identifier;
|
|
multi_identifier.set_node_type(__multi_id);
|
|
multi_identifier.set_node_line(this_token.line);
|
|
while(this_token.type!=__right_curve)
|
|
{
|
|
this->get_token();
|
|
if(this_token.type!=__id)
|
|
{
|
|
++error;
|
|
print_parse_error(definition_lack_id,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
abstract_syntax_tree id_node;
|
|
id_node.set_node_line(this_token.line);
|
|
id_node.set_node_type(__id);
|
|
id_node.set_var_name(this_token.str);
|
|
multi_identifier.add_children(id_node);
|
|
}
|
|
this->get_token();
|
|
if((this_token.type!=__comma) && (this_token.type!=__right_curve))
|
|
{
|
|
this->push_token();
|
|
++error;
|
|
print_parse_error(multi_definition_need_curve,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
}
|
|
definition_node.add_children(multi_identifier);
|
|
this->get_token();
|
|
if(this_token.type==__equal)// (var id,id,id)=
|
|
{
|
|
this->get_token();
|
|
if(this_token.type==__left_curve)
|
|
{
|
|
this->push_token();
|
|
if(check_multi_scalar())
|
|
{
|
|
abstract_syntax_tree multi_scalar_node;
|
|
this->get_token();// get '('
|
|
multi_scalar_node.set_node_line(this_token.line);
|
|
multi_scalar_node.set_node_type(__multi_scalar);
|
|
while(this_token.type!=__right_curve)
|
|
{
|
|
multi_scalar_node.add_children(scalar_generate());
|
|
this->get_token();
|
|
if((this_token.type!=__comma) && (this_token.type!=__right_curve))
|
|
{
|
|
++error;
|
|
print_parse_error(multi_definition_need_curve,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
}
|
|
definition_node.add_children(multi_scalar_node);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this->push_token();
|
|
definition_node.add_children(calculation());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this->push_token();
|
|
++error;
|
|
print_parse_error(definition_lack_equal,this_token.line,this_token.type);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this->get_token();
|
|
if(this_token.type==__id)
|
|
{
|
|
abstract_syntax_tree new_var_identifier;
|
|
new_var_identifier.set_node_type(__id);
|
|
new_var_identifier.set_node_line(this_token.line);
|
|
new_var_identifier.set_var_name(this_token.str);
|
|
definition_node.add_children(new_var_identifier);
|
|
this->get_token();
|
|
if(this_token.type==__equal)
|
|
definition_node.add_children(calculation());// var id = scalar
|
|
else
|
|
{
|
|
this->push_token();
|
|
++error;
|
|
print_parse_error(definition_lack_equal,this_token.line,this_token.type);
|
|
}
|
|
}
|
|
else if(this_token.type==__left_curve)
|
|
{
|
|
abstract_syntax_tree multi_identifier;
|
|
multi_identifier.set_node_type(__multi_id);
|
|
multi_identifier.set_node_line(this_token.line);
|
|
while(this_token.type!=__right_curve)
|
|
{
|
|
this->get_token();
|
|
if(this_token.type!=__id)
|
|
{
|
|
this->push_token();
|
|
++error;
|
|
print_parse_error(definition_lack_id,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
abstract_syntax_tree id_node;
|
|
id_node.set_node_line(this_token.line);
|
|
id_node.set_node_type(__id);
|
|
id_node.set_var_name(this_token.str);
|
|
multi_identifier.add_children(id_node);
|
|
}
|
|
this->get_token();
|
|
if((this_token.type!=__comma) && (this_token.type!=__right_curve))
|
|
{
|
|
this->push_token();
|
|
++error;
|
|
print_parse_error(multi_definition_need_curve,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
}
|
|
definition_node.add_children(multi_identifier);
|
|
this->get_token();
|
|
if(this_token.type==__equal)// var (id,id,id)=
|
|
{
|
|
this->get_token();
|
|
if(this_token.type==__left_curve)
|
|
{
|
|
this->push_token();
|
|
if(check_multi_scalar())
|
|
{
|
|
abstract_syntax_tree multi_scalar_node;
|
|
this->get_token();// get '('
|
|
multi_scalar_node.set_node_line(this_token.line);
|
|
multi_scalar_node.set_node_type(__multi_scalar);
|
|
while(this_token.type!=__right_curve)
|
|
{
|
|
multi_scalar_node.add_children(scalar_generate());
|
|
this->get_token();
|
|
if((this_token.type!=__comma) && (this_token.type!=__right_curve))
|
|
{
|
|
++error;
|
|
print_parse_error(multi_definition_need_curve,this_token.line,this_token.type);
|
|
break;
|
|
}
|
|
}
|
|
definition_node.add_children(multi_scalar_node);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this->push_token();
|
|
definition_node.add_children(calculation());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this->push_token();
|
|
++error;
|
|
print_parse_error(definition_lack_equal,this_token.line,this_token.type);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this->push_token();
|
|
++error;
|
|
print_parse_error(definition_lack_id,this_token.line);
|
|
}
|
|
}
|
|
return definition_node;
|
|
}
|
|
|
|
abstract_syntax_tree nasal_parse::loop_expr()
|
|
{
|
|
abstract_syntax_tree loop_main_node;
|
|
this->get_token(); // get the first token of loop
|
|
loop_main_node.set_node_line(this_token.line);
|
|
loop_main_node.set_node_type(this_token.type);
|
|
if(this_token.type==__for)
|
|
{
|
|
this->get_token();
|
|
if(this_token.type!=__left_curve)
|
|
{
|
|
++error;
|
|
print_parse_error(lack_left_curve,this_token.line);
|
|
}
|
|
this->get_token();
|
|
if(this_token.type==__semi)
|
|
{
|
|
abstract_syntax_tree null_node;
|
|
null_node.set_node_type(__null_type);
|
|
loop_main_node.add_children(null_node);
|
|
this->push_token();
|
|
}
|
|
else
|
|
{
|
|
if(this_token.type==__var)
|
|
{
|
|
this->push_token();
|
|
loop_main_node.add_children(definition());
|
|
}
|
|
else
|
|
{
|
|
this->push_token();
|
|
// cannot use calculation() here
|
|
// because for-loop's first statement must be definition or call_identifier
|
|
loop_main_node.add_children(calculation());
|
|
}
|
|
}
|
|
this->get_token();
|
|
if(this_token.type!=__semi)
|
|
{
|
|
++error;
|
|
print_parse_error(lack_semi,this_token.line);
|
|
}
|
|
this->get_token();
|
|
if(this_token.type==__semi)
|
|
{
|
|
abstract_syntax_tree null_node;
|
|
null_node.set_node_type(__null_type);
|
|
loop_main_node.add_children(null_node);
|
|
this->push_token();
|
|
}
|
|
else
|
|
{
|
|
this->push_token();
|
|
loop_main_node.add_children(calculation());
|
|
}
|
|
this->get_token();
|
|
if(this_token.type!=__semi)
|
|
{
|
|
++error;
|
|
print_parse_error(lack_semi,this_token.line);
|
|
}
|
|
this->get_token();
|
|
if(this_token.type==__right_curve)
|
|
{
|
|
abstract_syntax_tree null_node;
|
|
null_node.set_node_type(__null_type);
|
|
loop_main_node.add_children(null_node);
|
|
this->push_token();
|
|
}
|
|
else
|
|
{
|
|
this->push_token();
|
|
loop_main_node.add_children(calculation());
|
|
}
|
|
this->get_token();
|
|
if(this_token.type!=__right_curve)
|
|
{
|
|
++error;
|
|
print_parse_error(lack_right_curve,this_token.line);
|
|
}
|
|
}
|
|
else if(this_token.type==__while)
|
|
{
|
|
this->get_token();
|
|
if(this_token.type!=__left_curve)
|
|
{
|
|
++error;
|
|
print_parse_error(lack_left_curve,this_token.line,this_token.type);
|
|
}
|
|
loop_main_node.add_children(calculation());
|
|
this->get_token();
|
|
if(this_token.type!=__right_curve)
|
|
{
|
|
++error;
|
|
print_parse_error(lack_right_curve,this_token.line,this_token.type);
|
|
}
|
|
}
|
|
else if(this_token.type==__forindex || this_token.type==__foreach)
|
|
{
|
|
this->get_token();// '('
|
|
if(this_token.type!=__left_curve)
|
|
{
|
|
++error;
|
|
print_parse_error(lack_left_curve,this_token.line,this_token.type);
|
|
}
|
|
this->get_token();// 'var'
|
|
if(this_token.type!=__var)
|
|
{
|
|
// if checked not the 'var' then checking if this token is an identifier
|
|
if(this_token.type!=__id)
|
|
{
|
|
++error;
|
|
print_parse_error(lack_id,this_token.line);
|
|
}
|
|
else
|
|
{
|
|
this->push_token();
|
|
loop_main_node.add_children(scalar_generate());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
abstract_syntax_tree new_definition_node;
|
|
new_definition_node.set_node_line(this_token.line);
|
|
new_definition_node.set_node_type(__definition);
|
|
this->get_token();
|
|
if(this_token.type!=__id)
|
|
{
|
|
++error;
|
|
print_parse_error(lack_id,this_token.line);
|
|
}
|
|
else
|
|
{
|
|
abstract_syntax_tree new_id_node;
|
|
new_id_node.set_node_line(this_token.line);
|
|
new_id_node.set_node_type(__id);
|
|
new_id_node.set_var_name(this_token.str);
|
|
new_definition_node.add_children(new_id_node);
|
|
}
|
|
loop_main_node.add_children(new_definition_node);
|
|
}
|
|
this->get_token();// ';'
|
|
if(this_token.type!=__semi)
|
|
{
|
|
++error;
|
|
print_parse_error(lack_semi,this_token.line);
|
|
}
|
|
loop_main_node.add_children(scalar_generate());// get hash/vector or keys(hash/vector)
|
|
this->get_token();
|
|
if(this_token.type!=__right_curve)
|
|
{
|
|
++error;
|
|
print_parse_error(lack_right_curve,this_token.line,this_token.type);
|
|
}
|
|
}
|
|
loop_main_node.add_children(block_generate());
|
|
return loop_main_node;
|
|
}
|
|
|
|
abstract_syntax_tree nasal_parse::conditional_expr()
|
|
{
|
|
abstract_syntax_tree conditional_main_node;
|
|
abstract_syntax_tree if_node;
|
|
abstract_syntax_tree elsif_node;
|
|
abstract_syntax_tree else_node;
|
|
conditional_main_node.set_node_type(__conditional);
|
|
// get 'if'
|
|
this->get_token();
|
|
conditional_main_node.set_node_line(this_token.line);
|
|
if_node.set_node_type(__if);
|
|
if_node.set_node_line(this_token.line);
|
|
this->get_token();
|
|
if(this_token.type!=__left_curve)
|
|
{
|
|
++error;
|
|
print_parse_error(lack_left_curve,this_token.line);
|
|
}
|
|
if_node.add_children(calculation());
|
|
this->get_token();
|
|
if(this_token.type!=__right_curve)
|
|
{
|
|
++error;
|
|
print_parse_error(lack_right_curve,this_token.line);
|
|
}
|
|
if_node.add_children(block_generate());
|
|
conditional_main_node.add_children(if_node);
|
|
// add statements
|
|
this->get_token();
|
|
if(this_token.type==__elsif)
|
|
{
|
|
while(this_token.type==__elsif)
|
|
{
|
|
elsif_node.set_clear();
|
|
elsif_node.set_node_line(this_token.line);
|
|
elsif_node.set_node_type(__elsif);
|
|
|
|
this->get_token();
|
|
if(this_token.type!=__left_curve)
|
|
{
|
|
++error;
|
|
print_parse_error(lack_left_curve,this_token.line,this_token.type);
|
|
}
|
|
elsif_node.add_children(calculation());
|
|
this->get_token();
|
|
if(this_token.type!=__right_curve)
|
|
{
|
|
++error;
|
|
print_parse_error(lack_right_curve,this_token.line,this_token.type);
|
|
}
|
|
elsif_node.add_children(block_generate());
|
|
conditional_main_node.add_children(elsif_node);
|
|
this->get_token();// get next 'elsif' if it exists
|
|
}
|
|
this->push_token();
|
|
}
|
|
else
|
|
this->push_token();
|
|
this->get_token();
|
|
if(this_token.type==__else)
|
|
{
|
|
else_node.set_node_line(this_token.type);
|
|
else_node.set_node_type(__else);
|
|
else_node.add_children(block_generate());
|
|
conditional_main_node.add_children(else_node);
|
|
}
|
|
else
|
|
this->push_token();
|
|
// get elsif or else
|
|
return conditional_main_node;
|
|
}
|
|
#endif
|