text: /*
   *  script parser for finsh shell.
   *
   * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
   *
   *  This file is part of RT-Thread (http://www.rt-thread.org)
   *  Maintainer: bernard.xiong <bernard.xiong at gmail.com>
   *
   *  All rights reserved.
   *
   *  This program is free software; you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation; either version 2 of the License, or
   *  (at your option) any later version.
   *
   *  This program is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License along
   *  with this program; if not, write to the Free Software Foundation, Inc.,
   *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   *
   * Change Logs:
   * Date           Author       Notes
   * 2010-03-22     Bernard      first version
   * 2013-10-09     Bernard      fix the command line too long issue.
   */
  #include <finsh.h>
  
  #include "finsh_token.h"
  #include "finsh_node.h"
  #include "finsh_error.h"
  #include "finsh_parser.h"
  #include "finsh_var.h"
  
  /*
   * the structure of abstract syntax tree:
   * root____________
   * |               \
   * child__        sibling__
   * |      \       |        \
   * child sibling  child   sibling
   *                          ...
   */
  static enum finsh_type proc_type(struct finsh_parser* self);
  static int proc_identifier(struct finsh_parser* self, char* id);
  static struct finsh_node* proc_variable_decl(struct finsh_parser* self);
  static struct finsh_node* proc_expr(struct finsh_parser* self);
  static struct finsh_node* proc_assign_expr(struct finsh_parser* self);
  static struct finsh_node* proc_inclusive_or_expr(struct finsh_parser* self);
  static struct finsh_node* proc_exclusive_or_expr(struct finsh_parser* self);
  static struct finsh_node* proc_and_expr(struct finsh_parser* self);
  static struct finsh_node* proc_shift_expr(struct finsh_parser* self);
  static struct finsh_node* proc_additive_expr(struct finsh_parser* self);
  static struct finsh_node* proc_multiplicative_expr(struct finsh_parser* self);
  static struct finsh_node* proc_cast_expr(struct finsh_parser* self);
  static struct finsh_node* proc_unary_expr(struct finsh_parser* self);
  static struct finsh_node* proc_postfix_expr(struct finsh_parser* self);
  static struct finsh_node* proc_primary_expr(struct finsh_parser* self);
  static struct finsh_node* proc_param_list(struct finsh_parser* self);
  static struct finsh_node* proc_expr_statement(struct finsh_parser* self);
  static struct finsh_node* make_sys_node(uint8_t type, struct finsh_node* node1,
                                          struct finsh_node* node2);
  
  /* check token */
  #define check_token(token, lex, type) if ( (token) != (type) ) \
      { \
          finsh_error_set(FINSH_ERROR_INVALID_TOKEN); \
          finsh_token_replay(lex); \
      }
  
  /* is the token a data type? */
  #define is_base_type(token) ((token) == finsh_token_type_void \
      || (token) == finsh_token_type_char \
      || (token) == finsh_token_type_short \
      || (token) == finsh_token_type_int \
      || (token) == finsh_token_type_long)
  
  /* get the next token */
  #define next_token(token, lex)  (token) = finsh_token_token(lex)
  
  /* match a specified token */
  #define match_token(token, lex, type)   next_token(token, lex); \
      check_token(token, lex, type)
  
  /*
  process for function and variable declaration.
  decl_variable -> type declaration_list ';'
  declarator_list -> declarator_list ',' declarator
      | declarator
  declarator -> identifier
      | identifier ASSIGN expr_assign
  */
  static struct finsh_node* proc_variable_decl(struct finsh_parser* self)
  {
  	enum finsh_token_type token;
  	enum finsh_type type;
  	char id[FINSH_NAME_MAX + 1];
  
  	struct finsh_node* node;
  	struct finsh_node* end;
  	struct finsh_node* assign;
  
  	node = NULL;
  	end  = NULL;
  
  	/* get type */
  	type = proc_type(self);
  
  	/*process id.*/
  	if(proc_identifier(self, id) == 0) {
  		/* if add variable failed */
  		if(finsh_var_insert(id, type) < 0) {
  			finsh_error_set(FINSH_ERROR_VARIABLE_EXIST);
  		}
  	}
  
  	next_token(token, &(self->token));
  
  	switch(token) {
  		case finsh_token_type_comma:/*',', it's a variable_list declaration.*/
  			if(proc_identifier(self, id) == 0) {
  				/* if add variable failed */
  				if(finsh_var_insert(id, type) < 0) {
  					finsh_error_set(FINSH_ERROR_VARIABLE_EXIST);
  				}
  			}
  
  			next_token(token, &(self->token));
  
  			if(token == finsh_token_type_assign) {
  				/* get the right side of assign expression */
  				assign = proc_assign_expr(self);
  
  				if(assign != NULL) {
  					struct finsh_node* idnode;
  
  					idnode = finsh_node_new_id(id);
  					end = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign);
  					node = end;
  
  					next_token(token, &(self->token));
  				}
  			}
  
  			while(token == finsh_token_type_comma) {
  				if(proc_identifier(self, id) == 0) {
  					/* if add variable failed */
  					if(finsh_var_insert(id, type) < 0) {
  						finsh_error_set(FINSH_ERROR_VARIABLE_EXIST);
  					}
  				}
  
  				next_token(token, &(self->token));
  
  				if(token == finsh_token_type_assign) {
  					/* get the right side of assign expression */
  					assign = proc_assign_expr(self);
  
  					if(assign != NULL) {
  						struct finsh_node* idnode;
  
  						idnode = finsh_node_new_id(id);
  
  						/* make assign expression node */
  						if(node != NULL) {
  							finsh_node_sibling(end) = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign);
  							end = finsh_node_sibling(end);
  						} else {
  							end = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign);
  							node = end;
  						}
  
  						next_token(token, &(self->token));
  					}
  				}
  			}
  
  			check_token(token, &(self->token), finsh_token_type_semicolon);
  			return node;
  
  		case finsh_token_type_assign: { /*'=', it's a variable with assign declaration.*/
  			struct finsh_node* idnode;
  
  			assign = proc_assign_expr(self);
  
  			if(assign != NULL) {
  				idnode = finsh_node_new_id(id);
  
  				/* make assign expression node */
  				end = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign);
  				node = end;
  
  				next_token(token, &(self->token));
  			}
  
  			while(token == finsh_token_type_comma) {
  				if(proc_identifier(self, id) == 0) {
  					/* if add variable failed */
  					if(finsh_var_insert(id, type) < 0) {
  						finsh_error_set(FINSH_ERROR_VARIABLE_EXIST);
  					}
  				}
  
  				next_token(token, &(self->token));
  
  				if(token == finsh_token_type_assign) {
  					/* get the right side of assign expression */
  					assign = proc_assign_expr(self);
  
  					if(assign != NULL) {
  						idnode = finsh_node_new_id(id);
  
  						/* make assign expression node */
  						if(node != NULL) {
  							finsh_node_sibling(end) = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign);
  							end = finsh_node_sibling(end);
  						} else {
  							end = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign);
  							node = end;
  						}
  
  						next_token(token, &(self->token));
  					}
  				}
  			}
  
  			check_token(token, &(self->token), finsh_token_type_semicolon);
  			return node;
  		}
  
  		case finsh_token_type_semicolon:/*';', it's a variable declaration.*/
  			return node;
  
  		default:
  			finsh_error_set(FINSH_ERROR_EXPECT_TYPE);
  
  			return NULL;
  	}
  }
  
  /*
  type -> type_prefix type_basic | type_basic
  type_prefix -> UNSIGNED
  type_basic -> VOID
      | CHAR
      | SHORT
      | INT
      | STRING
  */
  static enum finsh_type proc_type(struct finsh_parser* self)
  {
  	enum finsh_type type;
  	enum finsh_token_type token;
  
  	/* set init type */
  	type = finsh_type_unknown;
  
  	next_token(token, &(self->token));
  
  	if(is_base_type(token)) {  /* base_type */
  		switch(token) {
  			case finsh_token_type_void:
  				type = finsh_type_void;
  				break;
  
  			case finsh_token_type_char:
  				type = finsh_type_char;
  				break;
  
  			case finsh_token_type_short:
  				type = finsh_type_short;
  				break;
  
  			case finsh_token_type_int:
  				type = finsh_type_int;
  				break;
  
  			case finsh_token_type_long:
  				type = finsh_type_long;
  				break;
  
  			default:
  				goto __return;
  		}
  	} else if(token == finsh_token_type_unsigned) { /* unsigned base_type */
  		next_token(token, &(self->token));
  
  		if(is_base_type(token)) {
  			switch(token) {
  				case finsh_token_type_char:
  					type = finsh_type_uchar;
  					break;
  
  				case finsh_token_type_short:
  					type = finsh_type_ushort;
  					break;
  
  				case finsh_token_type_int:
  					type = finsh_type_uint;
  					break;
  
  				case finsh_token_type_long:
  					type = finsh_type_ulong;
  					break;
  
  				default:
  					goto __return;
  			}
  		} else {
  			finsh_token_replay(&(self->token));
  			finsh_error_set(FINSH_ERROR_EXPECT_TYPE);
  		}
  	} else {
  		goto __return;
  	}
  
  	/* parse for pointer */
  	next_token(token, &(self->token));
  
  	if(token == finsh_token_type_mul) {
  		switch(type) {
  			case finsh_type_void:
  				type = finsh_type_voidp;
  				break;
  
  			case finsh_type_char:
  			case finsh_type_uchar:
  				type = finsh_type_charp;
  				break;
  
  			case finsh_type_short:
  			case finsh_type_ushort:
  				type = finsh_type_shortp;
  				break;
  
  			case finsh_type_int:
  			case finsh_type_uint:
  				type = finsh_type_intp;
  				break;
  
  			case finsh_type_long:
  			case finsh_type_ulong:
  				type = finsh_type_longp;
  				break;
  
  			default:
  				type = finsh_type_voidp;
  				break;
  		}
  	} else finsh_token_replay(&(self->token));
  
  	return type;
  
  __return:
  	finsh_token_replay(&(self->token));
  	finsh_error_set(FINSH_ERROR_UNKNOWN_TYPE);
  
  	return type;
  }
  
  /*
  identifier -> IDENTIFIER
  */
  static int proc_identifier(struct finsh_parser* self, char* id)
  {
  	enum finsh_token_type token;
  
  	match_token(token, &(self->token), finsh_token_type_identifier);
  
  	strncpy(id, (char*)self->token.string, FINSH_NAME_MAX);
  
  	return 0;
  }
  
  /*
  statement_expr -> ';'
      | expr ';'
  */
  static struct finsh_node* proc_expr_statement(struct finsh_parser* self)
  {
  	enum finsh_token_type token;
  	struct finsh_node* expr;
  
  	expr = NULL;
  	next_token(token, &(self->token));
  
  	if(token != finsh_token_type_semicolon) {
  		finsh_token_replay(&(self->token));
  		expr = proc_expr(self);
  
  		match_token(token, &(self->token), finsh_token_type_semicolon);
  	}
  
  	return expr;
  }
  
  /*
  expr -> expr_assign
  */
  static struct finsh_node* proc_expr(struct finsh_parser* self)
  {
  	return proc_assign_expr(self);
  }
  
  /*
  expr_assign -> expr_inclusive_or
      | expr_unary ASSIGN expr_assign
  */
  static struct finsh_node* proc_assign_expr(struct finsh_parser* self)
  {
  	enum finsh_token_type token;
  	struct finsh_node* or;
  	struct finsh_node* assign;
  
  	or = proc_inclusive_or_expr(self);
  
  	next_token(token, &(self->token));
  
  	if(token == finsh_token_type_assign) {
  		assign = proc_assign_expr(self);
  
  		return make_sys_node(FINSH_NODE_SYS_ASSIGN, or, assign);
  	} else finsh_token_replay(&(self->token));
  
  	return or;
  }
  
  /*
  expr_inclusive_or -> expr_exclusive_or
      | expr_inclusive_or '|' expr_exclusive_or
  */
  static struct finsh_node* proc_inclusive_or_expr(struct finsh_parser* self)
  {
  	enum finsh_token_type token;
  	struct finsh_node* xor;
  	struct finsh_node* xor_new;
  
  	xor = proc_exclusive_or_expr(self);
  
  	next_token(token, &(self->token));
  
  	while(token == finsh_token_type_or) {
  		xor_new = proc_exclusive_or_expr(self);
  
  		if(xor_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR);
  		else xor = make_sys_node(FINSH_NODE_SYS_OR, xor, xor_new);
  
  		next_token(token, &(self->token));
  	}
  
  	finsh_token_replay(&(self->token));
  	return xor;
  }
  
  /*
  expr_exclusive_or -> expr_and
      | expr_exclusive '^' expr_and
  */
  static struct finsh_node* proc_exclusive_or_expr(struct finsh_parser* self)
  {
  	enum finsh_token_type token;
  	struct finsh_node* and;
  	struct finsh_node* and_new;
  
  	and = proc_and_expr(self);
  	next_token(token, &(self->token));
  
  	while(token == finsh_token_type_xor) {
  		and_new = proc_and_expr(self);
  
  		if(and_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR);
  		else and = make_sys_node(FINSH_NODE_SYS_XOR, and, and_new);
  
  		next_token(token, &(self->token));
  	}
  
  	finsh_token_replay(&(self->token));
  	return and;
  }
  
  /*
  expr_and -> expr_shift
      | expr_and '&' expr_shift
  */
  static struct finsh_node* proc_and_expr(struct finsh_parser* self)
  {
  	enum finsh_token_type token;
  	struct finsh_node* shift;
  	struct finsh_node* shift_new;
  
  	shift = proc_shift_expr(self);
  
  	next_token(token, &(self->token));
  
  	while(token == finsh_token_type_and) {
  		shift_new = proc_shift_expr(self);
  
  		if(shift_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR);
  		else shift = make_sys_node(FINSH_NODE_SYS_AND, shift, shift_new);
  
  		next_token(token, &(self->token));
  	}
  
  	finsh_token_replay(&(self->token));
  	return shift;
  }
  
  /*
  expr_shift -> expr_additive
      | expr_shift '<<' expr_additive
      | expr_shift '>>' expr_additive
  */
  static struct finsh_node* proc_shift_expr(struct finsh_parser* self)
  {
  	enum finsh_token_type token;
  	struct finsh_node* add;
  	struct finsh_node* add_new;
  
  	add = proc_additive_expr(self);
  
  	next_token(token, &(self->token));
  
  	while(token == finsh_token_type_shl || token == finsh_token_type_shr) {
  		add_new = proc_additive_expr(self);
  
  		if(add_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR);
  		else {
  			switch(token) {
  				case finsh_token_type_shl:
  					add = make_sys_node(FINSH_NODE_SYS_SHL, add, add_new);
  					break;
  
  				case finsh_token_type_shr:
  					add = make_sys_node(FINSH_NODE_SYS_SHR, add, add_new);
  					break;
  
  				default:
  					finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR);
  					break;
  			}
  		}
  
  		next_token(token, &(self->token));
  	}
  
  	finsh_token_replay(&(self->token));
  	return add;
  }
  
  /*
  expr_additive -> expr_multiplicative
      | expr_additive SUB expr_multiplicative
      | expr_additive ADD expr_multiplicative
  */
  static struct finsh_node* proc_additive_expr(struct finsh_parser* self)
  {
  	enum finsh_token_type token;
  	struct finsh_node* mul;
  	struct finsh_node* mul_new;
  
  	mul = proc_multiplicative_expr(self);
  
  	next_token(token, &(self->token));
  
  	while(token == finsh_token_type_sub || token == finsh_token_type_add) {
  		mul_new = proc_multiplicative_expr(self);
  
  		if(mul_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR);
  		else {
  			switch(token) {
  				case finsh_token_type_sub:
  					mul = make_sys_node(FINSH_NODE_SYS_SUB, mul, mul_new);
  					break;
  
  				case finsh_token_type_add:
  					mul = make_sys_node(FINSH_NODE_SYS_ADD, mul, mul_new);
  					break;
  
  				default:
  					finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR);
  					break;
  			}
  		}
  
  		next_token(token, &(self->token));
  	}
  
  	finsh_token_replay(&(self->token));
  	return mul;
  }
  
  /*
  expr_multiplicative -> expr_cast
      | expr_multiplicative '*' expr_cast
      | expr_multiplicative '/' expr_cast
      | expr_multiplicative '%' expr_cast
  */
  static struct finsh_node* proc_multiplicative_expr(struct finsh_parser* self)
  {
  	enum finsh_token_type token;
  	struct finsh_node* cast;
  	struct finsh_node* cast_new;
  
  	cast = proc_cast_expr(self);
  	next_token(token, &(self->token));
  
  	while(token == finsh_token_type_mul ||
  	        token == finsh_token_type_div ||
  	        token == finsh_token_type_mod) {
  		cast_new = proc_cast_expr(self);
  
  		if(cast_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR);
  		else {
  			switch(token) {
  				case finsh_token_type_mul:
  					cast = make_sys_node(FINSH_NODE_SYS_MUL, cast, cast_new);
  					break;
  
  				case finsh_token_type_div:
  					cast = make_sys_node(FINSH_NODE_SYS_DIV, cast, cast_new);
  					break;
  
  				case finsh_token_type_mod:
  					cast = make_sys_node(FINSH_NODE_SYS_MOD, cast, cast_new);
  					break;
  
  				default:
  					finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR);
  					break;
  			}
  		}
  
  		next_token(token, &(self->token));
  	}
  
  	finsh_token_replay(&(self->token));
  	return cast;
  }
  
  /*
  20060313, add recast parse
  expr_cast -> expr_unary
      | '(' type ')' expr_cast
  */
  static struct finsh_node* proc_cast_expr(struct finsh_parser* self)
  {
  	enum finsh_token_type token;
  	enum finsh_type type;
  	struct finsh_node* cast;
  
  	next_token(token, &(self->token));
  
  	if(token == finsh_token_type_left_paren) {
  		type = proc_type(self);
  		match_token(token, &(self->token), finsh_token_type_right_paren);
  
  		cast = proc_cast_expr(self);
  
  		if(cast != NULL) {
  			cast->data_type = type;
  			return cast;
  		}
  	}
  
  	finsh_token_replay(&(self->token));
  	return proc_unary_expr(self);
  }
  
  /*
  20050921, add '*' and '&'
  expr_unary -> expr_postfix
      | ADD expr_cast
      | INC expr_cast
      | SUB expr_cast
      | DEC expr_cast
      | '~' expr_cast
      | '*' expr_cast
      | '&' expr_cast
  */
  static struct finsh_node* proc_unary_expr(struct finsh_parser* self)
  {
  	enum finsh_token_type token;
  	struct finsh_node* cast;
  
  	next_token(token, &(self->token));
  
  	switch(token) {
  		case finsh_token_type_add: /* + */
  			cast = proc_cast_expr(self);
  			return cast;
  
  		case finsh_token_type_inc: /* ++ */
  			cast = proc_cast_expr(self);
  			return make_sys_node(FINSH_NODE_SYS_PREINC, cast, NULL);
  
  		case finsh_token_type_sub: /* - */
  			cast = proc_cast_expr(self);
  			return make_sys_node(FINSH_NODE_SYS_SUB, finsh_node_new_long(0), cast);
  
  		case finsh_token_type_dec: /* -- */
  			cast = proc_cast_expr(self);
  			return make_sys_node(FINSH_NODE_SYS_PREDEC, cast, NULL);
  
  		case finsh_token_type_bitwise: /* ~ */
  			cast = proc_cast_expr(self);
  			return make_sys_node(FINSH_NODE_SYS_BITWISE, cast, NULL);
  
  		case finsh_token_type_mul: /* * */
  			cast = proc_cast_expr(self);
  			return make_sys_node(FINSH_NODE_SYS_GETVALUE, cast, NULL);
  
  		case finsh_token_type_and: /* & */
  			cast = proc_cast_expr(self);
  			return make_sys_node(FINSH_NODE_SYS_GETADDR, cast, NULL);
  
  		default:
  			finsh_token_replay(&(self->token));
  			return proc_postfix_expr(self);
  	}
  }
  
  /*
  expr_postfix -> expr_primary
      | expr_postfix INC
      | expr_postfix DEC
      | expr_postfix '(' param_list ')'
  */
  static struct finsh_node* proc_postfix_expr(struct finsh_parser* self)
  {
  	enum finsh_token_type token;
  	struct finsh_node* postfix;
  
  	postfix = proc_primary_expr(self);
  
  	next_token(token, &(self->token));
  
  	while(token == finsh_token_type_inc   ||
  	        token == finsh_token_type_dec       ||
  	        token == finsh_token_type_left_paren) {
  		switch(token) {
  			case finsh_token_type_inc :/* '++' */
  				postfix = make_sys_node(FINSH_NODE_SYS_INC, postfix, NULL);
  				break;
  
  			case finsh_token_type_dec :/* '--' */
  				postfix = make_sys_node(FINSH_NODE_SYS_DEC, postfix, NULL);
  				break;
  
  			case finsh_token_type_left_paren : { /* '(' */
  				struct finsh_node* param_list;
  
  				param_list = NULL;
  				next_token(token, &(self->token));
  
  				if(token != finsh_token_type_right_paren) {
  					finsh_token_replay(&(self->token));
  					param_list = proc_param_list(self);
  
  					match_token(token, &(self->token), finsh_token_type_right_paren);
  				}
  
  				postfix = make_sys_node(FINSH_NODE_SYS_FUNC, postfix, param_list);
  			}
  			break;
  
  			default:
  				break;
  		}
  
  		next_token(token, &(self->token));
  	}
  
  	finsh_token_replay(&(self->token));
  	return postfix;
  }
  
  /*
  expr_primary -> literal
      | '(' expr ')'
      | identifier
  */
  static struct finsh_node* proc_primary_expr(struct finsh_parser* self)
  {
  	enum finsh_token_type token;
  	struct finsh_node* expr;
  
  	next_token(token, &(self->token));
  
  	switch(token) {
  		case finsh_token_type_identifier: {
  			char id[FINSH_NAME_MAX + 1];
  
  			finsh_token_replay(&(self->token));
  			proc_identifier(self, id);
  			return finsh_node_new_id(id);
  		}
  
  		case finsh_token_type_left_paren:
  			expr = proc_expr(self);
  			match_token(token, &(self->token), finsh_token_type_right_paren);
  			return expr;
  
  		case finsh_token_type_value_int:
  			return finsh_node_new_int(self->token.value.int_value);
  
  		case finsh_token_type_value_long:
  			return finsh_node_new_long(self->token.value.long_value);
  
  		case finsh_token_type_value_char:
  			return finsh_node_new_char(self->token.value.char_value);
  
  		case finsh_token_type_value_string:
  			return finsh_node_new_string((char*)self->token.string);
  
  		case finsh_token_type_value_null:
  			return finsh_node_new_ptr(NULL);
  
  		default:
  			finsh_error_set(FINSH_ERROR_INVALID_TOKEN);
  			break;
  	}
  
  	return NULL;
  }
  
  /*
  param_list -> empty
      | expr_assign
      | param_list ',' expr_assign
  */
  static struct finsh_node* proc_param_list(struct finsh_parser* self)
  {
  	enum finsh_token_type token;
  	struct finsh_node* node, *assign;
  
  	assign = proc_assign_expr(self);
  
  	if(assign == NULL) return NULL;
  
  	node = assign;
  
  	next_token(token, &(self->token));
  
  	while(token == finsh_token_type_comma) {
  		finsh_node_sibling(assign) = proc_assign_expr(self);
  
  		if(finsh_node_sibling(assign) != NULL) assign = finsh_node_sibling(assign);
  		else finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR);
  
  		next_token(token, &(self->token));
  	}
  
  	finsh_token_replay(&(self->token));
  
  	return node;
  }
  
  /*
  make a new node as following tree:
  new_node
  |
  node1__
         \
         node2
  */
  static struct finsh_node* make_sys_node(uint8_t type, struct finsh_node* node1, struct finsh_node* node2)
  {
  	struct finsh_node* node;
  
  	node = finsh_node_allocate(type);
  
  	if((node1 != NULL) && (node != NULL)) {
  		finsh_node_child(node) = node1;
  		finsh_node_sibling(node1) = node2;
  	} else finsh_error_set(FINSH_ERROR_NULL_NODE);
  
  	return node;
  }
  
  /*
  start -> statement_expr | decl_variable
  */
  void finsh_parser_run(struct finsh_parser* self, const uint8_t* string)
  {
  	enum finsh_token_type token;
  	struct finsh_node* node;
  
  	node = NULL;
  
  	/* init parser */
  	self->parser_string = (uint8_t*)string;
  
  	/* init token */
  	finsh_token_init(&(self->token), self->parser_string);
  
  	/* get next token */
  	next_token(token, &(self->token));
  
  	while(token != finsh_token_type_eof && token != finsh_token_type_bad) {
  		switch(token) {
  			case finsh_token_type_identifier:
  				/* process expr_statement */
  				finsh_token_replay(&(self->token));
  
  				if(self->root != NULL) {
  					finsh_node_sibling(node) = proc_expr_statement(self);
  
  					if(finsh_node_sibling(node) != NULL)
  						node = finsh_node_sibling(node);
  				} else {
  					node = proc_expr_statement(self);
  					self->root = node;
  				}
  
  				break;
  
  			default:
  				if(is_base_type(token) || token == finsh_token_type_unsigned) {
  					/* variable decl */
  					finsh_token_replay(&(self->token));
  
  					if(self->root != NULL) {
  						finsh_node_sibling(node) = proc_variable_decl(self);
  
  						if(finsh_node_sibling(node) != NULL)
  							node = finsh_node_sibling(node);
  					} else {
  						node = proc_variable_decl(self);
  						self->root = node;
  					}
  				} else {
  					/* process expr_statement */
  					finsh_token_replay(&(self->token));
  
  					if(self->root != NULL) {
  						finsh_node_sibling(node) = proc_expr_statement(self);
  
  						if(finsh_node_sibling(node) != NULL)
  							node = finsh_node_sibling(node);
  						else next_token(token, &(self->token));
  					} else {
  						node = proc_expr_statement(self);
  						self->root = node;
  					}
  				}
  
  				break;
  		}
  
  		/* no root found, break out */
  		if(self->root == NULL) break;
  
  		/* get next token */
  		next_token(token, &(self->token));
  	}
  }
  
  int finsh_parser_init(struct finsh_parser* self)
  {
  	memset(self, 0, sizeof(struct finsh_parser));
  
  	return 0;
  }
  