00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00030 #include <stdarg.h>
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034
00035 #include "lcmaps_log.h"
00036 #include "pdl_rule.h"
00037 #include "pdl_policy.h"
00038 #include "pdl_variable.h"
00039
00040 const rule_t *top_rule=0;
00041 rule_t *last_rule=0;
00042 static BOOL add_new_rules = TRUE;
00043
00044 rule_t* _add_rule(const record_t* state, const record_t* true_branch, const record_t* false_branch);
00045 const rule_t* find_state(const rule_t* rule, const char* state);
00046 recursion_t has_recursion(const rule_t* rule, int* list, int unsigned depth, unsigned int* seen_rules);
00047 int find_insert_position(const int* list, const int rule_number, unsigned int high);
00048 unsigned int rule_number(const rule_t* rule);
00049 BOOL make_list(int* new_list, const int* list, const int rule_number, const unsigned int depth);
00050 unsigned int count_rules(const rule_t* rule);
00051 void update_list(unsigned int* rules, unsigned int rule);
00052 const rule_t* get_rule_number(unsigned int rule_num);
00053
00054
00058 void start_new_rules(void)
00059 {
00060
00061 top_rule = last_rule = 0;
00062 }
00063
00064
00071 void allow_new_rules(BOOL allow)
00072 {
00073 add_new_rules = allow;
00074 }
00075
00076
00086 rule_t* add_rule(record_t* state, record_t* true_branch,
00087 record_t* false_branch)
00088 {
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105 rule_t* rule = 0;
00106
00107 if (!(rule = _add_rule(state, true_branch, false_branch))) {
00108 free(state->string);
00109 if (true_branch) free(true_branch->string);
00110 if (false_branch) free(false_branch->string);
00111 }
00112
00113 free(state);
00114 if (true_branch) free(true_branch);
00115 if (false_branch) free(false_branch);
00116
00117 return rule;
00118 }
00119
00120
00144 rule_t* _add_rule(const record_t* state, const record_t* true_branch,
00145 const record_t* false_branch)
00146 {
00147 rule_t* rule;
00148 policy_t* policy;
00149
00150 if ((policy = find_policy(state->string))) {
00151 warning(PDL_ERROR, "Left hand side of a rule cannot be a policy; see also line %d.", policy->lineno);
00152 return 0;
00153 }
00154
00155
00156 if ((rule = (rule_t*)find_state(top_rule, state->string))) {
00157 warning(PDL_ERROR, "State '%s' is already in use. See line %d.\n", state->string, rule->lineno);
00158 return 0;
00159 }
00160
00161 if ((true_branch && (policy = find_policy(true_branch->string)))
00162 || (false_branch && (policy = find_policy(false_branch->string))))
00163 warning(PDL_ERROR, "Rule contians reference to a policy. This is currently not supported.");
00164
00165
00166
00167
00168
00169 if (!add_new_rules)
00170 return 0;
00171
00172 if (!(rule = (rule_t *)malloc(sizeof(rule_t)))) {
00173 warning(PDL_ERROR, "out of memory.");
00174 return 0;
00175 }
00176
00177 rule->state = state->string;
00178 rule->true_branch = true_branch ? true_branch->string : 0;
00179 rule->false_branch = false_branch ? false_branch->string : 0;
00180 rule->lineno = state->lineno;
00181 rule->next = 0;
00182
00183 if (top_rule)
00184 last_rule->next = rule;
00185 else
00186 top_rule = rule;
00187
00188 last_rule = rule;
00189
00190 return rule;
00191 }
00192
00193
00202 const rule_t* find_state(const rule_t* rule, const char* state)
00203 {
00204 if (!rule || !state)
00205 return 0;
00206
00207 while (rule && strcmp(state, rule->state))
00208 rule = rule->next;
00209
00210 return rule;
00211 }
00212
00213
00220 BOOL check_rule_for_recursion(const rule_t* rule)
00221 {
00222 unsigned int num_rules = count_rules(rule);
00223 unsigned int *rules;
00224 recursion_t rc;
00225 int i;
00226
00227 rules = (unsigned int*)calloc((num_rules+1), sizeof(*rules));
00228
00229 top_rule = rule;
00230
00231 rc = has_recursion(rule, 0, 0, rules);
00232
00233 if (rules[0] != num_rules) {
00234 int j=1;
00235 for (i=1; i<=num_rules; i++) {
00236 if (rules[j] != i) {
00237 lineno = get_rule_number(i-1)->lineno;
00238 warning(PDL_WARNING, "rule is not part of the chain.");
00239 } else
00240 j++;
00241 }
00242 }
00243
00244 free(rules);
00245
00246 return (rc & RECURSION) ? TRUE : FALSE;
00247 }
00248
00249
00257 unsigned int count_rules(const rule_t* rule)
00258 {
00259 unsigned int c=0;
00260
00261 while (rule) {
00262 c++;
00263 rule = rule->next;
00264 }
00265
00266 return c;
00267 }
00268
00269
00278 const rule_t* get_rule_number(unsigned int rule_num)
00279 {
00280 unsigned int i;
00281 const rule_t* r;
00282
00283 for (i=0, r=top_rule; r && i<rule_num; i++)
00284 r = r->next;
00285
00286 return r;
00287 }
00288
00289
00318 recursion_t has_recursion(const rule_t* rule, int* list, unsigned int depth,
00319 unsigned int* seen_rules)
00320 {
00321 unsigned int rule_num;
00322 recursion_t rc;
00323 int* new_list = 0;
00324
00325 ++depth;
00326
00327
00328
00329
00330
00331 if (!rule)
00332 return NO_RECURSION;
00333
00334
00335
00336
00337
00338 new_list = (int*)malloc(depth*sizeof(int));
00339 rc = NO_RECURSION;
00340 rule_num = rule_number(rule);
00341
00342
00343 update_list(seen_rules, rule_num);
00344
00345
00346
00347
00348
00349
00350
00351 if (make_list(new_list, list, rule_num, depth)) {
00352
00353 recursion_t rcl=rc, rcr=rc;
00354
00355
00356 if (rule->true_branch) {
00357 rcl = has_recursion(find_state(top_rule, rule->true_branch), new_list, depth, seen_rules);
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369 if ((rcl&RECURSION) && !(rcl&RECURSION_HANDLED)) {
00370 lineno = rule->lineno;
00371 if (rule->false_branch)
00372 warning(PDL_ERROR, "rule %s -> %s | %s causes infinite loop on true transition %s.", rule->state, rule->true_branch, rule->false_branch, rule->true_branch);
00373 else
00374 warning(PDL_ERROR, "rule %s -> %s causes infinite loop on transition %s.", rule->state, rule->true_branch, rule->true_branch);
00375
00376
00377
00378
00379
00380 rcl |= RECURSION_HANDLED;
00381 }
00382 }
00383
00384
00385 if (rule->false_branch) {
00386 rcr = has_recursion(find_state(top_rule, rule->false_branch), new_list, depth, seen_rules);
00387
00388 if ((rcr&RECURSION) && !(rcr&RECURSION_HANDLED)) {
00389 lineno = rule->lineno;
00390 if (rule->true_branch)
00391 warning(PDL_ERROR, "rule %s -> %s | %s causes infinite loop on false transition %s.", rule->state, rule->true_branch, rule->false_branch, rule->false_branch);
00392 else
00393 warning(PDL_ERROR, "rule ~%s -> %s causes infinite loop on transition %s.", rule->state, rule->false_branch, rule->false_branch);
00394
00395 rcr |= RECURSION_HANDLED;
00396 }
00397 }
00398
00399
00400
00401
00402
00403 rc = rcl|rcr;
00404 } else
00405
00406 rc = RECURSION;
00407
00408
00409
00410
00411
00412 free(new_list);
00413
00414 return rc;
00415 }
00416
00417
00425 unsigned int rule_number(const rule_t* rule)
00426 {
00427 int n;
00428 const rule_t* t;
00429
00430 for (n=0, t=top_rule; t; ++n, t=t->next) {
00431 if (t==rule) break;
00432 }
00433
00434 return n;
00435 }
00436
00437
00453 void update_list(unsigned int* rules, unsigned int rule)
00454 {
00455
00456 int p = 1 + find_insert_position(rules+1, rule, rules[0]);
00457
00458
00459 rule++;
00460
00461
00462 if (rules[p] != rule) {
00463 if (p <= rules[0])
00464 memmove(rules+p+1, rules+p, (1+rules[0]-p)*sizeof(unsigned int));
00465 rules[p] = rule;
00466
00467
00468
00469
00470
00471 rules[0]++;
00472 }
00473 }
00474
00475
00488 int find_insert_position(const int* list, const int rule_number, unsigned int high)
00489 {
00490 int low=0, mid;
00491
00492
00493
00494
00495
00496
00497 while (low<high) {
00498 mid = (low+high)/2;
00499
00500
00501 if (rule_number < list[mid])
00502 high = mid;
00503 else
00504 low = mid + 1;
00505 }
00506
00507
00508 return high;
00509 }
00510
00511
00526 BOOL make_list(int* new_list, const int* list, const int rule_number,
00527 const unsigned int depth)
00528 {
00529 int insert;
00530
00531 if (!list) {
00532 *new_list = rule_number;
00533 return TRUE;
00534 }
00535
00536 insert = find_insert_position(list, rule_number, depth-1);
00537
00538 if ((insert>0) && (list[insert-1] == rule_number))
00539 return FALSE;
00540
00541 memcpy(new_list, list, insert*sizeof(int));
00542 if ((depth-insert-1)>0)
00543 memcpy(new_list+insert+1, list+insert, (depth-insert-1)*sizeof(int));
00544
00545 new_list[insert] = rule_number;
00546
00547 return TRUE;
00548 }
00549
00550
00558 void reduce_rule(rule_t* rule)
00559 {
00560
00561
00562
00563
00564
00565 reduce_to_var(&rule->state, STATE);
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578 reduce_to_var(&rule->true_branch, TRUE_BRANCH);
00579
00580
00581 reduce_to_var(&rule->false_branch, FALSE_BRANCH);
00582 }
00583
00584
00585 const rule_t* get_rule(const char* rule, side_t side)
00586 {
00587 const rule_t* r = top_rule;
00588
00589 switch (side) {
00590 case left_side:
00591 while (r && (strcmp(r->state, rule)!=0)) {
00592 r = r->next;
00593 }
00594 break;
00595 case right_side:
00596 while (r && ((r->true_branch && (strcmp(r->true_branch, rule)!=0)) ||
00597 ((r->false_branch && strcmp(r->false_branch, rule)!=0)))) {
00598 r = r->next;
00599 }
00600 break;
00601 default:
00602 r = 0;
00603 }
00604
00605 return r;
00606 }
00607
00608
00615 void show_rules(const rule_t* rule)
00616 {
00617 while (rule) {
00618 if (rule->true_branch) {
00619 if (!rule->false_branch)
00620 lcmaps_log_debug(1, " %s -> %s\n", rule->state, rule->true_branch);
00621 else
00622 lcmaps_log_debug(1, " %s -> %s | %s\n", rule->state, rule->true_branch, rule->false_branch);
00623 } else
00624 lcmaps_log_debug(1, "~%s -> %s\n", rule->state, rule->false_branch);
00625
00626 rule = rule->next;
00627 }
00628 }
00629
00630
00637 void free_rules(rule_t* rule)
00638 {
00639 rule_t* tmp;
00640
00641 while (rule) {
00642 tmp = rule->next;
00643 free((char *)rule->state);
00644 free((char *)rule->true_branch);
00645 free((char *)rule->false_branch);
00646 free((char *)rule);
00647 rule = tmp;
00648 }
00649 }
00650
00651
00658 const rule_t* get_top_rule(void)
00659 {
00660 return top_rule;
00661 }
00662
00663
00670 void set_top_rule(const rule_t* rule)
00671 {
00672 top_rule = rule;
00673 }