1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
14 #include <ecoli_malloc.h>
15 #include <ecoli_log.h>
16 #include <ecoli_test.h>
17 #include <ecoli_strvec.h>
18 #include <ecoli_node.h>
19 #include <ecoli_parse.h>
20 #include <ecoli_complete.h>
21 #include <ecoli_node_seq.h>
22 #include <ecoli_node_many.h>
23 #include <ecoli_node_or.h>
24 #include <ecoli_node_expr.h>
26 EC_LOG_TYPE_REGISTER(node_expr);
32 struct ec_node *child;
34 /* the configuration nodes */
35 struct ec_node *val_node;
36 struct ec_node **bin_ops;
37 unsigned int bin_ops_len;
38 struct ec_node **pre_ops;
39 unsigned int pre_ops_len;
40 struct ec_node **post_ops;
41 unsigned int post_ops_len;
42 struct ec_node **open_ops;
43 struct ec_node **close_ops;
44 unsigned int paren_len;
47 static int ec_node_expr_parse(const struct ec_node *gen_node,
48 struct ec_parse *state,
49 const struct ec_strvec *strvec)
51 struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
53 if (node->child == NULL) {
58 return ec_node_parse_child(node->child, state, strvec);
62 ec_node_expr_complete(const struct ec_node *gen_node,
64 const struct ec_strvec *strvec)
66 struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
68 if (node->child == NULL) {
73 return ec_node_complete_child(node->child, comp, strvec);
76 static void ec_node_expr_free_priv(struct ec_node *gen_node)
78 struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
81 EC_LOG(EC_LOG_DEBUG, "free %p %p %p\n", node, node->child, node->val_node);
82 ec_node_free(node->val_node);
84 for (i = 0; i < node->bin_ops_len; i++)
85 ec_node_free(node->bin_ops[i]);
86 ec_free(node->bin_ops);
87 for (i = 0; i < node->pre_ops_len; i++)
88 ec_node_free(node->pre_ops[i]);
89 ec_free(node->pre_ops);
90 for (i = 0; i < node->post_ops_len; i++)
91 ec_node_free(node->post_ops[i]);
92 ec_free(node->post_ops);
93 for (i = 0; i < node->paren_len; i++) {
94 ec_node_free(node->open_ops[i]);
95 ec_node_free(node->close_ops[i]);
97 ec_free(node->open_ops);
98 ec_free(node->close_ops);
100 ec_node_free(node->child);
103 static int ec_node_expr_build(struct ec_node_expr *node)
105 struct ec_node *term = NULL, *expr = NULL, *next = NULL,
106 *pre_op = NULL, *post_op = NULL, *ref = NULL,
110 ec_node_free(node->child);
113 if (node->val_node == NULL) {
118 if (node->bin_ops_len == 0 && node->pre_ops_len == 0 &&
119 node->post_ops_len == 0) {
125 * Example of created grammar:
132 * term = post post_op*
133 * prod = term ( "*" term )*
134 * sum = prod ( "+" prod )*
138 /* we use this as a ref, will be set later */
139 ref = ec_node("seq", "ref");
143 /* prefix unary operators */
144 pre_op = ec_node("or", "pre-op");
147 for (i = 0; i < node->pre_ops_len; i++) {
148 if (ec_node_or_add(pre_op, ec_node_clone(node->pre_ops[i])) < 0)
152 /* suffix unary operators */
153 post_op = ec_node("or", "post-op");
156 for (i = 0; i < node->post_ops_len; i++) {
157 if (ec_node_or_add(post_op, ec_node_clone(node->post_ops[i])) < 0)
161 post = ec_node("or", "post");
164 if (ec_node_or_add(post, ec_node_clone(node->val_node)) < 0)
166 if (ec_node_or_add(post,
167 EC_NODE_SEQ(EC_NO_ID,
168 ec_node_clone(pre_op),
169 ec_node_clone(ref))) < 0)
171 for (i = 0; i < node->paren_len; i++) {
172 if (ec_node_or_add(post, EC_NODE_SEQ(EC_NO_ID,
173 ec_node_clone(node->open_ops[i]),
175 ec_node_clone(node->close_ops[i]))) < 0)
178 term = EC_NODE_SEQ("term",
180 ec_node_many(EC_NO_ID, ec_node_clone(post_op), 0, 0)
185 for (i = 0; i < node->bin_ops_len; i++) {
186 next = EC_NODE_SEQ("next",
188 ec_node_many(EC_NO_ID,
189 EC_NODE_SEQ(EC_NO_ID,
190 ec_node_clone(node->bin_ops[i]),
204 /* free the initial references */
205 ec_node_free(pre_op);
207 ec_node_free(post_op);
212 if (ec_node_seq_add(ref, ec_node_clone(expr)) < 0)
224 ec_node_free(pre_op);
225 ec_node_free(post_op);
232 static struct ec_node_type ec_node_expr_type = {
234 .parse = ec_node_expr_parse,
235 .complete = ec_node_expr_complete,
236 .size = sizeof(struct ec_node_expr),
237 .free_priv = ec_node_expr_free_priv,
240 EC_NODE_TYPE_REGISTER(ec_node_expr_type);
242 int ec_node_expr_set_val_node(struct ec_node *gen_node, struct ec_node *val_node)
244 struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
246 if (ec_node_check_type(gen_node, &ec_node_expr_type) < 0)
249 if (val_node == NULL) {
254 ec_node_free(node->val_node);
255 node->val_node = val_node;
256 ec_node_expr_build(node);
261 ec_node_free(val_node);
265 /* add a binary operator */
266 int ec_node_expr_add_bin_op(struct ec_node *gen_node, struct ec_node *op)
268 struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
269 struct ec_node **bin_ops;
271 if (ec_node_check_type(gen_node, &ec_node_expr_type) < 0)
274 if (node == NULL || op == NULL) {
279 bin_ops = ec_realloc(node->bin_ops,
280 (node->bin_ops_len + 1) * sizeof(*node->bin_ops));
284 node->bin_ops = bin_ops;
285 bin_ops[node->bin_ops_len] = op;
287 ec_node_expr_build(node);
296 /* add a unary pre-operator */
297 int ec_node_expr_add_pre_op(struct ec_node *gen_node, struct ec_node *op)
299 struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
300 struct ec_node **pre_ops;
302 if (ec_node_check_type(gen_node, &ec_node_expr_type) < 0)
305 if (node == NULL || op == NULL) {
310 pre_ops = ec_realloc(node->pre_ops,
311 (node->pre_ops_len + 1) * sizeof(*node->pre_ops));
315 node->pre_ops = pre_ops;
316 pre_ops[node->pre_ops_len] = op;
318 ec_node_expr_build(node);
327 /* add a unary post-operator */
328 int ec_node_expr_add_post_op(struct ec_node *gen_node, struct ec_node *op)
330 struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
331 struct ec_node **post_ops;
333 if (ec_node_check_type(gen_node, &ec_node_expr_type) < 0)
336 if (node == NULL || op == NULL) {
341 post_ops = ec_realloc(node->post_ops,
342 (node->post_ops_len + 1) * sizeof(*node->post_ops));
343 if (post_ops == NULL)
346 node->post_ops = post_ops;
347 post_ops[node->post_ops_len] = op;
348 node->post_ops_len++;
349 ec_node_expr_build(node);
358 /* add parenthesis symbols */
359 int ec_node_expr_add_parenthesis(struct ec_node *gen_node,
360 struct ec_node *open, struct ec_node *close)
362 struct ec_node_expr *node = (struct ec_node_expr *)gen_node;
363 struct ec_node **open_ops, **close_ops;
365 if (ec_node_check_type(gen_node, &ec_node_expr_type) < 0)
368 if (node == NULL || open == NULL || close == NULL) {
373 open_ops = ec_realloc(node->open_ops,
374 (node->paren_len + 1) * sizeof(*node->open_ops));
375 if (open_ops == NULL)
377 close_ops = ec_realloc(node->close_ops,
378 (node->paren_len + 1) * sizeof(*node->close_ops));
379 if (close_ops == NULL)
382 node->open_ops = open_ops;
383 node->close_ops = close_ops;
384 open_ops[node->paren_len] = open;
385 close_ops[node->paren_len] = close;
387 ec_node_expr_build(node);
397 enum expr_node_type {
407 static enum expr_node_type get_node_type(const struct ec_node *expr_gen_node,
408 const struct ec_node *check)
410 struct ec_node_expr *expr_node = (struct ec_node_expr *)expr_gen_node;
413 if (check == expr_node->val_node)
416 for (i = 0; i < expr_node->bin_ops_len; i++) {
417 if (check == expr_node->bin_ops[i])
420 for (i = 0; i < expr_node->pre_ops_len; i++) {
421 if (check == expr_node->pre_ops[i])
424 for (i = 0; i < expr_node->post_ops_len; i++) {
425 if (check == expr_node->post_ops[i])
429 for (i = 0; i < expr_node->paren_len; i++) {
430 if (check == expr_node->open_ops[i])
433 for (i = 0; i < expr_node->paren_len; i++) {
434 if (check == expr_node->close_ops[i])
444 const struct ec_parse *op;
445 enum expr_node_type op_type;
448 /* merge x and y results in x */
449 static int merge_results(void *userctx,
450 const struct ec_node_expr_eval_ops *ops,
451 struct result *x, const struct result *y)
453 if (y->has_val == 0 && y->op == NULL)
455 if (x->has_val == 0 && x->op == NULL) {
460 if (x->has_val && y->has_val && y->op != NULL) {
461 if (y->op_type == BIN_OP) {
462 if (ops->eval_bin_op(&x->val, userctx, x->val,
470 if (x->has_val == 0 && x->op != NULL && y->has_val && y->op == NULL) {
471 if (x->op_type == PRE_OP) {
472 if (ops->eval_pre_op(&x->val, userctx, y->val,
479 } else if (x->op_type == BIN_OP) {
486 if (x->has_val && x->op == NULL && y->has_val == 0 && y->op != NULL) {
487 if (ops->eval_post_op(&x->val, userctx, x->val, y->op) < 0)
493 assert(false); /* we should not get here */
497 static int eval_expression(struct result *result,
499 const struct ec_node_expr_eval_ops *ops,
500 const struct ec_node *expr_gen_node,
501 const struct ec_parse *parse)
504 struct ec_parse *open = NULL, *close = NULL;
505 struct result child_result;
506 struct ec_parse *child;
507 enum expr_node_type type;
509 memset(result, 0, sizeof(*result));
510 memset(&child_result, 0, sizeof(child_result));
512 type = get_node_type(expr_gen_node, ec_parse_get_node(parse));
514 if (ops->eval_var(&result->val, userctx, parse) < 0)
517 } else if (type == PRE_OP || type == POST_OP || type == BIN_OP) {
519 result->op_type = type;
522 EC_PARSE_FOREACH_CHILD(child, parse) {
524 type = get_node_type(expr_gen_node, ec_parse_get_node(child));
525 if (type == PAREN_OPEN) {
528 } else if (type == PAREN_CLOSE) {
533 if (eval_expression(&child_result, userctx, ops,
534 expr_gen_node, child) < 0)
537 if (merge_results(userctx, ops, result, &child_result) < 0)
540 memset(&child_result, 0, sizeof(child_result));
543 if (open != NULL && close != NULL) {
544 if (ops->eval_parenthesis(&result->val, userctx, open, close,
553 ops->eval_free(result->val, userctx);
554 if (child_result.has_val)
555 ops->eval_free(child_result.val, userctx);
556 memset(result, 0, sizeof(*result));
561 int ec_node_expr_eval(void **user_result, const struct ec_node *node,
562 struct ec_parse *parse, const struct ec_node_expr_eval_ops *ops,
565 struct result result;
567 if (ops == NULL || ops->eval_var == NULL || ops->eval_pre_op == NULL ||
568 ops->eval_post_op == NULL || ops->eval_bin_op == NULL ||
569 ops->eval_parenthesis == NULL ||
570 ops->eval_free == NULL) {
575 if (ec_node_check_type(node, &ec_node_expr_type) < 0)
578 if (!ec_parse_matches(parse)) {
583 if (eval_expression(&result, userctx, ops, node, parse) < 0)
586 assert(result.has_val);
587 assert(result.op == NULL);
588 *user_result = result.val;
593 /* the test case is in a separate file ecoli_node_expr_test.c */