987 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			987 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2006-2018, RT-Thread Development Team
 | |
|  *
 | |
|  * SPDX-License-Identifier: Apache-2.0
 | |
|  *
 | |
|  * 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;
 | |
| }
 |