00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00037 #include <stdarg.h>
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <string.h>
00041
00042 #include "lcmaps_log.h"
00043 #include "pdl_rule.h"
00044 #include "pdl_policy.h"
00045 #include "pdl_variable.h"
00046
00047 const rule_t *top_rule=0;
00048 rule_t *last_rule=0;
00049 static BOOL add_new_rules = TRUE;
00050
00051 rule_t* _add_rule(const record_t* state, const record_t* true_branch, const record_t* false_branch);
00052 const rule_t* find_state(const rule_t* rule, const char* state);
00053 recursion_t has_recursion(const rule_t* rule, int* list, int unsigned depth, unsigned int* seen_rules);
00054 int find_insert_position(const int* list, const int rule_number, unsigned int high);
00055 unsigned int rule_number(const rule_t* rule);
00056 BOOL make_list(int* new_list, const int* list, const int rule_number, const unsigned int depth);
00057 unsigned int count_rules(const rule_t* rule);
00058 void update_list(unsigned int* rules, unsigned int rule);
00059 const rule_t* get_rule_number(unsigned int rule_num);
00060
00061
00065 void start_new_rules(void)
00066 {
00067
00068 top_rule = last_rule = 0;
00069 }
00070
00071
00078 void allow_new_rules(BOOL allow)
00079 {
00080 add_new_rules = allow;
00081 }
00082
00083
00093 rule_t* add_rule(record_t* state, record_t* true_branch,
00094 record_t* false_branch)
00095 {
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112 rule_t* rule = 0;
00113
00114 if (!(rule = _add_rule(state, true_branch, false_branch))) {
00115 free(state->string);
00116 if (true_branch) free(true_branch->string);
00117 if (false_branch) free(false_branch->string);
00118 }
00119
00120 free(state);
00121 if (true_branch) free(true_branch);
00122 if (false_branch) free(false_branch);
00123
00124 return rule;
00125 }
00126
00127
00151 rule_t* _add_rule(const record_t* state, const record_t* true_branch,
00152 const record_t* false_branch)
00153 {
00154 rule_t* rule;
00155 policy_t* policy;
00156
00157 if ((policy = find_policy(state->string))) {
00158 warning(PDL_ERROR, "Left hand side of a rule cannot be a policy; see also line %d.", policy->lineno);
00159 return 0;
00160 }
00161
00162
00163 if ((rule = (rule_t*)find_state(top_rule, state->string))) {
00164 warning(PDL_ERROR, "State '%s' is already in use. See line %d.\n", state->string, rule->lineno);
00165 return 0;
00166 }
00167
00168 if ((true_branch && (policy = find_policy(true_branch->string)))
00169 || (false_branch && (policy = find_policy(false_branch->string))))
00170 warning(PDL_ERROR, "Rule contians reference to a policy. This is currently not supported.");
00171
00172
00173
00174
00175
00176 if (!add_new_rules)
00177 return 0;
00178
00179 if (!(rule = (rule_t *)malloc(sizeof(rule_t)))) {
00180 warning(PDL_ERROR, "out of memory.");
00181 return 0;
00182 }
00183
00184 rule->state = state->string;
00185 rule->true_branch = true_branch ? true_branch->string : 0;
00186 rule->false_branch = false_branch ? false_branch->string : 0;
00187 rule->lineno = state->lineno;
00188 rule->next = 0;
00189
00190 if (top_rule)
00191 last_rule->next = rule;
00192 else
00193 top_rule = rule;
00194
00195 last_rule = rule;
00196
00197 return rule;
00198 }
00199
00200
00210 const rule_t* find_state(const rule_t* rule, const char* state)
00211 {
00212 if (!rule || !state)
00213 return 0;
00214
00215 while (rule && strcmp(state, rule->state))
00216 rule = rule->next;
00217
00218 return rule;
00219 }
00220
00221
00228 BOOL check_rule_for_recursion(const rule_t* rule)
00229 {
00230 unsigned int num_rules = count_rules(rule);
00231 unsigned int *rules;
00232 recursion_t rc;
00233 int i;
00234
00235 rules = (unsigned int*)calloc((num_rules+1), sizeof(*rules));
00236
00237 top_rule = rule;
00238
00239 rc = has_recursion(rule, 0, 0, rules);
00240
00241 if (rules[0] != num_rules) {
00242 int j=1;
00243 for (i=1; i<=num_rules; i++) {
00244 if (rules[j] != i) {
00245 lineno = get_rule_number(i-1)->lineno;
00246 warning(PDL_WARNING, "rule is not part of the chain.");
00247 } else
00248 j++;
00249 }
00250 }
00251
00252 free(rules);
00253
00254 return (rc & RECURSION) ? TRUE : FALSE;
00255 }
00256
00257
00265 unsigned int count_rules(const rule_t* rule)
00266 {
00267 unsigned int c=0;
00268
00269 while (rule) {
00270 c++;
00271 rule = rule->next;
00272 }
00273
00274 return c;
00275 }
00276
00277
00286 const rule_t* get_rule_number(unsigned int rule_num)
00287 {
00288 unsigned int i;
00289 const rule_t* r;
00290
00291 for (i=0, r=top_rule; r && i<rule_num; i++)
00292 r = r->next;
00293
00294 return r;
00295 }
00296
00297
00326 recursion_t has_recursion(const rule_t* rule, int* list, unsigned int depth,
00327 unsigned int* seen_rules)
00328 {
00329 unsigned int rule_num;
00330 recursion_t rc;
00331 int* new_list = 0;
00332
00333 ++depth;
00334
00335
00336
00337
00338
00339 if (!rule)
00340 return NO_RECURSION;
00341
00342
00343
00344
00345
00346 new_list = (int*)malloc(depth*sizeof(int));
00347 rc = NO_RECURSION;
00348 rule_num = rule_number(rule);
00349
00350
00351 update_list(seen_rules, rule_num);
00352
00353
00354
00355
00356
00357
00358
00359 if (make_list(new_list, list, rule_num, depth)) {
00360
00361 recursion_t rcl=rc, rcr=rc;
00362
00363
00364 if (rule->true_branch) {
00365 rcl = has_recursion(find_state(top_rule, rule->true_branch), new_list, depth, seen_rules);
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377 if ((rcl&RECURSION) && !(rcl&RECURSION_HANDLED)) {
00378 lineno = rule->lineno;
00379 if (rule->false_branch)
00380 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);
00381 else
00382 warning(PDL_ERROR, "rule %s -> %s causes infinite loop on transition %s.", rule->state, rule->true_branch, rule->true_branch);
00383
00384
00385
00386
00387
00388 rcl |= RECURSION_HANDLED;
00389 }
00390 }
00391
00392
00393 if (rule->false_branch) {
00394 rcr = has_recursion(find_state(top_rule, rule->false_branch), new_list, depth, seen_rules);
00395
00396 if ((rcr&RECURSION) && !(rcr&RECURSION_HANDLED)) {
00397 lineno = rule->lineno;
00398 if (rule->true_branch)
00399 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);
00400 else
00401 warning(PDL_ERROR, "rule ~%s -> %s causes infinite loop on transition %s.", rule->state, rule->false_branch, rule->false_branch);
00402
00403 rcr |= RECURSION_HANDLED;
00404 }
00405 }
00406
00407
00408
00409
00410
00411 rc = rcl|rcr;
00412 } else
00413
00414 rc = RECURSION;
00415
00416
00417
00418
00419
00420 free(new_list);
00421
00422 return rc;
00423 }
00424
00425
00433 unsigned int rule_number(const rule_t* rule)
00434 {
00435 int n;
00436 const rule_t* t;
00437
00438 for (n=0, t=top_rule; t; ++n, t=t->next) {
00439 if (t==rule) break;
00440 }
00441
00442 return n;
00443 }
00444
00445
00461 void update_list(unsigned int* rules, unsigned int rule)
00462 {
00463
00464 int p = 1 + find_insert_position(rules+1, rule, rules[0]);
00465
00466
00467 rule++;
00468
00469
00470 if (rules[p] != rule) {
00471 if (p <= rules[0])
00472 memmove(rules+p+1, rules+p, (1+rules[0]-p)*sizeof(unsigned int));
00473 rules[p] = rule;
00474
00475
00476
00477
00478
00479 rules[0]++;
00480 }
00481 }
00482
00483
00496 int find_insert_position(const int* list, const int rule_number, unsigned int high)
00497 {
00498 int low=0, mid;
00499
00500
00501
00502
00503
00504
00505 while (low<high) {
00506 mid = (low+high)/2;
00507
00508
00509 if (rule_number < list[mid])
00510 high = mid;
00511 else
00512 low = mid + 1;
00513 }
00514
00515
00516 return high;
00517 }
00518
00519
00534 BOOL make_list(int* new_list, const int* list, const int rule_number,
00535 const unsigned int depth)
00536 {
00537 int insert;
00538
00539 if (!list) {
00540 *new_list = rule_number;
00541 return TRUE;
00542 }
00543
00544 insert = find_insert_position(list, rule_number, depth-1);
00545
00546 if ((insert>0) && (list[insert-1] == rule_number))
00547 return FALSE;
00548
00549 memcpy(new_list, list, insert*sizeof(int));
00550 if ((depth-insert-1)>0)
00551 memcpy(new_list+insert+1, list+insert, (depth-insert-1)*sizeof(int));
00552
00553 new_list[insert] = rule_number;
00554
00555 return TRUE;
00556 }
00557
00558
00566 void reduce_rule(rule_t* rule)
00567 {
00568
00569
00570
00571
00572
00573 reduce_to_var(&rule->state, STATE);
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586 reduce_to_var(&rule->true_branch, TRUE_BRANCH);
00587
00588
00589 reduce_to_var(&rule->false_branch, FALSE_BRANCH);
00590 }
00591
00592
00593 const rule_t* get_rule(const char* rule, side_t side)
00594 {
00595 const rule_t* r = top_rule;
00596
00597 switch (side) {
00598 case left_side:
00599 while (r && (strcmp(r->state, rule)!=0)) {
00600 r = r->next;
00601 }
00602 break;
00603 case right_side:
00604 while (r && ((r->true_branch && (strcmp(r->true_branch, rule)!=0)) ||
00605 ((r->false_branch && strcmp(r->false_branch, rule)!=0)))) {
00606 r = r->next;
00607 }
00608 break;
00609 default:
00610 r = 0;
00611 }
00612
00613 return r;
00614 }
00615
00616
00623 void show_rules(const rule_t* rule)
00624 {
00625 while (rule) {
00626 if (rule->true_branch) {
00627 if (!rule->false_branch)
00628 lcmaps_log_debug(1, " %s -> %s\n", rule->state, rule->true_branch);
00629 else
00630 lcmaps_log_debug(1, " %s -> %s | %s\n", rule->state, rule->true_branch, rule->false_branch);
00631 } else
00632 lcmaps_log_debug(1, "~%s -> %s\n", rule->state, rule->false_branch);
00633
00634 rule = rule->next;
00635 }
00636 }
00637
00638
00645 void free_rules(rule_t* rule)
00646 {
00647 rule_t* tmp;
00648
00649 while (rule) {
00650 tmp = rule->next;
00651 free((char *)rule->state); rule->state = NULL;
00652 free((char *)rule->true_branch); rule->true_branch = NULL;
00653 free((char *)rule->false_branch); rule->false_branch = NULL;
00654 free((char *)rule);
00655 rule = tmp;
00656 }
00657 }
00658
00659
00666 const rule_t* get_top_rule(void)
00667 {
00668 return top_rule;
00669 }
00670
00671
00678 void set_top_rule(const rule_t* rule)
00679 {
00680 top_rule = rule;
00681 }