BPredicate.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /**
  2. * @file BPredicate.c
  3. * @author Ambroz Bizjak <ambrop7@gmail.com>
  4. *
  5. * @section LICENSE
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the author nor the
  15. * names of its contributors may be used to endorse or promote products
  16. * derived from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. #include <stdlib.h>
  30. #include <stdio.h>
  31. #include <string.h>
  32. #include <misc/debug.h>
  33. #include <misc/offset.h>
  34. #include <misc/balloc.h>
  35. #include <misc/compare.h>
  36. #include <predicate/BPredicate_internal.h>
  37. #include <predicate/BPredicate_parser.h>
  38. #include <predicate/LexMemoryBufferInput.h>
  39. #include <base/BLog.h>
  40. #include <predicate/BPredicate.h>
  41. #include <generated/blog_channel_BPredicate.h>
  42. static int eval_predicate_node (BPredicate *p, struct predicate_node *root);
  43. void yyerror (YYLTYPE *yylloc, yyscan_t scanner, struct predicate_node **result, char *str)
  44. {
  45. }
  46. static int string_comparator (void *user, char *s1, char *s2)
  47. {
  48. int cmp = strcmp(s1, s2);
  49. return B_COMPARE(cmp, 0);
  50. }
  51. static int eval_function (BPredicate *p, struct predicate_node *root)
  52. {
  53. ASSERT(root->type == NODE_FUNCTION)
  54. // lookup function by name
  55. ASSERT(root->function.name)
  56. BAVLNode *tree_node;
  57. if (!(tree_node = BAVL_LookupExact(&p->functions_tree, root->function.name))) {
  58. BLog(BLOG_WARNING, "unknown function");
  59. return 0;
  60. }
  61. BPredicateFunction *func = UPPER_OBJECT(tree_node, BPredicateFunction, tree_node);
  62. // evaluate arguments
  63. struct arguments_node *arg = root->function.args;
  64. void *args[PREDICATE_MAX_ARGS];
  65. for (int i = 0; i < func->num_args; i++) {
  66. if (!arg) {
  67. BLog(BLOG_WARNING, "not enough arguments");
  68. return 0;
  69. }
  70. switch (func->args[i]) {
  71. case PREDICATE_TYPE_BOOL:
  72. if (arg->arg.type != ARGUMENT_PREDICATE) {
  73. BLog(BLOG_WARNING, "expecting predicate argument");
  74. return 0;
  75. }
  76. if (!eval_predicate_node(p, arg->arg.predicate)) {
  77. return 0;
  78. }
  79. args[i] = &arg->arg.predicate->eval_value;
  80. break;
  81. case PREDICATE_TYPE_STRING:
  82. if (arg->arg.type != ARGUMENT_STRING) {
  83. BLog(BLOG_WARNING, "expecting string argument");
  84. return 0;
  85. }
  86. args[i] = arg->arg.string;
  87. break;
  88. default:
  89. ASSERT(0);
  90. }
  91. arg = arg->next;
  92. }
  93. if (arg) {
  94. BLog(BLOG_WARNING, "too many arguments");
  95. return 0;
  96. }
  97. // call callback
  98. #ifndef NDEBUG
  99. p->in_function = 1;
  100. #endif
  101. int res = func->callback(func->user, args);
  102. #ifndef NDEBUG
  103. p->in_function = 0;
  104. #endif
  105. if (res != 0 && res != 1) {
  106. BLog(BLOG_WARNING, "callback returned non-boolean");
  107. return 0;
  108. }
  109. root->eval_value = res;
  110. return 1;
  111. }
  112. int eval_predicate_node (BPredicate *p, struct predicate_node *root)
  113. {
  114. ASSERT(root)
  115. switch (root->type) {
  116. case NODE_CONSTANT:
  117. root->eval_value = root->constant.val;
  118. return 1;
  119. case NODE_NEG:
  120. if (!eval_predicate_node(p, root->neg.op)) {
  121. return 0;
  122. }
  123. root->eval_value = !root->neg.op->eval_value;
  124. return 1;
  125. case NODE_CONJUNCT:
  126. if (!eval_predicate_node(p, root->conjunct.op1)) {
  127. return 0;
  128. }
  129. if (!root->conjunct.op1->eval_value) {
  130. root->eval_value = 0;
  131. return 1;
  132. }
  133. if (!eval_predicate_node(p, root->conjunct.op2)) {
  134. return 0;
  135. }
  136. if (!root->conjunct.op2->eval_value) {
  137. root->eval_value = 0;
  138. return 1;
  139. }
  140. root->eval_value = 1;
  141. return 1;
  142. case NODE_DISJUNCT:
  143. if (!eval_predicate_node(p, root->disjunct.op1)) {
  144. return 0;
  145. }
  146. if (root->disjunct.op1->eval_value) {
  147. root->eval_value = 1;
  148. return 1;
  149. }
  150. if (!eval_predicate_node(p, root->disjunct.op2)) {
  151. return 0;
  152. }
  153. if (root->disjunct.op2->eval_value) {
  154. root->eval_value = 1;
  155. return 1;
  156. }
  157. root->eval_value = 0;
  158. return 1;
  159. case NODE_FUNCTION:
  160. return eval_function(p, root);
  161. default:
  162. ASSERT(0)
  163. return 0;
  164. }
  165. }
  166. int BPredicate_Init (BPredicate *p, char *str)
  167. {
  168. // initialize input buffer object
  169. LexMemoryBufferInput input;
  170. LexMemoryBufferInput_Init(&input, str, strlen(str));
  171. // initialize lexical analyzer
  172. yyscan_t scanner;
  173. yylex_init_extra(&input, &scanner);
  174. // parse
  175. struct predicate_node *root = NULL;
  176. int result = yyparse(scanner, &root);
  177. // free lexical analyzer
  178. yylex_destroy(scanner);
  179. // check for errors
  180. if (LexMemoryBufferInput_HasError(&input) || result != 0 || !root) {
  181. if (root) {
  182. free_predicate_node(root);
  183. }
  184. return 0;
  185. }
  186. // init tree
  187. p->root = root;
  188. // init functions tree
  189. BAVL_Init(&p->functions_tree, OFFSET_DIFF(BPredicateFunction, name, tree_node), (BAVL_comparator)string_comparator, NULL);
  190. // init debuggind
  191. #ifndef NDEBUG
  192. p->in_function = 0;
  193. #endif
  194. // init debug object
  195. DebugObject_Init(&p->d_obj);
  196. return 1;
  197. }
  198. void BPredicate_Free (BPredicate *p)
  199. {
  200. ASSERT(BAVL_IsEmpty(&p->functions_tree))
  201. ASSERT(!p->in_function)
  202. // free debug object
  203. DebugObject_Free(&p->d_obj);
  204. // free tree
  205. free_predicate_node((struct predicate_node *)p->root);
  206. }
  207. int BPredicate_Eval (BPredicate *p)
  208. {
  209. ASSERT(!p->in_function)
  210. if (!eval_predicate_node(p, (struct predicate_node *)p->root)) {
  211. return -1;
  212. }
  213. return ((struct predicate_node *)p->root)->eval_value;
  214. }
  215. void BPredicateFunction_Init (BPredicateFunction *o, BPredicate *p, char *name, int *args, int num_args, BPredicate_callback callback, void *user)
  216. {
  217. ASSERT(strlen(name) <= PREDICATE_MAX_NAME)
  218. ASSERT(!BAVL_LookupExact(&p->functions_tree, name))
  219. ASSERT(num_args >= 0)
  220. ASSERT(num_args <= PREDICATE_MAX_ARGS)
  221. for (int i = 0; i < num_args; i++) {
  222. ASSERT(args[i] == PREDICATE_TYPE_BOOL || args[i] == PREDICATE_TYPE_STRING)
  223. }
  224. ASSERT(!p->in_function)
  225. // init arguments
  226. o->p = p;
  227. strcpy(o->name, name);
  228. memcpy(o->args, args, num_args * sizeof(int));
  229. o->num_args = num_args;
  230. o->callback = callback;
  231. o->user = user;
  232. // add to tree
  233. ASSERT_EXECUTE(BAVL_Insert(&p->functions_tree, &o->tree_node, NULL))
  234. // init debug object
  235. DebugObject_Init(&o->d_obj);
  236. }
  237. void BPredicateFunction_Free (BPredicateFunction *o)
  238. {
  239. ASSERT(!o->p->in_function)
  240. BPredicate *p = o->p;
  241. // free debug object
  242. DebugObject_Free(&o->d_obj);
  243. // remove from tree
  244. BAVL_Remove(&p->functions_tree, &o->tree_node);
  245. }