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 }