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
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 #include "soarkernel.h"
00067 #include <ctype.h>
00068 #include <errno.h>
00069 #include "soarapiUtils.h"
00070
00071 #ifdef _AIX
00072 #include <sys/select.h>
00073 #endif
00074
00075 extern void gds_invalid_so_remove_goal(wme * w);
00076 void calculate_output_link_tc_info(output_link * ol);
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 Symbol *get_new_io_identifier(char first_letter)
00101 {
00102
00103 return make_new_identifier(first_letter, TOP_GOAL_LEVEL);
00104 }
00105
00106 Symbol *get_io_sym_constant(char *name)
00107 {
00108 return make_sym_constant(name);
00109 }
00110
00111 Symbol *get_io_int_constant(long value)
00112 {
00113 return make_int_constant(value);
00114 }
00115
00116 Symbol *get_io_float_constant(float value)
00117 {
00118 return make_float_constant(value);
00119 }
00120
00121 void release_io_symbol(Symbol * sym)
00122 {
00123 symbol_remove_ref(sym);
00124 }
00125
00126 wme *add_input_wme(Symbol * id, Symbol * attr, Symbol * value)
00127 {
00128 wme *w;
00129
00130
00131 if (!(id && attr && value)) {
00132 print("Error: an input routine gave a NULL argument to add_input_wme.\n");
00133 return NIL;
00134 }
00135
00136 w = make_wme(id, attr, value, FALSE);
00137 insert_at_head_of_dll(id->id.input_wmes, w, next, prev);
00138 add_wme_to_wm(w);
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149 return w;
00150 }
00151
00152 bool remove_input_wme(wme * w)
00153 {
00154 wme *temp;
00155
00156
00157 if (!w) {
00158 print("Error: an input routine called remove_input_wme on a NULL wme.\n");
00159 return FALSE;
00160 }
00161 for (temp = w->id->id.input_wmes; temp != NIL; temp = temp->next)
00162 if (temp == w)
00163 break;
00164 if (!temp) {
00165 print("Error: an input routine called remove_input_wme on a wme that\n");
00166 print("isn't one of the input wmes currently in working memory.\n");
00167 return FALSE;
00168 }
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179 remove_from_dll(w->id->id.input_wmes, w, next, prev);
00180
00181 #ifndef SOAR_8_ONLY
00182 if (current_agent(operand2_mode)) {
00183 #endif
00184 if (w->gds) {
00185 if (w->gds->goal != NIL) {
00186 if (current_agent(soar_verbose_flag))
00187 print("\nremove_input_wme: Removing goal %d because element in GDS changed.\n",
00188 w->gds->goal->id.level);
00189 gds_invalid_so_remove_goal(w);
00190
00191
00192 }
00193 }
00194 #ifndef SOAR_8_ONLY
00195 }
00196 #endif
00197
00198
00199
00200 remove_wme_from_wm(w);
00201
00202 return TRUE;
00203 }
00204
00205 #ifndef NO_IO_CALLBACKS
00206
00207 void do_input_cycle(void)
00208 {
00209 wme *w;
00210
00211 #ifndef TRACE_CONTEXT_DECISIONS_ONLY
00212 if (current_agent(sysparams)[TRACE_PHASES_SYSPARAM])
00213 print("\n--- Input Phase --- \n");
00214 #endif
00215
00216 if (current_agent(prev_top_state) && (!current_agent(top_state))) {
00217
00218 release_io_symbol(current_agent(io_header));
00219 release_io_symbol(current_agent(io_header_input));
00220 release_io_symbol(current_agent(io_header_output));
00221 current_agent(io_header) = NIL;
00222 current_agent(io_header_input) = NIL;
00223 current_agent(io_header_output) = NIL;
00224 current_agent(io_header_link) = NIL;
00225 soar_invoke_callbacks(soar_agent, INPUT_PHASE_CALLBACK, (soar_call_data) TOP_STATE_JUST_REMOVED);
00226 } else if ((!current_agent(prev_top_state)) && current_agent(top_state)) {
00227
00228
00229 current_agent(io_header) = get_new_io_identifier('I');
00230 current_agent(io_header_link) = add_input_wme(current_agent(top_state),
00231 current_agent(io_symbol), current_agent(io_header));
00232 current_agent(io_header_input) = get_new_io_identifier('I');
00233 current_agent(io_header_output) = get_new_io_identifier('I');
00234 w = add_input_wme(current_agent(io_header), make_sym_constant("input-link"), current_agent(io_header_input));
00235
00236 w = add_input_wme(current_agent(io_header), make_sym_constant("output-link"), current_agent(io_header_output));
00237
00238
00239
00240
00241 do_buffered_wm_and_ownership_changes();
00242
00243 soar_invoke_callbacks(soar_agent, INPUT_PHASE_CALLBACK, (soar_call_data) TOP_STATE_JUST_CREATED);
00244 }
00245
00246
00247
00248 if (current_agent(top_state)) {
00249 soar_invoke_callbacks(soar_agent, INPUT_PHASE_CALLBACK, (soar_call_data) NORMAL_INPUT_CYCLE);
00250 }
00251
00252
00253 do_buffered_wm_and_ownership_changes();
00254
00255
00256 current_agent(prev_top_state) = current_agent(top_state);
00257
00258
00259
00260
00261
00262
00263
00264 current_agent(output_link_changed) = FALSE;
00265 }
00266
00267 #else
00268 void do_input_cycle(void)
00269 {
00270
00271
00272
00273
00274
00275
00276 current_agent(prev_top_state) = current_agent(top_state);
00277 current_agent(output_link_changed) = FALSE;
00278
00279 }
00280
00281 #endif
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310 #define NEW_OL_STATUS 0
00311 #define UNCHANGED_OL_STATUS 1
00312 #define MODIFIED_BUT_SAME_TC_OL_STATUS 2
00313
00314
00315 #define MODIFIED_OL_STATUS 3
00316
00317 #define REMOVED_OL_STATUS 4
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345 #define LINK_NAME_SIZE 1024
00346 void update_for_top_state_wme_addition(wme * w)
00347 {
00348 output_link *ol;
00349 soar_callback *cb;
00350 char link_name[LINK_NAME_SIZE];
00351
00352
00353 symbol_to_string(w->attr, FALSE, link_name, LINK_NAME_SIZE);
00354
00355 cb = soar_exists_callback_id(soar_agent, OUTPUT_PHASE_CALLBACK, link_name);
00356
00357 if (!cb)
00358 return;
00359
00360
00361 allocate_with_pool(¤t_agent(output_link_pool), &ol);
00362 insert_at_head_of_dll(current_agent(existing_output_links), ol, next, prev);
00363
00364 ol->status = NEW_OL_STATUS;
00365 ol->link_wme = w;
00366 wme_add_ref(w);
00367 ol->ids_in_tc = NIL;
00368 ol->cb = cb;
00369
00370 w->output_link = ol;
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390 current_agent(output_link_tc_num) = get_new_tc_number();
00391 ol->link_wme->value->id.tc_num = current_agent(output_link_tc_num);
00392 current_agent(output_link_for_tc) = ol;
00393
00394 push(current_agent(output_link_for_tc), ol->link_wme->value->id.associated_output_links);
00395
00396 }
00397
00398 void update_for_top_state_wme_removal(wme * w)
00399 {
00400 if (!w->output_link)
00401 return;
00402 w->output_link->status = REMOVED_OL_STATUS;
00403 }
00404
00405 void update_for_io_wme_change(wme * w)
00406 {
00407 cons *c;
00408 output_link *ol;
00409
00410 for (c = w->id->id.associated_output_links; c != NIL; c = c->rest) {
00411 ol = c->first;
00412 if (w->value->common.symbol_type == IDENTIFIER_SYMBOL_TYPE) {
00413
00414 if ((ol->status == UNCHANGED_OL_STATUS) || (ol->status == MODIFIED_BUT_SAME_TC_OL_STATUS))
00415 ol->status = MODIFIED_OL_STATUS;
00416 } else {
00417
00418 if (ol->status == UNCHANGED_OL_STATUS)
00419 ol->status = MODIFIED_BUT_SAME_TC_OL_STATUS;
00420 }
00421 }
00422 }
00423
00424 void inform_output_module_of_wm_changes(list * wmes_being_added, list * wmes_being_removed)
00425 {
00426 cons *c;
00427 wme *w;
00428
00429
00430 for (c = wmes_being_added; c != NIL; c = c->rest) {
00431 w = c->first;
00432
00433 if (w->id == current_agent(io_header)) {
00434 update_for_top_state_wme_addition(w);
00435 current_agent(output_link_changed) = TRUE;
00436 }
00437 if (w->id->id.associated_output_links) {
00438 update_for_io_wme_change(w);
00439 current_agent(output_link_changed) = TRUE;
00440 }
00441 #if DEBUG_RTO
00442 else {
00443 char id[100];
00444
00445 symbol_to_string(w->id, FALSE, id);
00446 if (!strcmp(id, "I3")) {
00447 print("--> Added to I3, but doesn't register as an OL change!");
00448 }
00449 }
00450 #endif
00451
00452 }
00453 for (c = wmes_being_removed; c != NIL; c = c->rest) {
00454 w = c->first;
00455 if (w->id == current_agent(io_header))
00456 update_for_top_state_wme_removal(w);
00457 if (w->id->id.associated_output_links)
00458 update_for_io_wme_change(w);
00459 }
00460 }
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474 void remove_output_link_tc_info(output_link * ol)
00475 {
00476 cons *c, *prev_c;
00477 Symbol *id;
00478
00479 while (ol->ids_in_tc) {
00480 c = ol->ids_in_tc;
00481 ol->ids_in_tc = c->rest;
00482 id = c->first;
00483 free_cons(c);
00484
00485
00486 prev_c = NIL;
00487 for (c = id->id.associated_output_links; c != NIL; prev_c = c, c = c->rest)
00488 if (c->first == ol)
00489 break;
00490 if (!c) {
00491 char msg[MESSAGE_SIZE];
00492 strncpy(msg, "io.c: Internal error: can't find output link in id's list\n", MESSAGE_SIZE);
00493 msg[MESSAGE_SIZE - 1] = 0;
00494 abort_with_fatal_error(msg);
00495 }
00496 if (prev_c)
00497 prev_c->rest = c->rest;
00498 else
00499 id->id.associated_output_links = c->rest;
00500 free_cons(c);
00501 symbol_remove_ref(id);
00502 }
00503 }
00504
00505 void add_id_to_output_link_tc(Symbol * id)
00506 {
00507 slot *s;
00508 wme *w;
00509
00510
00511 if (id->id.tc_num == current_agent(output_link_tc_num))
00512 return;
00513 id->id.tc_num = current_agent(output_link_tc_num);
00514
00515
00516 push(id, current_agent(output_link_for_tc)->ids_in_tc);
00517 symbol_add_ref(id);
00518
00519
00520
00521 push(current_agent(output_link_for_tc), id->id.associated_output_links);
00522
00523
00524
00525 for (w = id->id.input_wmes; w != NIL; w = w->next)
00526 if (w->value->common.symbol_type == IDENTIFIER_SYMBOL_TYPE)
00527 add_id_to_output_link_tc(w->value);
00528 for (s = id->id.slots; s != NIL; s = s->next)
00529 for (w = s->wmes; w != NIL; w = w->next)
00530 if (w->value->common.symbol_type == IDENTIFIER_SYMBOL_TYPE)
00531 add_id_to_output_link_tc(w->value);
00532
00533
00534 }
00535
00536 void calculate_output_link_tc_info(output_link * ol)
00537 {
00538
00539 if (ol->link_wme->value->common.symbol_type != IDENTIFIER_SYMBOL_TYPE)
00540 return;
00541
00542
00543 current_agent(output_link_for_tc) = ol;
00544 current_agent(output_link_tc_num) = get_new_tc_number();
00545 add_id_to_output_link_tc(ol->link_wme->value);
00546 }
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558 void add_wme_to_collected_io_wmes(wme * w)
00559 {
00560 io_wme *new;
00561
00562 allocate_with_pool(¤t_agent(io_wme_pool), &new);
00563 new->next = current_agent(collected_io_wmes);
00564 current_agent(collected_io_wmes) = new;
00565 new->id = w->id;
00566 new->attr = w->attr;
00567 new->value = w->value;
00568 }
00569
00570 io_wme *get_io_wmes_for_output_link(output_link * ol)
00571 {
00572 cons *c;
00573 Symbol *id;
00574 slot *s;
00575 wme *w;
00576
00577 current_agent(collected_io_wmes) = NIL;
00578 add_wme_to_collected_io_wmes(ol->link_wme);
00579 for (c = ol->ids_in_tc; c != NIL; c = c->rest) {
00580 id = c->first;
00581 for (w = id->id.input_wmes; w != NIL; w = w->next)
00582 add_wme_to_collected_io_wmes(w);
00583 for (s = id->id.slots; s != NIL; s = s->next)
00584 for (w = s->wmes; w != NIL; w = w->next)
00585 add_wme_to_collected_io_wmes(w);
00586 }
00587 return current_agent(collected_io_wmes);
00588 }
00589
00590 void deallocate_io_wme_list(io_wme * iw)
00591 {
00592 io_wme *next;
00593
00594 while (iw) {
00595 next = iw->next;
00596 free_with_pool(¤t_agent(io_wme_pool), iw);
00597 iw = next;
00598 }
00599 }
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610 output_call_info output_call_data;
00611
00612 #ifndef NO_IO_CALLBACKS
00613
00614 void do_output_cycle(void)
00615 {
00616 output_link *ol, *next_ol;
00617 io_wme *iw_list;
00618
00619 #ifndef TRACE_CONTEXT_DECISIONS_ONLY
00620 if (current_agent(sysparams)[TRACE_PHASES_SYSPARAM])
00621 print("\n--- Output Phase ---\n");
00622 #endif
00623
00624 for (ol = current_agent(existing_output_links); ol != NIL; ol = next_ol) {
00625 next_ol = ol->next;
00626
00627 switch (ol->status) {
00628 case UNCHANGED_OL_STATUS:
00629
00630 break;
00631
00632 case NEW_OL_STATUS:
00633
00634
00635 calculate_output_link_tc_info(ol);
00636 iw_list = get_io_wmes_for_output_link(ol);
00637 output_call_data.mode = ADDED_OUTPUT_COMMAND;
00638 output_call_data.outputs = iw_list;
00639 (ol->cb->function) (soar_agent, ol->cb->data, &output_call_data);
00640 deallocate_io_wme_list(iw_list);
00641 ol->status = UNCHANGED_OL_STATUS;
00642 break;
00643
00644 case MODIFIED_BUT_SAME_TC_OL_STATUS:
00645
00646 iw_list = get_io_wmes_for_output_link(ol);
00647 output_call_data.mode = MODIFIED_OUTPUT_COMMAND;
00648 output_call_data.outputs = iw_list;
00649 (ol->cb->function) (soar_agent, ol->cb->data, &output_call_data);
00650 deallocate_io_wme_list(iw_list);
00651 ol->status = UNCHANGED_OL_STATUS;
00652 break;
00653
00654 case MODIFIED_OL_STATUS:
00655
00656 remove_output_link_tc_info(ol);
00657 calculate_output_link_tc_info(ol);
00658 iw_list = get_io_wmes_for_output_link(ol);
00659 output_call_data.mode = MODIFIED_OUTPUT_COMMAND;
00660 output_call_data.outputs = iw_list;
00661 (ol->cb->function) (soar_agent, ol->cb->data, &output_call_data);
00662 deallocate_io_wme_list(iw_list);
00663 ol->status = UNCHANGED_OL_STATUS;
00664 break;
00665
00666 case REMOVED_OL_STATUS:
00667
00668 remove_output_link_tc_info(ol);
00669 iw_list = get_io_wmes_for_output_link(ol);
00670 output_call_data.mode = REMOVED_OUTPUT_COMMAND;
00671 output_call_data.outputs = iw_list;
00672 (ol->cb->function) (soar_agent, ol->cb->data, &output_call_data);
00673 deallocate_io_wme_list(iw_list);
00674 wme_remove_ref(ol->link_wme);
00675 remove_from_dll(current_agent(existing_output_links), ol, next, prev);
00676 free_with_pool(¤t_agent(output_link_pool), ol);
00677 break;
00678 }
00679 }
00680 }
00681 #else
00682
00683 void do_output_cycle(void)
00684 {
00685 output_link *ol, *next_ol;
00686
00687 for (ol = current_agent(existing_output_links); ol != NIL; ol = next_ol) {
00688 next_ol = ol->next;
00689
00690 switch (ol->status) {
00691 case UNCHANGED_OL_STATUS:
00692
00693 break;
00694
00695 default:
00696 print("io.c: Error -- Output Link has changed, but kernel was built with NO_IO_CALLBACKS\n");
00697 }
00698 }
00699 }
00700 #endif
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715 Symbol *get_output_value(io_wme * outputs, Symbol * id, Symbol * attr)
00716 {
00717 io_wme *iw;
00718
00719 for (iw = outputs; iw != NIL; iw = iw->next)
00720 if (((id == NIL) || (id == iw->id)) && ((attr == NIL) || (attr == iw->attr)))
00721 return iw->value;
00722 return NIL;
00723 }
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746 bool tio_constituent_char[256];
00747 bool tio_whitespace[256];
00748
00749 Symbol *get_io_symbol_from_tio_constituent_string(char *input_string)
00750 {
00751 int int_val;
00752 float float_val;
00753 bool possible_id, possible_var, possible_sc, possible_ic, possible_fc;
00754 bool rereadable;
00755
00756 determine_possible_symbol_types_for_string(input_string,
00757 strlen(input_string),
00758 &possible_id,
00759 &possible_var, &possible_sc, &possible_ic, &possible_fc, &rereadable);
00760
00761
00762 if (possible_ic) {
00763 errno = 0;
00764 int_val = strtol(input_string, NULL, 10);
00765 if (errno) {
00766 print("Text Input Error: bad integer (probably too large)\n");
00767 return NIL;
00768 }
00769 return get_io_int_constant(int_val);
00770 }
00771
00772
00773 if (possible_fc) {
00774 errno = 0;
00775
00776 float_val = (float) strtod(input_string, NULL);
00777 if (errno) {
00778 print("Text Input Error: bad floating point number\n");
00779 return NIL;
00780 }
00781 return get_io_float_constant(float_val);
00782 }
00783
00784
00785 return get_io_sym_constant(input_string);
00786 }
00787
00788 #define MAX_TEXT_INPUT_LINE_LENGTH 1000
00789
00790 Symbol *get_next_io_symbol_from_text_input_line(char **text_read_position)
00791 {
00792 char *ch;
00793 char input_string[MAX_TEXT_INPUT_LINE_LENGTH + 2];
00794 int input_lexeme_length;
00795
00796 ch = *text_read_position;
00797
00798
00799 while (tio_whitespace[(unsigned char) (*ch)])
00800 ch++;
00801
00802
00803 if ((*ch == '\n') || (*ch == 0)) {
00804 *text_read_position = ch;
00805 return NIL;
00806 }
00807
00808
00809 if (!tio_constituent_char[(unsigned char) (*ch)]) {
00810 input_string[0] = *ch++;
00811 input_string[1] = 0;
00812 *text_read_position = ch;
00813 return get_io_sym_constant(input_string);
00814 }
00815
00816
00817 input_lexeme_length = 0;
00818 while (tio_constituent_char[(unsigned char) (*ch)])
00819 input_string[input_lexeme_length++] = *ch++;
00820
00821
00822 input_string[input_lexeme_length] = 0;
00823 *text_read_position = ch;
00824 return get_io_symbol_from_tio_constituent_string(input_string);
00825 }
00826
00827
00828
00829
00830
00831
00832
00833 char extra_tio_constituents[] = "+-._";
00834
00835 void init_soar_io(void)
00836 {
00837 unsigned int i;
00838
00839 init_memory_pool(¤t_agent(output_link_pool), sizeof(output_link), "output link");
00840 init_memory_pool(¤t_agent(io_wme_pool), sizeof(io_wme), "io wme");
00841
00842
00843 for (i = 0; i < 256; i++)
00844 tio_constituent_char[i] = (char) isalnum(i);
00845 for (i = 0; i < strlen(extra_tio_constituents); i++)
00846 tio_constituent_char[(int) extra_tio_constituents[i]] = TRUE;
00847
00848
00849 for (i = 0; i < 256; i++)
00850 tio_whitespace[i] = (char) isspace(i);
00851 tio_whitespace[(int) '\n'] = FALSE;
00852 }