| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- /**
- * @file BPredicate.c
- * @author Ambroz Bizjak <ambrop7@gmail.com>
- *
- * @section LICENSE
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <misc/debug.h>
- #include <misc/offset.h>
- #include <misc/balloc.h>
- #include <predicate/BPredicate_internal.h>
- #include <predicate/BPredicate_parser.h>
- #include <predicate/LexMemoryBufferInput.h>
- #include <base/BLog.h>
- #include <predicate/BPredicate.h>
- #include <generated/blog_channel_BPredicate.h>
- static int eval_predicate_node (BPredicate *p, struct predicate_node *root);
- void yyerror (YYLTYPE *yylloc, yyscan_t scanner, struct predicate_node **result, char *str)
- {
- }
- static int string_comparator (void *user, char *s1, char *s2)
- {
- int cmp = strcmp(s1, s2);
- if (cmp < 0) {
- return -1;
- }
- if (cmp > 0) {
- return 1;
- }
- return 0;
- }
- static int eval_function (BPredicate *p, struct predicate_node *root)
- {
- ASSERT(root->type == NODE_FUNCTION)
-
- // lookup function by name
- ASSERT(root->function.name)
- BAVLNode *tree_node;
- if (!(tree_node = BAVL_LookupExact(&p->functions_tree, root->function.name))) {
- BLog(BLOG_WARNING, "unknown function");
- return 0;
- }
- BPredicateFunction *func = UPPER_OBJECT(tree_node, BPredicateFunction, tree_node);
-
- // evaluate arguments
- struct arguments_node *arg = root->function.args;
- void *args[PREDICATE_MAX_ARGS];
- for (int i = 0; i < func->num_args; i++) {
- if (!arg) {
- BLog(BLOG_WARNING, "not enough arguments");
- return 0;
- }
- switch (func->args[i]) {
- case PREDICATE_TYPE_BOOL:
- if (arg->arg.type != ARGUMENT_PREDICATE) {
- BLog(BLOG_WARNING, "expecting predicate argument");
- return 0;
- }
- if (!eval_predicate_node(p, arg->arg.predicate)) {
- return 0;
- }
- args[i] = &arg->arg.predicate->eval_value;
- break;
- case PREDICATE_TYPE_STRING:
- if (arg->arg.type != ARGUMENT_STRING) {
- BLog(BLOG_WARNING, "expecting string argument");
- return 0;
- }
- args[i] = arg->arg.string;
- break;
- default:
- ASSERT(0);
- }
- arg = arg->next;
- }
-
- if (arg) {
- BLog(BLOG_WARNING, "too many arguments");
- return 0;
- }
-
- // call callback
- #ifndef NDEBUG
- p->in_function = 1;
- #endif
- int res = func->callback(func->user, args);
- #ifndef NDEBUG
- p->in_function = 0;
- #endif
- if (res != 0 && res != 1) {
- BLog(BLOG_WARNING, "callback returned non-boolean");
- return 0;
- }
-
- root->eval_value = res;
- return 1;
- }
- int eval_predicate_node (BPredicate *p, struct predicate_node *root)
- {
- ASSERT(root)
-
- switch (root->type) {
- case NODE_CONSTANT:
- root->eval_value = root->constant.val;
- return 1;
- case NODE_NEG:
- if (!eval_predicate_node(p, root->neg.op)) {
- return 0;
- }
- root->eval_value = !root->neg.op->eval_value;
- return 1;
- case NODE_CONJUNCT:
- if (!eval_predicate_node(p, root->conjunct.op1)) {
- return 0;
- }
- if (!root->conjunct.op1->eval_value) {
- root->eval_value = 0;
- return 1;
- }
- if (!eval_predicate_node(p, root->conjunct.op2)) {
- return 0;
- }
- if (!root->conjunct.op2->eval_value) {
- root->eval_value = 0;
- return 1;
- }
- root->eval_value = 1;
- return 1;
- case NODE_DISJUNCT:
- if (!eval_predicate_node(p, root->disjunct.op1)) {
- return 0;
- }
- if (root->disjunct.op1->eval_value) {
- root->eval_value = 1;
- return 1;
- }
- if (!eval_predicate_node(p, root->disjunct.op2)) {
- return 0;
- }
- if (root->disjunct.op2->eval_value) {
- root->eval_value = 1;
- return 1;
- }
- root->eval_value = 0;
- return 1;
- case NODE_FUNCTION:
- return eval_function(p, root);
- default:
- ASSERT(0)
- return 0;
- }
- }
- int BPredicate_Init (BPredicate *p, char *str)
- {
- // initialize input buffer object
- LexMemoryBufferInput input;
- LexMemoryBufferInput_Init(&input, str, strlen(str));
-
- // initialize lexical analyzer
- yyscan_t scanner;
- yylex_init_extra(&input, &scanner);
-
- // parse
- struct predicate_node *root = NULL;
- int result = yyparse(scanner, &root);
-
- // free lexical analyzer
- yylex_destroy(scanner);
-
- // check for errors
- if (LexMemoryBufferInput_HasError(&input) || result != 0 || !root) {
- if (root) {
- free_predicate_node(root);
- }
- return 0;
- }
-
- // init tree
- p->root = root;
-
- // init functions tree
- BAVL_Init(&p->functions_tree, OFFSET_DIFF(BPredicateFunction, name, tree_node), (BAVL_comparator)string_comparator, NULL);
-
- // init debuggind
- #ifndef NDEBUG
- p->in_function = 0;
- #endif
-
- // init debug object
- DebugObject_Init(&p->d_obj);
-
- return 1;
- }
- void BPredicate_Free (BPredicate *p)
- {
- ASSERT(BAVL_IsEmpty(&p->functions_tree))
- ASSERT(!p->in_function)
-
- // free debug object
- DebugObject_Free(&p->d_obj);
-
- // free tree
- free_predicate_node(p->root);
- }
- int BPredicate_Eval (BPredicate *p)
- {
- ASSERT(!p->in_function)
-
- if (!eval_predicate_node(p, p->root)) {
- return -1;
- }
-
- return ((struct predicate_node *)p->root)->eval_value;
- }
- void BPredicateFunction_Init (BPredicateFunction *o, BPredicate *p, char *name, int *args, int num_args, BPredicate_callback callback, void *user)
- {
- ASSERT(strlen(name) <= PREDICATE_MAX_NAME)
- ASSERT(!BAVL_LookupExact(&p->functions_tree, name))
- ASSERT(num_args >= 0)
- ASSERT(num_args <= PREDICATE_MAX_ARGS)
- for (int i = 0; i < num_args; i++) {
- ASSERT(args[i] == PREDICATE_TYPE_BOOL || args[i] == PREDICATE_TYPE_STRING)
- }
- ASSERT(!p->in_function)
-
- // init arguments
- o->p = p;
- strcpy(o->name, name);
- memcpy(o->args, args, num_args * sizeof(int));
- o->num_args = num_args;
- o->callback = callback;
- o->user = user;
-
- // add to tree
- ASSERT_EXECUTE(BAVL_Insert(&p->functions_tree, &o->tree_node, NULL))
-
- // init debug object
- DebugObject_Init(&o->d_obj);
- }
- void BPredicateFunction_Free (BPredicateFunction *o)
- {
- ASSERT(!o->p->in_function)
-
- BPredicate *p = o->p;
-
- // free debug object
- DebugObject_Free(&o->d_obj);
-
- // remove from tree
- BAVL_Remove(&p->functions_tree, &o->tree_node);
- }
|