2 * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the University of California, Berkeley nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/queue.h>
34 #include "cfzy_list.h"
35 #include "cfzy_expr.h"
40 #define debug_printf(args...) fprintf(stderr, args)
42 #define debug_printf(args...) do { } while(0)
46 * Return the operator (or the variable name) of the root node of the
49 static const char *op_print(const struct cfzy_expr *exp)
51 switch (exp->optype) {
71 /* recursive function called by cfzy_expr_graph_dump() */
72 static void expr_dump_node(FILE *f, const struct cfzy_expr *exp, int level)
77 fprintf(f, "vertice %d %s:%p\n", level, op_print(exp), exp);
80 fprintf(f, "edge %p %p\n", exp, exp->left);
81 expr_dump_node(f, exp->left, level + 1);
85 fprintf(f, "edge %p %p\n", exp, exp->right);
86 expr_dump_node(f, exp->right, level + 1);
90 /* dump an expression graph in a file */
91 int cfzy_expr_graph_dump(const char *filename, const struct cfzy_expr *exp)
95 f = fopen(filename, "w");
98 expr_dump_node(f, exp, 0);
103 /* return true if it's a binary operator */
104 static int expr_is_bin_op(const struct cfzy_expr *exp)
106 if (exp->optype == OP_AND ||
107 exp->optype == OP_OR ||
108 exp->optype == OP_EQUAL)
114 * Dump the expression 'exp' as a string into the buffer 'buf' of
115 * length 'len'. The string is nul-terminated. Return the number of
116 * written bytes on success (not including \0), else return -1.
118 int cfzy_expr_to_str(const struct cfzy_expr *exp, char *buf, int len)
124 /* dump left expression if it's a binary operator (in case of
125 * unary operator, we only use the right child) */
126 if (expr_is_bin_op(exp)) {
127 n = cfzy_expr_to_str(exp->left, buf, len);
128 if (n == -1 || n >= len || len <= 0)
134 /* dump the operator */
135 if (expr_is_bin_op(exp))
136 n = snprintf(buf, len, " %s ", op_print(exp));
138 n = snprintf(buf, len, "%s", op_print(exp));
139 if (n == -1 || n >= len || len <= 0)
144 /* dump the right expression except if it's a variable */
145 if (exp->optype != OP_VAR) {
146 n = cfzy_expr_to_str(exp->right, buf, len);
147 if (n == -1 || n >= len || len <= 0)
153 /* close the bracket if needed */
154 if (exp->optype == OP_OBRACKET) {
155 n = snprintf(buf, len, ")");
156 if (n == -1 || n >= len || len <= 0)
162 return orig_len - len;
166 * Evaluate an expression. Return -1 on error, else the value of the
167 * expression (greater or equal to 0).
169 int cfzy_expr_eval(const struct cfzy_expr *exp,
170 int (*getvalue)(const char *, void *), void *opaque_arg)
172 switch (exp->optype) {
174 return cfzy_expr_eval(exp->left, getvalue, opaque_arg) ||
175 cfzy_expr_eval(exp->right, getvalue, opaque_arg);
177 return cfzy_expr_eval(exp->left, getvalue, opaque_arg) &&
178 cfzy_expr_eval(exp->right, getvalue, opaque_arg);
180 return cfzy_expr_eval(exp->left, getvalue, opaque_arg) ==
181 cfzy_expr_eval(exp->right, getvalue, opaque_arg);
183 return cfzy_expr_eval(exp->right, getvalue, opaque_arg);
185 return !cfzy_expr_eval(exp->right, getvalue, opaque_arg);
187 /* constants names (used for testing purposes) */
188 if (!strcmp("true", exp->varname))
190 if (!strcmp("false", exp->varname))
192 if (getvalue == NULL)
194 return getvalue(exp->varname, opaque_arg);
196 debug_printf("%s(): bad operator\n", __FUNCTION__);
201 /* The argument 'buf' is expression string that must start with an
202 * opening bracket '('. This function returns the len of the
203 * expression contained until we get the closing bracket corresponding
204 * to buf[0]. Return -1 on error. */
205 static int get_brac_len(const char *buf)
214 while(*s != '\0' && i != 0) {
228 * Allocate a new expression exp corresponding to the next characters
229 * in "buf". On success, a new expression exp is returned and the
230 * number of eaten characters is set in "eatlen". If the end of the
231 * string is reached, the expression exp contains the OP_EOF
232 * operator. On error, NULL is returned.
234 static struct cfzy_expr *get_next_op(const char *buf, unsigned *eatlen)
236 struct cfzy_expr *exp;
241 exp = malloc(sizeof(struct cfzy_expr));
244 memset(exp, 0, sizeof(*exp));
248 exp->optype = OP_EOF;
249 *eatlen = s - buf + 1;
252 exp->optype = OP_EOF;
253 *eatlen = s - buf + 1;
256 exp->optype = OP_OBRACKET;
257 *eatlen = s - buf + 1;
260 exp->optype = OP_CBRACKET;
261 *eatlen = s - buf + 1;
264 exp->optype = OP_NOT;
265 *eatlen = s - buf + 1;
268 exp->optype = OP_AND;
271 *eatlen = s - buf + 2;
277 *eatlen = s - buf + 2;
282 exp->optype = OP_EQUAL;
283 *eatlen = s - buf + 2;
286 /* a variable name must start with a letter */
292 /* It's a variable, get name */
293 while (isalnum(s[0]) || s[0] == '_')
296 exp->optype = OP_VAR;
299 /* alloc string for variable name */
301 exp->varname = malloc(len+1);
302 memcpy(exp->varname, buf, len);
303 exp->varname[len] = '\0';
312 * Parse the expression contained in s (which is a modifiable
313 * string). Return 0 on success, in this case the expression tree is
314 * returned in exp_ptr. On error, return -1.
316 static int expr_parse(char *s, struct cfzy_expr **exp_ptr)
318 struct cfzy_expr *top = NULL, *exp, *tmp;
322 debug_printf("parse <%s>\n", s);
333 /* get next operator/operand */
334 exp = get_next_op(s, &eatlen);
336 debug_printf("Parse error\n");
340 if (exp->optype == OP_EOF) {
346 debug_printf("New node: %s\n", op_print(exp));
347 switch (exp->optype) {
352 /* if it is the first node, error */
356 /* the rightest leaf must be a variable */
360 if (tmp->optype != OP_VAR)
363 /* if new node priority is lower than root
364 * node, it becomes the new root */
365 if (exp->optype < top->optype) {
371 /* exp is placed at the "rightest" leaf. Check
372 * that our parent is not a variable */
374 while (tmp->right && exp->optype > tmp->right->optype)
377 if (tmp->right == NULL)
380 exp->left = tmp->right;
385 /* if operator is an opening bracket,
386 * recursively call ourself with the
388 len = get_brac_len(s);
390 debug_printf("Cannot find closing bracket\n");
394 if (expr_parse(s+1, &exp->right) < 0)
396 if (exp->right == NULL)
401 /* if it is the first node */
407 /* exp is placed at the "rightest" leaf. Check
408 * that our parent is not a variable */
412 if (tmp->optype == OP_VAR)
419 /* if it is the first node */
425 /* exp is placed at the "rightest" leaf. Check
426 * that our parent is not a variable */
430 if (tmp->optype == OP_VAR)
436 /* should not happen */
437 debug_printf("Parse error\n");
447 /* the rightest leaf must be a variable */
451 if (tmp->optype != OP_VAR) {
452 debug_printf("Missing operand\n");
469 * Parse the expression contained in buf. Return an expression tree or
472 struct cfzy_expr *cfzy_expr_parse(const char *buf)
474 struct cfzy_expr *top;
482 ret = expr_parse(s, &top);
489 /* Free an expression tree */
490 void cfzy_expr_free(struct cfzy_expr *exp)
496 cfzy_expr_free(exp->left);
501 cfzy_expr_free(exp->right);
505 if (exp->varname != NULL)
511 /* recursive function called by cfzy_expr_get_vars() that browse the
512 * expr tree to fill the list */
514 expr_get_vars(const struct cfzy_expr *exp, struct cfzy_list_head *list)
516 struct cfzy_list_elt *e;
520 if (expr_get_vars(exp->left, list) < 0)
525 if (expr_get_vars(exp->right, list) < 0)
529 if (exp->optype != OP_VAR)
532 /* ignore true and false constants */
533 if (!strcmp(exp->varname, "true"))
535 if (!strcmp(exp->varname, "false"))
538 /* nothing to do if var is already in list */
539 TAILQ_FOREACH(e, list, next) {
540 if (!strcmp(e->ptr, exp->varname))
544 name = strdup(exp->varname);
548 if (cfzy_list_add_tail(list, name) < 0) {
556 /* Return a list containing all variables on which expression depend */
557 struct cfzy_list_head *cfzy_expr_get_vars(const struct cfzy_expr *exp)
559 struct cfzy_list_head *list;
561 list = cfzy_list_alloc();
565 if (expr_get_vars(exp, list) < 0) {
566 cfzy_list_free(list, free);