Soar Kernel  9.3.2 08-06-12
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
trace.cpp
Go to the documentation of this file.
1 #include <portability.h>
2 
3 /*************************************************************************
4  * PLEASE SEE THE FILE "license.txt" (INCLUDED WITH THIS SOFTWARE PACKAGE)
5  * FOR LICENSE AND COPYRIGHT INFORMATION.
6  *************************************************************************/
7 
8 /*************************************************************************
9  *
10  * file: trace.cpp
11  *
12  * =======================================================================
13  *
14  * Trace Format Routines for Soar 6
15  *
16  * This file contains definitions and routines for dealing with the trace
17  * formats used by Soar 6. Trace format are specified by the user as
18  * strings (with % escape sequences in them). At entry time, Soar 6
19  * parses these strings into trace_format structures.
20  *
21  * see soarkernel.h for more comments.
22  *
23  * =======================================================================
24  */
25 
26 #include <stdlib.h>
27 
28 #include "trace.h"
29 #include "mem.h"
30 #include "production.h"
31 #include "kernel.h"
32 #include "lexer.h"
33 #include "symtab.h"
34 #include "agent.h"
35 #include "print.h"
36 #include "init_soar.h"
37 #include "gdatastructs.h"
38 #include "tempmem.h"
39 #include "wmem.h"
40 #include "xml.h"
41 #include "soar_TraceNames.h"
42 
43 #include <ctype.h>
44 
45 using namespace soar_TraceNames;
46 
47 /* --- trace format types --- */
48 
50  STRING_TFT, /* print a string */
51  PERCENT_TFT, /* print a percent sign */
52  L_BRACKET_TFT, /* print a left bracket */
53  R_BRACKET_TFT, /* print a right bracket */
54  VALUES_TFT, /* print values of attr path or '*' */
55  VALUES_RECURSIVELY_TFT, /* ditto only print recursively */
56  ATTS_AND_VALUES_TFT, /* ditto only print attr's too */
57  ATTS_AND_VALUES_RECURSIVELY_TFT, /* combination of the two above */
58  CURRENT_STATE_TFT, /* print current state */
59  CURRENT_OPERATOR_TFT, /* print current operator */
60  DECISION_CYCLE_COUNT_TFT, /* print # of dc's */
61  ELABORATION_CYCLE_COUNT_TFT, /* print # of ec's */
62  IDENTIFIER_TFT, /* print identifier of object */
63  IF_ALL_DEFINED_TFT, /* print subformat if it's defined */
64  LEFT_JUSTIFY_TFT, /* left justify the subformat */
65  RIGHT_JUSTIFY_TFT, /* right justify the subformat */
66  SUBGOAL_DEPTH_TFT, /* print # of subgoal depth */
67  REPEAT_SUBGOAL_DEPTH_TFT, /* repeat subformat s.d. times */
68  NEWLINE_TFT }; /* print a newline */
69 
70 /* --- trace_format structure --- */
71 
72 typedef struct trace_format_struct {
73  struct trace_format_struct *next; /* next in linked list of format items */
74  enum trace_format_type type; /* what kind of item this is */
75  int num; /* for formats with extra numeric arg */
76  union trace_format_data_union { /* data depending on trace format type */
77  char *string; /* string to print */
78  struct trace_format_struct *subformat; /* [subformat in brackets] */
79  list *attribute_path; /* list.of.attr.path.symbols (NIL if path is '*') */
80  } data;
81 } trace_format;
82 
83 /* ----------------------------------------------------------------------
84  Deallocate Trace Format List
85 
86  This deallocates all the memory used by a (list of) trace_format.
87 ---------------------------------------------------------------------- */
88 
91 
92  while (tf) {
93  switch (tf->type) {
94  case STRING_TFT:
95  free_memory_block_for_string (thisAgent, tf->data.string);
96  break;
97 
98  case VALUES_TFT:
100  case ATTS_AND_VALUES_TFT:
103  break;
104 
105  case IF_ALL_DEFINED_TFT:
106  case LEFT_JUSTIFY_TFT:
107  case RIGHT_JUSTIFY_TFT:
110  break;
111 
112  default:
113  break; /* do nothing */
114  }
115  next = tf->next;
116  free_memory (thisAgent, tf, MISCELLANEOUS_MEM_USAGE);
117  tf = next;
118  }
119 }
120 
121 /* ----------------------------------------------------------------------
122  Trace Format String Parsing Routines
123 
124  Parse_format_string() parses a format string and returns a trace_format
125  structure for it, or NIL if any error occurred. This is the top-level
126  routine here.
127 
128  While parsing is in progress, the global variable "format" points to
129  the current character in the string. This is advanced through the
130  string as parsing proceeds. Parsing is done by recursive descent.
131  If any parsing routine encouters an error, it sets the global variable
132  "format_string_error_message" to be some appropriate error message,
133  and leaves "format" pointing to the location of the error.
134 
135  Parse_attribute_path_in_brackets() reads "[attr.path.or.star]" and
136  returns the path (consed list, or NIL for the '*' path).
137 
138  Parse_pattern_in_brackets() reads "[subformat pattern]" and returns
139  the trace format.
140 
141  Parse_item_from_format_string() is the main workhorse. It reads from
142  the current location up to the end of the item--a string, an escape
143  sequence (with arguments), etc. The end of an item is delineated by
144  the end-of-string, a "[" or "]", or the end of the escape sequence.
145 ---------------------------------------------------------------------- */
146 
147 const char *format;
149 
151 
152 trace_format *parse_format_string (agent* thisAgent, const char *string) {
153  trace_format *first, *prev, *New;
154 
155  format = string;
157 
158  prev = NIL;
159  first = NIL; /* unnecessary, but gcc -Wall warns without it */
160  while (*format!=0) {
161  New = parse_item_from_format_string (thisAgent);
162  if (!New) {
163  if (prev) prev->next = NIL; else first = NIL;
164  deallocate_trace_format_list (thisAgent, first);
165  print (thisAgent, "Error: bad trace format string: %s\n", string);
167  print (thisAgent, " %s\n", format_string_error_message);
168  print (thisAgent, " Error found at: %s\n", format);
169  }
170  return NIL;
171  }
172  if (prev) prev->next = New; else first = New;
173  prev = New;
174  }
175  if (prev) prev->next = NIL; else first = NIL;
176 
177  return first;
178 }
179 
181  list *path;
182  char name[MAX_LEXEME_LENGTH+20], *ch;
183  Symbol *sym;
184 
185  /* --- look for opening bracket --- */
186  if (*format != '[') {
187  format_string_error_message = "Expected '[' followed by attribute (path)";
188  return NIL;
189  }
190  format++;
191 
192  /* --- check for '*' (null path) --- */
193  if (*format=='*') {
194  path = NIL;
195  format++;
196  } else {
197  /* --- normal case: read the attribute path --- */
198  path = NIL;
199  while (TRUE) {
200  ch = name;
201  while ((*format!=0)&&(*format!=']')&&(*format!='.')) *ch++ = *format++;
202  if (*format==0) {
203  format_string_error_message = "'[' without closing ']'";
205  return NIL;
206  }
207  if (ch==name) {
208  format_string_error_message = "null attribute found in attribute path";
210  return NIL;
211  }
212  *ch = 0;
213  sym = make_sym_constant (thisAgent, name);
214  push (thisAgent, sym, path);
215  if (*format==']') break;
216  format++; /* skip past '.' */
217  }
218  path = destructively_reverse_list (path);
219  }
220 
221  /* --- look for closing bracket --- */
222  if (*format != ']') {
223  format_string_error_message = "'[' without closing ']'";
225  return NIL;
226  }
227  format++;
228 
229  return path;
230 }
231 
232 trace_format *parse_pattern_in_brackets (agent* thisAgent, Bool read_opening_bracket) {
233  trace_format *first, *prev, *New;
234 
235  /* --- look for opening bracket --- */
236  if (read_opening_bracket) {
237  if (*format != '[') {
238  format_string_error_message = "Expected '[' followed by attribute path";
239  return NIL;
240  }
241  format++;
242  }
243 
244  /* --- read pattern --- */
245  prev = NIL;
246  first = NIL; /* unnecessary, but gcc -Wall warns without it */
247  while ((*format!=0) && (*format!=']')) {
248  New = parse_item_from_format_string (thisAgent);
249  if (!New) {
250  if (prev) prev->next = NIL; else first = NIL;
251  deallocate_trace_format_list (thisAgent, first);
252  return NIL;
253  }
254  if (prev) prev->next = New; else first = New;
255  prev = New;
256  }
257  if (prev) prev->next = NIL; else first = NIL;
258 
259  /* --- look for closing bracket --- */
260  if (*format != ']') {
261  format_string_error_message = "'[' without closing ']'";
262  deallocate_trace_format_list (thisAgent, first);
263  return NIL;
264  }
265  format++;
266 
267  return first;
268 }
269 
271  trace_format *tf, *pattern;
272  char *ch;
273  list *attribute_path;
274  int n;
275 
276  if (*format == 0) return NIL;
277  if (*format == ']') return NIL;
278  if (*format == '[') {
279  format_string_error_message = "unexpected '[' character";
280  return NIL;
281  }
282 
283  if (*format != '%') {
284  char buf[MAX_LEXEME_LENGTH+20];
285 
286  ch = buf;
287  while ((*format != 0) && (*format != '%') &&
288  (*format != '[') && (*format != ']'))
289  *ch++ = *format++;
290  *ch = 0;
291  tf = static_cast<trace_format_struct *>(allocate_memory (thisAgent, sizeof(trace_format),
293  tf->type = STRING_TFT;
294  tf->data.string = make_memory_block_for_string (thisAgent, buf);
295  return tf;
296  }
297 
298  /* --- otherwise *format is '%', so parse the escape sequence --- */
299 
300  if (!strncmp(format, "%v", 2)) {
301  format += 2;
302  attribute_path = parse_attribute_path_in_brackets (thisAgent);
303  if (format_string_error_message) return NIL;
304  tf = static_cast<trace_format_struct *>(allocate_memory (thisAgent, sizeof(trace_format),
306  tf->type = VALUES_TFT;
307  tf->data.attribute_path = attribute_path;
308  return tf;
309  }
310 
311  if (!strncmp(format, "%o", 2)) {
312  format += 2;
313  attribute_path = parse_attribute_path_in_brackets (thisAgent);
314  if (format_string_error_message) return NIL;
315  tf = static_cast<trace_format_struct *>(allocate_memory (thisAgent, sizeof(trace_format),
318  tf->data.attribute_path = attribute_path;
319  return tf;
320  }
321 
322  if (!strncmp(format, "%av", 3)) {
323  format += 3;
324  attribute_path = parse_attribute_path_in_brackets (thisAgent);
325  if (format_string_error_message) return NIL;
326  tf = static_cast<trace_format_struct *>(allocate_memory (thisAgent, sizeof(trace_format),
329  tf->data.attribute_path = attribute_path;
330  return tf;
331  }
332 
333  if (!strncmp(format, "%ao", 3)) {
334  format += 3;
335  attribute_path = parse_attribute_path_in_brackets (thisAgent);
336  if (format_string_error_message) return NIL;
337  tf = static_cast<trace_format_struct *>(allocate_memory (thisAgent, sizeof(trace_format),
340  tf->data.attribute_path = attribute_path;
341  return tf;
342  }
343 
344  if (!strncmp(format, "%cs", 3)) {
345  format += 3;
346  tf = static_cast<trace_format_struct *>(allocate_memory (thisAgent, sizeof(trace_format),
348  tf->type = CURRENT_STATE_TFT;
349  return tf;
350  }
351 
352  if (!strncmp(format, "%co", 3)) {
353  format += 3;
354  tf = static_cast<trace_format_struct *>(allocate_memory (thisAgent, sizeof(trace_format),
357  return tf;
358  }
359 
360  if (!strncmp(format, "%dc", 3)) {
361  format += 3;
362  tf = static_cast<trace_format_struct *>(allocate_memory (thisAgent, sizeof(trace_format),
365  return tf;
366  }
367 
368  if (!strncmp(format, "%ec", 3)) {
369  format += 3;
370  tf = static_cast<trace_format_struct *>(allocate_memory (thisAgent, sizeof(trace_format),
373  return tf;
374  }
375 
376  if (!strncmp(format, "%%", 2)) {
377  format += 2;
378  tf = static_cast<trace_format_struct *>(allocate_memory (thisAgent, sizeof(trace_format),
380  tf->type = PERCENT_TFT;
381  return tf;
382  }
383 
384  if (!strncmp(format, "%[", 2)) {
385  format += 2;
386  tf = static_cast<trace_format_struct *>(allocate_memory (thisAgent, sizeof(trace_format),
388  tf->type = L_BRACKET_TFT;
389  return tf;
390  }
391 
392  if (!strncmp(format, "%]", 2)) {
393  format += 2;
394  tf = static_cast<trace_format_struct *>(allocate_memory (thisAgent, sizeof(trace_format),
396  tf->type = R_BRACKET_TFT;
397  return tf;
398  }
399 
400  if (!strncmp(format, "%sd", 3)) {
401  format += 3;
402  tf = static_cast<trace_format_struct *>(allocate_memory (thisAgent, sizeof(trace_format),
404  tf->type = SUBGOAL_DEPTH_TFT;
405  return tf;
406  }
407 
408  if (!strncmp(format, "%id", 3)) {
409  format += 3;
410  tf = static_cast<trace_format_struct *>(allocate_memory (thisAgent, sizeof(trace_format),
412  tf->type = IDENTIFIER_TFT;
413  return tf;
414  }
415 
416  if (! strncmp (format, "%ifdef", 6)) {
417  format += 6;
418  pattern = parse_pattern_in_brackets (thisAgent, TRUE);
419  if (format_string_error_message) return NIL;
420  tf = static_cast<trace_format_struct *>(allocate_memory (thisAgent, sizeof(trace_format),
422  tf->type = IF_ALL_DEFINED_TFT;
423  tf->data.subformat = pattern;
424  return tf;
425  }
426 
427  if (! strncmp (format, "%left", 5)) {
428  format += 5;
429  if (*format != '[') {
430  format_string_error_message = "Expected '[' after %left";
431  return NIL;
432  }
433  format++;
434  if (! isdigit(*format)) {
435  format_string_error_message = "Expected number with %left";
436  return NIL;
437  }
438  n = 0;
439  while (isdigit(*format)) n = 10*n + (*format++ - '0');
440  if (*format != ',') {
441  format_string_error_message = "Expected ',' after number in %left";
442  return NIL;
443  }
444  format++;
445  pattern = parse_pattern_in_brackets (thisAgent, FALSE);
446  if (format_string_error_message) return NIL;
447  tf = static_cast<trace_format_struct *>(allocate_memory (thisAgent, sizeof(trace_format),
449  tf->type = LEFT_JUSTIFY_TFT;
450  tf->num = n;
451  tf->data.subformat = pattern;
452  return tf;
453  }
454 
455  if (! strncmp (format, "%right", 6)) {
456  format += 6;
457  if (*format != '[') {
458  format_string_error_message = "Expected '[' after %right";
459  return NIL;
460  }
461  format++;
462  if (! isdigit(*format)) {
463  format_string_error_message = "Expected number with %right";
464  return NIL;
465  }
466  n = 0;
467  while (isdigit(*format)) n = 10*n + (*format++ - '0');
468  if (*format != ',') {
469  format_string_error_message = "Expected ',' after number in %right";
470  return NIL;
471  }
472  format++;
473  pattern = parse_pattern_in_brackets (thisAgent, FALSE);
474  if (format_string_error_message) return NIL;
475  tf = static_cast<trace_format_struct *>(allocate_memory (thisAgent, sizeof(trace_format),
477  tf->type = RIGHT_JUSTIFY_TFT;
478  tf->num = n;
479  tf->data.subformat = pattern;
480  return tf;
481  }
482 
483  if (! strncmp (format, "%rsd", 4)) {
484  format += 4;
485  pattern = parse_pattern_in_brackets (thisAgent, TRUE);
486  if (format_string_error_message) return NIL;
487  tf = static_cast<trace_format_struct *>(allocate_memory (thisAgent, sizeof(trace_format),
490  tf->data.subformat = pattern;
491  return tf;
492  }
493 
494  if (!strncmp(format, "%nl", 3)) {
495  format += 3;
496  tf = static_cast<trace_format_struct *>(allocate_memory (thisAgent, sizeof(trace_format),
498  tf->type = NEWLINE_TFT;
499  return tf;
500  }
501 
502  /* --- if we haven't recognized it yet, we don't understand it --- */
503  format_string_error_message = "Unrecognized escape sequence";
504  return NIL;
505 }
506 
507 /* ----------------------------------------------------------------------
508  Print Trace Format List
509 
510  This routine takes a trace format (list) and prints it out as a format
511  string (without the surrounding quotation marks).
512 ---------------------------------------------------------------------- */
513 
515  cons *c;
516 
517  for ( ; tf!=NIL; tf=tf->next) {
518  switch (tf->type) {
519  case STRING_TFT:
520  { char *s;
521  size_t i, len;
522 
523  s = string_to_escaped_string (thisAgent, tf->data.string, '"', NULL);
524  len = strlen (s);
525  for (i=1; i<len-1; i++) print (thisAgent, "%c", *(s+i));
526  }
527  break;
528  case PERCENT_TFT: print_string (thisAgent, "%%"); break;
529  case L_BRACKET_TFT: print_string (thisAgent, "%["); break;
530  case R_BRACKET_TFT: print_string (thisAgent, "%]"); break;
531 
532  case VALUES_TFT:
534  case ATTS_AND_VALUES_TFT:
536  if (tf->type==VALUES_TFT) print_string (thisAgent, "%v[");
537  else if (tf->type==VALUES_RECURSIVELY_TFT) print_string (thisAgent, "%o[");
538  else if (tf->type==ATTS_AND_VALUES_TFT) print_string (thisAgent, "%av[");
539  else print_string (thisAgent, "%ao[");
540  if (tf->data.attribute_path) {
541  for (c=tf->data.attribute_path; c!=NIL; c=c->rest) {
542  print_string (thisAgent, static_cast<Symbol *>(c->first)->sc.name);
543  if (c->rest) print_string (thisAgent, ".");
544  }
545  } else {
546  print_string (thisAgent, "*");
547  }
548  print_string (thisAgent, "]");
549  break;
550 
551  case CURRENT_STATE_TFT: print_string (thisAgent, "%cs"); break;
552  case CURRENT_OPERATOR_TFT: print_string (thisAgent, "%co"); break;
553  case DECISION_CYCLE_COUNT_TFT: print_string (thisAgent, "%dc"); break;
554  case ELABORATION_CYCLE_COUNT_TFT: print_string (thisAgent, "%ec"); break;
555  case IDENTIFIER_TFT: print_string (thisAgent, "%id"); break;
556 
557  case IF_ALL_DEFINED_TFT:
558  print_string (thisAgent, "%ifdef[");
559  print_trace_format_list (thisAgent, tf->data.subformat);
560  print_string (thisAgent, "]");
561  break;
562 
563  case LEFT_JUSTIFY_TFT:
564  case RIGHT_JUSTIFY_TFT:
565  if (tf->type==LEFT_JUSTIFY_TFT) print_string (thisAgent, "%left[");
566  else print_string (thisAgent, "%right[");
567  print (thisAgent, "%d,", tf->num);
568  print_trace_format_list (thisAgent, tf->data.subformat);
569  print_string (thisAgent, "]");
570  break;
571 
572  case SUBGOAL_DEPTH_TFT: print_string (thisAgent, "%sd"); break;
573 
575  print_string (thisAgent, "%rsd[");
576  print_trace_format_list (thisAgent, tf->data.subformat);
577  print_string (thisAgent, "]");
578  break;
579 
580  case NEWLINE_TFT: print_string (thisAgent, "%nl"); break;
581 
582  default:
583  { char msg[BUFFER_MSG_SIZE];
584  strncpy (msg, "Internal error: bad trace format type\n", BUFFER_MSG_SIZE);
585  msg[BUFFER_MSG_SIZE - 1] = 0; /* ensure null termination */
586  abort_with_fatal_error(thisAgent, msg);
587  }
588  }
589  }
590 }
591 
592 /* ======================================================================
593  Trace Format Specification Tables
594 
595  We maintain tables of object trace formats and selection trace formats.
596  Trace formats that apply to any *|g|p|s|o are stored in the arrays
597  object_tf_for_anything[] and stack_tf_for_anything[]. (The array
598  entry is NIL if no trace format has been specified.) Trace formats that
599  apply to *|g|p|s|o's with a certain name are stored in the hash tables
600  object_tr_ht[] and stack_tr_ht[]. (Hash tables are used so we can
601  look up the trace format from an object's name quickly.)
602 
603  Init_tracing() initializes the tables; at this point, there are no trace
604  formats for anything. This routine should be called at startup time.
605 
606  Trace formats are changed by calls to add_trace_format() and
607  remove_trace_format(). Lookup_trace_format() returns the trace
608  format matching a given type restriction and/or name restriction,
609  or NIL if no such format has been specified. Add_trace_format() returns
610  TRUE if the format was successfully added, or FALSE if the format
611  string didn't parse right. Remove_trace_format() returns TRUE if
612  a trace format was actually removed, or FALSE if there was no such
613  trace format for the given type/name restrictions. These routines take
614  a "stack_trace" argument, which should be TRUE if the stack trace
615  format is intended, or FALSE if the object trace format is intended.
616  Their "type_restriction" argument should be one of FOR_ANYTHING_TF,
617  ..., FOR_OPERATORS_TF (see soarkernel.h). The "name_restriction"
618  argument should be either a pointer to a symbol, if the trace format
619  is restricted to apply to objects with that name, or NIL if the format
620  can apply to any object.
621 
622  Print_all_trace_formats() prints out either all existing stack trace
623  or object trace formats.
624 ====================================================================== */
625 
626 /* --- trace formats that don't test the object name --- */
627 
628 typedef struct tracing_rule_struct {
629  /* Warning: this MUST be the first field, for the hash table routines */
631  int type_restriction; /* FOR_STATES_TF, etc. */
632  Symbol *name_restriction; /* points to name Symbol, or NIL */
633  trace_format *format; /* indicates the format to use */
634 } tracing_rule;
635 
636 /*#define hash_name_restriction(name,num_bits) \
637  ((name)->common.hash_id & masks_for_n_low_order_bits[(num_bits)])*/
638 inline uint32_t hash_name_restriction(Symbol * name, short num_bits)
639 {
640  return name->common.hash_id & masks_for_n_low_order_bits[num_bits];
641 }
642 
643 /* --- hash function for resizable hash table routines --- */
644 uint32_t tracing_rule_hash_function (void *item, short num_bits) {
645  tracing_rule *tr;
646 
647  tr = static_cast<tracing_rule_struct *>(item);
648  return hash_name_restriction (tr->name_restriction, num_bits);
649 }
650 
651 /* --- hash tables for stack and object traces --- */
652 
653 
654 void init_tracing (agent* thisAgent) {
655  int i;
656 
657  for (i=0; i<3; i++) {
658  thisAgent->object_tr_ht[i] = make_hash_table (thisAgent, 0, tracing_rule_hash_function);
659  thisAgent->stack_tr_ht[i] = make_hash_table (thisAgent, 0, tracing_rule_hash_function);
660  thisAgent->object_tf_for_anything[i] = NIL;
661  thisAgent->stack_tf_for_anything[i] = NIL;
662  }
663 }
664 
666  Bool stack_trace,
667  int type_restriction,
669  uint32_t hash_value;
670  hash_table *ht;
671  tracing_rule *tr;
672 
673  if (name_restriction) {
674  if (stack_trace)
675  ht = thisAgent->stack_tr_ht[type_restriction];
676  else
677  ht = thisAgent->object_tr_ht[type_restriction];
678  hash_value = hash_name_restriction (name_restriction, ht->log2size);
679  tr = reinterpret_cast<tracing_rule *>(*(ht->buckets + hash_value));
680  for ( ; tr!=NIL; tr = tr->next_in_hash_bucket)
681  if (tr->name_restriction==name_restriction) return tr->format;
682  return NIL;
683  }
684  /* --- no name restriction --- */
685  if (stack_trace)
686  return thisAgent->stack_tf_for_anything[type_restriction];
687  else
688  return thisAgent->object_tf_for_anything[type_restriction];
689 }
690 
692  Bool stack_trace,
693  int type_restriction,
695  uint32_t hash_value;
696  hash_table *ht;
697  tracing_rule *tr;
699 
700  if (name_restriction) {
701  if (stack_trace)
702  ht = thisAgent->stack_tr_ht[type_restriction];
703  else
704  ht = thisAgent->object_tr_ht[type_restriction];
705  hash_value = hash_name_restriction (name_restriction, ht->log2size);
706  tr = reinterpret_cast<tracing_rule *>(*(ht->buckets + hash_value));
707  for ( ; tr!=NIL; tr = tr->next_in_hash_bucket)
708  if (tr->name_restriction==name_restriction) break;
709  if (! tr) return FALSE;
710  deallocate_trace_format_list (thisAgent, tr->format);
711  remove_from_hash_table (thisAgent, ht, tr);
712  free_memory (thisAgent, tr, MISCELLANEOUS_MEM_USAGE);
713  symbol_remove_ref (thisAgent, name_restriction);
714  return TRUE;
715  }
716  /* --- no name restriction --- */
717  if (stack_trace)
718  format = &(thisAgent->stack_tf_for_anything[type_restriction]);
719  else
720  format = &(thisAgent->object_tf_for_anything[type_restriction]);
721  if (! *format) return FALSE;
722  deallocate_trace_format_list (thisAgent, *format);
723  *format = NIL;
724  return TRUE;
725 }
726 
728  Bool stack_trace,
729  int type_restriction,
731  const char *format_string) {
732  tracing_rule *tr;
733  trace_format *new_tf;
734  hash_table *ht;
735 
736  /* --- parse the format string into a trace_format --- */
737  new_tf = parse_format_string (thisAgent, format_string);
738  if (!new_tf) return FALSE;
739 
740  /* --- first remove any existing trace format with same conditions --- */
741  remove_trace_format (thisAgent, stack_trace, type_restriction, name_restriction);
742 
743  /* --- now add the new one --- */
744  if (name_restriction) {
745  symbol_add_ref (name_restriction);
746  if (stack_trace)
747  ht = thisAgent->stack_tr_ht[type_restriction];
748  else
749  ht = thisAgent->object_tr_ht[type_restriction];
750  tr = static_cast<tracing_rule_struct *>(allocate_memory (thisAgent, sizeof(tracing_rule),
754  tr->format = new_tf;
755  add_to_hash_table (thisAgent, ht, tr);
756  return TRUE;
757  }
758  /* --- no name restriction --- */
759  if (stack_trace)
760  thisAgent->stack_tf_for_anything[type_restriction] = new_tf;
761  else
762  thisAgent->object_tf_for_anything[type_restriction] = new_tf;
763 
764  return TRUE;
765 }
766 
767 char tracing_object_letters[3] = {'*','s','o'};
768 
770  trace_format *format) {
771  if (thisAgent->printing_stack_traces)
772 //#ifdef USE_TCL
773  print_string (thisAgent, "stack-trace-format");
774  else
775  print_string (thisAgent, "object-trace-format");
776 //#else
777 // print_string (thisAgent, "(stack-trace-format");
778 // else
779 // print_string (thisAgent, "(object-trace-format");
780 //#endif /* USE_TCL */
781  print (thisAgent, " :add %c ", tracing_object_letters[type_restriction]);
782  if (name_restriction) print_with_symbols (thisAgent, "%y ", name_restriction);
783  print_string (thisAgent, "\"");
784  print_trace_format_list (thisAgent, format);
785 //#ifdef USE_TCL
786  print (thisAgent, "\"\n");
787 //#else
788 // print (thisAgent, "\")\n");
789 //#endif /* USE_TCL */
790 }
791 
792 //#ifdef USE_TCL
794  trace_format *format) {
795  print (thisAgent, "%c ", tracing_object_letters[type_restriction]);
796  if (name_restriction) print_with_symbols (thisAgent, "%y ", name_restriction);
797  print_string (thisAgent, "{");
798  print_trace_format_list (thisAgent, format);
799  print (thisAgent, "}\n");
800 }
801 //#endif /* USE_TCL */
802 
803 
804 Bool print_trace_callback_fn (agent* thisAgent, void *item, void*) {
805  tracing_rule *tr;
806 
807  tr = static_cast<tracing_rule_struct *>(item);
808  print_tracing_rule (thisAgent, tr->type_restriction, tr->name_restriction, tr->format);
809  return FALSE;
810 }
811 
812 //#ifdef USE_TCL
813 Bool print_trace_callback_fn_tcl (agent* thisAgent, void *item, void*) {
814  tracing_rule *tr;
815 
816  tr = static_cast<tracing_rule_struct *>(item);
818  tr->format);
819  return FALSE;
820 }
821 //#endif /* USE_TCL */
822 
823 void print_all_trace_formats (agent* thisAgent, Bool stack_trace, FILE* f) {
824  int i;
825 
826  thisAgent->printing_stack_traces = stack_trace;
827  if (stack_trace) {
828  for (i=0; i<3; i++) {
829  if (thisAgent->stack_tf_for_anything[i])
830  print_tracing_rule (thisAgent, i, NIL, thisAgent->stack_tf_for_anything[i]);
831  do_for_all_items_in_hash_table (thisAgent, thisAgent->stack_tr_ht[i],print_trace_callback_fn,reinterpret_cast<void*>(f));
832  }
833  } else {
834  for (i=0; i<3; i++) {
835  if (thisAgent->object_tf_for_anything[i])
836  print_tracing_rule (thisAgent, i, NIL, thisAgent->object_tf_for_anything[i]);
837  do_for_all_items_in_hash_table (thisAgent, thisAgent->object_tr_ht[i],print_trace_callback_fn,reinterpret_cast<void*>(f));
838  }
839  }
840 }
841 
842 //#ifdef USE_TCL
843 void print_all_trace_formats_tcl (agent* thisAgent, Bool stack_trace, FILE* f) {
844  int i;
845 
846  thisAgent->printing_stack_traces = stack_trace;
847  if (stack_trace) {
848  for (i=0; i<3; i++) {
849  if (thisAgent->stack_tf_for_anything[i])
850  print_tracing_rule_tcl (thisAgent, i, NIL, thisAgent->stack_tf_for_anything[i]);
851  do_for_all_items_in_hash_table (thisAgent, thisAgent->stack_tr_ht[i],print_trace_callback_fn_tcl,reinterpret_cast<void*>(f));
852  }
853  } else {
854  for (i=0; i<3; i++) {
855  if (thisAgent->object_tf_for_anything[i])
856  print_tracing_rule_tcl (thisAgent, i, NIL, thisAgent->object_tf_for_anything[i]);
857  do_for_all_items_in_hash_table (thisAgent, thisAgent->object_tr_ht[i],print_trace_callback_fn_tcl,reinterpret_cast<void*>(f));
858  }
859  }
860 }
861 //#endif /* USE_TCL */
862 
863 
864 inline void set_print_trace_formats(agent* thisAgent){
865  /* --- add default object trace formats --- */
867  "%id %ifdef[(%v[name])]");
868  add_trace_format (thisAgent, FALSE, FOR_STATES_TF, NIL,
869  "%id %ifdef[(%v[attribute] %v[impasse])]");
870  /*********** enable when determine tagged output format
871  { Symbol *evaluate_object_sym;
872  evaluate_object_sym = make_sym_constant (thisAgent, "evaluate-object");
873  add_trace_format (thisAgent, FALSE, FOR_OPERATORS_TF, evaluate_object_sym,
874  "%id (evaluate-object %o[object])");
875  symbol_remove_ref (thisAgent, evaluate_object_sym);
876  }
877  *************/
878  /* --- add default stack trace formats --- */
879  add_trace_format (thisAgent, TRUE, FOR_STATES_TF, NIL,
880  "%right[6,%dc]: %rsd[ ]==>S: %cs");
882  "%right[6,%dc]: %rsd[ ] O: %co");
883 }
884 inline void set_tagged_trace_formats(agent* thisAgent){
885  // KJC 03/05: trying this for tagged output
886 
887  /* --- add tagged object trace formats --- */
889  "%id\" %ifdef[name=\"%v[name]\"]");
890  add_trace_format (thisAgent, FALSE, FOR_STATES_TF, NIL,
891  "%id\" %ifdef[impasse_object=\"%v[attribute]\" impasse_type=\"%v[impasse]\"]");
892  /*********** enable when determine tagged output format
893  { Symbol *evaluate_object_sym;
894  evaluate_object_sym = make_sym_constant (thisAgent, "evaluate-object");
895  add_trace_format (thisAgent, FALSE, FOR_OPERATORS_TF, evaluate_object_sym,
896  "%id (evaluate-object %o[object])");
897  symbol_remove_ref (thisAgent, evaluate_object_sym);
898  }
899  *************/
900  /* --- add tagged stack trace formats --- */
901 
902  add_trace_format (thisAgent, TRUE, FOR_STATES_TF, NIL,
903  "<state stack_level=\"%sd\" decision_cycle_count=\"%dc\" current_state_id=\"%cs>");
905  "<operator stack_level=\"%sd\" decision_cycle_count=\"%dc\" current_operator_id=\"%co>");
906 }
907 
908 
909 /* ======================================================================
910  Trace Format List To String
911 
912  Trace_format_list_to_string() is the main routine which, given a
913  trace format and a current object, builds and returns a growable_string
914  for that object's printout. A number of helper routines are used by
915  trace_format_list_to_string().
916 ====================================================================== */
917 
918 growable_string object_to_trace_string (agent* thisAgent, Symbol *object);
919 
920 
921 Bool found_undefined; /* set to TRUE whenever an escape sequence result is
922  undefined--for use with %ifdef */
923 
925  Symbol *current_s; /* current state, etc. -- for use in %cs, etc. */
927  Bool allow_cycle_counts; /* TRUE means allow %dc and %ec */
928 } tparams;
929 
930 /* ----------------------------------------------------------------
931  Adds all values of the given attribute path off the given object
932  to the "*result" growable_string. If "recursive" is TRUE, the
933  values are printed recursively as objects, rather than as simple
934  atomic values. "*count" is incremented each time a value is
935  printed. (To get a count of how many values were printed, the
936  caller should initialize this to 0, then call this routine.)
937 ---------------------------------------------------------------- */
938 
940  Symbol *object,
941  list *path,
942  growable_string *result,
943  Bool recursive,
944  int *count) {
945  slot *s;
946  wme *w;
947  char *ch;
948  growable_string gs;
949 
950  if (!path) { /* path is NIL, so we've reached the end of the path */
951  add_to_growable_string (thisAgent, result, " ");
952  if (recursive) {
953  gs = object_to_trace_string (thisAgent, object);
954  add_to_growable_string (thisAgent, result, text_of_growable_string(gs));
955  free_growable_string (thisAgent, gs);
956  } else {
957  ch = symbol_to_string (thisAgent, object, TRUE, NULL, 0);
958  add_to_growable_string (thisAgent, result, ch);
959  }
960  (*count)++;
961  return;
962  }
963 
964  /* --- not at end of path yet --- */
965  /* --- can't follow any more path segments off of a non-identifier --- */
966  if (object->common.symbol_type != IDENTIFIER_SYMBOL_TYPE) return;
967 
968  /* --- call this routine recursively on any wme matching the first segment
969  of the attribute path --- */
970  for (w=object->id.impasse_wmes; w!=NIL; w=w->next)
971  if (w->attr == path->first)
972  add_values_of_attribute_path (thisAgent, w->value, path->rest, result, recursive,
973  count);
974  for (w=object->id.input_wmes; w!=NIL; w=w->next)
975  if (w->attr == path->first)
976  add_values_of_attribute_path (thisAgent, w->value, path->rest, result, recursive,
977  count);
978  s = find_slot (object, static_cast<symbol_union *>(path->first));
979  if (s) {
980  for (w=s->wmes; w!=NIL; w=w->next)
981  add_values_of_attribute_path (thisAgent, w->value, path->rest, result, recursive,
982  count);
983  }
984 }
985 
986 /* ----------------------------------------------------------------
987  Adds info for a wme to the given "*result" growable_string. If
988  "print_attribute" is TRUE, then "^att-name" is included. If
989  "recursive" is TRUE, the value is printed recursively as an
990  object, rather than as a simple atomic value.
991 ---------------------------------------------------------------- */
992 
993 void add_trace_for_wme (agent* thisAgent,
994  growable_string *result,
995  wme *w,
996  Bool print_attribute,
997  Bool recursive) {
998  char *ch;
999  growable_string gs;
1000 
1001  add_to_growable_string (thisAgent, result, " ");
1002  if (print_attribute) {
1003  add_to_growable_string (thisAgent, result, "^");
1004  ch = symbol_to_string (thisAgent, w->attr, TRUE, NULL, 0);
1005  add_to_growable_string (thisAgent, result, ch);
1006  add_to_growable_string (thisAgent, result, " ");
1007  }
1008  if (recursive) {
1009  gs = object_to_trace_string (thisAgent, w->value);
1010  add_to_growable_string (thisAgent, result, text_of_growable_string(gs));
1011  free_growable_string (thisAgent, gs);
1012  } else {
1013  ch = symbol_to_string (thisAgent, w->value, TRUE, NULL, 0);
1014  add_to_growable_string (thisAgent, result, ch);
1015  }
1016 }
1017 
1018 /* ----------------------------------------------------------------
1019  Adds the trace for values of a given attribute path off a given
1020  object, to the given "*result" growable_string. If
1021  "print_attributes" is TRUE, then "^att-name" is included. If
1022  "recursive" is TRUE, the values are printed recursively as
1023  objects, rather than as a simple atomic value. If the given path
1024  is NIL, then all values of all attributes of the given object
1025  are printed.
1026 ---------------------------------------------------------------- */
1027 
1029  Symbol *object,
1030  list *path,
1031  growable_string *result,
1032  Bool print_attributes,
1033  Bool recursive) {
1034  growable_string values;
1035  cons *c;
1036  char *ch;
1037  int count;
1038  slot *s;
1039  wme *w;
1040 
1041  values = make_blank_growable_string(thisAgent);
1042 
1043  if (! path) {
1044  if (object->common.symbol_type!=IDENTIFIER_SYMBOL_TYPE) return;
1045  for (s=object->id.slots; s!=NIL; s=s->next)
1046  for (w=s->wmes; w!=NIL; w=w->next)
1047  add_trace_for_wme (thisAgent, &values, w, print_attributes, recursive);
1048  for (w=object->id.impasse_wmes; w!=NIL; w=w->next)
1049  add_trace_for_wme (thisAgent, &values, w, print_attributes, recursive);
1050  for (w=object->id.input_wmes; w!=NIL; w=w->next)
1051  add_trace_for_wme (thisAgent, &values, w, print_attributes, recursive);
1052  if (length_of_growable_string(values)>0)
1053  add_to_growable_string (thisAgent, result, text_of_growable_string(values)+1);
1054  free_growable_string (thisAgent, values);
1055  return;
1056  }
1057 
1058  count = 0;
1059  add_values_of_attribute_path (thisAgent, object, path, &values, recursive, &count);
1060  if (! count) {
1062  free_growable_string (thisAgent, values);
1063  return;
1064  }
1065 
1066  if (print_attributes) {
1067  add_to_growable_string (thisAgent, result, "^");
1068  for (c=path; c!=NIL; c=c->rest) {
1069  ch = symbol_to_string (thisAgent, static_cast<symbol_union *>(c->first), TRUE, NULL, 0);
1070  add_to_growable_string (thisAgent, result, ch);
1071  if (c->rest) add_to_growable_string (thisAgent, result, ".");
1072  }
1073  add_to_growable_string (thisAgent, result, " ");
1074  }
1075  if (length_of_growable_string(values)>0)
1076  add_to_growable_string (thisAgent, result, text_of_growable_string(values)+1);
1077  free_growable_string (thisAgent, values);
1078 }
1079 
1080 /* ----------------------------------------------------------------
1081  This is the main routine here. It returns a growable_string,
1082  given a trace format list (the format to use) and an object (the
1083  object being printed).
1084 ---------------------------------------------------------------- */
1085 
1087 #define GROWABLE_STRING_TRACE_FORMAT_LIST_TO_STRING_BUFFER_SIZE 50
1089  growable_string result, temp_gs;
1090  int i;
1091 
1092  result = make_blank_growable_string(thisAgent);
1093 
1094  for ( ; tf!=NIL; tf=tf->next) {
1095  switch (tf->type) {
1096  case STRING_TFT:
1097  add_to_growable_string (thisAgent, &result, tf->data.string);
1098  break;
1099  case PERCENT_TFT:
1100  add_to_growable_string (thisAgent, &result, "%");
1101  break;
1102  case L_BRACKET_TFT:
1103  add_to_growable_string (thisAgent, &result, "[");
1104  break;
1105  case R_BRACKET_TFT:
1106  add_to_growable_string (thisAgent, &result, "]");
1107  break;
1108 
1109  case VALUES_TFT:
1110  add_trace_for_attribute_path (thisAgent, object, tf->data.attribute_path, &result,
1111  FALSE, FALSE);
1112  break;
1114  add_trace_for_attribute_path (thisAgent, object, tf->data.attribute_path, &result,
1115  FALSE, TRUE);
1116  break;
1117  case ATTS_AND_VALUES_TFT:
1118  add_trace_for_attribute_path (thisAgent, object, tf->data.attribute_path, &result,
1119  TRUE, FALSE);
1120  break;
1122  add_trace_for_attribute_path (thisAgent, object, tf->data.attribute_path, &result,
1123  TRUE, TRUE);
1124  break;
1125 
1126  case CURRENT_STATE_TFT:
1127  if (! tparams.current_s) {
1129  } else {
1130  temp_gs = object_to_trace_string (thisAgent, tparams.current_s);
1131 
1132  // KJC added to play with tagged output...
1133  //add_to_growable_string (thisAgent, &result, "id=");
1134 
1135  add_to_growable_string (thisAgent, &result, text_of_growable_string(temp_gs));
1136 
1137  free_growable_string (thisAgent, temp_gs);
1138  }
1139  break;
1140  case CURRENT_OPERATOR_TFT:
1141  if (! tparams.current_o) {
1143  } else {
1144  temp_gs = object_to_trace_string (thisAgent, tparams.current_o);
1145  add_to_growable_string (thisAgent, &result, text_of_growable_string(temp_gs));
1146  free_growable_string (thisAgent, temp_gs);
1147  }
1148  break;
1149 
1152  SNPRINTF (buf,GROWABLE_STRING_TRACE_FORMAT_LIST_TO_STRING_BUFFER_SIZE, "%lu", static_cast<long unsigned int>(thisAgent->d_cycle_count));
1153  buf[GROWABLE_STRING_TRACE_FORMAT_LIST_TO_STRING_BUFFER_SIZE - 1] = 0; /* ensure null termination */
1154  add_to_growable_string (thisAgent, &result, buf);
1155  } else {
1157  }
1158  break;
1161  SNPRINTF (buf,GROWABLE_STRING_TRACE_FORMAT_LIST_TO_STRING_BUFFER_SIZE, "%lu", static_cast<long unsigned int>(thisAgent->e_cycle_count));
1162  buf[GROWABLE_STRING_TRACE_FORMAT_LIST_TO_STRING_BUFFER_SIZE - 1] = 0; /* ensure null termination */
1163  add_to_growable_string (thisAgent, &result, buf);
1164  } else {
1166  }
1167  break;
1168 
1169  case IDENTIFIER_TFT:
1170  ch = symbol_to_string (thisAgent, object, TRUE, NULL, 0);
1171  add_to_growable_string (thisAgent, &result, ch);
1172  break;
1173 
1174  case IF_ALL_DEFINED_TFT:
1175  { Bool saved_found_undefined;
1176  saved_found_undefined = found_undefined;
1178  temp_gs = trace_format_list_to_string (thisAgent, tf->data.subformat, object);
1179  if (! found_undefined)
1180  add_to_growable_string (thisAgent, &result, text_of_growable_string(temp_gs));
1181  free_growable_string (thisAgent, temp_gs);
1182  found_undefined = saved_found_undefined;
1183  }
1184  break;
1185 
1186  case LEFT_JUSTIFY_TFT:
1187  temp_gs = trace_format_list_to_string (thisAgent, tf->data.subformat, object);
1188  add_to_growable_string (thisAgent, &result, text_of_growable_string(temp_gs));
1189  for (i=tf->num - length_of_growable_string(temp_gs); i>0; i--)
1190  add_to_growable_string (thisAgent, &result, " ");
1191  free_growable_string (thisAgent, temp_gs);
1192  break;
1193 
1194  case RIGHT_JUSTIFY_TFT:
1195  temp_gs = trace_format_list_to_string (thisAgent, tf->data.subformat, object);
1196  for (i=tf->num - length_of_growable_string(temp_gs); i>0; i--)
1197  add_to_growable_string (thisAgent, &result, " ");
1198  add_to_growable_string (thisAgent, &result, text_of_growable_string(temp_gs));
1199  free_growable_string (thisAgent, temp_gs);
1200  break;
1201 
1202  case SUBGOAL_DEPTH_TFT:
1203  if (tparams.current_s) {
1205  buf[GROWABLE_STRING_TRACE_FORMAT_LIST_TO_STRING_BUFFER_SIZE - 1] = 0; /* ensure null termination */
1206  add_to_growable_string (thisAgent, &result, buf);
1207  } else {
1209  }
1210  break;
1211 
1213  if (tparams.current_s) {
1214  temp_gs = trace_format_list_to_string (thisAgent, tf->data.subformat, object);
1215  for (i = tparams.current_s->id.level - 1; i>0; i--)
1216  add_to_growable_string (thisAgent, &result, text_of_growable_string(temp_gs));
1217  free_growable_string (thisAgent, temp_gs);
1218  } else {
1220  }
1221  break;
1222 
1223  case NEWLINE_TFT:
1224  add_to_growable_string (thisAgent, &result, "\n");
1225  break;
1226 
1227  default:
1228  { char msg[BUFFER_MSG_SIZE];
1229  strncpy (msg,"Internal error: bad trace format type\n", BUFFER_MSG_SIZE);
1230  msg[BUFFER_MSG_SIZE - 1] = 0; /* ensure null termination */
1231  abort_with_fatal_error(thisAgent, msg);
1232  }
1233  }
1234  }
1235  return result;
1236 }
1237 
1238 /* ======================================================================
1239  Building Traces for Object and Selections
1240 
1241  Find_appropriate_trace_format() looks for an applicable trace_format
1242  among the current set of tracing rules.
1243 
1244  Object_to_trace_string() takes an object and returns a growable_string
1245  to use for its printed trace.
1246 
1247  Selection_to_trace_string() takes an object (the current selection),
1248  the current state, a "selection_type" (one of FOR_OPERATORS_TF, etc.),
1249  and a flag indicating whether %dc, %ec, etc. escapes should be
1250  allowed, and returns a growable_string to use for the trace.
1251 ====================================================================== */
1252 
1253 
1254  /* prevents infinite loops when printing circular
1255  structures */
1256 
1258  Bool stack_trace,
1259  int type,
1260  Symbol *name) {
1261  trace_format *tf;
1262 
1263  /* --- first try to find the exact one --- */
1264  tf = lookup_trace_format (thisAgent, stack_trace, type, name);
1265  if (tf) return tf;
1266 
1267  /* --- failing that, try ignoring the type but retaining the name --- */
1268  if (type!=FOR_ANYTHING_TF) {
1269  tf = lookup_trace_format (thisAgent, stack_trace, FOR_ANYTHING_TF, name);
1270  if (tf) return tf;
1271  }
1272 
1273  /* --- failing that, try ignoring the name but retaining the type --- */
1274  if (name) {
1275  tf = lookup_trace_format (thisAgent, stack_trace, type, NIL);
1276  if (tf) return tf;
1277  }
1278 
1279  /* --- last resort: find a format that applies to anything at all --- */
1280  return lookup_trace_format (thisAgent, stack_trace, FOR_ANYTHING_TF, NIL);
1281 }
1282 
1284  growable_string gs;
1285  int type_of_object;
1286  trace_format *tf;
1287  Symbol *name;
1288  struct tracing_parameters saved_tparams;
1289 
1290  /* --- If it's not an identifier, just print it as an atom. Also, if it's
1291  already being printed, print it as an atom to avoid getting into an
1292  infinite loop. --- */
1293  if ((object->common.symbol_type!=IDENTIFIER_SYMBOL_TYPE) ||
1294  (object->id.tc_num == thisAgent->tf_printing_tc)) {
1295  gs = make_blank_growable_string (thisAgent);
1296  add_to_growable_string (thisAgent, &gs, symbol_to_string (thisAgent, object, TRUE, NIL, 0));
1297  return gs;
1298  }
1299 
1300  /* --- mark it as being printed --- */
1301  object->id.tc_num = thisAgent->tf_printing_tc;
1302 
1303  /* --- determine the type and name of the object --- */
1304  if (object->id.isa_goal) type_of_object=FOR_STATES_TF;
1305  else if (object->id.isa_operator) type_of_object=FOR_OPERATORS_TF;
1306  else type_of_object=FOR_ANYTHING_TF;
1307 
1308  name = find_name_of_object (thisAgent, object);
1309 
1310  /* --- find the trace format to use --- */
1311  tf = find_appropriate_trace_format (thisAgent, FALSE, type_of_object, name);
1312 
1313  /* --- now call trace_format_list_to_string() --- */
1314  if (tf) {
1315  saved_tparams = tparams;
1318  gs = trace_format_list_to_string (thisAgent, tf, object);
1319  tparams = saved_tparams;
1320  } else {
1321  /* --- no applicable trace format, so just print the object itself --- */
1322  gs = make_blank_growable_string (thisAgent);
1323  add_to_growable_string (thisAgent, &gs, symbol_to_string (thisAgent, object, TRUE, NIL, 0));
1324  }
1325 
1326  object->id.tc_num = 0; /* unmark it now that we're done */
1327  return gs;
1328 }
1329 
1331  Symbol *object,
1332  Symbol *current_state,
1333  int selection_type,
1335  trace_format *tf;
1336  Symbol *name;
1337  growable_string gs;
1338  struct tracing_parameters saved_tparams;
1339 
1340  /* --- find the problem space name --- */
1341  name = NIL;
1342 
1343  /* --- find the trace format to use --- */
1344  tf = find_appropriate_trace_format (thisAgent, TRUE, selection_type, name);
1345 
1346  /* --- if there's no applicable trace format, print nothing --- */
1347  if (!tf) return make_blank_growable_string (thisAgent);
1348 
1349  /* --- save/restore tparams, and call trace_format_list_to_string() --- */
1350  saved_tparams = tparams;
1352  if (current_state) {
1353  tparams.current_s = current_state;
1354  if (current_state->id.operator_slot->wmes) {
1355  tparams.current_o = current_state->id.operator_slot->wmes->value;
1356  }
1357  }
1359  gs = trace_format_list_to_string (thisAgent, tf, object);
1360  tparams = saved_tparams;
1361 
1362  return gs;
1363 }
1364 
1365 /* ======================================================================
1366  Printing Object and Stack Traces
1367 
1368  Print_object_trace() takes an object (any symbol). It prints
1369  the trace for that object. Print_stack_trace() takes a (context)
1370  object (the state or op), the current state, the "slot_type" (one
1371  of FOR_OPERATORS_TF, etc.), and a flag indicating whether to allow
1372  %dc and %ec escapes (this flag should normally be TRUE for watch 0
1373  traces but FALSE during a "pgs" command). It prints the trace for
1374  that context object.
1375 ====================================================================== */
1376 
1377 void print_object_trace (agent* thisAgent, Symbol *object) {
1378  growable_string gs;
1379 
1380  thisAgent->tf_printing_tc = get_new_tc_number(thisAgent);
1381  gs = object_to_trace_string (thisAgent, object);
1382  print_string (thisAgent, text_of_growable_string(gs));
1383  free_growable_string (thisAgent, gs);
1384 }
1385 
1386 void print_stack_trace_xml(agent* thisAgent, Symbol *object, Symbol *state, int slot_type, Bool /*allow_cycle_counts*/) {
1387 
1388  Symbol* current_o = 0;
1389 
1390  switch(slot_type) {
1391  case FOR_STATES_TF:
1392  //create XML trace for state object
1393  xml_begin_tag( thisAgent, kTagState );
1394  xml_att_val( thisAgent, kState_StackLevel, state->id.level - 1 );
1395  xml_att_val( thisAgent, kState_DecisionCycleCt, thisAgent->d_cycle_count );
1396  xml_att_val( thisAgent, kState_ID, object );
1397 
1398  // find impasse object and add it to XML
1399  wme* w;
1400  for (w=object->id.impasse_wmes; w!=NIL; w=w->next) {
1401  if(w->attr == thisAgent->attribute_symbol) {
1402  xml_att_val( thisAgent, kState_ImpasseObject, w->value->sc.name );
1403  break;
1404  }
1405  }
1406 
1407  // find impasse type and add it to XML
1408  for (w=object->id.impasse_wmes; w!=NIL; w=w->next) {
1409  if(w->attr == thisAgent->impasse_symbol) {
1410  xml_att_val( thisAgent, kState_ImpasseType, w->value->sc.name );
1411  break;
1412  }
1413  }
1414 
1415  xml_end_tag( thisAgent, kTagState );
1416  break;
1417 
1418  case FOR_OPERATORS_TF:
1419  //create XML trace for operator object
1420  xml_begin_tag( thisAgent, kTagOperator );
1421  xml_att_val( thisAgent, kState_StackLevel, object->id.level - 1 );
1422  xml_att_val( thisAgent, kOperator_DecisionCycleCt, thisAgent->d_cycle_count );
1423 
1424  if (state->id.operator_slot->wmes)
1425  {
1426  current_o = state->id.operator_slot->wmes->value;
1427  }
1428  if(current_o) {
1429  xml_att_val( thisAgent, kOperator_ID, current_o );
1430  Symbol* name = find_name_of_object(thisAgent, current_o);
1431  if(name)
1432  {
1433  xml_att_val( thisAgent, kOperator_Name, name );
1434  }
1435  }
1436 
1437  xml_end_tag( thisAgent, kTagOperator );
1438  break;
1439 
1440  default:
1441  // technically it looks like we should try to print a name here, but I think that is an artifact (at least it doesn't make sense for the XML)
1442  break;
1443  }
1444 
1445  /* These are the trace formats which I've directly implemented above
1446  add_trace_format (thisAgent, TRUE, FOR_STATES_TF, NIL,
1447  "<state stack_level=\"%sd\" decision_cycle_count=\"%dc\" current_state_id=\"%cs>");
1448  add_trace_format (thisAgent, TRUE, FOR_OPERATORS_TF, NIL,
1449  "<operator stack_level=\"%sd\" decision_cycle_count=\"%dc\" current_operator_id=\"%co>");
1450 
1451  add_trace_format (thisAgent, FALSE, FOR_ANYTHING_TF, NIL,
1452  "%id\" %ifdef[name=\"%v[name]\"]");
1453  add_trace_format (thisAgent, FALSE, FOR_STATES_TF, NIL,
1454  "%id\" %ifdef[impasse_object=\"%v[attribute]\" impasse_type=\"%v[impasse]\"]");
1455  */
1456 }
1457 
1458 
1459 void print_stack_trace (agent* thisAgent, Symbol *object, Symbol *state, int slot_type,
1461  growable_string gs;
1462 
1463  thisAgent->tf_printing_tc = get_new_tc_number(thisAgent);
1464  gs = selection_to_trace_string (thisAgent, object, state, slot_type,allow_cycle_counts);
1465  print_string (thisAgent, text_of_growable_string(gs));
1466  free_growable_string (thisAgent, gs);
1467 
1468  // RPM 5/05
1469  print_stack_trace_xml(thisAgent, object, state, slot_type, allow_cycle_counts);
1470 }
1471 
1472 /* kjh(B1) begin */
1474  Symbol *object,
1475  Symbol *current_goal,
1476  char *format_string) {
1477  growable_string gs;
1478  struct tracing_parameters saved_tparams;
1479  trace_format *fs;
1480 
1481  fs = parse_format_string(thisAgent, format_string);
1482 
1483  thisAgent->tf_printing_tc = get_new_tc_number(thisAgent);
1484 
1485  saved_tparams = tparams;
1486 
1487  if (current_goal)
1488  tparams.current_s = current_goal;
1490 
1491  gs = trace_format_list_to_string (thisAgent, fs, object);
1492 
1493  tparams = saved_tparams;
1494 
1495  if(thisAgent->printer_output_column != 1)
1496  print_string (thisAgent, "\n");
1497 
1498  print_string (thisAgent, text_of_growable_string(gs));
1499  free_growable_string (thisAgent, gs);
1500  }
1501 /* kjh(B1) end */
1502