1006 lines
27 KiB
C
1006 lines
27 KiB
C
/*
|
|
* 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;
|
|
}
|