lang: ast: convert RPN expression queue to ast and replace generic EXPR node with it
This commit is contained in:
@@ -101,7 +101,7 @@ struct parser_state *parser_push_state(
|
||||
state->s_parent = current_state->s_node;
|
||||
}
|
||||
|
||||
state->s_node = ast_node_create_with_size(type, node_type->n_node_size);
|
||||
state->s_node = ast_node_create(type);
|
||||
b_queue_push_back(&parser->p_state, &state->s_entry);
|
||||
|
||||
if (node_type->n_init_state) {
|
||||
@@ -128,6 +128,17 @@ void parser_pop_state(struct ivy_parser *parser, enum pop_state_flags flags)
|
||||
free(state);
|
||||
}
|
||||
|
||||
void parser_replace_current_node(struct ivy_parser *parser, struct ivy_ast_node *new_node)
|
||||
{
|
||||
struct parser_state *state = parser_get_state_generic(parser);
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
|
||||
ivy_ast_node_destroy(state->s_node);
|
||||
state->s_node = new_node;
|
||||
}
|
||||
|
||||
bool ivy_parser_is_node_complete(struct ivy_parser *parser)
|
||||
{
|
||||
return (parser->p_state.q_first == parser->p_state.q_last);
|
||||
|
||||
@@ -30,4 +30,6 @@ extern struct parser_state *parser_push_state(
|
||||
extern void parser_pop_state(struct ivy_parser *parser, enum pop_state_flags flags);
|
||||
extern struct parser_state *parser_get_state_generic(struct ivy_parser *parser);
|
||||
|
||||
extern void parser_replace_current_node(struct ivy_parser *parser, struct ivy_ast_node *new_node);
|
||||
|
||||
#endif
|
||||
|
||||
220
lang/ast/expr.c
220
lang/ast/expr.c
@@ -29,7 +29,7 @@ struct expr_parser_state {
|
||||
unsigned int s_type;
|
||||
unsigned int s_prev_tok;
|
||||
enum expr_part s_prev_part;
|
||||
b_queue s_operand_queue;
|
||||
b_queue s_output_queue;
|
||||
b_queue s_operator_stack;
|
||||
};
|
||||
|
||||
@@ -61,34 +61,46 @@ static void set_previous(struct expr_parser_state *state, struct ivy_token *tok)
|
||||
}
|
||||
}
|
||||
|
||||
static void print_token(struct ivy_token *tok)
|
||||
static void print_operand(struct ivy_ast_node *node)
|
||||
{
|
||||
switch (tok->t_type) {
|
||||
case IVY_TOK_IDENT:
|
||||
printf("%s", tok->t_str);
|
||||
switch (node->n_type) {
|
||||
case IVY_AST_IDENT: {
|
||||
struct ivy_ast_ident_node *ident = (struct ivy_ast_ident_node *)node;
|
||||
printf("%s", ident->n_content->t_str);
|
||||
break;
|
||||
case IVY_TOK_INT:
|
||||
printf("%llu", tok->t_int);
|
||||
}
|
||||
case IVY_AST_INT: {
|
||||
struct ivy_ast_int_node *v = (struct ivy_ast_int_node *)node;
|
||||
printf("%llu", v->n_value->t_int);
|
||||
break;
|
||||
case IVY_TOK_DOUBLE:
|
||||
printf("%.2lf", tok->t_double);
|
||||
}
|
||||
case IVY_AST_DOUBLE: {
|
||||
struct ivy_ast_double_node *v = (struct ivy_ast_double_node *)node;
|
||||
printf("%.2lf", v->n_value->t_double);
|
||||
break;
|
||||
case IVY_TOK_SYMBOL:
|
||||
printf("%s", ivy_symbol_to_string(tok->t_symbol));
|
||||
}
|
||||
case IVY_AST_OP: {
|
||||
struct ivy_ast_op_node *v = (struct ivy_ast_op_node *)node;
|
||||
printf("%s", ivy_operator_id_to_string(v->n_op->op_id));
|
||||
break;
|
||||
case IVY_TOK_KEYWORD:
|
||||
printf("%s", ivy_keyword_to_string(tok->t_keyword));
|
||||
}
|
||||
case IVY_AST_MSG: {
|
||||
struct ivy_ast_msg_node *v = (struct ivy_ast_msg_node *)node;
|
||||
printf("%s()", v->n_sel->n_msg_name->t_str);
|
||||
break;
|
||||
case IVY_TOK_STRING:
|
||||
printf("\"%s\"", tok->t_str);
|
||||
}
|
||||
case IVY_AST_STRING: {
|
||||
struct ivy_ast_string_node *v = (struct ivy_ast_string_node *)node;
|
||||
printf("\"%s\"", v->n_value->t_str);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("<token>");
|
||||
printf("<node>");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static enum ivy_status finalise_expr(struct expr_parser_state *state)
|
||||
static enum ivy_status finalise_expr(struct expr_parser_state *state, struct ivy_ast_node **root)
|
||||
{
|
||||
b_queue_iterator it = {0};
|
||||
while (true) {
|
||||
@@ -97,33 +109,68 @@ static enum ivy_status finalise_expr(struct expr_parser_state *state)
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_tokoen *tok = b_unbox(struct ivy_token, entry, t_entry);
|
||||
if (!tok) {
|
||||
struct ivy_ast_node *node = b_unbox(struct ivy_ast_node, entry, n_entry);
|
||||
if (!node) {
|
||||
/* this should never happen */
|
||||
return IVY_ERR_INTERNAL_FAILURE;
|
||||
}
|
||||
|
||||
if (ivy_token_is_symbol(tok, IVY_SYM_LEFT_PAREN)) {
|
||||
if (node->n_type != IVY_AST_OP) {
|
||||
b_queue_push_back(&state->s_output_queue, entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct ivy_ast_op_node *op_node = (struct ivy_ast_op_node *)node;
|
||||
|
||||
if (op_node->n_op->op_id == IVY_OP_LEFT_PAREN) {
|
||||
/* mismatched parentheses */
|
||||
return IVY_ERR_BAD_SYNTAX;
|
||||
}
|
||||
|
||||
b_queue_push_back(&state->s_operand_queue, entry);
|
||||
b_queue_push_back(&state->s_output_queue, entry);
|
||||
}
|
||||
|
||||
b_queue q = B_QUEUE_INIT;
|
||||
b_queue_entry *tmp = NULL;
|
||||
b_queue_iterator_begin(&state->s_output_queue, &it);
|
||||
int i = 0;
|
||||
b_queue_foreach (&it, &state->s_operand_queue) {
|
||||
struct ivy_token *operand
|
||||
= b_unbox(struct ivy_token, it.entry, t_entry);
|
||||
|
||||
if (i > 0) {
|
||||
printf(" ");
|
||||
while (b_queue_iterator_is_valid(&it)) {
|
||||
struct ivy_ast_node *item
|
||||
= b_unbox(struct ivy_ast_node, it.entry, n_entry);
|
||||
b_queue_iterator_erase(&it);
|
||||
|
||||
if (item->n_type != IVY_AST_OP && item->n_type != IVY_AST_MSG) {
|
||||
/* operand */
|
||||
b_queue_push_back(&q, &item->n_entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
print_token(operand);
|
||||
i++;
|
||||
const struct ivy_operator *op = NULL;
|
||||
|
||||
if (item->n_type == IVY_AST_MSG) {
|
||||
struct ivy_ast_msg_node *msg = (struct ivy_ast_msg_node *)item;
|
||||
tmp = b_queue_pop_back(&q);
|
||||
msg->n_recipient = b_unbox(struct ivy_ast_node, tmp, n_entry);
|
||||
b_queue_push_back(&q, &msg->n_base.n_entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct ivy_ast_op_node *op_node = (struct ivy_ast_op_node *)item;
|
||||
op = op_node->n_op;
|
||||
tmp = b_queue_pop_back(&q);
|
||||
op_node->n_right = b_unbox(struct ivy_ast_node, tmp, n_entry);
|
||||
|
||||
if (op->op_arity == IVY_OP_BINARY) {
|
||||
tmp = b_queue_pop_back(&q);
|
||||
op_node->n_left = b_unbox(struct ivy_ast_node, tmp, n_entry);
|
||||
}
|
||||
|
||||
b_queue_push_back(&q, &op_node->n_base.n_entry);
|
||||
}
|
||||
|
||||
tmp = b_queue_pop_back(&q);
|
||||
*root = b_unbox(struct ivy_ast_node, tmp, n_entry);
|
||||
printf("\n");
|
||||
return IVY_OK;
|
||||
}
|
||||
@@ -142,6 +189,19 @@ static const struct ivy_operator *get_operator(struct ivy_token *tok)
|
||||
}
|
||||
}
|
||||
|
||||
static struct ivy_ast_selector_node *create_unary_selector_from_ident(struct ivy_token *tok)
|
||||
{
|
||||
struct ivy_ast_selector_node *sel = (struct ivy_ast_selector_node *)ast_node_create(IVY_AST_SELECTOR);
|
||||
if (!sel) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sel->n_msg_name = tok;
|
||||
sel->n_recipient = IVY_SELECTOR_RECIPIENT_NONE;
|
||||
|
||||
return sel;
|
||||
}
|
||||
|
||||
static enum ivy_status push_operator(
|
||||
struct expr_parser_state *state, struct ivy_token *tok, const struct ivy_operator *op)
|
||||
{
|
||||
@@ -170,13 +230,21 @@ static enum ivy_status push_operator(
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_token *top
|
||||
= b_unbox(struct ivy_token, top_entry, t_entry);
|
||||
if (ivy_token_is_symbol(top, IVY_SYM_LEFT_PAREN)) {
|
||||
struct ivy_ast_node *top
|
||||
= b_unbox(struct ivy_ast_node, top_entry, n_entry);
|
||||
|
||||
const struct ivy_operator *top_op = NULL;
|
||||
if (top->n_type == IVY_AST_OP) {
|
||||
struct ivy_ast_op_node *op_node = (struct ivy_ast_op_node *)top;
|
||||
top_op = op_node->n_op;
|
||||
} else if (top->n_type == IVY_AST_MSG) {
|
||||
top_op = ivy_operator_get(IVY_TOK_IDENT);
|
||||
}
|
||||
|
||||
if (top_op->op_id == IVY_OP_LEFT_PAREN) {
|
||||
break;
|
||||
}
|
||||
|
||||
const struct ivy_operator *top_op = get_operator(top);
|
||||
if (top_op->op_precedence < op->op_precedence) {
|
||||
break;
|
||||
}
|
||||
@@ -187,10 +255,58 @@ static enum ivy_status push_operator(
|
||||
}
|
||||
|
||||
b_queue_delete(&state->s_operator_stack, top_entry);
|
||||
b_queue_push_back(&state->s_operand_queue, top_entry);
|
||||
b_queue_push_back(&state->s_output_queue, top_entry);
|
||||
}
|
||||
|
||||
b_queue_push_back(&state->s_operator_stack, &tok->t_entry);
|
||||
if (tok->t_type == IVY_TOK_IDENT) {
|
||||
struct ivy_ast_msg_node *msg_node = (struct ivy_ast_msg_node *)ast_node_create(IVY_AST_MSG);
|
||||
msg_node->n_sel = create_unary_selector_from_ident(tok);
|
||||
b_queue_push_back(&state->s_operator_stack, &msg_node->n_base.n_entry);
|
||||
} else {
|
||||
struct ivy_ast_op_node *op_node = (struct ivy_ast_op_node *)ast_node_create(IVY_AST_OP);
|
||||
op_node->n_op = op;
|
||||
b_queue_push_back(&state->s_operator_stack, &op_node->n_base.n_entry);
|
||||
}
|
||||
|
||||
return IVY_OK;
|
||||
}
|
||||
|
||||
|
||||
static enum ivy_status push_operand(
|
||||
struct expr_parser_state *state, struct ivy_token *tok)
|
||||
{
|
||||
struct ivy_ast_node *node = NULL;
|
||||
|
||||
switch (tok->t_type) {
|
||||
case IVY_TOK_INT: {
|
||||
struct ivy_ast_int_node *v = (struct ivy_ast_int_node *)ast_node_create(IVY_AST_INT);
|
||||
v->n_value = tok;
|
||||
node = (struct ivy_ast_node *)v;
|
||||
break;
|
||||
}
|
||||
case IVY_TOK_DOUBLE: {
|
||||
struct ivy_ast_double_node *v = (struct ivy_ast_double_node *)ast_node_create(IVY_AST_DOUBLE);
|
||||
v->n_value = tok;
|
||||
node = (struct ivy_ast_node *)v;
|
||||
break;
|
||||
}
|
||||
case IVY_TOK_STRING: {
|
||||
struct ivy_ast_string_node *v = (struct ivy_ast_string_node *)ast_node_create(IVY_AST_STRING);
|
||||
v->n_value = tok;
|
||||
node = (struct ivy_ast_node *)v;
|
||||
break;
|
||||
}
|
||||
case IVY_TOK_IDENT: {
|
||||
struct ivy_ast_ident_node *v = (struct ivy_ast_ident_node *)ast_node_create(IVY_AST_IDENT);
|
||||
v->n_content = tok;
|
||||
node = (struct ivy_ast_node *)v;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return IVY_ERR_INTERNAL_FAILURE;
|
||||
}
|
||||
|
||||
b_queue_push_back(&state->s_output_queue, &node->n_entry);
|
||||
return IVY_OK;
|
||||
}
|
||||
|
||||
@@ -207,7 +323,7 @@ static struct token_parse_result parse_ident(
|
||||
if (state->s_prev_part == EXPR_OPERAND) {
|
||||
push_operator(state, tok, NULL);
|
||||
} else {
|
||||
b_queue_push_back(&state->s_operand_queue, &tok->t_entry);
|
||||
push_operand(state, tok);
|
||||
}
|
||||
|
||||
set_previous(state, tok);
|
||||
@@ -226,7 +342,7 @@ static struct token_parse_result parse_atom(
|
||||
state->s_end = EXPR_END_DOT;
|
||||
}
|
||||
|
||||
b_queue_push_back(&state->s_operand_queue, &tok->t_entry);
|
||||
push_operand(state, tok);
|
||||
set_previous(state, tok);
|
||||
state->s_prev_part = EXPR_OPERAND;
|
||||
|
||||
@@ -243,7 +359,7 @@ static struct token_parse_result parse_string(
|
||||
state->s_end = EXPR_END_DOT;
|
||||
}
|
||||
|
||||
b_queue_push_back(&state->s_operand_queue, &tok->t_entry);
|
||||
push_operand(state, tok);
|
||||
set_previous(state, tok);
|
||||
state->s_prev_part = EXPR_OPERAND;
|
||||
|
||||
@@ -282,7 +398,7 @@ static struct token_parse_result parse_int(
|
||||
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
|
||||
}
|
||||
|
||||
b_queue_push_back(&state->s_operand_queue, &tok->t_entry);
|
||||
push_operand(state, tok);
|
||||
set_previous(state, tok);
|
||||
state->s_prev_part = EXPR_OPERAND;
|
||||
|
||||
@@ -303,7 +419,7 @@ static struct token_parse_result parse_double(
|
||||
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
|
||||
}
|
||||
|
||||
b_queue_push_back(&state->s_operand_queue, &tok->t_entry);
|
||||
push_operand(state, tok);
|
||||
set_previous(state, tok);
|
||||
state->s_prev_part = EXPR_OPERAND;
|
||||
|
||||
@@ -345,7 +461,9 @@ static struct token_parse_result parse_left_paren(
|
||||
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
|
||||
}
|
||||
|
||||
b_queue_push_back(&state->s_operator_stack, &tok->t_entry);
|
||||
struct ivy_ast_op_node *paren_node = (struct ivy_ast_op_node *)ast_node_create(IVY_AST_OP);
|
||||
paren_node->n_op = ivy_operator_get(tok->t_symbol);
|
||||
b_queue_push_back(&state->s_operator_stack, &paren_node->n_base.n_entry);
|
||||
set_previous(state, tok);
|
||||
|
||||
return PARSE_RESULT(IVY_OK, 0);
|
||||
@@ -479,11 +597,17 @@ static struct token_parse_result parse_bang(
|
||||
if (state->s_end != EXPR_END_DOT) {
|
||||
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
|
||||
}
|
||||
|
||||
struct ivy_ast_node *expr_tree = NULL;
|
||||
enum ivy_status status = finalise_expr(state, &expr_tree);
|
||||
|
||||
if (status != IVY_OK) {
|
||||
return PARSE_RESULT(status, 0);
|
||||
}
|
||||
|
||||
enum ivy_status status = finalise_expr(state);
|
||||
|
||||
parser_replace_current_node(ctx, expr_tree);
|
||||
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
|
||||
return PARSE_RESULT(status, PARSE_REPEAT_TOKEN);
|
||||
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
|
||||
}
|
||||
|
||||
static struct token_parse_result parse_dot(
|
||||
@@ -496,10 +620,16 @@ static struct token_parse_result parse_dot(
|
||||
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
|
||||
}
|
||||
|
||||
enum ivy_status status = finalise_expr(state);
|
||||
struct ivy_ast_node *expr_tree = NULL;
|
||||
enum ivy_status status = finalise_expr(state, &expr_tree);
|
||||
|
||||
if (status != IVY_OK) {
|
||||
return PARSE_RESULT(status, 0);
|
||||
}
|
||||
|
||||
parser_replace_current_node(ctx, expr_tree);
|
||||
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
|
||||
return PARSE_RESULT(status, 0);
|
||||
return PARSE_RESULT(IVY_OK, 0);
|
||||
}
|
||||
|
||||
static struct token_parse_result parse_caret(
|
||||
|
||||
@@ -146,18 +146,21 @@ token_parse_function get_token_parser(
|
||||
return better_parser ? better_parser : generic_parser;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *ast_node_create_with_size(
|
||||
enum ivy_ast_node_type type, size_t size)
|
||||
struct ivy_ast_node *ast_node_create(enum ivy_ast_node_type type)
|
||||
{
|
||||
struct ivy_ast_node *node = malloc(size);
|
||||
const struct ast_node_type *type_info = get_ast_node_type(type);
|
||||
if (!type_info) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *node = malloc(type_info->n_node_size);
|
||||
if (!node) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(node, 0x0, size);
|
||||
memset(node, 0x0, type_info->n_node_size);
|
||||
|
||||
node->n_type = type;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
#include <ivy/lang/ast.h>
|
||||
#include <ivy/lang/lex.h>
|
||||
|
||||
#define ast_node_create(type_id, type_struct) \
|
||||
((type_struct *)ast_node_create_with_size(type_id, sizeof(type_struct)))
|
||||
|
||||
struct parser_state;
|
||||
|
||||
#define PARSE_RESULT(status, flags) \
|
||||
@@ -72,8 +69,7 @@ extern const struct ast_node_type *get_ast_node_type(enum ivy_ast_node_type type
|
||||
extern token_parse_function get_token_parser(
|
||||
struct ivy_ast_node *context, struct ivy_token *tok);
|
||||
extern enum token_expr_type get_token_expr_type(struct ivy_token *tok);
|
||||
extern struct ivy_ast_node *ast_node_create_with_size(
|
||||
enum ivy_ast_node_type type, size_t size);
|
||||
extern struct ivy_ast_node *ast_node_create(enum ivy_ast_node_type type);
|
||||
extern enum ivy_status ast_node_add_child(
|
||||
struct ivy_ast_node *parent, struct ivy_ast_node *child);
|
||||
|
||||
|
||||
@@ -215,7 +215,9 @@ static void print(struct ivy_ast_node *node)
|
||||
fputc('-', stdout);
|
||||
break;
|
||||
default:
|
||||
fputc('?', stdout);
|
||||
/* this will occur if the selector is being used to send a
|
||||
message at runtime, rather than as part of a message
|
||||
handler definition. */
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,13 @@ static struct token_parse_result parse_class_keyword(
|
||||
return PARSE_RESULT(IVY_OK, 0);
|
||||
}
|
||||
|
||||
static struct token_parse_result parse_expr_begin(
|
||||
struct ivy_parser *ctx, struct ivy_token *tok)
|
||||
{
|
||||
parser_push_state(ctx, IVY_AST_EXPR);
|
||||
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
|
||||
}
|
||||
|
||||
static enum ivy_status add_child(
|
||||
struct ivy_ast_node *parent, struct ivy_ast_node *child)
|
||||
{
|
||||
@@ -55,4 +62,7 @@ struct ast_node_type unit_node_ops = {
|
||||
KW_PARSER(CLASS, parse_class_keyword),
|
||||
KW_PARSER(USE, parse_use_keyword),
|
||||
},
|
||||
.n_expr_parser = {
|
||||
.expr_begin = parse_expr_begin,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -63,7 +63,7 @@ struct ivy_ast_unit_node {
|
||||
|
||||
struct ivy_ast_op_node {
|
||||
struct ivy_ast_node n_base;
|
||||
enum ivy_operator_id n_op;
|
||||
const struct ivy_operator *n_op;
|
||||
struct ivy_ast_node *n_left; // NULL for unary operators.
|
||||
struct ivy_ast_node *n_right;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user