Soar Kernel  9.3.2 08-06-12
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
rhsfun.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: rhsfun.cpp
11  *
12  * =======================================================================
13  * RHS Function Management for Soar 6
14  *
15  * The system maintains a list of available RHS functions. Functions
16  * can appear on the RHS of productions either as values (in make actions
17  * or as arguments to other function calls) or as stand-alone actions
18  * (e.g., "write" and "halt"). When a function is executed, its C code
19  * is called with one parameter--a (consed) list of the arguments (symbols).
20  * The C function should return either a symbol (if all goes well) or NIL
21  * (if an error occurred, or if the function is a stand-alone action).
22  *
23  * All available RHS functions should be setup at system startup time via
24  * calls to add_rhs_function(). It takes as arguments the name of the
25  * function (a symbol), a pointer to the corresponding C function, the
26  * number of arguments the function expects (-1 if the function can take
27  * any number of arguments), and flags indicating whether the function can
28  * be a RHS value or a stand-alone action.
29  *
30  * Lookup_rhs_function() takes a symbol and returns the corresponding
31  * rhs_function structure (or NIL if there is no such function).
32  *
33  * Init_built_in_rhs_functions() should be called at system startup time
34  * to setup all the built-in functions.
35  * =======================================================================
36  */
37 
38 #include <stdlib.h>
39 
40 #include "rhsfun.h"
41 #include "kernel.h"
42 #include "print.h"
43 #include "mem.h"
44 #include "symtab.h"
45 #include "init_soar.h"
46 #include "gsysparam.h"
47 #include "agent.h"
48 #include "production.h"
49 #include "rhsfun_math.h"
50 #include "io_soar.h"
51 #include "recmem.h"
52 #include "wmem.h"
53 #include "gdatastructs.h"
54 #include "xml.h"
55 #include "soar_TraceNames.h"
56 
57 #include <map>
58 #include <string>
59 #include <time.h>
60 
61 using namespace soar_TraceNames;
62 
63 void add_rhs_function (agent* thisAgent,
64  Symbol *name,
66  int num_args_expected,
67  Bool can_be_rhs_value,
68  Bool can_be_stand_alone_action,
69  void* user_data) {
70  rhs_function *rf;
71 
72  if ((!can_be_rhs_value) && (!can_be_stand_alone_action))
73  {
74  print (thisAgent, "Internal error: attempt to add_rhs_function that can't appear anywhere\n");
75  return;
76  }
77 
78  for (rf=thisAgent->rhs_functions; rf!=NIL; rf=rf->next)
79  {
80  if (rf->name==name)
81  {
82  print_with_symbols (thisAgent, "Internal error: attempt to add_rhs_function that already exists: %y\n", name);
83  return;
84  }
85  }
86 
87  rf = static_cast<rhs_function_struct *>(allocate_memory (thisAgent, sizeof(rhs_function), MISCELLANEOUS_MEM_USAGE));
88 
89  /* Insertion into the list */
90  rf->next = thisAgent->rhs_functions;
91  thisAgent->rhs_functions = rf;
92 
93  /* Rest of the stuff */
94  rf->name = name;
95  rf->f = f;
96  rf->num_args_expected = num_args_expected;
97  rf->can_be_rhs_value = can_be_rhs_value;
98  rf->can_be_stand_alone_action = can_be_stand_alone_action;
99  rf->user_data = user_data;
100 }
101 
103 {
104  rhs_function *rf;
105 
106  for (rf=thisAgent->rhs_functions; rf!=NIL; rf=rf->next)
107  {
108  if (rf->name==name)
109  return rf;
110  }
111  return NIL;
112 }
113 
114 void remove_rhs_function(agent* thisAgent, Symbol *name) { /* code from Koss 8/00 */
115 
116  rhs_function *rf = NIL, *prev;
117 
118  /* Find registered function by name */
119  for (prev = NIL, rf = thisAgent->rhs_functions;
120  rf != NIL;
121  prev = rf, rf = rf->next)
122  {
123  if (rf->name == name)
124  break;
125  }
126 
127  /* If not found, there's a problem */
128  if (rf == NIL) {
129  fprintf(stderr, "Internal error: attempt to remove_rhs_function that does not exist.\n");
130  print_with_symbols(thisAgent, "Internal error: attempt to remove_rhs_function that does not exist: %y\n", name);
131  }
132 
133  /* Else, remove it */
134  else
135  {
136 
137  /* Head of list special */
138  if (prev == NIL)
139  thisAgent->rhs_functions = rf->next;
140  else
141  prev->next = rf->next;
142 
143  free_memory(thisAgent, rf, MISCELLANEOUS_MEM_USAGE);
144  }
145 
146  // DJP-FREE: The name reference needs to be released now the function is gone
147  symbol_remove_ref(thisAgent,name);
148 }
149 
150 
151 /* ====================================================================
152 
153  Code for Executing Built-In RHS Functions
154 
155 ==================================================================== */
156 
157 /* --------------------------------------------------------------------
158  Write
159 
160  Takes any number of arguments, and prints each one.
161 -------------------------------------------------------------------- */
162 
163 Symbol *write_rhs_function_code (agent* thisAgent, list *args, void* /*user_data*/) {
164  Symbol *arg;
165  char *string;
166  growable_string gs = make_blank_growable_string(thisAgent); // for XML generation
167 
168  for ( ; args!=NIL; args=args->rest) {
169  arg = static_cast<symbol_union *>(args->first);
170  /* --- Note use of FALSE here--print the symbol itself, not a rereadable
171  version of it --- */
172  string = symbol_to_string (thisAgent, arg, FALSE, NIL, 0);
173  add_to_growable_string(thisAgent, &gs, string); // for XML generation
174  print_string (thisAgent, string);
175  }
176 
177  xml_object( thisAgent, kTagRHS_write, kRHS_String, text_of_growable_string(gs) );
178 
179  free_growable_string(thisAgent, gs);
180 
181  return NIL;
182 }
183 
184 /* --------------------------------------------------------------------
185  Crlf
186 
187  Just returns a sym_constant whose print name is a line feed.
188 -------------------------------------------------------------------- */
189 
190 Symbol *crlf_rhs_function_code (agent* thisAgent, list * /*args*/, void* /*user_data*/) {
191  return make_sym_constant (thisAgent, "\n");
192 }
193 
194 /* --------------------------------------------------------------------
195  Halt
196 
197  Just sets a flag indicating that the system has halted.
198 -------------------------------------------------------------------- */
199 
200 Symbol *halt_rhs_function_code (agent* thisAgent, list * /*args*/, void* /*user_data*/) {
201  thisAgent->system_halted = TRUE;
202  soar_invoke_callbacks(thisAgent,
204  0);
205 
206  return NIL;
207 }
208 
209 /* --------------------------------------------------------------------
210  Make-constant-symbol
211 
212  Returns a newly generated sym_constant. If no arguments are given,
213  the constant will start with "constant". If one or more arguments
214  are given, the constant will start with a string equal to the
215  concatenation of those arguments.
216 -------------------------------------------------------------------- */
217 
218 Symbol *make_constant_symbol_rhs_function_code (agent* thisAgent, list *args, void* /*user_data*/) {
219  std::stringstream buf;
220  char *string;
221  cons *c;
222 
223  if (!args) {
224  buf << "constant";
225  } else {
226  for (c=args; c!=NIL; c=c->rest) {
227  string = symbol_to_string (thisAgent, static_cast<symbol_union *>(c->first), FALSE, NIL, 0);
228  buf << string;
229  }
230  }
231  if ((!args) && (!find_sym_constant (thisAgent, buf.str().c_str())))
232  return make_sym_constant (thisAgent, buf.str().c_str());
233  return generate_new_sym_constant (thisAgent, buf.str().c_str(), &thisAgent->mcs_counter);
234 }
235 
236 
237 /* --------------------------------------------------------------------
238  Timestamp
239 
240  Returns a newly generated sym_constant whose name is a representation
241  of the current local time.
242 -------------------------------------------------------------------- */
243 
244 Symbol *timestamp_rhs_function_code (agent* thisAgent, list * /*args*/, void* /*user_data*/) {
245  time_t now;
246  struct tm *temp;
247 #define TIMESTAMP_BUFFER_SIZE 100
248  char buf[TIMESTAMP_BUFFER_SIZE];
249 
250  now = time(NULL);
251 #ifdef THINK_C
252  temp = localtime ((const time_t *)&now);
253 #else
254 #ifdef __SC__
255  temp = localtime ((const time_t *)&now);
256 #else
257 #ifdef __ultrix
258  temp = localtime ((const time_t *)&now);
259 #else
260 #ifdef MACINTOSH
261  temp = localtime ((const time_t *) &now);
262 #else
263  temp = localtime (&now);
264 #endif
265 #endif
266 #endif
267 #endif
268  SNPRINTF (buf,TIMESTAMP_BUFFER_SIZE, "%d/%d/%d-%02d:%02d:%02d",
269  temp->tm_mon + 1, temp->tm_mday, temp->tm_year,
270  temp->tm_hour, temp->tm_min, temp->tm_sec);
271  buf[TIMESTAMP_BUFFER_SIZE - 1] = 0; /* ensure null termination */
272  return make_sym_constant (thisAgent, buf);
273 }
274 
275 /* --------------------------------------------------------------------
276  Accept
277 
278  Waits for the user to type a line of input; then returns the first
279  symbol from that line.
280 -------------------------------------------------------------------- */
281 
282 Symbol *accept_rhs_function_code (agent* thisAgent, list * /*args*/, void* /*user_data*/) {
283  char buf[2000], *s;
284  Symbol *sym;
285 
286  while (TRUE) {
287  s = fgets (buf, 2000, stdin);
288  // s = Soar_Read(thisAgent, buf, 2000); /* kjh(CUSP-B10) */
289  if (!s) {
290  /* s==NIL means immediate eof encountered or read error occurred */
291  return NIL;
292  }
293  s = buf;
294  sym = get_next_io_symbol_from_text_input_line (thisAgent, &s);
295  if (sym) break;
296  }
297  symbol_add_ref (sym);
298  release_io_symbol (thisAgent, sym); /* because it was obtained using get_io_... */
299  return sym;
300 }
301 
302 
303 /* ---------------------------------------------------------------------
304  Capitalize a Symbol
305 ------------------------------------------------------------------------ */
306 
307 Symbol *
308 capitalize_symbol_rhs_function_code (agent* thisAgent, list *args, void* /*user_data*/)
309 {
310  char * symbol_to_capitalize;
311  Symbol * sym;
312 
313  if (!args) {
314  print (thisAgent, "Error: 'capitalize-symbol' function called with no arguments.\n");
315  return NIL;
316  }
317 
318  sym = static_cast<Symbol *>(args->first);
319  if (sym->common.symbol_type != SYM_CONSTANT_SYMBOL_TYPE) {
320  print_with_symbols (thisAgent, "Error: non-symbol (%y) passed to capitalize-symbol function.\n", sym);
321  return NIL;
322  }
323 
324  if (args->rest) {
325  print (thisAgent, "Error: 'capitalize-symbol' takes exactly 1 argument.\n");
326  return NIL;
327  }
328 
329  symbol_to_capitalize = symbol_to_string(thisAgent, sym, FALSE, NIL, 0);
330  symbol_to_capitalize = savestring(symbol_to_capitalize);
331  *symbol_to_capitalize = static_cast<char>(toupper(*symbol_to_capitalize));
332  return make_sym_constant(thisAgent, symbol_to_capitalize);
333 }
334 
335 /* AGR 520 begin 6-May-94 */
336 /* ------------------------------------------------------------
337  2 general purpose rhs functions by Gary.
338 ------------------------------------------------------------
339 
340 They are invoked in the following manner, and I use them
341 to produce nice traces.
342 
343  (ifeq <a> <b> abc def)
344 and
345  (strlen <a>)
346 
347 ifeq -- checks if the first argument is "eq" to the second argument
348  if it is then it returns the third argument else the fourth.
349  It is useful in similar situations to the "?" notation in C.
350  Contrary to earlier belief, all 4 arguments are required.
351 
352  examples:
353  (sp trace-juggling
354  (goal <g> ^state.ball.position <pos>)
355  -->
356  (write (ifeq <pos> at-top | o | ||) (crlf)
357  (ifeq <pos> left-middle | o | ||)
358  (ifeq <pos> right-middle | o | ||) (crlf)
359  (ifeq <pos> left-hand |o | ||)
360  (ifeq <pos> right-hand | o| ||) (crlf)
361  |V_______V| (crlf))
362  )
363 
364  This outputs with a single production one of the following
365  pictures depending on the ball's position (providing the ball
366  is not dropped of course. Then it outputs empty hands. :-)
367 
368  o
369  o o
370  o o
371  V-------V V-------V V-------V V-------V V-------V
372  or or or or
373 
374 
375  for a ball that takes this path.
376 
377  o
378  o o
379  o o
380  V-------V
381 
382  Basically this is useful when you don't want the trace to
383  match the internal working memory structure.
384 
385 strlen <val> - returns the string length of the output string so that
386  one can get the output to line up nicely. This is useful
387  along with ifeq when the output string varies in length.
388 
389  example:
390 
391  (strlen |abc|) returns 3
392 
393  (write (ifeq (strlen <foo>) 3 | | ||)
394  (ifeq (strlen <foo>) 2 | | ||)
395  (ifeq (strlen <foo>) 1 | | ||) <foo>)
396 
397  writes foo padding on the left with enough blanks so that
398  the length of the output is always at least 4 characters.
399 
400 ------------------------------------------------------------ */
401 
402 Symbol *ifeq_rhs_function_code (agent* thisAgent, list *args, void* /*user_data*/) {
403  Symbol *arg1, *arg2;
404  cons *c;
405 
406  if (!args) {
407  print (thisAgent, "Error: 'ifeq' function called with no arguments\n");
408  return NIL;
409  }
410 
411  /* --- two or more arguments --- */
412  arg1 = static_cast<symbol_union *>(args->first);
413  c=args->rest;
414  arg2 = static_cast<symbol_union *>(c->first);
415  c=c->rest;
416 
417  if (arg1 == arg2)
418  {
419  symbol_add_ref(static_cast<Symbol *>(c->first));
420  return static_cast<symbol_union *>(c->first);
421  }
422  else if (c->rest)
423  {
424  symbol_add_ref(static_cast<Symbol *>(c->rest->first));
425  return static_cast<symbol_union *>(c->rest->first);
426  }
427  else return NIL;
428 }
429 
430 Symbol *trim_rhs_function_code ( agent* thisAgent, list *args, void* /*user_data*/ )
431 {
432  char *symbol_to_trim;
433  Symbol *sym;
434 
435  if ( !args )
436  {
437  print( thisAgent, "Error: 'trim' function called with no arguments.\n" );
438  return NIL;
439  }
440 
441  sym = (Symbol *) args->first;
442 
443  if ( sym->common.symbol_type != SYM_CONSTANT_SYMBOL_TYPE )
444  {
445  print_with_symbols( thisAgent, "Error: non-symbol (%y) passed to 'trim' function.\n", sym );
446  return NIL;
447  }
448 
449  if ( args->rest )
450  {
451  print( thisAgent, "Error: 'trim' takes exactly 1 argument.\n" );
452  return NIL;
453  }
454 
455  symbol_to_trim = symbol_to_string( thisAgent, sym, FALSE, NIL, 0 );
456  symbol_to_trim = savestring( symbol_to_trim );
457 
458  std::string str( symbol_to_trim );
459  size_t start_pos = str.find_first_not_of( " \t\n" );
460  size_t end_pos = str.find_last_not_of( " \t\n" );
461 
462  if ( ( std::string::npos == start_pos ) || ( std::string::npos == end_pos ) )
463  str = "";
464  else
465  str = str.substr( start_pos, end_pos - start_pos + 1 );
466 
467  return make_sym_constant( thisAgent, str.c_str() );
468 }
469 
470 Symbol *strlen_rhs_function_code (agent* thisAgent, list *args, void* /*user_data*/) {
471  Symbol *arg;
472  char *string;
473 
474  arg = static_cast<symbol_union *>(args->first);
475 
476  /* --- Note use of FALSE here--print the symbol itself, not a rereadable
477  version of it --- */
478  string = symbol_to_string (thisAgent, arg, FALSE, NIL, 0);
479 
480  return make_int_constant (thisAgent, static_cast<int64_t>(strlen(string)));
481 }
482 /* AGR 520 end */
483 
484 /* --------------------------------------------------------------------
485  dont_learn
486 
487 Hack for learning. Allow user to denote states in which learning
488 shouldn't occur when "learning" is set to "except".
489 -------------------------------------------------------------------- */
490 
491 Symbol *dont_learn_rhs_function_code (agent* thisAgent, list *args, void* /*user_data*/) {
492  Symbol *state;
493 
494  if (!args) {
495  print (thisAgent, "Error: 'dont-learn' function called with no arg.\n");
496  return NIL;
497  }
498 
499  state = static_cast<Symbol *>(args->first);
500  if (state->common.symbol_type != IDENTIFIER_SYMBOL_TYPE) {
501  print_with_symbols (thisAgent, "Error: non-identifier (%y) passed to dont-learn function.\n", state);
502  return NIL;
503  } else if (! state->id.isa_goal) {
504  print_with_symbols(thisAgent, "Error: identifier passed to dont-learn is not a state: %y.\n",state);
505  }
506 
507  if (args->rest) {
508  print (thisAgent, "Error: 'dont-learn' takes exactly 1 argument.\n");
509  return NIL;
510  }
511 
512  if (! member_of_list (state, thisAgent->chunk_free_problem_spaces)) {
513  push(thisAgent, state, thisAgent->chunk_free_problem_spaces);
514  /* print_with_symbols("State %y added to chunk_free_list.\n",state); */
515  }
516  return NIL;
517 
518 }
519 
520 /* --------------------------------------------------------------------
521  force_learn
522 
523 Hack for learning. Allow user to denote states in which learning
524 should occur when "learning" is set to "only".
525 -------------------------------------------------------------------- */
526 
527 Symbol *force_learn_rhs_function_code (agent* thisAgent, list *args, void* /*user_data*/) {
528  Symbol *state;
529 
530  if (!args) {
531  print (thisAgent, "Error: 'force-learn' function called with no arg.\n");
532  return NIL;
533  }
534 
535  state = static_cast<Symbol *>(args->first);
536  if (state->common.symbol_type != IDENTIFIER_SYMBOL_TYPE) {
537  print_with_symbols (thisAgent, "Error: non-identifier (%y) passed to force-learn function.\n", state);
538  return NIL;
539  } else if (! state->id.isa_goal) {
540  print_with_symbols(thisAgent, "Error: identifier passed to force-learn is not a state: %y.\n",state);
541  }
542 
543 
544  if (args->rest) {
545  print (thisAgent, "Error: 'force-learn' takes exactly 1 argument.\n");
546  return NIL;
547  }
548 
549  if (! member_of_list (state, thisAgent->chunky_problem_spaces)) {
550  push(thisAgent, state, thisAgent->chunky_problem_spaces);
551  /* print_with_symbols("State %y added to chunky_list.\n",state); */
552  }
553  return NIL;
554 
555 }
556 
557 /* ====================================================================
558  RHS Deep copy recursive helper functions
559 ==================================================================== */
560 void recursive_deep_copy_helper(agent* thisAgent,
561  Symbol* id_to_process,
562  Symbol* parent_id,
563  std::map<Symbol*,Symbol*>& processedSymbols);
564 
565 void recursive_wme_copy(agent* thisAgent,
566  Symbol* parent_id,
567  wme* curwme,
568  std::map<Symbol*,Symbol*>& processedSymbols) {
569 
570  bool made_new_attr_symbol = false;
571  bool made_new_value_symbol = false;
572 
573  Symbol* new_id = parent_id;
574  Symbol* new_attr = curwme->attr;
575  Symbol* new_value = curwme->value;
576 
577  /* Handling the case where the attribute is an id symbol */
578  if ( curwme->attr->common.symbol_type == 1 ) {
579  /* Have I already made a new identifier for this identifier */
580  std::map<Symbol*,Symbol*>::iterator it = processedSymbols.find(curwme->attr);
581  if ( it != processedSymbols.end() ) {
582  /* Retrieve the previously created id symbol */
583  new_attr = it->second;
584  } else {
585  /* Make a new id symbol */
586  new_attr = make_new_identifier(thisAgent,
587  curwme->attr->id.name_letter,
588  1);
589  made_new_attr_symbol = true;
590  }
591 
592  recursive_deep_copy_helper(thisAgent,
593  curwme->attr,
594  new_attr,
595  processedSymbols);
596  }
597 
598  /* Handling the case where the value is an id symbol */
599  if ( curwme->value->common.symbol_type == 1 ) {
600  /* Have I already made a new identifier for this identifier */
601  std::map<Symbol*,Symbol*>::iterator it = processedSymbols.find(curwme->value);
602  if ( it != processedSymbols.end() ) {
603  /* Retrieve the previously created id symbol */
604  new_value = it->second;
605  } else {
606  /* Make a new id symbol */
607  new_value = make_new_identifier(thisAgent,
608  curwme->value->id.name_letter,
609  1);
610  made_new_value_symbol = true;
611  }
612 
613  recursive_deep_copy_helper(thisAgent,
614  curwme->value,
615  new_value,
616  processedSymbols);
617  }
618 
619  /* Making the new wme (Note just reusing the wme data structure, these
620  wme's actually get converted into preferences later).*/
621  wme* oldGlobalWme = glbDeepCopyWMEs;
622 
623  /* TODO: We need a serious reference counting audit of the kernel But I think
624  this mirrors what happens in the instantiate rhs value and execute action
625  functions. */
626  symbol_add_ref(new_id);
627  if ( !made_new_attr_symbol ) symbol_add_ref(new_attr);
628  if ( !made_new_value_symbol) symbol_add_ref(new_value);
629 
630  glbDeepCopyWMEs = make_wme(thisAgent, new_id, new_attr, new_value, true);
631  glbDeepCopyWMEs->next = oldGlobalWme;
632 
633 }
634 
636  Symbol* id_to_process,
637  Symbol* parent_id,
638  std::map<Symbol*,Symbol*>& processedSymbols)
639 {
640  /* If this symbol has already been processed then ignore it and return */
641  if ( processedSymbols.find(id_to_process) != processedSymbols.end() ) {
642  return;
643  }
644  processedSymbols.insert(std::pair<Symbol*,Symbol*>(id_to_process,parent_id));
645 
646  /* Iterating over the normal slot wmes */
647  for (slot* curslot = id_to_process->id.slots;
648  curslot != 0;
649  curslot = curslot->next) {
650 
651  /* Iterating over the wmes in this slot */
652  for (wme* curwme = curslot->wmes;
653  curwme != 0;
654  curwme = curwme->next) {
655 
656  recursive_wme_copy(thisAgent,
657  parent_id,
658  curwme,
659  processedSymbols);
660 
661  }
662 
663  }
664 
665  /* Iterating over input wmes */
666  for (wme* curwme = id_to_process->id.input_wmes;
667  curwme != 0;
668  curwme = curwme->next) {
669 
670  recursive_wme_copy(thisAgent,
671  parent_id,
672  curwme,
673  processedSymbols);
674 
675  }
676 
677 }
678 /* ====================================================================
679  RHS Deep copy function
680 ==================================================================== */
681 Symbol* deep_copy_rhs_function_code(agent* thisAgent, list *args, void* /*user_data*/) {
682 
683  /* Getting the argument symbol */
684  Symbol* baseid = static_cast<Symbol *>(args->first);
685  if ( baseid->common.symbol_type != 1 ) {
686  return make_sym_constant(thisAgent,"*symbol not id*");
687  }
688 
689  /* Making the new root identifier symbol */
690  Symbol* retval = make_new_identifier(thisAgent, 'D', 1);
691 
692  /* Now processing the wme's associated with the passed in symbol */
693  std::map<Symbol*,Symbol*> processedSymbols;
694  recursive_deep_copy_helper(thisAgent,
695  baseid,
696  retval,
697  processedSymbols);
698 
699 
700  return retval;;
701 }
702 
703 /* --------------------------------------------------------------------
704  Count
705 
706  Takes arbitrary arguments and adds one to the associated
707  dynamic counters.
708 -------------------------------------------------------------------- */
709 
710 Symbol *count_rhs_function_code (agent* thisAgent, list *args, void* /*user_data*/) {
711  Symbol *arg;
712  char *string;
713 
714  for ( ; args!=NIL; args=args->rest) {
715  arg = static_cast<symbol_union *>(args->first);
716  /* --- Note use of FALSE here--print the symbol itself, not a rereadable
717  version of it --- */
718  string = symbol_to_string (thisAgent, arg, FALSE, NIL, 0);
719  (*thisAgent->dyn_counters)[ string ]++;
720  }
721 
722  return NIL;
723 }
724 
725 /* ====================================================================
726 
727  Initialize the Built-In RHS Functions
728 
729 ==================================================================== */
730 
732  add_rhs_function (thisAgent, make_sym_constant (thisAgent, "write"), write_rhs_function_code,
733  -1, FALSE, TRUE, 0);
734  add_rhs_function (thisAgent, make_sym_constant (thisAgent, "crlf"), crlf_rhs_function_code,
735  0, TRUE, FALSE, 0);
736  add_rhs_function (thisAgent, make_sym_constant (thisAgent, "halt"), halt_rhs_function_code,
737  0, FALSE, TRUE, 0);
738  /*
739  Replaced with a gSKI rhs function
740  add_rhs_function (thisAgent, make_sym_constant (thisAgent, "interrupt"),
741  interrupt_rhs_function_code,
742  0, FALSE, TRUE, 0);
743  */
744  add_rhs_function (thisAgent, make_sym_constant (thisAgent, "make-constant-symbol"),
746  -1, TRUE, FALSE, 0);
747  add_rhs_function (thisAgent, make_sym_constant (thisAgent, "timestamp"),
749  0, TRUE, FALSE, 0);
750  add_rhs_function (thisAgent, make_sym_constant (thisAgent, "accept"), accept_rhs_function_code,
751  0, TRUE, FALSE, 0);
752  add_rhs_function (thisAgent, make_sym_constant (thisAgent, "trim"),
754  1,
755  TRUE,
756  FALSE,
757  0);
758  add_rhs_function (thisAgent, make_sym_constant (thisAgent, "capitalize-symbol"),
760  1,
761  TRUE,
762  FALSE,
763  0);
764 /* AGR 520 begin */
765  add_rhs_function (thisAgent, make_sym_constant (thisAgent, "ifeq"), ifeq_rhs_function_code,
766  4, TRUE, FALSE, 0);
767  add_rhs_function (thisAgent, make_sym_constant (thisAgent, "strlen"), strlen_rhs_function_code,
768  1, TRUE, FALSE, 0);
769 /* AGR 520 end */
770 
771  add_rhs_function (thisAgent, make_sym_constant (thisAgent, "dont-learn"),
773  1, FALSE, TRUE, 0);
774  add_rhs_function (thisAgent, make_sym_constant (thisAgent, "force-learn"),
776  1, FALSE, TRUE, 0);
777 
778  add_rhs_function (thisAgent, make_sym_constant (thisAgent, "deep-copy"),
780  1,TRUE,FALSE,0);
781 
782  add_rhs_function (thisAgent, make_sym_constant (thisAgent, "count"),
784  -1,FALSE,TRUE,0);
785 
787 }
788 
790 
791  // DJP-FREE: These used to call make_sym_constant, but the symbols must already exist and if we call make here again we leak a reference.
792  remove_rhs_function (thisAgent, find_sym_constant (thisAgent, "write"));
793  remove_rhs_function (thisAgent, find_sym_constant (thisAgent, "crlf"));
794  remove_rhs_function (thisAgent, find_sym_constant (thisAgent, "halt"));
795  remove_rhs_function (thisAgent, find_sym_constant (thisAgent, "make-constant-symbol"));
796  remove_rhs_function (thisAgent, find_sym_constant (thisAgent, "timestamp"));
797  remove_rhs_function (thisAgent, find_sym_constant (thisAgent, "accept"));
798  remove_rhs_function (thisAgent, find_sym_constant (thisAgent, "trim"));
799  remove_rhs_function (thisAgent, find_sym_constant (thisAgent, "capitalize-symbol"));
800  remove_rhs_function (thisAgent, find_sym_constant (thisAgent, "ifeq"));
801  remove_rhs_function (thisAgent, find_sym_constant (thisAgent, "strlen"));
802  remove_rhs_function (thisAgent, find_sym_constant (thisAgent, "dont-learn"));
803  remove_rhs_function (thisAgent, find_sym_constant (thisAgent, "force-learn"));
804  remove_rhs_function (thisAgent, find_sym_constant (thisAgent, "deep-copy"));
805  remove_rhs_function (thisAgent, find_sym_constant (thisAgent, "count"));
806 
808 }