00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047 #include "soarkernel.h"
00048 #include <ctype.h>
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 unsigned long placeholder_counter[26];
00065
00066 void reset_placeholder_variable_generator(void)
00067 {
00068 int i;
00069 for (i = 0; i < 26; i++)
00070 placeholder_counter[i] = 1;
00071 }
00072
00073
00074
00075
00076
00077
00078
00079
00080 #define NAMEBUF_SIZE 30
00081 test make_placeholder_test(char first_letter)
00082 {
00083 char namebuf[NAMEBUF_SIZE];
00084 Symbol *new_var;
00085
00086 if (isalpha(first_letter)) {
00087 if (isupper(first_letter))
00088 first_letter = (char) tolower(first_letter);
00089 } else {
00090 first_letter = 'v';
00091 }
00092
00093
00094 snprintf(namebuf, NAMEBUF_SIZE, "<#%c*%lu>", first_letter, placeholder_counter[first_letter - 'a']++);
00095 namebuf[NAMEBUF_SIZE - 1] = 0;
00096 new_var = make_variable(namebuf);
00097
00098 new_var->var.current_binding_value = NIL;
00099
00100 return make_equality_test_without_adding_reference(new_var);
00101 }
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119 void substitute_for_placeholders_in_symbol(Symbol ** sym)
00120 {
00121 char prefix[3];
00122 Symbol *var;
00123 bool just_created;
00124
00125
00126 if ((*sym)->common.symbol_type != VARIABLE_SYMBOL_TYPE)
00127 return;
00128
00129 if (*((*sym)->var.name + 1) != '#')
00130 return;
00131
00132 just_created = FALSE;
00133
00134 if (!(*sym)->var.current_binding_value) {
00135 prefix[0] = *((*sym)->var.name + 2);
00136 prefix[1] = '*';
00137 prefix[2] = 0;
00138 (*sym)->var.current_binding_value = generate_new_variable(prefix);
00139 just_created = TRUE;
00140 }
00141
00142 var = (*sym)->var.current_binding_value;
00143 symbol_remove_ref(*sym);
00144 *sym = var;
00145 if (!just_created)
00146 symbol_add_ref(var);
00147 }
00148
00149 void substitute_for_placeholders_in_test(test * t)
00150 {
00151 cons *c;
00152 complex_test *ct;
00153
00154 if (test_is_blank_test(*t))
00155 return;
00156 if (test_is_blank_or_equality_test(*t)) {
00157 substitute_for_placeholders_in_symbol((Symbol **) t);
00158
00159 return;
00160 }
00161
00162 ct = complex_test_from_test(*t);
00163
00164 switch (ct->type) {
00165 case GOAL_ID_TEST:
00166 case IMPASSE_ID_TEST:
00167 case DISJUNCTION_TEST:
00168 return;
00169 case CONJUNCTIVE_TEST:
00170 for (c = ct->data.conjunct_list; c != NIL; c = c->rest)
00171 substitute_for_placeholders_in_test((test *) (&(c->first)));
00172 return;
00173 default:
00174 substitute_for_placeholders_in_symbol(&(ct->data.referent));
00175 return;
00176 }
00177 }
00178
00179 void substitute_for_placeholders_in_condition_list(condition * cond)
00180 {
00181 for (; cond != NIL; cond = cond->next) {
00182 switch (cond->type) {
00183 case POSITIVE_CONDITION:
00184 case NEGATIVE_CONDITION:
00185 substitute_for_placeholders_in_test(&(cond->data.tests.id_test));
00186 substitute_for_placeholders_in_test(&(cond->data.tests.attr_test));
00187 substitute_for_placeholders_in_test(&(cond->data.tests.value_test));
00188 break;
00189 case CONJUNCTIVE_NEGATION_CONDITION:
00190 substitute_for_placeholders_in_condition_list(cond->data.ncc.top);
00191 break;
00192 }
00193 }
00194 }
00195
00196
00197 void substitute_for_placeholders_in_action_list(action * a)
00198 {
00199 for (; a != NIL; a = a->next) {
00200 if (a->type == MAKE_ACTION) {
00201 if (rhs_value_is_symbol(a->id)) {
00202 substitute_for_placeholders_in_symbol((Symbol **) & (a->id));
00203 }
00204 if (rhs_value_is_symbol(a->attr))
00205 substitute_for_placeholders_in_symbol((Symbol **) & (a->attr));
00206 if (rhs_value_is_symbol(a->value))
00207 substitute_for_placeholders_in_symbol((Symbol **) & (a->value));
00208 }
00209 }
00210 }
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238 char *help_on_lhs_grammar[] = {
00239 "Grammar for left hand sides of productions:",
00240 "",
00241 " <lhs> ::= <cond>+",
00242 " <cond> ::= <positive_cond> | - <positive_cond>",
00243 " <positive_cond> ::= <conds_for_one_id> | { <cond>+ }",
00244 " <conds_for_one_id> ::= ( [state|impasse] [<id_test>] <attr_value_tests>* )",
00245 " <id_test> ::= <test>",
00246 " <attr_value_tests> ::= [-] ^ <attr_test> [.<attr_test>]* <value_test>*",
00247 " <attr_test> ::= <test>",
00248 " <value_test> ::= <test> [+] | <conds_for_one_id> [+]",
00249 "",
00250 " <test> ::= <conjunctive_test> | <simple_test>",
00251 " <conjunctive_test> ::= { <simple_test>+ }",
00252 " <simple_test> ::= <disjunction_test> | <relational_test>",
00253 " <disjunction_test> ::= << <constant>* >>",
00254 " <relational_test> ::= [<relation>] <single_test>",
00255 " <relation> ::= <> | < | > | <= | >= | = | <=>",
00256 " <single_test> ::= variable | <constant>",
00257 " <constant> ::= sym_constant | int_constant | float_constant",
00258 "",
00259 "See also: rhs-grammar, sp",
00260 0
00261 };
00262
00263
00264
00265
00266
00267
00268
00269 Symbol *make_symbol_for_current_lexeme(void)
00270 {
00271 switch (current_agent(lexeme).type) {
00272 case SYM_CONSTANT_LEXEME:
00273 return make_sym_constant(current_agent(lexeme).string);
00274 case VARIABLE_LEXEME:
00275 return make_variable(current_agent(lexeme).string);
00276 case INT_CONSTANT_LEXEME:
00277 return make_int_constant(current_agent(lexeme).int_val);
00278 case FLOAT_CONSTANT_LEXEME:
00279 return make_float_constant(current_agent(lexeme).float_val);
00280
00281 case IDENTIFIER_LEXEME:
00282 {
00283 char msg[MESSAGE_SIZE];
00284 strncpy(msg, "parser.c: Internal error: ID found in make_symbol_for_current_lexeme\n", MESSAGE_SIZE);
00285 msg[MESSAGE_SIZE - 1] = 0;
00286 abort_with_fatal_error(msg);
00287 }
00288 default:
00289 {
00290 char msg[MESSAGE_SIZE];
00291 snprintf(msg, MESSAGE_SIZE,
00292 "parser.c: Internal error: bad lexeme type in make_symbol_for_current_lexeme\n, current_agent(lexeme).string=%s\n",
00293 current_agent(lexeme).string);
00294 msg[MESSAGE_SIZE - 1] = 0;
00295 abort_with_fatal_error(msg);
00296 }
00297 }
00298 return NIL;
00299 }
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320 test parse_relational_test(void)
00321 {
00322 byte test_type;
00323 bool use_equality_test;
00324 test t;
00325 Symbol *referent;
00326 complex_test *ct;
00327
00328 use_equality_test = FALSE;
00329 test_type = NOT_EQUAL_TEST;
00330
00331
00332 switch (current_agent(lexeme).type) {
00333 case EQUAL_LEXEME:
00334 use_equality_test = TRUE;
00335 get_lexeme();
00336 break;
00337
00338 case NOT_EQUAL_LEXEME:
00339 test_type = NOT_EQUAL_TEST;
00340 get_lexeme();
00341 break;
00342
00343 case LESS_LEXEME:
00344 test_type = LESS_TEST;
00345 get_lexeme();
00346 break;
00347
00348 case GREATER_LEXEME:
00349 test_type = GREATER_TEST;
00350 get_lexeme();
00351 break;
00352
00353 case LESS_EQUAL_LEXEME:
00354 test_type = LESS_OR_EQUAL_TEST;
00355 get_lexeme();
00356 break;
00357
00358 case GREATER_EQUAL_LEXEME:
00359 test_type = GREATER_OR_EQUAL_TEST;
00360 get_lexeme();
00361 break;
00362
00363 case LESS_EQUAL_GREATER_LEXEME:
00364 test_type = SAME_TYPE_TEST;
00365 get_lexeme();
00366 break;
00367
00368 default:
00369 use_equality_test = TRUE;
00370 break;
00371 }
00372
00373
00374 switch (current_agent(lexeme).type) {
00375 case SYM_CONSTANT_LEXEME:
00376 case INT_CONSTANT_LEXEME:
00377 case FLOAT_CONSTANT_LEXEME:
00378 case VARIABLE_LEXEME:
00379 referent = make_symbol_for_current_lexeme();
00380 get_lexeme();
00381 if (use_equality_test) {
00382 t = make_equality_test_without_adding_reference(referent);
00383 } else {
00384 allocate_with_pool(¤t_agent(complex_test_pool), &ct);
00385 ct->type = test_type;
00386 ct->data.referent = referent;
00387 t = make_test_from_complex_test(ct);
00388 }
00389 return t;
00390
00391 default:
00392 print("Expected variable or constant for test\n");
00393 print_location_of_most_recent_lexeme();
00394 return NIL;
00395 }
00396 }
00397
00398
00399
00400
00401
00402
00403
00404
00405 test parse_disjunction_test(void)
00406 {
00407 complex_test *ct;
00408 test t;
00409
00410 if (current_agent(lexeme).type != LESS_LESS_LEXEME) {
00411 print("Expected << to begin disjunction test\n");
00412 print_location_of_most_recent_lexeme();
00413 return NIL;
00414 }
00415 get_lexeme();
00416
00417 allocate_with_pool(¤t_agent(complex_test_pool), &ct);
00418 ct->type = DISJUNCTION_TEST;
00419 ct->data.disjunction_list = NIL;
00420 t = make_test_from_complex_test(ct);
00421
00422 while (current_agent(lexeme).type != GREATER_GREATER_LEXEME) {
00423 switch (current_agent(lexeme).type) {
00424 case SYM_CONSTANT_LEXEME:
00425 case INT_CONSTANT_LEXEME:
00426 case FLOAT_CONSTANT_LEXEME:
00427 push(make_symbol_for_current_lexeme(), ct->data.disjunction_list);
00428 get_lexeme();
00429 break;
00430 default:
00431 print("Expected constant or >> while reading disjunction test\n");
00432 print_location_of_most_recent_lexeme();
00433 deallocate_test(t);
00434 return NIL;
00435 }
00436 }
00437 get_lexeme();
00438 ct->data.disjunction_list = destructively_reverse_list(ct->data.disjunction_list);
00439 return t;
00440 }
00441
00442
00443
00444
00445
00446
00447
00448 test parse_simple_test(void)
00449 {
00450 if (current_agent(lexeme).type == LESS_LESS_LEXEME)
00451 return parse_disjunction_test();
00452 return parse_relational_test();
00453 }
00454
00455
00456
00457
00458
00459
00460
00461
00462 test parse_test(void)
00463 {
00464 complex_test *ct;
00465 test t, temp;
00466
00467 if (current_agent(lexeme).type != L_BRACE_LEXEME)
00468 return parse_simple_test();
00469
00470 get_lexeme();
00471 t = make_blank_test();
00472 do {
00473 temp = parse_simple_test();
00474 if (!temp) {
00475 deallocate_test(t);
00476 return NIL;
00477 }
00478 add_new_test_to_test(&t, temp);
00479 } while (current_agent(lexeme).type != R_BRACE_LEXEME);
00480 get_lexeme();
00481
00482 if (test_is_complex_test(t)) {
00483 ct = complex_test_from_test(t);
00484 if (ct->type == CONJUNCTIVE_TEST)
00485 ct->data.conjunct_list = destructively_reverse_list(ct->data.conjunct_list);
00486 }
00487
00488 return t;
00489 }
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513 void fill_in_id_tests(condition * conds, test t)
00514 {
00515 condition *positive_c, *c;
00516 test equality_test_from_t;
00517
00518
00519 for (positive_c = conds; positive_c != NIL; positive_c = positive_c->next)
00520 if ((positive_c->type == POSITIVE_CONDITION) && (positive_c->data.tests.id_test == NIL))
00521 break;
00522
00523 if (positive_c) {
00524
00525 equality_test_from_t = copy_of_equality_test_found_in_test(t);
00526 for (c = conds; c != NIL; c = c->next) {
00527 if (c->type == CONJUNCTIVE_NEGATION_CONDITION)
00528 fill_in_id_tests(c->data.ncc.top, equality_test_from_t);
00529 else if (c->data.tests.id_test == NIL)
00530 c->data.tests.id_test = copy_test(equality_test_from_t);
00531 }
00532 deallocate_test(equality_test_from_t);
00533
00534 deallocate_test(positive_c->data.tests.id_test);
00535 positive_c->data.tests.id_test = copy_test(t);
00536 return;
00537 }
00538
00539
00540 for (c = conds; c != NIL; c = c->next) {
00541 if (c->type == CONJUNCTIVE_NEGATION_CONDITION) {
00542 fill_in_id_tests(c->data.ncc.top, t);
00543 } else {
00544 if (c->data.tests.id_test == NIL)
00545 c->data.tests.id_test = copy_test(t);
00546 }
00547 }
00548 }
00549
00550 void fill_in_attr_tests(condition * conds, test t)
00551 {
00552 condition *positive_c, *c;
00553 test equality_test_from_t;
00554
00555
00556 for (positive_c = conds; positive_c != NIL; positive_c = positive_c->next)
00557 if ((positive_c->type == POSITIVE_CONDITION) && (positive_c->data.tests.attr_test == NIL))
00558 break;
00559
00560 if (positive_c) {
00561
00562 equality_test_from_t = copy_of_equality_test_found_in_test(t);
00563 for (c = conds; c != NIL; c = c->next) {
00564 if (c->type == CONJUNCTIVE_NEGATION_CONDITION)
00565 fill_in_attr_tests(c->data.ncc.top, equality_test_from_t);
00566 else if (c->data.tests.attr_test == NIL)
00567 c->data.tests.attr_test = copy_test(equality_test_from_t);
00568 }
00569 deallocate_test(equality_test_from_t);
00570
00571 deallocate_test(positive_c->data.tests.attr_test);
00572 positive_c->data.tests.attr_test = copy_test(t);
00573 return;
00574 }
00575
00576
00577 for (c = conds; c != NIL; c = c->next) {
00578 if (c->type == CONJUNCTIVE_NEGATION_CONDITION) {
00579 fill_in_attr_tests(c->data.ncc.top, t);
00580 } else {
00581 if (c->data.tests.attr_test == NIL)
00582 c->data.tests.attr_test = copy_test(t);
00583 }
00584 }
00585 }
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597 condition *negate_condition_list(condition * conds)
00598 {
00599 condition *temp, *last;
00600
00601 if (conds->next == NIL) {
00602
00603 switch (conds->type) {
00604 case POSITIVE_CONDITION:
00605 conds->type = NEGATIVE_CONDITION;
00606 return conds;
00607 case NEGATIVE_CONDITION:
00608 conds->type = POSITIVE_CONDITION;
00609 return conds;
00610 case CONJUNCTIVE_NEGATION_CONDITION:
00611 temp = conds->data.ncc.top;
00612 free_with_pool(¤t_agent(condition_pool), conds);
00613 return temp;
00614 }
00615 }
00616
00617 allocate_with_pool(¤t_agent(condition_pool), &temp);
00618 temp->type = CONJUNCTIVE_NEGATION_CONDITION;
00619 temp->next = NIL;
00620 temp->prev = NIL;
00621 temp->data.ncc.top = conds;
00622 for (last = conds; last->next != NIL; last = last->next);
00623 temp->data.ncc.bottom = last;
00624 return temp;
00625 }
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636 condition *parse_conds_for_one_id(char first_letter_if_no_id_given, test * dest_id_test);
00637
00638 condition *parse_value_test_star(char first_letter)
00639 {
00640 condition *c, *last_c, *first_c, *new_conds;
00641 test value_test;
00642 bool acceptable;
00643
00644 if ((current_agent(lexeme).type == MINUS_LEXEME) ||
00645 (current_agent(lexeme).type == UP_ARROW_LEXEME) || (current_agent(lexeme).type == R_PAREN_LEXEME)) {
00646
00647 allocate_with_pool(¤t_agent(condition_pool), &c);
00648 c->type = POSITIVE_CONDITION;
00649 c->next = c->prev = NIL;
00650 c->data.tests.id_test = NIL;
00651 c->data.tests.attr_test = NIL;
00652 c->data.tests.value_test = make_placeholder_test(first_letter);
00653 c->test_for_acceptable_preference = FALSE;
00654 return c;
00655 }
00656
00657 first_c = NIL;
00658 last_c = NIL;
00659 do {
00660 if (current_agent(lexeme).type == L_PAREN_LEXEME) {
00661
00662 new_conds = parse_conds_for_one_id(first_letter, &value_test);
00663 if (!new_conds) {
00664 deallocate_condition_list(first_c);
00665 return NIL;
00666 }
00667 } else {
00668
00669 new_conds = NIL;
00670 value_test = parse_test();
00671 if (!value_test) {
00672 deallocate_condition_list(first_c);
00673 return NIL;
00674 }
00675 if (!test_includes_equality_test_for_symbol(value_test, NIL)) {
00676 add_new_test_to_test(&value_test, make_placeholder_test(first_letter));
00677 }
00678 }
00679
00680 acceptable = FALSE;
00681 if (current_agent(lexeme).type == PLUS_LEXEME) {
00682 acceptable = TRUE;
00683 get_lexeme();
00684 }
00685
00686 allocate_with_pool(¤t_agent(condition_pool), &c);
00687 insert_at_head_of_dll(new_conds, c, next, prev);
00688 c->type = POSITIVE_CONDITION;
00689 c->data.tests.id_test = NIL;
00690 c->data.tests.attr_test = NIL;
00691 c->data.tests.value_test = value_test;
00692 c->test_for_acceptable_preference = acceptable;
00693
00694 if (last_c)
00695 last_c->next = new_conds;
00696 else
00697 first_c = new_conds;
00698 new_conds->prev = last_c;
00699 for (last_c = new_conds; last_c->next != NIL; last_c = last_c->next);
00700 } while ((current_agent(lexeme).type != MINUS_LEXEME) &&
00701 (current_agent(lexeme).type != UP_ARROW_LEXEME) && (current_agent(lexeme).type != R_PAREN_LEXEME));
00702 return first_c;
00703 }
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715 condition *parse_attr_value_tests(void)
00716 {
00717 test id_test_to_use, attr_test;
00718 bool negate_it;
00719 condition *first_c, *last_c, *c, *new_conds;
00720
00721
00722 negate_it = FALSE;
00723 if (current_agent(lexeme).type == MINUS_LEXEME) {
00724 negate_it = TRUE;
00725 get_lexeme();
00726 }
00727
00728
00729 if (current_agent(lexeme).type != UP_ARROW_LEXEME) {
00730 print("Expected ^ followed by attribute\n");
00731 print_location_of_most_recent_lexeme();
00732 return NIL;
00733 }
00734 get_lexeme();
00735
00736 first_c = NIL;
00737 last_c = NIL;
00738
00739
00740 attr_test = parse_test();
00741 if (!attr_test)
00742 return NIL;
00743 if (!test_includes_equality_test_for_symbol(attr_test, NIL)) {
00744 add_new_test_to_test(&attr_test, make_placeholder_test('a'));
00745 }
00746
00747
00748 id_test_to_use = NIL;
00749 while (current_agent(lexeme).type == PERIOD_LEXEME) {
00750 get_lexeme();
00751
00752
00753 allocate_with_pool(¤t_agent(condition_pool), &c);
00754 c->type = POSITIVE_CONDITION;
00755 if (last_c)
00756 last_c->next = c;
00757 else
00758 first_c = c;
00759 c->next = NIL;
00760 c->prev = last_c;
00761 last_c = c;
00762 if (id_test_to_use)
00763 c->data.tests.id_test = copy_test(id_test_to_use);
00764 else
00765 c->data.tests.id_test = NIL;
00766 c->data.tests.attr_test = attr_test;
00767 id_test_to_use = make_placeholder_test(first_letter_from_test(attr_test));
00768 c->data.tests.value_test = id_test_to_use;
00769 c->test_for_acceptable_preference = FALSE;
00770
00771 attr_test = parse_test();
00772 if (!attr_test) {
00773 deallocate_condition_list(first_c);
00774 return NIL;
00775 }
00776
00777 if (!test_includes_equality_test_for_symbol(attr_test, NIL)) {
00778 add_new_test_to_test(&attr_test, make_placeholder_test('a'));
00779 }
00780
00781 }
00782
00783
00784 new_conds = parse_value_test_star(first_letter_from_test(attr_test));
00785 if (!new_conds) {
00786 deallocate_condition_list(first_c);
00787 deallocate_test(attr_test);
00788 return NIL;
00789 }
00790 fill_in_attr_tests(new_conds, attr_test);
00791 if (id_test_to_use)
00792 fill_in_id_tests(new_conds, id_test_to_use);
00793 deallocate_test(attr_test);
00794 if (last_c)
00795 last_c->next = new_conds;
00796 else
00797 first_c = new_conds;
00798 new_conds->prev = last_c;
00799
00800
00801
00802 if (negate_it)
00803 first_c = negate_condition_list(first_c);
00804
00805 return first_c;
00806 }
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819 test parse_head_of_conds_for_one_id(char first_letter_if_no_id_given)
00820 {
00821 test id_test, id_goal_impasse_test, check_for_symconstant;
00822 complex_test *ct;
00823 Symbol *sym;
00824
00825 if (current_agent(lexeme).type != L_PAREN_LEXEME) {
00826 print("Expected ( to begin condition element\n");
00827 print_location_of_most_recent_lexeme();
00828 return NIL;
00829 }
00830 get_lexeme();
00831
00832
00833 if (current_agent(lexeme).type == SYM_CONSTANT_LEXEME) {
00834 if (!strcmp(current_agent(lexeme).string, "state")) {
00835 allocate_with_pool(¤t_agent(complex_test_pool), &ct);
00836 ct->type = GOAL_ID_TEST;
00837 id_goal_impasse_test = make_test_from_complex_test(ct);
00838 get_lexeme();
00839 first_letter_if_no_id_given = 's';
00840 } else if (!strcmp(current_agent(lexeme).string, "impasse")) {
00841 allocate_with_pool(¤t_agent(complex_test_pool), &ct);
00842 ct->type = IMPASSE_ID_TEST;
00843 id_goal_impasse_test = make_test_from_complex_test(ct);
00844 get_lexeme();
00845 first_letter_if_no_id_given = 'i';
00846 } else {
00847 id_goal_impasse_test = make_blank_test();
00848 }
00849 } else {
00850 id_goal_impasse_test = make_blank_test();
00851 }
00852
00853
00854 if ((current_agent(lexeme).type != MINUS_LEXEME) &&
00855 (current_agent(lexeme).type != UP_ARROW_LEXEME) && (current_agent(lexeme).type != R_PAREN_LEXEME)) {
00856 id_test = parse_test();
00857 if (!id_test) {
00858 deallocate_test(id_goal_impasse_test);
00859 return NIL;
00860 }
00861 if (!test_includes_equality_test_for_symbol(id_test, NIL)) {
00862 add_new_test_to_test(&id_test, make_placeholder_test(first_letter_if_no_id_given));
00863 } else {
00864 check_for_symconstant = copy_of_equality_test_found_in_test(id_test);
00865 sym = referent_of_equality_test(check_for_symconstant);
00866 deallocate_test(check_for_symconstant);
00867 if (sym->common.symbol_type != VARIABLE_SYMBOL_TYPE) {
00868 print_with_symbols("Warning: Constant %y in id field test.\n", sym);
00869 print(" This will never match.\n");
00870 print_location_of_most_recent_lexeme();
00871 deallocate_test(id_test);
00872 return NIL;
00873 }
00874 }
00875 } else {
00876 id_test = make_placeholder_test(first_letter_if_no_id_given);
00877 }
00878
00879
00880 add_new_test_to_test(&id_test, id_goal_impasse_test);
00881
00882
00883 return id_test;
00884 }
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897 condition *parse_tail_of_conds_for_one_id(void)
00898 {
00899 condition *first_c, *last_c, *new_conds;
00900 condition *c;
00901
00902
00903 if (current_agent(lexeme).type == R_PAREN_LEXEME) {
00904 get_lexeme();
00905 allocate_with_pool(¤t_agent(condition_pool), &c);
00906 c->type = POSITIVE_CONDITION;
00907 c->next = NIL;
00908 c->prev = NIL;
00909 c->data.tests.id_test = NIL;
00910 c->data.tests.attr_test = make_placeholder_test('a');
00911 c->data.tests.value_test = make_placeholder_test('v');
00912 c->test_for_acceptable_preference = FALSE;
00913 return c;
00914 }
00915
00916
00917 first_c = NIL;
00918 last_c = NIL;
00919 while (current_agent(lexeme).type != R_PAREN_LEXEME) {
00920 new_conds = parse_attr_value_tests();
00921 if (!new_conds) {
00922 deallocate_condition_list(first_c);
00923 return NIL;
00924 }
00925 if (last_c)
00926 last_c->next = new_conds;
00927 else
00928 first_c = new_conds;
00929 new_conds->prev = last_c;
00930 for (last_c = new_conds; last_c->next != NIL; last_c = last_c->next);
00931 }
00932
00933
00934 get_lexeme();
00935
00936 return first_c;
00937 }
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957 condition *parse_conds_for_one_id(char first_letter_if_no_id_given, test * dest_id_test)
00958 {
00959 condition *conds;
00960 test id_test, equality_test_from_id_test;
00961
00962
00963 id_test = parse_head_of_conds_for_one_id(first_letter_if_no_id_given);
00964 if (!id_test)
00965 return NIL;
00966
00967
00968 conds = parse_tail_of_conds_for_one_id();
00969 if (!conds) {
00970 deallocate_test(id_test);
00971 return NIL;
00972 }
00973
00974
00975 if (dest_id_test) {
00976 *dest_id_test = id_test;
00977 equality_test_from_id_test = copy_of_equality_test_found_in_test(id_test);
00978 fill_in_id_tests(conds, equality_test_from_id_test);
00979 deallocate_test(equality_test_from_id_test);
00980 } else {
00981 fill_in_id_tests(conds, id_test);
00982 deallocate_test(id_test);
00983 }
00984
00985 return conds;
00986 }
00987
00988
00989
00990
00991
00992
00993
00994
00995 condition *parse_cond_plus(void);
00996
00997 condition *parse_cond(void)
00998 {
00999 condition *c;
01000 bool negate_it;
01001
01002
01003 negate_it = FALSE;
01004 if (current_agent(lexeme).type == MINUS_LEXEME) {
01005 negate_it = TRUE;
01006 get_lexeme();
01007 }
01008
01009
01010 if (current_agent(lexeme).type == L_BRACE_LEXEME) {
01011
01012 get_lexeme();
01013 c = parse_cond_plus();
01014 if (!c)
01015 return NIL;
01016 if (current_agent(lexeme).type != R_BRACE_LEXEME) {
01017 print("Expected } to end conjunctive condition\n");
01018 print_location_of_most_recent_lexeme();
01019 deallocate_condition_list(c);
01020 return NIL;
01021 }
01022 get_lexeme();
01023 } else {
01024
01025 c = parse_conds_for_one_id('s', NULL);
01026 if (!c)
01027 return NIL;
01028 }
01029
01030
01031 if (negate_it)
01032 c = negate_condition_list(c);
01033
01034 return c;
01035 }
01036
01037
01038
01039
01040
01041
01042
01043 condition *parse_cond_plus(void)
01044 {
01045 condition *first_c, *last_c, *new_conds;
01046
01047 first_c = NIL;
01048 last_c = NIL;
01049 do {
01050
01051 new_conds = parse_cond();
01052 if (!new_conds) {
01053 deallocate_condition_list(first_c);
01054 return NIL;
01055 }
01056 if (last_c)
01057 last_c->next = new_conds;
01058 else
01059 first_c = new_conds;
01060 new_conds->prev = last_c;
01061 for (last_c = new_conds; last_c->next != NIL; last_c = last_c->next);
01062 } while ((current_agent(lexeme).type == MINUS_LEXEME) ||
01063 (current_agent(lexeme).type == L_PAREN_LEXEME) || (current_agent(lexeme).type == L_BRACE_LEXEME));
01064 return first_c;
01065 }
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075 condition *parse_lhs(void)
01076 {
01077 condition *c;
01078
01079 c = parse_cond_plus();
01080 if (!c)
01081 return NIL;
01082 return c;
01083 }
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123 char *help_on_rhs_grammar[] = {
01124 "Grammar for right hand sides of productions:",
01125 "",
01126 " <rhs> ::= <rhs_action>*",
01127 " <rhs_action> ::= ( variable <attr_value_make>+ ) | <function_call>",
01128 " <function_call> ::= ( <function_name> <rhs_value>* )",
01129 " <function_name> ::= sym_constant | + | -",
01130 " <rhs_value> ::= <constant> | <function_call> | variable",
01131 " <constant> ::= sym_constant | int_constant | float_constant",
01132 " <attr_value_make> ::= ^ <rhs_value> <value_make>+",
01133 " <value_make> ::= <rhs_value> <preferences>",
01134 "",
01135 " <preferences> ::= [,] | <preference_specifier>+",
01136 " <preference-specifier> ::= <naturally-unary-preference> [,]",
01137 " | <forced-unary-preference>",
01138 " | <binary-preference> <rhs_value> [,]",
01139 " <naturally-unary-preference> ::= + | - | ! | ~ | @",
01140 " <binary-preference> ::= > | = | < | &",
01141 " <any-preference> ::= <naturally-unary-preference> | <binary-preference>",
01142 " <forced-unary-preference> ::= <binary-preference> ",
01143 " {<any-preference> | , | ) | ^}",
01144 " ;but the parser shouldn't consume the <any-preference>, \")\" or \"^\"",
01145 " lexeme here",
01146 "",
01147 "See also: lhs-grammar, sp",
01148 0
01149 };
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163 rhs_value parse_rhs_value(void);
01164
01165 rhs_value parse_function_call_after_lparen(bool is_stand_alone_action)
01166 {
01167 rhs_function *rf;
01168 Symbol *fun_name;
01169 list *fl;
01170 cons *c, *prev_c;
01171 rhs_value arg_rv;
01172 int num_args;
01173
01174
01175 if (current_agent(lexeme).type == PLUS_LEXEME)
01176 fun_name = find_sym_constant("+");
01177 else if (current_agent(lexeme).type == MINUS_LEXEME)
01178 fun_name = find_sym_constant("-");
01179 else
01180 fun_name = find_sym_constant(current_agent(lexeme).string);
01181 if (!fun_name) {
01182 print("No RHS function named %s\n", current_agent(lexeme).string);
01183 print_location_of_most_recent_lexeme();
01184 return NIL;
01185 }
01186 rf = lookup_rhs_function(fun_name);
01187 if (!rf) {
01188 print("No RHS function named %s\n", current_agent(lexeme).string);
01189 print_location_of_most_recent_lexeme();
01190 return NIL;
01191 }
01192
01193
01194 if (is_stand_alone_action && (!rf->can_be_stand_alone_action)) {
01195 print("Function %s cannot be used as a stand-alone action\n", current_agent(lexeme).string);
01196 print_location_of_most_recent_lexeme();
01197 return NIL;
01198 }
01199 if ((!is_stand_alone_action) && (!rf->can_be_rhs_value)) {
01200 print("Function %s can only be used as a stand-alone action\n", current_agent(lexeme).string);
01201 print_location_of_most_recent_lexeme();
01202 return NIL;
01203 }
01204
01205
01206 allocate_cons(&fl);
01207 fl->first = rf;
01208 prev_c = fl;
01209 get_lexeme();
01210 num_args = 0;
01211 while (current_agent(lexeme).type != R_PAREN_LEXEME) {
01212 arg_rv = parse_rhs_value();
01213 if (!arg_rv) {
01214 prev_c->rest = NIL;
01215 deallocate_rhs_value(funcall_list_to_rhs_value(fl));
01216 return NIL;
01217 }
01218 num_args++;
01219 allocate_cons(&c);
01220 c->first = arg_rv;
01221 prev_c->rest = c;
01222 prev_c = c;
01223 }
01224 prev_c->rest = NIL;
01225
01226
01227 if ((rf->num_args_expected != -1) && (rf->num_args_expected != num_args)) {
01228 print("Wrong number of arguments to function %s (expected %d)\n", rf->name->sc.name, rf->num_args_expected);
01229 print_location_of_most_recent_lexeme();
01230 deallocate_rhs_value(funcall_list_to_rhs_value(fl));
01231 return NIL;
01232 }
01233
01234 get_lexeme();
01235 return funcall_list_to_rhs_value(fl);
01236 }
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248 rhs_value parse_rhs_value(void)
01249 {
01250 rhs_value rv;
01251
01252 if (current_agent(lexeme).type == L_PAREN_LEXEME) {
01253 get_lexeme();
01254 return parse_function_call_after_lparen(FALSE);
01255 }
01256 if ((current_agent(lexeme).type == SYM_CONSTANT_LEXEME) ||
01257 (current_agent(lexeme).type == INT_CONSTANT_LEXEME) ||
01258 (current_agent(lexeme).type == FLOAT_CONSTANT_LEXEME) || (current_agent(lexeme).type == VARIABLE_LEXEME)) {
01259 rv = symbol_to_rhs_value(make_symbol_for_current_lexeme());
01260 get_lexeme();
01261 return rv;
01262 }
01263 print("Illegal value for RHS value\n");
01264 print_location_of_most_recent_lexeme();
01265 return FALSE;
01266 }
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276 bool is_preference_lexeme(enum lexer_token_type test_lexeme)
01277 {
01278 switch (test_lexeme) {
01279
01280 case PLUS_LEXEME:
01281 return TRUE;
01282 case MINUS_LEXEME:
01283 return TRUE;
01284 case EXCLAMATION_POINT_LEXEME:
01285 return TRUE;
01286 case TILDE_LEXEME:
01287 return TRUE;
01288 case AT_LEXEME:
01289 return TRUE;
01290 case GREATER_LEXEME:
01291 return TRUE;
01292 case EQUAL_LEXEME:
01293 return TRUE;
01294 case LESS_LEXEME:
01295 return TRUE;
01296 case AMPERSAND_LEXEME:
01297 return TRUE;
01298 default:
01299 return FALSE;
01300 }
01301 }
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326 byte parse_preference_specifier_without_referent(void)
01327 {
01328 switch (current_agent(lexeme).type) {
01329
01330 case PLUS_LEXEME:
01331 get_lexeme();
01332 if (current_agent(lexeme).type == COMMA_LEXEME)
01333 get_lexeme();
01334 return ACCEPTABLE_PREFERENCE_TYPE;
01335
01336 case MINUS_LEXEME:
01337 get_lexeme();
01338 if (current_agent(lexeme).type == COMMA_LEXEME)
01339 get_lexeme();
01340 return REJECT_PREFERENCE_TYPE;
01341
01342 case EXCLAMATION_POINT_LEXEME:
01343 get_lexeme();
01344 if (current_agent(lexeme).type == COMMA_LEXEME)
01345 get_lexeme();
01346 return REQUIRE_PREFERENCE_TYPE;
01347
01348 case TILDE_LEXEME:
01349 get_lexeme();
01350 if (current_agent(lexeme).type == COMMA_LEXEME)
01351 get_lexeme();
01352 return PROHIBIT_PREFERENCE_TYPE;
01353
01354 case AT_LEXEME:
01355 get_lexeme();
01356 if (current_agent(lexeme).type == COMMA_LEXEME)
01357 get_lexeme();
01358 return RECONSIDER_PREFERENCE_TYPE;
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368 case GREATER_LEXEME:
01369 get_lexeme();
01370 if ((current_agent(lexeme).type != COMMA_LEXEME) &&
01371 (current_agent(lexeme).type != R_PAREN_LEXEME) &&
01372 (current_agent(lexeme).type != UP_ARROW_LEXEME) && (!is_preference_lexeme(current_agent(lexeme).type)))
01373 return BETTER_PREFERENCE_TYPE;
01374
01375 if (current_agent(lexeme).type == COMMA_LEXEME)
01376 get_lexeme();
01377 return BEST_PREFERENCE_TYPE;
01378
01379 case EQUAL_LEXEME:
01380 get_lexeme();
01381 if ((current_agent(lexeme).type != COMMA_LEXEME) &&
01382 (current_agent(lexeme).type != R_PAREN_LEXEME) &&
01383 (current_agent(lexeme).type != UP_ARROW_LEXEME) && (!is_preference_lexeme(current_agent(lexeme).type)))
01384 return BINARY_INDIFFERENT_PREFERENCE_TYPE;
01385
01386 if (current_agent(lexeme).type == COMMA_LEXEME)
01387 get_lexeme();
01388 return UNARY_INDIFFERENT_PREFERENCE_TYPE;
01389
01390 case LESS_LEXEME:
01391 get_lexeme();
01392 if ((current_agent(lexeme).type != COMMA_LEXEME) &&
01393 (current_agent(lexeme).type != R_PAREN_LEXEME) &&
01394 (current_agent(lexeme).type != UP_ARROW_LEXEME) && (!is_preference_lexeme(current_agent(lexeme).type)))
01395 return WORSE_PREFERENCE_TYPE;
01396
01397 if (current_agent(lexeme).type == COMMA_LEXEME)
01398 get_lexeme();
01399 return WORST_PREFERENCE_TYPE;
01400
01401 case AMPERSAND_LEXEME:
01402 get_lexeme();
01403 if ((current_agent(lexeme).type != COMMA_LEXEME) &&
01404 (current_agent(lexeme).type != R_PAREN_LEXEME) &&
01405 (current_agent(lexeme).type != UP_ARROW_LEXEME) && (!is_preference_lexeme(current_agent(lexeme).type)))
01406 return BINARY_PARALLEL_PREFERENCE_TYPE;
01407
01408 if (current_agent(lexeme).type == COMMA_LEXEME)
01409 get_lexeme();
01410 return UNARY_PARALLEL_PREFERENCE_TYPE;
01411
01412 default:
01413
01414 return ACCEPTABLE_PREFERENCE_TYPE;
01415 }
01416 }
01417
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433 action *parse_preferences(Symbol * id, rhs_value attr, rhs_value value)
01434 {
01435 action *a;
01436 action *prev_a;
01437 rhs_value referent;
01438 byte preference_type;
01439 bool saw_plus_sign;
01440
01441
01442
01443
01444 prev_a = NIL;
01445
01446 saw_plus_sign = (bool) (current_agent(lexeme).type == PLUS_LEXEME);
01447 preference_type = parse_preference_specifier_without_referent();
01448 if ((preference_type == ACCEPTABLE_PREFERENCE_TYPE) && (!saw_plus_sign)) {
01449
01450
01451
01452 if (current_agent(lexeme).type == COMMA_LEXEME)
01453 get_lexeme();
01454 }
01455
01456 for (;;) {
01457
01458 if (preference_is_binary(preference_type)) {
01459 referent = parse_rhs_value();
01460 if (!referent) {
01461 deallocate_action_list(prev_a);
01462 return NIL;
01463 }
01464 if (current_agent(lexeme).type == COMMA_LEXEME)
01465 get_lexeme();
01466 } else {
01467 referent = NIL;
01468 }
01469
01470
01471 allocate_with_pool(¤t_agent(action_pool), &a);
01472 a->next = prev_a;
01473 prev_a = a;
01474 a->type = MAKE_ACTION;
01475 a->preference_type = preference_type;
01476 a->id = symbol_to_rhs_value(id);
01477 symbol_add_ref(id);
01478 a->attr = copy_rhs_value(attr);
01479 a->value = copy_rhs_value(value);
01480 if (preference_is_binary(preference_type))
01481 a->referent = referent;
01482
01483
01484 saw_plus_sign = (bool) (current_agent(lexeme).type == PLUS_LEXEME);
01485 preference_type = parse_preference_specifier_without_referent();
01486
01487
01488 if ((preference_type == ACCEPTABLE_PREFERENCE_TYPE) && (!saw_plus_sign))
01489
01490
01491
01492 return prev_a;
01493 }
01494 }
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520 action *parse_preferences_soar8_non_operator(Symbol * id, rhs_value attr, rhs_value value)
01521 {
01522 action *a;
01523 action *prev_a;
01524 rhs_value referent;
01525 byte preference_type;
01526 bool saw_plus_sign;
01527
01528
01529
01530
01531
01532
01533
01534
01535 prev_a = NIL;
01536
01537 saw_plus_sign = (bool) (current_agent(lexeme).type == PLUS_LEXEME);
01538 preference_type = parse_preference_specifier_without_referent();
01539 if ((preference_type == ACCEPTABLE_PREFERENCE_TYPE) && (!saw_plus_sign)) {
01540
01541
01542
01543 if (current_agent(lexeme).type == COMMA_LEXEME)
01544 get_lexeme();
01545 }
01546
01547 for (;;) {
01548
01549
01550
01551 if (preference_is_binary(preference_type)) {
01552 print("\nERROR: in Soar8, binary preference illegal for non-operator.");
01553 print_with_symbols("\n id = %y\t attr = %y\t value = %y\n",
01554 id, rhs_value_to_symbol(attr), rhs_value_to_symbol(value));
01555 deallocate_action_list(prev_a);
01556 return NIL;
01557 } else {
01558 referent = NIL;
01559 }
01560
01561 if ((preference_type != ACCEPTABLE_PREFERENCE_TYPE) && (preference_type != REJECT_PREFERENCE_TYPE)) {
01562 print
01563 ("\nWARNING: in Soar8, the only allowable non-operator preference \nis REJECT - .\nIgnoring specified preferences.\n");
01564 print_with_symbols("id = %y\t attr = %y\t value = %y\n", id, rhs_value_to_symbol(attr),
01565 rhs_value_to_symbol(value));
01566 print_location_of_most_recent_lexeme();
01567 }
01568
01569 if (preference_type == REJECT_PREFERENCE_TYPE) {
01570
01571 allocate_with_pool(¤t_agent(action_pool), &a);
01572 a->next = prev_a;
01573 prev_a = a;
01574 a->type = MAKE_ACTION;
01575 a->preference_type = preference_type;
01576 a->id = symbol_to_rhs_value(id);
01577 symbol_add_ref(id);
01578 a->attr = copy_rhs_value(attr);
01579 a->value = copy_rhs_value(value);
01580 }
01581
01582
01583 saw_plus_sign = (bool) (current_agent(lexeme).type == PLUS_LEXEME);
01584 preference_type = parse_preference_specifier_without_referent();
01585
01586
01587 if ((preference_type == ACCEPTABLE_PREFERENCE_TYPE) && (!saw_plus_sign)) {
01588
01589
01590
01591
01592
01593
01594 if (prev_a == NIL) {
01595
01596 allocate_with_pool(¤t_agent(action_pool), &a);
01597 a->next = prev_a;
01598 prev_a = a;
01599 a->type = MAKE_ACTION;
01600 a->preference_type = ACCEPTABLE_PREFERENCE_TYPE;
01601 a->id = symbol_to_rhs_value(id);
01602 symbol_add_ref(id);
01603 a->attr = copy_rhs_value(attr);
01604 a->value = copy_rhs_value(value);
01605 }
01606 return prev_a;
01607 }
01608 }
01609 }
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624 action *parse_attr_value_make(Symbol * id)
01625 {
01626 rhs_value attr, value;
01627 action *all_actions, *new_actions, *last;
01628 Symbol *old_id, *new_var;
01629 char namebuf[NAMEBUF_SIZE], first_letter;
01630
01631 if (current_agent(lexeme).type != UP_ARROW_LEXEME) {
01632 print("Expected ^ in RHS make action\n");
01633 print_location_of_most_recent_lexeme();
01634 return NIL;
01635 }
01636 old_id = id;
01637
01638 get_lexeme();
01639 attr = parse_rhs_value();
01640 if (!attr)
01641 return NIL;
01642 all_actions = NIL;
01643
01644
01645 while (current_agent(lexeme).type == PERIOD_LEXEME) {
01646 get_lexeme();
01647
01648
01649
01650
01651
01652
01653 first_letter = first_letter_from_rhs_value(attr);
01654 snprintf(namebuf, NAMEBUF_SIZE, "<#%c*%lu>", first_letter, placeholder_counter[first_letter - 'a']++);
01655 namebuf[NAMEBUF_SIZE - 1] = 0;
01656 new_var = make_variable(namebuf);
01657
01658 new_var->var.current_binding_value = NIL;
01659
01660
01661
01662
01663 #ifndef SOAR_8_ONLY
01664 if (current_agent(operand2_mode) &&
01665 #else
01666 if (
01667 #endif
01668 (strcmp(rhs_value_to_string(attr, NULL, 0), "operator") != 0)) {
01669 new_actions = parse_preferences_soar8_non_operator(id, attr, symbol_to_rhs_value(new_var));
01670 } else {
01671 new_actions = parse_preferences(id, attr, symbol_to_rhs_value(new_var));
01672 }
01673 for (last = new_actions; last->next != NIL; last = last->next);
01674 last->next = all_actions;
01675 all_actions = new_actions;
01676
01677
01678
01679 id = new_var;
01680 attr = parse_rhs_value();
01681 if (!attr)
01682 return NIL;
01683
01684 }
01685
01686
01687 do {
01688 value = parse_rhs_value();
01689 if (!value) {
01690 deallocate_rhs_value(attr);
01691 deallocate_action_list(all_actions);
01692 return NIL;
01693 }
01694 #ifndef SOAR_8_ONLY
01695 if (current_agent(operand2_mode) &&
01696 #else
01697 if (
01698 #endif
01699 (strcmp(rhs_value_to_string(attr, NULL, 0), "operator") != 0)) {
01700 new_actions = parse_preferences_soar8_non_operator(id, attr, value);
01701 } else {
01702 new_actions = parse_preferences(id, attr, value);
01703 }
01704 deallocate_rhs_value(value);
01705 if (!new_actions) {
01706 deallocate_rhs_value(attr);
01707 return NIL;
01708 }
01709 for (last = new_actions; last->next != NIL; last = last->next);
01710 last->next = all_actions;
01711 all_actions = new_actions;
01712 } while ((current_agent(lexeme).type != R_PAREN_LEXEME) && (current_agent(lexeme).type != UP_ARROW_LEXEME));
01713
01714 deallocate_rhs_value(attr);
01715 return all_actions;
01716 }
01717
01718
01719
01720
01721
01722
01723
01724
01725
01726
01727 action *parse_rhs_action(void)
01728 {
01729 action *all_actions, *new_actions, *last;
01730 Symbol *var;
01731 rhs_value funcall_value;
01732
01733 if (current_agent(lexeme).type != L_PAREN_LEXEME) {
01734 print("Expected ( to begin RHS action\n");
01735 print_location_of_most_recent_lexeme();
01736 return NIL;
01737 }
01738 get_lexeme();
01739 if (current_agent(lexeme).type != VARIABLE_LEXEME) {
01740
01741 funcall_value = parse_function_call_after_lparen(TRUE);
01742 if (!funcall_value)
01743 return NIL;
01744 allocate_with_pool(¤t_agent(action_pool), &all_actions);
01745 all_actions->type = FUNCALL_ACTION;
01746 all_actions->next = NIL;
01747 all_actions->value = funcall_value;
01748 return all_actions;
01749 }
01750
01751 var = make_variable(current_agent(lexeme).string);
01752 get_lexeme();
01753 all_actions = NIL;
01754 while (current_agent(lexeme).type != R_PAREN_LEXEME) {
01755 new_actions = parse_attr_value_make(var);
01756 if (new_actions) {
01757 for (last = new_actions; last->next != NIL; last = last->next);
01758 last->next = all_actions;
01759 all_actions = new_actions;
01760 } else {
01761 symbol_remove_ref(var);
01762 deallocate_action_list(all_actions);
01763 return NIL;
01764 }
01765 }
01766 get_lexeme();
01767 symbol_remove_ref(var);
01768 return all_actions;
01769 }
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779
01780 bool parse_rhs(action ** dest_rhs)
01781 {
01782 action *all_actions, *new_actions, *last;
01783
01784 all_actions = NIL;
01785 while (current_agent(lexeme).type != R_PAREN_LEXEME) {
01786 new_actions = parse_rhs_action();
01787 if (new_actions) {
01788 for (last = new_actions; last->next != NIL; last = last->next);
01789 last->next = all_actions;
01790 all_actions = new_actions;
01791 } else {
01792 deallocate_action_list(all_actions);
01793 return FALSE;
01794 }
01795 }
01796 *dest_rhs = all_actions;
01797 return TRUE;
01798 }
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813 action *destructively_reverse_action_list(action * a)
01814 {
01815 action *prev, *current, *next;
01816
01817 prev = NIL;
01818 current = a;
01819 while (current) {
01820 next = current->next;
01821 current->next = prev;
01822 prev = current;
01823 current = next;
01824 }
01825 return prev;
01826 }
01827
01828
01829
01830
01831
01832
01833
01834
01835
01836
01837
01838
01839 production *parse_production(void)
01840 {
01841 Symbol *name;
01842 char *documentation;
01843 condition *lhs, *lhs_top, *lhs_bottom;
01844 action *rhs;
01845 production *p;
01846 byte declared_support;
01847 byte prod_type;
01848 byte rete_addition_result;
01849 bool rhs_okay;
01850 bool interrupt_on_match;
01851
01852 reset_placeholder_variable_generator();
01853
01854
01855 if (current_agent(lexeme).type != SYM_CONSTANT_LEXEME) {
01856 print("Expected symbol for production name\n");
01857 print_location_of_most_recent_lexeme();
01858 return NIL;
01859 }
01860 name = make_sym_constant(current_agent(lexeme).string);
01861 get_lexeme();
01862
01863
01864 if (name->sc.production) {
01865 excise_production(name->sc.production, (bool) (TRUE && current_agent(sysparams)[TRACE_LOADING_SYSPARAM]));
01866 }
01867
01868
01869 if (current_agent(lexeme).type == QUOTED_STRING_LEXEME) {
01870 documentation = make_memory_block_for_string(current_agent(lexeme).string);
01871 get_lexeme();
01872 } else {
01873 documentation = NIL;
01874 }
01875
01876
01877 declared_support = UNDECLARED_SUPPORT;
01878 prod_type = USER_PRODUCTION_TYPE;
01879 interrupt_on_match = FALSE;
01880 for (;;) {
01881 if (current_agent(lexeme).type != SYM_CONSTANT_LEXEME)
01882 break;
01883 if (!strcmp(current_agent(lexeme).string, ":o-support")) {
01884 declared_support = DECLARED_O_SUPPORT;
01885 get_lexeme();
01886 continue;
01887 }
01888 if (!strcmp(current_agent(lexeme).string, ":i-support")) {
01889 declared_support = DECLARED_I_SUPPORT;
01890 get_lexeme();
01891 continue;
01892 }
01893 if (!strcmp(current_agent(lexeme).string, ":chunk")) {
01894 prod_type = CHUNK_PRODUCTION_TYPE;
01895 get_lexeme();
01896 continue;
01897 }
01898 if (!strcmp(current_agent(lexeme).string, ":default")) {
01899 prod_type = DEFAULT_PRODUCTION_TYPE;
01900 get_lexeme();
01901 continue;
01902 }
01903 if (!strcmp(current_agent(lexeme).string, ":interrupt")) {
01904 #ifdef MATCHTIME_INTERRUPT
01905 interrupt_on_match = TRUE;
01906 #else
01907 print("WARNING :interrupt is not supported with the current build options...");
01908 #endif
01909 get_lexeme();
01910 continue;
01911 }
01912 break;
01913 }
01914
01915
01916 lhs = parse_lhs();
01917 if (!lhs) {
01918 print_with_symbols("(Ignoring production %y)\n\n", name);
01919 if (documentation)
01920 free_memory_block_for_string(documentation);
01921 symbol_remove_ref(name);
01922
01923 return NIL;
01924 }
01925
01926
01927 if (current_agent(lexeme).type != RIGHT_ARROW_LEXEME) {
01928 print("Expected --> in production\n");
01929 print_location_of_most_recent_lexeme();
01930 print_with_symbols("(Ignoring production %y)\n\n", name);
01931 if (documentation)
01932 free_memory_block_for_string(documentation);
01933 symbol_remove_ref(name);
01934 deallocate_condition_list(lhs);
01935
01936 return NIL;
01937 }
01938 get_lexeme();
01939
01940
01941 rhs_okay = parse_rhs(&rhs);
01942 if (!rhs_okay) {
01943 print_with_symbols("(Ignoring production %y)\n\n", name);
01944 if (documentation)
01945 free_memory_block_for_string(documentation);
01946 symbol_remove_ref(name);
01947 deallocate_condition_list(lhs);
01948
01949 return NIL;
01950 }
01951 rhs = destructively_reverse_action_list(rhs);
01952
01953
01954
01955 if (current_agent(lexeme).type != R_PAREN_LEXEME) {
01956 print("Expected ) to end production\n");
01957 print_location_of_most_recent_lexeme();
01958 if (documentation)
01959 free_memory_block_for_string(documentation);
01960 print_with_symbols("(Ignoring production %y)\n\n", name);
01961 symbol_remove_ref(name);
01962 deallocate_condition_list(lhs);
01963 deallocate_action_list(rhs);
01964
01965 return NIL;
01966 }
01967
01968
01969 reset_variable_generator(lhs, rhs);
01970 substitute_for_placeholders_in_condition_list(lhs);
01971 substitute_for_placeholders_in_action_list(rhs);
01972
01973
01974 lhs_top = lhs;
01975 for (lhs_bottom = lhs; lhs_bottom->next != NIL; lhs_bottom = lhs_bottom->next);
01976 p = make_production(prod_type, name, &lhs_top, &lhs_bottom, &rhs, TRUE);
01977
01978 if (!p) {
01979 if (documentation)
01980 free_memory_block_for_string(documentation);
01981 print_with_symbols("(Ignoring production %y)\n\n", name);
01982 symbol_remove_ref(name);
01983 deallocate_condition_list(lhs_top);
01984 deallocate_action_list(rhs);
01985
01986 return NIL;
01987 }
01988
01989 p->documentation = documentation;
01990 p->declared_support = declared_support;
01991 p->interrupt = interrupt_on_match;
01992 rete_addition_result = add_production_to_rete(p, lhs_top, NIL, TRUE);
01993 deallocate_condition_list(lhs_top);
01994
01995 if (rete_addition_result == DUPLICATE_PRODUCTION) {
01996 excise_production(p, FALSE);
01997 p = NIL;
01998 }
01999
02000 return p;
02001 }
02002
02003
02004
02005
02006
02007
02008
02009
02010
02011
02012
02013
02014
02015
02016
02017