home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume3 / trc / part5 < prev    next >
Encoding:
Text File  |  1986-11-30  |  37.5 KB  |  1,532 lines

  1. Newsgroups: mod.sources
  2. Subject: TRC - expert system building tool (part 5 of 8)
  3. Approved: jpn@panda.UUCP
  4.  
  5. Mod.sources:  Volume 3, Issue 113
  6. Submitted by: ihnp4!dicomed!ndsuvax!nckary (Daniel D. Kary)
  7.  
  8. This is NOT a shell archive.  Simply delete everything up to and including
  9. the cut mark and save the result as reference.3.doc.
  10.  
  11. Dan Kary
  12. ihnp4!dicomed!ndsuvax!nckary
  13.  
  14. -------------- cut here ---------------
  15.  
  16.  
  17.                            - 46 -
  18.  
  19.  
  20. that an object is 'in-use'.  The MARK variable is not needed
  21. for it's original purpose when it is in the backtrack stack.
  22.  
  23. OUTPUT:
  24.      relink_A_struct(start)
  25.      int start;
  26.      {
  27.          backtrack->mark_A++;
  28.          token[A]--;
  29.      }
  30.  
  31.      relink_B_struct(start)
  32.      int start;
  33.      {
  34.          int i, j;
  35.          struct B_struct *temp;
  36.  
  37.          for(i = start; i < B_max; i++)
  38.              if(B_list[i]){
  39.                  temp = B_list[0];
  40.                  j = 0;
  41.                  while(temp != B_list[i]){
  42.                      temp = temp->next;
  43.                      j++;
  44.                  }
  45.                  if(B_list[i]->prev == NULL)
  46.                      B_list[0] = B_list[i]->next;
  47.                  else
  48.                      B_list[i]->prev->next = B_list[i]->next;
  49.                  if(B_list[i]->next)
  50.                      B_list[i]->next->prev = B_list[i]->prev;
  51.                  B_list[i]->MARK = j;
  52.                  B_list[i]->next = backtrack->mark_B;
  53.                  backtrack->mark_B = B_list[i];
  54.                  B_list[i] = NULL;
  55.                  i = B_max;
  56.                  token[B]--;
  57.              }
  58.      }
  59.  
  60.  
  61.      The backtracking action itself is initiated  after  the
  62. label 'End:' in the procedure 'loop'.  If there is something
  63. on the backtrack stack, the index  of  the  last  rule  that
  64. fired is copied out and the procedure 'backup', which undoes
  65. the actions of the last rule that fired, is called.   Execu-
  66. tion continues with the rule that follows the last rule that
  67. fired.  The procedure 'backup' first restores  objects  that
  68. were  MARKed  by the last rule and then removes objects that
  69. were ADDed.  The MARKed objects are restored to their origi-
  70. nal positions in the list.
  71.  
  72. OUTPUT:
  73.      backup()
  74.  
  75.  
  76.  
  77.  
  78.  
  79.  
  80.  
  81.  
  82.  
  83.                            - 47 -
  84.  
  85.  
  86.      {
  87.          int i;
  88.          struct back_track_stack *temp;
  89.          struct B_struct *B_temp, *B_temp2;
  90.  
  91.          if(backtrack == NULL)
  92.              return;
  93.          token[A] += backtrack->mark_A;
  94.          token[A] -= backtrack->Add_A;
  95.          while(backtrack->mark_B){
  96.              B_temp2 = backtrack->mark_B;
  97.              backtrack->mark_B = backtrack->mark_B->next;
  98.              B_temp2->prev = NULL;
  99.              B_temp2->next = NULL;
  100.              B_temp = B_list[0];
  101.              if(B_temp){
  102.                  for(i = 0; i < B_temp2->MARK; i++)
  103.                      if(B_temp->next)
  104.                          B_temp = B_temp->next;
  105.                      else
  106.                          i = B_temp2->MARK + 1;
  107.              }
  108.              else i = -1;
  109.              if(i == B_temp2->MARK){
  110.                  B_temp2->next = B_temp;
  111.                  B_temp2->prev = B_temp->prev;
  112.                  if(B_temp->prev)
  113.                      B_temp->prev->next = B_temp2;
  114.                  else
  115.                      B_list[0] = B_temp2;
  116.                  B_temp->prev = B_temp2;
  117.              }
  118.              else{
  119.                  if(B_temp){
  120.                      B_temp->next = B_temp2;
  121.                      B_temp2->prev = B_temp;
  122.                      B_temp2->next = NULL;
  123.                  }
  124.                  else B_list[0] = B_temp2;
  125.              }
  126.              B_temp2->MARK = 0;
  127.              token[B]++;
  128.          }
  129.          for(i = 0; i < backtrack->Add_B; i++){
  130.              B_list[1] = B_list[0];
  131.              free_B_struct(1);
  132.          }
  133.          temp = backtrack;
  134.          backtrack = backtrack->next;
  135.          free(temp);
  136.      }
  137.  
  138.  
  139.      The procedures generated by the BACKTRACKing option can
  140.  
  141.  
  142.  
  143.  
  144.  
  145.  
  146.  
  147.  
  148.  
  149.                            - 48 -
  150.  
  151.  
  152. be  called from embedded c-code to implement user controlled
  153. backtracking.  A rule may undo itself with the following two
  154. statements:
  155.  
  156.      backup();
  157.      goto NEXT_RULE;
  158.  
  159.  
  160.      The label 'NEXT_RULE' is replaced with the label of the
  161. rule  that  follows  the  current  rule (this is done by the
  162. knowledge engineer, not TRC).  To undo the current rule  and
  163. the  rule  that  fired previous to the current rule, use the
  164. following two statements:
  165.  
  166.      backup();
  167.      goto End;
  168.  
  169.  
  170.      The label 'End' always refers to the point that follows
  171. the  action  part  of  the last rule.  Appendix C contains a
  172. small expert system that implements backtracking with  calls
  173. in embedded c-code.
  174.  
  175. _1_3._5.  _Z_E_R_O
  176.  
  177.      The ZERO option  generates  code  that  will  free  all
  178. dynamic  structures  allocated by TRC generated code.  It is
  179. useful in systems where the loop procedure is  entered  more
  180. than once.  It may be necessary to clean up the remains of a
  181. previous execution before beginning a  new  one.   A  single
  182. procedure,  'zero()',  is written on the file 'zero.c'.  The
  183. zero procedure will  free  all  the  elements  and  all  the
  184. objects  in  STM and zero the arrays that hold the counts of
  185. objects in each list.  If BACKTRACKing is enabled, zero will
  186. free  all  the  objects and elements in the backtrack stack.
  187. If the TRACE option is  enabled,  zero  will  free  all  the
  188. entries  in  the  trace  list.   If  the  PROFILE  option is
  189. enabled, zero will set the value of all  the  integer  array
  190. elements  to  zero.   The  actual code produced for the zero
  191. procedure is uninteresting and is not reproduced here.
  192.  
  193. _1_3._6.  _S_A_V_E
  194.  
  195.      The SAVE option writes a set of procedures on the  file
  196. 'save.c'  that  simplify  building expert systems capable of
  197. checkpointing their own execution.  Procedures are generated
  198. for saving and reloading each type of dynamic structure that
  199. might be generated.  In each case the procedures are  passed
  200. a  file  pointer that points to an open file.  The code pro-
  201. duced by the save procedures is uninteresting  so  only  the
  202. names are listed here.  The purpose of each procedure should
  203. be obvious from it's name:
  204.  
  205.      save_stm(fp)        load_stm(fp)
  206.  
  207.  
  208.  
  209.  
  210.  
  211.  
  212.  
  213.  
  214.  
  215.                            - 49 -
  216.  
  217.  
  218.      save_backtrack(fp)  load_backtrack(fp)
  219.      save_profile(fp)    load_profile(fp)
  220.      save_trace(fp)      load_trace(fp)
  221.  
  222.  
  223.      Appendix C presents a small expert system that uses the
  224. SAVE option to generate code for checkpointing the execution
  225. of the system.  The example includes  an  automatic  restart
  226. capability.
  227.  
  228.  
  229.  
  230.  
  231.  
  232.  
  233.  
  234.  
  235.  
  236.  
  237.  
  238.  
  239.  
  240.  
  241.  
  242.  
  243.  
  244.  
  245.  
  246.  
  247.  
  248.  
  249.  
  250.  
  251.  
  252.  
  253.  
  254.  
  255.  
  256.  
  257.  
  258.  
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  
  270.  
  271.  
  272.  
  273.  
  274.  
  275.  
  276.  
  277.  
  278.  
  279.  
  280.  
  281.                            - 50 -
  282.  
  283.  
  284.                   APPENDIX A: TRC GRAMMAR
  285.  
  286.      The grammar for TRC which is presented throughout  PART
  287. ONE of this document is presented in it's entirety here.
  288.  
  289.  
  290. identifier       ::=  letter { underscore | letter | digit}
  291. letter           ::=  upper-case-letter | lower-case-letter
  292. f-p              ::=  [ minus ] digits dot digits
  293. integer-literal  ::=  [ minus ] digits
  294. digits           ::=  digit { digit }
  295. string-literal   ::=  quote { [ character ] } quote
  296. comment          ::= slash asterisk { [ character ] } asterisk slash
  297. c_code           ::=  left-bracket { [character] | [c_code] } right-bracket
  298. definition       ::=  identifier
  299. definition       ::=  identifier left-paren item-list right-paren
  300. item-list        ::=  { [ item ] }
  301. item             ::=  identifier colon type
  302. type             ::=  INT | FLOAT | STRING | POINTER
  303. stm              ::=  { [ entry ] }
  304. entry            ::=  [ integer-literal ] identifier
  305. entry            ::=  [ integer-literal ] identifier
  306.                       left-paren { [ init-item ] } right-paren
  307. init-item        ::=  identifier arrow value
  308. value            ::=  integer-literal
  309. value            ::=  floating-point-literal
  310. value            ::=  string-literal
  311. ltm              ::=  { [option] } { rule }
  312. option           ::=  ZERO  |  PROFILE  |  BACKTRACK
  313.                    |  DUMP  |  RECURS  |  NORECURS
  314.                    |  SAVE  |  TRACE  | PREFIX identifier
  315. rule             ::=  label situation arrow action semicolon
  316. label            ::=  identifier colon  |  colon
  317. situation        ::=  { [ s-option ] } { [ match ] }
  318. s-option         ::=  EMPTY identifier identifier
  319. s-option         ::=  RECURS  |  NORECURS
  320. match            ::=  [ integer-literal ] identifier
  321. match            ::=  NOT identifier
  322. match            ::=  [ integer-literal ] left-paren name
  323.                       match-list right-paren
  324. match            ::=  c-code
  325. name             ::=  hat identifier identifier
  326. match-list       ::=  { match-item }
  327. match-item       ::=  identifier dot identifier relop literal
  328. match-item       ::=  identifier dot identifier relop
  329.                       identifier dot identifier
  330. relop            ::=  equality  |  not-equal  |  less-than
  331. relop            ::=  greater-than  |  greater-than-or-equal
  332. relop            ::=  less-than-or-equal
  333. action           ::=  statements c-code
  334. statements       ::=  { [statement] }
  335. statement        ::=  MARK mark-list
  336. statement        ::=  ADD  add-list
  337. statement        ::=  OPTIMIZE identifier
  338.  
  339.  
  340.  
  341.  
  342.  
  343.  
  344.  
  345.  
  346.  
  347.                            - 51 -
  348.  
  349.  
  350. mark-list        ::=  { [ mark-item ] }
  351. mark-item        ::=  [ integer-literal ] identifier
  352. add-list         ::=  { [ entry ] }
  353.  
  354.  
  355.  
  356.  
  357.  
  358.  
  359.  
  360.  
  361.  
  362.  
  363.  
  364.  
  365.  
  366.  
  367.  
  368.  
  369.  
  370.  
  371.  
  372.  
  373.  
  374.  
  375.  
  376.  
  377.  
  378.  
  379.  
  380.  
  381.  
  382.  
  383.  
  384.  
  385.  
  386.  
  387.  
  388.  
  389.  
  390.  
  391.  
  392.  
  393.  
  394.  
  395.  
  396.  
  397.  
  398.  
  399.  
  400.  
  401.  
  402.  
  403.  
  404.  
  405.  
  406.  
  407.  
  408.  
  409.  
  410.  
  411.  
  412.  
  413.                            - 52 -
  414.  
  415.  
  416.                  APPENDIX B: ERROR MESSAGES
  417.  
  418.      Error messages are listed and explained here in  alpha-
  419. betical  order.  All  messages  that refer to the input file
  420. begin with the line number of the input file where the error
  421. was  noticed.   This line number is not necessarily the line
  422. where the error occurred, the actual error could  be  on  an
  423. earlier line.  The notations %s and %o mean that a string or
  424. an octal  number,  respectively,  from  the  input  file  is
  425. included in the error message.
  426.  
  427.  
  428. %s is not an element of %s
  429.  
  430.           The named object does not include the  named  ele-
  431.           ment.
  432.  
  433.  
  434. cannot translate %s in rule %s
  435.  
  436.           A c-code in rule %s contains an identifier %s that
  437.           is preceded by a dollar character.  The identifier
  438.           is not known to TRC.  This will occur if a  dollar
  439.           character  occurs  at  some random point in the c-
  440.           code.  This error will also occur if an identifier
  441.           is misspelled.
  442.  
  443.  
  444. can't have %s and NOT %s in the same rule
  445.  
  446.           NOT %s is a test that is true only when %s  is  an
  447.           empty  list.   Obviously a list may not contain an
  448.           object and be empty so the statement  is  meaning-
  449.           less to TRC.
  450.  
  451.  
  452. can't MARK an EMPTY object
  453.  
  454.           An EMPTY object is an object that  exists  outside
  455.           of  STM.  The scope of an EMPTY object is the rule
  456.           in which it is declared.  Since EMPTY objects  are
  457.           not in STM, attempting to MARK one is meaningless.
  458.  
  459.  
  460. can't mark more %s's than are found
  461.  
  462.           Unless STM is  searched  for  an  object  and  the
  463.           object  is found it is not possible to remove that
  464.           object from STM.  STM  is  searched  only  in  the
  465.           situation  part,  anything  to  be  deleted in the
  466.           action part must have been found in the  situation
  467.           part.
  468.  
  469.  
  470.  
  471.  
  472.  
  473.  
  474.  
  475.  
  476.  
  477.  
  478.  
  479.                            - 53 -
  480.  
  481.  
  482. count on free variables undefined
  483.  
  484.           The purpose of a free variable is to assign a name
  485.           to a specific object.  Placing a count in front of
  486.           a free variable definition is meaningless  because
  487.           the name can be assigned to only one object.
  488.  
  489.  
  490. degenerate case please rewrite
  491.  
  492.           A match in a rule compares an element  to  itself.
  493.           The  result  of  comparing an element to itself is
  494.           known without performing any test.  TRC refuses to
  495.           generate  the  extra  code  that this useless test
  496.           requires.
  497.  
  498.  
  499. duplicate declaration  -> %s
  500.  
  501.           Object names must be unique, %s is the name of the
  502.           object  that  is mentioned twice in the definition
  503.           section.
  504.  
  505.  
  506. duplicate name in definition -> %s
  507.  
  508.           Each element in an object definition must  have  a
  509.           unique name.
  510.  
  511.  
  512. free variable already defined -> %s
  513.  
  514.           The scope of a free variable  is  a  single  rule.
  515.           Free  variable  names may be reused in every rule,
  516.           but only once per rule.
  517.  
  518.  
  519. label repeats object declaration -> %s
  520.  
  521.           Rule labels and object names must be distinct from
  522.           one  another to prevent name conflicts in the out-
  523.           put source code.
  524.  
  525.  
  526. negative count is undefined
  527.  
  528.           Be serious.  How can a list contain less than zero
  529.           items?
  530.  
  531.  
  532. newline embedded in string
  533.  
  534.           The scanner attempts to prevent errors  caused  by
  535.           forgetting to terminate a string.  For that reason
  536.  
  537.  
  538.  
  539.  
  540.  
  541.  
  542.  
  543.  
  544.  
  545.                            - 54 -
  546.  
  547.  
  548.           literal newlines are not permitted in strings.   A
  549.           newline and other control characters can be embed-
  550.           ded in a  string  using  the  normal  UNIX  and  C
  551.           escapes.
  552.  
  553.  
  554. no code produced due to errors in source
  555.  
  556.           TRC will generate code  only  when  there  are  no
  557.           errors in the source.
  558.  
  559.  
  560. object field must be a string
  561. object field must be double
  562. object field must be integer
  563.  
  564.           TRC enforces strong type checking  for  the  three
  565.           data  types,  all assignments and relational tests
  566.           must involve elements of the same type.
  567.  
  568.  
  569. objects in a complex test must match
  570.  
  571.           Here is an example of this type of error:
  572.  
  573.                (A.A1 == 2
  574.                 B.B1 == 3)
  575.  
  576.           Because a single set of parens bracket  this  test
  577.           it  is  presumed to be a test for a single object.
  578.           A single object can not be in both list  A  (A.A1)
  579.           and  list B (B.B1).  Either there is a typo in one
  580.           of object names or some parens are missing.
  581.  
  582.  
  583. OUT OF MEMORY
  584. TRC IS EXITING
  585.  
  586.           This message is not generated by TRC, rather it is
  587.           generated  by the code that TRC produces.  It will
  588.           occur when  the  TRC  generated  inference  engine
  589.           attempts  to  dynamically  allocate a data object.
  590.           If the allocate  fails,  the  TRC  generated  code
  591.           prints this message and exits.
  592.  
  593.  
  594. redefined label -> %s
  595.  
  596.           Every rule must have a distinct label.
  597.  
  598.  
  599. semantic error: use a free variable
  600.  
  601.           This message suggests a solution to the  perceived
  602.  
  603.  
  604.  
  605.  
  606.  
  607.  
  608.  
  609.  
  610.  
  611.                            - 55 -
  612.  
  613.  
  614.           problem.   It  is printed when the right hand side
  615.           of a relational test mentions an object name  that
  616.           is different from the object name mentioned on the
  617.           right hand side.  This type of test can be  accom-
  618.           plished,  but the item on the right hand side must
  619.           be found first and must have a free variable  name
  620.           assigned to it.
  621.  
  622.  
  623. syntax error
  624. syntax error in ADD statement
  625. syntax error in MARK statement
  626. syntax error in OPTIMIZE statement
  627. syntax error in definitions
  628. syntax error in header
  629. syntax error in previous rule
  630. syntax error in short term memory
  631. syntax error in trailer
  632.  
  633.           A syntax error is generated by the parser when  it
  634.           can  not  reduce the input tokens with any of it's
  635.           rules.  The current input token will be  discarded
  636.           and  the  parser  will  attempt  to reduce the new
  637.           input.  At least three input tokens must be parsed
  638.           before the parser will assume it is in sync.  Once
  639.           the parser finds an error it will throw tokens out
  640.           until  it  can sync.  This is the reason why semi-
  641.           colons are used as a rule terminator, they provide
  642.           an  absolute  point  where  the parser can sync no
  643.           matter how  badly  the  input  is  botched.   This
  644.           behavior is common to YACC generated parsers.  All
  645.           syntax error messages indicate the line  that  was
  646.           being  scanned when the error was noticed and most
  647.           inform the user of what section of  the  code  was
  648.           being parsed.
  649.  
  650.  
  651. types of element (%s) and value (%s) do not match
  652.  
  653.           Strong type checking is enforced by TRC.  Literals
  654.           must  be  of the same type as the element they are
  655.           being assigned to.  Floating point  literals  MUST
  656.           contain  a  decimal  point.  There can be no cross
  657.           assignment between integer and floating point ele-
  658.           ments.
  659.  
  660.  
  661. types of %s.%s and %s.%s do not match
  662.  
  663.           Strong type checking is  enforced  by  TRC.   Only
  664.           elements of identical types may be compared.
  665.  
  666.  
  667. unable to attach %s to the standard input
  668.  
  669.  
  670.  
  671.  
  672.  
  673.  
  674.  
  675.  
  676.  
  677.                            - 56 -
  678.  
  679.  
  680.           The scanner actually  reads  the  standard  input.
  681.           The  file  named  on the command line could not be
  682.           opened for reading and attached  to  the  standard
  683.           input.
  684.  
  685.  
  686. unable to open %s
  687.  
  688.           Open failed on  one  of  the  output  files.   TRC
  689.           aborts.
  690.  
  691.  
  692. unable to recover from earlier errors
  693.  
  694.           The parser completely wigged  out,   this  usually
  695.           happens  when  the  input  terminates  before  the
  696.           parser can resync.
  697.  
  698.  
  699. undefined element -> %s.%s
  700.  
  701.           The object %s does not have an element %s.
  702.  
  703.  
  704. undefined flag (%c)
  705.  
  706.           A command line argument included a  compiler  flag
  707.           that  is  not  defined.   Use  'man  trc' to get a
  708.           manual page.
  709.  
  710.  
  711. undefined free variable -> %s
  712.  
  713.           A reference was made to a  free  variable  on  the
  714.           right  hand  side of a relational test.  That free
  715.           variable was not attached  to  an  object  in  the
  716.           current  rule.   Remember that the scope of a free
  717.           variable is a single rule.
  718.  
  719.  
  720. undefined object -> %s
  721.  
  722.           The name %s was used as an  object  name  but  not
  723.           defined as such in the definition section.
  724.  
  725.  
  726. undefined object field -> %s.%s
  727.  
  728.           The object %s was defined, but it did not  contain
  729.           an element %s.
  730.  
  731.  
  732. unexpected '!'
  733. unexpected '%'
  734.  
  735.  
  736.  
  737.  
  738.  
  739.  
  740.  
  741.  
  742.  
  743.                            - 57 -
  744.  
  745.  
  746. unexpected '='
  747. unexpected or undefined character: %o
  748.  
  749.           These  messages  are  generated  by  the  scanner.
  750.           These  characters, when not embedded in a comment,
  751.           string or code section,  are  meaningful  only  as
  752.           part  of  a  compound  symbol (e.g !=, ==, %%).  A
  753.           single character is not  returned  to  the  parser
  754.           since it will only propagate errors.
  755.  
  756.  
  757. unterminated C code
  758. unterminated comment
  759.  
  760.           These elements of the input are handled completely
  761.           by the scanner.  These messages are printed if the
  762.           end of the input file is reached before  the  ter-
  763.           minating  character  is found.  Each of these mes-
  764.           sages indicate the line of the input  where  scan-
  765.           ning began.
  766.  
  767.  
  768. usage: trc [options] filename
  769.  
  770.           Command line error.  Use 'man trc' to get a manual
  771.           page.
  772.  
  773.  
  774. zero count is undefined
  775.  
  776.           Nice try.  If you really want to  search  STM  for
  777.           zero  occurrences  of something use the NOT state-
  778.           ment described in Section 6.3.1 of this document.
  779.  
  780.  
  781.  
  782.  
  783.  
  784.  
  785.  
  786.  
  787.  
  788.  
  789.  
  790.  
  791.  
  792.  
  793.  
  794.  
  795.  
  796.  
  797.  
  798.  
  799.  
  800.  
  801.  
  802.  
  803.  
  804.  
  805.  
  806.  
  807.  
  808.  
  809.                            - 58 -
  810.  
  811.  
  812.                   APPENDIX C: STYLE NOTES
  813.  
  814.      TRC was designed to produce fast code, but  it  is  not
  815. the  least bit difficult to produce very slow code with TRC.
  816. The intent of this section is to suggest  some  things  that
  817. can  be done that will lead to fast code and to suggest some
  818. ways to avoid creating slow code.
  819.  
  820.      The central issue is reducing the amount of time  spent
  821. searching  STM.   In  the  battle against long search times,
  822. TRC's first line  of  defense  is  the  definition  section.
  823. Think  of  STM as a data base.  When a data base is designed
  824. two issues are central: first the data base must be  capable
  825. of  representing  all  the  facts  that are to be stored and
  826. retrieved and second the data base should be arranged  in  a
  827. manner  that  will facilitate searching the data base.  In a
  828. relational data base, the data base manager  will  designate
  829. primary  keys  based,  in  part,  on  the way that users are
  830. likely to specify searches.  Think of STM as  a  data  base,
  831. the  rules  in LTM are the users that are searching the data
  832. base, design the data base (STM) for searching.
  833.  
  834.      Suppose an expert system for routing cargo  on  commer-
  835. cial  air  carriers  is  being built.  The objects that this
  836. expert system will deal with include  airplanes  and  cargo.
  837. It is certainly possible to define a single TRC object whose
  838. elements can describe either  an  airplane  or  a  piece  of
  839. cargo.  When a rule searches for an airplane in this system,
  840. it has to wade thru cargo and airplanes to find the airplane
  841. it  needs.   Why  not define two different objects, one that
  842. describes airplanes and one that describes  cargo.   Then  a
  843. rule  that  is searching for an airplane can search only the
  844. airplane list without having to wade thru the cargo too.
  845.  
  846.      Carried to an extreme, this suggestion implies  a  dif-
  847. ferent object definition for every combination of attributes
  848. that can exist in STM.  This extreme will often not be feas-
  849. able.   There  is  a  trade off to be made; by defining more
  850. objects, the length of each list  should  be  reduced  which
  851. should  reduce execution time.  The penalty is that for each
  852. object there is a code  overhead  for  the  procedures  that
  853. manipulate  those  objects.   Code  size is being traded for
  854. execution speed.
  855.  
  856.      For object definitions that do not include any elements
  857. there  is a very low code overhead.  Object definitions that
  858. do not include elements are useful when the objects  do  not
  859. differ  from  one another and only a count of how many there
  860. are is needed.  Since objects of this type do not differ, no
  861. list is maintained.  If STM can be represented entirely with
  862. objects that contain no  elements,  all  searching  will  be
  863. eliminated.   This  situation  usually  leads to the fastest
  864. executing systems.
  865.  
  866.  
  867.  
  868.  
  869.  
  870.  
  871.  
  872.  
  873.  
  874.  
  875.                            - 59 -
  876.  
  877.  
  878.      The situation part of a rule  is  the  second  line  of
  879. defense against slow expert systems.  On each pass thru LTM,
  880. only one rule is selected for  firing.   This  implies  that
  881. most  rules  fail  most  of the time and that is is somewhat
  882. unusual for a rule to actually fire.  Since rules  generally
  883. fail  far  more often than they fire, wouldn't it be reason-
  884. able to design rules  to  be  good  at  failing,  i.e.  fail
  885. quickly?   The  preconditions  automatically placed on every
  886. rule by TRC are an initial attempt to cause a rule  to  fail
  887. without doing any searching.
  888.  
  889.      If a rule searches for an object in list A, one in list
  890. B  and  one  in list C, the order that the list are searched
  891. may not be significant.  The order will  not  be  significan
  892. unless one of the searches refers to something that was pre-
  893. viously found.  If the order is  not  significant,  why  not
  894. first  search  for the object that is least likely to exist?
  895. If the objects are equally likely, why not first search  the
  896. list  that  is likely to be shortest?  The search is carried
  897. out in the order that the objects are listed in  the  situa-
  898. tion part.  Remember that rules usually fail and design your
  899. rules to fail quickly wherever possible.
  900.  
  901.      The optimizer is the third line of defense, use it.
  902.  
  903.  
  904.  
  905.  
  906.  
  907.  
  908.  
  909.  
  910.  
  911.  
  912.  
  913.  
  914.  
  915.  
  916.  
  917.  
  918.  
  919.  
  920.  
  921.  
  922.  
  923.  
  924.  
  925.  
  926.  
  927.  
  928.  
  929.  
  930.  
  931.  
  932.  
  933.  
  934.  
  935.  
  936.  
  937.  
  938.  
  939.  
  940.  
  941.                            - 60 -
  942.  
  943.  
  944.                       A SAMPLE SYSTEM
  945.  
  946.      This sample expert  system  demonstrates  some  of  the
  947. features  of  the  TRC  language.  The expert system finds a
  948. path from one node to another node in a 'dungeon'.  Some  of
  949. the  nodes  are  marked  as  'dangerous', and no path may go
  950. through that node.  The main procedure prints a map  of  the
  951. 'dungeon'  and  asks  the  user for start and end nodes.  It
  952. then initializes STM and calls loop.  On return from loop it
  953. prints  out  the  path  (if one was found) and the execution
  954. time and profile.  The path is not necessarily the  shortest
  955. path, only the first path found.  Cycles are not permitted.
  956.  
  957.      This sample system uses backtracking that is  initiated
  958. by  embedded  c-code.   It also uses the SAVE option to sim-
  959. plify the checkpoint and  reloading  procedures.   The  pro-
  960. cedure  'checkpoint'  saves  the state of all dynamic struc-
  961. tures and 're_do' restores from a previous  checkpoint.   If
  962. the  system  is  started  with no command line arguments, it
  963. simply queries the user for start and end points.  If it  is
  964. started  one or more command line arguments, it will restart
  965. from a previously saved snapshot.
  966.  
  967.      Since it is possible for a system to  crash  while  the
  968. checkpoint  files  are  being  written,  this  system writes
  969. alternately on two sets of files.   A  flag  file  indicates
  970. which set of files is complete.
  971.  
  972. INPUT:
  973.  
  974. %%
  975. END   (E1:STRING)
  976. NODE  (N1:STRING
  977.        N2:STRING
  978.        N3:STRING)
  979. PATH  (P1:STRING)
  980. START (S1:STRING)
  981. %%
  982. NODE  ( N1 => "ANEMONIE" N2 => "DANGER" N3 => "QUAGGA")
  983. NODE  ( N1 => "ANEMONIE" N2 => "DANGER" N3 => "YENTI")
  984. NODE  ( N1 => "ANEMONIE" N2 => "SAFE" N3 => "MEADOW")
  985. NODE  ( N1 => "ANEMONIE" N2 => "SAFE" N3 => "KESTREL")
  986. NODE  ( N1 => "BANDIT" N2 => "SAFE" N3 => "JABBERWOCK")
  987. NODE  ( N1 => "BANDIT" N2 => "SAFE" N3 => "PEGASUS")
  988. NODE  ( N1 => "BANDIT" N2 => "SAFE" N3 => "LAPIS LASULI")
  989. NODE  ( N1 => "CAVERN" N2 => "SAFE" N3 => "ICE ROOM")
  990. NODE  ( N1 => "CAVERN" N2 => "SAFE" N3 => "TREASURE")
  991. NODE  ( N1 => "CAVERN" N2 => "DANGER" N3 => "HOBGOBLIN")
  992. NODE  ( N1 => "DUBLOON" N2 => "SAFE" N3 => "ICE ROOM")
  993. NODE  ( N1 => "DUBLOON" N2 => "DANGER" N3 => "HOBGOBLIN")
  994. NODE  ( N1 => "DUBLOON" N2 => "SAFE" N3 => "SPRING")
  995. NODE  ( N1 => "ELVES" N2 => "SAFE" N3 => "NYMPH")
  996. NODE  ( N1 => "ELVES" N2 => "SAFE" N3 => "URCHIN")
  997. NODE  ( N1 => "FOUNTAIN" N2 => "SAFE" N3 => "RUBY")
  998.  
  999.  
  1000.  
  1001.  
  1002.  
  1003.  
  1004.  
  1005.  
  1006.  
  1007.                            - 61 -
  1008.  
  1009.  
  1010. NODE  ( N1 => "FOUNTAIN" N2 => "SAFE" N3 => "NYMPH")
  1011. NODE  ( N1 => "FOUNTAIN" N2 => "DANGER" N3 => "XEROC")
  1012. NODE  ( N1 => "GROTTO" N2 => "DANGER" N3 => "WRAITH")
  1013. NODE  ( N1 => "GROTTO" N2 => "SAFE" N3 => "OGRE")
  1014. NODE  ( N1 => "GROTTO" N2 => "SAFE" N3 => "RUBY")
  1015. NODE  ( N1 => "HOBGOBLIN" N2 => "SAFE" N3 => "TREASURE")
  1016. NODE  ( N1 => "HOBGOBLIN" N2 => "SAFE" N3 => "CAVERN")
  1017. NODE  ( N1 => "HOBGOBLIN" N2 => "SAFE" N3 => "ICE ROOM")
  1018. NODE  ( N1 => "HOBGOBLIN" N2 => "SAFE" N3 => "DUBLOON")
  1019. NODE  ( N1 => "HOBGOBLIN" N2 => "SAFE" N3 => "MEADOW")
  1020. NODE  ( N1 => "ICE ROOM" N2 => "SAFE" N3 => "CAVERN")
  1021. NODE  ( N1 => "ICE ROOM" N2 => "DANGER" N3 => "HOBGOBLIN")
  1022. NODE  ( N1 => "ICE ROOM" N2 => "SAFE" N3 => "DUBLOON")
  1023. NODE  ( N1 => "JABBERWOCK" N2 => "SAFE" N3 => "MEADOW")
  1024. NODE  ( N1 => "JABBERWOCK" N2 => "SAFE" N3 => "VERMIN")
  1025. NODE  ( N1 => "JABBERWOCK" N2 => "SAFE" N3 => "LAPIS LASULI")
  1026. NODE  ( N1 => "JABBERWOCK" N2 => "DANGER" N3 => "BANDIT")
  1027. NODE  ( N1 => "JABBERWOCK" N2 => "SAFE" N3 => "PEGASUS")
  1028. NODE  ( N1 => "JABBERWOCK" N2 => "DANGER" N3 => "ZOMBIE")
  1029. NODE  ( N1 => "KESTREL" N2 => "DANGER" N3 => "YENTI")
  1030. NODE  ( N1 => "KESTREL" N2 => "SAFE" N3 => "ANEMONIE")
  1031. NODE  ( N1 => "KESTREL" N2 => "DANGER" N3 => "QUAGGA")
  1032. NODE  ( N1 => "LAPIS LASULI" N2 => "SAFE" N3 => "VERMIN")
  1033. NODE  ( N1 => "LAPIS LASULI" N2 => "SAFE" N3 => "JABBERWOCK")
  1034. NODE  ( N1 => "LAPIS LASULI" N2 => "DANGER" N3 => "BANDIT")
  1035. NODE  ( N1 => "MEADOW" N2 => "DANGER" N3 => "HOBGOBLIN")
  1036. NODE  ( N1 => "MEADOW" N2 => "SAFE" N3 => "ANEMONIE")
  1037. NODE  ( N1 => "MEADOW" N2 => "SAFE" N3 => "JABBERWOCK")
  1038. NODE  ( N1 => "MEADOW" N2 => "SAFE" N3 => "NYMPH")
  1039. NODE  ( N1 => "MEADOW" N2 => "DANGER" N3 => "WRAITH")
  1040. NODE  ( N1 => "NYMPH" N2 => "SAFE" N3 => "MEADOW")
  1041. NODE  ( N1 => "NYMPH" N2 => "SAFE" N3 => "ELVES")
  1042. NODE  ( N1 => "NYMPH" N2 => "SAFE" N3 => "URCHIN")
  1043. NODE  ( N1 => "NYMPH" N2 => "DANGER" N3 => "XEROC")
  1044. NODE  ( N1 => "NYMPH" N2 => "SAFE" N3 => "FOUNTAIN")
  1045. NODE  ( N1 => "NYMPH" N2 => "SAFE" N3 => "RUBY")
  1046. NODE  ( N1 => "NYMPH" N2 => "SAFE" N3 => "URCHIN")
  1047. NODE  ( N1 => "OGRE" N2 => "SAFE" N3 => "SPRING")
  1048. NODE  ( N1 => "OGRE" N2 => "DANGER" N3 => "WRAITH")
  1049. NODE  ( N1 => "OGRE" N2 => "SAFE" N3 => "GROTTO")
  1050. NODE  ( N1 => "PEGASUS" N2 => "DANGER" N3 => "BANDIT")
  1051. NODE  ( N1 => "PEGASUS" N2 => "SAFE" N3 => "JABBERWOCK")
  1052. NODE  ( N1 => "PEGASUS" N2 => "DANGER" N3 => "ZOMBIE")
  1053. NODE  ( N1 => "QUAGGA" N2 => "SAFE" N3 => "KESTREL")
  1054. NODE  ( N1 => "QUAGGA" N2 => "SAFE" N3 => "ANEMONIE")
  1055. NODE  ( N1 => "QUAGGA" N2 => "SAFE" N3 => "VERMIN")
  1056. NODE  ( N1 => "RUBY" N2 => "SAFE" N3 => "GROTTO")
  1057. NODE  ( N1 => "RUBY" N2 => "SAFE" N3 => "NYMPH")
  1058. NODE  ( N1 => "RUBY" N2 => "SAFE" N3 => "FOUNTAIN")
  1059. NODE  ( N1 => "SPRING" N2 => "SAFE" N3 => "DUBLOON")
  1060. NODE  ( N1 => "SPRING" N2 => "DANGER" N3 => "WRAITH")
  1061. NODE  ( N1 => "SPRING" N2 => "SAFE" N3 => "OGRE")
  1062. NODE  ( N1 => "TREASURE" N2 => "SAFE" N3 => "CAVERN")
  1063. NODE  ( N1 => "TREASURE" N2 => "DANGER" N3 => "HOBGOBLIN")
  1064.  
  1065.  
  1066.  
  1067.  
  1068.  
  1069.  
  1070.  
  1071.  
  1072.  
  1073.                            - 62 -
  1074.  
  1075.  
  1076. NODE  ( N1 => "TREASURE" N2 => "DANGER" N3 => "YENTI")
  1077. NODE  ( N1 => "URCHIN" N2 => "SAFE" N3 => "ELVES")
  1078. NODE  ( N1 => "URCHIN" N2 => "SAFE" N3 => "NYMPH")
  1079. NODE  ( N1 => "URCHIN" N2 => "DANGER" N3 => "XEROC")
  1080. NODE  ( N1 => "VERMIN" N2 => "DANGER" N3 => "QUAGGA")
  1081. NODE  ( N1 => "VERMIN" N2 => "SAFE" N3 => "LAPIS LASULI")
  1082. NODE  ( N1 => "VERMIN" N2 => "SAFE" N3 => "JABBERWOCK")
  1083. NODE  ( N1 => "WRAITH" N2 => "SAFE" N3 => "MEADOW")
  1084. NODE  ( N1 => "WRAITH" N2 => "SAFE" N3 => "SPRING")
  1085. NODE  ( N1 => "WRAITH" N2 => "SAFE" N3 => "OGRE")
  1086. NODE  ( N1 => "WRAITH" N2 => "SAFE" N3 => "GROTTO")
  1087. NODE  ( N1 => "XEROC" N2 => "SAFE" N3 => "URCHIN")
  1088. NODE  ( N1 => "XEROC" N2 => "SAFE" N3 => "NYMPH")
  1089. NODE  ( N1 => "XEROC" N2 => "SAFE" N3 => "FOUNTAIN")
  1090. NODE  ( N1 => "YENTI" N2 => "SAFE" N3 => "KESTREL")
  1091. NODE  ( N1 => "YENTI" N2 => "SAFE" N3 => "ANEMONIE")
  1092. NODE  ( N1 => "YENTI" N2 => "SAFE" N3 => "TREASURE")
  1093. NODE  ( N1 => "ZOMBIE" N2 => "SAFE" N3 => "JABBERWOCK")
  1094. NODE  ( N1 => "ZOMBIE" N2 => "SAFE" N3 => "PEGASUS")
  1095. %%
  1096. BACKTRACK
  1097. DUMP
  1098. TRACE
  1099. PROFILE
  1100. SAVE
  1101. ZERO
  1102.  
  1103. R1:  /* See if we are at the end */
  1104.      (^START HERE)
  1105.      (END.E1 == HERE.S1)
  1106.      =>
  1107.      {
  1108.                printf("Found a path");
  1109.                remove_checkpoint();
  1110.                return;
  1111.      }
  1112.      ;
  1113.  
  1114. R2:  /* See if the next node that would be selected
  1115.         is already in the path.  If it is, remove it
  1116.         from consideration
  1117.      */
  1118.      (^START HERE)
  1119.      (^NODE  NEXT
  1120.        NODE.N2 != "DANGER"
  1121.        NODE.N1 == HERE.S1)
  1122.      (PATH.P1 == NEXT.N3)
  1123.      =>
  1124.      MARK NODE
  1125.      {
  1126.      }
  1127.      ;
  1128.  
  1129. R3:  /* Select the first non-dangerous node as the next node */
  1130.  
  1131.  
  1132.  
  1133.  
  1134.  
  1135.  
  1136.  
  1137.  
  1138.  
  1139.                            - 63 -
  1140.  
  1141.  
  1142.      (^START HERE)
  1143.      (^NODE  NEXT
  1144.        NODE.N2 != "DANGER"
  1145.        NODE.N1 == HERE.S1)
  1146.      =>
  1147.      MARK START NODE
  1148.      ADD START(S1 => NEXT.N3)
  1149.          PATH (P1 => NEXT.N3)
  1150.      {
  1151.      }
  1152.      ;
  1153.  
  1154. R4:  /* A dead end has been reached.  Undo the last path taken
  1155.         and mark it as dangerous in R5 */
  1156.      =>
  1157.      {
  1158.                /* undo this rule */
  1159.                backup();
  1160.                /* check if there was a previous rule */
  1161.                while(backtrack){
  1162.                    if(backtrack->next_rule == 5)
  1163.                     backtrack = backtrack->next;
  1164.                    else{
  1165.                        backup();   /* undo it */
  1166.                        goto R5;    /* and mark it as dangerous */
  1167.                    }
  1168.                }
  1169.                /* no solution */
  1170.                goto R6;
  1171.      }
  1172.      ;
  1173.  
  1174. R5:  /* Grab the first available path and call it dangerous */
  1175.  
  1176.      (^START HERE)
  1177.      (^NODE  NEXT
  1178.        NODE.N2 != "DANGER"
  1179.        NODE.N1 == HERE.S1)
  1180.      =>
  1181.      MARK NODE
  1182.      ADD  NODE (N1 => NEXT.N1
  1183.              N2 => "DANGER"
  1184.              N3 => NEXT.N3)
  1185.      {
  1186.                checkpoint();
  1187.      }
  1188.      ;
  1189.  
  1190. R6:  /* No solution */
  1191.      =>
  1192.      {
  1193.                printf("No Solution");
  1194.                remove_checkpoint();
  1195.                return;
  1196.  
  1197.  
  1198.  
  1199.  
  1200.  
  1201.  
  1202.  
  1203.  
  1204.  
  1205.                            - 64 -
  1206.  
  1207.  
  1208.      }
  1209.      ;
  1210. %%
  1211.  
  1212.  
  1213.  
  1214. MAIN.C
  1215.  
  1216. #include <ctype.h>
  1217. #include <sys/file.h>
  1218. #include <sys/time.h>
  1219. #include "X_loop.h"
  1220. extern char *rule_names[];
  1221.  
  1222. char *node_names[26] = {
  1223.     "ANEMONIE", "BANDIT", "CAVERN", "DUBLOON", "ELVES", "FOUNTAIN",
  1224.     "GROTTO", "HOBGOBLIN", "ICE ROOM", "JABBERWOCK", "KESTREL",
  1225.     "LAPIS LASULI", "MEADOW", "NYMPH", "OGRE", "PEGASUS", "QUAGGA",
  1226.     "RUBY", "SPRING", "TREASURE", "URCHIN", "VERMIN", "WRAITH",
  1227.     "XEROC", "YENTI", "ZOMBIE"
  1228. };
  1229.  
  1230. int danger[26] = {
  1231.     0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
  1232.     0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1
  1233. };
  1234.  
  1235. extern int X_fire_profile[], X_test_profile[];
  1236. char *start, *xit;
  1237.  
  1238. main(argc, argv)
  1239. int argc;
  1240. char *argv[];
  1241. {
  1242.     int  i, fire, test;
  1243.     char c[512];
  1244.     double d1, d2, d3;
  1245.     struct timeval tp, old_tp;
  1246.     struct timezone tzp;
  1247.  
  1248.     setbuf(stdout, NULL);
  1249.     if(argc > 1){
  1250.         if(re_do()){
  1251.             X_dump_PATH_struct();
  1252.             test = fire = 0;
  1253.             for(i = 0; i < 17; i++)
  1254.                 test += X_test_profile[i];
  1255.             for(i = 0; i < 7; i++)
  1256.                 fire += X_fire_profile[i];
  1257.             X_zero();
  1258.             printf("%d rules tested",test);
  1259.             printf("%d rules fired",fire);
  1260.         }
  1261.         printf("Continue [y or n] ");
  1262.  
  1263.  
  1264.  
  1265.  
  1266.  
  1267.  
  1268.  
  1269.  
  1270.  
  1271.                            - 65 -
  1272.  
  1273.  
  1274.         scanf("%s",c);
  1275.         if(isupper(c[0]))
  1276.             c[0] = tolower(c[0]);
  1277.         if(c[0] == 'n')
  1278.             exit(0);
  1279.     }
  1280.     while(1){
  1281.         start = xit = NULL;
  1282.         print_map();
  1283.         while(start == NULL){
  1284.             printf("Input start node ");
  1285.             scanf("%s",c);
  1286.             if(isupper(c[0]))
  1287.                 c[0]=tolower(c[0]);
  1288.             if(islower(c[0]))
  1289.                 start = node_names[c[0]-'a'];
  1290.         }
  1291.         while(xit == NULL){
  1292.             printf("Input exit node ");
  1293.             scanf("%s",c);
  1294.             if(isupper(c[0]))
  1295.                 c[0]=tolower(c[0]);
  1296.             if(islower(c[0]))
  1297.                 xit = node_names[c[0]-'a'];
  1298.         }
  1299.         printf("initializing");
  1300.         X_init();
  1301.         X_backtrack = (struct X_back_track_stack *)
  1302.      malloc(sizeof(struct X_back_track_stack));
  1303.         X_add_END_struct(xit);
  1304.         X_add_START_struct(start);
  1305.         X_add_PATH_struct(start);
  1306.         free(X_backtrack);
  1307.         X_backtrack = NULL;
  1308.         gettimeofday(&old_tp, &tzp);
  1309.         X_loop();
  1310.         gettimeofday(&tp, &tzp);
  1311.         X_dump_PATH_struct();
  1312.         d1 = old_tp.tv_sec;
  1313.         d2 = old_tp.tv_usec;
  1314.         d1 += d2/1000000;
  1315.         d2 = tp.tv_sec;
  1316.         d3 = tp.tv_usec;
  1317.         d2 += d3/1000000;
  1318.         d3 = d2 - d1;
  1319.         test = fire = 0;
  1320.         for(i = 0; i < 17; i++)
  1321.             test += X_test_profile[i];
  1322.         for(i = 0; i < 7; i++)
  1323.             fire += X_fire_profile[i];
  1324.         X_zero();
  1325.         d1 = test;
  1326.         d2 = fire;
  1327.         printf("Elapsed time =   %f seconds", d3);
  1328.  
  1329.  
  1330.  
  1331.  
  1332.  
  1333.  
  1334.  
  1335.  
  1336.  
  1337.                            - 66 -
  1338.  
  1339.  
  1340.         printf("%d rules tested (%f rules/sec)",test, d1/d3);
  1341.         printf("%d rules fired  (%f rules/sec)",fire, d2/d3);
  1342.         printf("Continue [y or n] ");
  1343.         scanf("%s",c);
  1344.         if(isupper(c[0]))
  1345.             c[0] = tolower(c[0]);
  1346.         if(c[0] == 'n')
  1347.             exit(0);
  1348.     }
  1349. }
  1350.  
  1351. print_map()
  1352. {
  1353.    printf(" NODE NAMES  (* DANGEROUS NODES)               C - I ");
  1354.    printf(" -------------------------------              / \\ / \\ ");
  1355.    printf(" ANEMONIE            NYMPH                   T - H - D ");
  1356.    printf(" BANDIT*             OGRE                   /    |    \\ ");
  1357.    printf(" CAVERN              PEGASUS               Y     |     S ");
  1358.    printf(" DUBLOON             QUAGGA*             / |     |     | \\ ");
  1359.    printf(" ELVES               RUBY              K - A --- M --- W - O ");
  1360.    printf(" FOUNTAIN            SPRING             \\ /     / \\     \\ / ");
  1361.    printf(" GROTTO              TREASURE            Q     /   \\     G ");
  1362.    printf(" HOBGOBLIN*          URCHIN              |    /     \\    | ");
  1363.    printf(" ICE ROOM            VERMIN              V   /       \\   R ");
  1364.    printf(" JABBERWOCK          WRAITH*            / \\ /         \\ / \\ ");
  1365.    printf(" KESTREL             XEROC*            L - J - Z   E - N - F ");
  1366.    printf(" LAPIS LASULI        YENTI*             \\ / \\ /     \\ / \\ / ");
  1367.    printf(" MEADOW              ZOMBIE*             B - P       U - X ");
  1368. }
  1369.  
  1370. int state = 0;
  1371. char *lock = "lock.0";
  1372. char *stm = "stm.0";
  1373. char *back = "back.0";
  1374. char *pro = "pro.0";
  1375. char *trace = "trace.0";
  1376.  
  1377. checkpoint()
  1378. /* save a snapshot of stm, back_track_stack, etc. */
  1379. {
  1380.     FILE *fp;
  1381.  
  1382.     lock[5] = '0' + state;
  1383.     stm[4] = '0' + state;
  1384.     back[5] = '0' + state;
  1385.     pro[4] = '0' + state;
  1386.     trace[6] = '0' + state;
  1387.     if(state)
  1388.         state = 0;
  1389.     else
  1390.         state = 1;
  1391.     unlink(lock);
  1392.     fp = fopen(stm, "w");
  1393.     X_save_stm(fp);
  1394.  
  1395.  
  1396.  
  1397.  
  1398.  
  1399.  
  1400.  
  1401.  
  1402.  
  1403.                            - 67 -
  1404.  
  1405.  
  1406.     fclose(fp);
  1407.     fp = fopen(back, "w");
  1408.     X_save_backtrack(fp);
  1409.     fclose(fp);
  1410.     fp = fopen(pro, "w");
  1411.     X_save_profile(fp);
  1412.     fclose(fp);
  1413.     fp = fopen(trace, "w");
  1414.     X_save_trace(fp);
  1415.     fclose(fp);
  1416.     fp = fopen(lock, "w");
  1417.     fprintf(fp,"good");
  1418.     fclose(fp);
  1419. }
  1420.  
  1421. remove_checkpoint()
  1422. /* remove all old snapshots */
  1423. {
  1424.     unlink(lock);
  1425.     unlink(stm);
  1426.     unlink(back);
  1427.     unlink(pro);
  1428.     unlink(trace);
  1429.     lock[5] = '0' + state;
  1430.     stm[4] = '0' + state;
  1431.     back[5] = '0' + state;
  1432.     pro[4] = '0' + state;
  1433.     trace[6] = '0' + state;
  1434.     unlink(lock);
  1435.     unlink(stm);
  1436.     unlink(back);
  1437.     unlink(pro);
  1438.     unlink(trace);
  1439. }
  1440.  
  1441. re_do()
  1442. /* restore from a snapshot and continue execution */
  1443. {
  1444.     char c[512];
  1445.     FILE *fp;
  1446.  
  1447.     if((fp = fopen(lock, "r")) != NULL)
  1448.         fscanf(fp,"%s", c);
  1449.     if(strncmp(c, "good", 4)){
  1450.         if(fp)
  1451.             fclose(fp);
  1452.         if(state)
  1453.             state = 0;
  1454.         else
  1455.             state = 1;
  1456.         lock[5] = '0' + state;
  1457.         stm[4] = '0' + state;
  1458.         back[5] = '0' + state;
  1459.         pro[4] = '0' + state;
  1460.  
  1461.  
  1462.  
  1463.  
  1464.  
  1465.  
  1466.  
  1467.  
  1468.  
  1469.                            - 68 -
  1470.  
  1471.  
  1472.         trace[6] = '0' + state;
  1473.         if((fp = fopen(lock, "r")) != NULL)
  1474.             fscanf(fp,"%s", c);
  1475.         if(strncmp(c, "good", 4)){
  1476.             remove_checkpoint();
  1477.             printf("No checkpoint files");
  1478.             return(0);
  1479.         }
  1480.     }
  1481.     fclose(fp);
  1482.     fp = fopen(stm, "r");
  1483.     X_load_stm(fp);
  1484.     fclose(fp);
  1485.     fp = fopen(back, "r");
  1486.     X_load_backtrack(fp);
  1487.     fclose(fp);
  1488.     fp = fopen(pro, "r");
  1489.     X_load_profile(fp);
  1490.     fclose(fp);
  1491.     fp = fopen(trace, "r");
  1492.     X_load_trace(fp);
  1493.     fclose(fp);
  1494.     X_loop();
  1495.     return(1);
  1496. }
  1497.  
  1498.  
  1499.  
  1500.  
  1501.  
  1502.  
  1503.  
  1504.  
  1505.  
  1506.  
  1507.  
  1508.  
  1509.  
  1510.  
  1511.  
  1512.  
  1513.  
  1514.  
  1515.  
  1516.  
  1517.  
  1518.  
  1519.  
  1520.  
  1521.  
  1522.  
  1523.  
  1524.  
  1525.  
  1526.  
  1527.  
  1528.  
  1529.  
  1530.  
  1531.  
  1532.