BPredicate.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  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 <predicate/BPredicate_internal.h>
  36. #include <predicate/BPredicate_parser.h>
  37. #include <predicate/LexMemoryBufferInput.h>
  38. #include <base/BLog.h>
  39. #include <predicate/BPredicate.h>
  40. #include <generated/blog_channel_BPredicate.h>
  41. static int eval_predicate_node (BPredicate *p, struct predicate_node *root);
  42. void yyerror (YYLTYPE *yylloc, yyscan_t scanner, struct predicate_node **result, char *str)
  43. {
  44. }
  45. static int string_comparator (void *user, char *s1, char *s2)
  46. {
  47. int cmp = strcmp(s1, s2);
  48. if (cmp < 0) {
  49. return -1;
  50. }
  51. if (cmp > 0) {
  52. return 1;
  53. }
  54. return 0;
  55. }
  56. static int eval_function (BPredicate *p, struct predicate_node *root)
  57. {
  58. ASSERT(root->type == NODE_FUNCTION)
  59. // lookup function by name
  60. ASSERT(root->function.name)
  61. BAVLNode *tree_node;
  62. if (!(tree_node = BAVL_LookupExact(&p->functions_tree, root->function.name))) {
  63. BLog(BLOG_WARNING, "unknown function");
  64. return 0;
  65. }
  66. BPredicateFunction *func = UPPER_OBJECT(tree_node, BPredicateFunction, tree_node);
  67. // evaluate arguments
  68. struct arguments_node *arg = root->function.args;
  69. void *args[PREDICATE_MAX_ARGS];
  70. for (int i = 0; i < func->num_args; i++) {
  71. if (!arg) {
  72. BLog(BLOG_WARNING, "not enough arguments");
  73. return 0;
  74. }
  75. switch (func->args[i]) {
  76. case PREDICATE_TYPE_BOOL:
  77. if (arg->arg.type != ARGUMENT_PREDICATE) {
  78. BLog(BLOG_WARNING, "expecting predicate argument");
  79. return 0;
  80. }
  81. if (!eval_predicate_node(p, arg->arg.predicate)) {
  82. return 0;
  83. }
  84. args[i] = &arg->arg.predicate->eval_value;
  85. break;
  86. case PREDICATE_TYPE_STRING:
  87. if (arg->arg.type != ARGUMENT_STRING) {
  88. BLog(BLOG_WARNING, "expecting string argument");
  89. return 0;
  90. }
  91. args[i] = arg->arg.string;
  92. break;
  93. default:
  94. ASSERT(0);
  95. }
  96. arg = arg->next;
  97. }
  98. if (arg) {
  99. BLog(BLOG_WARNING, "too many arguments");
  100. return 0;
  101. }
  102. // call callback
  103. #ifndef NDEBUG
  104. p->in_function = 1;
  105. #endif
  106. int res = func->callback(func->user, args);
  107. #ifndef NDEBUG
  108. p->in_function = 0;
  109. #endif
  110. if (res != 0 && res != 1) {
  111. BLog(BLOG_WARNING, "callback returned non-boolean");
  112. return 0;
  113. }
  114. root->eval_value = res;
  115. return 1;
  116. }
  117. int eval_predicate_node (BPredicate *p, struct predicate_node *root)
  118. {
  119. ASSERT(root)
  120. switch (root->type) {
  121. case NODE_CONSTANT:
  122. root->eval_value = root->constant.val;
  123. return 1;
  124. case NODE_NEG:
  125. if (!eval_predicate_node(p, root->neg.op)) {
  126. return 0;
  127. }
  128. root->eval_value = !root->neg.op->eval_value;
  129. return 1;
  130. case NODE_CONJUNCT:
  131. if (!eval_predicate_node(p, root->conjunct.op1)) {
  132. return 0;
  133. }
  134. if (!root->conjunct.op1->eval_value) {
  135. root->eval_value = 0;
  136. return 1;
  137. }
  138. if (!eval_predicate_node(p, root->conjunct.op2)) {
  139. return 0;
  140. }
  141. if (!root->conjunct.op2->eval_value) {
  142. root->eval_value = 0;
  143. return 1;
  144. }
  145. root->eval_value = 1;
  146. return 1;
  147. case NODE_DISJUNCT:
  148. if (!eval_predicate_node(p, root->disjunct.op1)) {
  149. return 0;
  150. }
  151. if (root->disjunct.op1->eval_value) {
  152. root->eval_value = 1;
  153. return 1;
  154. }
  155. if (!eval_predicate_node(p, root->disjunct.op2)) {
  156. return 0;
  157. }
  158. if (root->disjunct.op2->eval_value) {
  159. root->eval_value = 1;
  160. return 1;
  161. }
  162. root->eval_value = 0;
  163. return 1;
  164. case NODE_FUNCTION:
  165. return eval_function(p, root);
  166. default:
  167. ASSERT(0)
  168. return 0;
  169. }
  170. }
  171. int BPredicate_Init (BPredicate *p, char *str)
  172. {
  173. // initialize input buffer object
  174. LexMemoryBufferInput input;
  175. LexMemoryBufferInput_Init(&input, str, strlen(str));
  176. // initialize lexical analyzer
  177. yyscan_t scanner;
  178. yylex_init_extra(&input, &scanner);
  179. // parse
  180. struct predicate_node *root = NULL;
  181. int result = yyparse(scanner, &root);
  182. // free lexical analyzer
  183. yylex_destroy(scanner);
  184. // check for errors
  185. if (LexMemoryBufferInput_HasError(&input) || result != 0 || !root) {
  186. if (root) {
  187. free_predicate_node(root);
  188. }
  189. return 0;
  190. }
  191. // init tree
  192. p->root = root;
  193. // init functions tree
  194. BAVL_Init(&p->functions_tree, OFFSET_DIFF(BPredicateFunction, name, tree_node), (BAVL_comparator)string_comparator, NULL);
  195. // init debuggind
  196. #ifndef NDEBUG
  197. p->in_function = 0;
  198. #endif
  199. // init debug object
  200. DebugObject_Init(&p->d_obj);
  201. return 1;
  202. }
  203. void BPredicate_Free (BPredicate *p)
  204. {
  205. ASSERT(BAVL_IsEmpty(&p->functions_tree))
  206. ASSERT(!p->in_function)
  207. // free debug object
  208. DebugObject_Free(&p->d_obj);
  209. // free tree
  210. free_predicate_node(p->root);
  211. }
  212. int BPredicate_Eval (BPredicate *p)
  213. {
  214. ASSERT(!p->in_function)
  215. if (!eval_predicate_node(p, p->root)) {
  216. return -1;
  217. }
  218. return ((struct predicate_node *)p->root)->eval_value;
  219. }
  220. void BPredicateFunction_Init (BPredicateFunction *o, BPredicate *p, char *name, int *args, int num_args, BPredicate_callback callback, void *user)
  221. {
  222. ASSERT(strlen(name) <= PREDICATE_MAX_NAME)
  223. ASSERT(!BAVL_LookupExact(&p->functions_tree, name))
  224. ASSERT(num_args >= 0)
  225. ASSERT(num_args <= PREDICATE_MAX_ARGS)
  226. for (int i = 0; i < num_args; i++) {
  227. ASSERT(args[i] == PREDICATE_TYPE_BOOL || args[i] == PREDICATE_TYPE_STRING)
  228. }
  229. ASSERT(!p->in_function)
  230. // init arguments
  231. o->p = p;
  232. strcpy(o->name, name);
  233. memcpy(o->args, args, num_args * sizeof(int));
  234. o->num_args = num_args;
  235. o->callback = callback;
  236. o->user = user;
  237. // add to tree
  238. ASSERT_EXECUTE(BAVL_Insert(&p->functions_tree, &o->tree_node, NULL))
  239. // init debug object
  240. DebugObject_Init(&o->d_obj);
  241. }
  242. void BPredicateFunction_Free (BPredicateFunction *o)
  243. {
  244. ASSERT(!o->p->in_function)
  245. BPredicate *p = o->p;
  246. // free debug object
  247. DebugObject_Free(&o->d_obj);
  248. // remove from tree
  249. BAVL_Remove(&p->functions_tree, &o->tree_node);
  250. }