doubao_chat/apps/common/example/third_party/finsh/finsh_parser.c

937 lines
25 KiB
C

/*
* Copyright (c) 2006-2021, 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;
}