Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

trace.c

Go to the documentation of this file.
00001 /*************************************************************************
00002  *
00003  *  file:  trace.c
00004  *
00005  * =======================================================================
00006  *
00007  *                   Trace Format Routines for Soar 6
00008  *
00009  * This file contains definitions and routines for dealing with the trace
00010  * formats used by Soar 6.  Trace format are specified by the user as
00011  * strings (with % escape sequences in them).  At entry time, Soar 6 
00012  * parses these strings into trace_format structures.
00013  *
00014  * see soarkernel.h for more comments.
00015  *
00016  * =======================================================================
00017  *
00018  * Copyright 1995-2003 Carnegie Mellon University,
00019  *                                                                               University of Michigan,
00020  *                                                                               University of Southern California/Information
00021  *                                                                               Sciences Institute. All rights reserved.
00022  *                                                                              
00023  * Redistribution and use in source and binary forms, with or without
00024  * modification, are permitted provided that the following conditions are met:
00025  *
00026  * 1.   Redistributions of source code must retain the above copyright notice,
00027  *              this list of conditions and the following disclaimer. 
00028  * 2.   Redistributions in binary form must reproduce the above copyright notice,
00029  *              this list of conditions and the following disclaimer in the documentation
00030  *              and/or other materials provided with the distribution. 
00031  *
00032  * THIS SOFTWARE IS PROVIDED BY THE SOAR CONSORTIUM ``AS IS'' AND ANY EXPRESS OR
00033  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00034  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
00035  * EVENT SHALL THE SOAR CONSORTIUM  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00036  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00037  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00038  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00039  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00040  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00041  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00042  * The views and conclusions contained in the software and documentation are
00043  * those of the authors and should not be interpreted as representing official
00044  * policies, either expressed or implied, of Carnegie Mellon University, the
00045  * University of Michigan, the University of Southern California/Information
00046  * Sciences Institute, or the Soar consortium.
00047  * =======================================================================
00048  */
00049 
00050 #include "soarkernel.h"
00051 #include <ctype.h>
00052 
00053 /* --- trace format types --- */
00054 
00055 enum trace_format_type {
00056     STRING_TFT,                 /* print a string */
00057     PERCENT_TFT,                /* print a percent sign */
00058     L_BRACKET_TFT,              /* print a left bracket */
00059     R_BRACKET_TFT,              /* print a right bracket */
00060     VALUES_TFT,                 /* print values of attr path or '*' */
00061     VALUES_RECURSIVELY_TFT,     /* ditto only print recursively */
00062     ATTS_AND_VALUES_TFT,        /* ditto only print attr's too */
00063     ATTS_AND_VALUES_RECURSIVELY_TFT,    /* combination of the two above */
00064     CURRENT_STATE_TFT,          /* print current state */
00065     CURRENT_OPERATOR_TFT,       /* print current operator */
00066     DECISION_CYCLE_COUNT_TFT,   /* print # of dc's */
00067     ELABORATION_CYCLE_COUNT_TFT,        /* print # of ec's */
00068     IDENTIFIER_TFT,             /* print identifier of object */
00069     IF_ALL_DEFINED_TFT,         /* print subformat if it's defined */
00070     LEFT_JUSTIFY_TFT,           /* left justify the subformat */
00071     RIGHT_JUSTIFY_TFT,          /* right justify the subformat */
00072     SUBGOAL_DEPTH_TFT,          /* print # of subgoal depth */
00073     REPEAT_SUBGOAL_DEPTH_TFT,   /* repeat subformat s.d. times */
00074     NEWLINE_TFT
00075 };                              /* print a newline */
00076 
00077 /* --- trace_format structure --- */
00078 
00079 typedef struct trace_format_struct {
00080     struct trace_format_struct *next;   /* next in linked list of format items */
00081     enum trace_format_type type;        /* what kind of item this is */
00082     int num;                    /* for formats with extra numeric arg */
00083     union trace_format_data_union {     /* data depending on trace format type */
00084         char *string;           /* string to print */
00085         struct trace_format_struct *subformat;  /* [subformat in brackets] */
00086         list *attribute_path;   /* list.of.attr.path.symbols (NIL if path is '*') */
00087     } data;
00088 } trace_format;
00089 
00090 /* ----------------------------------------------------------------------
00091                      Deallocate Trace Format List
00092 
00093    This deallocates all the memory used by a (list of) trace_format.
00094 ---------------------------------------------------------------------- */
00095 
00096 void deallocate_trace_format_list(trace_format * tf)
00097 {
00098     trace_format *next;
00099 
00100     while (tf) {
00101         switch (tf->type) {
00102         case STRING_TFT:
00103             free_memory_block_for_string(tf->data.string);
00104             break;
00105 
00106         case VALUES_TFT:
00107         case VALUES_RECURSIVELY_TFT:
00108         case ATTS_AND_VALUES_TFT:
00109         case ATTS_AND_VALUES_RECURSIVELY_TFT:
00110             deallocate_symbol_list_removing_references(tf->data.attribute_path);
00111             break;
00112 
00113         case IF_ALL_DEFINED_TFT:
00114         case LEFT_JUSTIFY_TFT:
00115         case RIGHT_JUSTIFY_TFT:
00116         case REPEAT_SUBGOAL_DEPTH_TFT:
00117             deallocate_trace_format_list(tf->data.subformat);
00118             break;
00119 
00120         default:
00121             break;              /* do nothing */
00122         }
00123         next = tf->next;
00124         free_memory(tf, MISCELLANEOUS_MEM_USAGE);
00125         tf = next;
00126     }
00127 }
00128 
00129 /* ----------------------------------------------------------------------
00130                    Trace Format String Parsing Routines
00131 
00132    Parse_format_string() parses a format string and returns a trace_format
00133    structure for it, or NIL if any error occurred.  This is the top-level
00134    routine here.
00135 
00136    While parsing is in progress, the global variable "format" points to
00137    the current character in the string.  This is advanced through the 
00138    string as parsing proceeds.  Parsing is done by recursive descent.
00139    If any parsing routine encouters an error, it sets the global variable
00140    "format_string_error_message" to be some appropriate error message,
00141    and leaves "format" pointing to the location of the error.
00142 
00143    Parse_attribute_path_in_brackets() reads "[attr.path.or.star]" and
00144    returns the path (consed list, or NIL for the '*' path).  
00145 
00146    Parse_pattern_in_brackets() reads "[subformat pattern]" and returns
00147    the trace format.
00148 
00149    Parse_item_from_format_string() is the main workhorse.  It reads from
00150    the current location up to the end of the item--a string, an escape
00151    sequence (with arguments), etc.  The end of an item is delineated by
00152    the end-of-string, a "[" or "]", or the end of the escape sequence.
00153 ---------------------------------------------------------------------- */
00154 
00155 const char *format;
00156 char *format_string_error_message;
00157 
00158 trace_format *parse_item_from_format_string(void);
00159 
00160 trace_format *parse_format_string(const char *string)
00161 {
00162     trace_format *first, *prev, *new;
00163 
00164     format = string;
00165     format_string_error_message = NIL;
00166 
00167     prev = NIL;
00168     first = NIL;                /* unnecessary, but gcc -Wall warns without it */
00169     while (*format != 0) {
00170         new = parse_item_from_format_string();
00171         if (!new) {
00172             if (prev)
00173                 prev->next = NIL;
00174             else
00175                 first = NIL;
00176             deallocate_trace_format_list(first);
00177             print("Error:  bad trace format string: %s\n", string);
00178             if (format_string_error_message) {
00179                 print("        %s\n", format_string_error_message);
00180                 print("        Error found at: %s\n", format);
00181             }
00182             return NIL;
00183         }
00184         if (prev)
00185             prev->next = new;
00186         else
00187             first = new;
00188         prev = new;
00189     }
00190     if (prev)
00191         prev->next = NIL;
00192     else
00193         first = NIL;
00194 
00195     return first;
00196 }
00197 
00198 list *parse_attribute_path_in_brackets(void)
00199 {
00200     list *path;
00201     char name[MAX_LEXEME_LENGTH + 20], *ch;
00202     Symbol *sym;
00203 
00204     /* --- look for opening bracket --- */
00205     if (*format != '[') {
00206         format_string_error_message = "Expected '[' followed by attribute (path)";
00207         return NIL;
00208     }
00209     format++;
00210 
00211     /* --- check for '*' (null path) --- */
00212     if (*format == '*') {
00213         path = NIL;
00214         format++;
00215     } else {
00216         /* --- normal case: read the attribute path --- */
00217         path = NIL;
00218         for (;;) {
00219             ch = name;
00220             while ((*format != 0) && (*format != ']') && (*format != '.'))
00221                 *ch++ = *format++;
00222             if (*format == 0) {
00223                 format_string_error_message = "'[' without closing ']'";
00224                 deallocate_symbol_list_removing_references(path);
00225                 return NIL;
00226             }
00227             if (ch == name) {
00228                 format_string_error_message = "null attribute found in attribute path";
00229                 deallocate_symbol_list_removing_references(path);
00230                 return NIL;
00231             }
00232             *ch = 0;
00233             sym = make_sym_constant(name);
00234             push(sym, path);
00235             if (*format == ']')
00236                 break;
00237             format++;           /* skip past '.' */
00238         }
00239         path = destructively_reverse_list(path);
00240     }
00241 
00242     /* --- look for closing bracket --- */
00243     if (*format != ']') {
00244         format_string_error_message = "'[' without closing ']'";
00245         deallocate_symbol_list_removing_references(path);
00246         return NIL;
00247     }
00248     format++;
00249 
00250     return path;
00251 }
00252 
00253 trace_format *parse_pattern_in_brackets(bool read_opening_bracket)
00254 {
00255     trace_format *first, *prev, *new;
00256 
00257     /* --- look for opening bracket --- */
00258     if (read_opening_bracket) {
00259         if (*format != '[') {
00260             format_string_error_message = "Expected '[' followed by attribute path";
00261             return NIL;
00262         }
00263         format++;
00264     }
00265 
00266     /* --- read pattern --- */
00267     prev = NIL;
00268     first = NIL;                /* unnecessary, but gcc -Wall warns without it */
00269     while ((*format != 0) && (*format != ']')) {
00270         new = parse_item_from_format_string();
00271         if (!new) {
00272             if (prev)
00273                 prev->next = NIL;
00274             else
00275                 first = NIL;
00276             deallocate_trace_format_list(first);
00277             return NIL;
00278         }
00279         if (prev)
00280             prev->next = new;
00281         else
00282             first = new;
00283         prev = new;
00284     }
00285     if (prev)
00286         prev->next = NIL;
00287     else
00288         first = NIL;
00289 
00290     /* --- look for closing bracket --- */
00291     if (*format != ']') {
00292         format_string_error_message = "'[' without closing ']'";
00293         deallocate_trace_format_list(first);
00294         return NIL;
00295     }
00296     format++;
00297 
00298     return first;
00299 }
00300 
00301 trace_format *parse_item_from_format_string(void)
00302 {
00303     trace_format *tf, *pattern;
00304     char *ch;
00305     list *attribute_path;
00306     int n;
00307 
00308     if (*format == 0)
00309         return NIL;
00310     if (*format == ']')
00311         return NIL;
00312     if (*format == '[') {
00313         format_string_error_message = "unexpected '[' character";
00314         return NIL;
00315     }
00316 
00317     if (*format != '%') {
00318         char buf[MAX_LEXEME_LENGTH + 20];
00319 
00320         ch = buf;
00321         while ((*format != 0) && (*format != '%') && (*format != '[') && (*format != ']'))
00322             *ch++ = *format++;
00323         *ch = 0;
00324         tf = allocate_memory(sizeof(trace_format), MISCELLANEOUS_MEM_USAGE);
00325         tf->type = STRING_TFT;
00326         tf->data.string = make_memory_block_for_string(buf);
00327         return tf;
00328     }
00329 
00330     /* --- otherwise *format is '%', so parse the escape sequence --- */
00331 
00332     if (!strncmp(format, "%v", 2)) {
00333         format += 2;
00334         attribute_path = parse_attribute_path_in_brackets();
00335         if (format_string_error_message)
00336             return NIL;
00337         tf = allocate_memory(sizeof(trace_format), MISCELLANEOUS_MEM_USAGE);
00338         tf->type = VALUES_TFT;
00339         tf->data.attribute_path = attribute_path;
00340         return tf;
00341     }
00342 
00343     if (!strncmp(format, "%o", 2)) {
00344         format += 2;
00345         attribute_path = parse_attribute_path_in_brackets();
00346         if (format_string_error_message)
00347             return NIL;
00348         tf = allocate_memory(sizeof(trace_format), MISCELLANEOUS_MEM_USAGE);
00349         tf->type = VALUES_RECURSIVELY_TFT;
00350         tf->data.attribute_path = attribute_path;
00351         return tf;
00352     }
00353 
00354     if (!strncmp(format, "%av", 3)) {
00355         format += 3;
00356         attribute_path = parse_attribute_path_in_brackets();
00357         if (format_string_error_message)
00358             return NIL;
00359         tf = allocate_memory(sizeof(trace_format), MISCELLANEOUS_MEM_USAGE);
00360         tf->type = ATTS_AND_VALUES_TFT;
00361         tf->data.attribute_path = attribute_path;
00362         return tf;
00363     }
00364 
00365     if (!strncmp(format, "%ao", 3)) {
00366         format += 3;
00367         attribute_path = parse_attribute_path_in_brackets();
00368         if (format_string_error_message)
00369             return NIL;
00370         tf = allocate_memory(sizeof(trace_format), MISCELLANEOUS_MEM_USAGE);
00371         tf->type = ATTS_AND_VALUES_RECURSIVELY_TFT;
00372         tf->data.attribute_path = attribute_path;
00373         return tf;
00374     }
00375 
00376     if (!strncmp(format, "%cs", 3)) {
00377         format += 3;
00378         tf = allocate_memory(sizeof(trace_format), MISCELLANEOUS_MEM_USAGE);
00379         tf->type = CURRENT_STATE_TFT;
00380         return tf;
00381     }
00382 
00383     if (!strncmp(format, "%co", 3)) {
00384         format += 3;
00385         tf = allocate_memory(sizeof(trace_format), MISCELLANEOUS_MEM_USAGE);
00386         tf->type = CURRENT_OPERATOR_TFT;
00387         return tf;
00388     }
00389 
00390     if (!strncmp(format, "%dc", 3)) {
00391         format += 3;
00392         tf = allocate_memory(sizeof(trace_format), MISCELLANEOUS_MEM_USAGE);
00393         tf->type = DECISION_CYCLE_COUNT_TFT;
00394         return tf;
00395     }
00396 
00397     if (!strncmp(format, "%ec", 3)) {
00398         format += 3;
00399         tf = allocate_memory(sizeof(trace_format), MISCELLANEOUS_MEM_USAGE);
00400         tf->type = ELABORATION_CYCLE_COUNT_TFT;
00401         return tf;
00402     }
00403 
00404     if (!strncmp(format, "%%", 2)) {
00405         format += 2;
00406         tf = allocate_memory(sizeof(trace_format), MISCELLANEOUS_MEM_USAGE);
00407         tf->type = PERCENT_TFT;
00408         return tf;
00409     }
00410 
00411     if (!strncmp(format, "%[", 2)) {
00412         format += 2;
00413         tf = allocate_memory(sizeof(trace_format), MISCELLANEOUS_MEM_USAGE);
00414         tf->type = L_BRACKET_TFT;
00415         return tf;
00416     }
00417 
00418     if (!strncmp(format, "%]", 2)) {
00419         format += 2;
00420         tf = allocate_memory(sizeof(trace_format), MISCELLANEOUS_MEM_USAGE);
00421         tf->type = R_BRACKET_TFT;
00422         return tf;
00423     }
00424 
00425     if (!strncmp(format, "%sd", 3)) {
00426         format += 3;
00427         tf = allocate_memory(sizeof(trace_format), MISCELLANEOUS_MEM_USAGE);
00428         tf->type = SUBGOAL_DEPTH_TFT;
00429         return tf;
00430     }
00431 
00432     if (!strncmp(format, "%id", 3)) {
00433         format += 3;
00434         tf = allocate_memory(sizeof(trace_format), MISCELLANEOUS_MEM_USAGE);
00435         tf->type = IDENTIFIER_TFT;
00436         return tf;
00437     }
00438 
00439     if (!strncmp(format, "%ifdef", 6)) {
00440         format += 6;
00441         pattern = parse_pattern_in_brackets(TRUE);
00442         if (format_string_error_message)
00443             return NIL;
00444         tf = allocate_memory(sizeof(trace_format), MISCELLANEOUS_MEM_USAGE);
00445         tf->type = IF_ALL_DEFINED_TFT;
00446         tf->data.subformat = pattern;
00447         return tf;
00448     }
00449 
00450     if (!strncmp(format, "%left", 5)) {
00451         format += 5;
00452         if (*format != '[') {
00453             format_string_error_message = "Expected '[' after %left";
00454             return NIL;
00455         }
00456         format++;
00457         if (!isdigit(*format)) {
00458             format_string_error_message = "Expected number with %left";
00459             return NIL;
00460         }
00461         n = 0;
00462         while (isdigit(*format))
00463             n = 10 * n + (*format++ - '0');
00464         if (*format != ',') {
00465             format_string_error_message = "Expected ',' after number in %left";
00466             return NIL;
00467         }
00468         format++;
00469         pattern = parse_pattern_in_brackets(FALSE);
00470         if (format_string_error_message)
00471             return NIL;
00472         tf = allocate_memory(sizeof(trace_format), MISCELLANEOUS_MEM_USAGE);
00473         tf->type = LEFT_JUSTIFY_TFT;
00474         tf->num = n;
00475         tf->data.subformat = pattern;
00476         return tf;
00477     }
00478 
00479     if (!strncmp(format, "%right", 6)) {
00480         format += 6;
00481         if (*format != '[') {
00482             format_string_error_message = "Expected '[' after %right";
00483             return NIL;
00484         }
00485         format++;
00486         if (!isdigit(*format)) {
00487             format_string_error_message = "Expected number with %right";
00488             return NIL;
00489         }
00490         n = 0;
00491         while (isdigit(*format))
00492             n = 10 * n + (*format++ - '0');
00493         if (*format != ',') {
00494             format_string_error_message = "Expected ',' after number in %right";
00495             return NIL;
00496         }
00497         format++;
00498         pattern = parse_pattern_in_brackets(FALSE);
00499         if (format_string_error_message)
00500             return NIL;
00501         tf = allocate_memory(sizeof(trace_format), MISCELLANEOUS_MEM_USAGE);
00502         tf->type = RIGHT_JUSTIFY_TFT;
00503         tf->num = n;
00504         tf->data.subformat = pattern;
00505         return tf;
00506     }
00507 
00508     if (!strncmp(format, "%rsd", 4)) {
00509         format += 4;
00510         pattern = parse_pattern_in_brackets(TRUE);
00511         if (format_string_error_message)
00512             return NIL;
00513         tf = allocate_memory(sizeof(trace_format), MISCELLANEOUS_MEM_USAGE);
00514         tf->type = REPEAT_SUBGOAL_DEPTH_TFT;
00515         tf->data.subformat = pattern;
00516         return tf;
00517     }
00518 
00519     if (!strncmp(format, "%nl", 3)) {
00520         format += 3;
00521         tf = allocate_memory(sizeof(trace_format), MISCELLANEOUS_MEM_USAGE);
00522         tf->type = NEWLINE_TFT;
00523         return tf;
00524     }
00525 
00526     /* --- if we haven't recognized it yet, we don't understand it --- */
00527     format_string_error_message = "Unrecognized escape sequence";
00528     return NIL;
00529 }
00530 
00531 /* ----------------------------------------------------------------------
00532                       Print Trace Format List
00533 
00534    This routine takes a trace format (list) and prints it out as a format
00535    string (without the surrounding quotation marks).
00536 ---------------------------------------------------------------------- */
00537 
00538 void print_trace_format_list(trace_format * tf)
00539 {
00540     cons *c;
00541 
00542     for (; tf != NIL; tf = tf->next) {
00543         switch (tf->type) {
00544         case STRING_TFT:
00545             {
00546                 char *s;
00547                 int i, len;
00548 
00549                 s = string_to_escaped_string(tf->data.string, '"', NULL);
00550                 len = strlen(s);
00551                 for (i = 1; i < len - 1; i++)
00552                     print("%c", *(s + i));
00553             }
00554             break;
00555         case PERCENT_TFT:
00556             print_string("%%");
00557             break;
00558         case L_BRACKET_TFT:
00559             print_string("%[");
00560             break;
00561         case R_BRACKET_TFT:
00562             print_string("%]");
00563             break;
00564 
00565         case VALUES_TFT:
00566         case VALUES_RECURSIVELY_TFT:
00567         case ATTS_AND_VALUES_TFT:
00568         case ATTS_AND_VALUES_RECURSIVELY_TFT:
00569             if (tf->type == VALUES_TFT)
00570                 print_string("%v[");
00571             else if (tf->type == VALUES_RECURSIVELY_TFT)
00572                 print_string("%o[");
00573             else if (tf->type == ATTS_AND_VALUES_TFT)
00574                 print_string("%av[");
00575             else
00576                 print_string("%ao[");
00577             if (tf->data.attribute_path) {
00578                 for (c = tf->data.attribute_path; c != NIL; c = c->rest) {
00579                     print_string(((Symbol *) (c->first))->sc.name);
00580                     if (c->rest)
00581                         print_string(".");
00582                 }
00583             } else {
00584                 print_string("*");
00585             }
00586             print_string("]");
00587             break;
00588 
00589         case CURRENT_STATE_TFT:
00590             print_string("%cs");
00591             break;
00592         case CURRENT_OPERATOR_TFT:
00593             print_string("%co");
00594             break;
00595         case DECISION_CYCLE_COUNT_TFT:
00596             print_string("%dc");
00597             break;
00598         case ELABORATION_CYCLE_COUNT_TFT:
00599             print_string("%ec");
00600             break;
00601         case IDENTIFIER_TFT:
00602             print_string("%id");
00603             break;
00604 
00605         case IF_ALL_DEFINED_TFT:
00606             print_string("%ifdef[");
00607             print_trace_format_list(tf->data.subformat);
00608             print_string("]");
00609             break;
00610 
00611         case LEFT_JUSTIFY_TFT:
00612         case RIGHT_JUSTIFY_TFT:
00613             if (tf->type == LEFT_JUSTIFY_TFT)
00614                 print_string("%left[");
00615             else
00616                 print_string("%right[");
00617             print("%d,", tf->num);
00618             print_trace_format_list(tf->data.subformat);
00619             print_string("]");
00620             break;
00621 
00622         case SUBGOAL_DEPTH_TFT:
00623             print_string("%sd");
00624             break;
00625 
00626         case REPEAT_SUBGOAL_DEPTH_TFT:
00627             print_string("%rsd[");
00628             print_trace_format_list(tf->data.subformat);
00629             print_string("]");
00630             break;
00631 
00632         case NEWLINE_TFT:
00633             print_string("%nl");
00634             break;
00635 
00636         default:
00637             {
00638                 char msg[MESSAGE_SIZE];
00639                 strncpy(msg, "Internal error: bad trace format type\n", MESSAGE_SIZE);
00640                 msg[MESSAGE_SIZE - 1] = 0;
00641                 abort_with_fatal_error(msg);
00642             }
00643         }
00644     }
00645 }
00646 
00647 /* ======================================================================
00648                     Trace Format Specification Tables
00649 
00650    We maintain tables of object trace formats and selection trace formats.
00651    Trace formats that apply to any *|g|p|s|o are stored in the arrays
00652    object_tf_for_anything[] and stack_tf_for_anything[].  (The array
00653    entry is NIL if no trace format has been specified.)  Trace formats that
00654    apply to *|g|p|s|o's with a certain name are stored in the hash tables
00655    object_tr_ht[] and stack_tr_ht[].  (Hash tables are used so we can
00656    look up the trace format from an object's name quickly.)
00657 
00658    Init_tracing() initializes the tables; at this point, there are no trace
00659    formats for anything.  This routine should be called at startup time.
00660 
00661    Trace formats are changed by calls to add_trace_format() and
00662    remove_trace_format().  Lookup_trace_format() returns the trace
00663    format matching a given type restriction and/or name restriction,
00664    or NIL if no such format has been specified.  Add_trace_format() returns
00665    TRUE if the format was successfully added, or FALSE if the format
00666    string didn't parse right.  Remove_trace_format() returns TRUE if
00667    a trace format was actually removed, or FALSE if there was no such
00668    trace format for the given type/name restrictions.  These routines take
00669    a "stack_trace" argument, which should be TRUE if the stack trace
00670    format is intended, or FALSE if the object trace format is intended.
00671    Their "type_restriction" argument should be one of FOR_ANYTHING_TF,
00672    ..., FOR_OPERATORS_TF (see soarkernel.h).  The "name_restriction" 
00673    argument should be either a pointer to a symbol, if the trace format 
00674    is restricted to apply to objects with that name, or NIL if the format
00675    can apply to any object.
00676    
00677    Print_all_trace_formats() prints out either all existing stack trace
00678    or object trace formats.
00679 ====================================================================== */
00680 
00681 /* --- trace formats that don't test the object name --- */
00682 
00683 typedef struct tracing_rule_struct {
00684     /* Warning: this MUST be the first field, for the hash table routines */
00685     struct tracing_rule_struct *next_in_hash_bucket;
00686     int type_restriction;       /* FOR_STATES_TF, etc. */
00687     Symbol *name_restriction;   /* points to name Symbol, or NIL */
00688     trace_format *format;       /* indicates the format to use */
00689 } tracing_rule;
00690 
00691 #define hash_name_restriction(name,num_bits) \
00692   ((name)->common.hash_id & masks_for_n_low_order_bits[(num_bits)])
00693 
00694 /* --- hash function for resizable hash table routines --- */
00695 unsigned long tracing_rule_hash_function(void *item, short num_bits)
00696 {
00697     tracing_rule *tr;
00698 
00699     tr = item;
00700     return hash_name_restriction(tr->name_restriction, num_bits);
00701 }
00702 
00703 /* --- hash tables for stack and object traces --- */
00704 
00705 void init_tracing(void)
00706 {
00707     int i;
00708 
00709     for (i = 0; i < 3; i++) {
00710         current_agent(object_tr_ht)[i] = make_hash_table(0, tracing_rule_hash_function);
00711         current_agent(stack_tr_ht)[i] = make_hash_table(0, tracing_rule_hash_function);
00712         current_agent(object_tf_for_anything)[i] = NIL;
00713         current_agent(stack_tf_for_anything)[i] = NIL;
00714     }
00715 }
00716 
00717 trace_format *lookup_trace_format(bool stack_trace, int type_restriction, Symbol * name_restriction)
00718 {
00719     unsigned long hash_value;
00720     hash_table *ht;
00721     tracing_rule *tr;
00722 
00723     if (name_restriction) {
00724         if (stack_trace)
00725             ht = current_agent(stack_tr_ht)[type_restriction];
00726         else
00727             ht = current_agent(object_tr_ht)[type_restriction];
00728         hash_value = hash_name_restriction(name_restriction, ht->log2size);
00729         tr = (tracing_rule *) (*(ht->buckets + hash_value));
00730         for (; tr != NIL; tr = tr->next_in_hash_bucket)
00731             if (tr->name_restriction == name_restriction)
00732                 return tr->format;
00733         return NIL;
00734     }
00735     /* --- no name restriction --- */
00736     if (stack_trace)
00737         return current_agent(stack_tf_for_anything)[type_restriction];
00738     else
00739         return current_agent(object_tf_for_anything)[type_restriction];
00740 }
00741 
00742 bool remove_trace_format(bool stack_trace, int type_restriction, Symbol * name_restriction)
00743 {
00744     unsigned long hash_value;
00745     hash_table *ht;
00746     tracing_rule *tr;
00747     trace_format **format;
00748 
00749     if (name_restriction) {
00750         if (stack_trace)
00751             ht = current_agent(stack_tr_ht)[type_restriction];
00752         else
00753             ht = current_agent(object_tr_ht)[type_restriction];
00754         hash_value = hash_name_restriction(name_restriction, ht->log2size);
00755         tr = (tracing_rule *) (*(ht->buckets + hash_value));
00756         for (; tr != NIL; tr = tr->next_in_hash_bucket)
00757             if (tr->name_restriction == name_restriction)
00758                 break;
00759         if (!tr)
00760             return FALSE;
00761         deallocate_trace_format_list(tr->format);
00762         remove_from_hash_table(ht, tr);
00763         free_memory(tr, MISCELLANEOUS_MEM_USAGE);
00764         symbol_remove_ref(name_restriction);
00765         return TRUE;
00766     }
00767     /* --- no name restriction --- */
00768     if (stack_trace)
00769         format = &(current_agent(stack_tf_for_anything)[type_restriction]);
00770     else
00771         format = &(current_agent(object_tf_for_anything)[type_restriction]);
00772     if (!*format)
00773         return FALSE;
00774     deallocate_trace_format_list(*format);
00775     *format = NIL;
00776     return TRUE;
00777 }
00778 
00779 bool add_trace_format(bool stack_trace, int type_restriction, Symbol * name_restriction, const char *format_string)
00780 {
00781     tracing_rule *tr;
00782     trace_format *new_tf;
00783     hash_table *ht;
00784 
00785     /* --- parse the format string into a trace_format --- */
00786     new_tf = parse_format_string(format_string);
00787     if (!new_tf)
00788         return FALSE;
00789 
00790     /* --- first remove any existing trace format with same conditions --- */
00791     remove_trace_format(stack_trace, type_restriction, name_restriction);
00792 
00793     /* --- now add the new one --- */
00794     if (name_restriction) {
00795         symbol_add_ref(name_restriction);
00796         if (stack_trace)
00797             ht = current_agent(stack_tr_ht)[type_restriction];
00798         else
00799             ht = current_agent(object_tr_ht)[type_restriction];
00800         tr = allocate_memory(sizeof(tracing_rule), MISCELLANEOUS_MEM_USAGE);
00801         tr->type_restriction = type_restriction;
00802         tr->name_restriction = name_restriction;
00803         tr->format = new_tf;
00804         add_to_hash_table(ht, tr);
00805         return TRUE;
00806     }
00807     /* --- no name restriction --- */
00808     if (stack_trace)
00809         current_agent(stack_tf_for_anything)[type_restriction] = new_tf;
00810     else
00811         current_agent(object_tf_for_anything)[type_restriction] = new_tf;
00812 
00813     return TRUE;
00814 }
00815 
00816 char tracing_object_letters[3] = { '*', 's', 'o' };
00817 
00818 /* 
00819    This, along with some other functions in this file, had a doppleganger
00820    with the same name, but a _tcl suffix.  The difference 
00821    (as I understand it) is simply formatting style.  The _tcl versions
00822    using the new style (Soar 7.0.4 and above).  Since the old formating
00823    is obsolete, I have removed the old functions, and renamed those with
00824    new versions by removing the _tcl (since they really have nothing to do 
00825    with Tcl at all).
00826    081699 SW
00827 */
00828 void print_tracing_rule(int type_restriction, Symbol * name_restriction, trace_format * format)
00829 {
00830     print("%c ", tracing_object_letters[type_restriction]);
00831     if (name_restriction)
00832         print_with_symbols("%y ", name_restriction);
00833     print_string("{");
00834     print_trace_format_list(format);
00835     print("}\n");
00836 }
00837 
00838 /* 
00839    This, along with some other functions in this file, had a doppleganger
00840    with the same name, but a _tcl suffix.  The difference 
00841    (as I understand it) is simply formatting style.  The _tcl versions
00842    using the new style (Soar 7.0.4 and above).  Since the old formating
00843    is obsolete, I have removed the old functions, and renamed those with
00844    new versions by removing the _tcl (since they really have nothing to do 
00845    with Tcl at all).
00846    081699 SW
00847 */
00848 bool print_trace_callback_fn(void *item)
00849 {
00850     tracing_rule *tr;
00851 
00852     tr = item;
00853     print_tracing_rule(tr->type_restriction, tr->name_restriction, tr->format);
00854     return FALSE;
00855 }
00856 
00857 /* 
00858    This, along with some other functions in this file, had a doppleganger
00859    with the same name, but a _tcl suffix.  The difference 
00860    (as I understand it) is simply formatting style.  The _tcl versions
00861    using the new style (Soar 7.0.4 and above).  Since the old formating
00862    is obsolete, I have removed the old functions, and renamed those with
00863    new versions by removing the _tcl (since they really have nothing to do 
00864    with Tcl at all).
00865    081699 SW
00866 */
00867 
00868 void print_all_trace_formats(bool stack_trace)
00869 {
00870     int i;
00871 
00872     current_agent(printing_stack_traces) = stack_trace;
00873     if (stack_trace) {
00874         for (i = 0; i < 3; i++) {
00875             if (current_agent(stack_tf_for_anything)[i])
00876                 print_tracing_rule(i, NIL, current_agent(stack_tf_for_anything)[i]);
00877             do_for_all_items_in_hash_table(current_agent(stack_tr_ht)[i], print_trace_callback_fn);
00878         }
00879     } else {
00880         for (i = 0; i < 3; i++) {
00881             if (current_agent(object_tf_for_anything)[i])
00882                 print_tracing_rule(i, NIL, current_agent(object_tf_for_anything)[i]);
00883             do_for_all_items_in_hash_table(current_agent(object_tr_ht)[i], print_trace_callback_fn);
00884         }
00885     }
00886 }
00887 
00888 /* ======================================================================
00889                       Trace Format List To String
00890 
00891    Trace_format_list_to_string() is the main routine which, given a
00892    trace format and a current object, builds and returns a growable_string
00893    for that object's printout.  A number of helper routines are used by
00894    trace_format_list_to_string().
00895 ====================================================================== */
00896 
00897 growable_string object_to_trace_string(Symbol * object);
00898 
00899 bool found_undefined;           /* set to TRUE whenever an escape sequence result is
00900                                    undefined--for use with %ifdef */
00901 
00902 struct tracing_parameters {
00903     Symbol *current_s;          /* current state, etc. -- for use in %cs, etc. */
00904     Symbol *current_o;
00905     bool allow_cycle_counts;    /* TRUE means allow %dc and %ec */
00906 } tparams;
00907 
00908 /* ----------------------------------------------------------------
00909    Adds all values of the given attribute path off the given object
00910    to the "*result" growable_string.  If "recursive" is TRUE, the
00911    values are printed recursively as objects, rather than as simple
00912    atomic values.  "*count" is incremented each time a value is
00913    printed.  (To get a count of how many values were printed, the
00914    caller should initialize this to 0, then call this routine.)
00915 ---------------------------------------------------------------- */
00916 
00917 void add_values_of_attribute_path(Symbol * object, list * path, growable_string * result, bool recursive, int *count)
00918 {
00919     slot *s;
00920     wme *w;
00921     char *ch;
00922     growable_string gs;
00923 
00924     if (!path) {                /* path is NIL, so we've reached the end of the path */
00925         add_to_growable_string(result, " ");
00926         if (recursive) {
00927             gs = object_to_trace_string(object);
00928             add_to_growable_string(result, text_of_growable_string(gs));
00929             free_growable_string(gs);
00930         } else {
00931             ch = symbol_to_string(object, TRUE, NULL, 0);
00932             add_to_growable_string(result, ch);
00933         }
00934         (*count)++;
00935         return;
00936     }
00937 
00938     /* --- not at end of path yet --- */
00939     /* --- can't follow any more path segments off of a non-identifier --- */
00940     if (object->common.symbol_type != IDENTIFIER_SYMBOL_TYPE)
00941         return;
00942 
00943     /* --- call this routine recursively on any wme matching the first segment
00944        of the attribute path --- */
00945     for (w = object->id.impasse_wmes; w != NIL; w = w->next)
00946         if (w->attr == path->first)
00947             add_values_of_attribute_path(w->value, path->rest, result, recursive, count);
00948     for (w = object->id.input_wmes; w != NIL; w = w->next)
00949         if (w->attr == path->first)
00950             add_values_of_attribute_path(w->value, path->rest, result, recursive, count);
00951     s = find_slot(object, path->first);
00952     if (s) {
00953         for (w = s->wmes; w != NIL; w = w->next)
00954             add_values_of_attribute_path(w->value, path->rest, result, recursive, count);
00955     }
00956 }
00957 
00958 /* ----------------------------------------------------------------
00959    Adds info for a wme to the given "*result" growable_string. If
00960    "print_attribute" is TRUE, then "^att-name" is included.  If
00961    "recursive" is TRUE, the value is printed recursively as an
00962    object, rather than as a simple atomic value.
00963 ---------------------------------------------------------------- */
00964 
00965 void add_trace_for_wme(growable_string * result, wme * w, bool print_attribute, bool recursive)
00966 {
00967     char *ch;
00968     growable_string gs;
00969 
00970     add_to_growable_string(result, " ");
00971     if (print_attribute) {
00972         add_to_growable_string(result, "^");
00973         ch = symbol_to_string(w->attr, TRUE, NULL, 0);
00974         add_to_growable_string(result, ch);
00975         add_to_growable_string(result, " ");
00976     }
00977     if (recursive) {
00978         gs = object_to_trace_string(w->value);
00979         add_to_growable_string(result, text_of_growable_string(gs));
00980         free_growable_string(gs);
00981     } else {
00982         ch = symbol_to_string(w->value, TRUE, NULL, 0);
00983         add_to_growable_string(result, ch);
00984     }
00985 }
00986 
00987 /* ----------------------------------------------------------------
00988    Adds the trace for values of a given attribute path off a given
00989    object, to the given "*result" growable_string.  If
00990    "print_attributes" is TRUE, then "^att-name" is included.  If
00991    "recursive" is TRUE, the values are printed recursively as 
00992    objects, rather than as a simple atomic value.  If the given path
00993    is NIL, then all values of all attributes of the given object
00994    are printed.
00995 ---------------------------------------------------------------- */
00996 
00997 void add_trace_for_attribute_path(Symbol * object,
00998                                   list * path, growable_string * result, bool print_attributes, bool recursive)
00999 {
01000     growable_string values;
01001     cons *c;
01002     char *ch;
01003     int count;
01004     slot *s;
01005     wme *w;
01006 
01007     values = make_blank_growable_string();
01008 
01009     if (!path) {
01010         if (object->common.symbol_type != IDENTIFIER_SYMBOL_TYPE)
01011             return;
01012         for (s = object->id.slots; s != NIL; s = s->next)
01013             for (w = s->wmes; w != NIL; w = w->next)
01014                 add_trace_for_wme(&values, w, print_attributes, recursive);
01015         for (w = object->id.impasse_wmes; w != NIL; w = w->next)
01016             add_trace_for_wme(&values, w, print_attributes, recursive);
01017         for (w = object->id.input_wmes; w != NIL; w = w->next)
01018             add_trace_for_wme(&values, w, print_attributes, recursive);
01019         if (length_of_growable_string(values) > 0)
01020             add_to_growable_string(result, text_of_growable_string(values) + 1);
01021         free_growable_string(values);
01022         return;
01023     }
01024 
01025     count = 0;
01026     add_values_of_attribute_path(object, path, &values, recursive, &count);
01027     if (!count) {
01028         found_undefined = TRUE;
01029         free_growable_string(values);
01030         return;
01031     }
01032 
01033     if (print_attributes) {
01034         add_to_growable_string(result, "^");
01035         for (c = path; c != NIL; c = c->rest) {
01036             ch = symbol_to_string(c->first, TRUE, NULL, 0);
01037             add_to_growable_string(result, ch);
01038             if (c->rest)
01039                 add_to_growable_string(result, ".");
01040         }
01041         add_to_growable_string(result, " ");
01042     }
01043     if (length_of_growable_string(values) > 0)
01044         add_to_growable_string(result, text_of_growable_string(values) + 1);
01045     free_growable_string(values);
01046 }
01047 
01048 /* ----------------------------------------------------------------
01049    This is the main routine here.  It returns a growable_string,
01050    given a trace format list (the format to use) and an object (the
01051    object being printed).
01052 ---------------------------------------------------------------- */
01053 
01054 #define TRACE_FORMAT_LIST_TO_STRING_BUF_SIZE 50
01055 growable_string trace_format_list_to_string(trace_format * tf, Symbol * object)
01056 {
01057     char buf[TRACE_FORMAT_LIST_TO_STRING_BUF_SIZE], *ch;
01058     growable_string result, temp_gs;
01059     int i;
01060 
01061     result = make_blank_growable_string();
01062 
01063     for (; tf != NIL; tf = tf->next) {
01064         switch (tf->type) {
01065         case STRING_TFT:
01066             add_to_growable_string(&result, tf->data.string);
01067             break;
01068         case PERCENT_TFT:
01069             add_to_growable_string(&result, "%");
01070             break;
01071         case L_BRACKET_TFT:
01072             add_to_growable_string(&result, "[");
01073             break;
01074         case R_BRACKET_TFT:
01075             add_to_growable_string(&result, "]");
01076             break;
01077 
01078         case VALUES_TFT:
01079             add_trace_for_attribute_path(object, tf->data.attribute_path, &result, FALSE, FALSE);
01080             break;
01081         case VALUES_RECURSIVELY_TFT:
01082             add_trace_for_attribute_path(object, tf->data.attribute_path, &result, FALSE, TRUE);
01083             break;
01084         case ATTS_AND_VALUES_TFT:
01085             add_trace_for_attribute_path(object, tf->data.attribute_path, &result, TRUE, FALSE);
01086             break;
01087         case ATTS_AND_VALUES_RECURSIVELY_TFT:
01088             add_trace_for_attribute_path(object, tf->data.attribute_path, &result, TRUE, TRUE);
01089             break;
01090 
01091         case CURRENT_STATE_TFT:
01092             if (!tparams.current_s) {
01093                 found_undefined = TRUE;
01094             } else {
01095                 temp_gs = object_to_trace_string(tparams.current_s);
01096                 add_to_growable_string(&result, text_of_growable_string(temp_gs));
01097                 free_growable_string(temp_gs);
01098             }
01099             break;
01100         case CURRENT_OPERATOR_TFT:
01101             if (!tparams.current_o) {
01102                 found_undefined = TRUE;
01103             } else {
01104                 temp_gs = object_to_trace_string(tparams.current_o);
01105                 add_to_growable_string(&result, text_of_growable_string(temp_gs));
01106                 free_growable_string(temp_gs);
01107             }
01108             break;
01109 
01110         case DECISION_CYCLE_COUNT_TFT:
01111             if (tparams.allow_cycle_counts) {
01112                 snprintf(buf, TRACE_FORMAT_LIST_TO_STRING_BUF_SIZE, "%lu", current_agent(d_cycle_count));
01113                 buf[TRACE_FORMAT_LIST_TO_STRING_BUF_SIZE - 1] = 0;      /* snprintf doesn't set last char to null if output is truncated */
01114                 add_to_growable_string(&result, buf);
01115             } else {
01116                 found_undefined = TRUE;
01117             }
01118             break;
01119         case ELABORATION_CYCLE_COUNT_TFT:
01120             if (tparams.allow_cycle_counts) {
01121                 snprintf(buf, TRACE_FORMAT_LIST_TO_STRING_BUF_SIZE, "%lu", current_agent(e_cycle_count));
01122                 buf[TRACE_FORMAT_LIST_TO_STRING_BUF_SIZE - 1] = 0;      /* snprintf doesn't set last char to null if output is truncated */
01123                 add_to_growable_string(&result, buf);
01124             } else {
01125                 found_undefined = TRUE;
01126             }
01127             break;
01128 
01129         case IDENTIFIER_TFT:
01130             ch = symbol_to_string(object, TRUE, NULL, 0);
01131             add_to_growable_string(&result, ch);
01132             break;
01133 
01134         case IF_ALL_DEFINED_TFT:
01135             {
01136                 bool saved_found_undefined;
01137                 saved_found_undefined = found_undefined;
01138                 found_undefined = FALSE;
01139                 temp_gs = trace_format_list_to_string(tf->data.subformat, object);
01140                 if (!found_undefined)
01141                     add_to_growable_string(&result, text_of_growable_string(temp_gs));
01142                 free_growable_string(temp_gs);
01143                 found_undefined = saved_found_undefined;
01144             }
01145             break;
01146 
01147         case LEFT_JUSTIFY_TFT:
01148             temp_gs = trace_format_list_to_string(tf->data.subformat, object);
01149             add_to_growable_string(&result, text_of_growable_string(temp_gs));
01150             for (i = tf->num - length_of_growable_string(temp_gs); i > 0; i--)
01151                 add_to_growable_string(&result, " ");
01152             free_growable_string(temp_gs);
01153             break;
01154 
01155         case RIGHT_JUSTIFY_TFT:
01156             temp_gs = trace_format_list_to_string(tf->data.subformat, object);
01157             for (i = tf->num - length_of_growable_string(temp_gs); i > 0; i--)
01158                 add_to_growable_string(&result, " ");
01159             add_to_growable_string(&result, text_of_growable_string(temp_gs));
01160             free_growable_string(temp_gs);
01161             break;
01162 
01163         case SUBGOAL_DEPTH_TFT:
01164             if (tparams.current_s) {
01165                 snprintf(buf, TRACE_FORMAT_LIST_TO_STRING_BUF_SIZE, "%u", tparams.current_s->id.level - 1);
01166                 buf[TRACE_FORMAT_LIST_TO_STRING_BUF_SIZE - 1] = 0;      /* snprintf doesn't set last char to null if output is truncated */
01167                 add_to_growable_string(&result, buf);
01168             } else {
01169                 found_undefined = TRUE;
01170             }
01171             break;
01172 
01173         case REPEAT_SUBGOAL_DEPTH_TFT:
01174             if (tparams.current_s) {
01175                 temp_gs = trace_format_list_to_string(tf->data.subformat, object);
01176                 for (i = tparams.current_s->id.level - 1; i > 0; i--)
01177                     add_to_growable_string(&result, text_of_growable_string(temp_gs));
01178                 free_growable_string(temp_gs);
01179             } else {
01180                 found_undefined = TRUE;
01181             }
01182             break;
01183 
01184         case NEWLINE_TFT:
01185             add_to_growable_string(&result, "\n");
01186             break;
01187 
01188         default:
01189             {
01190                 char msg[MESSAGE_SIZE];
01191                 strncpy(msg, "Internal error: bad trace format type\n", MESSAGE_SIZE);
01192                 msg[MESSAGE_SIZE - 1] = 0;
01193                 abort_with_fatal_error(msg);
01194             }
01195         }
01196     }
01197     return result;
01198 }
01199 
01200 /* ======================================================================
01201                Building Traces for Object and Selections
01202 
01203    Find_appropriate_trace_format() looks for an applicable trace_format
01204    among the current set of tracing rules.
01205 
01206    Object_to_trace_string() takes an object and returns a growable_string
01207    to use for its printed trace.
01208 
01209    Selection_to_trace_string() takes an object (the current selection),
01210    the current state, a "selection_type" (one of FOR_OPERATORS_TF, etc.),
01211    and a flag indicating whether %dc, %ec, etc. escapes should be
01212    allowed, and returns a growable_string to use for the trace.
01213 ====================================================================== */
01214 
01215                           /* prevents infinite loops when printing circular
01216                              structures */
01217 
01218 trace_format *find_appropriate_trace_format(bool stack_trace, int type, Symbol * name)
01219 {
01220     trace_format *tf;
01221 
01222     /* --- first try to find the exact one --- */
01223     tf = lookup_trace_format(stack_trace, type, name);
01224     if (tf)
01225         return tf;
01226 
01227     /* --- failing that, try ignoring the type but retaining the name --- */
01228     if (type != FOR_ANYTHING_TF) {
01229         tf = lookup_trace_format(stack_trace, FOR_ANYTHING_TF, name);
01230         if (tf)
01231             return tf;
01232     }
01233 
01234     /* --- failing that, try ignoring the name but retaining the type --- */
01235     if (name) {
01236         tf = lookup_trace_format(stack_trace, type, NIL);
01237         if (tf)
01238             return tf;
01239     }
01240 
01241     /* --- last resort: find a format that applies to anything at all --- */
01242     return lookup_trace_format(stack_trace, FOR_ANYTHING_TF, NIL);
01243 }
01244 
01245 growable_string object_to_trace_string(Symbol * object)
01246 {
01247     growable_string gs;
01248     int type_of_object;
01249     trace_format *tf;
01250     Symbol *name;
01251     struct tracing_parameters saved_tparams;
01252 
01253     /* --- If it's not an identifier, just print it as an atom.  Also, if it's
01254        already being printed, print it as an atom to avoid getting into an
01255        infinite loop. --- */
01256     if ((object->common.symbol_type != IDENTIFIER_SYMBOL_TYPE) || (object->id.tc_num == current_agent(tf_printing_tc))) {
01257         gs = make_blank_growable_string();
01258         add_to_growable_string(&gs, symbol_to_string(object, TRUE, NIL, 0));
01259         return gs;
01260     }
01261 
01262     /* --- mark it as being printed --- */
01263     object->id.tc_num = current_agent(tf_printing_tc);
01264 
01265     /* --- determine the type and name of the object --- */
01266     if (object->id.isa_goal)
01267         type_of_object = FOR_STATES_TF;
01268     else if (object->id.isa_operator)
01269         type_of_object = FOR_OPERATORS_TF;
01270     else
01271         type_of_object = FOR_ANYTHING_TF;
01272 
01273     name = find_name_of_object(object);
01274 
01275     /* --- find the trace format to use --- */
01276     tf = find_appropriate_trace_format(FALSE, type_of_object, name);
01277 
01278     /* --- now call trace_format_list_to_string() --- */
01279     if (tf) {
01280         saved_tparams = tparams;
01281         tparams.current_s = tparams.current_o = NIL;
01282         tparams.allow_cycle_counts = FALSE;
01283         gs = trace_format_list_to_string(tf, object);
01284         tparams = saved_tparams;
01285     } else {
01286         /* --- no applicable trace format, so just print the object itself --- */
01287         gs = make_blank_growable_string();
01288         add_to_growable_string(&gs, symbol_to_string(object, TRUE, NIL, 0));
01289     }
01290 
01291     object->id.tc_num = 0;      /* unmark it now that we're done */
01292     return gs;
01293 }
01294 
01295 growable_string selection_to_trace_string(Symbol * object,
01296                                           Symbol * current_state, int selection_type, bool allow_cycle_counts)
01297 {
01298     trace_format *tf;
01299     Symbol *name;
01300     growable_string gs;
01301     struct tracing_parameters saved_tparams;
01302 
01303     /* --- find the problem space name --- */
01304     name = NIL;
01305 
01306     /* --- find the trace format to use --- */
01307     tf = find_appropriate_trace_format(TRUE, selection_type, name);
01308 
01309     /* --- if there's no applicable trace format, print nothing --- */
01310     if (!tf)
01311         return make_blank_growable_string();
01312 
01313     /* --- save/restore tparams, and call trace_format_list_to_string() --- */
01314     saved_tparams = tparams;
01315     tparams.current_s = tparams.current_o = NIL;
01316     if (current_state) {
01317         tparams.current_s = current_state;
01318         if (current_state->id.operator_slot->wmes) {
01319             tparams.current_o = current_state->id.operator_slot->wmes->value;
01320         }
01321     }
01322     tparams.allow_cycle_counts = allow_cycle_counts;
01323     gs = trace_format_list_to_string(tf, object);
01324     tparams = saved_tparams;
01325 
01326     return gs;
01327 }
01328 
01329 /* ======================================================================
01330                    Printing Object and Stack Traces 
01331 
01332    Print_object_trace() takes an object (any symbol).  It prints
01333    the trace for that object.  Print_stack_trace() takes a (context)
01334    object (the state or op), the current state, the "slot_type" (one
01335    of FOR_OPERATORS_TF, etc.), and a flag indicating whether to allow
01336    %dc and %ec escapes (this flag should normally be TRUE for watch 0
01337    traces but FALSE during a "pgs" command).  It prints the trace for
01338    that context object.
01339 ====================================================================== */
01340 
01341 void print_object_trace(Symbol * object)
01342 {
01343     growable_string gs;
01344 
01345     current_agent(tf_printing_tc) = get_new_tc_number();
01346     gs = object_to_trace_string(object);
01347     print_string(text_of_growable_string(gs));
01348     free_growable_string(gs);
01349 }
01350 
01351 void print_stack_trace(Symbol * object, Symbol * state, int slot_type, bool allow_cycle_counts)
01352 {
01353     growable_string gs;
01354 
01355     current_agent(tf_printing_tc) = get_new_tc_number();
01356     gs = selection_to_trace_string(object, state, slot_type, allow_cycle_counts);
01357     print_string(text_of_growable_string(gs));
01358     free_growable_string(gs);
01359 }
01360 
01361 /* kjh(B1) begin */
01362 void print_object_trace_using_provided_format_string(Symbol * object, Symbol * current_goal, char *format_string)
01363 {
01364     growable_string gs;
01365     struct tracing_parameters saved_tparams;
01366     trace_format *fs;
01367 
01368     fs = parse_format_string(format_string);
01369 
01370     current_agent(tf_printing_tc) = get_new_tc_number();
01371 
01372     saved_tparams = tparams;
01373 
01374     if (current_goal)
01375         tparams.current_s = current_goal;
01376     tparams.allow_cycle_counts = TRUE;
01377 
01378     gs = trace_format_list_to_string(fs, object);
01379 
01380     tparams = saved_tparams;
01381 
01382     if (current_agent(printer_output_column) != 1)
01383         print_string("\n");
01384 
01385     print_string(text_of_growable_string(gs));
01386     free_growable_string(gs);
01387 }
01388 
01389 /* kjh(B1) end */

Generated on Thu Dec 11 13:00:24 2003 for Soar Kernel by doxygen 1.3.5