This commit is contained in:
Valk Richard Li 2020-03-30 21:06:13 +08:00 committed by GitHub
parent a723b878f0
commit ca01383272
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 278 additions and 160 deletions

View File

@ -41,7 +41,7 @@
including a class named nasal_lexer including a class named nasal_lexer
including a string[] named lib_filename, by this way resource_file can load lib files including a string[] named lib_filename, by this way resource_file can load lib files
including a string[] named reserve_word, it is used in lexer,when generating an identifier,nasal_lexer will check if it is a reserve word including a string[] named reserve_word, it is used in lexer,when generating an identifier,nasal_lexer will check if it is a reserve word
including a struct named token, this struct is often used in nasal_lexer including a struct named token, this struct is often used in nasal_lexer and nasal_parse
including a function named is_reserve_word, checking if an identifier is a reserve word including a function named is_reserve_word, checking if an identifier is a reserve word
*/ */
#include "nasal_lexer.h" #include "nasal_lexer.h"

View File

@ -4,14 +4,21 @@
class abstract_syntax_tree class abstract_syntax_tree
{ {
private: private:
// basic elements /*
basic elements of ast node:
line: this marks the generated node's line in source code
node_type: this marks the node type
children: store the children of this node
*/
int line; int line;
int node_type; int node_type;
std::list<abstract_syntax_tree> children; std::list<abstract_syntax_tree> children;
// is this node is a number|string|identifier node /*
// then the three elements below is of great use var_number is used when the node_type is __number
// var_name is set for __id var_string is used when the node_type is __string
var_name is used when the node_type is __id, __dynamic_id, call_hash
*/
double var_number; double var_number;
std::string var_string; std::string var_string;
std::string var_name; std::string var_name;
@ -23,11 +30,22 @@ class abstract_syntax_tree
abstract_syntax_tree& operator=(const abstract_syntax_tree&); abstract_syntax_tree& operator=(const abstract_syntax_tree&);
/* main functions */ /* main functions */
// print /*
print_tree is the entrance of print function
print_tree will print the root address and call print_tree_block(1)
print_tree_block will print the information of each node by using DFS
*/
void print_tree(); void print_tree();
void print_tree_block(const int); void print_tree_block(const int);
// set /*
set_clear : clear all the elements in ast node
set_node_line : set the private:line
set_node_type : set the private:node_type
set_var_number: set the private:var_number
set_var_string: set the private:var_string
set_var_name : set the private:var_name
*/
void set_clear(); void set_clear();
void set_node_line(const int); void set_node_line(const int);
void set_node_type(const int); void set_node_type(const int);
@ -36,7 +54,13 @@ class abstract_syntax_tree
void set_var_name(std::string); void set_var_name(std::string);
void add_children(abstract_syntax_tree); void add_children(abstract_syntax_tree);
// get /*
get_node_line : get the private:line
get_node_type : get the private:node_type
get_var_number: get private:var_number
get_var_string: get private:var_string
get_var_name : get private:var_name
*/
int get_node_line(); int get_node_line();
int get_node_type(); int get_node_type();
double get_var_number(); double get_var_number();
@ -44,7 +68,10 @@ class abstract_syntax_tree
std::string get_var_name(); std::string get_var_name();
std::list<abstract_syntax_tree>& get_children(); std::list<abstract_syntax_tree>& get_children();
// merge /*
merge children of another ast into this one
used to link lib ast and source codes' ast together
*/
void merge_children(abstract_syntax_tree&); void merge_children(abstract_syntax_tree&);
}; };

View File

@ -1,6 +1,8 @@
#ifndef __NASAL_ENUM_H__ #ifndef __NASAL_ENUM_H__
#define __NASAL_ENUM_H__ #define __NASAL_ENUM_H__
// lexer token type is only used in nasal_lexer
// each scanned token will be recognized as one of these below
enum lexer_token_type enum lexer_token_type
{ {
__token_reserve_word=1, __token_reserve_word=1,
@ -25,29 +27,42 @@ void print_lexer_token(int type)
// parse_gen_type include enums for parser and ast // parse_gen_type include enums for parser and ast
enum parse_gen_type enum parse_gen_type
{ {
/*
stack end is an important flag for parse token stack to
check if it's stack is at end
if stack is empty,the parser will get a wrong memory space and cause SIGSEGV
*/
__stack_end=1, __stack_end=1,
// operators == != < <= > >=
// operators __cmp_equal,
__cmp_equal,__cmp_not_equal,__cmp_less,__cmp_less_or_equal,__cmp_more,__cmp_more_or_equal, __cmp_not_equal,
// == != < <= > >= __cmp_less,__cmp_less_or_equal,
__and_operator,__or_operator,__nor_operator,__add_operator,__sub_operator,__mul_operator,__div_operator,__link_operator, __cmp_more,__cmp_more_or_equal,
// and or ! + - * / ~ // operators and or ! + - * / ~
__equal,__add_equal,__sub_equal,__mul_equal,__div_equal,__link_equal, __and_operator, __or_operator,__nor_operator,
// = += -= *= /= ~= __add_operator,__sub_operator,
__mul_operator,__div_operator,__link_operator,
// operators = += -= *= /= ~=
__equal,
__add_equal,__sub_equal,
__mul_equal,__div_equal,__link_equal,
// operators {} [] () ; , : . ?
__left_brace,__right_brace, // {} __left_brace,__right_brace, // {}
__left_bracket,__right_bracket, // [] __left_bracket,__right_bracket, // []
__left_curve,__right_curve, // () __left_curve,__right_curve, // ()
__semi,__comma,__colon,__dot,__ques_mark, // ; , : . ? __semi,__comma,__colon,__dot,__ques_mark, // ; , : . ?
__unknown_operator, __unknown_operator,
// reserve words // reserve words
__var,__func,__return,__nil, __var,
__func,__return,__nil,
__if,__elsif,__else, __if,__elsif,__else,
__continue,__break, __continue,__break,
__for,__forindex,__foreach,__while, __for,__forindex,__foreach,__while,
// basic scalar type: number string identifier dynamic_identifier // basic scalar type: number string
__number,__string,__id,__dynamic_id, __number,__string,
// basic identifier type: identifier dynamic_identifier
__id,__dynamic_id,
// abstract_syntax_tree type below // abstract_syntax_tree type below
// abstract_syntax_tree also uses the types above, such as operators // abstract_syntax_tree also uses the types above, such as operators
@ -62,6 +77,7 @@ enum parse_gen_type
__definition, __definition,
__conditional __conditional
}; };
// print tokens that used in nasal_parse
void print_parse_token(int type) void print_parse_token(int type)
{ {
std::string context=""; std::string context="";
@ -130,6 +146,7 @@ void print_parse_token(int type)
std::cout<<context; std::cout<<context;
return; return;
} }
// print node types that used in abstract_syntax_tree
void print_ast_type(int type) void print_ast_type(int type)
{ {
std::string context=""; std::string context="";
@ -204,6 +221,7 @@ void print_ast_type(int type)
return; return;
} }
// basic scalar type used in nasal_runtime and nasal_gc
enum scalar_type enum scalar_type
{ {
scalar_nil=0, scalar_nil=0,
@ -213,6 +231,7 @@ enum scalar_type
scalar_hash, scalar_hash,
scalar_function scalar_function
}; };
// print types that used in nasal_runtime and nasal_gc
void print_scalar_type(const int type) void print_scalar_type(const int type)
{ {
switch(type) switch(type)

View File

@ -4,12 +4,12 @@
/* /*
__token_reserve_word: __token_reserve_word:
for,foreach,forindex,while : loop for,foreach,forindex,while : loop
var,func : definition var,func : definition
break,continue : in loop break,continue : in loop
return : in function return : in function
if,else,elsif : if-else statement if,else,elsif : conditional expr
and,or : calculation and,or : calculation
nil : special type nil : special type
__token_identifier: __token_identifier:
must begin with '_' or 'a'~'z' or 'A'~'Z' must begin with '_' or 'a'~'z' or 'A'~'Z'
can include '_' or 'a'~'z' or 'A'~'Z' or '0'~'9' can include '_' or 'a'~'z' or 'A'~'Z' or '0'~'9'
@ -27,11 +27,13 @@
__token_operator: __token_operator:
! + - * / ~ ! + - * / ~
= += -= *= /= ~= = += -= *= /= ~=
== != > >= < <= ('and' 'or' are operators too but they are recognized as operator in generate_detail_token()) == != > >= < <=
('and' 'or' are operators too but they are recognized as operator in generate_detail_token())
() [] {} ; , . : ? () [] {} ; , . : ?
others: __unknown_operator others: __unknown_operator
*/ */
/* filenames of lib files */
const std::string lib_filename[10]= const std::string lib_filename[10]=
{ {
"lib/base.nas", "lib/base.nas",
@ -45,14 +47,14 @@ const std::string lib_filename[10]=
"lib/unix.nas", "lib/unix.nas",
"lib/utf8.nas" "lib/utf8.nas"
}; };
/* reserve words */
std::string reserve_word[15]= std::string reserve_word[15]=
{ {
"for","foreach","forindex","while", "for","foreach","forindex","while",
"var","func","break","continue","return", "var","func","break","continue","return",
"if","else","elsif","and","or","nil" "if","else","elsif","and","or","nil"
}; };
/* check if an identifier is a reserve word */
int is_reserve_word(std::string str) int is_reserve_word(std::string str)
{ {
for(int i=0;i<15;++i) for(int i=0;i<15;++i)
@ -67,13 +69,11 @@ class resource_file
std::list<char> resource; std::list<char> resource;
public: public:
/* /*
resource_file(); delete_all_source: clear all the source codes in std::list<char> resource
~resource_file(); input_file : input source codes by filenames
void delete_all_source(); load_lib_file : input lib source codes
void input_file(std::string); get_source : get the std::list<char> resource
void load_lib_file(); print_resource : print source codes
std::list<char>& get_source();
void print_resource();
*/ */
resource_file() resource_file()
{ {
@ -157,7 +157,7 @@ class resource_file
return; return;
} }
}; };
/* struct token: mainly used in nasal_lexer and nasal_parse*/
struct token struct token
{ {
int line; int line;
@ -178,25 +178,27 @@ class nasal_lexer
std::list<token> token_list; std::list<token> token_list;
std::list<token> detail_token_list; std::list<token> detail_token_list;
int error; int error;
// change utf8 codes into '?'
// this function will be deleted if there is a way to print utf8 codes out correctly
std::string utf8_clear(std::string tmp) std::string utf8_clear(std::string tmp)
{ {
/* /*
0xxx xxxx 0x0 1 byte 0xxx xxxx 0x0 1 byte
110x xxxx 0xc0 2 byte 110x xxxx 0xc0 2 byte
1110 xxxx 0xe0 3 byte 1110 xxxx 0xe0 3 byte
1111 0xxx 0xf0 4 byte 1111 0xxx 0xf0 4 byte
1111 10xx 0xf8 5 byte 1111 10xx 0xf8 5 byte
1111 110x 0xfc 6 byte 1111 110x 0xfc 6 byte
bytes after it is: bytes after it is:
10xx xxxx 0x80 10xx xxxx 0x80
so utf-8 format is: so utf-8 format is:
0xxxxxxx 0xxxxxxx
110xxxxx 10xxxxxx 110xxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx 1110xxxx 10xxxxxx 10xxxxxx
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
*/ */
unsigned char utf8head[6]={0x0,0xc0,0xe0,0xf0,0xf8,0xfc}; unsigned char utf8head[6]={0x0,0xc0,0xe0,0xf0,0xf8,0xfc};
std::string ret=""; std::string ret="";
@ -222,13 +224,11 @@ class nasal_lexer
} }
public: public:
/* /*
nasal_lexer(); print_token_list : print generated token list
~nasal_lexer(); scanner : scan the source codes and generate tokens
void print_token_list(); generate_detail_token: recognize and change token types to detailed types that can be processed by nasal_parse
void scanner(std::list<char>&); get_error : get the number of errors that occurred when generating tokens
void generate_detail_token(); get_detail_token : output the detailed tokens,must be used after generate_detail_token()
int get_error();
std::list<token>& get_detail_token();
*/ */
nasal_lexer() nasal_lexer()
{ {

View File

@ -1,6 +1,18 @@
#ifndef __NASAL_MISC_H__ #ifndef __NASAL_MISC_H__
#define __NASAL_MISC_H__ #define __NASAL_MISC_H__
/*
check_numerable_string:
check if a string can be converted to a number
strings like these below is correct:
'0.00012'
'12314.234'
'1234'
'0xdeadbeef'
'0xDEADBEEF'
'0o71230'
*/
bool check_numerable_string(std::string str) bool check_numerable_string(std::string str)
{ {
if(str.length()>1 && str[0]=='-') if(str.length()>1 && str[0]=='-')
@ -49,6 +61,10 @@ bool check_numerable_string(std::string str)
return false; return false;
} }
/*
trans_string_to_number:
convert string to number
*/
double trans_string_to_number(std::string str) double trans_string_to_number(std::string str)
{ {
bool is_negative=false; bool is_negative=false;
@ -120,6 +136,10 @@ double trans_string_to_number(std::string str)
return trans_str_number; return trans_str_number;
} }
/*
trans_number_to_string:
convert number to string
*/
std::string trans_number_to_string(double number) std::string trans_number_to_string(double number)
{ {
std::string trans_num_string=""; std::string trans_num_string="";
@ -149,9 +169,12 @@ std::string trans_number_to_string(double number)
return trans_num_string; return trans_num_string;
} }
/*
prt_hex:
transform int to hex format and print it out (std::cout)
*/
void prt_hex(const int ptr) void prt_hex(const int ptr)
{ {
// transform int to hex and print it (std::cout)
char hex[9]; char hex[9];
hex[8]=0; hex[8]=0;
int tmp_plc=ptr; int tmp_plc=ptr;
@ -162,6 +185,26 @@ void prt_hex(const int ptr)
} }
else else
std::cout<<"0x"; std::cout<<"0x";
/*
int: 00000000 00000000 00000000 00000000
int: 0x00 00 00 00
example:
a=0x13 57 9b df
a=00010011 01010111 10011011 11011111
a & 0x00 00 00 0f:
00010011 01010111 10011011 11011111
and 00000000 00000000 00000000 00001111
---------------------------------------
00000000 00000000 00000000 00001111
a>>=4:
00000001 00110101 01111001 10111101
a & 0x00 00 00 0f
00000001 00110101 01111001 10111101
and 00000000 00000000 00000000 00001111
---------------------------------------
00000000 00000000 00000000 00001101
then convert 0~15 to 0~9 a~f
*/
for(int j=7;j>=0;--j) for(int j=7;j>=0;--j)
{ {
int tmp=(tmp_plc & 0x0000000f); int tmp=(tmp_plc & 0x0000000f);

View File

@ -4,11 +4,19 @@
class nasal_parse class nasal_parse
{ {
private: 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> parse_token_stream;
std::stack<token> checked_tokens; std::stack<token> checked_tokens;
token this_token; token this_token;
int error; int error;
abstract_syntax_tree root; abstract_syntax_tree root;
/* parsse_error_type: used in print_parse_error,including all types of errors*/
enum parse_error_type enum parse_error_type
{ {
parse_unknown_error=0, // unknown error parse_unknown_error=0, // unknown error
@ -52,33 +60,36 @@ class nasal_parse
ternary_operator_lack_colon, // lack ':' ternary_operator_lack_colon, // lack ':'
}; };
/* print the error type and it's line*/
void print_parse_error(int,int,int); void print_parse_error(int,int,int);
// most important function of parser /*
// these two functions are used to get and push token get_token and push_token are most important functions of parser
// by using them,parser can generate ast these two functions are used to get and push token
and the result will be stored in this_token
*/
void get_token(); void get_token();
void push_token(); void push_token();
// block statements generation /* block statements generation */
abstract_syntax_tree block_generate(); abstract_syntax_tree block_generate();
// check ';' // check ';'
void check_semi(); void check_semi();
// check '(' confliction /* check '(' confliction */
bool check_multi_assignment();// check multi_call_id '=' multi_scalar bool check_multi_assignment(); // check multi_call_id '=' multi_scalar
bool check_multi_scalar(); // check multi_scalar bool check_multi_scalar(); // check multi_scalar
bool check_var_in_curve(); // check multi_definition: (var id,id,id) 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 bool check_function_end(abstract_syntax_tree&); // check end of definition or '=' is a function
/* /*
calculation() will get elements generated by and_calculation() calculation : will get elements generated by and_calculation()
and_calculation() will get elements generated by or_calculation() and_calculation : will get elements generated by or_calculation()
or_calculation() will get elements generated by cmp_calculation() or_calculation : will get elements generated by cmp_calculation()
cmp_calculation() will get elements generated by additive_calculation() cmp_calculation : will get elements generated by additive_calculation()
additive_calculation() will get elements generated by multive_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() multive_calculation : will get elements generated by assign_calculation()(assignment <call_id> '=' <calculation>) and scalar_generate()
assign_calculation() get elements from scalar_generate() assign_calculation : get elements from scalar_generate()
please notice that: please notice that:
if the elements begin with '!' or '-',multive_calculation() gets them from scalar_generate() if the elements begin with '!' or '-',multive_calculation() gets them from scalar_generate()
if not,multive_calculation() gets them from assign_calculation() if not,multive_calculation() gets them from assign_calculation()
because '!' and '-' cannot be used with assignment together such as: -a=1 because '!' and '-' cannot be used with assignment together such as: -a=1
*/ */
abstract_syntax_tree calculation(); abstract_syntax_tree calculation();
abstract_syntax_tree and_calculation(); abstract_syntax_tree and_calculation();
@ -87,13 +98,13 @@ class nasal_parse
abstract_syntax_tree additive_calculation(); abstract_syntax_tree additive_calculation();
abstract_syntax_tree multive_calculation(); abstract_syntax_tree multive_calculation();
abstract_syntax_tree scalar_generate(); abstract_syntax_tree scalar_generate();
// normal data type generation /* normal data type generation */
abstract_syntax_tree hash_generate(); abstract_syntax_tree hash_generate();
abstract_syntax_tree vector_generate(); abstract_syntax_tree vector_generate();
abstract_syntax_tree function_generate(); abstract_syntax_tree function_generate();
// return_expr() generates ebnf: <return> [<calculation>] ';' /* return_expr() generates ebnf: <return> [<calculation>] ';' */
abstract_syntax_tree return_expr(); abstract_syntax_tree return_expr();
// normal expressions /* normal expressions */
abstract_syntax_tree multi_scalar_assignment(); abstract_syntax_tree multi_scalar_assignment();
abstract_syntax_tree definition(); abstract_syntax_tree definition();
abstract_syntax_tree loop_expr(); abstract_syntax_tree loop_expr();
@ -102,7 +113,7 @@ class nasal_parse
// basic functions // basic functions
void delete_all_elements() void delete_all_elements()
{ {
// used in 'del' command // used in 'del' command in main()
while(!parse_token_stream.empty()) while(!parse_token_stream.empty())
parse_token_stream.pop(); parse_token_stream.pop();
while(!checked_tokens.empty()) while(!checked_tokens.empty())
@ -114,8 +125,7 @@ class nasal_parse
void get_token_list(std::list<token>&); void get_token_list(std::list<token>&);
int get_error(); int get_error();
abstract_syntax_tree& get_root(); abstract_syntax_tree& get_root();
// abstract_syntax_tree generation /* main process of parser */
// main process of parser
void main_generate(); void main_generate();
}; };
@ -126,6 +136,7 @@ void nasal_parse::print_detail_token()
std::stack<token> tmp=parse_token_stream; std::stack<token> tmp=parse_token_stream;
// indent // indent
std::string indent=""; std::string indent="";
int brace_cnt=0;
int line=1; int line=1;
std::cout<<line<<"\t"; std::cout<<line<<"\t";
while((!tmp.empty()) && (tmp.top().type!=__stack_end)) while((!tmp.empty()) && (tmp.top().type!=__stack_end))
@ -133,6 +144,7 @@ void nasal_parse::print_detail_token()
if(tmp.top().line!=line) if(tmp.top().line!=line)
{ {
// if line changes,print '\n' and number of 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) for(int i=line+1;i<tmp.top().line;++i)
std::cout<<std::endl<<i<<"\t"; std::cout<<std::endl<<i<<"\t";
line=tmp.top().line; line=tmp.top().line;
@ -140,9 +152,14 @@ void nasal_parse::print_detail_token()
} }
print_parse_token(tmp.top().type); print_parse_token(tmp.top().type);
if(tmp.top().type==__left_brace) if(tmp.top().type==__left_brace)
{
++brace_cnt;
indent+=' '; indent+=' ';
}
else if(tmp.top().type==__right_brace)
--brace_cnt;
tmp.pop(); tmp.pop();
if((!tmp.empty()) && (tmp.top().type==__right_brace)) if((!tmp.empty()) && (tmp.top().type==__right_brace) && brace_cnt>=1)
indent.pop_back(); indent.pop_back();
} }
std::cout<<std::endl; std::cout<<std::endl;
@ -394,8 +411,7 @@ bool nasal_parse::check_multi_assignment()
this->get_token(); this->get_token();
++cnt; ++cnt;
// these determine statements are used with curve_cnt,bracket_cnt and brace_cnt together // these determine statements are used with curve_cnt,bracket_cnt and brace_cnt together
// to avoid checking commas in other curves/brackets/braces // to avoid checking commas in other curves/brackets/braces such as ([0,1,2,3])
// such as ([0,1,2,3])
// but in multi_assignment, only things like (id[scalar],id.id[scalar]) can be recognized as multi_scalar // 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 // 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 // but in fact ([0,1,2,3]) is not
@ -406,13 +422,16 @@ bool nasal_parse::check_multi_assignment()
if(this_token.type==__right_bracket)--bracket_cnt; if(this_token.type==__right_bracket)--bracket_cnt;
if(this_token.type==__right_brace) --brace_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) if(!curve_cnt && !bracket_cnt && !brace_cnt && this_token.type==__comma)
{ {
ret=true; ret=true;
break; break;
} }
if(!curve_cnt && !bracket_cnt && brace_cnt<0) // error occurred
if(curve_cnt<0 || brace_cnt<0 || brace_cnt<0)
break; break;
// exit when meeting stack end
if((!parse_token_stream.empty() && parse_token_stream.top().type==__stack_end) || (this_token.type==__semi)) if((!parse_token_stream.empty() && parse_token_stream.top().type==__stack_end) || (this_token.type==__semi))
break; break;
} }
@ -446,13 +465,16 @@ bool nasal_parse::check_multi_scalar()
if(this_token.type==__right_bracket)--bracket_cnt; if(this_token.type==__right_bracket)--bracket_cnt;
if(this_token.type==__right_brace) --brace_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) if(!curve_cnt && !bracket_cnt && !brace_cnt && this_token.type==__comma)
{ {
ret=true; ret=true;
break; break;
} }
if(!curve_cnt && !bracket_cnt && brace_cnt<0) // error occurred
if(curve_cnt<0 || brace_cnt<0 || brace_cnt<0)
break; break;
// exit when meeting stack end
if((!parse_token_stream.empty() && parse_token_stream.top().type==__stack_end) || (this_token.type==__semi)) if((!parse_token_stream.empty() && parse_token_stream.top().type==__stack_end) || (this_token.type==__semi))
break; break;
} }
@ -575,8 +597,7 @@ abstract_syntax_tree nasal_parse::block_generate()
block_node.set_node_type(__normal_statement_block); block_node.set_node_type(__normal_statement_block);
if(this_token.type!=__left_brace) if(this_token.type!=__left_brace)
{ {
// only one statement // only one statement, so this doesn't need check_semi()
// so this doesn't need check_semi()
switch(this_token.type) switch(this_token.type)
{ {
case __var: case __var:
@ -629,6 +650,8 @@ abstract_syntax_tree nasal_parse::block_generate()
print_parse_error(error_token_in_block,this_token.line,this_token.type); print_parse_error(error_token_in_block,this_token.line,this_token.type);
break; 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(); this->get_token();
if(this_token.type!=__semi) if(this_token.type!=__semi)
this->push_token(); this->push_token();
@ -702,8 +725,8 @@ abstract_syntax_tree nasal_parse::block_generate()
print_parse_error(error_token_in_block,this_token.line,this_token.type); print_parse_error(error_token_in_block,this_token.line,this_token.type);
break; break;
} }
// why the last statement can avoid semi check()? // the last statement can avoid semi check althought need_semi_check is true
// see more details in function: check_semi() // because check_semi will scan the next token,if this token is '}',then semi_check can be avoided
if(need_semi_check) if(need_semi_check)
check_semi(); check_semi();
this->get_token(); this->get_token();

View File

@ -82,6 +82,7 @@ class nasal_runtime
__special_call_vector_too_large_value, __special_call_vector_too_large_value,
__normal_call_vector_too_large_value, __normal_call_vector_too_large_value,
__function_returned_value_be_assigned, __function_returned_value_be_assigned,
__subvec_value_be_assigned,
__call_function_lack_para, __call_function_lack_para,
__forindex_foreach_not_vector, __forindex_foreach_not_vector,
__break_not_used_in_loop, __break_not_used_in_loop,
@ -165,7 +166,9 @@ void nasal_runtime::error_interrupt(const int type,const int line)
case __normal_call_vector_too_large_value: case __normal_call_vector_too_large_value:
std::cout<<"the number used to call the vector is too large(over 0x7fffffff)."<<std::endl;break; std::cout<<"the number used to call the vector is too large(over 0x7fffffff)."<<std::endl;break;
case __function_returned_value_be_assigned: case __function_returned_value_be_assigned:
std::cout<<"cannot assigned a value that function returns."<<std::endl;break; std::cout<<"cannot assign a value that function returns."<<std::endl;break;
case __subvec_value_be_assigned:
std::cout<<"cannot assign a subvec value."<<std::endl;break;
case __call_function_lack_para: case __call_function_lack_para:
std::cout<<"lack parameter(s) when calling a function."<<std::endl;break; std::cout<<"lack parameter(s) when calling a function."<<std::endl;break;
case __forindex_foreach_not_vector: case __forindex_foreach_not_vector:
@ -1863,8 +1866,7 @@ int nasal_runtime::assignment(std::list<std::map<std::string,int> >& local_scope
assigned_addr=&((*iter)[tmp_id_name]); assigned_addr=&((*iter)[tmp_id_name]);
if(!assigned_addr) if(!assigned_addr)
return -1; return -1;
int assigned_value_addr=*assigned_addr; std::vector<int> tmp_subvec_addr;
nasal_gc.reference_add(*assigned_addr);
for(std::list<abstract_syntax_tree>::iterator iter=node.get_children().begin();iter!=node.get_children().end();++iter) for(std::list<abstract_syntax_tree>::iterator iter=node.get_children().begin();iter!=node.get_children().end();++iter)
{ {
// call vector/special call hash/subvec // call vector/special call hash/subvec
@ -1872,7 +1874,7 @@ int nasal_runtime::assignment(std::list<std::map<std::string,int> >& local_scope
if(iter->get_node_type()==__call_vector) if(iter->get_node_type()==__call_vector)
{ {
// check the scalar type of called identifier here // check the scalar type of called identifier here
int called_type=nasal_gc.get_scalar(assigned_value_addr).get_type(); int called_type=nasal_gc.get_scalar(*assigned_addr).get_type();
if(called_type!=scalar_vector && called_type!=scalar_hash) if(called_type!=scalar_vector && called_type!=scalar_hash)
{ {
error_interrupt(__error_value_type,iter->get_node_line()); error_interrupt(__error_value_type,iter->get_node_line());
@ -1971,7 +1973,7 @@ int nasal_runtime::assignment(std::list<std::map<std::string,int> >& local_scope
int begin_num=(int)nasal_gc.get_scalar(num1_addr).get_number().get_number(); int begin_num=(int)nasal_gc.get_scalar(num1_addr).get_number().get_number();
int end_num=0; int end_num=0;
if(num2_addr<0 || nasal_gc.get_scalar(num2_addr).get_type()==scalar_nil) if(num2_addr<0 || nasal_gc.get_scalar(num2_addr).get_type()==scalar_nil)
end_num=nasal_gc.get_scalar(assigned_value_addr).get_vector().get_size(); end_num=nasal_gc.get_scalar(*assigned_addr).get_vector().get_size();
else else
end_num=(int)nasal_gc.get_scalar(num2_addr).get_number().get_number(); end_num=(int)nasal_gc.get_scalar(num2_addr).get_number().get_number();
if(num1_addr>=0) if(num1_addr>=0)
@ -1982,7 +1984,7 @@ int nasal_runtime::assignment(std::list<std::map<std::string,int> >& local_scope
for(int i=begin_num;i<end_num;++i) for(int i=begin_num;i<end_num;++i)
{ {
// addr used here // addr used here
int tmp_data_addr=nasal_gc.get_scalar(assigned_value_addr).get_vector().get_elem(i); int tmp_data_addr=nasal_gc.get_scalar(*assigned_addr).get_vector().get_elem(i);
int new_addr=-1; int new_addr=-1;
if(tmp_data_addr<0) if(tmp_data_addr<0)
{ {
@ -2019,12 +2021,11 @@ int nasal_runtime::assignment(std::list<std::map<std::string,int> >& local_scope
nasal_gc.reference_delete(tmp_data_addr); nasal_gc.reference_delete(tmp_data_addr);
subvec_result.push_back(new_addr); subvec_result.push_back(new_addr);
} }
int tmp_addr=assigned_value_addr; int tmp_addr=nasal_gc.gc_alloc();
assigned_value_addr=nasal_gc.gc_alloc(); nasal_gc.get_scalar(tmp_addr).set_type(scalar_vector);
nasal_gc.get_scalar(assigned_value_addr).set_type(scalar_vector);
for(int i=0;i<subvec_result.size();++i) for(int i=0;i<subvec_result.size();++i)
nasal_gc.get_scalar(assigned_value_addr).get_vector().vec_push(subvec_result[i]); nasal_gc.get_scalar(tmp_addr).get_vector().vec_push(subvec_result[i]);
nasal_gc.reference_delete(tmp_addr); tmp_subvec_addr.push_back(tmp_addr);
assigned_addr=NULL; assigned_addr=NULL;
}// end sub-vector }// end sub-vector
else else
@ -2058,16 +2059,12 @@ int nasal_runtime::assignment(std::list<std::map<std::string,int> >& local_scope
error_interrupt(__normal_call_vector_too_large_value,iter->get_children().front().get_node_line()); error_interrupt(__normal_call_vector_too_large_value,iter->get_children().front().get_node_line());
return -1; return -1;
} }
int tmp_addr=assigned_value_addr; assigned_addr=nasal_gc.get_scalar(*assigned_addr).get_vector().get_elem_addr((int)place_num);
assigned_addr=nasal_gc.get_scalar(tmp_addr).get_vector().get_elem_addr((int)place_num);
if(!assigned_addr) if(!assigned_addr)
{ {
error_interrupt(__invalid_vector_member,iter->get_children().front().get_children().front().get_node_line()); error_interrupt(__invalid_vector_member,iter->get_children().front().get_children().front().get_node_line());
return -1; return -1;
} }
assigned_value_addr=*assigned_addr;
nasal_gc.reference_add(assigned_value_addr);
nasal_gc.reference_delete(tmp_addr);
} }
else if(called_type==scalar_hash) else if(called_type==scalar_hash)
{ {
@ -2076,16 +2073,12 @@ int nasal_runtime::assignment(std::list<std::map<std::string,int> >& local_scope
error_interrupt(__error_value_type_when_calling_hash,iter->get_children().front().get_node_line()); error_interrupt(__error_value_type_when_calling_hash,iter->get_children().front().get_node_line());
return -1; return -1;
} }
int tmp_addr=assigned_value_addr; assigned_addr=nasal_gc.get_scalar(*assigned_addr).get_hash().get_hash_member_addr(nasal_gc.get_scalar(data_addr).get_string().get_string());
assigned_addr=nasal_gc.get_scalar(tmp_addr).get_hash().get_hash_member_addr(nasal_gc.get_scalar(data_addr).get_string().get_string());
if(!assigned_addr) if(!assigned_addr)
{ {
error_interrupt(__invalid_hash_member,iter->get_children().front().get_node_line()); error_interrupt(__invalid_hash_member,iter->get_children().front().get_node_line());
return -1; return -1;
} }
assigned_value_addr=*assigned_addr;
nasal_gc.reference_add(assigned_value_addr);
nasal_gc.reference_delete(tmp_addr);
} }
nasal_gc.reference_delete(tmp_data_addr); nasal_gc.reference_delete(tmp_data_addr);
} }
@ -2093,21 +2086,17 @@ int nasal_runtime::assignment(std::list<std::map<std::string,int> >& local_scope
// call hash identifier.identifier // call hash identifier.identifier
else if(iter->get_node_type()==__call_hash) else if(iter->get_node_type()==__call_hash)
{ {
if(nasal_gc.get_scalar(assigned_value_addr).get_type()!=scalar_hash) if(nasal_gc.get_scalar(*assigned_addr).get_type()!=scalar_hash)
{ {
error_interrupt(__not_callable_hash,iter->get_node_line()); error_interrupt(__not_callable_hash,iter->get_node_line());
return -1; return -1;
} }
int tmp_addr=assigned_value_addr; assigned_addr=nasal_gc.get_scalar(*assigned_addr).get_hash().get_hash_member_addr(iter->get_var_name());
assigned_addr=nasal_gc.get_scalar(assigned_value_addr).get_hash().get_hash_member_addr(iter->get_var_name());
if(!assigned_addr) if(!assigned_addr)
{ {
error_interrupt(__invalid_hash_member,iter->get_node_line()); error_interrupt(__invalid_hash_member,iter->get_node_line());
return -1; return -1;
} }
assigned_value_addr=*assigned_addr;
nasal_gc.reference_add(assigned_value_addr);
nasal_gc.reference_delete(tmp_addr);
}// end call hash }// end call hash
// call function identifier(...) // call function identifier(...)
else if(iter->get_node_type()==__call_function) else if(iter->get_node_type()==__call_function)
@ -2116,34 +2105,56 @@ int nasal_runtime::assignment(std::list<std::map<std::string,int> >& local_scope
return -1; return -1;
} }
} }
switch(nasal_gc.get_scalar(data_addr).get_type()) nasal_gc.reference_delete(*assigned_addr);
if(assigned_addr)
{ {
case scalar_nil: switch(nasal_gc.get_scalar(data_addr).get_type())
*assigned_addr=nasal_gc.gc_alloc(); {
nasal_gc.get_scalar(*assigned_addr).set_type(scalar_nil); case scalar_nil:
break; *assigned_addr=nasal_gc.gc_alloc();
case scalar_number: nasal_gc.get_scalar(*assigned_addr).set_type(scalar_nil);
*assigned_addr=nasal_gc.gc_alloc(); break;
nasal_gc.get_scalar(*assigned_addr).set_type(scalar_number); case scalar_number:
nasal_gc.get_scalar(*assigned_addr).get_number().deep_copy(nasal_gc.get_scalar(data_addr).get_number()); *assigned_addr=nasal_gc.gc_alloc();
break; nasal_gc.get_scalar(*assigned_addr).set_type(scalar_number);
case scalar_string: nasal_gc.get_scalar(*assigned_addr).get_number().deep_copy(nasal_gc.get_scalar(data_addr).get_number());
*assigned_addr=nasal_gc.gc_alloc(); break;
nasal_gc.get_scalar(*assigned_addr).set_type(scalar_string); case scalar_string:
nasal_gc.get_scalar(*assigned_addr).get_string().deep_copy(nasal_gc.get_scalar(data_addr).get_string()); *assigned_addr=nasal_gc.gc_alloc();
break; nasal_gc.get_scalar(*assigned_addr).set_type(scalar_string);
case scalar_function: nasal_gc.get_scalar(*assigned_addr).get_string().deep_copy(nasal_gc.get_scalar(data_addr).get_string());
*assigned_addr=nasal_gc.gc_alloc(); break;
nasal_gc.get_scalar(*assigned_addr).set_type(scalar_function); case scalar_function:
nasal_gc.get_scalar(*assigned_addr).get_function().deep_copy(nasal_gc.get_scalar(data_addr).get_function()); *assigned_addr=nasal_gc.gc_alloc();
break; nasal_gc.get_scalar(*assigned_addr).set_type(scalar_function);
case scalar_vector: nasal_gc.get_scalar(*assigned_addr).get_function().deep_copy(nasal_gc.get_scalar(data_addr).get_function());
case scalar_hash: break;
*assigned_addr=data_addr; case scalar_vector:
nasal_gc.reference_add(data_addr); case scalar_hash:
break; *assigned_addr=data_addr;
nasal_gc.reference_add(data_addr);
break;
}
} }
else
{
error_interrupt(__subvec_value_be_assigned,node.get_children().back().get_node_line());
return -1;
}
/*
assigned_addr=find_address()
while(children.size())
{
assigned_addr=new_addr()
}
*assigned_addr->refcnt--
*assigned_addr=new_value_addr
*/
// data_addr is only a parameter here,and it's refcnt has not been changed when using it here // data_addr is only a parameter here,and it's refcnt has not been changed when using it here
nasal_gc.reference_add(*assigned_addr);
for(int i=0;i<tmp_subvec_addr.size();++i)
nasal_gc.reference_delete(tmp_subvec_addr[i]);
return *assigned_addr; return *assigned_addr;
} }
int nasal_runtime::call_identifier(std::list<std::map<std::string,int> >& local_scope,abstract_syntax_tree& node) int nasal_runtime::call_identifier(std::list<std::map<std::string,int> >& local_scope,abstract_syntax_tree& node)
@ -2870,8 +2881,8 @@ int nasal_runtime::block_proc(std::list<std::map<std::string,int> >& local_scope
return state; return state;
} }
int nasal_runtime::func_proc( int nasal_runtime::func_proc(
std::list<std::map<std::string,int> >& parameters_assist_scope,// scope that used to generate parameters
std::list<std::map<std::string,int> >& local_scope,// running scope,often gets the scope that calls it std::list<std::map<std::string,int> >& local_scope,// running scope,often gets the scope that calls it
std::list<std::map<std::string,int> >& function_scope,// running scope,often gets the scope that has been recorded in nasal function
abstract_syntax_tree& parameter_list, // parameter list format of nasal function abstract_syntax_tree& parameter_list, // parameter list format of nasal function
abstract_syntax_tree& func_root, // main runnning block of nasal function abstract_syntax_tree& func_root, // main runnning block of nasal function
abstract_syntax_tree& input_parameters, // input parameters when calling this nasal function abstract_syntax_tree& input_parameters, // input parameters when calling this nasal function
@ -2881,12 +2892,7 @@ int nasal_runtime::func_proc(
function_returned_addr=-1; function_returned_addr=-1;
std::map<std::string,int> new_scope; std::map<std::string,int> new_scope;
local_scope.push_back(new_scope); local_scope.push_back(new_scope);
for(std::list<std::map<std::string,int> >::iterator i=function_scope.begin();i!=function_scope.end();++i)
for(std::map<std::string,int>::iterator j=i->begin();j!=i->end();++j)
{
local_scope.back()[j->first]=j->second;
nasal_gc.reference_delete(j->second);
}
if(called_hash_addr>=0) if(called_hash_addr>=0)
local_scope.back()["me"]=called_hash_addr; local_scope.back()["me"]=called_hash_addr;
// loading parameters // loading parameters
@ -2904,7 +2910,7 @@ int nasal_runtime::func_proc(
else if(iter->get_node_type()==__default_parameter) else if(iter->get_node_type()==__default_parameter)
{ {
para_name_list.push_back(iter->get_children().front().get_var_name()); para_name_list.push_back(iter->get_children().front().get_var_name());
int default_val_addr=calculation(local_scope,iter->get_children().back()); int default_val_addr=calculation(parameters_assist_scope,iter->get_children().back());
if(default_val_addr<0) if(default_val_addr<0)
return -1; return -1;
local_scope.back()[para_name_list.back()]=default_val_addr; local_scope.back()[para_name_list.back()]=default_val_addr;
@ -2925,7 +2931,7 @@ int nasal_runtime::func_proc(
{ {
if(has_dynamic_id) if(has_dynamic_id)
{ {
int val_addr=calculation(local_scope,*iter); int val_addr=calculation(parameters_assist_scope,*iter);
if(val_addr<0) if(val_addr<0)
return -1; return -1;
nasal_gc.get_scalar(dynamic_args).get_vector().vec_push(val_addr); nasal_gc.get_scalar(dynamic_args).get_vector().vec_push(val_addr);
@ -2935,7 +2941,7 @@ int nasal_runtime::func_proc(
} }
else else
{ {
int val_addr=calculation(local_scope,*iter); int val_addr=calculation(parameters_assist_scope,*iter);
if(val_addr<0) if(val_addr<0)
return -1; return -1;
if(local_scope.back()[para_name_list[tmp_ptr]]<0) if(local_scope.back()[para_name_list[tmp_ptr]]<0)
@ -2956,7 +2962,7 @@ int nasal_runtime::func_proc(
std::string tmp_para_name=iter->get_children().front().get_var_name(); std::string tmp_para_name=iter->get_children().front().get_var_name();
if(local_scope.back().find(tmp_para_name)!=local_scope.back().end()) if(local_scope.back().find(tmp_para_name)!=local_scope.back().end())
{ {
int val_addr=calculation(local_scope,iter->get_children().back()); int val_addr=calculation(parameters_assist_scope,iter->get_children().back());
if(val_addr<0) if(val_addr<0)
return -1; return -1;
if(local_scope.back()[tmp_para_name]<0) if(local_scope.back()[tmp_para_name]<0)