[comp.ai] AI expert sources

turner@imagen.UUCP (D'arc Angel) (01/19/87)

here it is and rather lengthly, cat all nine parts together and shar
it, don't forget to remove my .signature at the end of each file.

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	AIAPP.JAN
#	CONTNT.JAN
#	EXPERT.JAN
#	FILES.JAN
#	OPSNET.JAN
#	PERCEP.JAN
# This archive created: Sun Jan 18 19:24:39 1987
# By:	D'arc Angel (The Houses of the Holy)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'AIAPP.JAN'" '(29884 characters)'
if test -f 'AIAPP.JAN'
then
	echo shar: "will not over-write existing file 'AIAPP.JAN'"
else
sed 's/^	X//' << \SHAR_EOF > 'AIAPP.JAN'
	X
	X
	X                          AI Apprentice
	X                by Bill Thompson and Bev Thompson
	X             "Creating Expert Systems from Examples"
	X                     January 1987 AI EXPERT
	X
	X
	X
	XFigure 1.
	X
	X        batch#      part#       power       symptom      Problem
	X
	X        b           312         ac          no power     powersupply
	X        a           312         ac          weak         gear bad
	X        c           412         dc          sparking     powersupply
	X        d           412         ac          no power     wiring
	X        c           212         dc          sparking     powersupply
	X        c           412         ac          weak         wiring
	X        a           212         ac          no power     gear bad
	X        b           412         dc          weak         wiring
	X        b           212         ac          weak         gear bad
	X
	X
	X
	XFigure 2 - A decision tree produced from the data in Table 1.
	X
	X
	X        batch#      part#       power       symptom     Result
	X
	X        b           412         ac          weak         gear bad
	X        a           212         dc          weak         powersupply
	X        d           212         dc          sparking     wiring
	X        d           412         ac          no power     powersupply
	X
	X
	X
	XTable 1 - A training set of data for a repair problem.
	X
	X	If batch# is a
	X        then result is gear bad.
	X
	X        If batch# is b
	X        and part# is 212
	X        then result is gear bad.
	X
	X        If batch# is b
	X        and part# is 312
	X        then result is powersupply.
	X
	X        If batch# is b
	X        and part# is 412
	X        then result is wiring.
	X
	X        If batch# is c
        and power is ac
	X        then result is wiring.
	X
	X        If batch# is c
	X        and power is dc
	X        then result is powersupply.
	X
	X        If batch# is d
	X        then result is wiring.
	X
	X
	X batch# ?
	X  a:  ---------------------------------------------gear bad
	X  b:part# ?
	X     212: ---------------------------------------- gear bad
	X     312: ---------------------------------------- powersupply
	X     412: ---------------------------------------- wiring
	X  c:power??
	X     ac: ----------------------------------------- wiring
	X     dc: ----------------------------------------- powersupply
	X  d: --------------------------------------------- wiring
	X
	X
	X
	XTable 2 - A new set of data collected for the repair problem.  This data
	X          is used for validation of the solution.
	X
	X
	Xclinical    descript      distribution  group         Result
	X
	Xfever       upper resp.   epidemic      respiratory   parainfluenza
	Xchills      lower resp.   local         enteric       adenovirus
	Xrash        mid resp.     children      exanthems     mumps
	Xswelling                  hospital      latent        rhinovirus
	Xmalaise                   youngadults                 echo
	Xheadache                  universal                   coxasackie
	Xcough                                                 varicella
	X
	X
	X                                                      rubella
	X
	XTable 3 - Definitions of results and attributes for identifying viruses.
	X
	Xlevel      type of  subject  programming  cover type  basic      Author
	X           software matter      covered               language
	Xintro/adv  gen/spec gen/spec    no/yes    soft/hard   no/yes
	X1.         1.          4.          3.        soft     5.       Jones
	X2.         5.          5.          4.        soft     1.       Smith
	X1.         1.          1.          3.        soft     1.       Fisher
	X1.         1.          1.          3.        hard     5.       Mitchell
	X1.         1.          1.          1.        soft     1.       Argyle
	X5.         1.          5.          5.        hard     1.       Chang
	X
	X
	X
Table 4 - An example set for selecting a textbook.  This set was produced
	X          using the Flexigrid program.
	X
	Xsubject matter ?  (gen/spec)
	X < 2.50: programming covered ? (no/yes)
	X        < 2.00: ---------------------------------- Concepts
	X        >=2.00: cover ?
	X                  hard: -------------------------- Today's
	X                  soft: -------------------------- Information
	X  >=2.50: level ? (intro/adv)
	X          < 1.50: -------------------------------- Society
	X          >=1.50: level ? (intro/adv)
	X                  < 3.50: ------------------------ Applications
	X                  >=3.50: ------------------------ Data_structures
	X
	X
	Xupply of serotinous cones
	X.
	X
	Xprompt 10/acre adequate
	XAre 10 trees per acre adequate to seed the area ?
	X.
	X
	Xtrans 10/acre adequate
	X10 per acre is /not/ adequate
	X.
	X
	Xprompt burning planned
	XHas a prescribed burning been planned ?
	X.
	X
	Xtrans burning planned
	Xburning is /not/ planned
	X.
	X
	Xtrans use seed tree
	XYou should /not/ use seed trees to seed the area
	X.
	X
15
	Xif branch 11 is yes
	Xand pine desired is yes
	Xand pine suited is yes
	Xand desirable seed is yes
	Xand serotinous cones is yes
	Xand 10/acre adequate is yes
	Xand burning planned is no
	Xthen silviculture method is clearcut
	Xand branch 17 is yes .
	X
	Xtrans silvaculture method
	Xthe best silviculture method to use
	X.
	X
	X16
	Xif branch 11 is yes
	Xand pine desired is yes
	Xand pine suited is yes
	Xand desirable seed is yes
	Xand serotinous cones is yes
	Xand 10/acre adequate is no
	Xthen silviculture method is clearcut
	Xand branch 17 is yes .
	X
	X17
	Xif branch 11 is yes
	Xand pine desired is yes
	Xand pine suited is yes
	Xand desirable seed is yes
	Xand serotinous cones is no
	Xand two harvests wanted is yes
	Xand two harvests possible is yes
	Xthen silviculture method is shelterwood
	Xand branch 17 is yes .
	X
	Xprompt two harvests wanted
	XDo you want to do two commercial harvests on this area ?
	X.
	X
	Xtrans two harvests wanted
	Xtwo commercial harvests are /not/ wanted
	X.
	X
	Xprompt two harvests possible
	XIs it possible to get two harvests from this area ?
	X.
	X
	Xtrans two harvests possible
	Xtwo harvests can /not/ be done on this area
	X.
	X
	X18
	Xif branch 11 is yes
	Xand pine desired is yes
	Xand pine suited is yes
	Xand desirable seed is yes
	Xand serotinous cones is no
	Xand two harvests wanted is yes
	Xand two harvests possible is no
then silviculture method is clearcut
	Xand branch 17 is yes .
	X
	X19
	Xif branch 11 is yes
	Xand pine desired is yes
	Xand pine suited is yes
	Xand desirable seed is yes
	Xand serotinous cones is no
	Xand two harvests wanted is no
	Xthen silviculture method is clearcut
	Xand branch 17 is yes .
	X
	X20
	Xif branch 11 is yes
	Xand pine desired is yes
	Xand pine suited is yes
	Xand desirable seed is no
	Xthen silviculture method is clearcut
	Xand branch 17 is yes .
	X
	X21
	Xif branch 11 is yes
	Xand pine desired is yes
	Xand pine suited is no
	Xthen convert is yes
	Xand recommend is convert .
	X
	Xtrans convert
	Xyou should /not/ convert the area to some more desirable kind of tree
	X.
	X
	X22
	Xif branch 11 is yes
	Xand pine desired is no
	Xthen convert is yes
	Xand recommend is convert .
	X
	X
	X26
	Xif branch 17 is yes
	Xand adequate seedbed is yes
	Xthen branch 18 is yes .
	X
	Xprompt adequate seedbed
	XIs there an adequate seedbed for planting ?
	X.
	X
	Xtrans adequate seedbed
	Xthere is /not/ an adequate seedbed for planting
	X.
	X
	X27
	Xif branch 17 is yes
	Xand adequate seedbed is no
	Xthen prepare site is yes
	Xand branch 18 is yes .
	X
trans prepare site
	Xthe site should /not/ be prepared before planting
	X.
	X
	X28
	Xif branch 18 is yes
	Xand silviculture method is shelterwood
	Xthen use natural seeding is yes
	Xand recommend is use natural seeding .
	X
	Xtrans use natural seeding
	Xnatural seeding techniques should /not/ be used
	X.
	X
	X29
	Xif branch 18 is yes
	Xand silviculture method is clearcut
	Xand improved stock is yes
	Xthen plant is yes
	Xand recommend is plant .
	X
	Xprompt improved stock
	XIs there improved planting stock available ?
	X.
	X
	Xtrans improved stock
	Xthere is /not/ improved stock available
	X.
	X
	Xtrans plant
	Xsince there is better stock available you can /not/ plant using that stock
	X.
	X
	X30
	Xif branch 18 is yes
	Xand silviculture method is clearcut
	Xand improved stock is no
	Xand good cone supply is yes
	Xthen scatter cones is yes
	Xand recommend is scatter cones .
	X
	Xprompt good cone supply
	XIs there a good supply of serotinous cones on the area ?
	X.
	X
	Xtrans good cone supply
	Xthere is /not/ a good cone supply
	X.
	X
	Xtrans scatter cones
	Xyou should /not/ scatter the supply of serotinous cones over the area
	X.
	X
	X31
	Xif branch 18 is yes
	Xand silviculture method is clearcut
	Xand improved stock is no
	Xand good cone supply is no
	Xthen direct seed is yes
	Xand recommend is direct seed .
	X
	Xtrans direct seed
	XSince the cone supply is inadequate, you should /not/ directly seed the
area
	X.
	X
	X
	X-------------------------------------------------------------------------
	X
	XThe following comments are not a part of the knowledge base.  If you
	Xtry to run the knowledge base this part of the file should be removed
	X
	X
	XAbbreviated KEY
	X
	X1.  stocking good is yes ............................. 2
	X1.  stocking good is no  ............................. 10
	X    2. avg < 5 is yes ................................ 3
	X    2. avg < 5 is no ................................. 4
	X3.  2000 + per acre is yes ..........WEED OR CLEAN.... 8
	X3.  2000 + per acre is no ............................ 8
	X    4. age is mature ................................. 11
	X    4. age is immature ............................... 5
	X5.  site index > 60 is yes ........................... 6
	X5.  site index > 60 is no ............................ 9
	X    6. product size is large ......................... 7
	X    6. product size is small ......................... 9
	X7.  120 + basal area is yes .........THIN............. 9
	X7.  120 + basal area is no ........................... 9
	X    8. severe competition is yes ....RELEASE.......... 9
	X    8. severe competition is no ...................... 9
	X9.  high risk is yes ................................. CONTROL IF FEASIBLE
	X9.  high risk is no .................................. WAIT
	X    10. other resources is yes ....................... MAINTAIN
	X    10. other resources is no ........................ 11
	X11. pine suitable is yes ............................. 12
	X11. pine suitable is no .............................. CONVERT
	X    12. desirable seed is yes ........................ 13
	X    12. desirable seed is no ........USE CLEARCUT..... 17
	X13. serotinous cones is yes .......................... 14
	X13. serotinous cones is no ........................... 16
	X    14. 10/acre adequate is yes ...................... 15
	X    14. 10/acre adequate is no ......USE CLEARCUT..... 17
	X15. burning planned is yes ........................... USE SEED TREE
	X15. burning planned is no ...........USE CLEARCUT..... 17
	X    16. two harvests wanted is yes ..USE SHELTERWOOD.. 17
	X    16. two harvests wanted is no ...USE CLEARCUT..... 17
	X17. adequate seedbeds is yes ......................... 18
	X17. adequate seedbeds is no .........PREPARE SITE..... 18
	X    18. silviculture method is shelterwood ........... USE NATURAL SEEDING
	X    18. silviculture method is clearcut .............. 19
	X19. improved stock is yes ............................ PLANT
	X19. improved stock is no ............................. 20
	X    20. good cone supply is yes ...................... SCATTER CONES
	X    20. good cone supply is no ....................... DIRECT SEED
	X
	X
	X
	XThe purpose of this exercise is to show how a knowledge base can be
designed to directly follow a key.  There are several places where the
	XKB could have been made more efficient, but this would have meant
	Xdeparting from the order of the key.  You might find it an interesting
	Xexercise to explore other ways this same information could have been
	Xrepresented in the KB.
	X
	XThe key appears in the Managers Handbood for Jack Pine in the North Central
	XStates.  The Handbook was produced by the North Central Forest Experiment
	XStation of the Forest Service of the U.S. Dept. of Agriculture.  Our
	Xintention in writing this knowledge base is to show the structure of a
	Xknowledge base written for a backward chaining inference engine directly
	Xfrom an existing document.  If this KB were to be actually used, it would
	Xneed to have clearer questions and more explanations to the user.  These
	Xexplanations are provided in the handbook and could be easily incorporated
	Xinto the knowledge base.
	X
	XThe knowledge base will run on the expert system shell MicroExpert which is
	Xan example of a backward chaining inference engine. MicroExpert is
	Xavailable from McGraw-Hill for $49.95 and can be ordered by calling 1-800-
	X628-0004 or, in NY, 212-512-2999 . The knowledge base is described in the
	Xcolumn AI Apprentice which appears in the November issue of AI Expert
	Xmagazine.  The design details of the inference engine which runs the KB is
	Xdescribed in the article "Inside an Expert System" in the April 1985
	Xisuue of BYTE magazine.
	X
	XMicroExpert, AI Apprentice and "Inside an Expert System" are all written
	Xby Bev and Bill Thompson . We're always happy to hear about your thoughts
	Xand comments, good or bad on any of our work.  Contact us at the address
	Xbelow, on Compuserve or BIX. Our Compuserve id is 76703,4324 and we can be
	Xreached by Easyplex or in the AI Expert Forum.  Our BIX id is bbt and  we
	Xmay  be  contacted via BIXmail or by leaving comments in the  MicroExpert
	Xconference.
	X
	XBill and Bev Thompson
	XR.D. 2 Box 430
	XNassau, N.Y.  12123
	X
	X
	X                            TREES.PRO
	X                         PROLOG program 
	X
	X
	X/* This PDPROLOG program implements a knowledge base based upon the
	X   following key:
	X
	X   To run the program type "go."
	X   Caution - This program can be very S L O W.
	X
	XAbbreviated KEY
	X
	X1.  stocking good is yes ............................. 2
	X1.  stocking good is no  ............................. 10
	X    2. avg < 5 is yes ................................ 3
	X    2. avg < 5 is no ................................. 4
	X3.  2000 + per acre is yes ..........WEED OR CLEAN.... 8
3.  2000 + per acre is no ............................ 8
	X    4. age is mature ................................. 11
	X    4. age is immature ............................... 5
	X5.  site index > 60 is yes ........................... 6
	X5.  site index > 60 is no ............................ 9
	X    6. product size is large ......................... 7
	X    6. product size is small ......................... 9
	X7.  120 + basal area is yes .........THIN............. 9
	X7.  120 + basal area is no ........................... 9
	X    8. severe competition is yes ....RELEASE.......... 9
	X    8. severe competition is no ...................... 9
	X9.  high risk is yes ................................. CONTROL IF FEASIBLE
	X9.  high risk is no .................................. WAIT
	X    10. other resources is yes ....................... MAINTAIN
	X    10. other resources is no ........................ 11
	X11. pine suitable is yes ............................. 12
	X11. pine suitable is no .............................. CONVERT
	X    12. desirable seed is yes ........................ 13
	X    12. desirable seed is no ........USE CLEARCUT..... 17
	X13. serotinous cones is yes .......................... 14
	X13. serotinous cones is no ........................... 16
	X    14. 10/acre adequate is yes ...................... 15
	X    14. 10/acre adequate is no ......USE CLEARCUT..... 17
	X15. burning planned is yes ........................... USE SEED TREE
	X15. burning planned is no ...........USE CLEARCUT..... 17
	X    16. two harvests wanted is yes ..USE SHELTERWOOD.. 17
	X    16. two harvests wanted is no ...USE CLEARCUT..... 17
	X17. adequate seedbeds is yes ......................... 18
	X17. adequate seedbeds is no .........PREPARE SITE..... 18
	X    18. silviculture method is shelterwood ........... USE NATURAL SEEDING
	X    18. silviculture method is clearcut .............. 19
	X19. improved stock is yes ............................ PLANT
	X19. improved stock is no ............................. 20
	X    20. good cone supply is yes ...................... SCATTER CONES
	X    20. good cone supply is no ....................... DIRECT SEED
	X
	X
	X
	XThe purpose of this exercise is to show how an expert system can be
	Xdesigned to directly follow a key.  There are several places where the
	Xprogram could have been made more efficient, but this would have meant
	Xdeparting from the order of the key.  You might find it an interesting
	Xexercise to explore other ways this same information could have been
	Xrepresented in the program.
	X
	XThe key appears in the Managers Handbood for Jack Pine in the North Central
	XStates.  The Handbook was produced by the North Central Forest Experiment
	XStation of the Forest Service of the U.S. Dept. of Agriculture.  Our
	Xintention in writing this knowledge base is to show the structure of a
	Xknowledge base written for a backward chaining inference engine directly
	Xfrom an existing document.  If this KB were to be actually used, it would
	Xneed to have clearer questions and more explanations to the user.  These
	Xexplanations are provided in the handbook and could be easily incorporated
	Xinto the knowledge base.
	X
This program is similar to the KB for the expert system shell
	XMicroExpert which is an example of a backward chaining inference engine.
	XMicroExpert is available from McGraw-Hill for $49.95 and can be ordered
	Xby calling 1-800-628-0004 or, in NY, 212-512-2999 .
	XThe knowledge base is described in the AI Apprentice column which appears
	Xin the November issue of AI Expert magazine.
	XThe design details of the inference engine which runs the KB is
	Xdescribed in the article "Inside an Expert System" in the April 1985
	Xisuue of BYTE magazine.
	X
	XMicroExpert, AI Apprentice and "Inside an Expert System" are all written
	Xby Bev and Bill Thompson . We're always happy to hear about your thoughts
	Xand comments, good or bad on any of our work.  Contact us at the address
	Xbelow, on Compuserve or BIX. Our Compuserve id is 76703,4324 and we can be
	Xreached by Easyplex or in the AI Expert Forum.  Our BIX id is bbt and  we
	Xmay  be  contacted via BIXmail or by leaving comments in the  MicroExpert
	Xconference.
	X
	XBill and Bev Thompson
	XR.D. 2 Box 430
	XNassau, N.Y.  12123      */
	X
	X/* Control - In MicroExpert terms, the goal of the consultation is
	X   recommendation */
	X
	Xgo :- clear_kb,
	X      give_advice.
	Xgive_advice :- recommendation(X),
	X               fail.
	Xgive_advice :- print_advice.
	X
	X/* The rules -
	X   These are implemented this way to mimic the MicroExpert rule set.
	X   Looking at them side by side should show the similarities. */
	X
	Xfact(branch8,yes) :- fact('stocking good',yes),
	X                     fact('avg < 5',yes),
	X                     fact('2000+ per acre',yes),
	X                     recommend('The stand of jack pine must be weeded and cleaned.').
	Xfact(branch8,yes) :- fact('stocking good',yes),
	X                     fact('avg < 5',yes),
	X                     fact('2000+ per acre',no).
	Xfact(branch9,no) :- fact('stocking good',yes),
	X                    fact('avg < 5',no),
	X                    fact(age,mature),
	X                    assertz(fact(branch11,yes)).
	Xfact(branch11,yes) :- fact('stocking good',yes),
	X                      fact('avg < 5',no),
	X                      fact(age,mature),
	X                      assertz(fact(branch9,no)).
	Xfact(branch9,yes) :- fact('stocking good',yes),
	X                     fact('avg < 5',no),
	X                     fact(age,immature),
	X                     fact('site index > 60',yes),
	X                     fact('product size',large),
                     fact('120+ basal area',yes),
	X                     recommend('It is important to thin the area').
	Xfact(branch9,yes) :- fact('stocking good',yes),
	X                     fact('avg < 5',no),
	X                     fact(age,immature),
	X                     fact('site index > 60',yes),
	X                     fact('product size',large),
	X                     fact('120+ basal area',no).
	Xfact(branch9,yes) :- fact('stocking good',yes),
	X                     fact('avg < 5',no),
	X                     fact(age,immature),
	X                     fact('site index > 60',yes),
	X                     fact('product size',large).
	Xfact(branch9,yes) :- fact('stocking good',yes),
	X                     fact('avg < 5',no),
	X                     fact(age,immature),
	X                     fact('site index > 60',yes).
	Xrecommendation(maintain) :-
	X       fact('stocking good',no),
	X       fact('other resources',yes),
	X       recommend('You should maintain the stand in its present condition').
	Xfact(branch11,yes) :- fact('stocking good',no),
	X                      fact('other resources',no).
	Xfact(branch9,yes) :- fact(branch8,yes),
	X                     fact('severe competition',yes),
	X                     recommend('Competing trees should be eliminated.').
	Xfact(branch9,yes) :- fact(branch8,yes),
	X                     fact('severe competition',no).
	Xrecommendation(control) :-
	X        fact(branch9,yes),
	X        fact('high risk',yes),
	X        recommend('The current area should be controlled, if at all feasible.').
	Xrecommendation(wait) :-
	X        fact(branch9,yes),
	X        fact('high risk',no),
	X        recommend('You should wait before doing anything else to this stand.').
	Xrecommendation('use seed tree') :-
	X        fact(branch11,yes),
	X        fact('pine desired',yes),
	X        fact('pine suited',yes),
	X        fact('desirable seed',yes),
	X        fact('serotinous cones',yes),
	X        fact('10/acres adequate',yes),
	X        fact('burning planned',yes),
	X        recommend('You should use seed trees to seed the area.').
	Xfact(branch17,yes) :-
	X            fact(branch11,yes),
	X            fact('pine desired',yes),
	X            fact('pine suited',yes),
	X            fact('desirable seed',yes),
	X            fact('serotinous cones',yes),
	X            fact('10/acres adequate',yes),
	X            fact('burning planned',no),
	X            add_fact(silvaculture,clearcut),
	X            recommend('The best silvaculture method to use is clearcut.').
fact(branch17,yes) :-
	X        fact(branch11,yes),
	X        fact('pine desired',yes),
	X        fact('pine suited',yes),
	X        fact('desirable seed',yes),
	X        fact('serotinous cones',yes),
	X        fact('10/acres adequate',no),
	X        add_fact(silvaculture,clearcut),
	X        recommend('The best silvaculture method to use is clearcut.').
	Xfact(branch17,yes) :-
	X        fact(branch11,yes),
	X        fact('pine desired',yes),
	X        fact('pine suited',yes),
	X        fact('desirable seed',yes),
	X        fact('serotinous cones',no),
	X        fact('two harvests wanted',yes),
	X        fact('two harvests possible',yes),
	X        add_fact(silvaculture,shelterwood),
	X        recommend('The best silvaculture method to use is the shlterwood method.').
	Xfact(branch17,yes) :-
	X        fact(branch11,yes),
	X        fact('pine desired',yes),
	X        fact('pine suited',yes),
	X        fact('desirable seed',yes),
	X        fact('serotinous cones',no),
	X        fact('two harvests wanted',yes),
	X        fact('two harvests possible',no),
	X        add_fact(silvaculture,clearcut),
	X        recommend('The best silvaculture method to use is clearcut.').
	Xfact(branch17,yes) :-
	X        fact(branch11,yes),
	X        fact('pine desired',yes),
	X        fact('pine suited',yes),
	X        fact('desirable seed',yes),
	X        fact('serotinous cones',no),
	X        fact('two harvests wanted',no),
	X        add_fact(silvaculture,clearcut),
	X        recommend('The best silvaculture method to use is clearcut.').
	Xfact(branch17,yes) :-
	X        fact(branch11,yes),
	X        fact('pine desired',yes),
	X        fact('pine suited',yes),
	X        fact('desirable seed',no),
	X        add_fact(silvaculture,clearcut),
	X        recommend('The best silvaculture method to use is clearcut.').
	Xrecommendation(convert) :-
	X        fact(branch11,yes),
	X        fact('pine desired',yes),
	X        fact('pine suited',no),
	X        recommend('You should convert the area to some more desirable kind of tree.').
	Xrecommendation(convert) :-
	X        fact(branch11,yes),
	X        fact('pine desired',no),
	X        recommend('You should convert the area to some more desirable kind of tree.').
	Xfact(branch18,yes) :-
        fact(branch17,yes),
	X        fact('adequate seedbed',yes).
	Xfact(branch18,yes) :-
	X        fact(branch17,yes),
	X        fact('adequate seedbed',no),
	X        recommend('The site should be prepared before planting.').
	Xrecommendation('natural seeding') :-
	X        fact(branch18,yes),
	X        fact(silvaculture,shelterwood),
	X        recommend('The natural seeding technique should be used.').
	Xrecommendation(plant) :-
	X        fact(branch18,yes),
	X        fact(silvaculture,clearcut),
	X        fact('improved stock',yes),
	X        recommend('Since there is better stock available, you can plant using that stock.').
	Xrecommendation('scatter cones') :-
	X        fact(branch18,yes),
	X        fact(silvaculture,clearcut),
	X        fact('improved stock',no),
	X        fact('good cone supply',yes),
	X        recommend('You should scatter the serotinous cones over the area.').
	Xrecommendation('direct seed') :-
	X        fact(branch18,yes),
	X        fact(silvaculture,clearcut),
	X        fact('improved stock',no),
	X        fact('good cone supply',no),
	X        recommend('You should directly seed the area.').
	X
	X/* These routines add new facts to the internal knowledge base - kb */
	X
	Xfact(X,Y) :- kb(X,Y),! .
	Xfact(X,Y) :- not(kb(X,Anything)),
	X             question(X,Answer),
	X             assertz(kb(X,Answer)),
	X             Y = Answer.
	X
	Xadd_fact(X,Y) :- kb(X,Y),!.
	Xadd_fact(X,Y) :- assertz(kb(X,Y)).
	X
	Xrecommend(X) :- add_fact(advice,X).
	X
	X/* Questions to ask the user */
	X
	Xquestion('stocking good',Ans) :-
	X        print('Is the stocking of the jack pine stand currently'),nl,
	X        print('at least minimum ? '),nl,nl,
	X        print('If you are unsure of how to determine stocking,'),nl,
	X        print('see page 4 in the Managers Handbook for Jack Pine'),
	X        nl,
	X        ask('',Ans,[ yes , no ]).
	Xquestion('avg < 5',Ans) :-
	X        ask('Is the average diameter of the trees less than 5 inches ?',
	X             Ans,[yes,no]).
	Xquestion('2000+ per acre',Ans) :-
	X        ask('Are there 2000 or more trees per acre ?',Ans,[yes,no]).
question(age,Ans) :-
	X        ask('Is the age of the stand mature or immature ?',
	X             Ans,[mature,immature]).
	Xquestion('site index > 60',Ans) :-
	X        ask('Is the site index greater than 60 ?',Ans,[yes,no]).
	Xquestion('product size',Ans) :-
	X        ask('Do you want to manage the timber for large or small products ?',
	X            Ans,[large,small]).
	Xquestion('120+ basal area',Ans) :-
	X        ask('Is the basal area per acre at least 120 square feet ?',
	X            Ans,[yes,no]).
	Xquestion('other resources',Ans) :-
	X        ask('Do you want to maintain this condition to support other resources?',
	X             Ans,[yes,no]).
	Xquestion('severe competition',Ans) :-
	X        ask('Is there severe overstory competition ?',Ans,[yes,no]).
	Xquestion('high risk',Ans) :-
	X        ask('Is there a high risk of loss or injury ?',Ans,[yes,no]).
	Xquestion('pine desired',Ans) :-
	X        ask('Do you want to keep jack pine in this area ?',Ans,[yes,no]).
	Xquestion('pine suited',Ans) :-
	X        ask('Is jack pine well suited to this site ?',Ans,[yes,no]).
	Xquestion('desirable seed',Ans) :-
	X        ask('Is there a desirable jack pine seed source on the area ?',
	X             Ans,[yes,no]).
	Xquestion('serotinous cones',Ans) :-
	X        ask('Do the trees on the site have serotinous cones ?',Ans,[yes,no]).
	Xquestion('10/acres adequate',Ans) :-
	X        ask('Are 10 trees per acre adequate to seed the area ?',Ans,[yes,no]).
	Xquestion('burning planned',Ans) :-
	X        ask('Has a prescribed burning been planned ?',Ans,[yes,no]).
	Xquestion('two harvests wanted',Ans) :-
	X        ask('Do you want two commercial harvests on this area ?',Ans,[yes,no]).
	Xquestion('two harvests possible',Ans) :-
	X        ask('Is it possible to get two harvests from this area ?',Ans,[yes,no]).
	Xquestion('adequate seedbed',Ans) :-
	X        ask('Is there an adequate seedbed for planting ?',Ans,[yes,no]).
	Xquestion('improved stock',Ans) :-
	X        ask('Is there an improved planting stock available ?',Ans,[yes,no]).
	Xquestion('good cone supply',Ans) :-
	X        ask('Is there a good supply of serotinous cones in the area ?',
	X             Ans,[yes,no]).
	X
	X/* Utility Routines - to be useful, we should add some routines to allow
	X                       the user to ask "How" and "Why" */
	X
	Xdisplay_kb :- kb(X,Y),
	X              print(X,' is ',Y),
	X              nl,
	X              fail.
	Xdisplay_kb.
	X
	X
	Xprint_advice :-
	X    nl,nl,
    print('Based upon your responses, the following is recommended :'),nl,nl,
	X    show_advice.
	Xshow_advice :-
	X    kb(advice,X),
	X    print(X),
	X    nl,
	X    fail.
	Xshow_advice :-
	X    nl,print('To see the complete set of derived facts,'),
	X    print('type "display_kb."').
	X
	X
	Xclear_kb :- retract(kb(_,_)),
	X            fail .
	Xclear_kb.
	X
	Xmember(X,[X|_]).
	Xmember(X,[_|Y]) :- member(X,Y).
	X
	Xask(Ques,Ans,LegalResponses) :-
	X    nl,print(Ques,' '),
	X    read(Ans),
	X    member(Ans,LegalResponses),!.
	Xask(Ques,Ans,LegalResponses) :-
	X   nl,nl,nl,
	X   print('Please respond with : ',LegalResponses),nl,nl,
	X   ask(Ques,Ans,LegalResponses).
	X
	X
	X
	X
	X
	X
	X
	X                      Listings and Figures
	X                  printed in AI EXPERT magazine
	X
	X
	X1.  Jack pine stand with minimum or higher stocking .................. 2
	X1.  Jack pine stand with less than minimum stocking .................. 10
	X
	X    2.  Average tree diameter less than 5 inches ..................... 3
	X    2.  Average tree diameter 5 inches or more ....................... 4
	X
	X3.  2,000 or more trees per acre ..................WEED OR CLEAN ..... 8
	X3.  Less than 2,000 trees per acre ................................... 8
	X
	X    4.  Stand is mature .............................................. 11
	X    4.  Stand is not mature .......................................... 5
	X
	XFigure 1 - Key for forest management taken from USDA Forest Service
	X           Handbook
	X
	X
	X

	X                                                        |-- yes ===> weed or clean
	X                                                        |            and do # 8
	X                             |-- yes --- 2000+ per acre-|
	X                             |                          |-- no ===> do # 8
	X         |-- yes -- diameter-|
	X         |          < 5 in.  |             |-- mature ===> do # 11
	Xminimum  |                   |-- no -- age-|
	Xstocking-|                                 |-- young ===> do # 5
	X         |
	X         |              
echo shar: "a missing newline was added to 'AIAPP.JAN'"
echo shar: "18 control characters may be missing from 'AIAPP.JAN'"
SHAR_EOF
if test 29884 -ne "`wc -c < 'AIAPP.JAN'`"
then
	echo shar: "error transmitting 'AIAPP.JAN'" '(should have been 29884 characters)'
fi
fi
echo shar: "extracting 'CONTNT.JAN'" '(2351 characters)'
if test -f 'CONTNT.JAN'
then
	echo shar: "will not over-write existing file 'CONTNT.JAN'"
else
sed 's/^	X//' << \SHAR_EOF > 'CONTNT.JAN'
	X
	X                            Contents -- AI EXPERT
	X                                 January 1987 
	X
	X
	XARTICLES
	X--------
	X
	XPlanning with TWEAK
	Xby Jonathan Amsterdam
	X
	XLike all exploratory work in the sciences, AI research proceeds 
	Xin cycles of 'scruffy' exploration and 'neat' consolidation.  
	XAfter years of exploration into different planning algorithm 
	Xdesign strategies, M.I.T.'s David Chapman may have created a new 
	Xera in planning research with his neat summary of more than a 
	Xdecade of scruffy work on an algorithm called TWEAK. 
	X
	X
	XRete Match Algorithm                                     
	Xby Charles L. Forgy and Susan Shepard
	X
	XThe Rete Match algorithm is a fast method for comparing a set of 
	Xpatterns to a set of objects to determine all possible matches.  
	XIt may be the most efficient algorithm for performing the match 
	Xoperation on single processor.  Developed by Charles L. Forgy in 
	X1974, it has been implemented in several languages in both 
	Xresearch and commercial grade systems.  
	X
	X
	XImperative Pattern Matching in OPS5                    
	Xby Dan Neiman
	X
	XSurely the Rete Match algorithm is an efficient data structure 
	Xfor implementing production systems.  But what else can it be 
	Xused for?  Let's look at the OPS5 language as a case study of 
	Xthe Rete net as an experimental tool kit.  Then we'll present a 
	Xtechnique that will show the programmer how to use Rete Match as 
	Xa general purpose pattern matching tool.
	X
	X
	XPerceptrons and Neural Nets
	Xby Peter Reece
	X
	XThere are at least ten billion neurons handling over one million 
	Xinput messages per second in the human brain.  With many of the 
	Xearlier hardware and software obstacles now overcome, let's look 
	Xback to one of the most successful pattern classification 
	Xcomputers---the Perceptron---and show how you can implement a 
	Xsimple Perceptron on your home computer.
	X
	X
	XDEPARTMENTS
	X-----------
	X
	XBrain Waves
	X"AI for Competitive Advantage"
	Xby Eugene Wang, Gold Hill Computers
	X
	XAI INSIDER
	X
	XEXPERT'S TOOLBOX
	X"Using Smalltalk to Implement Frames"
	Xby Marc Rettig
	X
	XAI APPRENTICE
	X"Creating Expert Systems from Examples"
	Xby Beverly and Bill Thompson
	X
	XIN PRACTICE
	X"Air Traffic Control:  A Challenge for AI"
	Xby Nicholas Findler
	X
	XHARDWARE REVIEW
	X"A LISP Machine Profile:  Symbolics 3650"
	Xby Douglas Schuler, et. al.
	X
	XSOFTWARE REVIEW
	X"Expertelligence's PROLOG for the Mac:
	XExperPROLOG II"
	X
	X 
echo shar: "a missing newline was added to 'CONTNT.JAN'"
echo shar: "159 control characters may be missing from 'CONTNT.JAN'"
SHAR_EOF
if test 2351 -ne "`wc -c < 'CONTNT.JAN'`"
then
	echo shar: "error transmitting 'CONTNT.JAN'" '(should have been 2351 characters)'
fi
fi
echo shar: "extracting 'EXPERT.JAN'" '(7019 characters)'
if test -f 'EXPERT.JAN'
then
	echo shar: "will not over-write existing file 'EXPERT.JAN'"
else
sed 's/^	X//' << \SHAR_EOF > 'EXPERT.JAN'
	X
	X                         Expert's Toolbox
	X                           January 1987
	X               "Using Smalltalk to Implement Frames"
	X                          by Marc Rettig
	X
	X
	X
	XListing 1
	X
	XDEFINITION OF CLASS SLOT
	X
	XDictionary variableSubclass: #Slot
	X  instanceVariableNames: ''
	X  classVariableNames: ''
	X  poolDictionaries: ''
	X
	XMETHODS FOR CLASS SLOT
	X
	XsetFacet:facetName with:aValue
	X   self at:facetName put:aValue
	X   ^aValue
	X
	XgetFacet: facetName
	X   ^self at:facetName ifAbsent:[nil]
	X
	XsetValue:aValue
	X   self setFacet:'value' with:aValue
	X
	XgetValue
	X   ^self getFacet:'value'
	X
	X_________________________________________
	XDEFINITION OF CLASS FRAME
	X
	XDictionary variableSubclass: #Frame
	X  instanceVariableNames: ''
	X  classVariableNames: ''
	X  poolDictionaries: ''
	X
	XMETHODS FOR CLASS FRAME
	X
	XsetSlot:slotName facet:facetName contents:aValue
	X   | tempSlot |
	X   tempSlot := self at:slotName 
	X                    ifAbsent:[self at:slotName put: Slot new].
	X   tempSlot setFacet:facetName with:aValue.
	X   ^aValue
	X
	XgetSlot:slotName facet:facetName
	X   ^(self includesKey:slotName)
	X      ifTrue: [(self at:slotName) getFacet:facetName]
	X      ifFalse:[nil]
	X
	XsetSlot:slotName value:aValue
	X   ^self setSlot:slotName facet:'value' contents:aValue

	XgetSlotValue:slotName
	X   "Get the value facet of a slot.  If no such slot, look up the AKO
	X    inheritance chain.  It that's no good, run a demon to get the value."
	X   | temp |
	X   ((temp := self getSlot:slotName) isNil)
	X      ifTrue: [((temp := self lookUpAkoChain:slotName) isNil)
	X         ifTrue: [^self runDemonForValue:slotName]
	X         ifFalse:[^temp getValue]]
	X      ifFalse:[(temp includesKey:'value')
	X         ifTrue: [^temp getValue]]
	X         ifFalse:[^self runDemonForValue:slotName]]
	X
	XgetSlot:slotName
	X   ^self at:slotName ifAbsent:[nil]
	X
	XsetSlot:slotName with:aSlot
	X   ^self at:slotName put:aSlot
	X
	XlookUpAkoChain:slotName
	X   "Look up the inheritance chain for a slot with the name in slotName.
	X    If you find it, return the Slot."
	X   ^(self includesKey:'AKO')
	X      ifTrue: [((self isAKO) includesKey:slotName)
	X         ifTrue: [^(self isAKO) getSlot:slotName]
	X         ifFalse:[^(self isAKO) lookUpAkoChain:slotName]]
	X      ifFalse:[nil]
	X
	XisAKO
	X   ^self getSlot:'AKO' facet:'value'
	X
	XisAKO:aFrame
	X   self setSlot:'AKO' value:aFrame
	X
	X____________________________________
	XSOME SAMPLE METHODS FOR DEMONS
	X
	XaddDemon:aBlock slot:slotName type:demonType
	X   (#('ifNeeded' 'ifAdded' 'ifRemoved') includes:demonType)
	X      ifTrue: [self setSlot:slotName facet:demonType with:aBlock]
	X      ifFalse:[self error:'Invalid Demon Type']
	X
	XrunDemonForValue:slotName
	X   | aBlock |
	X   aBlock := self getSlot:slotName facet:'ifNeeded'.
	X   (aBlock isNil)
	X     ifTrue: [^nil]
	X     ifFalse:[^self setSlot:slotName value:(aBlock value)]
	X
	X
	X
	XListing 2 
	X
	XA SAMPLE HIERARCHY OF FRAMES, SHOWING USE OF DEMONS
	X
| mammal dog firstDog askDemon |
	Xmammal := Frame new.
	Xmammal setSlot:'hide' value:'hairy'.
	Xmammal setSlot:'blood' value:'warm'.
	X
	Xdog := Frame new.
	Xdog isAKO:mammal.
	Xdog setSlot 'numberOfLegs' value:4.
	X
	X" Here is a simple if-needed demon, which will ask the 
	X  user for a value,while suggesting a default value."
	XaskDemon := [Prompter prompt:'What is this doggie''s name?
	X                      default:'Phydeaux'].
	X
	XfirstDog := Frame new.
	XfirstDog addDemon:askDemon slot:'name' type:'ifNeeded'.
	XfirstDog isAKO:dog.
	XfirstDog setSlot:'color' value:'brown'.
	X
	X"This message would cause the demon to be fired off..."
	Xfido getSlotValue:'name'
	X
	X
	XFRAME.CLS
	X
	XDictionary variableSubclass: #Frame
	X  instanceVariableNames: ''
	X  classVariableNames: ''
	X  poolDictionaries: '' !
	X
	X!Frame class methods ! !
	X
	X
	X!Frame methods !
	X
	XaddDemon:aBlock slot:slotName type:demonType
	X    (#('ifNeeded' 'ifAdded' 'ifRemoved') includes:demonType)
	X        ifTrue: [self setSlot:slotName facet:demonType with:aBlock]
	X        ifFalse:[self error:'Invalid Demon Type']!
	X
	XgetSlot:slotName
	X    "return the slot object corresponding to slotName."
	X
	X    ^self at: slotName ifAbsent: [nil]!
	X
	XgetSlot: slotName facet: facetName
	X
	X    ^(self includesKey: slotName)
	X        ifTrue: [(self at:slotName) getFacet:facetName]
	X        ifFalse: [nil]!
	X
	XgetSlotValue:slotName
	X    "get the value facet of a slot.  If no such slot, look up AKO chain.
	X     If that's no good, run a demon to get the value."
	X
	X    | temp |
	X    ((temp := self getSlot: slotName) isNil)
	X        ifTrue: [((temp := self lookUpAkoChain: slotName) isNil)
	X            ifTrue: [^self runDemonForValue:slotName]
	X            ifFalse:[^temp getValue]]
	X        ifFalse:[(temp includesKey: 'value')
	X            ifTrue: [^temp getValue]
	X            ifFalse:[^self runDemonForValue:slotName]]!
	X
	XisAKO
	X    ^self getSlot: 'AKO' facet:'value'!
	X
	XisAKO: aFrame
	X    "set the AKO slot of a frame"
	X
	X    self setSlot:'AKO' value:aFrame!
	X
	XlookUpAkoChain: slotName
	X    "Look up the inheritance chain for a slot with the name in slotName.
	X     If you find it, return the Slot"
	X
	X    ^(self includesKey: 'AKO')
	X        ifTrue:[((self isAKO) includesKey:slotName)
	X                    ifTrue: [^(self isAKO) getSlot: slotName]
	X                    ifFalse:[^(self isAKO) lookUpAkoChain: slotName]]
	X        ifFalse:[nil]!
	X
	XremoveSlot: slotName
	X    ^self removeKey:slotName ifAbsent:[nil]!
	X
	XrunDemonForValue: slotName
	X
	X    | aBlock |
	X    aBlock := self getSlot: slotName facet: 'ifNeeded'.
	X    (aBlock isNil)
	X        ifTrue: [^nil]
	X        ifFalse:[^self setSlot:slotName value:(aBlock value)]!
	X
	XsetSlot: slotName facet: facetName with: value
	X
	X    | tempSlot |
	X    tempSlot := self at:slotName
	X                     ifAbsent: [self at:slotName put: Slot new].
	X    tempSlot setFacet: facetName with: value.
	X    ^value!
	X
	XsetSlot:slotName value:aValue
	X    "set the value facet of a slot"
	X
	X    ^self setSlot:slotName facet:'value' with:aValue.!
	X
	XsetSlot:slotName with: aSlot
	X    "associate the slot aSlot with the name slotName. "
	X
	X    ^self at: slotName put: aSlot! !
	X
	X
	XFRMTRM.TXT
	X
	X| mammal dog fido s askDemon t |
	X" Examples of frame and slot classes in use.
	X  Select and DOIT."
	X  
	Xmammal := Frame new.
	Xmammal setSlot: 'hide' value: 'hairy'.
	Xmammal setSlot: 'bloodType' value: 'warm'.
	X
	Xdog := Frame new.
	Xdog isAKO: mammal.
	Xdog setSlot: 'numberLegs' value: 4.
	X
	XaskDemon := [Prompter prompt:'What is this dog''s name?' default: 'Bruno'].
	Xdog addDemon:askDemon slot:'name' type:'ifNeeded'.
	X
	Xfido := Frame new.
	Xfido addDemon:askDemon slot:'name' type:'ifNeeded'.
	Xfido isAKO:dog.
	Xfido setSlot:'color' value:'brown'.
	X
	X" Let's see the demon fire "
	Xfido getSlotValue:'name'.
	X
	X
	XSLOT.CLS
	X
	XDictionary variableSubclass: #Slot
	X  instanceVariableNames: ''
	X  classVariableNames: ''
	X  poolDictionaries: '' !
	X
	X!Slot class methods ! !
	X
	X
	X!Slot methods !
	X
	XgetFacet: facetName
	X    ^self at: facetName ifAbsent: [nil]!
	X
	XgetValue
	X    ^self getFacet: 'value'!
	X
	XremoveFacet: facetName
	X    ^self removeKey:facetName ifAbsent:[nil]!
	X
	XsetFacet: facetName with: aValue
	X
	X    self at: facetName put: aValue.
	X    ^aValue!
	X
	XsetValue: aValue
	X    self setFacet: 'value' with: aValue! !
	X a
echo shar: "a missing newline was added to 'EXPERT.JAN'"
echo shar: "55 control characters may be missing from 'EXPERT.JAN'"
SHAR_EOF
if test 7019 -ne "`wc -c < 'EXPERT.JAN'`"
then
	echo shar: "error transmitting 'EXPERT.JAN'" '(should have been 7019 characters)'
fi
fi
echo shar: "extracting 'FILES.JAN'" '(837 characters)'
if test -f 'FILES.JAN'
then
	echo shar: "will not over-write existing file 'FILES.JAN'"
else
sed 's/^	X//' << \SHAR_EOF > 'FILES.JAN'
	X
	X
	X               Articles and Departments that have
	X                    Additional On-Line Files 
	X
	X                            AI EXPERT
	X                          January 1987
	X          (Note:  Contents page is in file CONTNT.JAN)
	X
	X
	X
	X
	XARTICLES                                        RELEVANT FILES
	X--------                                        --------------  
	X
	XJanuary Table of Contents                         CONTNT.JAN
	X
	XAdding Rete Net to Your OPS5 Toolbox              OPSNET.JAN
	Xby Dan Neiman
	X
	XPerceptrons & Neural Nets                         PERCEP.JAN
	Xby Peter Reece
	X
	X
	XDEPARTMENTS
	X
	XExpert's Toolbox                                  EXPERT.JAN
	X"Using Smalltalk to Implement Frames"
	Xby Marc Rettig
	X
	XAI Apprentice                                     AIAPP.JAN
	X"Creating Expert Systems frm Examples"
	Xby Beverly and Bill Thompson
	X
SHAR_EOF
if test 837 -ne "`wc -c < 'FILES.JAN'`"
then
	echo shar: "error transmitting 'FILES.JAN'" '(should have been 837 characters)'
fi
fi
echo shar: "extracting 'OPSNET.JAN'" '(359936 characters)'
if test -f 'OPSNET.JAN'
then
	echo shar: "will not over-write existing file 'OPSNET.JAN'"
else
sed 's/^	X//' << \SHAR_EOF > 'OPSNET.JAN'
	X
	X
	X                Adding the Rete Net to Your OPS5 Toolbox
	X           (Supplemental files arranged by filename headings)
	X                        January 1987 AI EXPERT
	X                             by Dan Neiman
	X
	X
	X
	XEditor's Note:
	X
	XAdditional notes and clarifications for Imperative Pattern Match code,
	Xas described in January '87 issue of AI/Expert.
	X
	XThe code described in AI/Expert is still evolving (i.e. the more I use it, the more
	Xfeatures I add), and there was not sufficient space to give complete instructions in 
	Xthe magazine, so the following notes should be used as a supplement to the 
	Xarticle.
	X
	XTo use the Rete net modifications, load the code into an existing Common Lisp OPS5
	Ximage. Then use the pmatch and map-pmatch functions as described in the article. 
	X
	X
	XIt was probably not made clear in the article, but both pmatch and map-pmatch 
	Xreturn the values of the last expression evaluated in the righthand side.  So, 
	Xfor example, to get the names of all employees making 30K a year, you might use the
	Xcode:
	X?(map-pmatch (employees ^name <emp> ^salary > 30000)
	X       -->
	X       ?<emp> )
	X
	XThe RHS of the above function just evaluates and returns the binding of <emp>.  
	XBecause the function used was map-pmatch, a list of *all* employees satisfying the
	Xgiven constraints is returned.
	X
	XThe syntax of the pmatch and map-pmatch commands has been modified slightly since
	Xthe article went to press.  The method described for passing Lisp variables to a 
	Xpattern match function proved to be inexpressibly awkward for lexically bound Lisps
	X(the system was originally written in Franz).  The following modification makes it
	Xconsiderably easier to pass arguments to the pattern match routines.
	X
	XBecause the pattern match is compiled, the only way to interactively match a particular 
	Xvalue is to write that value into working memory, and include that working memory element
	Xin the pattern match.  This is fairly awkward to do by hand, so I've incorporated a macro
	Xinto the pmatch and map-pmatch commands which do it automagically. The arguments are passed
	Xby following the pmatch function with an argument list.  The argument list is distinguished
	Xfrom a pattern by the "args" keyword.   The syntax is:
	X
	X(pmatch (args arg1 arg2 ... argN)
	X        (condition element 1)
	X	(condition element 2)
	X	-->
	X        RHS)
	X
	XAfter macro expansion, the result is effectively
	X      (let ((tt (make ipm$data arg1 arg2 ... argN)))
	X	(query1  (ipm$data <arg1> <arg2> <arg3>)
	X                 (condition element 1)
	X           	 (condition element 2)
	X                   :      :       :
	X               -->
	X                  RHS)
	X       (oremove tt) )
	X
	XNote that the working memory element is added and deleted automatically.
	X
	XAs an example, the code to locate all children of a couple might look like this
	X(defun children(mother father)
	X   ?(map-pmatch (args mother father)
	X	    (mother ^name <mother> ^child <child>)
	X	    (father ^name <father> ^child <child>)
	X          -->
	X          (make parents ^name <child> ^father <father> ^mother <mother>)
	X          ?<child>)
	X
	Xand given the working memory:
	X(mother ^name ann ^child bob)
	X(father ^name fred ^child bob)
	X(mother ^name sue ^child alex)
	X(father ^name fred ^child john)
	X(mother ^name ann ^child john)
	X(father ^name fred ^child cheryl)
	X
	X(children 'ann 'fred) would return (bob john)
	X
	Xand create the working memory elements
	X
	X(parents ^name bob ^father fred ^mother ann)
	X(parents ^name john ^father fred ^mother ann)
	X
	XDebugging code:  As is the case with OPS5 productions, if you recompile a pmatch 
	Xor map-pmatch function, you must remove working memory and replace it.  A pattern match
	Xwill only work on data which has been added after compilation.  This does tend to 
	Xmake debugging tedious.
	X
	XEverytime a pmatch operation is recompiled, it generates a new body bound to a variable of 
	Xthe form queryN.  Because queries are not explictly named, it's difficult to automatically
	Xexcise them. So the net will tend to fill with superfluous nodes during debugging.
	XThe function exquery will excise all existing queries.  Executing the sequence,
	X(oremove *)
	X(exquery)
	X(i-g-v)
	X
	Xwill remove all working memory and queries and reset all global variables.
	X
	XIf a pmatch or map-pmatch function blows up while evaluating its RHS, reset the
	Xglobal variable *in-rhs* to nil before proceeding.
	X
	XQuestions about this code can be directed to:
	XDan Neiman
	XCompuServe 72277,2604
	XCSNET dann@UMASS-CS.csnet  
	X
	Xor c/o COINS Dept.
	X       Lederle Graduate Research Center
	X       University of Massachusetts
	X       Amherst, MA 01003
	X
	X
	XIndex to software:
	X
	XCLSUP.LSP : Common Lisp support functions to define some canonical 
	X             functions missing in Common Lisp.
	X             
	XOPSMODS.L  : The OPS5 modifications described in the article.
	X                        
	XCOMMON.OPS : OPS5 for Common Lisp
	XTI.OPS     : OPS5 for TI Explorers
	XFRANZ.OPS  : OPS5 for Franz Lisp
	X
	XMONK.OPS : Test file for OPS5
	XPRTOWER.OPS : Test file for OPS5
	X
	X
	XNEWOPS.L
	X
	X;OPS5 modifications for Common Lisp
	X; by: Dan Neiman
	X; Original idea conceived at  ITT ATC   May, 1986
	X; Converted to Common Lisp and expanded at COINS Dept., UMASS Fall 1986
	X
	X;Copyright notice:  Much of this code is modified or original OPS5 code which is 
	X;copyrighted by C. Lanny Forgy of CMU, and is used with his permission.  The rest is
	X;Copyright (c) Daniel Neiman, COINS Dept. UMass.  Permission is given to use this
	X;code freely for personal, educational, or research applications.  It is not to be
	X;sold, or incorporated into a for-profit product without permission of the author.
	X;The purpose of this code is to illustrate alternative uses of the Rete net and 
	X;alternative control structures in OPS5.  No guarantees are made about its fitness
	X;any particular application, and no claim is made about the presence or absence of 
	X;bugs.
	X;Version of 12/12/86
	X
	X;This file contains the necessary OPS5 modifications to perform 
	X;the RHS pattern matching/control function described in the 
	X;accompanying January '87 AI/Expert article.  The code is a supplement to OPS5 and is
	X;intended to be loaded into a Common Lisp OPS5 image.
	X
	X;Note:  The idea behind this modification is to add memory to the &p node and create
	X;functions to interrogate that memory at will.  Sort of an elegant idea.  But, because
	X;it has to be patched into an implementation which was not designed to do so, there's a
	X;lot of fairly nasty looking code here.  Take heart, most of it is just slightly modified
	X;ops5 code and can be pretty much ignored.
	X
	X;This variable is used to determine if we encountered a pmatch
	X;or map-pmatch in top-level lisp code or while compiling an 
	X;OPS5 production.
	X
	X(proclaim '(special *compiling-rhs* *qnames* *cmp-p-context-stack*
	X    *system-state-stack* *NMATCHES* *ipm-data-stack*))
	X(setq *qnames* nil)
	X(setq *system-state-stack* nil)
	X(setq *cmp-p-context-stack* nil)
	X(setq *compiling-rhs* nil)
	X(setq *ipm-data-stack* nil)
	X
	X;Read macro for variable evaluation on "RHS" of pattern match
	X;All &whatever macros on the righthand side must be preceded by
	X;a ?.  This will expand to ($varbind '&whatever)
	X;To avoid having a plethora of read macros, ? will be double-duty.
	X;If ? precedes a ?(pmatch ....), then the expression is evaluated
	X;and the appropriate match stuff is placed in the rete net.  The
;code is replaced by (query queryN pattern-body).
	X
	X;Read macro ? executes the following function.  
	X(defun $$ipm$$dofunc$$(strm chr)
	X     (let ((inp (read strm t nil t)))
	X      (cond ((atom inp)
	X     (if (eq '#\< (char (string inp) 0)) ;is it an OPS variable?
	X `($varbind ',inp)
	X         (intern (concatenate 'string "?" (princ-to-string inp)))))
	X    ((member (car inp) '(map-pmatch pmatch) :test #'eq)
	X     (eval inp))
	X    (t 
	X     inp))))
	X     
	X
	X;make ? a read macro
	X(set-macro-character #\? #'$$ipm$$dofunc$$ t)
	X
	X(defun &query (rating name var-dope ce-var-dope rhs frhs)
	X  (prog (fp dp)
	X        (cond (*sendtocall*
	X               (setq fp *flag-part*)
	X               (setq dp *data-part*))
	X              (t
	X               (setq fp *alpha-flag-part*)
	X               (setq dp *alpha-data-part*)))
	X        (and (member fp '(nil old)) 
	X             (ipm-removepm name dp))
	X        (and fp (ipm-insertpm name dp)))) 
	X
	X
	X; each conflict set element is a list of the following form:
-- 
---------------
C'est la vie, C'est la guerre, C'est la pomme de terre
Mail:	Imagen Corp. 2650 San Tomas Expressway Santa Clara, CA 95052-8101 
UUCP:	...{decvax,ucbvax}!decwrl!imagen!turner      AT&T: (408) 986-9400

turner@imagen.UUCP (D'arc Angel) (01/19/87)

	X; ((p-name . data-part) (sorted wm-recency) special-case-number)
	X
	X;I'm storing the results of the pattern matches on a property list, pmatches. 
	X
	X;modified OPS5 removecs
	X;remove results of the pattern match
	X
	X(defun ipm-removepm (name cr-data)
	X  (prog (inst cs pmtchs)
	X(setq pmtchs (setq cs (get name 'pmatches)))
	X  l(cond ((null cs) 
	X               (return nil)))
	X(setq inst (car cs))
	X(setq cs (cdr cs))
	X(and (not (top-levels-eq inst cr-data)) (go l))
	X(putprop name (remove inst pmtchs)
	X      'pmatches)
	X))
	X
	X;modified OPS5 insertcs
	X;store the results of the pattern match
	X;Stored as (data ) rather than original conflict set format 
	X;of ((name . data) (order tags) rating)

	X(defun ipm-insertpm (name data)
	X  (let ((pmtch (get name 'pmatches)))
	X    (setq pmtch (get name 'pmatches))
	X    (and (atom pmtch) (setq pmtch nil))
	X    (setq pmtch (cons data pmtch))
	X    (putprop name pmtch 'pmatches)
	X     pmtch
	X    )) 
	X
	X;PMATCH is the RHS/LISP equivalent of the (p rule) macro. When used from Lisp,
	X;it should always be preceded by the ? read macro, so as to force evaluation
	X;at read time.  Otherwise, the Rete net won't be set up correctly.
	X
	X(defmacro pmatch(&rest z) 
	X  `(let ((pname (newsym query))
	X         (level (newsym level)))
	X    (finish-literalize)
	X    (princ '*) 
	X    (cond ((and (listp (car ',z)) (eq (caar ',z) 'args))
	X           (ipm-compile-production pname (add-data-to-prod pname ',z ))
	X  `(let ((tt  (make-ipm-data ',pname ,@(cdar ',z) )) 
	X         (ans (query ',pname)))
	X(restore-ipm-data tt)
	X                ans))
	X  (t 
	X   (ipm-compile-production pname ',z)
	X   `(query ',pname)))))
	X
	X(defun restore-ipm-data(current)
	X   (let ((inrhsflg *in-rhs*)
	X (old (pop *ipm-data-stack*)))
	X       (setq *in-rhs* nil)
	X       (eval (list 'oremove current))
	X       (setq *in-rhs* inrhsflg)
	X       (if old
	X   (add-to-wm (car old) (cdr old)))))
	X   
	X;Note, the only way to pass input to the pattern matcher is to create a 
	X;working memory element containing that input.  The following utility functions
	X;automagically create the ipm$data working memory element and modify the 
	X;production to use it.
	X
	X;MAKE-DATA:  Make data takes a list of values and a unique level specifier
	X;and creates a working memory element of the form (ipm$data val1 val2 val3 .. )
	X;Saves old ipm$data elements on stack so that no interference results.
	X(defun make-ipm-data(&rest arglst)
	X (let ((inrhsflg *in-rhs*)
	X       (old (car (get 'ipm$data 'wmpart*))))
	X   (if old (push old *ipm-data-stack*))
	X   (setq *in-rhs* nil)
	X   (eval (list 'oremove (cdr old))) ;needs in-rhs to be nil
	X   (setq *in-rhs* inrhsflg)
	X   ($reset)
	X   ($change 'ipm$data)
   (mapc #'(lambda(tab val)
	X         ($tab tab)
	X         ($change val)) 
	X       '(a b c d e f g h i j k l) (cdr arglst))
	X   ($tab 'for) ;target data for particular query
	X   ($change (car arglst)) 
	X   ($assert)))
	X
	X;Modify the production so that it accesses the data passed by the ipm$data wme
	X(defun add-data-to-prod(pname prod)
	X    (let ((args (cdar prod))
	X  (body (cdr prod)))
	X     (cons 
	X       `(ipm$data ,@(mapcan #'(lambda(slot arg) (list  '^ slot (concat '\< arg '\> ))) 
	X        '(a b c d e f g h i j k l) args) 
	X       ^for ,pname)
	X       body)))
	X 
	X
	X;Finish-literalize: modified to define special wme type ipm$data which is used to 
	X;transfer lisp arguments to working memory.
	X(defun finish-literalize nil
	X  (cond ((not (null *class-list*))
	X         (cond ((not (member 'ipm$data *class-list*))
	X             (literalize ipm$data a b c d e f g h i j k l for)))
	X         (mapc (function note-user-assigns) *class-list*)
	X         (mapc (function assign-scalars) *class-list*)
	X         (mapc (function assign-vectors) *class-list*)
	X         (mapc (function put-ppdat) *class-list*)
	X         (mapc (function erase-literal-info) *class-list*)
	X         (setq *class-list* nil)
	X         (setq *buckets* nil)))) 
	X
	X
	X
	X;Map the RHS across all matching data.
	X(defmacro map-pmatch(&rest z) 
	X  `(let ((pname (newsym query))
	X         (level (newsym level)))
	X    (finish-literalize)
	X    (princ '*) 
	X    (cond ((and (listp (car ',z)) (eq (caar ',z) 'args))
	X           (ipm-compile-production pname (add-data-to-prod pname ',z ))
	X  `(let ((tt  (make-ipm-data ',pname ,@(cdar ',z) )) 
	X         (ans (map-query ',pname)))
	X(restore-ipm-data tt)
	Xans))
	X  (t 
	X   (ipm-compile-production pname ',z)
	X   `(map-query ',pname)))))
	X
	X
	X(defun ipm-compile-production (name matrix)
	X  (prog (erm)
	X        (setq *p-name* name)
(cond (*compiling-rhs*
	X               (setq erm (catch (ipm-cmp-p-recursive name matrix) '!error!)))
	X      (t
	X               (setq erm (catch (ipm-cmp-p name matrix) '!error!))))
	X; following line is modified to save production name on *qnames*
	X        (pushnew name *qnames*)
	X(return erm)))
	X
	X
	X;save globals *feature-count *ce-count* *vars* *ce-vars* *rhs-bound-vars*
	X;*rhs-bound-ce-vars* *last-branch* on a push-down stack.
	X
	X;Push global variables takes a stack name, and a list of global variables, creates a 
	X;list of lists of the form ((varname value) (varname value) ... ) and pushes it onto
	X;the indicated stack.
	X
	X(defun push-global-variables(stack &rest vars)
	X    (push
	X      (mapcar #'(lambda(var)
	X                  (cons var (eval var)))  ;copy may not be needed, but better safe....
	X               vars)
	X      (symbol-value stack)))
	X
	X;Pop global variables takes a stack name, pops most recent entry off the stack,
	X;and resets the values of the variables.
	X(defun pop-global-variables(stack)
	X   (mapcar #'(lambda(varbinding)
	X                (set (car varbinding) (cdr varbinding)))
	X           (pop stack))  )
	X
	X
	X;This version of cmp-p is used when compiling patterns on the 
	X;righthand side in which we want variable bindings consistent
	X;with variable bindings on the LHS.  Effectively, the RHS 
	X;pattern is just treated as a continuation of the LHS 
	X;pattern, except, of course, that the results of the RHS 
	X;pattern match will not affect the firing of the production.
	X(defun ipm-cmp-p-recursive (name matrix)
	X  (prog (m bakptrs srhs frhs)
	X  (push-global-variables '*cmp-p-context-stack* '*matrix*
	X      '*feature-count* '*ce-count* 
	X      '*vars* '*ce-vars*
	X      '*rhs-bound-vars* '*rhs-bound-ce-vars*
	X      '*last-branch* '*last-node*)
	X        (prepare-lex matrix)
	X(setq *rhs-bound-vars* nil)
	X(setq *rhs-bound-ce-vars* nil)
	X        (setq m (rest-of-p))
	X   l1   (and (end-of-p) (\%error '|no '-->' in production| m))
	X        (cmp-prin)
	X        (setq bakptrs (cons *last-branch* bakptrs))
	X        (or (eq '--> (peek-lex)) (go l1))
	X        (lex)
	X(setq srhs (rest-of-p)) ; get righthand side
	X(if (setq frhs (cdr (memq '<-- srhs))) 
    (setq srhs (remove-frhs srhs)))
	X(ipm-check-rhs srhs)
	X;note, we change the structure of the &query node to have a tail
	X;component.  This is the action to take on a failed pattern match
	X        (link-new-node (list '&query
	X                             *feature-count*
	X     name
	X                             (encode-dope)
	X                             (encode-ce-dope)
	X                             (cons 'progn srhs)
	X     (cons 'progn frhs)))
	X        (putprop name (cdr (nreverse bakptrs)) 'backpointers)
	X(putprop name matrix 'production)
	X        (putprop name *last-node* 'topnode)
	X(pop-global-variables *cmp-p-context-stack*)
	X))
	X
	X;Extract failed pattern match rhs actions from production.
	X(defun remove-frhs(rhs)
	X   (do ((lis nil (append lis (list inp))) 
	X(inp (car rhs) (car rhs)))
	X       ((eq inp '<--)
	X(return lis))
	X      (setq rhs (cdr rhs))
	X       ))
	X
	X;;Modified version of OPS5 cmp-p, compiles pattern match and links
	X;&query node into Rete net. If pmatch occurs in the righthand side of the rule, then
	X;nodes are linked to tree generated by rule's LHS.
	X(defun ipm-cmp-p (name matrix)
	X  (prog (m bakptrs srhs frhs)
	X        (prepare-lex matrix)
	X        (excise-p name)
	X        (setq bakptrs nil)
	X        (setq *pcount* (1+ *pcount*))
	X        (setq *feature-count* 0.)
	X(setq *ce-count* 0)
	X        (setq *vars* nil)
	X        (setq *ce-vars* nil)
	X(setq *rhs-bound-vars* nil)
	X(setq *rhs-bound-ce-vars* nil)
	X        (setq *last-branch* nil)
	X        (setq m (rest-of-p))
	X   l1   (and (end-of-p) (\%error '|no '-->' in production| m))
	X        (cmp-prin)
	X        (setq bakptrs (cons *last-branch* bakptrs))
	X        (or (eq '--> (peek-lex)) (go l1))
	X        (lex)
	X(setq srhs (rest-of-p)) ; get righthand side
	X(if (setq frhs (cdr (memq '<-- srhs))) 
	X    (setq srhs (remove-frhs srhs)))
	X(ipm-check-rhs srhs)
	X;note, we change the structure of the &query node to have a tail
	X;component.  This is the action to take on a failed pattern match
	X        (link-new-node (list '&query
                             *feature-count*
	X                             name
	X                             (encode-dope)
	X                             (encode-ce-dope)
	X                             (cons 'progn srhs)
	X     (cons 'progn frhs)))
	X(terpri)
	X        (putprop name (cdr (nreverse bakptrs)) 'backpointers)
	X(putprop name matrix 'production)
	X        (putprop name *last-node* 'topnode))) 
	X
	X;Modified OPS5 code, sets *compiling-rhs* variable.
	X(defun check-rhs (rhs) 
	X    (setq *compiling-rhs* t)
	X    (mapc (function check-action) rhs)
	X    (setq *compiling-rhs* nil))
	X
	X
	X;rhs part to be evaluated upon pattern match failure
	X
	X(defun frhs-part (pnode) (car (last pnode)))
	X
	X;;returns value of last expression in RHS
	X(defun query (qname)
	X  (ipm-eval-query qname (car (get qname 'pmatches))))
	X   
	X;IPM-EVAL-QUERY: Given a pointer to a query and the associated data, this function
	X;sets up the appropriate environment to evaluate the RHS of the pattern match.
	X;This is a modified eval-rhs from OPS5.
	X
	X(defun ipm-eval-query (pname data)
	X  (let ((node (get pname 'topnode))
	X        (ans nil)
	X        (saved nil))
	X   (if (setq saved *in-rhs*) ;in case of recursive call,save system state and
	X       (save-system-state))  ;set saved flag
	X    (setq *data-matched* data)
	X    (setq *p-name* pname)
	X    (setq *last* nil)
	X    (setq node (get pname 'topnode))
	X    (ipm-init-var-mem (var-part node))
	X    (ipm-init-var-nmatches pname)
	X    (ipm-init-ce-var-mem (ce-var-part node))
	X    (setq *in-rhs* t)
	X    (setq ans
	X      (if (neq *NMATCHES* 0) ;if match failed, execute failpart, if any
	X(eval (rhs-part node))
	X(eval (frhs-part node)) ))
	X    (setq *in-rhs* nil)
	X   (if saved
	X      (restore-system-state))
	X    ans
	X))
	X
	X;map-query is just like query, except that we are performing the 
;eval operation for each match.  Therefore, some of the initialization
	X;must be factored out of ipm-eval-map-query.
	X(defun map-query(qname)
	X   (let* ((node (get qname 'topnode))
	X          (ans nil) 
	X          (saved nil))
	X   (if (setq saved *in-rhs*) ;in case of recursive call,save system state and
	X       (save-system-state))  ;set saved flag
	X      (setq *p-name* qname)
	X      (setq *last* nil)
	X  (setq ans
	X   (if (> (length (get qname 'pmatches)) 0)
	X      (mapcar '(lambda(qinstance) 
	X            (ipm-eval-map-query qname qinstance node))
	X          (get qname 'pmatches))
	X      (eval (frhs-part node)) ))
	X   (if saved
	X      (restore-system-state))
	X   ans)) 
	X
	X(defun ipm-eval-map-query (qname data node)
	X  (let ((ans))
	X    (setq *data-matched* data)
	X    (setq node (get qname 'topnode))
	X    (ipm-init-var-mem (var-part node))
	X    (ipm-init-var-nmatches qname)
	X    (ipm-init-ce-var-mem (ce-var-part node))
	X    (setq *in-rhs* t)
	X    (setq ans (eval (rhs-part node)))
	X    (setq *in-rhs* nil)
	X    ans
	X )) 
	X
	X
	X;the variable &nmatches is bound to the number of production
	X;matches in each query.  Useful for counting applications and
	X;deciding if any matches succeeded.
	X
	X(defun ipm-init-var-nmatches(pname)
	X    (setq *NMATCHES* (length (get pname 'pmatches)))
	X    (setq *variable-memory* ;remove previous number of matches
	X  (remove (assoc '\<NMATCHES\> *variable-memory*) *variable-memory*))
	X    (setq *variable-memory*  ;set up &NMATCHES environ. variable
	X          (cons (cons '\<NMATCHES\> *NMATCHES*)
	X*variable-memory*)))
	X
	X;More modified OPS5 code.  Initializes the variable and ce-variable bindings
	X;to be consistent with the results of the pattern match.
	X(defun ipm-init-var-mem (vlist)
	X  (prog (v ind r)
	X(or *in-rhs* ;if we're in rhs, then global is already set
	X          (setq *variable-memory* nil))
	X   top  (and (atom vlist) (return nil))
	X        (setq v (car vlist))
	X        (setq ind (cadr vlist))
        (setq vlist (cddr vlist))
	X        (setq r (gelm *data-matched* ind))
	X        (setq *variable-memory* (cons (cons v r) *variable-memory*))
	X        (go top))) 
	X
	X(defun ipm-init-ce-var-mem (vlist)
	X  (prog (v ind r)
	X(or *in-rhs* ;if we're in rhs, then global is already set
	X          (setq *ce-variable-memory* nil))
	X   top  (and (atom vlist) (return nil))
	X        (setq v (car vlist))
	X        (setq ind (cadr vlist))
	X        (setq vlist (cddr vlist))
	X        (setq r (ce-gelm *data-matched* ind))
	X        (setq *ce-variable-memory*
	X              (cons (cons v r) *ce-variable-memory*))
	X        (go top))) 
	X
	X(defun save-system-state()
	X   (push-global-variables '*system-state-stack* '*ce-variable-memory* '*data-matched*
	X                          '*variable-memory* '*NMATCHES* '*p-name* '*in-rhs*))
	X
	X(defun restore-system-state()
	X   (pop-global-variables *system-state-stack*))
	X
	X;changed OPS5 code to accept &query
	X(defun link-new-node (r)
	X  (cond ((not (member (car r) '(&query &p &mem &two &and &not)))
	X (setq *feature-count* (1+ *feature-count*))))
	X  (setq *virtual-cnt* (1+ *virtual-cnt*))
	X  (setq *last-node* (link-left *last-node* r))) 
	X
	X(defun ipm-check-rhs (rhs) 
	X    (setq *compiling-rhs* t)
	X    (mapc (function ipm-check-action) rhs)
	X    (setq *compiling-rhs* nil))
	X
	X(defun myreplace(x y)
	X   (rplaca x (car y))
	X   (rplacd x (cdr y)))
	X
	X;This check-action is called by pmatch or map-pmatch macros
	X(defun ipm-check-action (x)
	X  (prog (a)
	X    (cond ((atom x)
	X           (%warn '|atomic action| x)
	X   (return nil)))
	X    (setq a (setq *action-type* (car x)))
	X   (cond ((eq a 'bind) (check-bind x))
	X          ((eq a 'query) nil) ;never happens?
	X          ((eq a 'map-query) nil) ;never happens?
	X  ;if we come across an unexpanded pmatch, expand and compile it.
	X  ;replace with result
	X          ((eq a 'pmatch) (myreplace x (eval x)))
	X          ((eq a 'map-pmatch) (myreplace x (eval x)))
          ((eq a 'cbind) (check-cbind x))
	X          ((eq a 'make) (check-make x))
	X          ((eq a 'modify) (check-modify x))
	X          ((eq a 'remove) (check-remove x))
	X          ((eq a 'write) (check-write x))
	X          ((eq a 'call) (check-call x))
	X          ((eq a 'halt) (check-halt x))
	X          ((eq a 'openfile) (check-openfile x))
	X          ((eq a 'closefile) (check-closefile x))
	X          ((eq a 'default) (check-default x))
	X          ((eq a 'build) (check-build x))
	X          (t nil) ;in a pmatch rhs, code is not restricted to OPS rhs actions.
	X  )))
	X
	X;This check action is just modified so that pmatch or map-pmatch
	X;are acceptable right-hand sides.
	X(defun check-action (x)
	X  (prog (a)
	X    (cond ((atom x)
	X           (%warn '|atomic action| x)
	X   (return nil)))
	X    (setq a (setq *action-type* (car x)))
	X    (cond ((eq a 'bind) (check-bind x))
	X          ((eq a 'query) nil) ;never happens
	X          ((eq a 'map-query) nil) ;never happens
	X  ;if we come across an unexpanded pmatch, expand and compile it.
	X  ;replace with result
	X          ((eq a 'pmatch) (myreplace x (eval x)))
	X          ((eq a 'map-pmatch) (myreplace x (eval x)))
	X          ((eq a 'cbind) (check-cbind x))
	X          ((eq a 'make) (check-make x))
	X          ((eq a 'modify) (check-modify x))
	X          ((eq a 'remove) (check-remove x))
	X          ((eq a 'write) (check-write x))
	X          ((eq a 'call) (check-call x))
	X          ((eq a 'halt) (check-halt x))
	X          ((eq a 'openfile) (check-openfile x))
	X          ((eq a 'closefile) (check-closefile x))
	X          ((eq a 'default) (check-default x))
	X          ((eq a 'build) (check-build x))
	X          (t (%warn '|undefined rhs action| a))))) 
	X
	X
	X;add-to-wm: modified to return timetag number of item added
	X(defun add-to-wm (wme override)
	X  (prog (fa z part timetag port)
	X    (setq *critical* t)
	X    (setq *current-wm* (1+ *current-wm*))
	X    (and (> *current-wm* *max-wm*) (setq *max-wm* *current-wm*))
	X    (setq *action-count* (1+ *action-count*))
	X    (setq fa (wm-hash wme))
	X    (or (memq fa *wmpart-list*)
	X        (setq *wmpart-list* (cons fa *wmpart-list*)))
	X    (setq part (get fa 'wmpart*))
	X    (cond (override (setq timetag override))
          (t (setq timetag *action-count*)))
	X    (setq z (cons wme timetag))
	X    (putprop fa (cons z part) 'wmpart*)
	X    (record-change '=>wm *action-count* wme)
	X    (match 'new wme)
	X    (setq *critical* nil)
	X    (cond ((and *in-rhs* *wtrace*)
	X           (setq port (trace-file))
	X           (terpri port)
	X           (princ '|=>wm: | port)
	X           (ppelm wme port)))
	X    (and *in-rhs* *mtrace* (setq *madeby* 
	X                                 (cons (cons wme *p-name*) *madeby*)))
	X    (return timetag))) 
	X
	X(defun &old (&rest a) nil) ;a null function used for deleting node
	X
	X
	X;MAKESYM: Does the same thing as gensym, but allows a symbol to be passed, so
	X;         the resulting symbol is meaningful.
	X(defun makesym(x)
	X  (prog(numb)
	X       (and (not (setq numb (get x '$cntr)))
	X    (setq numb 0))
	X       (putprop x (add1 numb) '$cntr)
	X       (return (concat x numb))))
	X
	X;CONCAT: Make a symbol from a number of symbols
	X(defun concat(&rest x)
	X   (do ((lst x (cdr lst))
	X        (strng nil))
	X       ((null lst)
	X        (intern strng))
	X       (setq strng (concatenate 'string strng (princ-to-string (car lst))))
	X    ))
	X
	X;A general purpose gensym function.  Input is 
	X; [atom], output is [atom]N, where N is a unique integer.
	X; ie. (newsym baz) ==> baz1
	X;     (newsym baz) ==> baz2, etc.
	X
	X(defmacro newsym(x)
	X  `(makesym ',x))
	X
	X
	X(defun exquery()
	X  (mapc #'(lambda(q) (eval `(excise ,q))) *qnames*)
	X  (setq *qnames* nil))
	X
	X;The following is a minimal test for the opsmods programs.
	X;To use it, uncomment it, and load it. The code should load without
	X;blowing up. Complaints about atomic actions in RHS are OK, ignore them. 
	X;Type
	X;(setup)
	X;(cs) -- foo and baz should be in the conflict set.
;Type (run 1), the program should print out a list of blocks.
	X;(run) should continue until only chartreuse blocks are left.
	X;While simple, this code tests for nested use of pattern matches, recursive calls,
	X;and use of pmatch in the rhs of OPS productions.
	X;(i-g-v)
	X;(literalize block a b c)
	X
	X
	X;(p baz 
	X;   { <a> (block ^a <colour> ) }
	X;         (block ^a <> <colour>)
	X;  -->
	X;   (pmatch  (block ^a <> <colour> ) 
	X;       -->
	X;           (find-block-colors ?<colour> )
	X;   (oremove <a> ))
	X;   (make block ^a chartreuse))
	X
	X;Test for recursive use of pmatch. (find-block-colors uses map-pmatch and 
	X;appears in a RHS of another pmatch)
	X;(defun rtest(a )
	X;   ?(pmatch (args a )
	X;    (block ^a <a> <numb>)
	X;        -->
	X;          (find-block-colors 'green)
	X;          (format t "Block color ~a is ~a~%" ?<a> ?<numb>)))
	X
	X;(defun find-block-colors (color)
	X;  ?(map-pmatch (args color)
	X;       (block ^a <color> <numb>)
	X;     -->
	X;   (format t "~%Find-block-colors ~a ~a~%" ?<color> ?<numb>))) 
	X
	X;(defun setup()
	X;  (setq *in-rhs* nil)
	X;  (oremove *)              
	X;  (make block ^a green 1)
	X;  (make block ^a green 2)
	X;  (make block ^a green 3)
	X;  (make block ^a green 4)
	X;  (make block ^a green 5)
	X;  (make block ^a red 6)
	X;  (make block ^a red 7)
	X;  (make block ^a yellow 8)
	X;  (make block ^a blue 9)
	X;  )
	X
	X
	XCLSUP.LIS
	X
	X;Common Lisp Support Functions: 
	X;These functions are not defined in vanilla Common Lisp, but are used
	X;in the OPSMODS.l code and in OPS5.  
	X
	X(defun putprop(name val att)
	X   (setf (get name att) val))
	X
	X(defun memq(obj lis)
	X    (member obj lis :test #'eq))
	X
	X(defun fix(num)
	X    (round num))
	X    
	X
	X(defun assq(item alist)
	X     (assoc item alist :test #'eq))
	X
	X(defun ncons(x) (cons x nil))
	X
	X(defun neq(x y) (not (eq x y)))
	X
	X(defun delq(obj list)
	X   (delete obj list :test #'eq))
	X
	X(defmacro comment(&optional &rest x) nil) ;comment is a noop
	X
	X(defun plus(x y)
	X   (+ x y))
	X
	X(defun quotient(x y)
	X   (/ x y))
	X
	X(defun flatc(x)
	X   (length (princ-to-string x)))
	X
	X
	X
	XCOMMON.OPS
	X
	X;	VPS2 -- Interpreter for OPS5
	X;
	X;	Copyright (C) 1979, 1980, 1981
	X;	Charles L. Forgy,  Pittsburgh, Pennsylvania
	X
	X
	X
	X; Users of this interpreter are requested to contact
	X
	X;
	X;	Charles Forgy
	X;	Computer Science Department
	X;	Carnegie-Mellon University
	X;	Pittsburgh, PA  15213
	X; or
	X;	Forgy@CMUA
	X; 
	X; so that they can be added to the mailing list for OPS5.  The mailing list
	X; is needed when new versions of the interpreter or manual are released.
	X
	X
	X
	X;;; Definitions
	X
	X#+ vax (defun putprop(name val att)
	X   (setf (get name att) val))
	X
	X
	X
	X(proclaim '(special *matrix* *feature-count* *pcount* *vars* *cur-vars*
	X          *curcond* *subnum* *last-node* *last-branch* *first-node*
	X          *sendtocall* *flag-part* *alpha-flag-part* *data-part*
	X          *alpha-data-part* *ce-vars* *virtual-cnt* *real-cnt*
	X          *current-token* *c1* *c2* *c3* *c4* *c5* *c6* *c7* *c8* *c9*
	X          *c10* *c11* *c12* *c13* *c14* *c15* *c16* *c17* *c18* *c19*
	X          *c20* *c21* *c22* *c23* *c24* *c25* *c26* *c27* *c28* *c29*
	X          *c30* *c31* *c32* *c33* *c34* *c35* *c36* *c37* *c38* *c39*
	X          *c40* *c41* *c42* *c43* *c44* *c45* *c46* *c47* *c48* *c49*
	X          *c50* *c51* *c52* *c53* *c54* *c55* *c56* *c57* *c58* *c59*
	X          *c60* *c61* *c62* *c63* *c64* *record-array* *result-array* 
	X          *max-cs* *total-cs* *limit-cs* *cr-temp* *side*
	X          *conflict-set* *halt-flag* *phase* *critical*
	X          *cycle-count* *total-token* *max-token* *refracts* 
	X          *limit-token* *total-wm* *current-wm* *max-wm*
	X          *action-count* *wmpart-list* *wm* *data-matched* *p-name*
	X          *variable-memory* *ce-variable-memory* 
	X          *max-index* ; number of right-most field in wm element 
	X          *next-index* *size-result-array* *rest* *build-trace* *last*
	X          *ptrace* *wtrace* *in-rhs* *recording* *accept-file* *trace-file* 
	X          *mtrace* *madeby* ; used to trace and record makers of elements
	X          *write-file* *record-index* *max-record-index* *old-wm*
	X          *record* *filters* *break-flag* *strategy* *remaining-cycles*
	X	  *wm-filter* *rhs-bound-vars* *rhs-bound-ce-vars* *ppline* 
	X	  *ce-count* *brkpts* *class-list* *buckets* *action-type*
	X          *literals*   ;stores literal definitions
	X          *pnames*     ;stores production names
	X	  *externals*  ;tracks external declarations 
	X          *vector-attributes*  ;list of vector-attributes
	X	  ))
	X
	X;(declare (localf ce-gelm gelm peek-sublex sublex
	X;          eval-nodelist sendto and-left and-right not-left not-right
	X;          top-levels-eq add-token real-add-token remove-old
	X;          remove-old-num remove-old-no-num removecs insertcs dsort
	X;          best-of best-of* conflict-set-compare =alg ))
	X
	X
	X;;; Functions that were revised so that they would compile efficiently
	X
	X
	X;* The function == is machine dependent\!
	X;* This function compares small integers for equality.  It uses EQ
	X;* so that it will be fast, and it will consequently not work on all
	X;* Lisps.  It works in Franz Lisp for integers in [-128, 127]
	X
	X
	X;(defun == (&rest z) (= (cadr z) (caddr z)))
	X(defun == (x y) (= x y))
	X
	X; =ALG returns T if A and B are algebraicly equal.
	X
	X(defun =alg (a b) (= a b))
	X
	X(defmacro fast-symeval (&rest z)
	X	 `(cond ((eq ,(car z) '*c1*) *c1*)
	X		((eq ,(car z) '*c2*) *c2*)
	X		((eq ,(car z) '*c3*) *c3*)
	X		((eq ,(car z) '*c4*) *c4*)
	X		((eq ,(car z) '*c5*) *c5*)
	X		((eq ,(car z) '*c6*) *c6*)
	X		((eq ,(car z) '*c7*) *c7*)
	X		(t (eval ,(car z)))  ))
	X
	X; getvector and putvector are fast routines for using one-dimensional
	X; arrays.  these routines do no checking; they assume
	X;	1. the array is a vector with 0 being the index of the first
	X;	   element
	X;	2. the vector holds arbitrary list values
	X;defun versions are useful for tracing
	X
	X; Example call: (putvector array index value)
	X
	X(defmacro putvector (array_ref ind var)
	X      `(setf (aref ,array_ref ,ind) ,var))
	X
	X;(defun putvector (array_ref ind var)
	X;      (setf (aref array_ref ind) var))
	X
	X; Example call: (getvector name index)
	X
	X;(defmacro getvector(&rest z)
	X;     (list 'cxr (caddr z) (cadr z)))
	X
	X(defmacro getvector(array_ref ind)
	X      `(aref ,array_ref ,ind))
	X
	X;(defun getvector (array_ref ind)
	X ;       (aref array_ref ind))
	X
	X(defun ce-gelm (x k)
	X  (prog nil
	X   loop (and (== k 1.) (return (car x)))
	X        (setq k (1- k))
	X        (setq x (cdr x))
	X        (go loop))) 
	X
	X; The loops in gelm were unwound so that fewer calls on DIFFERENCE
	X; would be needed
	X
	X(defun gelm (x k)
	X  (prog (ce sub)
	X        (setq ce  (floor (/ k 10000)))
	X        (setq sub (- k (* ce 10000)))
	X celoop (and (== ce 0) (go ph2))
	X        (setq x (cdr x))
	X        (and (== ce 1) (go ph2))
	X        (setq x (cdr x))
	X        (and (== ce 2) (go ph2))
	X        (setq x (cdr x))
	X        (and (== ce 3) (go ph2))
	X        (setq x (cdr x))
	X        (and (== ce 4) (go ph2))
	X        (setq ce (- ce 4))
	X        (go celoop)
	X   ph2  (setq x (car x))
	X   subloop (and (== sub 0) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 1) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 2) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 3) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 4) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 5) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 6) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 7) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 8) (go finis))
	X        (setq sub (- sub 8))
	X        (go subloop)
	X   finis (return (car x)))) 
	X
	X
	X;;; Utility functions
	X
	X
	X
	X(defun printline (x) (mapc (function printline*) x)) 
	X
	X(defun printline* (y) (princ '| |) (print y)) 
	X
	X(defun printlinec (x) (mapc (function printlinec*) x)) 
	X
	X(defun printlinec* (y) (princ '| |) (princ y)) 
	X
	X; intersect two lists using eq for the equality test
	X
	X(defun interq (x y)
	X  (intersection x y :test #'eq))
	X
	X(defun enter (x ll)
	X   (and (not (member x ll :test #'equal))
	X       (push x ll)))
	X
	X
	X;Hack read-macro tables to accept single characters -- right out of CL book.
	X(defun single-macro-character (stream char)
	X   (declare (ignore stream))
	X   (character char))
	X
	X(defun i-g-v nil
	X (prog (x)
	X        (set-macro-character #\{ #'single-macro-character )
	X        (set-macro-character #\} #'single-macro-character )
	X        (set-macro-character #\^ #'single-macro-character )
	X;	(setsyntax '\{ 66.) ;These are already normal characters in CL
	X;	(setsyntax '\} 66.)
	X;	(setsyntax '^ 66.)
	X	(setq *buckets* 64.)		; OPS5 allows 64 named slots
	X	(setq *accept-file* nil)
	X	(setq *write-file* nil)
	X	(setq *trace-file* nil)
	X        (and (boundp '*class-list*)
	X          (mapc #'(lambda(class) (putprop class nil 'att-list)) *class-list*))
	X	(setq *class-list* nil)
	X	(setq *brkpts* nil)
	X	(setq *strategy* 'lex)
	X  	(setq *in-rhs* nil)
	X  	(setq *ptrace* t)
	X  	(setq *wtrace* nil)
	X	(setq *mtrace* t)            ; turn on made-by tracing
	X	(setq *madeby* nil)          ; record makers of wm elements
	X  	(setq *recording* nil)
	X        (setq *refracts* nil)
	X	(setq *real-cnt* (setq *virtual-cnt* 0.))
	X	(setq *max-cs* (setq *total-cs* 0.))
	X  	(setq *limit-token* 1000000.)
	X	(setq *limit-cs* 1000000.)
	X	(setq *critical* nil)
	X	(setq *build-trace* nil)
	X	(setq *wmpart-list* nil)
	X        (setq *pnames* nil)
	X        (setq *literals* nil) ; records literal definitions
	X	(setq *externals* nil) ; records external definitions
	X	(setq *vector-attributes* nil) ;records vector attributes
	X	(setq *size-result-array* 127.)
	X	(setq *result-array* (make-array 128))
	X	(setq *record-array* (make-array 128))
	X	(setq x 0)
	X        (setq *pnames* nil)     ; list of production names
	X  loop	(putvector *result-array* x nil)
	X	(setq x (1+ x))
	X	(and (not (> x *size-result-array*)) (go loop))
	X	(make-bottom-node)
	X	(setq *pcount* 0.)
	X	(initialize-record)
	X	(setq *cycle-count* (setq *action-count* 0.))
	X	(setq *total-token*
	X	       (setq *max-token* (setq *current-token* 0.)))
	X	(setq *total-cs* (setq *max-cs* 0.))
	X	(setq *total-wm* (setq *max-wm* (setq *current-wm* 0.)))
	X	(setq *conflict-set* nil)
	X	(setq *wmpart-list* nil)
	X	(setq *p-name* nil)
	X	(setq *remaining-cycles* 1000000)
	X))
	X
	X; if the size of result-array changes, change the line in i-g-v which
	X; sets the value of *size-result-array*
	X
	X(defun %warn (what where)
	X  (prog nil
	X    (terpri)
	X    (princ '?)
	X    (and *p-name* (princ *p-name*))
	X    (princ '|..|)
	X    (princ where)
	X    (princ '|..|)
	X    (princ what)
	X    (return where))) 
	X
	X(defun %error (what where)
	X    (%warn what where)
	X    (throw '!error! nil)) 
	X
	X
	X(defun top-levels-eq (la lb)
	X  (prog nil
	X   lx   (cond ((eq la lb) (return t))
	X              ((null la) (return nil))
	X              ((null lb) (return nil))
	X              ((not (eq (car la) (car lb))) (return nil)))
	X        (setq la (cdr la))
	X        (setq lb (cdr lb))
	X        (go lx))) 
	X
	X
	X;;; LITERAL and LITERALIZE
	X
	X(defmacro literal (&rest z)
	X  `(prog (atm val old args)
	X        (setq args ',z)
	X   top  (and (atom args) (return 'bound))
	X        (or (eq (cadr args) '=) (return (%warn '|wrong format| args)))
	X        (setq atm (car args))
	X        (setq val (caddr args))
	X        (setq args (cdddr args))
	X        (cond ((not (numberp val))
	X               (%warn '|can bind only to numbers| val))
	X              ((or (not (symbolp atm)) (variablep atm))
	X                (%warn '|can bind only constant atoms| atm))
	X              ((and (setq old (literal-binding-of atm)) (not (equal old val)))
	X               (%warn '|attempt to rebind attribute| atm))
	X              (t (putprop atm val 'ops-bind )))
	X        (go top))) 
	X
	X(defmacro literalize (&rest l)
	X  `(prog (class-name atts)
	X    (setq class-name (car ',l))
	X    (cond ((have-compiled-production)
	X           (%warn '|literalize called after p| class-name)
	X           (return nil))
	X          ((get class-name 'att-list)
	X           (%warn '|attempt to redefine class| class-name)
	X	   (return nil)))
	X    (setq *class-list* (cons class-name *class-list*))
	X    (setq atts (remove-duplicates (cdr ',l)))
	X    (test-attribute-names atts)
	X    (mark-conflicts atts atts)
	X    (putprop class-name  atts 'att-list))) 
	X
	X(defmacro vector-attribute  (&rest l)
	X  `(cond ((have-compiled-production)
	X         (%warn '|vector-attribute called after p| ',l))
	X        (t 
	X         (test-attribute-names ',l)
	X	 (mapc (function vector-attribute2) ',l)))) 
	X
	X(defun vector-attribute2 (att) (putprop att t 'vector-attribute)
	X			       (setq  *vector-attributes* 
	X				   (enter att *vector-attributes*)))
	X
	X(defun is-vector-attribute (att) (get att 'vector-attribute))
	X
	X(defun test-attribute-names (l)
	X  (mapc (function test-attribute-names2) l)) 
	X
	X(defun test-attribute-names2 (atm)
	X  (cond ((or (not (symbolp atm)) (variablep atm))
	X         (%warn '|can bind only constant atoms| atm)))) 
	X
	X(defun finish-literalize nil
	X  (cond ((not (null *class-list*))
	X         (mapc (function note-user-assigns) *class-list*)
	X         (mapc (function assign-scalars) *class-list*)
	X         (mapc (function assign-vectors) *class-list*)
	X         (mapc (function put-ppdat) *class-list*)
	X         (mapc (function erase-literal-info) *class-list*)
	X         (setq *class-list* nil)
	X         (setq *buckets* nil)))) 
	X
	X(defun have-compiled-production nil (not (zerop *pcount*))) 
	X
	X(defun put-ppdat (class)
	X  (prog (al att ppdat)
	X        (setq ppdat nil)
	X        (setq al (get class 'att-list))
	X   top  (cond ((not (atom al))
	X               (setq att (car al))
	X               (setq al (cdr al))
	X               (setq ppdat
	X                     (cons (cons (literal-binding-of att) att)
	X                           ppdat))
	X               (go top)))
	X        (putprop class ppdat 'ppdat))) 
	X
	X; note-user-assigns and note-user-vector-assigns are needed only when
	X; literal and literalize are both used in a program.  They make sure that
	X; the assignments that are made explicitly with literal do not cause problems
	X; for the literalized classes.
	X
	X(defun note-user-assigns (class)
	X  (mapc (function note-user-assigns2) (get class 'att-list)))
	X
	X(defun note-user-assigns2 (att)
	X  (prog (num conf buck clash)
	X        (setq num (literal-binding-of att))
	X	(and (null num) (return nil))
	X	(setq conf (get att 'conflicts))
	X	(setq buck (store-binding att num))
	X	(setq clash (find-common-atom buck conf))
	X	(and clash
	X	     (%warn '|attributes in a class assigned the same number|
	X	            (cons att clash)))
	X        (return nil)))
	X
	X(defun note-user-vector-assigns (att given needed)
	X  (and (> needed given)
	X       (%warn '|vector attribute assigned too small a value in literal| att)))
	X
	X(defun assign-scalars (class)
	X  (mapc (function assign-scalars2) (get class 'att-list))) 
	X
	X(defun assign-scalars2 (att)
	X  (prog (tlist num bucket conf)
	X        (and (literal-binding-of att) (return nil))
	X        (and (is-vector-attribute att) (return nil))
	X        (setq tlist (buckets))
	X        (setq conf (get att 'conflicts))
	X   top  (cond ((atom tlist)
	X               (%warn '|could not generate a binding| att)
	X               (store-binding att -1.)
	X               (return nil)))
	X        (setq num (caar tlist))
	X        (setq bucket (cdar tlist))
	X        (setq tlist (cdr tlist))
	X        (cond ((disjoint bucket conf) (store-binding att num))
	X        (t (go top))))) 
	X
	X(defun assign-vectors (class)
	X  (mapc (function assign-vectors2) (get class 'att-list))) 
	X
	X(defun assign-vectors2 (att)
	X  (prog (big conf new old need)
	X        (and (not (is-vector-attribute att)) (return nil))
	X        (setq big 1.)
	X        (setq conf (get att 'conflicts))
	X   top  (cond ((not (atom conf))
	X               (setq new (car conf))
	X               (setq conf (cdr conf))
	X               (cond ((is-vector-attribute new)
	X                      (%warn '|class has two vector attributes|
	X		              (list att new)))
	X                     (t (setq big (max (literal-binding-of new) big))))
	X               (go top)))
	X        (setq need (1+ big))
	X	(setq old (literal-binding-of att))
	X	(cond (old (note-user-vector-assigns att old need))
	X	      (t (store-binding att need)))
	X        (return nil)))
	X
	X(defun disjoint (la lb) (not (find-common-atom la lb))) 
	X
	X(defun find-common-atom (la lb)
	X  (prog nil
	X   top  (cond ((null la) (return nil))
	X              ((member (car la) lb :test #'eq) (return (car la)))
	X              (t (setq la (cdr la)) (go top))))) 
	X
	X(defun mark-conflicts (rem all)
	X  (cond ((not (null rem))
	X         (mark-conflicts2 (car rem) all)
	X         (mark-conflicts (cdr rem) all)))) 
	X
	X(defun mark-conflicts2 (atm lst)
	X  (prog (l)
	X        (setq l lst)
	X   top  (and (atom l) (return nil))
	X        (conflict atm (car l))
	X        (setq l (cdr l))
	X        (go top))) 
	X
	X(defun conflict (a b)
	X  (prog (old)
	X    (setq old (get a 'conflicts))
	X    (and (not (eq a b))
	X         (not (member b old :test #'eq))
	X         (putprop a (cons b old) 'conflicts )))) 
	X
	X;(defun remove-duplicates (lst)
	X;  (cond ((atom lst) nil)
	X;        ((member (car lst) (cdr lst) :test #'eq) (remove-duplicates (cdr lst)))
	X;        (t (cons (car lst) (remove-duplicates (cdr lst)))))) 
	X
	X(defun literal-binding-of (name) (get name 'ops-bind)) 
	X
	X(defun store-binding (name lit)
	X  (putprop name lit 'ops-bind)
	X  (add-bucket name lit)) 
	X
	X(defun add-bucket (name num)
	X  (prog (buc)
	X    (setq buc (assoc num (buckets)))
	X    (and (not (member name buc :test #'eq))
	X         (rplacd buc (cons name (cdr buc))))
	X    (return buc))) 
	X
	X(defun buckets nil
	X  (and (atom *buckets*) (setq *buckets* (make-nums *buckets*)))
	X  *buckets*) 
	X
	X(defun make-nums (k)
	X  (prog (nums)
	X        (setq nums nil)
	X   l    (and (< k 2.) (return nums))
	X        (setq nums (cons (cons k nil) nums))
	X        (setq k (1- k))
	X        (go l))) 
	X
	X;(defun erase-literal-info (class)
	X;  (mapc (function erase-literal-info2) (get class 'att-list))
	X;  (remprop class 'att-list)) 
	X
	X; modified to record literal info in the variable *literals*
	X(defun erase-literal-info (class)
	X      (setq *literals*
	X            (cons (cons class (get class 'att-list)) *literals*))
	X      (mapc (function erase-literal-info2) (get class 'att-list))
	X      (remprop class 'att-list))
	X
	X
	X(defun erase-literal-info2 (att) (remprop att 'conflicts)) 
	X
	X
	X;;; LHS Compiler
	X
	X(defmacro p (&rest z) 
	X `(progn 
	X   (finish-literalize)
	X   (princ '*) 
	X  ;(drain);drain probably drains a line feed
	X   (compile-production (car ',z) (cdr ',z)))) 
	X
	X(defun compile-production (name matrix)
	X  (prog (erm)
	X        (setq *p-name* name)
	X        (setq erm (catch '!error! (cmp-p name matrix) ))
	X	; following line is modified to save production name on *pnames*
	X        (and (null erm) (setq *pnames* (enter name *pnames*)))
	X	(setq *p-name* nil)
	X	(return erm)))
	X
	X(defun peek-lex nil (car *matrix*)) 
	X
	X(defun lex nil
	X  (prog2 nil (car *matrix*) (setq *matrix* (cdr *matrix*)))) 
	X
	X(defun end-of-p nil (atom *matrix*)) 
	X
	X(defun rest-of-p nil *matrix*) 
	X
	X(defun prepare-lex (prod) (setq *matrix* prod)) 
	X
	X
	X(defun peek-sublex nil (car *curcond*)) 
	X
	X(defun sublex nil
	X  (prog2 nil (car *curcond*) (setq *curcond* (cdr *curcond*)))) 
	X
	X(defun end-of-ce nil (atom *curcond*)) 
	X
	X(defun rest-of-ce nil *curcond*) 
	X
	X(defun prepare-sublex (ce) (setq *curcond* ce)) 
	X
	X(defun make-bottom-node nil (setq *first-node* (list '&bus nil))) 
	X
	X(defun cmp-p (name matrix)
	X  (prog (m bakptrs)
	X        (cond ((or (null name) (listp name))
	X               (%error '|illegal production name| name))
	X              ((equal (get name 'production) matrix)
	X	       (return nil)))
	X        (prepare-lex matrix)
	X        (excise-p name)
	X        (setq bakptrs nil)
	X        (setq *pcount* (1+ *pcount*))
	X        (setq *feature-count* 0.)
	X	(setq *ce-count* 0)
	X        (setq *vars* nil)
	X        (setq *ce-vars* nil)
	X	(setq *rhs-bound-vars* nil)
	X	(setq *rhs-bound-ce-vars* nil)
	X        (setq *last-branch* nil)
	X        (setq m (rest-of-p))
	X   l1   (and (end-of-p) (%error '|no '-->' in production| m))
	X        (cmp-prin)
	X        (setq bakptrs (cons *last-branch* bakptrs))
	X        (or (eq '--> (peek-lex)) (go l1))
	X        (lex)
	X	(check-rhs (rest-of-p))
	X        (link-new-node (list '&p
	X                             *feature-count*
	X                             name
	X                             (encode-dope)
	X                             (encode-ce-dope)
	X                             (cons 'progn (rest-of-p))))
	X        (putprop name (cdr (nreverse bakptrs)) 'backpointers )
	X	(putprop name matrix 'production)
	X        (putprop name *last-node* 'topnode))) 
	X
	X(defun rating-part (pnode) (cadr pnode)) 
	X
	X(defun var-part (pnode) (car (cdddr pnode))) 
	X
	X(defun ce-var-part (pnode) (cadr (cdddr pnode))) 
	X
	X(defun rhs-part (pnode) (caddr (cdddr pnode))) 
	X
	X(defun excise-p (name)
	X  (cond ((and (symbolp name) (get name 'topnode))
	X	 (printline (list name 'is 'excised))
	X         (setq *pcount* (1- *pcount*))
	X         (remove-from-conflict-set name)
	X         (kill-node (get name 'topnode))
	X         (setq *pnames* (delete name *pnames* :test #'eq))
	X	 (remprop name 'production)
	X	 (remprop name 'backpointers)
	X         (remprop name 'topnode)))) 
	X
	X(defun kill-node (node)
	X  (prog nil
	X   top  (and (atom node) (return nil))
	X        (rplaca node '&old)
	X        (setq node (cdr node))
	X        (go top))) 
	X
	X(defun cmp-prin nil
	X  (prog nil
	X        (setq *last-node* *first-node*)
	X        (cond ((null *last-branch*) (cmp-posce) (cmp-nobeta))
	X              ((eq (peek-lex) '-) (cmp-negce) (cmp-not))
	X              (t (cmp-posce) (cmp-and))))) 
	X
	X(defun cmp-negce nil (lex) (cmp-ce)) 
	X
	X(defun cmp-posce nil
	X  (setq *ce-count* (1+ *ce-count*))
	X  (cond ((eq (peek-lex) #\{) (cmp-ce+cevar))
	X        (t (cmp-ce)))) 
	X
	X(defun cmp-ce+cevar nil
	X  (prog (z)
	X        (lex)
	X        (cond ((atom (peek-lex)) (cmp-cevar) (cmp-ce))
	X              (t (cmp-ce) (cmp-cevar)))
	X        (setq z (lex))
	X        (or (eq z #\}) (%error '|missing '}'| z)))) 
	X
	X(defun new-subnum (k)
	X  (or (numberp k) (%error '|tab must be a number| k))
	X  (setq *subnum* (round k))) 
	X
	X(defun incr-subnum nil (setq *subnum* (1+ *subnum*))) 
	X
	X(defun cmp-ce nil
	X  (prog (z)
	X        (new-subnum 0.)
	X        (setq *cur-vars* nil)
	X        (setq z (lex))
	X        (and (atom z)
	X             (%error '|atomic conditions are not allowed| z))
	X        (prepare-sublex z)
	X   la   (and (end-of-ce) (return nil))
	X        (incr-subnum)
	X        (cmp-element)
	X        (go la))) 
	X
	X(defun cmp-element nil
	X        (and (eq (peek-sublex) #\^) (cmp-tab))
	X        (cond ((eq (peek-sublex) '#\{) (cmp-product))
	X              (t (cmp-atomic-or-any))))
	X
	X(defun cmp-atomic-or-any nil
	X        (cond ((eq (peek-sublex) '<<) (cmp-any))
	X              (t (cmp-atomic))))
	X
	X(defun cmp-any nil
	X  (prog (a z)
	X        (sublex)
	X        (setq z nil)
	X   la   (cond ((end-of-ce) (%error '|missing '>>'| a)))
	X        (setq a (sublex))
	X        (cond ((not (eq '>> a)) (setq z (cons a z)) (go la)))
	X        (link-new-node (list '&any nil (current-field) z)))) 
	X
	X
	X(defun cmp-tab nil
	X  (prog (r)
	X        (sublex)
	X        (setq r (sublex))
	X        (setq r ($litbind r))
	X        (new-subnum r))) 
	X
	X(defun $litbind (x)
	X  (prog (r)
	X        (cond ((and (symbolp x) (setq r (literal-binding-of x)))
	X               (return r))
	X              (t (return x))))) 
	X
	X(defun get-bind (x)
	X  (prog (r)
	X        (cond ((and (symbolp x) (setq r (literal-binding-of x)))
	X               (return r))
	X              (t (return nil))))) 
	X
	X(defun cmp-atomic nil
	X  (prog (test x)
	X        (setq x (peek-sublex))
	X        (cond ((eq x '=) (setq test 'eq) (sublex))
	X              ((eq x '<>) (setq test 'ne) (sublex))
	X              ((eq x '<) (setq test 'lt) (sublex))
	X              ((eq x '<=) (setq test 'le) (sublex))
	X              ((eq x '>) (setq test 'gt) (sublex))
	X              ((eq x '>=) (setq test 'ge) (sublex))
	X              ((eq x '<=>) (setq test 'xx) (sublex))
	X              (t (setq test 'eq)))
	X        (cmp-symbol test))) 
	X
	X(defun cmp-product nil
	X  (prog (save)
	X        (setq save (rest-of-ce))
	X        (sublex)
	X   la   (cond ((end-of-ce)
	X               (cond ((member #\} save) 
	X		      (%error '|wrong contex for '}'| save))
	X		     (t (%error '|missing '}'| save))))
	X              ((eq (peek-sublex) #\}) (sublex) (return nil)))
	X        (cmp-atomic-or-any)
	X        (go la))) 
	X
	X(defun variablep (x) (and (symbolp x) (char-equal (char (symbol-name x) 0) #\<))) 
	X
	X(defun cmp-symbol (test)
	X  (prog (flag)
	X        (setq flag t)
	X        (cond ((eq (peek-sublex) '//) (sublex) (setq flag nil)))
	X        (cond ((and flag (variablep (peek-sublex)))
	X               (cmp-var test))
	X              ((numberp (peek-sublex)) (cmp-number test))
	X              ((symbolp (peek-sublex)) (cmp-constant test))
	X              (t (%error '|unrecognized symbol| (sublex)))))) 
	X
	X(defun concat3(x y z)
	X   (intern (format nil "~s~s~s" x y z)))
	X
	X(defun cmp-constant (test)
	X  (or (member test '(eq ne xx) )
	X      (%error '|non-numeric constant after numeric predicate| (sublex)))
	X  (link-new-node (list (concat3 't test 'a)
	X                       nil
	X                       (current-field)
	X                       (sublex)))) 
	X
	X
	X(defun cmp-number (test)
	X  (link-new-node (list (concat3 't test 'n)
	X                       nil
	X                       (current-field)
	X                       (sublex)))) 
	X
	X(defun current-field nil (field-name *subnum*)) 
	X
	X(defun field-name (num)
	X  (cond ((= num 1.) '*c1*)
	X        ((= num 2.) '*c2*)
	X        ((= num 3.) '*c3*)
	X        ((= num 4.) '*c4*)
	X        ((= num 5.) '*c5*)
	X        ((= num 6.) '*c6*)
	X        ((= num 7.) '*c7*)
	X        ((= num 8.) '*c8*)
	X        ((= num 9.) '*c9*)
	X        ((= num 10.) '*c10*)
	X        ((= num 11.) '*c11*)
	X        ((= num 12.) '*c12*)
	X        ((= num 13.) '*c13*)
	X        ((= num 14.) '*c14*)
	X        ((= num 15.) '*c15*)
	X        ((= num 16.) '*c16*)
	X        ((= num 17.) '*c17*)
	X        ((= num 18.) '*c18*)
	X        ((= num 19.) '*c19*)
	X        ((= num 20.) '*c20*)
	X        ((= num 21.) '*c21*)
	X        ((= num 22.) '*c22*)
	X        ((= num 23.) '*c23*)
	X        ((= num 24.) '*c24*)
	X        ((= num 25.) '*c25*)
	X        ((= num 26.) '*c26*)
	X        ((= num 27.) '*c27*)
	X        ((= num 28.) '*c28*)
	X        ((= num 29.) '*c29*)
	X        ((= num 30.) '*c30*)
	X        ((= num 31.) '*c31*)
	X        ((= num 32.) '*c32*)
	X        ((= num 33.) '*c33*)
	X        ((= num 34.) '*c34*)
	X        ((= num 35.) '*c35*)
	X        ((= num 36.) '*c36*)
	X        ((= num 37.) '*c37*)
	X        ((= num 38.) '*c38*)
	X        ((= num 39.) '*c39*)
	X        ((= num 40.) '*c40*)
	X        ((= num 41.) '*c41*)
	X        ((= num 42.) '*c42*)
	X        ((= num 43.) '*c43*)
	X        ((= num 44.) '*c44*)
	X        ((= num 45.) '*c45*)
	X        ((= num 46.) '*c46*)
	X        ((= num 47.) '*c47*)
	X        ((= num 48.) '*c48*)
	X        ((= num 49.) '*c49*)
	X        ((= num 50.) '*c50*)
	X        ((= num 51.) '*c51*)
	X        ((= num 52.) '*c52*)
	X        ((= num 53.) '*c53*)
	X        ((= num 54.) '*c54*)
	X        ((= num 55.) '*c55*)
	X        ((= num 56.) '*c56*)
	X        ((= num 57.) '*c57*)
	X        ((= num 58.) '*c58*)
	X        ((= num 59.) '*c59*)
	X        ((= num 60.) '*c60*)
	X        ((= num 61.) '*c61*)
	X        ((= num 62.) '*c62*)
	X        ((= num 63.) '*c63*)
	X        ((= num 64.) '*c64*)
	X        (t (%error '|condition is too long| (rest-of-ce))))) 
	X
	X
	X;;; Compiling variables
	X;
	X;
	X;
	X; *cur-vars* are the variables in the condition element currently 
	X; being compiled.  *vars* are the variables in the earlier condition
	X; elements.  *ce-vars* are the condition element variables.  note
	X; that the interpreter will not confuse condition element and regular
	X; variables even if they have the same name.
	X;
	X; *cur-vars* is a list of triples: (name predicate subelement-number)
	X; eg:		( (<x> eq 3)
	X;		  (<y> ne 1)
	X;		  . . . )
	X;
	X; *vars* is a list of triples: (name ce-number subelement-number)
	X; eg:		( (<x> 3 3)
	X;		  (<y> 1 1)
	X;		  . . . )
	X;
	X; *ce-vars* is a list of pairs: (name ce-number)
	X; eg:		( (ce1 1)
	X;		  (<c3> 3)
	X;		  . . . )
	X
	X(defun var-dope (var) (assoc var *vars* :test #'eq))
	X
	X(defun ce-var-dope (var) (assoc var *ce-vars* :test #'eq))
	X
	X(defun cmp-var (test)
	X  (prog (old name)
	X        (setq name (sublex))
	X        (setq old (assoc name *cur-vars* :test #'eq))
	X        (cond ((and old (eq (cadr old) 'eq))
	X               (cmp-old-eq-var test old))
	X              ((and old (eq test 'eq)) (cmp-new-eq-var name old))
	X              (t (cmp-new-var name test))))) 
	X
	X(defun cmp-new-var (name test)
	X  (setq *cur-vars* (cons (list name test *subnum*) *cur-vars*))) 
	X
	X(defun cmp-old-eq-var (test old)
	X  (link-new-node (list (concat3 't test 's)
	X                       nil
	X                       (current-field)
	X                       (field-name (caddr old))))) 
	X
	X(defun cmp-new-eq-var (name old)
	X  (prog (pred next)
	X        (setq *cur-vars* (delete old *cur-vars* :test #'eq))
	X        (setq next (assoc name *cur-vars* :test #'eq))
	X        (cond (next (cmp-new-eq-var name next))
	X              (t (cmp-new-var name 'eq)))
	X        (setq pred (cadr old))
	X        (link-new-node (list (concat3 't pred 's)
	X                             nil
	X                             (field-name (caddr old))
	X                             (current-field))))) 
	X
	X(defun cmp-cevar nil
	X  (prog (name old)
	X        (setq name (lex))
	X        (setq old (assoc name *ce-vars* :test #'eq))
	X        (and old
	X             (%error '|condition element variable used twice| name))
	X        (setq *ce-vars* (cons (list name 0.) *ce-vars*)))) 
	X
	X(defun cmp-not nil (cmp-beta '&not)) 
	X
	X(defun cmp-nobeta nil (cmp-beta nil)) 
	X
	X(defun cmp-and nil (cmp-beta '&and)) 
	X
	X(defun cmp-beta (kind)
	X  (prog (tlist vdope vname vpred vpos old)
	X        (setq tlist nil)
	X   la   (and (atom *cur-vars*) (go lb))
	X        (setq vdope (car *cur-vars*))
	X        (setq *cur-vars* (cdr *cur-vars*))
	X        (setq vname (car vdope))
	X        (setq vpred (cadr vdope))
	X        (setq vpos (caddr vdope))
	X        (setq old (assoc vname *vars* :test #'eq))
	X        (cond (old (setq tlist (add-test tlist vdope old)))
	X              ((not (eq kind '&not)) (promote-var vdope)))
	X        (go la)
	X   lb   (and kind (build-beta kind tlist))
	X        (or (eq kind '&not) (fudge))
	X        (setq *last-branch* *last-node*))) 
	X
	X(defun add-test (list new old)
	X  (prog (ttype lloc rloc)
	X	(setq *feature-count* (1+ *feature-count*))
	X        (setq ttype (concat3 't (cadr new) 'b))
	X        (setq rloc (encode-singleton (caddr new)))
	X        (setq lloc (encode-pair (cadr old) (caddr old)))
	X        (return (cons ttype (cons lloc (cons rloc list)))))) 
	X
-- 
---------------
C'est la vie, C'est la guerre, C'est la pomme de terre
Mail:	Imagen Corp. 2650 San Tomas Expressway Santa Clara, CA 95052-8101 
UUCP:	...{decvax,ucbvax}!decwrl!imagen!turner      AT&T: (408) 986-9400

turner@imagen.UUCP (D'arc Angel) (01/19/87)

	X; the following two functions encode indices so that gelm can
	X; decode them as fast as possible
	X
	X(defun encode-pair (a b) (+ (* 10000. (1- a)) (1- b))) 
	X
	X(defun encode-singleton (a) (1- a)) 
	X
	X(defun promote-var (dope)
	X  (prog (vname vpred vpos new)
	X        (setq vname (car dope))
	X        (setq vpred (cadr dope))
	X        (setq vpos (caddr dope))
	X        (or (eq 'eq vpred)
	X            (%error '|illegal predicate for first occurrence|
	X                   (list vname vpred)))
	X        (setq new (list vname 0. vpos))
	X        (setq *vars* (cons new *vars*)))) 
	X
	X(defun fudge nil
	X  (mapc (function fudge*) *vars*)
	X  (mapc (function fudge*) *ce-vars*)) 
	X
	X(defun fudge* (z)
	X  (prog (a) (setq a (cdr z)) (rplaca a (1+ (car a))))) 
	X
	X(defun build-beta (type tests)
	X  (prog (rpred lpred lnode lef)
	X        (link-new-node (list '&mem nil nil (protomem)))
	X        (setq rpred *last-node*)
	X        (cond ((eq type '&and)
	X               (setq lnode (list '&mem nil nil (protomem))))
	X              (t (setq lnode (list '&two nil nil))))
	X        (setq lpred (link-to-branch lnode))
	X        (cond ((eq type '&and) (setq lef lpred))
	X              (t (setq lef (protomem))))
	X        (link-new-beta-node (list type nil lef rpred tests)))) 
	X
	X(defun protomem nil (list nil)) 
	X
	X(defun memory-part (mem-node) (car (cadddr mem-node))) 
	X
	X(defun encode-dope nil
	X  (prog (r all z k)
	X        (setq r nil)
	X        (setq all *vars*)
	X   la   (and (atom all) (return r))
	X        (setq z (car all))
	X        (setq all (cdr all))
	X        (setq k (encode-pair (cadr z) (caddr z)))
	X        (setq r (cons (car z) (cons k r)))
	X        (go la))) 
	X
	X(defun encode-ce-dope nil
	X  (prog (r all z k)
	X        (setq r nil)
	X        (setq all *ce-vars*)
	X   la   (and (atom all) (return r))
	X        (setq z (car all))
	X        (setq all (cdr all))
	X        (setq k (cadr z))
	X        (setq r (cons (car z) (cons k r)))
	X        (go la))) 
	X
	X
	X
	X;;; Linking the nodes
	X
	X(defun link-new-node (r)
	X  (cond ((not (member (car r) '(&p &mem &two &and &not)))
	X	 (setq *feature-count* (1+ *feature-count*))))
	X  (setq *virtual-cnt* (1+ *virtual-cnt*))
	X  (setq *last-node* (link-left *last-node* r))) 
	X
	X(defun link-to-branch (r)
	X  (setq *virtual-cnt* (1+ *virtual-cnt*))
	X  (setq *last-branch* (link-left *last-branch* r))) 
	X
	X(defun link-new-beta-node (r)
	X  (setq *virtual-cnt* (1+ *virtual-cnt*))
	X  (setq *last-node* (link-both *last-branch* *last-node* r))
	X  (setq *last-branch* *last-node*)) 
	X
	X(defun link-left (pred succ)
	X  (prog (a r)
	X        (setq a (left-outs pred))
	X        (setq r (find-equiv-node succ a))
	X        (and r (return r))
	X        (setq *real-cnt* (1+ *real-cnt*))
	X        (attach-left pred succ)
	X        (return succ))) 
	X
	X(defun link-both (left right succ)
	X  (prog (a r)
	X        (setq a (interq (left-outs left) (right-outs right)))
	X        (setq r (find-equiv-beta-node succ a))
	X        (and r (return r))
	X        (setq *real-cnt* (1+ *real-cnt*))
	X        (attach-left left succ)
	X        (attach-right right succ)
	X        (return succ))) 
	X
	X(defun attach-right (old new)
	X  (rplaca (cddr old) (cons new (caddr old)))) 
	X
	X(defun attach-left (old new)
	X  (rplaca (cdr old) (cons new (cadr old)))) 
	X
	X(defun right-outs (node) (caddr node)) 
	X
	X(defun left-outs (node) (cadr node)) 
	X
	X(defun find-equiv-node (node list)
	X  (prog (a)
	X        (setq a list)
	X   l1   (cond ((atom a) (return nil))
	X              ((equiv node (car a)) (return (car a))))
	X        (setq a (cdr a))
	X        (go l1))) 
	X
	X(defun find-equiv-beta-node (node list)
	X  (prog (a)
	X        (setq a list)
	X   l1   (cond ((atom a) (return nil))
	X              ((beta-equiv node (car a)) (return (car a))))
	X        (setq a (cdr a))
	X        (go l1))) 
	X
	X; do not look at the predecessor fields of beta nodes; they have to be
	X; identical because of the way the candidate nodes were found
	X
	X(defun equiv (a b)
	X  (and (eq (car a) (car b))
	X       (or (eq (car a) '&mem)
	X           (eq (car a) '&two)
	X           (equal (caddr a) (caddr b)))
	X       (equal (cdddr a) (cdddr b)))) 
	X
	X(defun beta-equiv (a b)
	X  (and (eq (car a) (car b))
	X       (equal (cddddr a) (cddddr b))
	X       (or (eq (car a) '&and) (equal (caddr a) (caddr b))))) 
	X
	X; the equivalence tests are set up to consider the contents of
	X; node memories, so they are ready for the build action
	X
	X;;; Network interpreter
	X
	X(defun match (flag wme)
	X  (sendto flag (list wme) 'left (list *first-node*)))
	X
	X; note that eval-nodelist is not set up to handle building
	X; productions.  would have to add something like ops4's build-flag
	X
	X(defun eval-nodelist (nl)
	X  (prog nil
	X   top  (and (not nl) (return nil))
	X        (setq *sendtocall* nil)
	X	(setq *last-node* (car nl))
	X        (apply (caar nl) (cdar nl))
	X        (setq nl (cdr nl))
	X        (go top))) 
	X
	X(defun sendto (flag data side nl)
	X  (prog nil
	X   top  (and (not nl) (return nil))
	X        (setq *side* side)
	X        (setq *flag-part* flag)
	X        (setq *data-part* data)
	X        (setq *sendtocall* t)
	X	(setq *last-node* (car nl))
	X        (apply (caar nl) (cdar nl))
	X        (setq nl (cdr nl))
	X        (go top))) 
	X
	X; &bus sets up the registers for the one-input nodes.  note that this
	X(defun &bus (outs)
	X  (prog (dp)
	X        (setq *alpha-flag-part* *flag-part*)
	X        (setq *alpha-data-part* *data-part*)
	X        (setq dp (car *data-part*))
	X        (setq *c1* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c2* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c3* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c4* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c5* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c6* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c7* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c8* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c9* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c10* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c11* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c12* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c13* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c14* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c15* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c16* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c17* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c18* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c19* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c20* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c21* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c22* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c23* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c24* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c25* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c26* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c27* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c28* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c29* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c30* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c31* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c32* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c33* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c34* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c35* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c36* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c37* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c38* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c39* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c40* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c41* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c42* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c43* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c44* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c45* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c46* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c47* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c48* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c49* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c50* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c51* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c52* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c53* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c54* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c55* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c56* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c57* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c58* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c59* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c60* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c61* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c62* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c63* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c64* (car dp))
	X        (eval-nodelist outs))) 
	X
	X(defun &any (outs register const-list)
	X  (prog (z c)
	X        (setq z (fast-symeval register))
	X        (cond ((numberp z) (go number)))
	X   symbol (cond ((null const-list) (return nil))
	X                ((eq (car const-list) z) (go ok))
	X                (t (setq const-list (cdr const-list)) (go symbol)))
	X   number (cond ((null const-list) (return nil))
	X                ((and (numberp (setq c (car const-list)))
	X                      (=alg c z))
	X                 (go ok))
	X                (t (setq const-list (cdr const-list)) (go number)))
	X   ok   (eval-nodelist outs))) 
	X
	X(defun teqa (outs register constant)
	X  (and (eq (fast-symeval register) constant) (eval-nodelist outs))) 
	X
	X(defun tnea (outs register constant)
	X  (and (not (eq (fast-symeval register) constant)) (eval-nodelist outs))) 
	X
	X(defun txxa (outs register constant)
	X  (and (symbolp (fast-symeval register)) (eval-nodelist outs))) 
	X
	X(defun teqn (outs register constant)
	X  (prog (z)
	X        (setq z (fast-symeval register))
	X        (and (numberp z)
	X             (=alg z constant)
	X             (eval-nodelist outs)))) 
	X
	X(defun tnen (outs register constant)
	X  (prog (z)
	X        (setq z (fast-symeval register))
	X        (and (or (not (numberp z))
	X                 (not (=alg z constant)))
	X             (eval-nodelist outs)))) 
	X
	X(defun txxn (outs register constant)
	X  (prog (z)
	X        (setq z (fast-symeval register))
	X        (and (numberp z) (eval-nodelist outs)))) 
	X
	X(defun tltn (outs register constant)
	X  (prog (z)
	X        (setq z (fast-symeval register))
	X        (and (numberp z)
	X             (greaterp constant z)
	X             (eval-nodelist outs)))) 
	X
	X(defun tgtn (outs register constant)
	X  (prog (z)
	X        (setq z (fast-symeval register))
	X        (and (numberp z)
	X             (greaterp z constant)
	X             (eval-nodelist outs)))) 
	X
	X(defun tgen (outs register constant)
	X  (prog (z)
	X        (setq z (fast-symeval register))
	X        (and (numberp z)
	X             (not (greaterp constant z))
	X             (eval-nodelist outs)))) 
	X
	X(defun tlen (outs register constant)
	X  (prog (z)
	X        (setq z (fast-symeval register))
	X        (and (numberp z)
	X             (not (greaterp z constant))
	X             (eval-nodelist outs)))) 
	X
	X(defun teqs (outs vara varb)
	X  (prog (a b)
	X        (setq a (fast-symeval vara))
	X        (setq b (fast-symeval varb))
	X        (cond ((eq a b) (eval-nodelist outs))
	X              ((and (numberp a)
	X                    (numberp b)
	X                    (=alg a b))
	X               (eval-nodelist outs))))) 
	X
	X(defun tnes (outs vara varb)
	X  (prog (a b)
	X        (setq a (fast-symeval vara))
	X        (setq b (fast-symeval varb))
	X        (cond ((eq a b) (return nil))
	X              ((and (numberp a)
	X                    (numberp b)
	X                    (=alg a b))
	X               (return nil))
	X              (t (eval-nodelist outs))))) 
	X
	X(defun txxs (outs vara varb)
	X  (prog (a b)
	X        (setq a (fast-symeval vara))
	X        (setq b (fast-symeval varb))
	X        (cond ((and (numberp a) (numberp b)) (eval-nodelist outs))
	X              ((and (not (numberp a)) (not (numberp b)))
	X               (eval-nodelist outs))))) 
	X
	X(defun tlts (outs vara varb)
	X  (prog (a b)
	X        (setq a (fast-symeval vara))
	X        (setq b (fast-symeval varb))
	X        (and (numberp a)
	X             (numberp b)
	X             (greaterp b a)
	X             (eval-nodelist outs)))) 
	X
	X(defun tgts (outs vara varb)
	X  (prog (a b)
	X        (setq a (fast-symeval vara))
	X        (setq b (fast-symeval varb))
	X        (and (numberp a)
	X             (numberp b)
	X             (greaterp a b)
	X             (eval-nodelist outs)))) 
	X
	X(defun tges (outs vara varb)
	X  (prog (a b)
	X        (setq a (fast-symeval vara))
	X        (setq b (fast-symeval varb))
	X        (and (numberp a)
	X             (numberp b)
	X             (not (greaterp b a))
	X             (eval-nodelist outs)))) 
	X
	X(defun tles (outs vara varb)
	X  (prog (a b)
	X        (setq a (fast-symeval vara))
	X        (setq b (fast-symeval varb))
	X        (and (numberp a)
	X             (numberp b)
	X             (not (greaterp a b))
	X             (eval-nodelist outs)))) 
	X
	X(defun &two (left-outs right-outs)
	X  (prog (fp dp)
	X        (cond (*sendtocall*
	X               (setq fp *flag-part*)
	X               (setq dp *data-part*))
	X              (t
	X               (setq fp *alpha-flag-part*)
	X               (setq dp *alpha-data-part*)))
	X        (sendto fp dp 'left left-outs)
	X        (sendto fp dp 'right right-outs))) 
	X
	X(defun &mem (left-outs right-outs memory-list)
	X  (prog (fp dp)
	X        (cond (*sendtocall*
	X               (setq fp *flag-part*)
	X               (setq dp *data-part*))
	X              (t
	X               (setq fp *alpha-flag-part*)
	X               (setq dp *alpha-data-part*)))
	X        (sendto fp dp 'left left-outs)
	X        (add-token memory-list fp dp nil)
	X        (sendto fp dp 'right right-outs))) 
	X
	X(defun &and (outs lpred rpred tests)
	X  (prog (mem)
	X        (cond ((eq *side* 'right) (setq mem (memory-part lpred)))
	X              (t (setq mem (memory-part rpred))))
	X        (cond ((not mem) (return nil))
	X              ((eq *side* 'right) (and-right outs mem tests))
	X              (t (and-left outs mem tests))))) 
	X
	X(defun and-left (outs mem tests)
	X  (prog (fp dp memdp tlist tst lind rind res)
	X        (setq fp *flag-part*)
	X        (setq dp *data-part*)
	X   fail (and (null mem) (return nil))
	X        (setq memdp (car mem))
	X        (setq mem (cdr mem))
	X        (setq tlist tests)
	X   tloop (and (null tlist) (go succ))
	X        (setq tst (car tlist))
	X        (setq tlist (cdr tlist))
	X        (setq lind (car tlist))
	X        (setq tlist (cdr tlist))
	X        (setq rind (car tlist))
	X        (setq tlist (cdr tlist))
	X        ;the next line differs in and-left & -right
	X        (setq res (funcall tst (gelm memdp rind) (gelm dp lind)))
	X        (cond (res (go tloop))
	X              (t (go fail)))
	X   succ ;the next line differs in and-left & -right
	X        (sendto fp (cons (car memdp) dp) 'left outs)
	X        (go fail))) 
	X
	X(defun and-right (outs mem tests)
	X  (prog (fp dp memdp tlist tst lind rind res)
	X        (setq fp *flag-part*)
	X        (setq dp *data-part*)
	X   fail (and (null mem) (return nil))
	X        (setq memdp (car mem))
	X        (setq mem (cdr mem))
	X        (setq tlist tests)
	X   tloop (and (null tlist) (go succ))
	X        (setq tst (car tlist))
	X        (setq tlist (cdr tlist))
	X        (setq lind (car tlist))
	X        (setq tlist (cdr tlist))
	X        (setq rind (car tlist))
	X        (setq tlist (cdr tlist))
	X        ;the next line differs in and-left & -right
	X        (setq res (funcall tst (gelm dp rind) (gelm memdp lind)))
	X        (cond (res (go tloop))
	X              (t (go fail)))
	X   succ ;the next line differs in and-left & -right
	X        (sendto fp (cons (car dp) memdp) 'right outs)
	X        (go fail))) 
	X
	X
	X(defun teqb (new eqvar)
	X  (cond ((eq new eqvar) t)
	X        ((not (numberp new)) nil)
	X        ((not (numberp eqvar)) nil)
	X        ((=alg new eqvar) t)
	X        (t nil))) 
	X
	X(defun tneb (new eqvar)
	X  (cond ((eq new eqvar) nil)
	X        ((not (numberp new)) t)
	X        ((not (numberp eqvar)) t)
	X        ((=alg new eqvar) nil)
	X        (t t))) 
	X
	X(defun tltb (new eqvar)
	X  (cond ((not (numberp new)) nil)
	X        ((not (numberp eqvar)) nil)
	X        ((greaterp eqvar new) t)
	X        (t nil))) 
	X
	X(defun tgtb (new eqvar)
	X  (cond ((not (numberp new)) nil)
	X        ((not (numberp eqvar)) nil)
	X        ((greaterp new eqvar) t)
	X        (t nil))) 
	X
	X(defun tgeb (new eqvar)
	X  (cond ((not (numberp new)) nil)
	X        ((not (numberp eqvar)) nil)
	X        ((not (greaterp eqvar new)) t)
	X        (t nil))) 
	X
	X(defun tleb (new eqvar)
	X  (cond ((not (numberp new)) nil)
	X        ((not (numberp eqvar)) nil)
	X        ((not (greaterp new eqvar)) t)
	X        (t nil))) 
	X
	X(defun txxb (new eqvar)
	X  (cond ((numberp new)
	X         (cond ((numberp eqvar) t)
	X               (t nil)))
	X        (t
	X         (cond ((numberp eqvar) nil)
	X               (t t))))) 
	X
	X
	X(defun &p (rating name var-dope ce-var-dope rhs)
	X  (prog (fp dp)
	X        (cond (*sendtocall*
	X               (setq fp *flag-part*)
	X               (setq dp *data-part*))
	X              (t
	X               (setq fp *alpha-flag-part*)
	X               (setq dp *alpha-data-part*)))
	X        (and (member fp '(nil old)) (removecs name dp))
	X        (and fp (insertcs name dp rating)))) 
	X
	X(defun &old (a b c d e) nil) ;a null function used for deleting node
	X
	X(defun &not (outs lmem rpred tests)
	X  (cond ((and (eq *side* 'right) (eq *flag-part* 'old)) nil)
	X        ((eq *side* 'right) (not-right outs (car lmem) tests))
	X        (t (not-left outs (memory-part rpred) tests lmem)))) 
	X
	X(defun not-left (outs mem tests own-mem)
	X  (prog (fp dp memdp tlist tst lind rind res c)
	X        (setq fp *flag-part*)
	X        (setq dp *data-part*)
	X        (setq c 0.)
	X   fail (and (null mem) (go fin))
	X        (setq memdp (car mem))
	X        (setq mem (cdr mem))
	X        (setq tlist tests)
	X   tloop (and (null tlist) (setq c (1+ c)) (go fail))
	X        (setq tst (car tlist))
	X        (setq tlist (cdr tlist))
	X        (setq lind (car tlist))
	X        (setq tlist (cdr tlist))
	X        (setq rind (car tlist))
	X        (setq tlist (cdr tlist))
	X        ;the next line differs in not-left & -right
	X        (setq res (funcall tst (gelm memdp rind) (gelm dp lind)))
	X        (cond (res (go tloop))
	X              (t (go fail)))
	X   fin  (add-token own-mem fp dp c)
	X        (and (== c 0.) (sendto fp dp 'left outs)))) 
	X
	X(defun not-right (outs mem tests)
	X  (prog (fp dp memdp tlist tst lind rind res newfp inc newc)
	X        (setq fp *flag-part*)
	X        (setq dp *data-part*)
	X        (cond ((not fp) (setq inc -1.) (setq newfp 'new))
	X              ((eq fp 'new) (setq inc 1.) (setq newfp nil))
	X              (t (return nil)))
	X   fail (and (null mem) (return nil))
	X        (setq memdp (car mem))
	X        (setq newc (cadr mem))
	X        (setq tlist tests)
	X   tloop (and (null tlist) (go succ))
	X        (setq tst (car tlist))
	X        (setq tlist (cdr tlist))
	X        (setq lind (car tlist))
	X        (setq tlist (cdr tlist))
	X        (setq rind (car tlist))
	X        (setq tlist (cdr tlist))
	X        ;the next line differs in not-left & -right
	X        (setq res (funcall tst (gelm dp rind) (gelm memdp lind)))
	X        (cond (res (go tloop))
	X              (t (setq mem (cddr mem)) (go fail)))
	X   succ (setq newc (+ inc newc))
	X        (rplaca (cdr mem) newc)
	X        (cond ((or (and (== inc -1.) (== newc 0.))
	X                   (and (== inc 1.) (== newc 1.)))
	X               (sendto newfp memdp 'right outs)))
	X        (setq mem (cddr mem))
	X        (go fail))) 
	X
	X
	X
	X;;; Node memories
	X
	X
	X(defun add-token (memlis flag data-part num)
	X  (prog (was-present)
	X        (cond ((eq flag 'new)
	X               (setq was-present nil)
	X               (real-add-token memlis data-part num))
	X              ((not flag) 
	X	       (setq was-present (remove-old memlis data-part num)))
	X              ((eq flag 'old) (setq was-present t)))
	X        (return was-present))) 
	X
	X(defun real-add-token (lis data-part num)
	X  (setq *current-token* (1+ *current-token*))
	X  (cond (num (rplaca lis (cons num (car lis)))))
	X  (rplaca lis (cons data-part (car lis)))) 
	X
	X(defun remove-old (lis data num)
	X  (cond (num (remove-old-num lis data))
	X        (t (remove-old-no-num lis data)))) 
	X
	X(defun remove-old-num (lis data)
	X  (prog (m next last)
	X        (setq m (car lis))
	X        (cond ((atom m) (return nil))
	X              ((top-levels-eq data (car m))
	X               (setq *current-token* (1- *current-token*))
	X               (rplaca lis (cddr m))
	X               (return (car m))))
	X        (setq next m)
	X   loop (setq last next)
	X        (setq next (cddr next))
	X        (cond ((atom next) (return nil))
	X              ((top-levels-eq data (car next))
	X               (rplacd (cdr last) (cddr next))
	X               (setq *current-token* (1- *current-token*))
	X               (return (car next)))
	X              (t (go loop))))) 
	X
	X(defun remove-old-no-num (lis data)
	X  (prog (m next last)
	X        (setq m (car lis))
	X        (cond ((atom m) (return nil))
	X              ((top-levels-eq data (car m))
	X               (setq *current-token* (1- *current-token*))
	X               (rplaca lis (cdr m))
	X               (return (car m))))
	X        (setq next m)
	X   loop (setq last next)
	X        (setq next (cdr next))
	X        (cond ((atom next) (return nil))
	X              ((top-levels-eq data (car next))
	X               (rplacd last (cdr next))
	X               (setq *current-token* (1- *current-token*))
	X               (return (car next)))
	X              (t (go loop))))) 
	X
	X
	X
	X;;; Conflict Resolution
	X;
	X;
	X; each conflict set element is a list of the following form:
	X; ((p-name . data-part) (sorted wm-recency) special-case-number)
	X
	X(defun removecs (name data)
	X  (prog (cr-data inst cs)
	X        (setq cr-data (cons name data))
	X	(setq cs *conflict-set*)
	X loop1	(cond ((null cs) 
	X               (record-refract name data)
	X               (return nil)))
	X	(setq inst (car cs))
	X	(setq cs (cdr cs))
	X	(and (not (top-levels-eq (car inst) cr-data)) (go loop1))
	X        (setq *conflict-set* (delete inst *conflict-set* :test #'eq))))
	X
	X(defun insertcs (name data rating)
	X  (prog (instan)
	X    (and (refracted name data) (return nil))
	X    (setq instan (list (cons name data) (order-tags data) rating))
	X    (and (atom *conflict-set*) (setq *conflict-set* nil))
	X    (return (setq *conflict-set* (cons instan *conflict-set*))))) 
	X
	X(defun order-tags (dat)
	X  (prog (tags)
	X        (setq tags nil)
	X   l1  (and (atom dat) (go l2))
	X        (setq tags (cons (creation-time (car dat)) tags))
	X        (setq dat (cdr dat))
	X        (go l1)
	X   l2  (cond ((eq *strategy* 'mea)
	X               (return (cons (car tags) (dsort (cdr tags)))))
	X              (t (return (dsort tags)))))) 
	X
	X; destructively sort x into descending order
	X
	X(defun dsort (x)
	X  (prog (sorted cur next cval nval)
	X        (and (atom (cdr x)) (return x))
	X   loop (setq sorted t)
	X        (setq cur x)
	X        (setq next (cdr x))
	X   chek (setq cval (car cur))
	X        (setq nval (car next))
	X        (cond ((> nval cval)
	X               (setq sorted nil)
	X               (rplaca cur nval)
	X               (rplaca next cval)))
	X        (setq cur next)
	X        (setq next (cdr cur))
	X        (cond ((not (null next)) (go chek))
	X              (sorted (return x))
	X              (t (go loop))))) 
	X
	X(defun conflict-resolution nil
	X  (prog (best len)
	X        (setq len (length *conflict-set*))
	X        (cond ((> len *max-cs*) (setq *max-cs* len)))
	X        (setq *total-cs* (+ *total-cs* len))
	X        (cond (*conflict-set*
	X               (setq best (best-of *conflict-set*))
	X               (setq *conflict-set* (delete best *conflict-set* :test #'eq))
	X               (return (pname-instantiation best)))
	X              (t (return nil))))) 
	X
	X(defun best-of (set) (best-of* (car set) (cdr set))) 
	X
	X(defun best-of* (best rem)
	X  (cond ((not rem) best)
	X        ((conflict-set-compare best (car rem))
	X         (best-of* best (cdr rem)))
	X        (t (best-of* (car rem) (cdr rem))))) 
	X
	X(defun remove-from-conflict-set (name)
	X  (prog (cs entry)
	X   l1   (setq cs *conflict-set*)
	X   l2   (cond ((atom cs) (return nil)))
	X        (setq entry (car cs))
	X        (setq cs (cdr cs))
	X        (cond ((eq name (caar entry))
	X               (setq *conflict-set* (delete entry *conflict-set* :test #'eq))
	X               (go l1))
	X              (t (go l2))))) 
	X
	X(defun pname-instantiation (conflict-elem) (car conflict-elem)) 
	X
	X(defun order-part (conflict-elem) (cdr conflict-elem)) 
	X
	X(defun instantiation (conflict-elem)
	X  (cdr (pname-instantiation conflict-elem))) 
	X
	X
	X(defun conflict-set-compare (x y)
	X  (prog (x-order y-order xl yl xv yv)
	X        (setq x-order (order-part x))
	X        (setq y-order (order-part y))
	X        (setq xl (car x-order))
	X        (setq yl (car y-order))
	X   data (cond ((and (null xl) (null yl)) (go ps))
	X              ((null yl) (return t))
	X              ((null xl) (return nil)))
	X        (setq xv (car xl))
	X        (setq yv (car yl))
	X        (cond ((> xv yv) (return t))
	X              ((> yv xv) (return nil)))
	X        (setq xl (cdr xl))
	X        (setq yl (cdr yl))
	X        (go data)
	X   ps   (setq xl (cdr x-order))
	X        (setq yl (cdr y-order))
	X   psl  (cond ((null xl) (return t)))
	X        (setq xv (car xl))
	X        (setq yv (car yl))
	X        (cond ((> xv yv) (return t))
	X              ((> yv xv) (return nil)))
	X        (setq xl (cdr xl))
	X        (setq yl (cdr yl))
	X        (go psl))) 
	X
	X
	X(defun conflict-set nil
	X  (prog (cnts cs p z best)
	X        (setq cnts nil)
	X        (setq cs *conflict-set*)
	X   l1  (and (atom cs) (go l2))
	X        (setq p (caaar cs))
	X        (setq cs (cdr cs))
	X        (setq z (assoc p cnts :test #'eq))
	X        (cond ((null z) (setq cnts (cons (cons p 1.) cnts)))
	X              (t (rplacd z (1+ (cdr z)))))
	X        (go l1)
	X   l2  (cond ((atom cnts)
	X               (setq best (best-of *conflict-set*))
	X               (terpri)
	X               (return (list (caar best) 'dominates))))
	X        (terpri)
	X        (princ (caar cnts))
	X        (cond ((> (cdar cnts) 1.)
	X               (princ '|	(|)
	X               (princ (cdar cnts))
	X               (princ '| occurrences)|)))
	X        (setq cnts (cdr cnts))
	X        (go l2))) 
	X	
	X
	X
	X;;; WM maintaining functions
	X;
	X; The order of operations in the following two functions is critical.
	X; add-to-wm order: (1) change wm (2) record change (3) match 
	X; remove-from-wm order: (1) record change (2) match (3) change wm
	X; (back will not restore state properly unless wm changes are recorded
	X; before the cs changes that they cause)  (match will give errors if 
	X; the thing matched is not in wm at the time)
	X
	X
	X(defun add-to-wm (wme override)
	X  (prog (fa z part timetag port)
	X    (setq *critical* t)
	X    (setq *current-wm* (1+ *current-wm*))
	X    (and (> *current-wm* *max-wm*) (setq *max-wm* *current-wm*))
	X    (setq *action-count* (1+ *action-count*))
	X    (setq fa (wm-hash wme))
	X    (or (member fa *wmpart-list* :test #'eq)
	X        (setq *wmpart-list* (cons fa *wmpart-list*)))
	X    (setq part (get fa 'wmpart*))
	X    (cond (override (setq timetag override))
	X          (t (setq timetag *action-count*)))
	X    (setq z (cons wme timetag))
	X    (putprop fa (cons z part) 'wmpart*)
	X    (record-change '=>wm *action-count* wme)
	X    (match 'new wme)
	X    (setq *critical* nil)
	X    (cond ((and *in-rhs* *wtrace*)
	X           (setq port (trace-file))
	X           (terpri port)
	X           (princ '|=>wm: | port)
	X           (ppelm wme port)))
	X    (and *in-rhs* *mtrace* (setq *madeby* 
	X                                 (cons (cons wme *p-name*) *madeby*))))) 
	X
	X; remove-from-wm uses eq, not equal to determine if wme is present
	X
	X(defun remove-from-wm (wme)
	X  (prog (fa z part timetag port)
	X    (setq fa (wm-hash wme))
	X    (setq part (get fa 'wmpart*))
	X    (setq z (assoc wme part :test #'eq))
	X    (or z (return nil))
	X    (setq timetag (cdr z))
	X    (cond ((and *wtrace* *in-rhs*)
	X           (setq port (trace-file))
	X           (terpri port)
	X           (princ '|<=wm: | port)
	X           (ppelm wme port)))
	X    (setq *action-count* (1+ *action-count*))
	X    (setq *critical* t)
	X    (setq *current-wm* (1- *current-wm*))
	X    (record-change '<=wm timetag wme)
	X    (match nil wme)
	X    (putprop fa (delete z part :test #'eq) 'wmpart* )
	X    (setq *critical* nil))) 
	X
	X; mapwm maps down the elements of wm, applying fn to each element
	X; each element is of form (datum . creation-time)
	X
	X(defun mapwm (fn)
	X  (prog (wmpl part)
	X        (setq wmpl *wmpart-list*)
	X   lab1 (cond ((atom wmpl) (return nil)))
	X        (setq part (get (car wmpl) 'wmpart*))
	X        (setq wmpl (cdr wmpl))
	X        (mapc fn part)
	X        (go lab1))) 
	X
	X(defmacro wm (&rest a) 
	X  `(progn
	X   (mapc (function (lambda (z) (terpri) (ppelm z t))) 
	X	(get-wm ',a))
	X  nil) )
	X
	X(defun get-wm (z)
	X  (setq *wm-filter* z)
	X  (setq *wm* nil)
	X  (mapwm (function get-wm2))
	X  (prog2 nil *wm* (setq *wm* nil))) 
	X
	X(defun get-wm2 (elem) 
	X (cond ((or (null *wm-filter*) (member (cdr elem) *wm-filter*))
	X	(setq *wm* (cons (car elem) *wm*)))))
	X
	X(defun wm-hash (x)
	X  (cond ((not x) '<default>)
	X        ((not (car x)) (wm-hash (cdr x)))
	X        ((symbolp (car x)) (car x))
	X        (t (wm-hash (cdr x))))) 
	X
	X(defun creation-time (wme)
	X  (cdr (assoc wme (get (wm-hash wme) 'wmpart*) :test #'eq))) 
	X
	X(defun rehearse nil
	X  (prog nil
	X    (setq *old-wm* nil)
	X    (mapwm (function refresh-collect))
	X    (mapc (function refresh-del) *old-wm*)
	X    (mapc (function refresh-add) *old-wm*)
	X    (setq *old-wm* nil))) 
	X
	X(defun refresh-collect (x) (setq *old-wm* (cons x *old-wm*))) 
	X
	X(defun refresh-del (x) (remove-from-wm (car x))) 
	X
	X(defun refresh-add (x) (add-to-wm (car x) (cdr x))) 
	X
	X(defun trace-file ()
	X  (prog (port)
	X        (setq port t)
	X	(cond (*trace-file*
	X	       (setq port ($ofile *trace-file*))
	X	       (cond ((null port)
	X	              (%warn '|trace: file has been closed| *trace-file*)
	X		      (setq port t)))))
	X        (return port)))
	X
	X
	X;;; Basic functions for RHS evaluation
	X
	X(defun eval-rhs (pname data)
	X  (prog (node port)
	X    (cond (*ptrace*
	X           (setq port (trace-file))
	X           (terpri port)
	X           (princ *cycle-count* port)
	X           (princ '|. | port)
	X           (princ pname port)
	X           (time-tag-print data port)))
	X    (setq *data-matched* data)
	X    (setq *p-name* pname)
	X    (setq *last* nil)
	X    (setq node (get pname 'topnode))
	X    (init-var-mem (var-part node))
	X    (init-ce-var-mem (ce-var-part node))
	X    (begin-record pname data)
	X    (setq *in-rhs* t)
	X    (eval (rhs-part node))
	X    (setq *in-rhs* nil)
	X    (end-record))) 
	X
	X(defun time-tag-print (data port)
	X  (cond ((not (null data))
	X         (time-tag-print (cdr data) port)
	X         (princ '| | port)
	X         (princ (creation-time (car data)) port))))
	X
	X(defun init-var-mem (vlist)
	X  (prog (v ind r)
	X        (setq *variable-memory* nil)
	X   top  (and (atom vlist) (return nil))
	X        (setq v (car vlist))
	X        (setq ind (cadr vlist))
	X        (setq vlist (cddr vlist))
	X        (setq r (gelm *data-matched* ind))
	X        (setq *variable-memory* (cons (cons v r) *variable-memory*))
	X        (go top))) 
	X
	X(defun init-ce-var-mem (vlist)
	X  (prog (v ind r)
	X        (setq *ce-variable-memory* nil)
	X   top  (and (atom vlist) (return nil))
	X        (setq v (car vlist))
	X        (setq ind (cadr vlist))
	X        (setq vlist (cddr vlist))
	X        (setq r (ce-gelm *data-matched* ind))
	X        (setq *ce-variable-memory*
	X              (cons (cons v r) *ce-variable-memory*))
	X        (go top))) 
	X
	X(defun make-ce-var-bind (var elem)
	X  (setq *ce-variable-memory*
	X        (cons (cons var elem) *ce-variable-memory*))) 
	X
	X(defun make-var-bind (var elem)
	X  (setq *variable-memory* (cons (cons var elem) *variable-memory*))) 
	X
	X(defun $varbind (x)
	X  (prog (r)
	X	(and (not *in-rhs*) (return x))
	X        (setq r (assoc x *variable-memory* :test #'eq))
	X        (cond (r (return (cdr r)))
	X              (t (return x))))) 
	X
	X(defun get-ce-var-bind (x)
	X  (prog (r)
	X        (cond ((numberp x) (return (get-num-ce x))))
	X        (setq r (assoc x *ce-variable-memory* :test #'eq))
	X        (cond (r (return (cdr r)))
	X              (t (return nil))))) 
	X
	X(defun get-num-ce (x)
	X  (prog (r l d)
	X        (setq r *data-matched*)
	X        (setq l (length r))
	X        (setq d (- l x))
	X        (and (> 0. d) (return nil))
	X   la   (cond ((null r) (return nil))
	X              ((> 1. d) (return (car r))))
	X        (setq d (1- d))
	X        (setq r (cdr r))
	X        (go la))) 
	X
	X
	X(defun build-collect (z)
	X  (prog (r)
	X   la   (and (atom z) (return nil))
	X        (setq r (car z))
	X        (setq z (cdr z))
	X        (cond ((and r (listp r))
	X               ($value '\()
	X               (build-collect r)
	X               ($value '\)))
	X              ((eq r '\\) ($change (car z)) (setq z (cdr z)))
	X              (t ($value r)))
	X        (go la))) 
	X
	X(defun unflat (x) (setq *rest* x) (unflat*)) 
	X
	X(defun unflat* nil
	X  (prog (c)
	X        (cond ((atom *rest*) (return nil)))
	X        (setq c (car *rest*))
	X        (setq *rest* (cdr *rest*))
	X        (cond ((eq c '\() (return (cons (unflat*) (unflat*))))
	X              ((eq c '\)) (return nil))
	X              (t (return (cons c (unflat*))))))) 
	X
	X
	X(defun $change (x)
	X  (prog nil
	X        (cond ((and x (listp x)) (eval-function x)) ;modified to check for nil
	X              (t ($value ($varbind x)))))) 
	X
	X(defun eval-args (z)
	X  (prog (r)
	X        (rhs-tab 1.)
	X   la   (and (atom z) (return nil))
	X        (setq r (car z))
	X        (setq z (cdr z))
	X        (cond ((eq r #\^)
	X               (rhs-tab (car z))
	X               (setq r (cadr z))
	X               (setq z (cddr z))))
	X        (cond ((eq r '//) ($value (car z)) (setq z (cdr z)))
	X              (t ($change r)))
	X        (go la))) 
	X
	X
	X(defun eval-function (form)
	X  (cond ((not *in-rhs*)
	X	 (%warn '|functions cannot be used at top level| (car form)))
	X	(t (eval form))))
	X
	X
	X;;; Functions to manipulate the result array
	X
	X
	X(defun $reset nil
	X  (setq *max-index* 0)
	X  (setq *next-index* 1)) 
	X
	X; rhs-tab implements the tab ('^') function in the rhs.  it has
	X; four responsibilities:
	X;	- to move the array pointers
	X;	- to watch for tabbing off the left end of the array
	X;	  (ie, to watch for pointers less than 1)
	X;	- to watch for tabbing off the right end of the array
	X;	- to write nil in all the slots that are skipped
	X; the last is necessary if the result array is not to be cleared
	X; after each use; if rhs-tab did not do this, $reset
	X; would be much slower.
	X
	X(defun rhs-tab (z) ($tab ($varbind z)))
	X
	X(defun $tab (z)
	X  (prog (edge next)
	X        (setq next ($litbind z))
	X        (and (floatp next) (setq next (round next)))
	X        (cond ((or (not (numberp next)) 
	X		   (> next *size-result-array*)
	X		   (> 1. next))
	X               (%warn '|illegal index after ^| next)
	X               (return *next-index*)))
	X        (setq edge (- next 1.))
	X        (cond ((> *max-index* edge) (go ok)))
	X   clear (cond ((== *max-index* edge) (go ok)))
	X        (putvector *result-array* edge nil)
	X        (setq edge (1- edge))
	X        (go clear)
	X   ok   (setq *next-index* next)
	X        (return next))) 
	X
	X(defun $value (v)
	X  (cond ((> *next-index* *size-result-array*)
	X         (%warn '|index too large| *next-index*))
	X        (t
	X         (and (> *next-index* *max-index*)
	X              (setq *max-index* *next-index*))
	X         (putvector *result-array* *next-index* v)
	X         (setq *next-index* (1+ *next-index*))))) 
	X
	X(defun use-result-array nil
	X  (prog (k r)
	X        (setq k *max-index*)
	X        (setq r nil)
	X   top  (and (== k 0.) (return r))
	X        (setq r (cons (getvector *result-array* k) r))
	X        (setq k (1- k))
	X        (go top))) 
	X
	X(defun $assert nil
	X  (setq *last* (use-result-array))
	X  (add-to-wm *last* nil))
	X
	X(defun $parametercount nil *max-index*)
	X
	X(defun $parameter (k)
	X  (cond ((or (not (numberp k)) (> k *size-result-array*) (< k 1.))
	X	 (%warn '|illegal parameter number | k)
	X         nil)
	X        ((> k *max-index*) nil)
	X	(t (getvector *result-array* k))))
	X
	X
	X;;; RHS actions
	X
	X
	X(defmacro make(&rest z)
	X  `(prog nil
	X        ($reset)
	X        (eval-args ',z)
	X        ($assert))) 
	X
	X(defmacro modify (&rest z)
	X  `(prog (old args)
	X        (setq args ',z)
	X	(cond ((not *in-rhs*)
	X	       (%warn '|cannot be called at top level| 'modify)
	X	       (return nil)))
	X        (setq old (get-ce-var-bind (car args)))
	X        (cond ((null old)
	X               (%warn '|modify: first argument must be an element variable|
	X                        (car args))
	X               (return nil)))
	X        (remove-from-wm old)
	X        (setq args (cdr args))
	X        ($reset)
	X   copy (and (atom old) (go fin))
	X        ($change (car old))
	X        (setq old (cdr old))
	X        (go copy)
	X   fin  (eval-args args)
	X        ($assert))) 
	X
	X(defmacro bind (&rest z)
	X  `(prog (val)
	X	(cond ((not *in-rhs*)
	X	       (%warn '|cannot be called at top level| 'bind)
	X	       (return nil)))
	X    (cond ((< (length z) 1.)
	X           (%warn '|bind: wrong number of arguments to| ',z)
	X           (return nil))
	X          ((not (symbolp (car ',z)))
	X           (%warn '|bind: illegal argument| (car ',z))
	X           (return nil))
	X          ((= (length ',z) 1.) (setq val (gensym)))
	X          (t ($reset)
	X             (eval-args (cdr ',z))
	X             (setq val ($parameter 1.))))
	X    (make-var-bind (car ',z) val))) 
	X
	X(defmacro cbind (&rest z)
	X  `(cond ((not *in-rhs*)
	X	 (%warn '|cannot be called at top level| 'cbind))
	X	((not (= (length ',z) 1.))
	X	 (%warn '|cbind: wrong number of arguments| ',z))
	X	((not (symbolp (car ',z)))
	X	 (%warn '|cbind: illegal argument| (car ',z)))
	X	((null *last*)
	X	 (%warn '|cbind: nothing added yet| (car ',z)))
	X	(t (make-ce-var-bind (car ',z) *last*)))) 
	X
	X(defmacro oremove (&rest z)
	X  `(prog (old args)
	X        (setq args ',z)
	X	(and (not *in-rhs*)(return (top-level-remove args)))
	X   top  (and (atom args) (return nil))
	X        (setq old (get-ce-var-bind (car args)))
	X        (cond ((null old)
	X               (%warn '|remove: argument not an element variable| (car args))
	X               (return nil)))
	X        (remove-from-wm old)
	X        (setq args (cdr args))
	X        (go top))) 
	X
	X(defmacro ocall (&rest z)
	X  `(prog (f)
	X	(setq f (car ',z))
	X        ($reset)
	X        (eval-args (cdr ',z))
	X        (funcall f))) 
	X
	X(defmacro owrite (&rest z)
	X `(prog (port max k x needspace)
	X	(cond ((not *in-rhs*)
	X	       (%warn '|cannot be called at top level| 'write)
	X	       (return nil)))
	X	($reset)
	X	(eval-args ',z)
	X	(setq k 1.)
	X	(setq max ($parametercount))
	X	(cond ((< max 1.)
	X	       (%warn '|write: nothing to print| ',z)
	X	       (return nil)))
	X	(setq port (default-write-file))
	X	(setq x ($parameter 1.))
	X	(cond ((and (symbolp x) ($ofile x)) 
	X	       (setq port ($ofile x))
	X	       (setq k 2.)))
	X        (setq needspace t)
	X   la   (and (> k max) (return nil))
	X	(setq x ($parameter k))
	X	(cond ((eq x '|=== C R L F ===|)
	X	       (setq needspace nil)
	X               (terpri port))
	X              ((eq x '|=== R J U S T ===|)
	X	       (setq k (+ 2 k))
	X	       (do-rjust ($parameter (1- k)) ($parameter k) port))
	X	      ((eq x '|=== T A B T O ===|)
	X	       (setq needspace nil)
	X	       (setq k (1+ k))
	X	       (do-tabto ($parameter k) port))
	X	      (t 
	X	       (and needspace (princ '| | port))
	X	       (setq needspace t)
	X	       (princ x port)))
	X	(setq k (1+ k))
	X	(go la))) 
	X	
	X(defun default-write-file ()
	X  (prog (port)
	X	(setq port t)
	X	(cond (*write-file*
	X	       (setq port ($ofile *write-file*))
	X	       (cond ((null port) 
	X		      (%warn '|write: file has been closed| *write-file*)
	X		      (setq port t)))))
	X        (return port)))
	X
	X                                                                                                                                                                                                         
	X(defun do-rjust (width value port)
	X  (prog (size)
	X	(cond ((eq value '|=== T A B T O ===|)
	X	       (%warn '|rjust cannot precede this function| 'tabto)
	X               (return nil))
	X	      ((eq value '|=== C R L F ===|)
	X	       (%warn '|rjust cannot precede this function| 'crlf)
	X               (return nil))
	X	      ((eq value '|=== R J U S T ===|)
	X	       (%warn '|rjust cannot precede this function| 'rjust)
	X               (return nil)))
	X        (setq size (length (princ-to-string value )))
	X	(cond ((> size width)
	X	       (princ '| | port)
	X	       (princ value port)
	X	       (return nil)))
	X        (do k (- width size) (1- k) (not (> k 0)) (princ '| | port))
	X	(princ value port)))
	X
	X(defun do-tabto (col port)
	X  (eval `(format ,port (concatenate 'string "~" (princ-to-string ,col) "T"))))
	X
	X;  (prog (pos)
	X;	(setq pos (1+ (nwritn port)))
	X;	(cond ((> pos col)
	X;	       (terpri port)
	X;	       (setq pos 1)))
	X;	(do k (- col pos) (1- k) (not (> k 0)) (princ '| | port))
	X;	(return nil)))
	X
	X
	X(defun halt nil 
	X  (cond ((not *in-rhs*)
	X	 (%warn '|cannot be called at top level| 'halt))
	X	(t (setq *halt-flag* t)))) 
	X
	X(defmacro build (&rest z)
	X  `(prog (r)
	X	(cond ((not *in-rhs*)
	X	       (%warn '|cannot be called at top level| 'build)
	X	       (return nil)))
	X        ($reset)
	X        (build-collect ',z)
	X        (setq r (unflat (use-result-array)))
	X        (and *build-trace* (funcall *build-trace* r))
	X        (compile-production (car r) (cdr r)))) 
	X
	X(defun infile(file)
	X   (open file :direction :input))
	X
	X(defun outfile(file)
	X   (open file :direction :output))
	X
	X(defmacro openfile (&rest z)
	X  `(prog (file mode id)
	X	($reset)
	X	(eval-args ',z)
	X	(cond ((not (equal ($parametercount) 3.))
	X	       (%warn '|openfile: wrong number of arguments| ',z)
	X	       (return nil)))
	X	(setq id ($parameter 1))
	X	(setq file ($parameter 2))
	X	(setq mode ($parameter 3))
	X	(cond ((not (symbolp id))
	X	       (%warn '|openfile: file id must be a symbolic atom| id)
	X	       (return nil))
	X              ((null id)
	X               (%warn '|openfile: 'nil' is reserved for the terminal| nil)
	X               (return nil))
	X	      ((or ($ifile id)($ofile id))
	X	       (%warn '|openfile: name already in use| id)
	X	       (return nil)))
	X	(cond ((eq mode 'in) (putprop id  (infile file) 'inputfile))
	X	      ((eq mode 'out) (putprop id  (outfile file) 'outputfile))
	X	      (t (%warn '|openfile: illegal mode| mode)
	X		 (return nil)))
	X	(return nil)))
	X
	X(defun $ifile (x) 
	X  (cond ((and x (symbolp x)) (get x 'inputfile))
	X        (t *standard-input*)))
	X 
	X(defun $ofile (x) 
	X  (cond ((and x (symbolp x)) (get x 'outputfile))
	X        (t *standard-output*)))
	X
	X
	X(defmacro closefile (&rest z)
	X  `(progn 
	X    ($reset)
	X    (eval-args ',z)
	X    (mapc (function closefile2) (use-result-array))))
	X
	X(defun closefile2 (file)
	X  (prog (port)
	X	(cond ((not (symbolp file))
	X	       (%warn '|closefile: illegal file identifier| file))
	X	      ((setq port ($ifile file))
	X	       (close port)
	X	       (remprop file 'inputfile))
	X	      ((setq port ($ofile file))
	X	       (close port)
	X	       (remprop file 'outputfile)))
	X	(return nil)))
	X
	X(defmacro default (&rest z)
	X  `(prog (file use)
	X	($reset)
	X	(eval-args ',z)
	X	(cond ((not (equal ($parametercount) 2.))
	X	       (%warn '|default: wrong number of arguments| ',z)
	X	       (return nil)))
	X	(setq file ($parameter 1))
	X	(setq use ($parameter 2))
	X	(cond ((not (symbolp file))
	X	       (%warn '|default: illegal file identifier| file)
	X	       (return nil))
	X	      ((not (member use '(write accept trace)))
	X	       (%warn '|default: illegal use for a file| use)
	X	       (return nil))
	X	      ((and (member use '(write trace)) 
	X		    (not (null file))
	X		    (not ($ofile file)))
	X	       (%warn '|default: file has not been opened for output| file)
	X	       (return nil))
	X	      ((and (eq use 'accept) 
	X		    (not (null file))
	X		    (not ($ifile file)))
	X	       (%warn '|default: file has not been opened for input| file)
	X	       (return nil))
	X	      ((eq use 'write) (setq *write-file* file))
	X	      ((eq use 'accept) (setq *accept-file* file))
	X	      ((eq use 'trace) (setq *trace-file* file)))
	X	(return nil)))
	X
	X
	X
	X;;; RHS Functions
	X
	X(defmacro accept (&rest z)
	X  `(prog (port arg)
	X	(cond ((> (length ',z) 1.)
	X	       (%warn '|accept: wrong number of arguments| ',z)
	X	       (return nil)))
	X	(setq port t)
	X	(cond (*accept-file*
	X	       (setq port ($ifile *accept-file*))
	X	       (cond ((null port) 
	X		      (%warn '|accept: file has been closed| *accept-file*)
	X		      (return nil)))))
	X	(cond ((= (length ',z) 1)
	X	       (setq arg ($varbind (car ',z)))
	X	       (cond ((not (symbolp arg))
	X	              (%warn '|accept: illegal file name| arg)
	X		      (return nil)))
	X	       (setq port ($ifile arg))
	X	       (cond ((null port) 
	X		      (%warn '|accept: file not open for input| arg)
	X		      (return nil)))))
	X        (cond ((= (tyipeek port) -1.)
	X	       ($value 'end-of-file)
	X	       (return nil)))
	X	(flat-value (read port)))) 
	X
	X(defun flat-value (x)
	X  (cond ((atom x) ($value x))
	X        (t (mapc (function flat-value) x)))) 
	X
	X(defun span-chars (x prt)
	X  (do ((ch (tyipeek prt) (tyipeek prt))) ((not (member ch x #'char-equal))) (read-char prt)))
	X
	X(defmacro acceptline (&rest z)
	X  `(prog ( def arg port)
	X	(setq port t)
	X	(setq def ',z)
	X	(cond (*accept-file*
	X	       (setq port ($ifile *accept-file*))
	X	       (cond ((null port) 
	X		      (%warn '|acceptline: file has been closed| 
	X		             *accept-file*)
	X		      (return nil)))))
	X	(cond ((> (length def) 0)
	X	       (setq arg ($varbind (car def)))
	X	       (cond ((and (symbolp arg) ($ifile arg))
	X	              (setq port ($ifile arg))
	X		      (setq def (cdr def))))))
	X        (span-chars '(9. 41.) port)
	X	(cond ((member (tyipeek port) '(-1. 10.))
	X	       (mapc (function $change) def)
	X	       (return nil)))
	X   lp1	(flat-value (read port))
	X        (span-chars '(9. 41.) port)
	X	(cond ((not (member (tyipeek port) '(-1. 10.))) (go lp1)))))
	X
	X(defmacro substr (&rest l)
	X  `(prog (k elm start end)
	X        (cond ((not (= (length ',l) 3.))
	X               (%warn '|substr: wrong number of arguments| ',l)
-- 
---------------
C'est la vie, C'est la guerre, C'est la pomme de terre
Mail:	Imagen Corp. 2650 San Tomas Expressway Santa Clara, CA 95052-8101 
UUCP:	...{decvax,ucbvax}!decwrl!imagen!turner      AT&T: (408) 986-9400

turner@imagen.UUCP (D'arc Angel) (01/19/87)

	X               (return nil)))
	X        (setq elm (get-ce-var-bind (car ',l)))
	X        (cond ((null elm)
	X               (%warn '|first argument to substr must be a ce var|
	X                        ',l)
	X               (return nil)))
	X        (setq start ($varbind (cadr ',l)))
	X	(setq start ($litbind start))
	X        (cond ((not (numberp start))
	X               (%warn '|second argument to substr must be a number|
	X                        ',l)
	X               (return nil)))
	X	;if a variable is bound to INF, the following
	X	;will get the binding and treat it as INF is
	X	;always treated.  that may not be good
	X        (setq end ($varbind (caddr ',l)))
	X        (cond ((eq end 'inf) (setq end (length elm))))
	X	(setq end ($litbind end))
	X        (cond ((not (numberp end))
	X               (%warn '|third argument to substr must be a number|
	X                        ',l)
	X               (return nil)))
	X        ;this loop does not check for the end of elm
	X        ;instead it relies on cdr of nil being nil
	X        ;this may not work in all versions of lisp
	X        (setq k 1.)
	X   la   (cond ((> k end) (return nil))
	X              ((not (< k start)) ($value (car elm))))
	X        (setq elm (cdr elm))
	X        (setq k (1+ k))
	X        (go la))) 
	X
	X
	X(defmacro compute (&rest z) `($value (ari ',z))) 
	X
	X; arith is the obsolete form of compute
	X(defmacro arith (&rest z) `($value (ari ',z))) 
	X
	X(defun ari (x)
	X  (cond ((atom x)
	X         (%warn '|bad syntax in arithmetic expression | x)
	X	 0.)
	X        ((atom (cdr x)) (ari-unit (car x)))
	X        ((eq (cadr x) '+)
	X         (+ (ari-unit (car x)) (ari (cddr x))))
	X        ((eq (cadr x) '-)
	X         (difference (ari-unit (car x)) (ari (cddr x))))
	X        ((eq (cadr x) '*)
	X         (times (ari-unit (car x)) (ari (cddr x))))
	X        ((eq (cadr x) '//)
	X         (/ (ari-unit (car x)) (ari (cddr x))))
	X        ((eq (cadr x) '\\)
	X         (mod (round (ari-unit (car x))) (round (ari (cddr x)))))
	X        (t (%warn '|bad syntax in arithmetic expression | x) 0.))) 
	X
	X(defun ari-unit (a)
	X  (prog (r)
	X        (cond ((listp a) (setq r (ari a)))
	X              (t (setq r ($varbind a))))
	X        (cond ((not (numberp r))
	X               (%warn '|bad value in arithmetic expression| a)
	X               (return 0.))
	X              (t (return r))))) 
	X
	X(defun genatom nil ($value (gensym))) 
	X
	X(defmacro litval (&rest z)
	X  `(prog (r)
	X	(cond ((not (= (length ',z) 1.))
	X	       (%warn '|litval: wrong number of arguments| ',z)
	X	       ($value 0) 
	X	       (return nil))
	X	      ((numberp (car ',z)) ($value (car ',z)) (return nil)))
	X	(setq r ($litbind ($varbind (car ',z))))
	X	(cond ((numberp r) ($value r) (return nil)))
	X	(%warn '|litval: argument has no literal binding| (car ',z))
	X	($value 0)))
	X
	X
	X(defmacro rjust (&rest z)
	X  `(prog (val)
	X        (cond ((not (= (length ',z) 1.))
	X	       (%warn '|rjust: wrong number of arguments| ',z)
	X               (return nil)))
	X        (setq val ($varbind (car ',z)))
	X	(cond ((or (not (numberp val)) (< val 1.) (> val 127.))
	X	       (%warn '|rjust: illegal value for field width| val)
	X	       (return nil)))
	X        ($value '|=== R J U S T ===|)
	X	($value val)))
	X
	X
	X(defmacro crlf()
	X     ($value '|=== C R L F ===|))
	X
	X(defmacro tabto (&rest z)
	X  `(prog (val)
	X        (cond ((not (= (length ',z) 1.))
	X	       (%warn '|tabto: wrong number of arguments| ',z)
	X	       (return nil)))
	X        (setq val ($varbind (car ',z)))
	X	(cond ((or (not (numberp val)) (< val 1.) (> val 127.))
	X	       (%warn '|tabto: illegal column number| ',z)
	X	       (return nil)))
	X        ($value '|=== T A B T O ===|)
	X	($value val)))
	X
	X
	X
	X;;; Printing WM
	X
	X(defmacro ppwm (&rest z)
	X  `(prog (next a avlist)
	X        (setq avlist ',z)
	X        (setq *filters* nil)
	X        (setq next 1.)
	X   l   (and (atom avlist) (go print))
	X        (setq a (car avlist))
	X        (setq avlist (cdr avlist))
	X        (cond ((eq a #\^)
	X               (setq next (car avlist))
	X               (setq avlist (cdr avlist))
	X               (setq next ($litbind next))
	X               (and (floatp next) (setq next (round next)))
	X               (cond ((or (not (numberp next))
	X                          (> next *size-result-array*)
	X                          (> 1. next))
	X                      (%warn '|illegal index after ^| next)
	X                      (return nil))))
	X              ((variablep a)
	X               (%warn '|ppwm does not take variables| a)
	X               (return nil))
	X              (t (setq *filters* (cons next (cons a *filters*)))
	X                 (setq next (1+ next))))
	X        (go l)
	X   print (mapwm (function ppwm2))
	X        (terpri)
	X        (return nil))) 
	X
	X(defun ppwm2 (elm-tag)
	X  (cond ((filter (car elm-tag)) (terpri) (ppelm (car elm-tag) t)))) 
	X
	X(defun filter (elm)
	X  (prog (fl indx val)
	X        (setq fl *filters*)
	X   top  (and (atom fl) (return t))
	X        (setq indx (car fl))
	X        (setq val (cadr fl))
	X        (setq fl (cddr fl))
	X        (and (ident (nth (1- indx) elm) val) (go top))
	X        (return nil))) 
	X
	X(defun ident (x y)
	X  (cond ((eq x y) t)
	X        ((not (numberp x)) nil)
	X        ((not (numberp y)) nil)
	X        ((=alg x y) t)
	X        (t nil))) 
	X
	X; the new ppelm is designed especially to handle literalize format
	X; however, it will do as well as the old ppelm on other formats
	X
	X(defun ppelm (elm port)
	X  (prog (ppdat sep val att mode lastpos)
	X	(princ (creation-time elm) port)
	X	(princ '|:  | port)
	X        (setq mode 'vector)
	X	(setq ppdat (get (car elm) 'ppdat))
	X	(and ppdat (setq mode 'a-v))
	X	(setq sep '|(|)
	X        (setq lastpos 0)
	X	(do
	X	 ((curpos 1 (1+ curpos)) (vlist elm (cdr vlist)))
	X	 ((atom vlist) nil)
	X	 (setq val (car vlist))
	X	 (setq att (assoc curpos ppdat))
	X	 (cond (att (setq att (cdr att)))
	X	       (t (setq att curpos)))
	X         (and (symbolp att) (is-vector-attribute att) (setq mode 'vector))
	X	 (cond ((or (not (null val)) (eq mode 'vector))
	X		(princ sep port)
	X		(ppval val att lastpos port)
	X		(setq sep '|    |)
	X		(setq lastpos curpos))))
	X	(princ '|)| port)))
	X
	X(defun ppval (val att lastpos port)
	X  (cond ((not (equal att (1+ lastpos)))
	X         (princ '^ port)
	X         (princ att port)
	X         (princ '| | port)))
	X  (princ val port))
	X
	X
	X
	X;;; printing production memory
	X
	X(defmacro pm (&rest z)  `(progn (mapc #'pprule ',z) (terpri) nil)) 
	X
	X;Major modification here, because Common Lisp doesn't have a standard method
	X;for determining the column position of the cursor.  So we have to keep count.
	X;So colprinc records the current column number and prints the symbol.
	X
	X(proclaim '(special *current-col*))
	X(setq *current-col* 0)
	X
	X(defun nflatc(x)
	X   (length (princ-to-string x)))
	X
	X(defun colprinc(x)
	X    (setq *current-col* (+ *current-col* (nflatc x)))
	X    (princ x))
	X
	X(defun pprule (name)
	X  (prog (matrix next lab)
	X        (terpri)
	X        (setq *current-col* 0)
	X        (and (not (symbolp name)) (return nil))
	X        (setq matrix (get name 'production))
	X	(and (null matrix) (return nil))
	X	(terpri)
	X	(colprinc '|(p |)
	X	(colprinc name)
	X   top	(and (atom matrix) (go fin))
	X        (setq next (car matrix))
	X	(setq matrix (cdr matrix))
	X	(setq lab nil)
	X	(terpri)
	X	(cond ((eq next '-)
	X	       (colprinc '|  - |)
	X	       (setq next (car matrix))
	X	       (setq matrix (cdr matrix)))
	X	      ((eq next '-->)
	X	       (colprinc '|  |))
	X	      ((and (eq next '{) (atom (car matrix)))
	X	       (colprinc '|   {|)
	X	       (setq lab (car matrix))
	X	       (setq next (cadr matrix))
	X	       (setq matrix (cdddr matrix)))
	X	      ((eq next '{)
	X	       (colprinc '|   {|)
	X	       (setq lab (cadr matrix))
	X	       (setq next (car matrix))
	X	       (setq matrix (cdddr matrix)))
	X	      (t (colprinc '|    |)))
	X        (ppline next)
	X	(cond (lab (colprinc '| |) (colprinc lab) (colprinc '})))
	X	(go top)
	X    fin	(colprinc '|)|)))
	X
	X(defun ppline (line)
	X  (prog ()
	X	(cond ((atom line) (colprinc line))
	X              ((equalp (symbol-name (car line)) "DISPLACED") ;don't print expanded macros
	X               (ppline (cadr line)))
	X	      (t
	X	       (colprinc '|(|)
	X	       (setq *ppline* line)
	X	       (ppline2)
	X	       (colprinc '|)|)))
	X        (return nil)))
	X
	X(defun ppline2 ()
	X  (prog (needspace)
	X        (setq needspace nil)
	X   top  (and (atom *ppline*) (return nil))
	X        (and needspace (colprinc '| |))
	X        (cond ((eq (car *ppline*) #\^) (ppattval))
	X	      (t (pponlyval)))
	X        (setq needspace t)
	X        (go top)))
	X
	X;NWRITN, sort of. 
	X(defun nwritn(&optional port)
	X   (- 76 *current-col*))
	X
	X(defun ppattval ()
	X  (prog (att val)
	X        (setq att (cadr *ppline*))
	X	(setq *ppline* (cddr *ppline*))
	X	(setq val (getval))
	X	(cond ((> (+ (nwritn) (nflatc att) (nflatc val)) 76.)
	X	       (terpri)
	X	       (colprinc '|        |)))
	X        (colprinc '^)
	X	(colprinc att)
	X	(mapc (function (lambda (z) (colprinc '| |) (colprinc z))) val)))
	X
	X(defun pponlyval ()
	X  (prog (val needspace)
	X	(setq val (getval))
	X	(setq needspace nil)
	X	(cond ((> (+ (nwritn) (nflatc val)) 76.)
	X	       (setq needspace nil)
	X	       (terpri)
	X	       (colprinc '|        |)))
	X    top	(and (atom val) (return nil))
	X        (and needspace (colprinc '| |))
	X	(setq needspace t)
	X	(colprinc (car val))
	X	(setq val (cdr val))
	X	(go top)))
	X
	X(defun getval ()
	X  (prog (res v1)
	X        (setq v1 (car *ppline*))
	X	(setq *ppline* (cdr *ppline*))
	X	(cond ((member v1 '(= <> < <= => > <=>) :test #'eq)
	X	       (setq res (cons v1 (getval))))
	X	      ((eq v1 '{)
	X	       (setq res (cons v1 (getupto '}))))
	X	      ((eq v1 '<<)
	X	       (setq res (cons v1 (getupto '>>))))
	X	      ((eq v1 '//)
	X	       (setq res (list v1 (car *ppline*)))
	X	       (setq *ppline* (cdr *ppline*)))
	X	      (t (setq res (list v1))))
	X        (return res)))
	X
	X(defun getupto (end)
	X  (prog (v)
	X        (and (atom *ppline*) (return nil))
	X	(setq v (car *ppline*))
	X	(setq *ppline* (cdr *ppline*))
	X	(cond ((eq v end) (return (list v)))
	X	      (t (return (cons v (getupto end))))))) 
	X
	X
	X
	X
	X
	X
	X;;; backing up
	X
	X
	X
	X(defun record-index-plus (k)
	X  (setq *record-index* (+ k *record-index*))
	X  (cond ((< *record-index* 0.)
	X         (setq *record-index* *max-record-index*))
	X        ((> *record-index* *max-record-index*)
	X         (setq *record-index* 0.)))) 
	X
	X; the following routine initializes the record.  putting nil in the
	X; first slot indicates that that the record does not go back further
	X; than that.  (when the system backs up, it writes nil over the used
	X; records so that it will recognize which records it has used.  thus
	X; the system is set up anyway never to back over a nil.)
	X
	X(defun initialize-record nil
	X  (setq *record-index* 0.)
	X  (setq *recording* nil)
	X  (setq *max-record-index* 31.)
	X  (putvector *record-array* 0. nil)) 
	X
	X; *max-record-index* holds the maximum legal index for record-array
	X; so it and the following must be changed at the same time
	X
	X(defun begin-record (p data)
	X  (setq *recording* t)
	X  (setq *record* (list '=>refract p data))) 
	X
	X(defun end-record nil
	X  (cond (*recording*
	X         (setq *record*
	X               (cons *cycle-count* (cons *p-name* *record*)))
	X         (record-index-plus 1.)
	X         (putvector *record-array* *record-index* *record*)
	X         (setq *record* nil)
	X         (setq *recording* nil)))) 
	X
	X(defun record-change (direct time elm)
	X  (cond (*recording*
	X         (setq *record*
	X               (cons direct (cons time (cons elm *record*))))))) 
	X
	X; to maintain refraction information, need keep only one piece of information:
	X; need to record all unsuccessful attempts to delete things from the conflict
	X; set.  unsuccessful deletes are caused by attempting to delete refracted
	X; instantiations.  when backing up, have to avoid putting things back into the
	X; conflict set if they were not deleted when running forward
	X
	X(defun record-refract (rule data)
	X  (and *recording*
	X       (setq *record* (cons '<=refract (cons rule (cons data *record*))))))
	X
	X(defun refracted (rule data)
	X  (prog (z)
	X        (and (null *refracts*) (return nil))
	X	(setq z (cons rule data))
	X	(return (member z *refracts*))))
	X
	X(defun back (k)
	X  (prog (r)
	X   l   (and (< k 1.) (return nil))
	X        (setq r (getvector *record-array* *record-index*))
	X        (and (null r) (return '|nothing more stored|))
	X        (putvector *record-array* *record-index* nil)
	X        (record-index-plus -1.)
	X        (undo-record r)
	X        (setq k (1- k))
	X        (go l))) 
	X
	X(defun undo-record (r)
	X  (prog (save act a b rate)
	X        ;*recording* must be off during back up
	X        (setq save *recording*)
	X        (setq *refracts* nil)
	X        (setq *recording* nil)
	X        (and *ptrace* (back-print (list 'undo (car r) (cadr r))))
	X        (setq r (cddr r))
	X   top  (and (atom r) (go fin))
	X        (setq act (car r))
	X        (setq a (cadr r))
	X        (setq b (caddr r))
	X        (setq r (cdddr r))
	X        (and *wtrace* (back-print (list 'undo act a)))
	X        (cond ((eq act '<=wm) (add-to-wm b a))
	X              ((eq act '=>wm) (remove-from-wm b))
	X              ((eq act '<=refract)
	X               (setq *refracts* (cons (cons a b) *refracts*)))
	X              ((and (eq act '=>refract) (still-present b))
	X	       (setq *refracts* (delete (cons a b) *refracts*))
	X               (setq rate (rating-part (get a 'topnode)))
	X               (removecs a b)
	X               (insertcs a b rate))
	X              (t (%warn '|back: cannot undo action| (list act a))))
	X        (go top)
	X   fin  (setq *recording* save)
	X        (setq *refracts* nil)
	X        (return nil))) 
	X
	X; still-present makes sure that the user has not deleted something
	X; from wm which occurs in the instantiation about to be restored; it
	X; makes the check by determining whether each wme still has a time tag.
	X
	X(defun still-present (data)
	X  (prog nil
	X   l   (cond ((atom data) (return t))
	X              ((creation-time (car data))
	X               (setq data (cdr data))
	X               (go l))
	X              (t (return nil))))) 
	X
	X
	X(defun back-print (x) 
	X  (prog (port)
	X        (setq port (trace-file))
	X        (terpri port)
	X	(print x port)))
	X
	X
	X
	X
	X;;; Functions to show how close rules are to firing
	X
	X(defmacro matches (&rest rule-list)
	X  `(progn 
	X    (mapc (function matches2) ',rule-list)
	X    (terpri)) )
	X
	X(defun matches2 (p)
	X  (cond ((atom p)
	X         (terpri)
	X         (terpri)
	X         (princ p)
	X         (matches3 (get p 'backpointers) 2. (cons 1. nil))))) 
	X
	X(defun matches3 (nodes ce part)
	X  (cond ((not (null nodes))
	X         (terpri)
	X         (princ '| ** matches for |)
	X         (princ part)
	X         (princ '| ** |)
	X         (mapc (function write-elms) (find-left-mem (car nodes)))
	X         (terpri)
	X         (princ '| ** matches for |)
	X         (princ (cons ce nil))
	X         (princ '| ** |)
	X         (mapc (function write-elms) (find-right-mem (car nodes)))
	X         (matches3 (cdr nodes) (1+ ce) (cons ce part))))) 
	X
	X(defun write-elms (wme-or-count)
	X  (cond ((listp wme-or-count)
	X	 (terpri)
	X	 (mapc (function write-elms2) wme-or-count)))) 
	X
	X(defun write-elms2 (x)
	X  (princ '|  |)
	X  (princ (creation-time x)))
	X
	X(defun find-left-mem (node)
	X  (cond ((eq (car node) '&and) (memory-part (caddr node)))
	X        (t (car (caddr node))))) 
	X
	X(defun find-right-mem (node) (memory-part (cadddr node))) 
	X
	X
	X;;; Check the RHSs of productions 
	X
	X
	X(defun check-rhs (rhs) (mapc (function check-action) rhs))
	X
	X(defun check-action (x)
	X  (prog (a)
	X    (cond ((atom x)
	X           (%warn '|atomic action| x)
	X	   (return nil)))
	X    (setq a  (car x))
	X    (cond ((eq a 'bind) (check-bind x))
	X          ((eq a 'cbind) (check-cbind x))
	X          ((eq a 'make) (check-make x))
	X          ((eq a 'modify) (check-modify x))
	X          ((eq a 'oremove) (check-remove x))
	X          ((eq a 'owrite) (check-write x))
	X          ((eq a 'ocall) (check-call x))
	X          ((eq a 'halt) (check-halt x))
	X          ((eq a 'openfile) (check-openfile x))
	X          ((eq a 'closefile) (check-closefile x))
	X          ((eq a 'default) (check-default x))
	X          ((eq a 'build) (check-build x))
	X          ;;the following section is responsible for replacing standard ops RHS actions
	X          ;;with actions which don't conflict with existing CL functions.  The RPLACA function
	X          ;;is used so that the change will be reflected in the production body.
	X          ((eq a 'remove) (rplaca x 'oremove) 
	X                          (check-remove x))
	X          ((eq a 'write)   (rplaca x 'owrite)
	X                          (check-write x)) 
	X          ((eq a 'call)   (rplaca x 'ocall)
	X                          (check-call x))
	X          (t (%warn '|undefined rhs action| a))))) 
	X
	X(defun check-build (z)
	X  (and (null (cdr z)) (%warn '|needs arguments| z))
	X  (check-build-collect (cdr z)))
	X
	X(defun check-build-collect (args)
	X  (prog (r)
	X    top	(and (null args) (return nil))
	X	(setq r (car args))
	X	(setq args (cdr args))
	X	(cond ((listp r) (check-build-collect r))
	X	      ((eq r '\\)
	X	       (and (null args) (%warn '|nothing to evaluate| r))
	X	       (check-rhs-value (car args))
	X	       (setq args (cdr args))))
	X	(go top)))
	X
	X(defun check-remove (z) 
	X  (and (null (cdr z)) (%warn '|needs arguments| z))
	X  (mapc (function check-rhs-ce-var) (cdr z))) 
	X
	X(defun check-make (z)
	X  (and (null (cdr z)) (%warn '|needs arguments| z))
	X  (check-change& (cdr z))) 
	X
	X(defun check-openfile (z)
	X  (and (null (cdr z)) (%warn '|needs arguments| z))
	X  (check-change& (cdr z))) 
	X
	X(defun check-closefile (z)
	X  (and (null (cdr z)) (%warn '|needs arguments| z))
	X  (check-change& (cdr z))) 
	X
	X(defun check-default (z)
	X  (and (null (cdr z)) (%warn '|needs arguments| z))
	X  (check-change& (cdr z))) 
	X
	X(defun check-modify (z)
	X  (and (null (cdr z)) (%warn '|needs arguments| z))
	X  (check-rhs-ce-var (cadr z))
	X  (and (null (cddr z)) (%warn '|no changes to make| z))
	X  (check-change& (cddr z))) 
	X
	X(defun check-write (z)
	X  (and (null (cdr z)) (%warn '|needs arguments| z))
	X  (check-change& (cdr z))) 
	X
	X(defun check-call (z)
	X  (prog (f)
	X    (and (null (cdr z)) (%warn '|needs arguments| z))
	X    (setq f (cadr z))
	X    (and (variablep f)
	X         (%warn '|function name must be a constant| z))
	X    (or (symbolp f)
	X        (%warn '|function name must be a symbolic atom| f))
	X    (or (externalp f)
	X        (%warn '|function name not declared external| f))
	X    (check-change& (cddr z)))) 
	X
	X(defun check-halt (z)
	X  (or (null (cdr z)) (%warn '|does not take arguments| z))) 
	X
	X(defun check-cbind (z)
	X  (prog (v)
	X    (or (= (length z) 2.) (%warn '|takes only one argument| z))
	X    (setq v (cadr z))
	X    (or (variablep v) (%warn '|takes variable as argument| z))
	X    (note-ce-variable v))) 
	X
	X(defun check-bind (z)
	X  (prog (v)
	X    (or (> (length z) 1.) (%warn '|needs arguments| z))
	X    (setq v (cadr z))
	X    (or (variablep v) (%warn '|takes variable as argument| z))
	X    (note-variable v)
	X    (check-change& (cddr z)))) 
	X
	X
	X(defun check-change& (z)
	X  (prog (r tab-flag)
	X        (setq tab-flag nil)
	X   la   (and (atom z) (return nil))
	X        (setq r (car z))
	X        (setq z (cdr z))
	X        (cond ((eq r #\^)
	X               (and tab-flag
	X                    (%warn '|no value before this tab| (car z)))
	X               (setq tab-flag t)
	X               (check-tab-index (car z))
	X               (setq z (cdr z)))
	X              ((eq r '//) (setq tab-flag nil) (setq z (cdr z)))
	X              (t (setq tab-flag nil) (check-rhs-value r)))
	X        (go la))) 
	X
	X(defun check-rhs-ce-var (v)
	X  (cond ((and (not (numberp v)) (not (ce-bound? v)))
	X         (%warn '|unbound element variable| v))
	X        ((and (numberp v) (or (< v 1.) (> v *ce-count*)))
	X         (%warn '|numeric element designator out of bounds| v)))) 
	X
	X(defun check-rhs-value (x)
	X  (cond ((and x (listp x)) (check-rhs-function x))
	X        (t (check-rhs-atomic x)))) 
	X
	X(defun check-rhs-atomic (x)
	X  (and (variablep x) 
	X       (not (bound? x)) 
	X       (%warn '|unbound variable| x)))
	X
	X(defun check-rhs-function (x)
	X  (prog (a)
	X    (setq a (car x))
	X    (cond ((eq a 'compute) (check-compute x))
	X          ((eq a 'arith) (check-compute x))
	X          ((eq a 'substr) (check-substr x))
	X          ((eq a 'accept) (check-accept x))
	X          ((eq a 'acceptline) (check-acceptline x))
	X          ((eq a 'crlf) (check-crlf x))
	X          ((eq a 'genatom) (check-genatom x))
	X	  ((eq a 'litval) (check-litval x))
	X          ((eq a 'tabto) (check-tabto x))
	X	  ((eq a 'rjust) (check-rjust x))
	X	  ((not (externalp a))
	X	   (%warn '"rhs function not declared external" a)))))
	X
	X(defun check-litval (x) 
	X  (or (= (length x) 2) (%warn '|wrong number of arguments| x))
	X  (check-rhs-atomic (cadr x)))
	X
	X(defun check-accept (x)
	X  (cond ((= (length x) 1) nil)
	X        ((= (length x) 2) (check-rhs-atomic (cadr x)))
	X	(t (%warn '|too many arguments| x))))
	X
	X(defun check-acceptline (x)
	X  (mapc (function check-rhs-atomic) (cdr x)))
	X
	X(defun check-crlf (x) 
	X  (check-0-args x)) 
	X
	X(defun check-genatom (x) (check-0-args x)) 
	X
	X(defun check-tabto (x)
	X  (or (= (length x) 2) (%warn '|wrong number of arguments| x))
	X  (check-print-control (cadr x)))
	X
	X(defun check-rjust (x)
	X  (or (= (length x) 2) (%warn '|wrong number of arguments| x))
	X  (check-print-control (cadr x)))
	X
	X(defun check-0-args (x)
	X  (or (= (length x) 1.) (%warn '|should not have arguments| x))) 
	X
	X(defun check-substr (x)
	X  (or (= (length x) 4.) (%warn '|wrong number of arguments| x))
	X  (check-rhs-ce-var (cadr x))
	X  (check-substr-index (caddr x))
	X  (check-last-substr-index (cadddr x))) 
	X
	X(defun check-compute (x) (check-arithmetic (cdr x))) 
	X
	X(defun check-arithmetic (l)
	X  (cond ((atom l)
	X         (%warn '|syntax error in arithmetic expression| l))
	X        ((atom (cdr l)) (check-term (car l)))
	X        ((not (member (cadr l) '(+ - * // \\) :test #'eq))
	X         (%warn '|unknown operator| l))
	X        (t (check-term (car l)) (check-arithmetic (cddr l))))) 
	X
	X(defun check-term (x)
	X  (cond ((listp x) (check-arithmetic x))
	X        (t (check-rhs-atomic x)))) 
	X
	X(defun check-last-substr-index (x)
	X  (or (eq x 'inf) (check-substr-index x))) 
	X
	X(defun check-substr-index (x)
	X  (prog (v)
	X    (cond ((bound? x) (return x)))
	X    (setq v ($litbind x))
	X    (cond ((not (numberp v))
	X           (%warn '|unbound symbol used as index in substr| x))
	X          ((or (< v 1.) (> v 127.))
	X           (%warn '|index out of bounds in tab| x))))) 
	X
	X(defun check-print-control (x)
	X  (prog ()
	X    (cond ((bound? x) (return x)))
	X    (cond ((or (not (numberp x)) (< x 1.) (> x 127.))
	X           (%warn '|illegal value for printer control| x))))) 
	X
	X(defun check-tab-index (x)
	X  (prog (v)
	X    (cond ((bound? x) (return x)))
	X    (setq v ($litbind x))
	X    (cond ((not (numberp v))
	X           (%warn '|unbound symbol occurs after ^| x))
	X          ((or (< v 1.) (> v 127.))
	X           (%warn '|index out of bounds after ^| x))))) 
	X
	X(defun note-variable (var)
	X  (setq *rhs-bound-vars* (cons var *rhs-bound-vars*)))
	X
	X(defun bound? (var)
	X  (or (member var *rhs-bound-vars* :test #'eq)
	X      (var-dope var)))
	X
	X(defun note-ce-variable (ce-var)
	X  (setq *rhs-bound-ce-vars* (cons ce-var *rhs-bound-ce-vars*)))
	X
	X(defun ce-bound? (ce-var)
	X  (or (member ce-var *rhs-bound-ce-vars* :test #'eq)
	X      (ce-var-dope ce-var)))
	X
	X;;; Top level routines
	X
	X(defun process-changes (adds dels)
	X  (prog (x)
	X   process-deletes (and (atom dels) (go process-adds))
	X        (setq x (car dels))
	X        (setq dels (cdr dels))
	X        (remove-from-wm x)
	X        (go process-deletes)
	X   process-adds (and (atom adds) (return nil))
	X        (setq x (car adds))
	X        (setq adds (cdr adds))
	X        (add-to-wm x nil)
	X        (go process-adds))) 
	X
	X(defun main nil
	X  (prog (instance r)
	X        (setq *halt-flag* nil)
	X        (setq *break-flag* nil)
	X        (setq instance nil)
	X   dil  (setq *phase* 'conflict-resolution)
	X        (cond (*halt-flag*
	X               (setq r '|end -- explicit halt|)
	X               (go finis))
	X	      ((zerop *remaining-cycles*)
	X	       (setq r '***break***)
	X	       (setq *break-flag* t)
	X	       (go finis))
	X              (*break-flag* (setq r '***break***) (go finis)))
	X	(setq *remaining-cycles* (1- *remaining-cycles*))
	X        (setq instance (conflict-resolution))
	X        (cond ((not instance)
	X               (setq r '|end -- no production true|)
	X               (go finis)))
	X        (setq *phase* (car instance))
	X        (accum-stats)
	X        (eval-rhs (car instance) (cdr instance))
	X        (check-limits)
	X	(and (broken (car instance)) (setq *break-flag* t))
	X        (go dil)
	X  finis (setq *p-name* nil)
	X        (return r))) 
	X
	X(defun do-continue (wmi)
	X    (cond (*critical*
	X           (terpri)
	X           (princ '|warning: network may be inconsistent|)))
	X    (process-changes wmi nil)
	X    (print-times (main))) 
	X
	X(defun accum-stats nil
	X  (setq *cycle-count* (1+ *cycle-count*))
	X  (setq *total-token* (+ *total-token* *current-token*))
	X  (cond ((> *current-token* *max-token*)
	X         (setq *max-token* *current-token*)))
	X  (setq *total-wm* (+ *total-wm* *current-wm*))
	X  (cond ((> *current-wm* *max-wm*) (setq *max-wm* *current-wm*)))) 
	X
	X
	X(defun print-times (mess)
	X  (prog (cc ac)
	X    	(cond (*break-flag* (terpri) (return mess)))
	X        (setq cc (+ (float *cycle-count*) 1.0e-20))
	X        (setq ac (+ (float *action-count*) 1.0e-20))
	X        (terpri)
	X        (princ mess)
	X        (pm-size)
	X        (printlinec (list *cycle-count*
	X                          'firings
	X                          (list *action-count* 'rhs 'actions)))
	X        (terpri)
	X        (printlinec (list (round (/ (float *total-wm*) cc))
	X                          'mean 'working 'memory 'size
	X                          (list *max-wm* 'maximum)))
	X        (terpri)
	X        (printlinec (list (round (/ (float *total-cs*) cc))
	X                          'mean 'conflict 'set 'size
	X                          (list *max-cs* 'maximum)))
	X        (terpri)
	X        (printlinec (list (round (/ (float *total-token*) cc))
	X                          'mean 'token 'memory 'size
	X                          (list *max-token* 'maximum)))
	X        (terpri))) 
	X
	X(defun pm-size nil
	X  (terpri)
	X  (printlinec (list *pcount*
	X                    'productions
	X                    (list *real-cnt* '// *virtual-cnt* 'nodes)))
	X  (terpri)) 
	X
	X(defun check-limits nil
	X  (cond ((> (length *conflict-set*) *limit-cs*)
	X         (terpri)
	X         (terpri)
	X         (printlinec (list '|conflict set size exceeded the limit of|
	X                           *limit-cs*
	X                           '|after|
	X                           *p-name*))
	X         (setq *halt-flag* t)))
	X  (cond ((> *current-token* *limit-token*)
	X         (terpri)
	X         (terpri)
	X         (printlinec (list '|token memory size exceeded the limit of|
	X                           *limit-token*
	X                           '|after|
	X                           *p-name*))
	X         (setq *halt-flag* t)))) 
	X
	X
	X(defun top-level-remove (z)
	X  (cond ((equal z '(*)) (process-changes nil (get-wm nil)))
	X        (t (process-changes nil (get-wm z))))) 
	X
	X(defmacro excise (&rest z) `(mapc (function excise-p) ',z))
	X
	X(defmacro run (&rest z)
	X  `(cond ((null ',z) (setq *remaining-cycles* 1000000.) (do-continue nil))
	X        ((and (atom (cdr ',z)) (numberp (car ',z)) (> (car ',z) 0.))
	X         (setq *remaining-cycles* (car ',z))
	X         (do-continue nil))
	X        (t 'what\?))) 
	X
	X(defmacro strategy (&rest z)
	X  `(cond ((atom ',z) *strategy*)
	X        ((equal ',z '(lex)) (setq *strategy* 'lex))
	X        ((equal ',z '(mea)) (setq *strategy* 'mea))
	X        (t 'what\?))) 
	X
	X(defmacro cs (&optional z)
	X  `(cond ((null ',z) (conflict-set))
	X        (t 'what?))) 
	X
	X(defmacro watch (&rest z)
	X  `(cond ((equal ',z '(0.))
	X         (setq *wtrace* nil)
	X         (setq *ptrace* nil)
	X         0.)
	X        ((equal ',z '(1.)) (setq *wtrace* nil) (setq *ptrace* t) 1.)
	X        ((equal ',z '(2.)) (setq *wtrace* t) (setq *ptrace* t) 2.)
	X        ((equal ',z '(3.))
	X         (setq *wtrace* t)
	X         (setq *ptrace* t)
	X         '(2. -- conflict set trace not supported))
	X        ((and (atom ',z) (null *ptrace*)) 0.)
	X        ((and (atom ',z) (null *wtrace*)) 1.)
	X        ((atom ',z) 2.)
	X        (t 'what\?))) 
	X
	X(defmacro external  (&rest z) `(catch (external2 ',z) '!error!))
	X
	X(defun external2 (z) (mapc (function external3) z))
	X
	X(defun external3 (x) 
	X  (cond ((symbolp x) (putprop x t 'external-routine)
	X		     (setq *externals* (enter x *externals*)))
	X	(t (%error '|not a legal function name| x))))
	X
	X(defun externalp (x)
	X  (cond ((symbolp x) (get x 'external-routine))
	X	(t (%warn '|not a legal function name| x) nil)))
	X
	X(defmacro pbreak (&rest z)
	X  `(cond ((atom ',z) (terpri) *brkpts*)
	X	(t (mapc (function pbreak2) ',z) nil)))
	X
	X(defun pbreak2 (rule)
	X  (cond ((not (symbolp rule)) (%warn '|illegal name| rule))
	X	((not (get rule 'topnode)) (%warn '|not a production| rule))
	X	((member rule *brkpts* :test #'eq) (setq *brkpts* (rematm rule *brkpts*)))
	X	(t (setq *brkpts* (cons rule *brkpts*)))))
	X
	X(defun rematm (atm list)
	X  (cond ((atom list) list)
	X	((eq atm (car list)) (rematm atm (cdr list)))
	X	(t (cons (car list) (rematm atm (cdr list))))))
	X
	X(defun broken (rule) (member rule *brkpts* :test #'eq))
	X
	X
	XFRANZ.OPS
	X
	X;	VPS2 -- Interpreter for OPS5
	X;
	X;	Copyright (C) 1979, 1980, 1981
	X;	Charles L. Forgy,  Pittsburgh, Pennsylvania
	X
	X
	X
	X; Users of this interpreter are requested to contact
	X;
	X;	Charles Forgy
	X;	Computer Science Department
	X;	Carnegie-Mellon University
	X;	Pittsburgh, PA  15213
	X; or
	X;	Forgy@CMUA
	X; 
	X; so that they can be added to the mailing list for OPS5.  The mailing list
	X; is needed when new versions of the interpreter or manual are released.
	X
	X
	X
	X
	X;   Modifications added starting July, 1982 to make it easier to build 
	X;   user environment - Ruven Brooks
	X;                      ITT Integrated Systems Center
	X;                      1 Research Drive
	X;                      Shelton, CT.
	X
	X;;; Definitions
	X
	X
	X
	X(declare (special *matrix* *feature-count* *pcount* *vars* *cur-vars*
	X          *curcond* *subnum* *last-node* *last-branch* *first-node*
	X          *sendtocall* *flag-part* *alpha-flag-part* *data-part*
	X          *alpha-data-part* *ce-vars* *virtual-cnt* *real-cnt*
	X          *current-token* *c1* *c2* *c3* *c4* *c5* *c6* *c7* *c8* *c9*
	X          *c10* *c11* *c12* *c13* *c14* *c15* *c16* *c17* *c18* *c19*
	X          *c20* *c21* *c22* *c23* *c24* *c25* *c26* *c27* *c28* *c29*
	X          *c30* *c31* *c32* *c33* *c34* *c35* *c36* *c37* *c38* *c39*
	X          *c40* *c41* *c42* *c43* *c44* *c45* *c46* *c47* *c48* *c49*
	X          *c50* *c51* *c52* *c53* *c54* *c55* *c56* *c57* *c58* *c59*
	X          *c60* *c61* *c62* *c63* *c64* *record-array* *result-array* 
	X          *max-cs* *total-cs* *limit-cs* *cr-temp* *side*
	X          *conflict-set* *halt-flag* *phase* *critical*
	X          *cycle-count* *total-token* *max-token* *refracts* 
	X          *limit-token* *total-wm* *current-wm* *max-wm*
	X          *action-count* *wmpart-list* *wm* *data-matched* *p-name*
	X          *variable-memory* *ce-variable-memory* 
	X          *max-index* ; number of right-most field in wm element 
	X          *next-index* *size-result-array* *rest* *build-trace* *last*
	X          *ptrace* *wtrace* *in-rhs* *recording* *accept-file* *trace-file* 
	X          *mtrace* *madeby* ; used to trace and record makers of elements
	X          *write-file* *record-index* *max-record-index* *old-wm*
	X          *record* *filters* *break-flag* *strategy* *remaining-cycles*
	X	  *wm-filter* *rhs-bound-vars* *rhs-bound-ce-vars* *ppline* 
	X	  *ce-count* *brkpts* *class-list* *buckets* *action-type*
	X          *literals*   ;stores literal definitions
	X          *pnames*     ;stores production names
	X	  *externals*  ;tracks external declarations 
	X          *vector-attributes*  ;list of vector-attributes
	X	  ))
	X
	X(declare (localf ce-gelm gelm peek-sublex sublex
	X          eval-nodelist sendto and-left and-right not-left not-right
	X          top-levels-eq add-token real-add-token remove-old
	X          remove-old-num remove-old-no-num removecs insertcs dsort
	X          best-of best-of* conflict-set-compare =alg ))
	X
	X
	X;;; Functions that were revised so that they would compile efficiently
	X
	X
	X;* The function == is machine dependent\!
	X;* This function compares small integers for equality.  It uses EQ
	X;* so that it will be fast, and it will consequently not work on all
	X;* Lisps.  It works in Franz Lisp for integers in [-128, 127]
	X
	X(def == (macro (z) `(eq ,(cadr z) ,(caddr z))))
	X
	X; =ALG returns T if A and B are algebraicly equal.
	X
	X(defun =alg (a b) (zerop (difference a b)))
	X
	X(def fast-symeval 
	X  (macro (z)
	X	 `(cond ((eq ,(cadr z) '*c1*) *c1*)
	X		((eq ,(cadr z) '*c2*) *c2*)
	X		((eq ,(cadr z) '*c3*) *c3*)
	X		((eq ,(cadr z) '*c4*) *c4*)
	X		((eq ,(cadr z) '*c5*) *c5*)
	X		((eq ,(cadr z) '*c6*) *c6*)
	X		((eq ,(cadr z) '*c7*) *c7*)
	X		(t (eval ,(cadr z)))]
	X
	X; getvector and putvector are fast routines for using one-dimensional
	X; arrays.  these routines do no checking; they assume
	X;	1. the array is a vector with 0 being the index of the first
	X;	   element
	X;	2. the vector holds arbitrary list values
	X
	X; Example call: (putvector array index value)
	X
	X(def putvector
	X  (macro (z)
	X    (list '*rplacx (caddr z) (cadr z) (cadddr z))]
	X
	X; Example call: (getvector name index)
	X
	X(def getvector
	X  (macro (z)
	X    (list 'cxr (caddr z) (cadr z))]
	X
	X(defun ce-gelm (x k)
	X  (prog nil
	X   loop (and (== k 1.) (return (car x)))
	X        (setq k (1- k))
	X        (setq x (cdr x))
	X        (go loop))) 
	X
	X; The loops in gelm were unwound so that fewer calls on DIFFERENCE
	X; would be needed
	X
	X(defun gelm (x k)
	X  (prog (ce sub)
	X        (setq ce (/ k 10000.))
	X        (setq sub (- k (* ce 10000.)))
	X   celoop (and (== ce 0.) (go ph2))
	X        (setq x (cdr x))
	X        (and (== ce 1.) (go ph2))
	X        (setq x (cdr x))
	X        (and (== ce 2.) (go ph2))
	X        (setq x (cdr x))
	X        (and (== ce 3.) (go ph2))
	X        (setq x (cdr x))
	X        (and (== ce 4.) (go ph2))
	X        (setq ce (- ce 4.))
	X        (go celoop)
	X   ph2  (setq x (car x))
	X   subloop (and (== sub 0.) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 1.) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 2.) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 3.) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 4.) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 5.) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 6.) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 7.) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 8.) (go finis))
	X        (setq sub (- sub 8.))
	X        (go subloop)
	X   finis (return (car x)))) 
	X
	X
	X;;; Utility functions
	X
	X
	X
	X(defun printline (x) (mapc (function printline*) x)) 
	X
	X(defun printline* (y) (princ '| |) (print y)) 
	X
	X(defun printlinec (x) (mapc (function printlinec*) x)) 
	X
	X(defun printlinec* (y) (princ '| |) (princ y)) 
	X
	X; intersect two lists using eq for the equality test
	X
	X(defun interq (x y)
	X  (cond ((atom x) nil)
	X        ((memq (car x) y) (cons (car x) (interq (cdr x) y)))
	X        (t (interq (cdr x) y)))) 
	X
	X(defun enter (x ll)
	X   (and (not (member x ll)) (setq ll (cons x ll))))
	X
	X; later versions of Franz have this standard
	X(defun neq (x y)
	X   (not (eq x y)))
	X(defun i-g-v nil
	X (prog (x)
	X	(sstatus translink t)
	X	(setsyntax '\{ 66.)
	X	(setsyntax '\} 66.)
	X	(setsyntax '^ 66.)
	X	(setq *buckets* 64.)		; OPS5 allows 64 named slots
	X	(setq *accept-file* nil)
	X	(setq *write-file* nil)
	X	(setq *trace-file* nil)
	X	(setq *class-list* nil)
	X	(setq *brkpts* nil)
	X	(setq *strategy* 'lex)
	X  	(setq *in-rhs* nil)
	X  	(setq *ptrace* t)
	X  	(setq *wtrace* nil)
	X	(setq *mtrace* t)            ; turn on made-by tracing
	X	(setq *madeby* nil)          ; record makers of wm elements
	X  	(setq *recording* nil)
	X        (setq *refracts* nil)
	X	(setq *real-cnt* (setq *virtual-cnt* 0.))
	X	(setq *max-cs* (setq *total-cs* 0.))
	X  	(setq *limit-token* 1000000.)
	X	(setq *limit-cs* 1000000.)
	X	(setq *critical* nil)
	X	(setq *build-trace* nil)
	X	(setq *wmpart-list* nil)
	X        (setq *pnames* nil)
	X        (setq *literals* nil) ; records literal definitions
	X	(setq *externals* nil) ; records external definitions
	X	(setq *vector-attributes* nil) ;records vector attributes
	X	(setq *size-result-array* 127.)
	X	(setq *result-array* (*makhunk 6))
	X	(setq *record-array* (*makhunk 6))
	X	(setq x 0)
	X        (setq *pnames* nil)     ; list of production names
	X  loop	(putvector *result-array* x nil)
	X	(setq x (1+ x))
	X	(and (not (> x *size-result-array*)) (go loop))
	X	(make-bottom-node)
	X	(setq *pcount* 0.)
	X	(initialize-record)
	X	(setq *cycle-count* (setq *action-count* 0.))
	X	(setq *total-token*
	X	       (setq *max-token* (setq *current-token* 0.)))
	X	(setq *total-cs* (setq *max-cs* 0.))
	X	(setq *total-wm* (setq *max-wm* (setq *current-wm* 0.)))
	X	(setq *conflict-set* nil)
	X	(setq *wmpart-list* nil)
	X	(setq *p-name* nil)
	X	(setq *remaining-cycles* 1000000)]
	X
	X; if the size of result-array changes, change the line in i-g-v which
	X; sets the value of *size-result-array*
	X
	X(defun \%warn (what where)
	X  (prog nil
	X    (terpri)
	X    (princ '\?)
	X    (and *p-name* (princ *p-name*))
	X    (princ '|..|)
	X    (princ where)
	X    (princ '|..|)
	X    (princ what)
	X    (return where))) 
	X
	X(defun %error (what where)
	X    (%warn what where)
	X    (throw '\!error\! \!error\!)) 
	X
	X(defun round (x) (fix (plus 0.5 x))) 
	X
	X(defun top-levels-eq (la lb)
	X  (prog nil
	X   lx   (cond ((eq la lb) (return t))
	X              ((null la) (return nil))
	X              ((null lb) (return nil))
	X              ((not (eq (car la) (car lb))) (return nil)))
	X        (setq la (cdr la))
	X        (setq lb (cdr lb))
	X        (go lx))) 
	X
	X
	X;;; LITERAL and LITERALIZE
	X
	X(defun literal fexpr (z)
	X  (prog (atm val old)
	X   top  (and (atom z) (return 'bound))
	X        (or (eq (cadr z) '=) (return (%warn '|wrong format| z)))
	X        (setq atm (car z))
	X        (setq val (caddr z))
	X        (setq z (cdddr z))
	X        (cond ((not (numberp val))
	X               (%warn '|can bind only to numbers| val))
	X              ((or (not (symbolp atm)) (variablep atm))
	X               (%warn '|can bind only constant atoms| atm))
	X              ((and (setq old (literal-binding-of atm)) (not (equal old val)))
	X               (%warn '|attempt to rebind attribute| atm))
	X              (t (putprop atm val 'ops-bind)))
	X        (go top))) 
	X
	X(defun literalize fexpr (l)
	X  (prog (class-name atts)
	X    (setq class-name (car l))
	X    (cond ((have-compiled-production)
	X           (%warn '|literalize called after p| class-name)
	X           (return nil))
	X          ((get class-name 'att-list)
	X           (%warn '|attempt to redefine class| class-name)
	X	   (return nil)))
	X    (setq *class-list* (cons class-name *class-list*))
	X    (setq atts (remove-duplicates (cdr l)))
	X    (test-attribute-names atts)
	X    (mark-conflicts atts atts)
	X    (putprop class-name atts 'att-list))) 
	X
	X(defun vector-attribute fexpr (l)
	X  (cond ((have-compiled-production)
	X         (%warn '|vector-attribute called after p| l))
	X        (t 
	X         (test-attribute-names l)
	X	 (mapc (function vector-attribute2) l)))) 
	X
	X(defun vector-attribute2 (att) (putprop att t 'vector-attribute)
	X			       (setq  *vector-attributes* 
	X				   (enter att *vector-attributes*)))
	X
	X(defun is-vector-attribute (att) (get att 'vector-attribute))
	X
	X(defun test-attribute-names (l)
	X  (mapc (function test-attribute-names2) l)) 
	X
	X(defun test-attribute-names2 (atm)
	X  (cond ((or (not (symbolp atm)) (variablep atm))
	X         (%warn '|can bind only constant atoms| atm)))) 
	X
	X(defun finish-literalize nil
	X  (cond ((not (null *class-list*))
	X         (mapc (function note-user-assigns) *class-list*)
	X         (mapc (function assign-scalars) *class-list*)
	X         (mapc (function assign-vectors) *class-list*)
	X         (mapc (function put-ppdat) *class-list*)
	X         (mapc (function erase-literal-info) *class-list*)
	X         (setq *class-list* nil)
	X         (setq *buckets* nil)))) 
	X
	X(defun have-compiled-production nil (not (zerop *pcount*))) 
	X
	X(defun put-ppdat (class)
	X  (prog (al att ppdat)
	X        (setq ppdat nil)
	X        (setq al (get class 'att-list))
	X   top  (cond ((not (atom al))
	X               (setq att (car al))
	X               (setq al (cdr al))
	X               (setq ppdat
	X                     (cons (cons (literal-binding-of att) att)
	X                           ppdat))
	X               (go top)))
	X        (putprop class ppdat 'ppdat))) 
	X
	X; note-user-assigns and note-user-vector-assigns are needed only when
	X; literal and literalize are both used in a program.  They make sure that
	X; the assignments that are made explicitly with literal do not cause problems
	X; for the literalized classes.
	X
	X(defun note-user-assigns (class)
	X  (mapc (function note-user-assigns2) (get class 'att-list)))
	X
	X(defun note-user-assigns2 (att)
	X  (prog (num conf buck clash)
	X        (setq num (literal-binding-of att))
	X	(and (null num) (return nil))
	X	(setq conf (get att 'conflicts))
	X	(setq buck (store-binding att num))
	X	(setq clash (find-common-atom buck conf))
	X	(and clash
	X	     (%warn '|attributes in a class assigned the same number|
	X	            (cons att clash)))
	X        (return nil)))
	X
	X(defun note-user-vector-assigns (att given needed)
	X  (and (> needed given)
	X       (%warn '|vector attribute assigned too small a value in literal| att)))
	X
	X(defun assign-scalars (class)
	X  (mapc (function assign-scalars2) (get class 'att-list))) 
	X
	X(defun assign-scalars2 (att)
	X  (prog (tlist num bucket conf)
	X        (and (literal-binding-of att) (return nil))
	X        (and (is-vector-attribute att) (return nil))
	X        (setq tlist (buckets))
	X        (setq conf (get att 'conflicts))
	X   top  (cond ((atom tlist)
	X               (%warn '|could not generate a binding| att)
	X               (store-binding att -1.)
	X               (return nil)))
	X        (setq num (caar tlist))
	X        (setq bucket (cdar tlist))
	X        (setq tlist (cdr tlist))
	X        (cond ((disjoint bucket conf) (store-binding att num))
	X        (t (go top))))) 
	X
	X(defun assign-vectors (class)
	X  (mapc (function assign-vectors2) (get class 'att-list))) 
	X
	X(defun assign-vectors2 (att)
	X  (prog (big conf new old need)
	X        (and (not (is-vector-attribute att)) (return nil))
	X        (setq big 1.)
	X        (setq conf (get att 'conflicts))
	X   top  (cond ((not (atom conf))
	X               (setq new (car conf))
	X               (setq conf (cdr conf))
	X               (cond ((is-vector-attribute new)
	X                      (%warn '|class has two vector attributes|
	X		              (list att new)))
	X                     (t (setq big (max (literal-binding-of new) big))))
	X               (go top)))
	X        (setq need (1+ big))
	X	(setq old (literal-binding-of att))
	X	(cond (old (note-user-vector-assigns att old need))
	X	      (t (store-binding att need)))
	X        (return nil)))
	X
	X(defun disjoint (la lb) (not (find-common-atom la lb))) 
	X
	X(defun find-common-atom (la lb)
	X  (prog nil
	X   top  (cond ((null la) (return nil))
	X              ((memq (car la) lb) (return (car la)))
	X              (t (setq la (cdr la)) (go top))))) 
	X
	X(defun mark-conflicts (rem all)
	X  (cond ((not (null rem))
	X         (mark-conflicts2 (car rem) all)
	X         (mark-conflicts (cdr rem) all)))) 
	X
	X(defun mark-conflicts2 (atm lst)
	X  (prog (l)
	X        (setq l lst)
	X   top  (and (atom l) (return nil))
	X        (conflict atm (car l))
	X        (setq l (cdr l))
	X        (go top))) 
	X
	X(defun conflict (a b)
	X  (prog (old)
	X    (setq old (get a 'conflicts))
	X    (and (not (eq a b))
	X         (not (memq b old))
	X         (putprop a (cons b old) 'conflicts)))) 
	X
	X(defun remove-duplicates (lst)
	X  (cond ((atom lst) nil)
	X        ((memq (car lst) (cdr lst)) (remove-duplicates (cdr lst)))
	X        (t (cons (car lst) (remove-duplicates (cdr lst)))))) 
	X
	X(defun literal-binding-of (name) (get name 'ops-bind)) 
	X
	X(defun store-binding (name lit)
	X  (putprop name lit 'ops-bind)
	X  (add-bucket name lit)) 
	X
	X(defun add-bucket (name num)
	X  (prog (buc)
	X    (setq buc (assoc num (buckets)))
	X    (and (not (memq name buc))
	X         (rplacd buc (cons name (cdr buc))))
	X    (return buc))) 
	X
	X(defun buckets nil
	X  (and (atom *buckets*) (setq *buckets* (make-nums *buckets*)))
	X  *buckets*) 
	X
	X(defun make-nums (k)
	X  (prog (nums)
	X        (setq nums nil)
	X   l    (and (< k 2.) (return nums))
	X        (setq nums (cons (ncons k) nums))
	X        (setq k (1- k))
	X        (go l))) 
	X
	X;(defun erase-literal-info (class)
	X;  (mapc (function erase-literal-info2) (get class 'att-list))
	X;  (remprop class 'att-list)) 
	X
	X; modified to record literal info in the variable *literals*
	X(def erase-literal-info
	X     (lambda (class)
	X      (setq *literals*
	X            (cons (cons class (get class 'att-list)) *literals*))
	X      (mapc (function erase-literal-info2) (get class 'att-list))
	X      (remprop class 'att-list)))
	X
	X
	X(defun erase-literal-info2 (att) (remprop att 'conflicts)) 
	X
	X
	X;;; LHS Compiler
	X
	X(defun p fexpr (z) 
	X  (finish-literalize)
	X  (princ '*) 
	X  (drain)
	X  (compile-production (car z) (cdr z))) 
	X
	X(defun compile-production (name matrix)
	X  (prog (erm)
	X        (setq *p-name* name)
	X        (setq erm (catch (cmp-p name matrix) \!error\!))
	X	; following line is modified to save production name on *pnames*
	X        (and (null erm) (setq *pnames* (enter name *pnames*)))
	X	(setq *p-name* nil)
	X	(return erm)))
	X
	X(defun peek-lex nil (car *matrix*)) 
	X
	X(defun lex nil
	X  (prog2 nil (car *matrix*) (setq *matrix* (cdr *matrix*)))) 
	X
	X(defun end-of-p nil (atom *matrix*)) 
	X
	X(defun rest-of-p nil *matrix*) 
	X
	X(defun prepare-lex (prod) (setq *matrix* prod)) 
	X
	X
	X(defun peek-sublex nil (car *curcond*)) 
	X
	X(defun sublex nil
	X  (prog2 nil (car *curcond*) (setq *curcond* (cdr *curcond*)))) 
	X
	X(defun end-of-ce nil (atom *curcond*)) 
	X
	X(defun rest-of-ce nil *curcond*) 
	X
	X(defun prepare-sublex (ce) (setq *curcond* ce)) 
	X
	X(defun make-bottom-node nil (setq *first-node* (list '&bus nil))) 
	X
	X(defun cmp-p (name matrix)
	X  (prog (m bakptrs)
	X        (cond ((or (null name) (dtpr name))
	X               (%error '|illegal production name| name))
	X              ((equal (get name 'production) matrix)
	X	       (return nil)))
	X        (prepare-lex matrix)
	X        (excise-p name)
	X        (setq bakptrs nil)
	X        (setq *pcount* (1+ *pcount*))
	X        (setq *feature-count* 0.)
	X	(setq *ce-count* 0)
	X        (setq *vars* nil)
	X        (setq *ce-vars* nil)
	X	(setq *rhs-bound-vars* nil)
	X	(setq *rhs-bound-ce-vars* nil)
	X        (setq *last-branch* nil)
	X        (setq m (rest-of-p))
	X   l1   (and (end-of-p) (%error '|no '-->' in production| m))
	X        (cmp-prin)
	X        (setq bakptrs (cons *last-branch* bakptrs))
	X        (or (eq '--> (peek-lex)) (go l1))
	X        (lex)
	X	(check-rhs (rest-of-p))
	X        (link-new-node (list '&p
	X                             *feature-count*
	X                             name
	X                             (encode-dope)
	X                             (encode-ce-dope)
	X                             (cons 'progn (rest-of-p))))
	X        (putprop name (cdr (nreverse bakptrs)) 'backpointers)
	X	(putprop name matrix 'production)
	X        (putprop name *last-node* 'topnode))) 
	X
	X(defun rating-part (pnode) (cadr pnode)) 
	X
	X(defun var-part (pnode) (car (cdddr pnode))) 
	X
	X(defun ce-var-part (pnode) (cadr (cdddr pnode))) 
	X
	X(defun rhs-part (pnode) (caddr (cdddr pnode))) 
	X
	X(defun excise-p (name)
	X  (cond ((and (symbolp name) (get name 'topnode))
	X	 (printline (list name 'is 'excised))
-- 
---------------
C'est la vie, C'est la guerre, C'est la pomme de terre
Mail:	Imagen Corp. 2650 San Tomas Expressway Santa Clara, CA 95052-8101 
UUCP:	...{decvax,ucbvax}!decwrl!imagen!turner      AT&T: (408) 986-9400

turner@imagen.UUCP (D'arc Angel) (01/19/87)

	X         (setq *pcount* (1- *pcount*))
	X         (remove-from-conflict-set name)
	X         (kill-node (get name 'topnode))
	X         (setq *pnames* (delq name *pnames*))
	X	 (remprop name 'production)
	X	 (remprop name 'backpointers)
	X         (remprop name 'topnode)))) 
	X
	X(defun kill-node (node)
	X  (prog nil
	X   top  (and (atom node) (return nil))
	X        (rplaca node '&old)
	X        (setq node (cdr node))
	X        (go top))) 
	X
	X(defun cmp-prin nil
	X  (prog nil
	X        (setq *last-node* *first-node*)
	X        (cond ((null *last-branch*) (cmp-posce) (cmp-nobeta))
	X              ((eq (peek-lex) '-) (cmp-negce) (cmp-not))
	X              (t (cmp-posce) (cmp-and))))) 
	X
	X(defun cmp-negce nil (lex) (cmp-ce)) 
	X
	X(defun cmp-posce nil
	X  (setq *ce-count* (1+ *ce-count*))
	X  (cond ((eq (peek-lex) '\{) (cmp-ce+cevar))
	X        (t (cmp-ce)))) 
	X
	X(defun cmp-ce+cevar nil
	X  (prog (z)
	X        (lex)
	X        (cond ((atom (peek-lex)) (cmp-cevar) (cmp-ce))
	X              (t (cmp-ce) (cmp-cevar)))
	X        (setq z (lex))
	X        (or (eq z '\}) (%error '|missing '}'| z)))) 
	X
	X(defun new-subnum (k)
	X  (or (numberp k) (%error '|tab must be a number| k))
	X  (setq *subnum* (fix k))) 
	X
	X(defun incr-subnum nil (setq *subnum* (1+ *subnum*))) 
	X
	X(defun cmp-ce nil
	X  (prog (z)
	X        (new-subnum 0.)
	X        (setq *cur-vars* nil)
	X        (setq z (lex))
	X        (and (atom z)
	X             (%error '|atomic conditions are not allowed| z))
	X        (prepare-sublex z)
	X   la   (and (end-of-ce) (return nil))
	X        (incr-subnum)
	X        (cmp-element)
	X        (go la))) 
	X
	X(defun cmp-element nil
	X        (and (eq (peek-sublex) '^) (cmp-tab))
	X        (cond ((eq (peek-sublex) '\{) (cmp-product))
	X              (t (cmp-atomic-or-any))))
	X
	X(defun cmp-atomic-or-any nil
	X        (cond ((eq (peek-sublex) '<<) (cmp-any))
	X              (t (cmp-atomic))))
	X
	X(defun cmp-any nil
	X  (prog (a z)
	X        (sublex)
	X        (setq z nil)
	X   la   (cond ((end-of-ce) (%error '|missing '>>'| a)))
	X        (setq a (sublex))
	X        (cond ((not (eq '>> a)) (setq z (cons a z)) (go la)))
	X        (link-new-node (list '&any nil (current-field) z)))) 
	X
	X
	X(defun cmp-tab nil
	X  (prog (r)
	X        (sublex)
	X        (setq r (sublex))
	X        (setq r ($litbind r))
	X        (new-subnum r))) 
	X
	X(defun $litbind (x)
	X  (prog (r)
	X        (cond ((and (symbolp x) (setq r (literal-binding-of x)))
	X               (return r))
	X              (t (return x))))) 
	X
	X(defun get-bind (x)
	X  (prog (r)
	X        (cond ((and (symbolp x) (setq r (literal-binding-of x)))
	X               (return r))
	X              (t (return nil))))) 
	X
	X(defun cmp-atomic nil
	X  (prog (test x)
	X        (setq x (peek-sublex))
	X        (cond ((eq x '=) (setq test 'eq) (sublex))
	X              ((eq x '<>) (setq test 'ne) (sublex))
	X              ((eq x '<) (setq test 'lt) (sublex))
	X              ((eq x '<=) (setq test 'le) (sublex))
	X              ((eq x '>) (setq test 'gt) (sublex))
	X              ((eq x '>=) (setq test 'ge) (sublex))
	X              ((eq x '<=>) (setq test 'xx) (sublex))
	X              (t (setq test 'eq)))
	X        (cmp-symbol test))) 
	X
	X(defun cmp-product nil
	X  (prog (save)
	X        (setq save (rest-of-ce))
	X        (sublex)
	X   la   (cond ((end-of-ce)
	X               (cond ((member '\} save) 
	X		      (%error '|wrong contex for '}'| save))
	X		     (t (%error '|missing '}'| save))))
	X              ((eq (peek-sublex) '\}) (sublex) (return nil)))
	X        (cmp-atomic-or-any)
	X        (go la))) 
	X
	X(defun variablep (x) (and (symbolp x) (eq (getchar x 1.) '<))) 
	X
	X(defun cmp-symbol (test)
	X  (prog (flag)
	X        (setq flag t)
	X        (cond ((eq (peek-sublex) '//) (sublex) (setq flag nil)))
	X        (cond ((and flag (variablep (peek-sublex)))
	X               (cmp-var test))
	X              ((numberp (peek-sublex)) (cmp-number test))
	X              ((symbolp (peek-sublex)) (cmp-constant test))
	X              (t (%error '|unrecognized symbol| (sublex)))))) 
	X
	X(defun cmp-constant (test)
	X  (or (memq test '(eq ne xx))
	X      (%error '|non-numeric constant after numeric predicate| (sublex)))
	X  (link-new-node (list (concat 't test 'a)
	X                       nil
	X                       (current-field)
	X                       (sublex)))) 
	X
	X(defun cmp-number (test)
	X  (link-new-node (list (concat 't test 'n)
	X                       nil
	X                       (current-field)
	X                       (sublex)))) 
	X
	X(defun current-field nil (field-name *subnum*)) 
	X
	X(defun field-name (num)
	X  (cond ((= num 1.) '*c1*)
	X        ((= num 2.) '*c2*)
	X        ((= num 3.) '*c3*)
	X        ((= num 4.) '*c4*)
	X        ((= num 5.) '*c5*)
	X        ((= num 6.) '*c6*)
	X        ((= num 7.) '*c7*)
	X        ((= num 8.) '*c8*)
	X        ((= num 9.) '*c9*)
	X        ((= num 10.) '*c10*)
	X        ((= num 11.) '*c11*)
	X        ((= num 12.) '*c12*)
	X        ((= num 13.) '*c13*)
	X        ((= num 14.) '*c14*)
	X        ((= num 15.) '*c15*)
	X        ((= num 16.) '*c16*)
	X        ((= num 17.) '*c17*)
	X        ((= num 18.) '*c18*)
	X        ((= num 19.) '*c19*)
	X        ((= num 20.) '*c20*)
	X        ((= num 21.) '*c21*)
	X        ((= num 22.) '*c22*)
	X        ((= num 23.) '*c23*)
	X        ((= num 24.) '*c24*)
	X        ((= num 25.) '*c25*)
	X        ((= num 26.) '*c26*)
	X        ((= num 27.) '*c27*)
	X        ((= num 28.) '*c28*)
	X        ((= num 29.) '*c29*)
	X        ((= num 30.) '*c30*)
	X        ((= num 31.) '*c31*)
	X        ((= num 32.) '*c32*)
	X        ((= num 33.) '*c33*)
	X        ((= num 34.) '*c34*)
	X        ((= num 35.) '*c35*)
	X        ((= num 36.) '*c36*)
	X        ((= num 37.) '*c37*)
	X        ((= num 38.) '*c38*)
	X        ((= num 39.) '*c39*)
	X        ((= num 40.) '*c40*)
	X        ((= num 41.) '*c41*)
	X        ((= num 42.) '*c42*)
	X        ((= num 43.) '*c43*)
	X        ((= num 44.) '*c44*)
	X        ((= num 45.) '*c45*)
	X        ((= num 46.) '*c46*)
	X        ((= num 47.) '*c47*)
	X        ((= num 48.) '*c48*)
	X        ((= num 49.) '*c49*)
	X        ((= num 50.) '*c50*)
	X        ((= num 51.) '*c51*)
	X        ((= num 52.) '*c52*)
	X        ((= num 53.) '*c53*)
	X        ((= num 54.) '*c54*)
	X        ((= num 55.) '*c55*)
	X        ((= num 56.) '*c56*)
	X        ((= num 57.) '*c57*)
	X        ((= num 58.) '*c58*)
	X        ((= num 59.) '*c59*)
	X        ((= num 60.) '*c60*)
	X        ((= num 61.) '*c61*)
	X        ((= num 62.) '*c62*)
	X        ((= num 63.) '*c63*)
	X        ((= num 64.) '*c64*)
	X        (t (%error '|condition is too long| (rest-of-ce))))) 
	X
	X
	X;;; Compiling variables
	X;
	X;
	X;
	X; *cur-vars* are the variables in the condition element currently 
	X; being compiled.  *vars* are the variables in the earlier condition
	X; elements.  *ce-vars* are the condition element variables.  note
	X; that the interpreter will not confuse condition element and regular
	X; variables even if they have the same name.
	X;
	X; *cur-vars* is a list of triples: (name predicate subelement-number)
	X; eg:		( (<x> eq 3)
	X;		  (<y> ne 1)
	X;		  . . . )
	X;
	X; *vars* is a list of triples: (name ce-number subelement-number)
	X; eg:		( (<x> 3 3)
	X;		  (<y> 1 1)
	X;		  . . . )
	X;
	X; *ce-vars* is a list of pairs: (name ce-number)
	X; eg:		( (ce1 1)
	X;		  (<c3> 3)
	X;		  . . . )
	X
	X(defun var-dope (var) (assq var *vars*))
	X
	X(defun ce-var-dope (var) (assq var *ce-vars*))
	X
	X(defun cmp-var (test)
	X  (prog (old name)
	X        (setq name (sublex))
	X        (setq old (assq name *cur-vars*))
	X        (cond ((and old (eq (cadr old) 'eq))
	X               (cmp-old-eq-var test old))
	X              ((and old (eq test 'eq)) (cmp-new-eq-var name old))
	X              (t (cmp-new-var name test))))) 
	X
	X(defun cmp-new-var (name test)
	X  (setq *cur-vars* (cons (list name test *subnum*) *cur-vars*))) 
	X
	X(defun cmp-old-eq-var (test old)
	X  (link-new-node (list (concat 't test 's)
	X                       nil
	X                       (current-field)
	X                       (field-name (caddr old))))) 
	X
	X(defun cmp-new-eq-var (name old)
	X  (prog (pred next)
	X        (setq *cur-vars* (delq old *cur-vars*))
	X        (setq next (assq name *cur-vars*))
	X        (cond (next (cmp-new-eq-var name next))
	X              (t (cmp-new-var name 'eq)))
	X        (setq pred (cadr old))
	X        (link-new-node (list (concat 't pred 's)
	X                             nil
	X                             (field-name (caddr old))
	X                             (current-field))))) 
	X
	X(defun cmp-cevar nil
	X  (prog (name old)
	X        (setq name (lex))
	X        (setq old (assq name *ce-vars*))
	X        (and old
	X             (%error '|condition element variable used twice| name))
	X        (setq *ce-vars* (cons (list name 0.) *ce-vars*)))) 
	X
	X(defun cmp-not nil (cmp-beta '&not)) 
	X
	X(defun cmp-nobeta nil (cmp-beta nil)) 
	X
	X(defun cmp-and nil (cmp-beta '&and)) 
	X
	X(defun cmp-beta (kind)
	X  (prog (tlist vdope vname vpred vpos old)
	X        (setq tlist nil)
	X   la   (and (atom *cur-vars*) (go lb))
	X        (setq vdope (car *cur-vars*))
	X        (setq *cur-vars* (cdr *cur-vars*))
	X        (setq vname (car vdope))
	X        (setq vpred (cadr vdope))
	X        (setq vpos (caddr vdope))
	X        (setq old (assq vname *vars*))
	X        (cond (old (setq tlist (add-test tlist vdope old)))
	X              ((neq kind '&not) (promote-var vdope)))
	X        (go la)
	X   lb   (and kind (build-beta kind tlist))
	X        (or (eq kind '&not) (fudge))
	X        (setq *last-branch* *last-node*))) 
	X
	X(defun add-test (list new old)
	X  (prog (ttype lloc rloc)
	X	(setq *feature-count* (1+ *feature-count*))
	X        (setq ttype (concat 't (cadr new) 'b))
	X        (setq rloc (encode-singleton (caddr new)))
	X        (setq lloc (encode-pair (cadr old) (caddr old)))
	X        (return (cons ttype (cons lloc (cons rloc list)))))) 
	X
	X; the following two functions encode indices so that gelm can
	X; decode them as fast as possible
	X
	X(defun encode-pair (a b) (+ (* 10000. (1- a)) (1- b))) 
	X
	X(defun encode-singleton (a) (1- a)) 
	X
	X(defun promote-var (dope)
	X  (prog (vname vpred vpos new)
	X        (setq vname (car dope))
	X        (setq vpred (cadr dope))
	X        (setq vpos (caddr dope))
	X        (or (eq 'eq vpred)
	X            (%error '|illegal predicate for first occurrence|
	X                   (list vname vpred)))
	X        (setq new (list vname 0. vpos))
	X        (setq *vars* (cons new *vars*)))) 
	X
	X(defun fudge nil
	X  (mapc (function fudge*) *vars*)
	X  (mapc (function fudge*) *ce-vars*)) 
	X
	X(defun fudge* (z)
	X  (prog (a) (setq a (cdr z)) (rplaca a (1+ (car a))))) 
	X
	X(defun build-beta (type tests)
	X  (prog (rpred lpred lnode lef)
	X        (link-new-node (list '&mem nil nil (protomem)))
	X        (setq rpred *last-node*)
	X        (cond ((eq type '&and)
	X               (setq lnode (list '&mem nil nil (protomem))))
	X              (t (setq lnode (list '&two nil nil))))
	X        (setq lpred (link-to-branch lnode))
	X        (cond ((eq type '&and) (setq lef lpred))
	X              (t (setq lef (protomem))))
	X        (link-new-beta-node (list type nil lef rpred tests)))) 
	X
	X(defun protomem nil (list nil)) 
	X
	X(defun memory-part (mem-node) (car (cadddr mem-node))) 
	X
	X(defun encode-dope nil
	X  (prog (r all z k)
	X        (setq r nil)
	X        (setq all *vars*)
	X   la   (and (atom all) (return r))
	X        (setq z (car all))
	X        (setq all (cdr all))
	X        (setq k (encode-pair (cadr z) (caddr z)))
	X        (setq r (cons (car z) (cons k r)))
	X        (go la))) 
	X
	X(defun encode-ce-dope nil
	X  (prog (r all z k)
	X        (setq r nil)
	X        (setq all *ce-vars*)
	X   la   (and (atom all) (return r))
	X        (setq z (car all))
	X        (setq all (cdr all))
	X        (setq k (cadr z))
	X        (setq r (cons (car z) (cons k r)))
	X        (go la))) 
	X
	X
	X
	X;;; Linking the nodes
	X
	X(defun link-new-node (r)
	X  (cond ((not (member (car r) '(&p &mem &two &and &not)))
	X	 (setq *feature-count* (1+ *feature-count*))))
	X  (setq *virtual-cnt* (1+ *virtual-cnt*))
	X  (setq *last-node* (link-left *last-node* r))) 
	X
	X(defun link-to-branch (r)
	X  (setq *virtual-cnt* (1+ *virtual-cnt*))
	X  (setq *last-branch* (link-left *last-branch* r))) 
	X
	X(defun link-new-beta-node (r)
	X  (setq *virtual-cnt* (1+ *virtual-cnt*))
	X  (setq *last-node* (link-both *last-branch* *last-node* r))
	X  (setq *last-branch* *last-node*)) 
	X
	X(defun link-left (pred succ)
	X  (prog (a r)
	X        (setq a (left-outs pred))
	X        (setq r (find-equiv-node succ a))
	X        (and r (return r))
	X        (setq *real-cnt* (1+ *real-cnt*))
	X        (attach-left pred succ)
	X        (return succ))) 
	X
	X(defun link-both (left right succ)
	X  (prog (a r)
	X        (setq a (interq (left-outs left) (right-outs right)))
	X        (setq r (find-equiv-beta-node succ a))
	X        (and r (return r))
	X        (setq *real-cnt* (1+ *real-cnt*))
	X        (attach-left left succ)
	X        (attach-right right succ)
	X        (return succ))) 
	X
	X(defun attach-right (old new)
	X  (rplaca (cddr old) (cons new (caddr old)))) 
	X
	X(defun attach-left (old new)
	X  (rplaca (cdr old) (cons new (cadr old)))) 
	X
	X(defun right-outs (node) (caddr node)) 
	X
	X(defun left-outs (node) (cadr node)) 
	X
	X(defun find-equiv-node (node list)
	X  (prog (a)
	X        (setq a list)
	X   l1   (cond ((atom a) (return nil))
	X              ((equiv node (car a)) (return (car a))))
	X        (setq a (cdr a))
	X        (go l1))) 
	X
	X(defun find-equiv-beta-node (node list)
	X  (prog (a)
	X        (setq a list)
	X   l1   (cond ((atom a) (return nil))
	X              ((beta-equiv node (car a)) (return (car a))))
	X        (setq a (cdr a))
	X        (go l1))) 
	X
	X; do not look at the predecessor fields of beta nodes; they have to be
	X; identical because of the way the candidate nodes were found
	X
	X(defun equiv (a b)
	X  (and (eq (car a) (car b))
	X       (or (eq (car a) '&mem)
	X           (eq (car a) '&two)
	X           (equal (caddr a) (caddr b)))
	X       (equal (cdddr a) (cdddr b)))) 
	X
	X(defun beta-equiv (a b)
	X  (and (eq (car a) (car b))
	X       (equal (cddddr a) (cddddr b))
	X       (or (eq (car a) '&and) (equal (caddr a) (caddr b))))) 
	X
	X; the equivalence tests are set up to consider the contents of
	X; node memories, so they are ready for the build action
	X
	X;;; Network interpreter
	X
	X(defun match (flag wme)
	X  (sendto flag (list wme) 'left (list *first-node*)))
	X
	X; note that eval-nodelist is not set up to handle building
	X; productions.  would have to add something like ops4's build-flag
	X
	X(defun eval-nodelist (nl)
	X  (prog nil
	X   top  (and (not nl) (return nil))
	X        (setq *sendtocall* nil)
	X	(setq *last-node* (car nl))
	X        (apply (caar nl) (cdar nl))
	X        (setq nl (cdr nl))
	X        (go top))) 
	X
	X(defun sendto (flag data side nl)
	X  (prog nil
	X   top  (and (not nl) (return nil))
	X        (setq *side* side)
	X        (setq *flag-part* flag)
	X        (setq *data-part* data)
	X        (setq *sendtocall* t)
	X	(setq *last-node* (car nl))
	X        (apply (caar nl) (cdar nl))
	X        (setq nl (cdr nl))
	X        (go top))) 
	X
	X; &bus sets up the registers for the one-input nodes.  note that this
	X(defun &bus (outs)
	X  (prog (dp)
	X        (setq *alpha-flag-part* *flag-part*)
	X        (setq *alpha-data-part* *data-part*)
	X        (setq dp (car *data-part*))
	X        (setq *c1* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c2* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c3* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c4* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c5* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c6* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c7* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c8* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c9* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c10* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c11* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c12* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c13* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c14* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c15* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c16* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c17* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c18* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c19* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c20* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c21* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c22* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c23* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c24* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c25* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c26* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c27* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c28* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c29* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c30* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c31* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c32* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c33* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c34* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c35* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c36* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c37* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c38* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c39* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c40* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c41* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c42* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c43* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c44* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c45* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c46* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c47* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c48* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c49* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c50* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c51* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c52* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c53* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c54* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c55* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c56* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c57* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c58* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c59* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c60* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c61* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c62* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c63* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c64* (car dp))
	X        (eval-nodelist outs))) 
	X
	X(defun &any (outs register const-list)
	X  (prog (z c)
	X        (setq z (fast-symeval register))
	X        (cond ((numberp z) (go number)))
	X   symbol (cond ((null const-list) (return nil))
	X                ((eq (car const-list) z) (go ok))
	X                (t (setq const-list (cdr const-list)) (go symbol)))
	X   number (cond ((null const-list) (return nil))
	X                ((and (numberp (setq c (car const-list)))
	X                      (=alg c z))
	X                 (go ok))
	X                (t (setq const-list (cdr const-list)) (go number)))
	X   ok   (eval-nodelist outs))) 
	X
	X(defun teqa (outs register constant)
	X  (and (eq (fast-symeval register) constant) (eval-nodelist outs))) 
	X
	X(defun tnea (outs register constant)
	X  (and (not (eq (fast-symeval register) constant)) (eval-nodelist outs))) 
	X
	X(defun txxa (outs register constant)
	X  (and (symbolp (fast-symeval register)) (eval-nodelist outs))) 
	X
	X(defun teqn (outs register constant)
	X  (prog (z)
	X        (setq z (fast-symeval register))
	X        (and (numberp z)
	X             (=alg z constant)
	X             (eval-nodelist outs)))) 
	X
	X(defun tnen (outs register constant)
	X  (prog (z)
	X        (setq z (fast-symeval register))
	X        (and (or (not (numberp z))
	X                 (not (=alg z constant)))
	X             (eval-nodelist outs)))) 
	X
	X(defun txxn (outs register constant)
	X  (prog (z)
	X        (setq z (fast-symeval register))
	X        (and (numberp z) (eval-nodelist outs)))) 
	X
	X(defun tltn (outs register constant)
	X  (prog (z)
	X        (setq z (fast-symeval register))
	X        (and (numberp z)
	X             (greaterp constant z)
	X             (eval-nodelist outs)))) 
	X
	X(defun tgtn (outs register constant)
	X  (prog (z)
	X        (setq z (fast-symeval register))
	X        (and (numberp z)
	X             (greaterp z constant)
	X             (eval-nodelist outs)))) 
	X
	X(defun tgen (outs register constant)
	X  (prog (z)
	X        (setq z (fast-symeval register))
	X        (and (numberp z)
	X             (not (greaterp constant z))
	X             (eval-nodelist outs)))) 
	X
	X(defun tlen (outs register constant)
	X  (prog (z)
	X        (setq z (fast-symeval register))
	X        (and (numberp z)
	X             (not (greaterp z constant))
	X             (eval-nodelist outs)))) 
	X
	X(defun teqs (outs vara varb)
	X  (prog (a b)
	X        (setq a (fast-symeval vara))
	X        (setq b (fast-symeval varb))
	X        (cond ((eq a b) (eval-nodelist outs))
	X              ((and (numberp a)
	X                    (numberp b)
	X                    (=alg a b))
	X               (eval-nodelist outs))))) 
	X
	X(defun tnes (outs vara varb)
	X  (prog (a b)
	X        (setq a (fast-symeval vara))
	X        (setq b (fast-symeval varb))
	X        (cond ((eq a b) (return nil))
	X              ((and (numberp a)
	X                    (numberp b)
	X                    (=alg a b))
	X               (return nil))
	X              (t (eval-nodelist outs))))) 
	X
	X(defun txxs (outs vara varb)
	X  (prog (a b)
	X        (setq a (fast-symeval vara))
	X        (setq b (fast-symeval varb))
	X        (cond ((and (numberp a) (numberp b)) (eval-nodelist outs))
	X              ((and (not (numberp a)) (not (numberp b)))
	X               (eval-nodelist outs))))) 
	X
	X(defun tlts (outs vara varb)
	X  (prog (a b)
	X        (setq a (fast-symeval vara))
	X        (setq b (fast-symeval varb))
	X        (and (numberp a)
	X             (numberp b)
	X             (greaterp b a)
	X             (eval-nodelist outs)))) 
	X
	X(defun tgts (outs vara varb)
	X  (prog (a b)
	X        (setq a (fast-symeval vara))
	X        (setq b (fast-symeval varb))
	X        (and (numberp a)
	X             (numberp b)
	X             (greaterp a b)
	X             (eval-nodelist outs)))) 
	X
	X(defun tges (outs vara varb)
	X  (prog (a b)
	X        (setq a (fast-symeval vara))
	X        (setq b (fast-symeval varb))
	X        (and (numberp a)
	X             (numberp b)
	X             (not (greaterp b a))
	X             (eval-nodelist outs)))) 
	X
	X(defun tles (outs vara varb)
	X  (prog (a b)
	X        (setq a (fast-symeval vara))
	X        (setq b (fast-symeval varb))
	X        (and (numberp a)
	X             (numberp b)
	X             (not (greaterp a b))
	X             (eval-nodelist outs)))) 
	X
	X(defun &two (left-outs right-outs)
	X  (prog (fp dp)
	X        (cond (*sendtocall*
	X               (setq fp *flag-part*)
	X               (setq dp *data-part*))
	X              (t
	X               (setq fp *alpha-flag-part*)
	X               (setq dp *alpha-data-part*)))
	X        (sendto fp dp 'left left-outs)
	X        (sendto fp dp 'right right-outs))) 
	X
	X(defun &mem (left-outs right-outs memory-list)
	X  (prog (fp dp)
	X        (cond (*sendtocall*
	X               (setq fp *flag-part*)
	X               (setq dp *data-part*))
	X              (t
	X               (setq fp *alpha-flag-part*)
	X               (setq dp *alpha-data-part*)))
	X        (sendto fp dp 'left left-outs)
	X        (add-token memory-list fp dp nil)
	X        (sendto fp dp 'right right-outs))) 
	X
	X(defun &and (outs lpred rpred tests)
	X  (prog (mem)
	X        (cond ((eq *side* 'right) (setq mem (memory-part lpred)))
	X              (t (setq mem (memory-part rpred))))
	X        (cond ((not mem) (return nil))
	X              ((eq *side* 'right) (and-right outs mem tests))
	X              (t (and-left outs mem tests))))) 
	X
	X(defun and-left (outs mem tests)
	X  (prog (fp dp memdp tlist tst lind rind res)
	X        (setq fp *flag-part*)
	X        (setq dp *data-part*)
	X   fail (and (null mem) (return nil))
	X        (setq memdp (car mem))
	X        (setq mem (cdr mem))
	X        (setq tlist tests)
	X   tloop (and (null tlist) (go succ))
	X        (setq tst (car tlist))
	X        (setq tlist (cdr tlist))
	X        (setq lind (car tlist))
	X        (setq tlist (cdr tlist))
	X        (setq rind (car tlist))
	X        (setq tlist (cdr tlist))
	X        (comment the next line differs in and-left & -right)
	X        (setq res (funcall tst (gelm memdp rind) (gelm dp lind)))
	X        (cond (res (go tloop))
	X              (t (go fail)))
	X   succ (comment the next line differs in and-left & -right)
	X        (sendto fp (cons (car memdp) dp) 'left outs)
	X        (go fail))) 
	X
	X(defun and-right (outs mem tests)
	X  (prog (fp dp memdp tlist tst lind rind res)
	X        (setq fp *flag-part*)
	X        (setq dp *data-part*)
	X   fail (and (null mem) (return nil))
	X        (setq memdp (car mem))
	X        (setq mem (cdr mem))
	X        (setq tlist tests)
	X   tloop (and (null tlist) (go succ))
	X        (setq tst (car tlist))
	X        (setq tlist (cdr tlist))
	X        (setq lind (car tlist))
	X        (setq tlist (cdr tlist))
	X        (setq rind (car tlist))
	X        (setq tlist (cdr tlist))
	X        (comment the next line differs in and-left & -right)
	X        (setq res (funcall tst (gelm dp rind) (gelm memdp lind)))
	X        (cond (res (go tloop))
	X              (t (go fail)))
	X   succ (comment the next line differs in and-left & -right)
	X        (sendto fp (cons (car dp) memdp) 'right outs)
	X        (go fail))) 
	X
	X
	X(defun teqb (new eqvar)
	X  (cond ((eq new eqvar) t)
	X        ((not (numberp new)) nil)
	X        ((not (numberp eqvar)) nil)
	X        ((=alg new eqvar) t)
	X        (t nil))) 
	X
	X(defun tneb (new eqvar)
	X  (cond ((eq new eqvar) nil)
	X        ((not (numberp new)) t)
	X        ((not (numberp eqvar)) t)
	X        ((=alg new eqvar) nil)
	X        (t t))) 
	X
	X(defun tltb (new eqvar)
	X  (cond ((not (numberp new)) nil)
	X        ((not (numberp eqvar)) nil)
	X        ((greaterp eqvar new) t)
	X        (t nil))) 
	X
	X(defun tgtb (new eqvar)
	X  (cond ((not (numberp new)) nil)
	X        ((not (numberp eqvar)) nil)
	X        ((greaterp new eqvar) t)
	X        (t nil))) 
	X
	X(defun tgeb (new eqvar)
	X  (cond ((not (numberp new)) nil)
	X        ((not (numberp eqvar)) nil)
	X        ((not (greaterp eqvar new)) t)
	X        (t nil))) 
	X
	X(defun tleb (new eqvar)
	X  (cond ((not (numberp new)) nil)
	X        ((not (numberp eqvar)) nil)
	X        ((not (greaterp new eqvar)) t)
	X        (t nil))) 
	X
	X(defun txxb (new eqvar)
	X  (cond ((numberp new)
	X         (cond ((numberp eqvar) t)
	X               (t nil)))
	X        (t
	X         (cond ((numberp eqvar) nil)
	X               (t t))))) 
	X
	X
	X(defun &p (rating name var-dope ce-var-dope rhs)
	X  (prog (fp dp)
	X        (cond (*sendtocall*
	X               (setq fp *flag-part*)
	X               (setq dp *data-part*))
	X              (t
	X               (setq fp *alpha-flag-part*)
	X               (setq dp *alpha-data-part*)))
	X        (and (memq fp '(nil old)) (removecs name dp))
	X        (and fp (insertcs name dp rating)))) 
	X
	X(defun &old (a b c d e) nil) 
	X
	X(defun &not (outs lmem rpred tests)
	X  (cond ((and (eq *side* 'right) (eq *flag-part* 'old)) nil)
	X        ((eq *side* 'right) (not-right outs (car lmem) tests))
	X        (t (not-left outs (memory-part rpred) tests lmem)))) 
	X
	X(defun not-left (outs mem tests own-mem)
	X  (prog (fp dp memdp tlist tst lind rind res c)
	X        (setq fp *flag-part*)
	X        (setq dp *data-part*)
	X        (setq c 0.)
	X   fail (and (null mem) (go fin))
	X        (setq memdp (car mem))
	X        (setq mem (cdr mem))
	X        (setq tlist tests)
	X   tloop (and (null tlist) (setq c (1+ c)) (go fail))
	X        (setq tst (car tlist))
	X        (setq tlist (cdr tlist))
	X        (setq lind (car tlist))
	X        (setq tlist (cdr tlist))
	X        (setq rind (car tlist))
	X        (setq tlist (cdr tlist))
	X        (comment the next line differs in not-left & -right)
	X        (setq res (funcall tst (gelm memdp rind) (gelm dp lind)))
	X        (cond (res (go tloop))
	X              (t (go fail)))
	X   fin  (add-token own-mem fp dp c)
	X        (and (== c 0.) (sendto fp dp 'left outs)))) 
	X
	X(defun not-right (outs mem tests)
	X  (prog (fp dp memdp tlist tst lind rind res newfp inc newc)
	X        (setq fp *flag-part*)
	X        (setq dp *data-part*)
	X        (cond ((not fp) (setq inc -1.) (setq newfp 'new))
	X              ((eq fp 'new) (setq inc 1.) (setq newfp nil))
	X              (t (return nil)))
	X   fail (and (null mem) (return nil))
	X        (setq memdp (car mem))
	X        (setq newc (cadr mem))
	X        (setq tlist tests)
	X   tloop (and (null tlist) (go succ))
	X        (setq tst (car tlist))
	X        (setq tlist (cdr tlist))
	X        (setq lind (car tlist))
	X        (setq tlist (cdr tlist))
	X        (setq rind (car tlist))
	X        (setq tlist (cdr tlist))
	X        (comment the next line differs in not-left & -right)
	X        (setq res (funcall tst (gelm dp rind) (gelm memdp lind)))
	X        (cond (res (go tloop))
	X              (t (setq mem (cddr mem)) (go fail)))
	X   succ (setq newc (+ inc newc))
	X        (rplaca (cdr mem) newc)
	X        (cond ((or (and (== inc -1.) (== newc 0.))
	X                   (and (== inc 1.) (== newc 1.)))
	X               (sendto newfp memdp 'right outs)))
	X        (setq mem (cddr mem))
	X        (go fail))) 
	X
	X
	X
	X;;; Node memories
	X
	X
	X(defun add-token (memlis flag data-part num)
	X  (prog (was-present)
	X        (cond ((eq flag 'new)
	X               (setq was-present nil)
	X               (real-add-token memlis data-part num))
	X              ((not flag) 
	X	       (setq was-present (remove-old memlis data-part num)))
	X              ((eq flag 'old) (setq was-present t)))
	X        (return was-present))) 
	X
	X(defun real-add-token (lis data-part num)
	X  (setq *current-token* (1+ *current-token*))
	X  (cond (num (rplaca lis (cons num (car lis)))))
	X  (rplaca lis (cons data-part (car lis)))) 
	X
	X(defun remove-old (lis data num)
	X  (cond (num (remove-old-num lis data))
	X        (t (remove-old-no-num lis data)))) 
	X
	X(defun remove-old-num (lis data)
	X  (prog (m next last)
	X        (setq m (car lis))
	X        (cond ((atom m) (return nil))
	X              ((top-levels-eq data (car m))
	X               (setq *current-token* (1- *current-token*))
	X               (rplaca lis (cddr m))
	X               (return (car m))))
	X        (setq next m)
	X   loop (setq last next)
	X        (setq next (cddr next))
	X        (cond ((atom next) (return nil))
	X              ((top-levels-eq data (car next))
	X               (rplacd (cdr last) (cddr next))
	X               (setq *current-token* (1- *current-token*))
	X               (return (car next)))
	X              (t (go loop))))) 
	X
	X(defun remove-old-no-num (lis data)
	X  (prog (m next last)
	X        (setq m (car lis))
	X        (cond ((atom m) (return nil))
	X              ((top-levels-eq data (car m))
	X               (setq *current-token* (1- *current-token*))
	X               (rplaca lis (cdr m))
	X               (return (car m))))
	X        (setq next m)
	X   loop (setq last next)
	X        (setq next (cdr next))
	X        (cond ((atom next) (return nil))
	X              ((top-levels-eq data (car next))
	X               (rplacd last (cdr next))
	X               (setq *current-token* (1- *current-token*))
	X               (return (car next)))
	X              (t (go loop))))) 
	X
	X
	X
	X;;; Conflict Resolution
	X;
	X;
	X; each conflict set element is a list of the following form:
	X; ((p-name . data-part) (sorted wm-recency) special-case-number)
	X
	X(defun removecs (name data)
	X  (prog (cr-data inst cs)
	X        (setq cr-data (cons name data))
	X	(setq cs *conflict-set*)
	X  l:	(cond ((null cs) 
	X               (record-refract name data)
	X               (return nil)))
	X	(setq inst (car cs))
	X	(setq cs (cdr cs))
	X	(and (not (top-levels-eq (car inst) cr-data)) (go l:))
	X        (setq *conflict-set* (delq inst *conflict-set*))))
	X
	X(defun insertcs (name data rating)
	X  (prog (instan)
	X    (and (refracted name data) (return nil))
	X    (setq instan (list (cons name data) (order-tags data) rating))
	X    (and (atom *conflict-set*) (setq *conflict-set* nil))
	X    (return (setq *conflict-set* (cons instan *conflict-set*))))) 
	X
	X(defun order-tags (dat)
	X  (prog (tags)
	X        (setq tags nil)
	X   l1:  (and (atom dat) (go l2:))
	X        (setq tags (cons (creation-time (car dat)) tags))
	X        (setq dat (cdr dat))
	X        (go l1:)
	X   l2:  (cond ((eq *strategy* 'mea)
	X               (return (cons (car tags) (dsort (cdr tags)))))
	X              (t (return (dsort tags)))))) 
	X
	X; destructively sort x into descending order
	X
	X(defun dsort (x)
	X  (prog (sorted cur next cval nval)
	X        (and (atom (cdr x)) (return x))
	X   loop (setq sorted t)
	X        (setq cur x)
	X        (setq next (cdr x))
	X   chek (setq cval (car cur))
	X        (setq nval (car next))
	X        (cond ((> nval cval)
	X               (setq sorted nil)
	X               (rplaca cur nval)
	X               (rplaca next cval)))
	X        (setq cur next)
	X        (setq next (cdr cur))
	X        (cond ((not (null next)) (go chek))
	X              (sorted (return x))
	X              (t (go loop))))) 
	X
	X(defun conflict-resolution nil
	X  (prog (best len)
	X        (setq len (length *conflict-set*))
	X        (cond ((> len *max-cs*) (setq *max-cs* len)))
	X        (setq *total-cs* (+ *total-cs* len))
	X        (cond (*conflict-set*
	X               (setq best (best-of *conflict-set*))
	X               (setq *conflict-set* (delq best *conflict-set*))
	X               (return (pname-instantiation best)))
	X              (t (return nil))))) 
	X
	X(defun best-of (set) (best-of* (car set) (cdr set))) 
	X
	X(defun best-of* (best rem)
	X  (cond ((not rem) best)
	X        ((conflict-set-compare best (car rem))
	X         (best-of* best (cdr rem)))
	X        (t (best-of* (car rem) (cdr rem))))) 
	X
	X(defun remove-from-conflict-set (name)
	X  (prog (cs entry)
	X   l1   (setq cs *conflict-set*)
	X   l2   (cond ((atom cs) (return nil)))
	X        (setq entry (car cs))
	X        (setq cs (cdr cs))
	X        (cond ((eq name (caar entry))
	X               (setq *conflict-set* (delq entry *conflict-set*))
	X               (go l1))
	X              (t (go l2))))) 
	X
	X(defun pname-instantiation (conflict-elem) (car conflict-elem)) 
	X
	X(defun order-part (conflict-elem) (cdr conflict-elem)) 
	X
	X(defun instantiation (conflict-elem)
	X  (cdr (pname-instantiation conflict-elem))) 
	X
	X
	X(defun conflict-set-compare (x y)
	X  (prog (x-order y-order xl yl xv yv)
	X        (setq x-order (order-part x))
	X        (setq y-order (order-part y))
	X        (setq xl (car x-order))
	X        (setq yl (car y-order))
	X   data (cond ((and (null xl) (null yl)) (go ps))
	X              ((null yl) (return t))
	X              ((null xl) (return nil)))
	X        (setq xv (car xl))
	X        (setq yv (car yl))
	X        (cond ((> xv yv) (return t))
	X              ((> yv xv) (return nil)))
	X        (setq xl (cdr xl))
	X        (setq yl (cdr yl))
	X        (go data)
	X   ps   (setq xl (cdr x-order))
	X        (setq yl (cdr y-order))
	X   psl  (cond ((null xl) (return t)))
	X        (setq xv (car xl))
	X        (setq yv (car yl))
	X        (cond ((> xv yv) (return t))
	X              ((> yv xv) (return nil)))
	X        (setq xl (cdr xl))
	X        (setq yl (cdr yl))
	X        (go psl))) 
	X
	X
	X(defun conflict-set nil
	X  (prog (cnts cs p z best)
	X        (setq cnts nil)
	X        (setq cs *conflict-set*)
	X   l1:  (and (atom cs) (go l2:))
	X        (setq p (caaar cs))
	X        (setq cs (cdr cs))
	X        (setq z (assq p cnts))
	X        (cond ((null z) (setq cnts (cons (cons p 1.) cnts)))
	X              (t (rplacd z (1+ (cdr z)))))
	X        (go l1:)
	X   l2:  (cond ((atom cnts)
	X               (setq best (best-of *conflict-set*))
	X               (terpri)
	X               (return (list (caar best) 'dominates))))
	X        (terpri)
	X        (princ (caar cnts))
	X        (cond ((> (cdar cnts) 1.)
	X               (princ '|	(|)
	X               (princ (cdar cnts))
	X               (princ '| occurrences)|)))
	X        (setq cnts (cdr cnts))
	X        (go l2:))) 
	X	
	X
	X
	X;;; WM maintaining functions
	X;
	X; The order of operations in the following two functions is critical.
	X; add-to-wm order: (1) change wm (2) record change (3) match 
	X; remove-from-wm order: (1) record change (2) match (3) change wm
	X; (back will not restore state properly unless wm changes are recorded
	X; before the cs changes that they cause)  (match will give errors if 
	X; the thing matched is not in wm at the time)
	X
	X
	X(defun add-to-wm (wme override)
	X  (prog (fa z part timetag port)
	X    (setq *critical* t)
	X    (setq *current-wm* (1+ *current-wm*))
	X    (and (> *current-wm* *max-wm*) (setq *max-wm* *current-wm*))
	X    (setq *action-count* (1+ *action-count*))
	X    (setq fa (wm-hash wme))
	X    (or (memq fa *wmpart-list*)
	X        (setq *wmpart-list* (cons fa *wmpart-list*)))
	X    (setq part (get fa 'wmpart*))
	X    (cond (override (setq timetag override))
	X          (t (setq timetag *action-count*)))
	X    (setq z (cons wme timetag))
	X    (putprop fa (cons z part) 'wmpart*)
	X    (record-change '=>wm *action-count* wme)
	X    (match 'new wme)
	X    (setq *critical* nil)
	X    (cond ((and *in-rhs* *wtrace*)
	X           (setq port (trace-file))
	X           (terpri port)
	X           (princ '|=>wm: | port)
	X           (ppelm wme port)))
	X    (and *in-rhs* *mtrace* (setq *madeby* 
	X                                 (cons (cons wme *p-name*) *madeby*))))) 
	X
	X; remove-from-wm uses eq, not equal to determine if wme is present
	X
	X(defun remove-from-wm (wme)
	X  (prog (fa z part timetag port)
	X    (setq fa (wm-hash wme))
	X    (setq part (get fa 'wmpart*))
	X    (setq z (assq wme part))
	X    (or z (return nil))
	X    (setq timetag (cdr z))
	X    (cond ((and *wtrace* *in-rhs*)
	X           (setq port (trace-file))
	X           (terpri port)
	X           (princ '|<=wm: | port)
	X           (ppelm wme port)))
	X    (setq *action-count* (1+ *action-count*))
	X    (setq *critical* t)
	X    (setq *current-wm* (1- *current-wm*))
	X    (record-change '<=wm timetag wme)
	X    (match nil wme)
	X    (putprop fa (delq z part) 'wmpart*)
	X    (setq *critical* nil))) 
	X
	X; mapwm maps down the elements of wm, applying fn to each element
	X; each element is of form (datum . creation-time)
	X
	X(defun mapwm (fn)
	X  (prog (wmpl part)
	X        (setq wmpl *wmpart-list*)
	X   lab1 (cond ((atom wmpl) (return nil)))
	X        (setq part (get (car wmpl) 'wmpart*))
	X        (setq wmpl (cdr wmpl))
	X        (mapc fn part)
	X        (go lab1))) 
	X
	X(defun wm fexpr (a) 
	X  (mapc (function (lambda (z) (terpri) (ppelm z t))) 
	X	(get-wm a))
	X  nil) 
	X
	X(defun get-wm (z)
	X  (setq *wm-filter* z)
	X  (setq *wm* nil)
	X  (mapwm (function get-wm2))
	X  (prog2 nil *wm* (setq *wm* nil))) 
	X
	X(defun get-wm2 (elem) 
	X (cond ((or (null *wm-filter*) (member (cdr elem) *wm-filter*))
	X	(setq *wm* (cons (car elem) *wm*)]
	X
	X(defun wm-hash (x)
	X  (cond ((not x) '<default>)
	X        ((not (car x)) (wm-hash (cdr x)))
	X        ((symbolp (car x)) (car x))
	X        (t (wm-hash (cdr x))))) 
	X
	X(defun creation-time (wme)
	X  (cdr (assq wme (get (wm-hash wme) 'wmpart*)))) 
	X
	X(defun rehearse nil
	X  (prog nil
	X    (setq *old-wm* nil)
	X    (mapwm (function refresh-collect))
	X    (mapc (function refresh-del) *old-wm*)
	X    (mapc (function refresh-add) *old-wm*)
	X    (setq *old-wm* nil))) 
	X
	X(defun refresh-collect (x) (setq *old-wm* (cons x *old-wm*))) 
	X
	X(defun refresh-del (x) (remove-from-wm (car x))) 
	X
	X(defun refresh-add (x) (add-to-wm (car x) (cdr x))) 
	X
	X(defun trace-file ()
	X  (prog (port)
	X        (setq port t)
	X	(cond (*trace-file*
	X	       (setq port ($ofile *trace-file*))
	X	       (cond ((null port)
	X	              (%warn '|trace: file has been closed| *trace-file*)
	X		      (setq port t)))))
	X        (return port)))
	X
	X
	X;;; Basic functions for RHS evaluation
	X
	X(defun eval-rhs (pname data)
	X  (prog (node port)
	X    (cond (*ptrace*
	X           (setq port (trace-file))
	X           (terpri port)
	X           (princ *cycle-count* port)
	X           (princ '|. | port)
	X           (princ pname port)
	X           (time-tag-print data port)))
	X    (setq *data-matched* data)
	X    (setq *p-name* pname)
	X    (setq *last* nil)
	X    (setq node (get pname 'topnode))
	X    (init-var-mem (var-part node))
	X    (init-ce-var-mem (ce-var-part node))
	X    (begin-record pname data)
	X    (setq *in-rhs* t)
	X    (eval (rhs-part node))
	X    (setq *in-rhs* nil)
	X    (end-record))) 
	X
	X(defun time-tag-print (data port)
	X  (cond ((not (null data))
	X         (time-tag-print (cdr data) port)
	X         (princ '| | port)
	X         (princ (creation-time (car data)) port))))
	X
	X(defun init-var-mem (vlist)
	X  (prog (v ind r)
	X        (setq *variable-memory* nil)
	X   top  (and (atom vlist) (return nil))
	X        (setq v (car vlist))
	X        (setq ind (cadr vlist))
	X        (setq vlist (cddr vlist))
	X        (setq r (gelm *data-matched* ind))
	X        (setq *variable-memory* (cons (cons v r) *variable-memory*))
	X        (go top))) 
	X
	X(defun init-ce-var-mem (vlist)
	X  (prog (v ind r)
	X        (setq *ce-variable-memory* nil)
	X   top  (and (atom vlist) (return nil))
	X        (setq v (car vlist))
	X        (setq ind (cadr vlist))
	X        (setq vlist (cddr vlist))
	X        (setq r (ce-gelm *data-matched* ind))
	X        (setq *ce-variable-memory*
	X              (cons (cons v r) *ce-variable-memory*))
	X        (go top))) 
	X
	X(defun make-ce-var-bind (var elem)
	X  (setq *ce-variable-memory*
	X        (cons (cons var elem) *ce-variable-memory*))) 
	X
	X(defun make-var-bind (var elem)
	X  (setq *variable-memory* (cons (cons var elem) *variable-memory*))) 
	X
	X(defun $varbind (x)
	X  (prog (r)
	X	(and (not *in-rhs*) (return x))
	X        (setq r (assq x *variable-memory*))
	X        (cond (r (return (cdr r)))
	X              (t (return x))))) 
	X
	X(defun get-ce-var-bind (x)
	X  (prog (r)
	X        (cond ((numberp x) (return (get-num-ce x))))
	X        (setq r (assq x *ce-variable-memory*))
	X        (cond (r (return (cdr r)))
	X              (t (return nil))))) 
	X
	X(defun get-num-ce (x)
	X  (prog (r l d)
	X        (setq r *data-matched*)
	X        (setq l (length r))
	X        (setq d (- l x))
	X        (and (> 0. d) (return nil))
	X   la   (cond ((null r) (return nil))
	X              ((> 1. d) (return (car r))))
	X        (setq d (1- d))
	X        (setq r (cdr r))
	X        (go la))) 
	X
	X
	X(defun build-collect (z)
	X  (prog (r)
	X   la   (and (atom z) (return nil))
	X        (setq r (car z))
	X        (setq z (cdr z))
	X        (cond ((dtpr r)
	X               ($value '\()
	X               (build-collect r)
	X               ($value '\)))
	X              ((eq r '\\) ($change (car z)) (setq z (cdr z)))
	X              (t ($value r)))
	X        (go la))) 
	X
	X(defun unflat (x) (setq *rest* x) (unflat*)) 
	X
	X(defun unflat* nil
	X  (prog (c)
	X        (cond ((atom *rest*) (return nil)))
	X        (setq c (car *rest*))
	X        (setq *rest* (cdr *rest*))
	X        (cond ((eq c '\() (return (cons (unflat*) (unflat*))))
	X              ((eq c '\)) (return nil))
	X              (t (return (cons c (unflat*))))))) 
	X
	X
	X(defun $change (x)
	X  (prog nil
	X        (cond ((dtpr x) (eval-function x))
	X              (t ($value ($varbind x)))))) 
	X
	X(defun eval-args (z)
	X  (prog (r)
	X        (rhs-tab 1.)
	X   la   (and (atom z) (return nil))
	X        (setq r (car z))
	X        (setq z (cdr z))
	X        (cond ((eq r '^)
	X               (rhs-tab (car z))
	X               (setq r (cadr z))
	X               (setq z (cddr z))))
	X        (cond ((eq r '//) ($value (car z)) (setq z (cdr z)))
	X              (t ($change r)))
	X        (go la))) 
	X
	X
	X(defun eval-function (form)
	X  (cond ((not *in-rhs*)
	X	 (%warn '|functions cannot be used at top level| (car form)))
	X	(t (eval form))))
	X
	X
	X;;; Functions to manipulate the result array
	X
	X
	X(defun $reset nil
	X  (setq *max-index* 0.)
	X  (setq *next-index* 1.)) 
	X
	X; rhs-tab implements the tab ('^') function in the rhs.  it has
	X; four responsibilities:
	X;	- to move the array pointers
	X;	- to watch for tabbing off the left end of the array
	X;	  (ie, to watch for pointers less than 1)
	X;	- to watch for tabbing off the right end of the array
	X;	- to write nil in all the slots that are skipped
	X; the last is necessary if the result array is not to be cleared
	X; after each use; if rhs-tab did not do this, $reset
	X; would be much slower.
	X
	X(defun rhs-tab (z) ($tab ($varbind z)))
	X
	X(defun $tab (z)
	X  (prog (edge next)
	X        (setq next ($litbind z))
	X        (and (floatp next) (setq next (fix next)))
	X        (cond ((or (not (numberp next)) 
	X		   (> next *size-result-array*)
	X		   (> 1. next))
	X               (%warn '|illegal index after ^| next)
	X               (return *next-index*)))
	X        (setq edge (- next 1.))
	X        (cond ((> *max-index* edge) (go ok)))
	X   clear (cond ((== *max-index* edge) (go ok)))
	X        (putvector *result-array* edge nil)
	X        (setq edge (1- edge))
	X        (go clear)
	X   ok   (setq *next-index* next)
	X        (return next))) 
	X
	X(defun $value (v)
	X  (cond ((> *next-index* *size-result-array*)
	X         (%warn '|index too large| *next-index*))
	X        (t
	X         (and (> *next-index* *max-index*)
	X              (setq *max-index* *next-index*))
	X         (putvector *result-array* *next-index* v)
	X         (setq *next-index* (1+ *next-index*))))) 
	X
	X(defun use-result-array nil
	X  (prog (k r)
	X        (setq k *max-index*)
	X        (setq r nil)
	X   top  (and (== k 0.) (return r))
	X        (setq r (cons (getvector *result-array* k) r))
	X        (setq k (1- k))
	X        (go top))) 
	X
	X(defun $assert nil
	X  (setq *last* (use-result-array))
	X  (add-to-wm *last* nil))
	X
	X(defun $parametercount nil *max-index*)
	X
	X(defun $parameter (k)
	X  (cond ((or (not (numberp k)) (> k *size-result-array*) (< k 1.))
	X	 (%warn '|illegal parameter number | k)
	X         nil)
	X        ((> k *max-index*) nil)
	X	(t (getvector *result-array* k))))
	X
	X
	X;;; RHS actions
	X
	X(defun make fexpr (z)
	X  (prog nil
	X        ($reset)
	X        (eval-args z)
	X        ($assert))) 
	X
	X(defun modify fexpr (z)
	X  (prog (old)
	X	(cond ((not *in-rhs*)
	X	       (%warn '|cannot be called at top level| 'modify)
-- 
---------------
C'est la vie, C'est la guerre, C'est la pomme de terre
Mail:	Imagen Corp. 2650 San Tomas Expressway Santa Clara, CA 95052-8101 
UUCP:	...{decvax,ucbvax}!decwrl!imagen!turner      AT&T: (408) 986-9400

turner@imagen.UUCP (D'arc Angel) (01/19/87)

	X(proclaim '(special *matrix* *feature-count* *pcount* *vars* *cur-vars*
	X          *curcond* *subnum* *last-node* *last-branch* *first-node*
	X          *sendtocall* *flag-part* *alpha-flag-part* *data-part*
	X          *alpha-data-part* *ce-vars* *virtual-cnt* *real-cnt*
	X          *current-token* *c1* *c2* *c3* *c4* *c5* *c6* *c7* *c8* *c9*
	X          *c10* *c11* *c12* *c13* *c14* *c15* *c16* *c17* *c18* *c19*
	X          *c20* *c21* *c22* *c23* *c24* *c25* *c26* *c27* *c28* *c29*
	X          *c30* *c31* *c32* *c33* *c34* *c35* *c36* *c37* *c38* *c39*
	X          *c40* *c41* *c42* *c43* *c44* *c45* *c46* *c47* *c48* *c49*
	X          *c50* *c51* *c52* *c53* *c54* *c55* *c56* *c57* *c58* *c59*
	X          *c60* *c61* *c62* *c63* *c64* *record-array* *result-array* 
	X          *max-cs* *total-cs* *limit-cs* *cr-temp* *side*
	X          *conflict-set* *halt-flag* *phase* *critical*
	X          *cycle-count* *total-token* *max-token* *refracts* 
	X          *limit-token* *total-wm* *current-wm* *max-wm*
	X          *action-count* *wmpart-list* *wm* *data-matched* *p-name*
	X          *variable-memory* *ce-variable-memory* 
	X          *max-index* ; number of right-most field in wm element 
	X          *next-index* *size-result-array* *rest* *build-trace* *last*
	X          *ptrace* *wtrace* *in-rhs* *recording* *accept-file* *trace-file* 
	X          *mtrace* *madeby* ; used to trace and record makers of elements
	X          *write-file* *record-index* *max-record-index* *old-wm*
	X          *record* *filters* *break-flag* *strategy* *remaining-cycles*
	X	  *wm-filter* *rhs-bound-vars* *rhs-bound-ce-vars* *ppline* 
	X	  *ce-count* *brkpts* *class-list* *buckets* *action-type*
	X          *literals*   ;stores literal definitions
	X          *pnames*     ;stores production names
	X	  *externals*  ;tracks external declarations 
	X          *vector-attributes*  ;list of vector-attributes
	X	  ))
	X
	X;(declare (localf ce-gelm gelm peek-sublex sublex
	X;          eval-nodelist sendto and-left and-right not-left not-right
	X;          top-levels-eq add-token real-add-token remove-old
	X;          remove-old-num remove-old-no-num removecs insertcs dsort
	X;          best-of best-of* conflict-set-compare =alg ))
	X
	X
	X;;; Functions that were revised so that they would compile efficiently
	X
	X
	X;* The function == is machine dependent\!
	X;* This function compares small integers for equality.  It uses EQ
	X;* so that it will be fast, and it will consequently not work on all
	X;* Lisps.  It works in Franz Lisp for integers in [-128, 127]
	X
	X
	X;(defun == (&rest z) (= (cadr z) (caddr z)))
	X(defun == (x y) (= x y))
	X
	X; =ALG returns T if A and B are algebraicly equal.
	X
	X(defun =alg (a b) (= a b))
	X
	X(defmacro fast-symeval (&rest z)
	X	 `(cond ((eq ,(car z) '*c1*) *c1*)
	X		((eq ,(car z) '*c2*) *c2*)
	X		((eq ,(car z) '*c3*) *c3*)
	X		((eq ,(car z) '*c4*) *c4*)
	X		((eq ,(car z) '*c5*) *c5*)
	X		((eq ,(car z) '*c6*) *c6*)
	X		((eq ,(car z) '*c7*) *c7*)
	X		(t (eval ,(car z)))  ))
	X
	X; getvector and putvector are fast routines for using one-dimensional
	X; arrays.  these routines do no checking; they assume
	X;	1. the array is a vector with 0 being the index of the first
	X;	   element
	X;	2. the vector holds arbitrary list values
	X;defun versions are useful for tracing
	X
	X; Example call: (putvector array index value)
	X
	X(defmacro putvector (array_ref ind var)
	X      `(setf (aref ,array_ref ,ind) ,var))
	X
	X;(defun putvector (array_ref ind var)
	X;      (setf (aref array_ref ind) var))
	X
	X; Example call: (getvector name index)
	X
	X;(defmacro getvector(&rest z)
	X;     (list 'cxr (caddr z) (cadr z)))
	X
	X(defmacro getvector(array_ref ind)
	X      `(aref ,array_ref ,ind))
	X
	X;(defun getvector (array_ref ind)
	X ;       (aref array_ref ind))
	X
	X(defun ce-gelm (x k)
	X  (prog nil
	X   loop (and (== k 1.) (return (car x)))
	X        (setq k (1- k))
	X        (setq x (cdr x))
	X        (go loop))) 
	X
	X; The loops in gelm were unwound so that fewer calls on DIFFERENCE
	X; would be needed
	X
	X(defun gelm (x k)
	X  (prog (ce sub)
	X        (setq ce  (floor (/ k 10000)))
	X        (setq sub (- k (* ce 10000)))
	X celoop (and (== ce 0) (go ph2))
	X        (setq x (cdr x))
	X        (and (== ce 1) (go ph2))
	X        (setq x (cdr x))
	X        (and (== ce 2) (go ph2))
	X        (setq x (cdr x))
	X        (and (== ce 3) (go ph2))
	X        (setq x (cdr x))
	X        (and (== ce 4) (go ph2))
	X        (setq ce (- ce 4))
	X        (go celoop)
	X   ph2  (setq x (car x))
	X   subloop (and (== sub 0) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 1) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 2) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 3) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 4) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 5) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 6) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 7) (go finis))
	X        (setq x (cdr x))
	X        (and (== sub 8) (go finis))
	X        (setq sub (- sub 8))
	X        (go subloop)
	X   finis (return (car x)))) 
	X
	X
	X;;; Utility functions
	X
	X
	X
	X(defun printline (x) (mapc (function printline*) x)) 
	X
	X(defun printline* (y) (princ '| |) (print y)) 
	X
	X(defun printlinec (x) (mapc (function printlinec*) x)) 
	X
	X(defun printlinec* (y) (princ '| |) (princ y)) 
	X
	X; intersect two lists using eq for the equality test
	X
	X(defun interq (x y)
	X  (intersection x y :test #'eq))
	X
	X(defun enter (x ll)
	X   (and (not (member x ll :test #'equal))
	X       (push x ll)))
	X
	X; later versions of Franz have this standard
	X;(defun neq (x y)
	X;   (not (eq x y)))
	X
	X;Hack read-macro tables to accept single characters -- right out of CL book.
	X(defun single-macro-character (stream char)
	X   (declare (ignore stream))
	X   (character char))
	X
	X(defun i-g-v nil
	X (prog (x)
	X        (set-macro-character #\{ #'single-macro-character )
	X        (set-macro-character #\} #'single-macro-character )
	X        (set-macro-character #\^ #'single-macro-character )
	X;	(setsyntax '\{ 66.) ;These are already normal characters in CL
	X;	(setsyntax '\} 66.)
	X;	(setsyntax '^ 66.)
	X	(setq *buckets* 64.)		; OPS5 allows 64 named slots
	X	(setq *accept-file* nil)
	X	(setq *write-file* nil)
	X	(setq *trace-file* nil)
	X        (and (boundp '*class-list*)
	X          (mapc #'(lambda(class) (putprop class nil 'att-list)) *class-list*))
	X	(setq *class-list* nil)
	X	(setq *brkpts* nil)
	X	(setq *strategy* 'lex)
	X  	(setq *in-rhs* nil)
	X  	(setq *ptrace* t)
	X  	(setq *wtrace* nil)
	X	(setq *mtrace* t)            ; turn on made-by tracing
	X	(setq *madeby* nil)          ; record makers of wm elements
	X  	(setq *recording* nil)
	X        (setq *refracts* nil)
	X	(setq *real-cnt* (setq *virtual-cnt* 0.))
	X	(setq *max-cs* (setq *total-cs* 0.))
	X  	(setq *limit-token* 1000000.)
	X	(setq *limit-cs* 1000000.)
	X	(setq *critical* nil)
	X	(setq *build-trace* nil)
	X	(setq *wmpart-list* nil)
	X        (setq *pnames* nil)
	X        (setq *literals* nil) ; records literal definitions
	X	(setq *externals* nil) ; records external definitions
	X	(setq *vector-attributes* nil) ;records vector attributes
	X	(setq *size-result-array* 127.)
	X	(setq *result-array* (make-array 128))
	X	(setq *record-array* (make-array 128))
	X	(setq x 0)
	X        (setq *pnames* nil)     ; list of production names
	X  loop	(putvector *result-array* x nil)
	X	(setq x (1+ x))
	X	(and (not (> x *size-result-array*)) (go loop))
	X	(make-bottom-node)
	X	(setq *pcount* 0.)
	X	(initialize-record)
	X	(setq *cycle-count* (setq *action-count* 0.))
	X	(setq *total-token*
	X	       (setq *max-token* (setq *current-token* 0.)))
	X	(setq *total-cs* (setq *max-cs* 0.))
	X	(setq *total-wm* (setq *max-wm* (setq *current-wm* 0.)))
	X	(setq *conflict-set* nil)
	X	(setq *wmpart-list* nil)
	X	(setq *p-name* nil)
	X	(setq *remaining-cycles* 1000000)
	X))
	X
	X; if the size of result-array changes, change the line in i-g-v which
	X; sets the value of *size-result-array*
	X
	X(defun %warn (what where)
	X  (prog nil
	X    (terpri)
	X    (princ '?)
	X    (and *p-name* (princ *p-name*))
	X    (princ '|..|)
	X    (princ where)
	X    (princ '|..|)
	X    (princ what)
	X    (return where))) 
	X
	X(defun %error (what where)
	X    (%warn what where)
	X    (throw '!error! nil)) 
	X
	X;(defun round (x) (fix (plus 0.5 x))) 
	X
	X(defun top-levels-eq (la lb)
	X  (prog nil
	X   lx   (cond ((eq la lb) (return t))
	X              ((null la) (return nil))
	X              ((null lb) (return nil))
	X              ((not (eq (car la) (car lb))) (return nil)))
	X        (setq la (cdr la))
	X        (setq lb (cdr lb))
	X        (go lx))) 
	X
	X
	X;;; LITERAL and LITERALIZE
	X
	X(defmacro literal (&rest z)
	X  `(prog (atm val old args)
	X        (setq args ',z)
	X   top  (and (atom args) (return 'bound))
	X        (or (eq (cadr args) '=) (return (%warn '|wrong format| args)))
	X        (setq atm (car args))
	X        (setq val (caddr args))
	X        (setq args (cdddr args))
	X        (cond ((not (numberp val))
	X               (%warn '|can bind only to numbers| val))
	X              ((or (not (symbolp atm)) (variablep atm))
	X                (%warn '|can bind only constant atoms| atm))
	X              ((and (setq old (literal-binding-of atm)) (not (equal old val)))
	X               (%warn '|attempt to rebind attribute| atm))
	X              (t (putprop atm val 'ops-bind )))
	X        (go top))) 
	X
	X(defmacro literalize (&rest l)
	X  `(prog (class-name atts)
	X    (setq class-name (car ',l))
	X    (cond ((have-compiled-production)
	X           (%warn '|literalize called after p| class-name)
	X           (return nil))
	X          ((get class-name 'att-list)
	X           (%warn '|attempt to redefine class| class-name)
	X	   (return nil)))
	X    (setq *class-list* (cons class-name *class-list*))
	X    (setq atts (remove-duplicates (cdr ',l)))
	X    (test-attribute-names atts)
	X    (mark-conflicts atts atts)
	X    (putprop class-name  atts 'att-list))) 
	X
	X(defun vector-attribute  (&quote &rest l)
	X  (cond ((have-compiled-production)
	X         (%warn '|vector-attribute called after p| l))
	X        (t 
	X         (test-attribute-names l)
	X	 (mapc (function vector-attribute2) l)))) 
	X
	X(defun vector-attribute2 (att) (putprop att t 'vector-attribute)
	X			       (setq  *vector-attributes* 
	X				   (enter att *vector-attributes*)))
	X
	X(defun is-vector-attribute (att) (get att 'vector-attribute))
	X
	X(defun test-attribute-names (l)
	X  (mapc (function test-attribute-names2) l)) 
	X
	X(defun test-attribute-names2 (atm)
	X  (cond ((or (not (symbolp atm)) (variablep atm))
	X         (%warn '|can bind only constant atoms| atm)))) 
	X
	X(defun finish-literalize nil
	X  (cond ((not (null *class-list*))
	X         (mapc (function note-user-assigns) *class-list*)
	X         (mapc (function assign-scalars) *class-list*)
	X         (mapc (function assign-vectors) *class-list*)
	X         (mapc (function put-ppdat) *class-list*)
	X         (mapc (function erase-literal-info) *class-list*)
	X         (setq *class-list* nil)
	X         (setq *buckets* nil)))) 
	X
	X(defun have-compiled-production nil (not (zerop *pcount*))) 
	X
	X(defun put-ppdat (class)
	X  (prog (al att ppdat)
	X        (setq ppdat nil)
	X        (setq al (get class 'att-list))
	X   top  (cond ((not (atom al))
	X               (setq att (car al))
	X               (setq al (cdr al))
	X               (setq ppdat
	X                     (cons (cons (literal-binding-of att) att)
	X                           ppdat))
	X               (go top)))
	X        (putprop class ppdat 'ppdat))) 
	X
	X; note-user-assigns and note-user-vector-assigns are needed only when
	X; literal and literalize are both used in a program.  They make sure that
	X; the assignments that are made explicitly with literal do not cause problems
	X; for the literalized classes.
	X
	X(defun note-user-assigns (class)
	X  (mapc (function note-user-assigns2) (get class 'att-list)))
	X
	X(defun note-user-assigns2 (att)
	X  (prog (num conf buck clash)
	X        (setq num (literal-binding-of att))
	X	(and (null num) (return nil))
	X	(setq conf (get att 'conflicts))
	X	(setq buck (store-binding att num))
	X	(setq clash (find-common-atom buck conf))
	X	(and clash
	X	     (%warn '|attributes in a class assigned the same number|
	X	            (cons att clash)))
	X        (return nil)))
	X
	X(defun note-user-vector-assigns (att given needed)
	X  (and (> needed given)
	X       (%warn '|vector attribute assigned too small a value in literal| att)))
	X
	X(defun assign-scalars (class)
	X  (mapc (function assign-scalars2) (get class 'att-list))) 
	X
	X(defun assign-scalars2 (att)
	X  (prog (tlist num bucket conf)
	X        (and (literal-binding-of att) (return nil))
	X        (and (is-vector-attribute att) (return nil))
	X        (setq tlist (buckets))
	X        (setq conf (get att 'conflicts))
	X   top  (cond ((atom tlist)
	X               (%warn '|could not generate a binding| att)
	X               (store-binding att -1.)
	X               (return nil)))
	X        (setq num (caar tlist))
	X        (setq bucket (cdar tlist))
	X        (setq tlist (cdr tlist))
	X        (cond ((disjoint bucket conf) (store-binding att num))
	X        (t (go top))))) 
	X
	X(defun assign-vectors (class)
	X  (mapc (function assign-vectors2) (get class 'att-list))) 
	X
	X(defun assign-vectors2 (att)
	X  (prog (big conf new old need)
	X        (and (not (is-vector-attribute att)) (return nil))
	X        (setq big 1.)
	X        (setq conf (get att 'conflicts))
	X   top  (cond ((not (atom conf))
	X               (setq new (car conf))
	X               (setq conf (cdr conf))
	X               (cond ((is-vector-attribute new)
	X                      (%warn '|class has two vector attributes|
	X		              (list att new)))
	X                     (t (setq big (max (literal-binding-of new) big))))
	X               (go top)))
	X        (setq need (1+ big))
	X	(setq old (literal-binding-of att))
	X	(cond (old (note-user-vector-assigns att old need))
	X	      (t (store-binding att need)))
	X        (return nil)))
	X
	X(defun disjoint (la lb) (not (find-common-atom la lb))) 
	X
	X(defun find-common-atom (la lb)
	X  (prog nil
	X   top  (cond ((null la) (return nil))
	X              ((memq (car la) lb) (return (car la)))
	X              (t (setq la (cdr la)) (go top))))) 
	X
	X(defun mark-conflicts (rem all)
	X  (cond ((not (null rem))
	X         (mark-conflicts2 (car rem) all)
	X         (mark-conflicts (cdr rem) all)))) 
	X
	X(defun mark-conflicts2 (atm lst)
	X  (prog (l)
	X        (setq l lst)
	X   top  (and (atom l) (return nil))
	X        (conflict atm (car l))
	X        (setq l (cdr l))
	X        (go top))) 
	X
	X(defun conflict (a b)
	X  (prog (old)
	X    (setq old (get a 'conflicts))
	X    (and (not (eq a b))
	X         (not (memq b old))
	X         (putprop a (cons b old) 'conflicts )))) 
	X
	X;(defun remove-duplicates (lst)
	X;  (cond ((atom lst) nil)
	X;        ((memq (car lst) (cdr lst)) (remove-duplicates (cdr lst)))
	X;        (t (cons (car lst) (remove-duplicates (cdr lst)))))) 
	X
	X(defun literal-binding-of (name) (get name 'ops-bind)) 
	X
	X(defun store-binding (name lit)
	X  (putprop name lit 'ops-bind)
	X  (add-bucket name lit)) 
	X
	X(defun add-bucket (name num)
	X  (prog (buc)
	X    (setq buc (assoc num (buckets)))
	X    (and (not (memq name buc))
	X         (rplacd buc (cons name (cdr buc))))
	X    (return buc))) 
	X
	X(defun buckets nil
	X  (and (atom *buckets*) (setq *buckets* (make-nums *buckets*)))
	X  *buckets*) 
	X
	X(defun make-nums (k)
	X  (prog (nums)
	X        (setq nums nil)
	X   l    (and (< k 2.) (return nums))
	X        (setq nums (cons (ncons k) nums))
	X        (setq k (1- k))
	X        (go l))) 
	X
	X;(defun erase-literal-info (class)
	X;  (mapc (function erase-literal-info2) (get class 'att-list))
	X;  (remprop class 'att-list)) 
	X
	X; modified to record literal info in the variable *literals*
	X(defun erase-literal-info (class)
	X      (setq *literals*
	X            (cons (cons class (get class 'att-list)) *literals*))
	X      (mapc (function erase-literal-info2) (get class 'att-list))
	X      (remprop class 'att-list))
	X
	X
	X(defun erase-literal-info2 (att) (remprop att 'conflicts)) 
	X
	X
	X;;; LHS Compiler
	X
	X(defun p (&quote &rest z) 
	X  (finish-literalize)
	X  (princ '*) 
	X  ;(drain);drain probably drains a line feed
	X  (compile-production (car z) (cdr z))) 
	X
	X(defun compile-production (name matrix)
	X  (prog (erm)
	X        (setq *p-name* name)
	X        (setq erm (catch '!error! (cmp-p name matrix) ))
	X	; following line is modified to save production name on *pnames*
	X        (and (null erm) (setq *pnames* (enter name *pnames*)))
	X	(setq *p-name* nil)
	X	(return erm)))
	X
	X(defun peek-lex nil (car *matrix*)) 
	X
	X(defun lex nil
	X  (prog2 nil (car *matrix*) (setq *matrix* (cdr *matrix*)))) 
	X
	X(defun end-of-p nil (atom *matrix*)) 
	X
	X(defun rest-of-p nil *matrix*) 
	X
	X(defun prepare-lex (prod) (setq *matrix* prod)) 
	X
	X
	X(defun peek-sublex nil (car *curcond*)) 
	X
	X(defun sublex nil
	X  (prog2 nil (car *curcond*) (setq *curcond* (cdr *curcond*)))) 
	X
	X(defun end-of-ce nil (atom *curcond*)) 
	X
	X(defun rest-of-ce nil *curcond*) 
	X
	X(defun prepare-sublex (ce) (setq *curcond* ce)) 
	X
	X(defun make-bottom-node nil (setq *first-node* (list '&bus nil))) 
	X
	X(defun cmp-p (name matrix)
	X  (prog (m bakptrs)
	X        (cond ((or (null name) (listp name))
	X               (%error '|illegal production name| name))
	X              ((equal (get name 'production) matrix)
	X	       (return nil)))
	X        (prepare-lex matrix)
	X        (excise-p name)
	X        (setq bakptrs nil)
	X        (setq *pcount* (1+ *pcount*))
	X        (setq *feature-count* 0.)
	X	(setq *ce-count* 0)
	X        (setq *vars* nil)
	X        (setq *ce-vars* nil)
	X	(setq *rhs-bound-vars* nil)
	X	(setq *rhs-bound-ce-vars* nil)
	X        (setq *last-branch* nil)
	X        (setq m (rest-of-p))
	X   l1   (and (end-of-p) (%error '|no '-->' in production| m))
	X        (cmp-prin)
	X        (setq bakptrs (cons *last-branch* bakptrs))
	X        (or (eq '--> (peek-lex)) (go l1))
	X        (lex)
	X	(check-rhs (rest-of-p))
	X        (link-new-node (list '&p
	X                             *feature-count*
	X                             name
	X                             (encode-dope)
	X                             (encode-ce-dope)
	X                             (cons 'progn (rest-of-p))))
	X        (putprop name (cdr (nreverse bakptrs)) 'backpointers )
	X	(putprop name matrix 'production)
	X        (putprop name *last-node* 'topnode))) 
	X
	X(defun rating-part (pnode) (cadr pnode)) 
	X
	X(defun var-part (pnode) (car (cdddr pnode))) 
	X
	X(defun ce-var-part (pnode) (cadr (cdddr pnode))) 
	X
	X(defun rhs-part (pnode) (caddr (cdddr pnode))) 
	X
	X(defun excise-p (name)
	X  (cond ((and (symbolp name) (get name 'topnode))
	X	 (printline (list name 'is 'excised))
	X         (setq *pcount* (1- *pcount*))
	X         (remove-from-conflict-set name)
	X         (kill-node (get name 'topnode))
	X         (setq *pnames* (delq name *pnames*))
	X	 (remprop name 'production)
	X	 (remprop name 'backpointers)
	X         (remprop name 'topnode)))) 
	X
	X(defun kill-node (node)
	X  (prog nil
	X   top  (and (atom node) (return nil))
	X        (rplaca node '&old)
	X        (setq node (cdr node))
	X        (go top))) 
	X
	X(defun cmp-prin nil
	X  (prog nil
	X        (setq *last-node* *first-node*)
	X        (cond ((null *last-branch*) (cmp-posce) (cmp-nobeta))
	X              ((eq (peek-lex) '-) (cmp-negce) (cmp-not))
	X              (t (cmp-posce) (cmp-and))))) 
	X
	X(defun cmp-negce nil (lex) (cmp-ce)) 
	X
	X(defun cmp-posce nil
	X  (setq *ce-count* (1+ *ce-count*))
	X  (cond ((eq (peek-lex) #\{) (cmp-ce+cevar))
	X        (t (cmp-ce)))) 
	X
	X(defun cmp-ce+cevar nil
	X  (prog (z)
	X        (lex)
	X        (cond ((atom (peek-lex)) (cmp-cevar) (cmp-ce))
	X              (t (cmp-ce) (cmp-cevar)))
	X        (setq z (lex))
	X        (or (eq z #\}) (%error '|missing '}'| z)))) 
	X
	X(defun new-subnum (k)
	X  (or (numberp k) (%error '|tab must be a number| k))
	X  (setq *subnum* (fix k))) 
	X
	X(defun incr-subnum nil (setq *subnum* (1+ *subnum*))) 
	X
	X(defun cmp-ce nil
	X  (prog (z)
	X        (new-subnum 0.)
	X        (setq *cur-vars* nil)
	X        (setq z (lex))
	X        (and (atom z)
	X             (%error '|atomic conditions are not allowed| z))
	X        (prepare-sublex z)
	X   la   (and (end-of-ce) (return nil))
	X        (incr-subnum)
	X        (cmp-element)
	X        (go la))) 
	X
	X(defun cmp-element nil
	X        (and (eq (peek-sublex) #\^) (cmp-tab))
	X        (cond ((eq (peek-sublex) '#\{) (cmp-product))
	X              (t (cmp-atomic-or-any))))
	X
	X(defun cmp-atomic-or-any nil
	X        (cond ((eq (peek-sublex) '<<) (cmp-any))
	X              (t (cmp-atomic))))
	X
	X(defun cmp-any nil
	X  (prog (a z)
	X        (sublex)
	X        (setq z nil)
	X   la   (cond ((end-of-ce) (%error '|missing '>>'| a)))
	X        (setq a (sublex))
	X        (cond ((not (eq '>> a)) (setq z (cons a z)) (go la)))
	X        (link-new-node (list '&any nil (current-field) z)))) 
	X
	X
	X(defun cmp-tab nil
	X  (prog (r)
	X        (sublex)
	X        (setq r (sublex))
	X        (setq r ($litbind r))
	X        (new-subnum r))) 
	X
	X(defun $litbind (x)
	X  (prog (r)
	X        (cond ((and (symbolp x) (setq r (literal-binding-of x)))
	X               (return r))
	X              (t (return x))))) 
	X
	X(defun get-bind (x)
	X  (prog (r)
	X        (cond ((and (symbolp x) (setq r (literal-binding-of x)))
	X               (return r))
	X              (t (return nil))))) 
	X
	X(defun cmp-atomic nil
	X  (prog (test x)
	X        (setq x (peek-sublex))
	X        (cond ((eq x '=) (setq test 'eq) (sublex))
	X              ((eq x '<>) (setq test 'ne) (sublex))
	X              ((eq x '<) (setq test 'lt) (sublex))
	X              ((eq x '<=) (setq test 'le) (sublex))
	X              ((eq x '>) (setq test 'gt) (sublex))
	X              ((eq x '>=) (setq test 'ge) (sublex))
	X              ((eq x '<=>) (setq test 'xx) (sublex))
	X              (t (setq test 'eq)))
	X        (cmp-symbol test))) 
	X
	X(defun cmp-product nil
	X  (prog (save)
	X        (setq save (rest-of-ce))
	X        (sublex)
	X   la   (cond ((end-of-ce)
	X               (cond ((member #\} save) 
	X		      (%error '|wrong contex for '}'| save))
	X		     (t (%error '|missing '}'| save))))
	X              ((eq (peek-sublex) #\}) (sublex) (return nil)))
	X        (cmp-atomic-or-any)
	X        (go la))) 
	X
	X(defun variablep (x) (and (symbolp x) (char-equal (char (symbol-name x) 0) #\<))) 
	X
	X(defun cmp-symbol (test)
	X  (prog (flag)
	X        (setq flag t)
	X        (cond ((eq (peek-sublex) '//) (sublex) (setq flag nil)))
	X        (cond ((and flag (variablep (peek-sublex)))
	X               (cmp-var test))
	X              ((numberp (peek-sublex)) (cmp-number test))
	X              ((symbolp (peek-sublex)) (cmp-constant test))
	X              (t (%error '|unrecognized symbol| (sublex)))))) 
	X
	X(defun concat3(x y z)
	X   (intern (format nil "~s~s~s" x y z)))
	X
	X(defun cmp-constant (test)
	X  (or (memq test '(eq ne xx))
	X      (%error '|non-numeric constant after numeric predicate| (sublex)))
	X  (link-new-node (list (concat3 't test 'a)
	X                       nil
	X                       (current-field)
	X                       (sublex)))) 
	X
	X
	X(defun cmp-number (test)
	X  (link-new-node (list (concat3 't test 'n)
	X                       nil
	X                       (current-field)
	X                       (sublex)))) 
	X
	X(defun current-field nil (field-name *subnum*)) 
	X
	X(defun field-name (num)
	X  (cond ((= num 1.) '*c1*)
	X        ((= num 2.) '*c2*)
	X        ((= num 3.) '*c3*)
	X        ((= num 4.) '*c4*)
	X        ((= num 5.) '*c5*)
	X        ((= num 6.) '*c6*)
	X        ((= num 7.) '*c7*)
	X        ((= num 8.) '*c8*)
	X        ((= num 9.) '*c9*)
	X        ((= num 10.) '*c10*)
	X        ((= num 11.) '*c11*)
	X        ((= num 12.) '*c12*)
	X        ((= num 13.) '*c13*)
	X        ((= num 14.) '*c14*)
	X        ((= num 15.) '*c15*)
	X        ((= num 16.) '*c16*)
	X        ((= num 17.) '*c17*)
	X        ((= num 18.) '*c18*)
	X        ((= num 19.) '*c19*)
	X        ((= num 20.) '*c20*)
	X        ((= num 21.) '*c21*)
	X        ((= num 22.) '*c22*)
	X        ((= num 23.) '*c23*)
	X        ((= num 24.) '*c24*)
	X        ((= num 25.) '*c25*)
	X        ((= num 26.) '*c26*)
	X        ((= num 27.) '*c27*)
	X        ((= num 28.) '*c28*)
	X        ((= num 29.) '*c29*)
	X        ((= num 30.) '*c30*)
	X        ((= num 31.) '*c31*)
	X        ((= num 32.) '*c32*)
	X        ((= num 33.) '*c33*)
	X        ((= num 34.) '*c34*)
	X        ((= num 35.) '*c35*)
	X        ((= num 36.) '*c36*)
	X        ((= num 37.) '*c37*)
	X        ((= num 38.) '*c38*)
	X        ((= num 39.) '*c39*)
	X        ((= num 40.) '*c40*)
	X        ((= num 41.) '*c41*)
	X        ((= num 42.) '*c42*)
	X        ((= num 43.) '*c43*)
	X        ((= num 44.) '*c44*)
	X        ((= num 45.) '*c45*)
	X        ((= num 46.) '*c46*)
	X        ((= num 47.) '*c47*)
	X        ((= num 48.) '*c48*)
	X        ((= num 49.) '*c49*)
	X        ((= num 50.) '*c50*)
	X        ((= num 51.) '*c51*)
	X        ((= num 52.) '*c52*)
	X        ((= num 53.) '*c53*)
	X        ((= num 54.) '*c54*)
	X        ((= num 55.) '*c55*)
	X        ((= num 56.) '*c56*)
	X        ((= num 57.) '*c57*)
	X        ((= num 58.) '*c58*)
	X        ((= num 59.) '*c59*)
	X        ((= num 60.) '*c60*)
	X        ((= num 61.) '*c61*)
	X        ((= num 62.) '*c62*)
	X        ((= num 63.) '*c63*)
	X        ((= num 64.) '*c64*)
	X        (t (%error '|condition is too long| (rest-of-ce))))) 
	X
	X
	X;;; Compiling variables
	X;
	X;
	X;
	X; *cur-vars* are the variables in the condition element currently 
	X; being compiled.  *vars* are the variables in the earlier condition
	X; elements.  *ce-vars* are the condition element variables.  note
	X; that the interpreter will not confuse condition element and regular
	X; variables even if they have the same name.
	X;
	X; *cur-vars* is a list of triples: (name predicate subelement-number)
	X; eg:		( (<x> eq 3)
	X;		  (<y> ne 1)
	X;		  . . . )
	X;
	X; *vars* is a list of triples: (name ce-number subelement-number)
	X; eg:		( (<x> 3 3)
	X;		  (<y> 1 1)
	X;		  . . . )
	X;
	X; *ce-vars* is a list of pairs: (name ce-number)
	X; eg:		( (ce1 1)
	X;		  (<c3> 3)
	X;		  . . . )
	X
	X(defun var-dope (var) (assq var *vars*))
	X
	X(defun ce-var-dope (var) (assq var *ce-vars*))
	X
	X(defun cmp-var (test)
	X  (prog (old name)
	X        (setq name (sublex))
	X        (setq old (assq name *cur-vars*))
	X        (cond ((and old (eq (cadr old) 'eq))
	X               (cmp-old-eq-var test old))
	X              ((and old (eq test 'eq)) (cmp-new-eq-var name old))
	X              (t (cmp-new-var name test))))) 
	X
	X(defun cmp-new-var (name test)
	X  (setq *cur-vars* (cons (list name test *subnum*) *cur-vars*))) 
	X
	X(defun cmp-old-eq-var (test old)
	X  (link-new-node (list (concat3 't test 's)
	X                       nil
	X                       (current-field)
	X                       (field-name (caddr old))))) 
	X
	X(defun cmp-new-eq-var (name old)
	X  (prog (pred next)
	X        (setq *cur-vars* (delq old *cur-vars*))
	X        (setq next (assq name *cur-vars*))
	X        (cond (next (cmp-new-eq-var name next))
	X              (t (cmp-new-var name 'eq)))
	X        (setq pred (cadr old))
	X        (link-new-node (list (concat3 't pred 's)
	X                             nil
	X                             (field-name (caddr old))
	X                             (current-field))))) 
	X
	X(defun cmp-cevar nil
	X  (prog (name old)
	X        (setq name (lex))
	X        (setq old (assq name *ce-vars*))
	X        (and old
	X             (%error '|condition element variable used twice| name))
	X        (setq *ce-vars* (cons (list name 0.) *ce-vars*)))) 
	X
	X(defun cmp-not nil (cmp-beta '&not)) 
	X
	X(defun cmp-nobeta nil (cmp-beta nil)) 
	X
	X(defun cmp-and nil (cmp-beta '&and)) 
	X
	X(defun cmp-beta (kind)
	X  (prog (tlist vdope vname vpred vpos old)
	X        (setq tlist nil)
	X   la   (and (atom *cur-vars*) (go lb))
	X        (setq vdope (car *cur-vars*))
	X        (setq *cur-vars* (cdr *cur-vars*))
	X        (setq vname (car vdope))
	X        (setq vpred (cadr vdope))
	X        (setq vpos (caddr vdope))
	X        (setq old (assq vname *vars*))
	X        (cond (old (setq tlist (add-test tlist vdope old)))
	X              ((neq kind '&not) (promote-var vdope)))
	X        (go la)
	X   lb   (and kind (build-beta kind tlist))
	X        (or (eq kind '&not) (fudge))
	X        (setq *last-branch* *last-node*))) 
	X
	X(defun add-test (list new old)
	X  (prog (ttype lloc rloc)
	X	(setq *feature-count* (1+ *feature-count*))
	X        (setq ttype (concat3 't (cadr new) 'b))
	X        (setq rloc (encode-singleton (caddr new)))
	X        (setq lloc (encode-pair (cadr old) (caddr old)))
	X        (return (cons ttype (cons lloc (cons rloc list)))))) 
	X
	X; the following two functions encode indices so that gelm can
	X; decode them as fast as possible
	X
	X(defun encode-pair (a b) (+ (* 10000. (1- a)) (1- b))) 
	X
	X(defun encode-singleton (a) (1- a)) 
	X
	X(defun promote-var (dope)
	X  (prog (vname vpred vpos new)
	X        (setq vname (car dope))
	X        (setq vpred (cadr dope))
	X        (setq vpos (caddr dope))
	X        (or (eq 'eq vpred)
	X            (%error '|illegal predicate for first occurrence|
	X                   (list vname vpred)))
	X        (setq new (list vname 0. vpos))
	X        (setq *vars* (cons new *vars*)))) 
	X
	X(defun fudge nil
	X  (mapc (function fudge*) *vars*)
	X  (mapc (function fudge*) *ce-vars*)) 
	X
	X(defun fudge* (z)
	X  (prog (a) (setq a (cdr z)) (rplaca a (1+ (car a))))) 
	X
	X(defun build-beta (type tests)
	X  (prog (rpred lpred lnode lef)
	X        (link-new-node (list '&mem nil nil (protomem)))
	X        (setq rpred *last-node*)
	X        (cond ((eq type '&and)
	X               (setq lnode (list '&mem nil nil (protomem))))
	X              (t (setq lnode (list '&two nil nil))))
	X        (setq lpred (link-to-branch lnode))
	X        (cond ((eq type '&and) (setq lef lpred))
	X              (t (setq lef (protomem))))
	X        (link-new-beta-node (list type nil lef rpred tests)))) 
	X
	X(defun protomem nil (list nil)) 
	X
	X(defun memory-part (mem-node) (car (cadddr mem-node))) 
	X
	X(defun encode-dope nil
	X  (prog (r all z k)
	X        (setq r nil)
	X        (setq all *vars*)
	X   la   (and (atom all) (return r))
	X        (setq z (car all))
	X        (setq all (cdr all))
	X        (setq k (encode-pair (cadr z) (caddr z)))
	X        (setq r (cons (car z) (cons k r)))
	X        (go la))) 
	X
	X(defun encode-ce-dope nil
	X  (prog (r all z k)
	X        (setq r nil)
	X        (setq all *ce-vars*)
	X   la   (and (atom all) (return r))
	X        (setq z (car all))
	X        (setq all (cdr all))
	X        (setq k (cadr z))
	X        (setq r (cons (car z) (cons k r)))
	X        (go la))) 
	X
	X
	X
	X;;; Linking the nodes
	X
	X(defun link-new-node (r)
	X  (cond ((not (member (car r) '(&p &mem &two &and &not)))
	X	 (setq *feature-count* (1+ *feature-count*))))
	X  (setq *virtual-cnt* (1+ *virtual-cnt*))
	X  (setq *last-node* (link-left *last-node* r))) 
	X
	X(defun link-to-branch (r)
	X  (setq *virtual-cnt* (1+ *virtual-cnt*))
	X  (setq *last-branch* (link-left *last-branch* r))) 
	X
	X(defun link-new-beta-node (r)
	X  (setq *virtual-cnt* (1+ *virtual-cnt*))
	X  (setq *last-node* (link-both *last-branch* *last-node* r))
	X  (setq *last-branch* *last-node*)) 
	X
	X(defun link-left (pred succ)
	X  (prog (a r)
	X        (setq a (left-outs pred))
	X        (setq r (find-equiv-node succ a))
	X        (and r (return r))
	X        (setq *real-cnt* (1+ *real-cnt*))
	X        (attach-left pred succ)
	X        (return succ))) 
	X
	X(defun link-both (left right succ)
	X  (prog (a r)
	X        (setq a (interq (left-outs left) (right-outs right)))
	X        (setq r (find-equiv-beta-node succ a))
	X        (and r (return r))
	X        (setq *real-cn (sublex))
	X              ((eq x '<=) (setq test 'le) (sublex))
	X              ((eq x '>) (setq test 'gt) (sublex))
	X              ((eq x '>=) (setq test 'ge) (sublex))
	X              ((eq x '<=>) (setq test 'xx) (sublex))
	X              (t (setq test 'eq)))
	X        (cmp-symbol test))) 
	X
	X(defun cmp-product nil
	X  (prog (save)
	X        (setq save (rest-of-ce))
	X        (sublex)
	X   la   (cond ((end-of-ce)
	X               (cond ((member #\} save) 
	X		      (%error '|wrong contex for '}'| save))
	X		     (t (%error '|missing '}'| save))))
	X              ((eq (peek-sublex) #\}) (sublex) (return nil)))
	X        (cmp-atomic-or-any)
	X        (go la))) 
	X
	X(defun variablep (x) (and (symbolp x) (char-equal (char (symbol-name x) 0) #\<))) 
	X
	X(defun cmp-symbol (test)
	X  (prog (flag)
	X        (setq flag t)
	X        (cond ((eq (peek-sublex) '//) (sublex) (setq flag nil)))
	X        (cond ((and flag (variablep (peek-sublex)))
	X               (cmp-var test))
	X              ((numberp (peek-sublex)) (cmp-number test))
	X              ((symbolp (peek-sublex)) (cmp-constant test))
	X              (t (%error '|unrecognized symbol| (sublex)))))) 
	X
	X(defun concat3(x y z)
	X   (intern (format nil "~s~s~s" x y z)))
	X
	X(defun cmp-constant (test)
	X  (or (memq test '(eq ne xx))
	X      (%error '|non-numeric constant after numeric predicate| (sublex)))
	X  (link-new-node (list (concat3 't test 'a)
	X                       nil
	X                       (current-field)
	X                       (sublex)))) 
	X
	X
	X(defun cmp-number (test)
	X  (link-new-node (list (concat3 't test 'n)
	X                       nil
	X                       (current-field)
	X                       (sublex)))) 
	X
	X(defun current-field nil (field-name *subnum*)) 
	X
	X(defun field-name (num)
	X  (cond ((= num 1.) '*c1*)
	X        ((= num 2.) '*c2*)
	X        ((= num 3.) '*c3*)
	X        ((= num 4.) '*c4*)
	X        ((= num 5.) '*c5*)
	X        ((= num 6.) '*c6*)
	X        ((= num 7.) '*c7*)
	X        ((= num 8.) '*c8*)
	X        ((= num 9.) '*c9*)
	X        ((= num 10.) '*c10*)
	X        ((= num 11.) '*c11*)
	X        ((= num 12.) '*c12*)
	X        ((= num 13.) '*c13*)
	X        ((= num 14.) '*c14*)
	X        ((= num 15.) '*c15*)
	X        ((= num 16.) '*c16*)
	X        ((= num 17.) '*c17*)
	X        ((= num 18.) '*c18*)
	X        ((= num 19.) '*c19*)
	X        ((= num 20.) '*c20*)
	X        ((= num 21.) '*c21*)
	X        ((= num 22.) '*c22*)
	X        ((= num 23.) '*c23*)
	X        ((= num 24.) '*c24*)
	X        ((= num 25.) '*c25*)
	X        ((= num 26.) '*c26*)
	X        ((= num 27.) '*c27*)
	X        ((= num 28.) '*c28*)
	X        ((= num 29.) '*c29*)
	X        ((= num 30.) '*c30*)
	X        ((= num 31.) '*c31*)
	X        ((= num 32.) '*c32*)
	X        ((= num 33.) '*c33*)
	X        ((= num 34.) '*c34*)
	X        ((= num 35.) '*c35*)
	X        ((= num 36.) '*c36*)
	X        ((= num 37.) '*c37*)
	X        ((= num 38.) '*c38*)
	X        ((= num 39.) '*c39*)
	X        ((= num 40.) '*c40*)
	X        ((= num 41.) '*c41*)
	X        ((= num 42.) '*c42*)
	X        ((= num 43.) '*c43*)
	X        ((= num 44.) '*c44*)
	X        ((= num 45.) '*c45*)
	X        ((= num 46.) '*c46*)
	X        ((= num 47.) '*c47*)
	X        ((= num 48.) '*c48*)
	X        ((= num 49.) '*c49*)
	X        ((= num 50.) '*c50*)
	X        ((= num 51.) '*c51*)
	X        ((= num 52.) '*c52*)
	X        ((= num 53.) '*c53*)
	X        ((= num 54.) '*c54*)
	X        ((= num 55.) '*c55*)
	X        ((= num 56.) '*c56*)
	X        ((= num 57.) '*c57*)
	X        ((= num 58.) '*c58*)
	X        ((= num 59.) '*c59*)
	X        ((= num 60.) '*c60*)
	X        ((= num 61.) '*c61*)
	X        ((= num 62.) '*c62*)
	X        ((= num 63.) '*c63*)
	X        ((= num 64.) '*c64*)
	X        (t (%error '|condition is too long| (rest-of-ce))))) 
	X
	X
	X;;; Compiling variables
	X;
	X;
	X;
	X; *cur-vars* are the variables in the condition element currently 
	X; being compiled.  *vars* are the variables in the earlier condition
	X; elements.  *ce-vars* are the condition element variables.  note
	X; that the interpreter will not confuse condition element and regular
	X; variables even if they have the same name.
	X;
	X; *cur-vars* is a list of triples: (name predicate subelement-number)
	X; eg:		( (<x> eq 3)
	X;		  (<y> ne 1)
	X;		  . . . )
	X;
	X; *vars* is a list of triples: (name ce-number subelement-number)
	X; eg:		( (<x> 3 3)
	X;		  (<y> 1 1)
	X;		  . . . )
	X;
	X; *ce-vars* is a list of pairs: (name ce-number)
	X; eg:		( (ce1 1)
	X;		  (<c3> 3)
	X;		  . . . )
	X
	X(defun var-dope (var) (assq var *vars*))
	X
	X(defun ce-var-dope (var) (assq var *ce-vars*))
	X
	X(defun cmp-var (test)
	X  (prog (old name)
	X        (setq name (sublex))
	X        (setq old (assq name *cur-vars*))
	X        (cond ((and old (eq (cadr old) 'eq))
	X               (cmp-old-eq-var test old))
	X              ((and old (eq test 'eq)) (cmp-new-eq-var name old))
	X              (t (cmp-new-var name test))))) 
	X
	X(defun cmp-new-var (name test)
	X  (setq *cur-vars* (cons (list name test *subnum*) *cur-vars*))) 
	X
	X(defun cmp-old-eq-var (test old)
	X  (link-new-node (list (concat3 't test 's)
	X                       nil
	X                       (current-field)
	X                       (field-name (caddr old))))) 
	X
	X(defun cmp-new-eq-var (name old)
	X  (prog (pred next)
	X        (setq *cur-vars* (delq old *cur-vars*))
	X        (setq next (assq name *cur-vars*))
	X        (cond (next (cmp-new-eq-var name next))
	X              (t (cmp-new-var name 'eq)))
	X        (setq pred (cadr old))
	X        (link-new-node (list (concat3 't pred 's)
	X                             nil
	X                             (field-name (caddr old))
	X                             (current-field))))) 
	X
	X(defun cmp-cevar nil
	X  (prog (name old)
	X        (setq name (lex))
	X        (setq old (assq name *ce-vars*))
	X        (and old
	X             (%error '|condition element variable used twice| name))
	X        (setq *ce-vars* (cons (list name 0.) *ce-vars*)))) 
	X
	X(defun cmp-not nil (cmp-beta '&not)) 
	X
	X(defun cmp-nobeta nil (cmp-beta nil)) 
	X
	X(defun cmp-and nil (cmp-beta '&and)) 
	X
	X(defun cmp-beta (kind)
	X  (prog (tlist vdope vname vpred vpos old)
	X        (setq tlist nil)
	X   la   (and (atom *cur-vars*) (go lb))
	X        (setq vdope (car *cur-vars*))
	X        (setq *cur-vars* (cdr *cur-vars*))
	X        (setq vname (car vdope))
	X        (setq vpred (cadr vdope))
	X        (setq vpos (caddr vdope))
	X        (setq old (assq vname *vars*))
	X        (cond (old (setq tlist (add-test tlist vdope old)))
	X              ((neq kind '&not) (promote-var vdope)))
	X        (go la)
	X   lb   (and kind (build-beta kind tlist))
	X        (or (eq kind '&not) (fudge))
	X        (setq *last-branch* *last-node*))) 
	X
	X(defun add-test (list new old)
	X  (prog (ttype lloc rloc)
	X	(setq *feature-count* (1+ *feature-count*))
	X        (setq ttype (concat3 't (cadr new) 'b))
	X        (setq rloc (encode-singleton (caddr new)))
	X        (setq lloc (encode-pair (cadr old) (caddr old)))
	X        (return (cons ttype (cons lloc (cons rloc list)))))) 
	X
	X; the following two functions encode indices so that gelm can
	X; decode them as fast as possible
	X
	X(defun encode-pair (a b) (+ (* 10000. (1- a)) (1- b))) 
	X
	X(defun encode-singleton (a) (1- a)) 
	X
	X(defun promote-var (dope)
	X  (prog (vname vpred vpos new)
	X        (setq vname (car dope))
	X        (setq vpred (cadr dope))
	X        (setq vpos (caddr dope))
	X        (or (eq 'eq vpred)
	X            (%error '|illegal predicate for first occurrence|
	X                   (list vname vpred)))
	X        (setq new (list vname 0. vpos))
	X        (setq *vars* (cons new *vars*)))) 
	X
	X(defun fudge nil
	X  (mapc (function fudge*) *vars*)
	X  (mapc (function fudge*) *ce-vars*)) 
	X
	X(defun fudge* (z)
	X  (prog (a) (setq a (cdr z)) (rplaca a (1+ (car a))))) 
	X
	X(defun build-beta (type tests)
	X  (prog (rpred lpred lnode lef)
	X        (link-new-node (list '&mem nil nil (protomem)))
	X        (setq rpred *last-node*)
	X        (cond ((eq type '&and)
	X               (setq lnode (list '&mem nil nil (protomem))))
	X              (t (setq lnode (list '&two nil nil))))
	X        (setq lpred (link-to-branch lnode))
	X        (cond ((eq type '&and) (setq lef lpred))
	X              (t (setq lef (protomem))))
	X        (link-new-beta-node (list type nil lef rpred tests)))) 
	X
	X(defun protomem nil (list nil)) 
	X
	X(defun memory-part (mem-node) (car (cadddr mem-node))) 
	X
	X(defun encode-dope nil
	X  (prog (r all z k)
	X        (setq r nil)
	X        (setq all *vars*)
	X   la   (and (atom all) (return r))
	X        (setq z (car all))
	X        (setq all (cdr all))
	X        (setq k (encode-pair (cadr z) (caddr z)))
	X        (setq r (cons (car z) (cons k r)))
	X        (go la))) 
	X
	X(defun encode-ce-dope nil
	X  (prog (r all z k)
	X        (setq r nil)
	X        (setq all *ce-vars*)
	X   la   (and (atom all) (return r))
	X        (setq z (car all))
	X        (setq all (cdr all))
	X        (setq k (cadr z))
	X        (setq r (cons (car z) (cons k r)))
	X        (go la))) 
	X
	X
	X
	X;;; Linking the nodes
	X
	X(defun link-new-node (r)
	X  (cond ((not (member (car r) '(&p &mem &two &and &not)))
	X	 (setq *feature-count* (1+ *feature-count*))))
	X  (setq *virtual-cnt* (1+ *virtual-cnt*))
	X  (setq *last-node* (link-left *last-node* r))) 
	X
	X(defun link-to-branch (r)
	X  (setq *virtual-cnt* (1+ *virtual-cnt*))
	X  (setq *last-branch* (link-left *last-branch* r))) 
	X
	X(defun link-new-beta-node (r)
	X  (setq *virtual-cnt* (1+ *virtual-cnt*))
	X  (setq *last-node* (link-both *last-branch* *last-node* r))
	X  (setq *last-branch* *last-node*)) 
	X
	X(defun link-left (pred succ)
	X  (prog (a r)
	X        (setq a (left-outs pred))
	X        (setq r (find-equiv-node succ a))
	X        (and r (return r))
	X        (setq *real-cnt* (1+ *real-cnt*))
	X        (attach-left pred succ)
	X        (return succ))) 
	X
	X(defun link-both (left right succ)
	X  (prog (a r)
	X        (setq a (interq (left-outs left) (right-outs right)))
	X        (setq r (find-equiv-beta-node succ a))
	X        (and r (return r))
	X        (setq *real-cnt* (1+ *real-cnt*))
	X        (attach-left left succ)
	X        (attach-right right succ)
	X        (return succ))) 
	X
	X(defun attach-right (old new)
	X  (rplaca (cddr old) (cons new (caddr old)))) 
	X
	X(defun attach-left (old new)
	X  (rplaca (cdr old) (cons new (cadr old)))) 
	X
	X(defun right-outs (node) (caddr node)) 
	X
	X(defun left-outs (node) (cadr node)) 
	X
	X(defun find-equiv-node (node list)
	X  (prog (a)
	X        (setq a list)
	X   l1   (cond ((atom a) (return nil))
	X              ((equiv node (car a)) (return (car a))))
	X        (setq a (cdr a))
	X        (go l1))) 
	X
	X(defun find-equiv-beta-node (node list)
	X  (prog (a)
	X        (setq a list)
	X   l1   (cond ((atom a) (return nil))
	X              ((beta-equiv node (car a)) (return (car a))))
	X        (setq a (cdr a))
	X        (go l1))) 
	X
	X; do not look at the predecessor fields of beta nodes; they have to be
	X; identical because of the way the candidate nodes were found
	X
	X(defun equiv (a b)
	X  (and (eq (car a) (car b))
	X       (or (eq (car a) '&mem)
	X           (eq (car a) '&two)
	X           (equal (caddr a) (caddr b)))
	X       (equal (cdddr a) (cdddr b)))) 
	X
	X(defun beta-equiv (a b)
	X  (and (eq (car a) (car b))
	X       (equal (cddddr a) (cddddr b))
	X       (or (eq (car a) '&and) (equal (caddr a) (caddr b))))) 
	X
	X; the equivalence tests are set up to consider the contents of
	X; node memories, so they are ready for the build action
	X
	X;;; Network interpreter
	X
	X(defun match (flag wme)
	X  (sendto flag (list wme) 'left (list *first-node*)))
	X
	X; note that eval-nodelist is not set up to handle building
	X; productions.  would have to add something like ops4's build-flag
	X
	X(defun eval-nodelist (nl)
	X  (prog nil
	X   top  (and (not nl) (return nil))
	X        (setq *sendtocall* nil)
	X	(setq *last-node* (car nl))
	X        (apply (caar nl) (cdar nl))
	X        (setq nl (cdr nl))
	X        (go top))) 
	X
	X(defun sendto (flag data side nl)
	X  (prog nil
	X   top  (and (not nl) (return nil))
	X        (setq *side* side)
	X        (setq *flag-part* flag)
	X        (setq *data-part* data)
	X        (setq *sendtocall* t)
	X	(setq *last-node* (car nl))
	X        (apply (caar nl) (cdar nl))
	X        (setq nl (cdr nl))
	X        (go top))) 
	X
	X; &bus sets up the registers for the one-input nodes.  note that this
	X(defun &bus (outs)
	X  (prog (dp)
	X        (setq *alpha-flag-part* *flag-part*)
	X        (setq *alpha-data-part* *data-part*)
	X        (setq dp (car *data-part*))
	X        (setq *c1* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c2* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c3* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c4* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c5* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c6* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c7* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c8* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c9* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c10* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c11* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c12* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c13* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c14* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c15* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c16* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c17* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c18* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c19* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c20* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c21* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c22* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c23* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c24* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c25* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c26* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c27* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c28* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c29* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c30* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c31* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c32* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c33* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c34* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c35* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c36* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c37* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c38* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c39* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c40* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c41* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c42* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c43* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c44* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c45* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c46* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c47* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c48* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c49* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c50* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c51* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c52* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c53* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c54* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c55* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c56* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c57* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c58* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c59* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c60* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c61* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c62* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c63* (car dp))
	X        (setq dp (cdr dp))
	X        (setq *c64* (car dp))
	X        (eval-nodelist outs))) 
	X
	X(defun &any (outs register const-list)
	X  (prog (z c)
	X        (setq z (fast-symeval register))
	X        (cond ((numberp z) (go number)))
	X   symbol (cond ((null const-list) (return nil))
	X                ((eq (car const-list) z) (go ok))
	X                (t (setq const-list (cdr const-list)) (go symbol)))
	X   number (cond ((null const-list) (return nil))
	X                ((and (numberp (setq c (car const-list)))
	X                      (=alg c 

turner@imagen.UUCP (D'arc Angel) (01/19/87)

	X        (setq tlist (cdr tlist))
	X        (setq lind (car tlist))
	X        (setq tlist (cdr tlist))
	X        (setq rind (car tlist))
	X        (setq tlist (cdr tlist))
	X        (comment the next line differs in not-left & -right)
	X        (setq res (funcall tst (gelm dp rind) (gelm memdp lind)))
	X        (cond (res (go tloop))
	X              (t (setq mem (cddr mem)) (go fail)))
	X   succ (setq newc (+ inc newc))
	X        (rplaca (cdr mem) newc)
	X        (cond ((or (and (== inc -1.) (== newc 0.))
	X                   (and (== inc 1.) (== newc 1.)))
	X               (sendto newfp memdp 'right outs)))
	X        (setq mem (cddr mem))
	X        (go fail))) 
	X
	X
	X
	X;;; Node memories
	X
	X
	X(defun add-token (memlis flag data-part num)
	X  (prog (was-present)
	X        (cond ((eq flag 'new)
	X               (setq was-present nil)
	X               (real-add-token memlis data-part num))
	X              ((not flag) 
	X	       (setq was-present (remove-old memlis data-part num)))
	X              ((eq flag 'old) (setq was-present t)))
	X        (return was-present))) 
	X
	X(defun real-add-token (lis data-part num)
	X  (setq *current-token* (1+ *current-token*))
	X  (cond (num (rplaca lis (cons num (car lis)))))
	X  (rplaca lis (cons data-part (car lis)))) 
	X
	X(defun remove-old (lis data num)
	X  (cond (num (remove-old-num lis data))
	X        (t (remove-old-no-num lis data)))) 
	X
	X(defun remove-old-num (lis data)
	X  (prog (m next last)
	X        (setq m (car lis))
	X        (cond ((atom m) (return nil))
	X              ((top-levels-eq data (car m))
	X               (setq *current-token* (1- *current-token*))
	X               (rplaca lis (cddr m))
	X               (return (car m))))
	X        (setq next m)
	X   loop (setq last next)
	X        (setq next (cddr next))
	X        (cond ((atom next) (return nil))
	X              ((top-levels-eq data (car next))
	X               (rplacd (cdr last) (cddr next))
	X               (setq *current-token* (1- *current-token*))
	X               (return (car next)))
	X              (t (go loop))))) 
	X
	X(defun remove-old-no-num (lis data)
	X  (prog (m next last)
	X        (setq m (car lis))
	X        (cond ((atom m) (return nil))
	X              ((top-levels-eq data (car m))
	X               (setq *current-token* (1- *current-token*))
	X               (rplaca lis (cdr m))
	X               (return (car m))))
	X        (setq next m)
	X   loop (setq last next)
	X        (setq next (cdr next))
	X        (cond ((atom next) (return nil))
	X              ((top-levels-eq data (car next))
	X               (rplacd last (cdr next))
	X               (setq *current-token* (1- *current-token*))
	X               (return (car next)))
	X              (t (go loop))))) 
	X
	X
	X
	X;;; Conflict Resolution
	X;
	X;
	X; each conflict set element is a list of the following form:
	X; ((p-name . data-part) (sorted wm-recency) special-case-number)
	X
	X(defun removecs (name data)
	X  (prog (cr-data inst cs)
	X        (setq cr-data (cons name data))
	X	(setq cs *conflict-set*)
	X loop1	(cond ((null cs) 
	X               (record-refract name data)
	X               (return nil)))
	X	(setq inst (car cs))
	X	(setq cs (cdr cs))
	X	(and (not (top-levels-eq (car inst) cr-data)) (go loop1))
	X        (setq *conflict-set* (delq inst *conflict-set*))))
	X
	X(defun insertcs (name data rating)
	X  (prog (instan)
	X    (and (refracted name data) (return nil))
	X    (setq instan (list (cons name data) (order-tags data) rating))
	X    (and (atom *conflict-set*) (setq *conflict-set* nil))
	X    (return (setq *conflict-set* (cons instan *conflict-set*))))) 
	X
	X(defun order-tags (dat)
	X  (prog (tags)
	X        (setq tags nil)
	X   l1  (and (atom dat) (go l2))
	X        (setq tags (cons (creation-time (car dat)) tags))
	X        (setq dat (cdr dat))
	X        (go l1)
	X   l2  (cond ((eq *strategy* 'mea)
	X               (return (cons (car tags) (dsort (cdr tags)))))
	X              (t (return (dsort tags)))))) 
	X
	X; destructively sort x into descending order
	X
	X(defun dsort (x)
	X  (prog (sorted cur next cval nval)
	X        (and (atom (cdr x)) (return x))
	X   loop (setq sorted t)
	X        (setq cur x)
	X        (setq next (cdr x))
	X   chek (setq cval (car cur))
	X        (setq nval (car next))
	X        (cond ((> nval cval)
	X               (setq sorted nil)
	X               (rplaca cur nval)
	X               (rplaca next cval)))
	X        (setq cur next)
	X        (setq next (cdr cur))
	X        (cond ((not (null next)) (go chek))
	X              (sorted (return x))
	X              (t (go loop))))) 
	X
	X(defun conflict-resolution nil
	X  (prog (best len)
	X        (setq len (length *conflict-set*))
	X        (cond ((> len *max-cs*) (setq *max-cs* len)))
	X        (setq *total-cs* (+ *total-cs* len))
	X        (cond (*conflict-set*
	X               (setq best (best-of *conflict-set*))
	X               (setq *conflict-set* (delq best *conflict-set*))
	X               (return (pname-instantiation best)))
	X              (t (return nil))))) 
	X
	X(defun best-of (set) (best-of* (car set) (cdr set))) 
	X
	X(defun best-of* (best rem)
	X  (cond ((not rem) best)
	X        ((conflict-set-compare best (car rem))
	X         (best-of* best (cdr rem)))
	X        (t (best-of* (car rem) (cdr rem))))) 
	X
	X(defun remove-from-conflict-set (name)
	X  (prog (cs entry)
	X   l1   (setq cs *conflict-set*)
	X   l2   (cond ((atom cs) (return nil)))
	X        (setq entry (car cs))
	X        (setq cs (cdr cs))
	X        (cond ((eq name (caar entry))
	X               (setq *conflict-set* (delq entry *conflict-set*))
	X               (go l1))
	X              (t (go l2))))) 
	X
	X(defun pname-instantiation (conflict-elem) (car conflict-elem)) 
	X
	X(defun order-part (conflict-elem) (cdr conflict-elem)) 
	X
	X(defun instantiation (conflict-elem)
	X  (cdr (pname-instantiation conflict-elem))) 
	X
	X
	X(defun conflict-set-compare (x y)
	X  (prog (x-order y-order xl yl xv yv)
	X        (setq x-order (order-part x))
	X        (setq y-order (order-part y))
	X        (setq xl (car x-order))
	X        (setq yl (car y-order))
	X   data (cond ((and (null xl) (null yl)) (go ps))
	X              ((null yl) (return t))
	X              ((null xl) (return nil)))
	X        (setq xv (car xl))
	X        (setq yv (car yl))
	X        (cond ((> xv yv) (return t))
	X              ((> yv xv) (return nil)))
	X        (setq xl (cdr xl))
	X        (setq yl (cdr yl))
	X        (go data)
	X   ps   (setq xl (cdr x-order))
	X        (setq yl (cdr y-order))
	X   psl  (cond ((null xl) (return t)))
	X        (setq xv (car xl))
	X        (setq yv (car yl))
	X        (cond ((> xv yv) (return t))
	X              ((> yv xv) (return nil)))
	X        (setq xl (cdr xl))
	X        (setq yl (cdr yl))
	X        (go psl))) 
	X
	X
	X(defun conflict-set nil
	X  (prog (cnts cs p z best)
	X        (setq cnts nil)
	X        (setq cs *conflict-set*)
	X   l1  (and (atom cs) (go l2))
	X        (setq p (caaar cs))
	X        (setq cs (cdr cs))
	X        (setq z (assq p cnts))
	X        (cond ((null z) (setq cnts (cons (cons p 1.) cnts)))
	X              (t (rplacd z (1+ (cdr z)))))
	X        (go l1)
	X   l2  (cond ((atom cnts)
	X               (setq best (best-of *conflict-set*))
	X               (terpri)
	X               (return (list (caar best) 'dominates))))
	X        (terpri)
	X        (princ (caar cnts))
	X        (cond ((> (cdar cnts) 1.)
	X               (princ '|	(|)
	X               (princ (cdar cnts))
	X               (princ '| occurrences)|)))
	X        (setq cnts (cdr cnts))
	X        (go l2))) 
	X	
	X
	X
	X;;; WM maintaining functions
	X;
	X; The order of operations in the following two functions is critical.
	X; add-to-wm order: (1) change wm (2) record change (3) match 
	X; remove-from-wm order: (1) record change (2) match (3) change wm
	X; (back will not restore state properly unless wm changes are recorded
	X; before the cs changes that they cause)  (match will give errors if 
	X; the thing matched is not in wm at the time)
	X
	X
	X(defun add-to-wm (wme override)
	X  (prog (fa z part timetag port)
	X    (setq *critical* t)
	X    (setq *current-wm* (1+ *current-wm*))
	X    (and (> *current-wm* *max-wm*) (setq *max-wm* *current-wm*))
	X    (setq *action-count* (1+ *action-count*))
	X    (setq fa (wm-hash wme))
	X    (or (memq fa *wmpart-list*)
	X        (setq *wmpart-list* (cons fa *wmpart-list*)))
	X    (setq part (get fa 'wmpart*))
	X    (cond (override (setq timetag override))
	X          (t (setq timetag *action-count*)))
	X    (setq z (cons wme timetag))
	X    (putprop fa (cons z part) 'wmpart*)
	X    (record-change '=>wm *action-count* wme)
	X    (match 'new wme)
	X    (setq *critical* nil)
	X    (cond ((and *in-rhs* *wtrace*)
	X           (setq port (trace-file))
	X           (terpri port)
	X           (princ '|=>wm: | port)
	X           (ppelm wme port)))
	X    (and *in-rhs* *mtrace* (setq *madeby* 
	X                                 (cons (cons wme *p-name*) *madeby*))))) 
	X
	X; remove-from-wm uses eq, not equal to determine if wme is present
	X
	X(defun remove-from-wm (wme)
	X  (prog (fa z part timetag port)
	X    (setq fa (wm-hash wme))
	X    (setq part (get fa 'wmpart*))
	X    (setq z (assq wme part))
	X    (or z (return nil))
	X    (setq timetag (cdr z))
	X    (cond ((and *wtrace* *in-rhs*)
	X           (setq port (trace-file))
	X           (terpri port)
	X           (princ '|<=wm: | port)
	X           (ppelm wme port)))
	X    (setq *action-count* (1+ *action-count*))
	X    (setq *critical* t)
	X    (setq *current-wm* (1- *current-wm*))
	X    (record-change '<=wm timetag wme)
	X    (match nil wme)
	X    (putprop fa (delq z part) 'wmpart* )
	X    (setq *critical* nil))) 
	X
	X; mapwm maps down the elements of wm, applying fn to each element
	X; each element is of form (datum . creation-time)
	X
	X(defun mapwm (fn)
	X  (prog (wmpl part)
	X        (setq wmpl *wmpart-list*)
	X   lab1 (cond ((atom wmpl) (return nil)))
	X        (setq part (get (car wmpl) 'wmpart*))
	X        (setq wmpl (cdr wmpl))
	X        (mapc fn part)
	X        (go lab1))) 
	X
	X(defun wm (&quote &rest a) 
	X  (mapc (function (lambda (z) (terpri) (ppelm z t))) 
	X	(get-wm a))
	X  nil) 
	X
	X(defun get-wm (z)
	X  (setq *wm-filter* z)
	X  (setq *wm* nil)
	X  (mapwm (function get-wm2))
	X  (prog2 nil *wm* (setq *wm* nil))) 
	X
	X(defun get-wm2 (elem) 
	X (cond ((or (null *wm-filter*) (member (cdr elem) *wm-filter*))
	X	(setq *wm* (cons (car elem) *wm*)))))
	X
	X(defun wm-hash (x)
	X  (cond ((not x) '<default>)
	X        ((not (car x)) (wm-hash (cdr x)))
	X        ((symbolp (car x)) (car x))
	X        (t (wm-hash (cdr x))))) 
	X
	X(defun creation-time (wme)
	X  (cdr (assq wme (get (wm-hash wme) 'wmpart*)))) 
	X
	X(defun rehearse nil
	X  (prog nil
	X    (setq *old-wm* nil)
	X    (mapwm (function refresh-collect))
	X    (mapc (function refresh-del) *old-wm*)
	X    (mapc (function refresh-add) *old-wm*)
	X    (setq *old-wm* nil))) 
	X
	X(defun refresh-collect (x) (setq *old-wm* (cons x *old-wm*))) 
	X
	X(defun refresh-del (x) (remove-from-wm (car x))) 
	X
	X(defun refresh-add (x) (add-to-wm (car x) (cdr x))) 
	X
	X(defun trace-file ()
	X  (prog (port)
	X        (setq port t)
	X	(cond (*trace-file*
	X	       (setq port ($ofile *trace-file*))
	X	       (cond ((null port)
	X	              (%warn '|trace: file has been closed| *trace-file*)
	X		      (setq port t)))))
	X        (return port)))
	X
	X
	X;;; Basic functions for RHS evaluation
	X
	X(defun eval-rhs (pname data)
	X  (prog (node port)
	X    (cond (*ptrace*
	X           (setq port (trace-file))
	X           (terpri port)
	X           (princ *cycle-count* port)
	X           (princ '|. | port)
	X           (princ pname port)
	X           (time-tag-print data port)))
	X    (setq *data-matched* data)
	X    (setq *p-name* pname)
	X    (setq *last* nil)
	X    (setq node (get pname 'topnode))
	X    (init-var-mem (var-part node))
	X    (init-ce-var-mem (ce-var-part node))
	X    (begin-record pname data)
	X    (setq *in-rhs* t)
	X    (eval (rhs-part node))
	X    (setq *in-rhs* nil)
	X    (end-record))) 
	X
	X(defun time-tag-print (data port)
	X  (cond ((not (null data))
	X         (time-tag-print (cdr data) port)
	X         (princ '| | port)
	X         (princ (creation-time (car data)) port))))
	X
	X(defun init-var-mem (vlist)
	X  (prog (v ind r)
	X        (setq *variable-memory* nil)
	X   top  (and (atom vlist) (return nil))
	X        (setq v (car vlist))
	X        (setq ind (cadr vlist))
	X        (setq vlist (cddr vlist))
	X        (setq r (gelm *data-matched* ind))
	X        (setq *variable-memory* (cons (cons v r) *variable-memory*))
	X        (go top))) 
	X
	X(defun init-ce-var-mem (vlist)
	X  (prog (v ind r)
	X        (setq *ce-variable-memory* nil)
	X   top  (and (atom vlist) (return nil))
	X        (setq v (car vlist))
	X        (setq ind (cadr vlist))
	X        (setq vlist (cddr vlist))
	X        (setq r (ce-gelm *data-matched* ind))
	X        (setq *ce-variable-memory*
	X              (cons (cons v r) *ce-variable-memory*))
	X        (go top))) 
	X
	X(defun make-ce-var-bind (var elem)
	X  (setq *ce-variable-memory*
	X        (cons (cons var elem) *ce-variable-memory*))) 
	X
	X(defun make-var-bind (var elem)
	X  (setq *variable-memory* (cons (cons var elem) *variable-memory*))) 
	X
	X(defun $varbind (x)
	X  (prog (r)
	X	(and (not *in-rhs*) (return x))
	X        (setq r (assq x *variable-memory*))
	X        (cond (r (return (cdr r)))
	X              (t (return x))))) 
	X
	X(defun get-ce-var-bind (x)
	X  (prog (r)
	X        (cond ((numberp x) (return (get-num-ce x))))
	X        (setq r (assq x *ce-variable-memory*))
	X        (cond (r (return (cdr r)))
	X              (t (return nil))))) 
	X
	X(defun get-num-ce (x)
	X  (prog (r l d)
	X        (setq r *data-matched*)
	X        (setq l (length r))
	X        (setq d (- l x))
	X        (and (> 0. d) (return nil))
	X   la   (cond ((null r) (return nil))
	X              ((> 1. d) (return (car r))))
	X        (setq d (1- d))
	X        (setq r (cdr r))
	X        (go la))) 
	X
	X
	X(defun build-collect (z)
	X  (prog (r)
	X   la   (and (atom z) (return nil))
	X        (setq r (car z))
	X        (setq z (cdr z))
	X        (cond ((and r (listp r))
	X               ($value '\()
	X               (build-collect r)
	X               ($value '\)))
	X              ((eq r '\\) ($change (car z)) (setq z (cdr z)))
	X              (t ($value r)))
	X        (go la))) 
	X
	X(defun unflat (x) (setq *rest* x) (unflat*)) 
	X
	X(defun unflat* nil
	X  (prog (c)
	X        (cond ((atom *rest*) (return nil)))
	X        (setq c (car *rest*))
	X        (setq *rest* (cdr *rest*))
	X        (cond ((eq c '\() (return (cons (unflat*) (unflat*))))
	X              ((eq c '\)) (return nil))
	X              (t (return (cons c (unflat*))))))) 
	X
	X
	X(defun $change (x)
	X  (prog nil
	X        (cond ((and x (listp x)) (eval-function x)) ;modified to check for nil
	X              (t ($value ($varbind x)))))) 
	X
	X(defun eval-args (z)
	X  (prog (r)
	X        (rhs-tab 1.)
	X   la   (and (atom z) (return nil))
	X        (setq r (car z))
	X        (setq z (cdr z))
	X        (cond ((eq r #\^)
	X               (rhs-tab (car z))
	X               (setq r (cadr z))
	X               (setq z (cddr z))))
	X        (cond ((eq r '//) ($value (car z)) (setq z (cdr z)))
	X              (t ($change r)))
	X        (go la))) 
	X
	X
	X(defun eval-function (form)
	X  (cond ((not *in-rhs*)
	X	 (%warn '|functions cannot be used at top level| (car form)))
	X	(t (eval form))))
	X
	X
	X;;; Functions to manipulate the result array
	X
	X
	X(defun $reset nil
	X  (setq *max-index* 0)
	X  (setq *next-index* 1)) 
	X
	X; rhs-tab implements the tab ('^') function in the rhs.  it has
	X; four responsibilities:
	X;	- to move the array pointers
	X;	- to watch for tabbing off the left end of the array
	X;	  (ie, to watch for pointers less than 1)
	X;	- to watch for tabbing off the right end of the array
	X;	- to write nil in all the slots that are skipped
	X; the last is necessary if the result array is not to be cleared
	X; after each use; if rhs-tab did not do this, $reset
	X; would be much slower.
	X
	X(defun rhs-tab (z) ($tab ($varbind z)))
	X
	X(defun $tab (z)
	X  (prog (edge next)
	X        (setq next ($litbind z))
	X        (and (floatp next) (setq next (fix next)))
	X        (cond ((or (not (numberp next)) 
	X		   (> next *size-result-array*)
	X		   (> 1. next))
	X               (%warn '|illegal index after ^| next)
	X               (return *next-index*)))
	X        (setq edge (- next 1.))
	X        (cond ((> *max-index* edge) (go ok)))
	X   clear (cond ((== *max-index* edge) (go ok)))
	X        (putvector *result-array* edge nil)
	X        (setq edge (1- edge))
	X        (go clear)
	X   ok   (setq *next-index* next)
	X        (return next))) 
	X
	X(defun $value (v)
	X  (cond ((> *next-index* *size-result-array*)
	X         (%warn '|index too large| *next-index*))
	X        (t
	X         (and (> *next-index* *max-index*)
	X              (setq *max-index* *next-index*))
	X         (putvector *result-array* *next-index* v)
	X         (setq *next-index* (1+ *next-index*))))) 
	X
	X(defun use-result-array nil
	X  (prog (k r)
	X        (setq k *max-index*)
	X        (setq r nil)
	X   top  (and (== k 0.) (return r))
	X        (setq r (cons (getvector *result-array* k) r))
	X        (setq k (1- k))
	X        (go top))) 
	X
	X(defun $assert nil
	X  (setq *last* (use-result-array))
	X  (add-to-wm *last* nil))
	X
	X(defun $parametercount nil *max-index*)
	X
	X(defun $parameter (k)
	X  (cond ((or (not (numberp k)) (> k *size-result-array*) (< k 1.))
	X	 (%warn '|illegal parameter number | k)
	X         nil)
	X        ((> k *max-index*) nil)
	X	(t (getvector *result-array* k))))
	X
	X
	X;;; RHS actions
	X
	X(defun make (&quote &rest z)
	X  (prog nil
	X        ($reset)
	X        (eval-args z)
	X        ($assert))) 
	X
	X(defun modify (&quote &rest z)
	X  (prog (old)
	X	(cond ((not *in-rhs*)
	X	       (%warn '|cannot be called at top level| 'modify)
	X	       (return nil)))
	X        (setq old (get-ce-var-bind (car z)))
	X        (cond ((null old)
	X               (%warn '|modify: first argument must be an element variable|
	X                        (car z))
	X               (return nil)))
	X        (remove-from-wm old)
	X        (setq z (cdr z))
	X        ($reset)
	X   copy (and (atom old) (go fin))
	X        ($change (car old))
	X        (setq old (cdr old))
	X        (go copy)
	X   fin  (eval-args z)
	X        ($assert))) 
	X
	X(defun bind (&quote &rest z)
	X  (prog (val)
	X	(cond ((not *in-rhs*)
	X	       (%warn '|cannot be called at top level| 'bind)
	X	       (return nil)))
	X    (cond ((< (length z) 1.)
	X           (%warn '|bind: wrong number of arguments to| z)
	X           (return nil))
	X          ((not (symbolp (car z)))
	X           (%warn '|bind: illegal argument| (car z))
	X           (return nil))
	X          ((= (length z) 1.) (setq val (gensym)))
	X          (t ($reset)
	X             (eval-args (cdr z))
	X             (setq val ($parameter 1.))))
	X    (make-var-bind (car z) val))) 
	X
	X(defun cbind (&quote &rest z)
	X  (cond ((not *in-rhs*)
	X	 (%warn '|cannot be called at top level| 'cbind))
	X	((not (= (length z) 1.))
	X	 (%warn '|cbind: wrong number of arguments| z))
	X	((not (symbolp (car z)))
	X	 (%warn '|cbind: illegal argument| (car z)))
	X	((null *last*)
	X	 (%warn '|cbind: nothing added yet| (car z)))
	X	(t (make-ce-var-bind (car z) *last*)))) 
	X
	X(defun oremove (&quote &rest z)
	X  (prog (old)
	X	(and (not *in-rhs*)(return (top-level-remove z)))
	X   top  (and (atom z) (return nil))
	X        (setq old (get-ce-var-bind (car z)))
	X        (cond ((null old)
	X               (%warn '|remove: argument not an element variable| (car z))
	X               (return nil)))
	X        (remove-from-wm old)
	X        (setq z (cdr z))
	X        (go top))) 
	X
	X(defun ocall (&quote &rest z)
	X  (prog (f)
	X	(setq f (car z))
	X        ($reset)
	X        (eval-args (cdr z))
	X        (funcall f))) 
	X
	X(defun owrite (&quote &rest z)
	X  (prog (port max k x needspace)
	X	(cond ((not *in-rhs*)
	X	       (%warn '|cannot be called at top level| 'write)
	X	       (return nil)))
	X	($reset)
	X	(eval-args z)
	X	(setq k 1.)
	X	(setq max ($parametercount))
	X	(cond ((< max 1.)
	X	       (%warn '|write: nothing to print| z)
	X	       (return nil)))
	X	(setq port (default-write-file))
	X	(setq x ($parameter 1.))
	X	(cond ((and (symbolp x) ($ofile x)) 
	X	       (setq port ($ofile x))
	X	       (setq k 2.)))
	X        (setq needspace t)
	X   la   (and (> k max) (return nil))
	X	(setq x ($parameter k))
	X	(cond ((eq x '|=== C R L F ===|)
	X	       (setq needspace nil)
	X               (terpri port))
	X              ((eq x '|=== R J U S T ===|)
	X	       (setq k (+ 2 k))
	X	       (do-rjust ($parameter (1- k)) ($parameter k) port))
	X	      ((eq x '|=== T A B T O ===|)
	X	       (setq needspace nil)
	X	       (setq k (1+ k))
	X	       (do-tabto ($parameter k) port))
	X	      (t 
	X	       (and needspace (princ '| | port))
	X	       (setq needspace t)
	X	       (princ x port)))
	X	(setq k (1+ k))
	X	(go la))) 
	X	
	X(defun default-write-file ()
	X  (prog (port)
	X	(setq port t)
	X	(cond (*write-file*
	X	       (setq port ($ofile *write-file*))
	X	       (cond ((null port) 
	X		      (%warn '|write: file has been closed| *write-file*)
	X		      (setq port t)))))
	X        (return port)))
	X
	X                                                                                                                                                                                                         
	X(defun do-rjust (width value port)
	X  (prog (size)
	X	(cond ((eq value '|=== T A B T O ===|)
	X	       (%warn '|rjust cannot precede this function| 'tabto)
	X               (return nil))
	X	      ((eq value '|=== C R L F ===|)
	X	       (%warn '|rjust cannot precede this function| 'crlf)
	X               (return nil))
	X	      ((eq value '|=== R J U S T ===|)
	X	       (%warn '|rjust cannot precede this function| 'rjust)
	X               (return nil)))
	X        (setq size (flatc value ))
	X	(cond ((> size width)
	X	       (princ '| | port)
	X	       (princ value port)
	X	       (return nil)))
	X        (do k (- width size) (1- k) (not (> k 0)) (princ '| | port))
	X	(princ value port)))
	X
	X(defun do-tabto (col port)
	X  (eval `(format ,port (concatenate 'string "~" (princ-to-string ,col) "T"))))
	X
	X;  (prog (pos)
	X;	(setq pos (1+ (nwritn port)))
	X;	(cond ((> pos col)
	X;	       (terpri port)
	X;	       (setq pos 1)))
	X;	(do k (- col pos) (1- k) (not (> k 0)) (princ '| | port))
	X;	(return nil)))
	X
	X
	X(defun halt nil 
	X  (cond ((not *in-rhs*)
	X	 (%warn '|cannot be called at top level| 'halt))
	X	(t (setq *halt-flag* t)))) 
	X
	X(defun build (&quote &rest z)
	X  (prog (r)
	X	(cond ((not *in-rhs*)
	X	       (%warn '|cannot be called at top level| 'build)
	X	       (return nil)))
	X        ($reset)
	X        (build-collect z)
	X        (setq r (unflat (use-result-array)))
	X        (and *build-trace* (funcall *build-trace* r))
	X        (compile-production (car r) (cdr r)))) 
	X
	X(defun infile(file)
	X    (open file :direction :input))
	X
	X(defun outfile (file)
	X    (open file :direction :output))
	X
	X(defun openfile (&quote &rest z)
	X  (prog (file mode id)
	X	($reset)
	X	(eval-args z)
	X	(cond ((not (equal ($parametercount) 3.))
	X	       (%warn '|openfile: wrong number of arguments| z)
	X	       (return nil)))
	X	(setq id ($parameter 1))
	X	(setq file ($parameter 2))
	X	(setq mode ($parameter 3))
	X	(cond ((not (symbolp id))
	X	       (%warn '|openfile: file id must be a symbolic atom| id)
	X	       (return nil))
	X              ((null id)
	X               (%warn '|openfile: 'nil' is reserved for the terminal| nil)
	X               (return nil))
	X	      ((or ($ifile id)($ofile id))
	X	       (%warn '|openfile: name already in use| id)
	X	       (return nil)))
	X	(cond ((eq mode 'in) (putprop id  (infile file) 'inputfile))
	X	      ((eq mode 'out) (putprop id  (outfile file) 'outputfile))
	X	      (t (%warn '|openfile: illegal mode| mode)
	X		 (return nil)))
	X	(return nil)))
	X
	X(defun $ifile (x) 
	X  (cond ((and x (symbolp x)) (get x 'inputfile))
	X        (t *standard-input*)))
	X 
	X(defun $ofile (x) 
	X  (cond ((and x (symbolp x)) (get x 'outputfile))
	X        (t *standard-output*)))
	X
	X
	X(defun closefile (&quote &rest z)
	X  ($reset)
	X  (eval-args z)
	X  (mapc (function closefile2) (use-result-array)))
	X
	X(defun closefile2 (file)
	X  (prog (port)
	X	(cond ((not (symbolp file))
	X	       (%warn '|closefile: illegal file identifier| file))
	X	      ((setq port ($ifile file))
	X	       (close port)
	X	       (remprop file 'inputfile))
	X	      ((setq port ($ofile file))
	X	       (close port)
	X	       (remprop file 'outputfile)))
	X	(return nil)))
	X
	X(defun default (&quote &rest z)
	X  (prog (file use)
	X	($reset)
	X	(eval-args z)
	X	(cond ((not (equal ($parametercount) 2.))
	X	       (%warn '|default: wrong number of arguments| z)
	X	       (return nil)))
	X	(setq file ($parameter 1))
	X	(setq use ($parameter 2))
	X	(cond ((not (symbolp file))
	X	       (%warn '|default: illegal file identifier| file)
	X	       (return nil))
	X	      ((not (memq use '(write accept trace)))
	X	       (%warn '|default: illegal use for a file| use)
	X	       (return nil))
	X	      ((and (memq use '(write trace)) 
	X		    (not (null file))
	X		    (not ($ofile file)))
	X	       (%warn '|default: file has not been opened for output| file)
	X	       (return nil))
	X	      ((and (eq use 'accept) 
	X		    (not (null file))
	X		    (not ($ifile file)))
	X	       (%warn '|default: file has not been opened for input| file)
	X	       (return nil))
	X	      ((eq use 'write) (setq *write-file* file))
	X	      ((eq use 'accept) (setq *accept-file* file))
	X	      ((eq use 'trace) (setq *trace-file* file)))
	X	(return nil)))
	X
	X
	X
	X;;; RHS Functions
	X
	X(defun accept (&quote &rest z)
	X  (prog (port arg)
	X	(cond ((> (length z) 1.)
	X	       (%warn '|accept: wrong number of arguments| z)
	X	       (return nil)))
	X	(setq port t)
	X	(cond (*accept-file*
	X	       (setq port ($ifile *accept-file*))
	X	       (cond ((null port) 
	X		      (%warn '|accept: file has been closed| *accept-file*)
	X		      (return nil)))))
	X	(cond ((= (length z) 1)
	X	       (setq arg ($varbind (car z)))
	X	       (cond ((not (symbolp arg))
	X	              (%warn '|accept: illegal file name| arg)
	X		      (return nil)))
	X	       (setq port ($ifile arg))
	X	       (cond ((null port) 
	X		      (%warn '|accept: file not open for input| arg)
	X		      (return nil)))))
	X        (cond ((= (tyipeek port) -1.)
	X	       ($value 'end-of-file)
	X	       (return nil)))
	X	(flat-value (read port)))) 
	X
	X(defun flat-value (x)
	X  (cond ((atom x) ($value x))
	X        (t (mapc (function flat-value) x)))) 
	X
	X(defun span-chars (x prt)
	X  (do ch (tyipeek prt) (tyipeek prt) (not (member ch x #'char-equal)) (read-char prt)))
	X
	X(defun acceptline (&quote &rest z)
	X  (prog ( def arg port)
	X	(setq port t)
	X	(setq def z)
	X	(cond (*accept-file*
	X	       (setq port ($ifile *accept-file*))
	X	       (cond ((null port) 
	X		      (%warn '|acceptline: file has been closed| 
	X		             *accept-file*)
	X		      (return nil)))))
	X	(cond ((> (length def) 0)
	X	       (setq arg ($varbind (car def)))
	X	       (cond ((and (symbolp arg) ($ifile arg))
	X	              (setq port ($ifile arg))
	X		      (setq def (cdr def))))))
	X        (span-chars '(9. 41.) port)
	X	(cond ((memq (tyipeek port) '(-1. 10.))
	X	       (mapc (function $change) def)
	X	       (return nil)))
	X   lp1	(flat-value (read port))
	X        (span-chars '(9. 41.) port)
	X	(cond ((not (memq (tyipeek port) '(-1. 10.))) (go lp1)))))
	X
	X(defun substr (&quote &rest l)
	X  (prog (k elm start end)
	X        (cond ((not (= (length l) 3.))
	X               (%warn '|substr: wrong number of arguments| l)
	X               (return nil)))
	X        (setq elm (get-ce-var-bind (car l)))
	X        (cond ((null elm)
	X               (%warn '|first argument to substr must be a ce var|
	X                        l)
	X               (return nil)))
	X        (setq start ($varbind (cadr l)))
	X	(setq start ($litbind start))
	X        (cond ((not (numberp start))
	X               (%warn '|second argument to substr must be a number|
	X                        l)
	X               (return nil)))
	X	(comment |if a variable is bound to INF, the following|
	X		 |will get the binding and treat it as INF is|
	X		 |always treated.  that may not be good|)
	X        (setq end ($varbind (caddr l)))
	X        (cond ((eq end 'inf) (setq end (length elm))))
	X	(setq end ($litbind end))
	X        (cond ((not (numberp end))
	X               (%warn '|third argument to substr must be a number|
	X                        l)
	X               (return nil)))
	X        (comment |this loop does not check for the end of elm|
	X                 |instead it relies on cdr of nil being nil|
	X                 |this may not work in all versions of lisp|)
	X        (setq k 1.)
	X   la   (cond ((> k end) (return nil))
	X              ((not (< k start)) ($value (car elm))))
	X        (setq elm (cdr elm))
	X        (setq k (1+ k))
	X        (go la))) 
	X
	X
	X(defun compute (&quote &rest z) ($value (ari z))) 
	X
	X; arith is the obsolete form of compute
	X(defun arith (&quote &rest z) ($value (ari z))) 
	X
	X(defun ari (x)
	X  (cond ((atom x)
	X         (%warn '|bad syntax in arithmetic expression | x)
	X	 0.)
	X        ((atom (cdr x)) (ari-unit (car x)))
	X        ((eq (cadr x) '+)
	X         (plus (ari-unit (car x)) (ari (cddr x))))
	X        ((eq (cadr x) '-)
	X         (difference (ari-unit (car x)) (ari (cddr x))))
	X        ((eq (cadr x) '*)
	X         (times (ari-unit (car x)) (ari (cddr x))))
	X        ((eq (cadr x) '//)
	X         (quotient (ari-unit (car x)) (ari (cddr x))))
	X        ((eq (cadr x) '\\)
	X         (mod (fix (ari-unit (car x))) (fix (ari (cddr x)))))
	X        (t (%warn '|bad syntax in arithmetic expression | x) 0.))) 
	X
	X(defun ari-unit (a)
	X  (prog (r)
	X        (cond ((listp a) (setq r (ari a)))
	X              (t (setq r ($varbind a))))
	X        (cond ((not (numberp r))
	X               (%warn '|bad value in arithmetic expression| a)
	X               (return 0.))
	X              (t (return r))))) 
	X
	X(defun genatom nil ($value (gensym))) 
	X
	X(defun litval (&quote &rest z)
	X  (prog (r)
	X	(cond ((not (= (length z) 1.))
	X	       (%warn '|litval: wrong number of arguments| z)
	X	       ($value 0) 
	X	       (return nil))
	X	      ((numberp (car z)) ($value (car z)) (return nil)))
	X	(setq r ($litbind ($varbind (car z))))
	X	(cond ((numberp r) ($value r) (return nil)))
	X	(%warn '|litval: argument has no literal binding| (car z))
	X	($value 0)))
	X
	X
	X(defun rjust (&quote &rest z)
	X  (prog (val)
	X        (cond ((not (= (length z) 1.))
	X	       (%warn '|rjust: wrong number of arguments| z)
	X               (return nil)))
	X        (setq val ($varbind (car z)))
	X	(cond ((or (not (numberp val)) (< val 1.) (> val 127.))
	X	       (%warn '|rjust: illegal value for field width| val)
	X	       (return nil)))
	X        ($value '|=== R J U S T ===|)
	X	($value val)))
	X
	X(defun crlf (&quote &optional z)
	X        (cond  (z (%warn '|crlf: does not take arguments| z))
	X	       (t ($value '|=== C R L F ===|))))
	X
	X(defun tabto (&quote &rest z)
	X  (prog (val)
	X        (cond ((not (= (length z) 1.))
	X	       (%warn '|tabto: wrong number of arguments| z)
	X	       (return nil)))
	X        (setq val ($varbind (car z)))
	X	(cond ((or (not (numberp val)) (< val 1.) (> val 127.))
	X	       (%warn '|tabto: illegal column number| z)
	X	       (return nil)))
	X        ($value '|=== T A B T O ===|)
	X	($value val)))
	X
	X
	X
	X;;; Printing WM
	X
	X(defun ppwm (&quote &rest avlist)
	X  (prog (next a)
	X        (setq *filters* nil)
	X        (setq next 1.)
	X   l   (and (atom avlist) (go print))
	X        (setq a (car avlist))
	X        (setq avlist (cdr avlist))
	X        (cond ((eq a #\^)
	X               (setq next (car avlist))
	X               (setq avlist (cdr avlist))
	X               (setq next ($litbind next))
	X               (and (floatp next) (setq next (fix next)))
	X               (cond ((or (not (numberp next))
	X                          (> next *size-result-array*)
	X                          (> 1. next))
	X                      (%warn '|illegal index after ^| next)
	X                      (return nil))))
	X              ((variablep a)
	X               (%warn '|ppwm does not take variables| a)
	X               (return nil))
	X              (t (setq *filters* (cons next (cons a *filters*)))
	X                 (setq next (1+ next))))
	X        (go l)
	X   print (mapwm (function ppwm2))
	X        (terpri)
	X        (return nil))) 
	X
	X(defun ppwm2 (elm-tag)
	X  (cond ((filter (car elm-tag)) (terpri) (ppelm (car elm-tag) t)))) 
	X
	X(defun filter (elm)
	X  (prog (fl indx val)
	X        (setq fl *filters*)
	X   top  (and (atom fl) (return t))
	X        (setq indx (car fl))
	X        (setq val (cadr fl))
	X        (setq fl (cddr fl))
	X        (and (ident (nth (1- indx) elm) val) (go top))
	X        (return nil))) 
	X
	X(defun ident (x y)
	X  (cond ((eq x y) t)
	X        ((not (numberp x)) nil)
	X        ((not (numberp y)) nil)
	X        ((=alg x y) t)
	X        (t nil))) 
	X
	X; the new ppelm is designed especially to handle literalize format
	X; however, it will do as well as the old ppelm on other formats
	X
	X(defun ppelm (elm port)
	X  (prog (ppdat sep val att mode lastpos)
	X	(princ (creation-time elm) port)
	X	(princ '|:  | port)
	X        (setq mode 'vector)
	X	(setq ppdat (get (car elm) 'ppdat))
	X	(and ppdat (setq mode 'a-v))
	X	(setq sep '|(|)
	X        (setq lastpos 0)
	X	(do
	X	 ((curpos 1 (1+ curpos)) (vlist elm (cdr vlist)))
	X	 ((atom vlist) nil)
	X	 (setq val (car vlist))
	X	 (setq att (assoc curpos ppdat))
	X	 (cond (att (setq att (cdr att)))
	X	       (t (setq att curpos)))
	X         (and (symbolp att) (is-vector-attribute att) (setq mode 'vector))
	X	 (cond ((or (not (null val)) (eq mode 'vector))
	X		(princ sep port)
	X		(ppval val att lastpos port)
	X		(setq sep '|    |)
	X		(setq lastpos curpos))))
	X	(princ '|)| port)))
	X
	X(defun ppval (val att lastpos port)
	X  (cond ((not (equal att (1+ lastpos)))
	X         (princ '^ port)
	X         (princ att port)
	X         (princ '| | port)))
	X  (princ val port))
	X
	X
	X
	X;;; printing production memory
	X
	X(defmacro pm (&rest z)  `(progn (mapc #'pprule ',z) (terpri) nil)) 
	X
	X(defun pprule (name)
	X  (prog (matrix next lab)
	X        (and (not (symbolp name)) (return nil))
	X        (setq matrix (get name 'production))
	X	(and (null matrix) (return nil))
	X	(terpri)
	X	(princ '|(p |)
	X	(princ name)
	X   top	(and (atom matrix) (go fin))
	X        (setq next (car matrix))
	X	(setq matrix (cdr matrix))
	X	(setq lab nil)
	X	(terpri)
	X	(cond ((eq next '-)
	X	       (princ '|  - |)
	X	       (setq next (car matrix))
	X	       (setq matrix (cdr matrix)))
	X	      ((eq next '-->)
	X	       (princ '|  |))
	X	      ((and (eq next '{) (atom (car matrix)))
	X	       (princ '|   {|)
	X	       (setq lab (car matrix))
	X	       (setq next (cadr matrix))
	X	       (setq matrix (cdddr matrix)))
	X	      ((eq next '{)
	X	       (princ '|   {|)
	X	       (setq lab (cadr matrix))
	X	       (setq next (car matrix))
	X	       (setq matrix (cdddr matrix)))
	X	      (t (princ '|    |)))
	X        (ppline next)
	X	(cond (lab (princ '| |) (princ lab) (princ '})))
	X	(go top)
	X    fin	(princ '|)|)))
	X
	X(defun ppline (line)
	X  (prog ()
	X	(cond ((atom line) (princ line))
	X	      (t
	X	       (princ '|(|)
	X	       (setq *ppline* line)
	X	       (ppline2)
	X	       (princ '|)|)))
	X        (return nil)))
	X
	X(defun ppline2 ()
	X  (prog (needspace)
	X        (setq needspace nil)
	X   top  (and (atom *ppline*) (return nil))
	X        (and needspace (princ '| |))
	X        (cond ((eq (car *ppline*) #\^) (ppattval))
	X	      (t (pponlyval)))
	X        (setq needspace t)
	X        (go top)))
	X
	X;NWRITN, sort of.  This is implementation dependant for the TI Explorer.
	X(defun nwritn(&optional port)
	X   (cond ((null port) 
	X          (cdr (cursorpos)))
	X         (t
	X          (cursorpos port))))
	X
	X(defun ppattval ()
	X  (prog (att val)
	X        (setq att (cadr *ppline*))
	X	(setq *ppline* (cddr *ppline*))
	X	(setq val (getval))
	X	(cond ((> (+ (nwritn) (flatc att) (flatc val)) 76.)
	X	       (terpri)
	X	       (princ '|        |)))
	X        (princ '^)
	X	(princ att)
	X	(mapc (function (lambda (z) (princ '| |) (princ z))) val)))
	X
	X(defun pponlyval ()
	X  (prog (val needspace)
	X	(setq val (getval))
	X	(setq needspace nil)
	X	(cond ((> (+ (nwritn) (flatc val)) 76.)
	X	       (setq needspace nil)
	X	       (terpri)
	X	       (princ '|        |)))
	X    top	(and (atom val) (return nil))
	X        (and needspace (princ '| |))
	X	(setq needspace t)
	X	(princ (car val))
	X	(setq val (cdr val))
	X	(go top)))
	X
	X(defun getval ()
	X  (prog (res v1)
	X        (setq v1 (car *ppline*))
	X	(setq *ppline* (cdr *ppline*))
	X	(cond ((memq v1 '(= <> < <= => > <=>))
	X	       (setq res (cons v1 (getval))))
	X	      ((eq v1 '{)
	X	       (setq res (cons v1 (getupto '}))))
	X	      ((eq v1 '<<)
	X	       (setq res (cons v1 (getupto '>>))))
	X	      ((eq v1 '//)
	X	       (setq res (list v1 (car *ppline*)))
	X	       (setq *ppline* (cdr *ppline*)))
	X	      (t (setq res (list v1))))
	X        (return res)))
	X
	X(defun getupto (end)
	X  (prog (v)
	X        (and (atom *ppline*) (return nil))
	X	(setq v (car *ppline*))
	X	(setq *ppline* (cdr *ppline*))
	X	(cond ((eq v end) (return (list v)))
	X	      (t (return (cons v (getupto end))))))) 
	X
	X
	X
	X
	X
	X
	X;;; backing up
	X
	X
	X
	X(defun record-index-plus (k)
	X  (setq *record-index* (+ k *record-index*))
	X  (cond ((< *record-index* 0.)
	X         (setq *record-index* *max-record-index*))
	X        ((> *record-index* *max-record-index*)
	X         (setq *record-index* 0.)))) 
	X
	X; the following routine initializes the record.  putting nil in the
	X; first slot indicates that that the record does not go back further
	X; than that.  (when the system backs up, it writes nil over the used
	X; records so that it will recognize which records it has used.  thus
	X; the system is set up anyway never to back over a nil.)
	X
	X(defun initialize-record nil
	X  (setq *record-index* 0.)
	X  (setq *recording* nil)
	X  (setq *max-record-index* 31.)
	X  (putvector *record-array* 0. nil)) 
	X
	X; *max-record-index* holds the maximum legal index for record-array
	X; so it and the following must be changed at the same time
	X
	X(defun begin-record (p data)
	X  (setq *recording* t)
	X  (setq *record* (list '=>refract p data))) 
	X
	X(defun end-record nil
	X  (cond (*recording*
	X         (setq *record*
	X               (cons *cycle-count* (cons *p-name* *record*)))
	X         (record-index-plus 1.)
	X         (putvector *record-array* *record-index* *record*)
	X         (setq *record* nil)
	X         (setq *recording* nil)))) 
	X
	X(defun record-change (direct time elm)
	X  (cond (*recording*
	X         (setq *record*
	X               (cons direct (cons time (cons elm *record*))))))) 
	X
	X; to maintain refraction information, need keep only one piece of information:
	X; need to record all unsuccessful attempts to delete things from the conflict
	X; set.  unsuccessful deletes are caused by attempting to delete refracted
	X; instantiations.  when backing up, have to avoid putting things back into the
	X; conflict set if they were not deleted when running forward
	X
	X(defun record-refract (rule data)
	X  (and *recording*
	X       (setq *record* (cons '<=refract (cons rule (cons data *record*))))))
	X
	X(defun refracted (rule data)
	X  (prog (z)
	X        (and (null *refracts*) (return nil))
	X	(setq z (cons rule data))
	X	(return (member z *refracts*))))
	X
	X(defun back (k)
	X  (prog (r)
	X   l   (and (< k 1.) (return nil))
	X        (setq r (getvector *record-array* *record-index*))
	X        (and (null r) (return '|nothing more stored|))
	X        (putvector *record-array* *record-index* nil)
	X        (record-index-plus -1.)
	X        (undo-record r)
	X        (setq k (1- k))
	X        (go l))) 
	X
	X(defun undo-record (r)
	X  (prog (save act a b rate)
	X        (comment *recording* must be off during back up)
	X        (setq save *recording*)
	X        (setq *refracts* nil)
	X        (setq *recording* nil)
	X        (and *ptrace* (back-print (list 'undo (car r) (cadr r))))
	X        (setq r (cddr r))
	X   top  (and (atom r) (go fin))
	X        (setq act (car r))
	X        (setq a (cadr r))
	X        (setq b (caddr r))
	X        (setq r (cdddr r))
	X        (and *wtrace* (back-print (list 'undo act a)))
	X        (cond ((eq act '<=wm) (add-to-wm b a))
	X              ((eq act '=>wm) (remove-from-wm b))
	X              ((eq act '<=refract)
	X               (setq *refracts* (cons (cons a b) *refracts*)))
	X              ((and (eq act '=>refract) (still-present b))
	X	       (setq *refracts* (delete (cons a b) *refracts*))
	X               (setq rate (rating-part (get a 'topnode)))
	X               (removecs a b)
	X               (insertcs a b rate))
	X              (t (%warn '|back: cannot undo action| (list act a))))
	X        (go top)
	X   fin  (setq *recording* save)
	X        (setq *refracts* nil)
	X        (return nil))) 
	X
	X; still-present makes sure that the user has not deleted something
	X; from wm which occurs in the instantiation about to be restored; it
	X; makes the check by determining whether each wme still has a time tag.
	X
	X(defun still-present (data)
	X  (prog nil
	X   l   (cond ((atom data) (return t))
	X              ((creation-time (car data))
	X               (setq data (cdr data))
	X               (go l))
	X              (t (return nil))))) 
	X
	X
	X(defun back-print (x) 
	X  (prog (port)
	X        (setq port (trace-file))
	X        (terpri port)
	X	(print x port)))
	X
	X
	X
	X
	X;;; Functions to show how close rules are to firing
	X
	X(defun matches (&quote &rest rule-list)
	X  (progn 
	X    (mapc (function matches2) rule-list)
	X    (terpri)) )
	X
	X(defun matches2 (p)
	X  (cond ((atom p)
	X         (terpri)
	X         (terpri)
	X         (princ p)
	X         (matches3 (get p 'backpointers) 2. (ncons 1.))))) 
	X
	X(defun matches3 (nodes ce part)
	X  (cond ((not (null nodes))
	X         (terpri)
	X         (princ '| ** matches for |)
	X         (princ part)
	X         (princ '| ** |)
	X         (mapc (function write-elms) (find-left-mem (car nodes)))
	X         (terpri)
	X         (princ '| ** matches for |)
	X         (princ (ncons ce))
	X         (princ '| ** |)
	X         (mapc (function write-elms) (find-right-mem (car nodes)))
	X         (matches3 (cdr nodes) (1+ ce) (cons ce part))))) 
	X
	X(defun write-elms (wme-or-count)
	X  (cond ((listp wme-or-count)
	X	 (terpri)
	X	 (mapc (function write-elms2) wme-or-count)))) 
	X
	X(defun write-elms2 (x)
	X  (princ '|  |)
	X  (princ (creation-time x)))
	X
	X(defun find-left-mem (node)
	X  (cond ((eq (car node) '&and) (memory-part (caddr node)))
	X        (t (car (caddr node))))) 
	X
	X(defun find-right-mem (node) (memory-part (cadddr node))) 
	X
	X
	X;;; Check the RHSs of productions 
	X
	X
	X(defun check-rhs (rhs) (mapc (function check-action) rhs))
	X
	X(defun check-action (x)
	X  (prog (a)
	X    (cond ((atom x)
	X           (%warn '|atomic action| x)
	X	   (return nil)))
	X    (setq a  (car x))
	X    (cond ((eq a 'bind) (check-bind x))
	X          ((eq a 'cbind) (check-cbind x))
	X          ((eq a 'make) (check-make x))
	X          ((eq a 'modify) (check-modify x))
	X          ((eq a 'oremove) (check-remove x))
	X          ((eq a 'owrite) (check-write x))
	X          ((eq a 'ocall) (check-call x))
	X          ((eq a 'halt) (check-halt x))
	X          ((eq a 'openfile) (check-openfile x))
	X          ((eq a 'closefile) (check-closefile x))
	X          ((eq a 'default) (check-default x))
	X          ((eq a 'build) (check-build x))
	X          ;;the following section is responsible for replacing standard ops RHS actions
	X          ;;with actions which don't conflict with existing CL functions.  The RPLACA function
	X          ;;is used so that the change will be reflected in the production body.
	X          ((eq a 'remove) (rplaca x 'oremove) 
	X                          (check-remove x))
	X          ((eq a 'write)   (rplaca x 'owrite)
	X                          (check-write x)) 
	X          ((eq a 'call)   (rplaca x 'ocall)
	X                          (check-call x))
	X          (t (%warn '|undefined rhs action| a))))) 
	X
	X(defun check-build (z)
	X  (and (null (cdr z)) (%warn '|needs arguments| z))
	X  (check-build-collect (cdr z)))
	X
	X(defun check-build-collect (args)
	X  (prog (r)
	X    top	(and (null args) (return nil))
	X	(setq r (car args))
	X	(setq args (cdr args))
	X	(cond ((listp r) (check-build-collect r))
	X	      ((eq r '\\)
	X	       (and (null args) (%warn '|nothing to evaluate| r))
	X	       (check-rhs-value (car args))
	X	       (setq args (cdr args))))
	X	(go top)))
	X
	X(defun check-remove (z) 
	X  (and (null (cdr z)) (%warn '|needs arguments| z))
	X  (mapc (function check-rhs-ce-var) (cdr z))) 
	X
	X(defun check-make (z)
	X  (and (null (cdr z)) (%warn '|needs arguments| z))
	X  (check-change& (cdr z))) 
	X
	X(defun check-openfile (z)
	X  (and (null (cdr z)) (%warn '|needs arguments| z))
	X  (check-change& (cdr z))) 
	X
	X(defun check-closefile (z)
	X  (and (null (cdr z)) (%warn '|needs arguments| z))
	X  (check-change& (cdr z))) 
	X
	X(defun check-default (z)
	X  (and (null (cdr z)) (%warn '|needs arguments| z))
	X  (check-change& (cdr z))) 
	X
	X(defun check-modify (z)
	X  (and (null (cdr z)) (%warn '|needs arguments| z))
	X  (check-rhs-ce-var (cadr z))
	X  (and (null (cddr z)) (%warn '|no changes to make| z))
	X  (check-change& (cddr z))) 
	X
	X(defun check-write (z)
	X  (and (null (cdr z)) (%warn '|needs arguments| z))
	X  (check-change& (cdr z))) 
	X
	X(defun check-call (z)
	X  (prog (f)
	X    (and (null (cdr z)) (%warn '|needs arguments| z))
	X    (setq f (cadr z))
	X    (and (variablep f)
	X         (%warn '|function name must be a constant| z))
	X    (or (symbolp f)
	X        (%warn '|function name must be a symbolic atom| f))
	X    (or (externalp f)
	X        (%warn '|function name not declared external| f))
	X    (check-change& (cddr z)))) 
	X
	X(defun check-halt (z)
	X  (or (null (cdr z)) (%warn '|does not take arguments| z))) 
	X
	X(defun check-cbind (z)
	X  (prog (v)
	X    (or (= (length z) 2.) (%warn '|takes only one argument| z))
	X    (setq v (cadr z))
	X    (or (variablep v) (%warn '|takes variable as argument| z))
	X    (note-ce-variable v))) 
	X
	X(defun check-bind (z)
	X  (prog (v)
	X    (or (> (length z) 1.) (%warn '|needs arguments| z))
	X    (setq v (cadr z))
	X    (or (variablep v) (%warn '|takes variable as argument| z))
	X    (note-variable v)
	X    (check-change& (cddr z)))) 
	X
	X
	X(defun check-change& (z)
	X  (prog (r tab-flag)
	X        (setq tab-flag nil)
	X   la   (and (atom z) (return nil))
	X        (setq r (car z))
	X        (setq z (cdr z))
	X        (cond ((eq r #\^)
	X               (and tab-flag
	X                    (%warn '|no value before this tab| (car z)))
	X               (setq tab-flag t)
	X               (check-tab-index (car z))
	X               (setq z (cdr z)))
	X              ((eq r '//) (setq tab-flag nil) (setq z (cdr z)))
	X              (t (setq tab-flag nil) (check-rhs-value r)))
	X        (go la))) 
	X
	X(defun check-rhs-ce-var (v)
	X  (cond ((and (not (numberp v)) (not (ce-bound? v)))
	X         (%warn '|unbound element variable| v))
	X        ((and (numberp v) (or (< v 1.) (> v *ce-count*)))
	X         (%warn '|numeric element designator out of bounds| v)))) 
	X
	X(defun check-rhs-value (x)
	X  (cond ((and x (listp x)) (check-rhs-function x))
	X        (t (check-rhs-atomic x)))) 
	X
	X(defun check-rhs-atomic (x)
	X  (and (variablep x) 
	X       (not (bound? x)) 
	X       (%warn '|unbound variable| x)))
	X
	X(defun check-rhs-function (x)
	X  (prog (a)
	X    (setq a (car x))
	X    (cond ((eq a 'compute) (check-compute x))
-- 
---------------
C'est la vie, C'est la guerre, C'est la pomme de terre
Mail:	Imagen Corp. 2650 San Tomas Expressway Santa Clara, CA 95052-8101 
UUCP:	...{decvax,ucbvax}!decwrl!imagen!turner      AT&T: (408) 986-9400

turner@imagen.UUCP (D'arc Angel) (01/19/87)

	X          ((eq a 'arith) (check-compute x))
	X          ((eq a 'substr) (check-substr x))
	X          ((eq a 'accept) (check-accept x))
	X          ((eq a 'acceptline) (check-acceptline x))
	X          ((eq a 'crlf) (check-crlf x))
	X          ((eq a 'genatom) (check-genatom x))
	X	  ((eq a 'litval) (check-litval x))
	X          ((eq a 'tabto) (check-tabto x))
	X	  ((eq a 'rjust) (check-rjust x))
	X	  ((not (externalp a))
	X	   (%warn '"rhs function not declared external" a)))))
	X
	X(defun check-litval (x) 
	X  (or (= (length x) 2) (%warn '|wrong number of arguments| x))
	X  (check-rhs-atomic (cadr x)))
	X
	X(defun check-accept (x)
	X  (cond ((= (length x) 1) nil)
	X        ((= (length x) 2) (check-rhs-atomic (cadr x)))
	X	(t (%warn '|too many arguments| x))))
	X
	X(defun check-acceptline (x)
	X  (mapc (function check-rhs-atomic) (cdr x)))
	X
	X(defun check-crlf (x) 
	X  (check-0-args x)) 
	X
	X(defun check-genatom (x) (check-0-args x)) 
	X
	X(defun check-tabto (x)
	X  (or (= (length x) 2) (%warn '|wrong number of arguments| x))
	X  (check-print-control (cadr x)))
	X
	X(defun check-rjust (x)
	X  (or (= (length x) 2) (%warn '|wrong number of arguments| x))
	X  (check-print-control (cadr x)))
	X
	X(defun check-0-args (x)
	X  (or (= (length x) 1.) (%warn '|should not have arguments| x))) 
	X
	X(defun check-substr (x)
	X  (or (= (length x) 4.) (%warn '|wrong number of arguments| x))
	X  (check-rhs-ce-var (cadr x))
	X  (check-substr-index (caddr x))
	X  (check-last-substr-index (cadddr x))) 
	X
	X(defun check-compute (x) (check-arithmetic (cdr x))) 
	X
	X(defun check-arithmetic (l)
	X  (cond ((atom l)
	X         (%warn '|syntax error in arithmetic expression| l))
	X        ((atom (cdr l)) (check-term (car l)))
	X        ((not (memq (cadr l) '(+ - * // \\)))
	X         (%warn '|unknown operator| l))
	X        (t (check-term (car l)) (check-arithmetic (cddr l))))) 
	X
	X(defun check-term (x)
	X  (cond ((listp x) (check-arithmetic x))
	X        (t (check-rhs-atomic x)))) 
	X
	X(defun check-last-substr-index (x)
	X  (or (eq x 'inf) (check-substr-index x))) 
	X
	X(defun check-substr-index (x)
	X  (prog (v)
	X    (cond ((bound? x) (return x)))
	X    (setq v ($litbind x))
	X    (cond ((not (numberp v))
	X           (%warn '|unbound symbol used as index in substr| x))
	X          ((or (< v 1.) (> v 127.))
	X           (%warn '|index out of bounds in tab| x))))) 
	X
	X(defun check-print-control (x)
	X  (prog ()
	X    (cond ((bound? x) (return x)))
	X    (cond ((or (not (numberp x)) (< x 1.) (> x 127.))
	X           (%warn '|illegal value for printer control| x))))) 
	X
	X(defun check-tab-index (x)
	X  (prog (v)
	X    (cond ((bound? x) (return x)))
	X    (setq v ($litbind x))
	X    (cond ((not (numberp v))
	X           (%warn '|unbound symbol occurs after ^| x))
	X          ((or (< v 1.) (> v 127.))
	X           (%warn '|index out of bounds after ^| x))))) 
	X
	X(defun note-variable (var)
	X  (setq *rhs-bound-vars* (cons var *rhs-bound-vars*)))
	X
	X(defun bound? (var)
	X  (or (memq var *rhs-bound-vars*)
	X      (var-dope var)))
	X
	X(defun note-ce-variable (ce-var)
	X  (setq *rhs-bound-ce-vars* (cons ce-var *rhs-bound-ce-vars*)))
	X
	X(defun ce-bound? (ce-var)
	X  (or (memq ce-var *rhs-bound-ce-vars*)
	X      (ce-var-dope ce-var)))
	X
	X;;; Top level routines
	X
	X(defun process-changes (adds dels)
	X  (prog (x)
	X   process-deletes (and (atom dels) (go process-adds))
	X        (setq x (car dels))
	X        (setq dels (cdr dels))
	X        (remove-from-wm x)
	X        (go process-deletes)
	X   process-adds (and (atom adds) (return nil))
	X        (setq x (car adds))
	X        (setq adds (cdr adds))
	X        (add-to-wm x nil)
	X        (go process-adds))) 
	X
	X(defun main nil
	X  (prog (instance r)
	X        (setq *halt-flag* nil)
	X        (setq *break-flag* nil)
	X        (setq instance nil)
	X   dil  (setq *phase* 'conflict-resolution)
	X        (cond (*halt-flag*
	X               (setq r '|end -- explicit halt|)
	X               (go finis))
	X	      ((zerop *remaining-cycles*)
	X	       (setq r '***break***)
	X	       (setq *break-flag* t)
	X	       (go finis))
	X              (*break-flag* (setq r '***break***) (go finis)))
	X	(setq *remaining-cycles* (1- *remaining-cycles*))
	X        (setq instance (conflict-resolution))
	X        (cond ((not instance)
	X               (setq r '|end -- no production true|)
	X               (go finis)))
	X        (setq *phase* (car instance))
	X        (accum-stats)
	X        (eval-rhs (car instance) (cdr instance))
	X        (check-limits)
	X	(and (broken (car instance)) (setq *break-flag* t))
	X        (go dil)
	X  finis (setq *p-name* nil)
	X        (return r))) 
	X
	X(defun do-continue (wmi)
	X    (cond (*critical*
	X           (terpri)
	X           (princ '|warning: network may be inconsistent|)))
	X    (process-changes wmi nil)
	X    (print-times (main))) 
	X
	X(defun accum-stats nil
	X  (setq *cycle-count* (1+ *cycle-count*))
	X  (setq *total-token* (+ *total-token* *current-token*))
	X  (cond ((> *current-token* *max-token*)
	X         (setq *max-token* *current-token*)))
	X  (setq *total-wm* (+ *total-wm* *current-wm*))
	X  (cond ((> *current-wm* *max-wm*) (setq *max-wm* *current-wm*)))) 
	X
	X
	X(defun print-times (mess)
	X  (prog (cc ac)
	X    	(cond (*break-flag* (terpri) (return mess)))
	X        (setq cc (plus (float *cycle-count*) 1.0e-20))
	X        (setq ac (plus (float *action-count*) 1.0e-20))
	X        (terpri)
	X        (princ mess)
	X        (pm-size)
	X        (printlinec (list *cycle-count*
	X                          'firings
	X                          (list *action-count* 'rhs 'actions)))
	X        (terpri)
	X        (printlinec (list (round (quotient (float *total-wm*) cc))
	X                          'mean 'working 'memory 'size
	X                          (list *max-wm* 'maximum)))
	X        (terpri)
	X        (printlinec (list (round (quotient (float *total-cs*) cc))
	X                          'mean 'conflict 'set 'size
	X                          (list *max-cs* 'maximum)))
	X        (terpri)
	X        (printlinec (list (round (quotient (float *total-token*) cc))
	X                          'mean 'token 'memory 'size
	X                          (list *max-token* 'maximum)))
	X        (terpri))) 
	X
	X(defun pm-size nil
	X  (terpri)
	X  (printlinec (list *pcount*
	X                    'productions
	X                    (list *real-cnt* '// *virtual-cnt* 'nodes)))
	X  (terpri)) 
	X
	X(defun check-limits nil
	X  (cond ((> (length *conflict-set*) *limit-cs*)
	X         (terpri)
	X         (terpri)
	X         (printlinec (list '|conflict set size exceeded the limit of|
	X                           *limit-cs*
	X                           '|after|
	X                           *p-name*))
	X         (setq *halt-flag* t)))
	X  (cond ((> *current-token* *limit-token*)
	X         (terpri)
	X         (terpri)
	X         (printlinec (list '|token memory size exceeded the limit of|
	X                           *limit-token*
	X                           '|after|
	X                           *p-name*))
	X         (setq *halt-flag* t)))) 
	X
	X
	X(defun top-level-remove (z)
	X  (cond ((equal z '(*)) (process-changes nil (get-wm nil)))
	X        (t (process-changes nil (get-wm z))))) 
	X
	X(defun excise (&quote &rest z) (mapc (function excise-p) z))
	X
	X(defun run (&quote &rest z)
	X  (cond ((null z) (setq *remaining-cycles* 1000000.) (do-continue nil))
	X        ((and (atom (cdr z)) (numberp (car z)) (> (car z) 0.))
	X         (setq *remaining-cycles* (car z))
	X         (do-continue nil))
	X        (t 'what\?))) 
	X
	X(defmacro strategy (&rest z)
	X  `(cond ((atom ',z) *strategy*)
	X        ((equal ',z '(lex)) (setq *strategy* 'lex))
	X        ((equal ',z '(mea)) (setq *strategy* 'mea))
	X        (t 'what\?))) 
	X
	X(defmacro cs (&optional z)
	X  `(cond ((null ',z) (conflict-set))
	X        (t 'what?))) 
	X
	X(defmacro watch (&rest z)
	X  `(cond ((equal ',z '(0.))
	X         (setq *wtrace* nil)
	X         (setq *ptrace* nil)
	X         0.)
	X        ((equal ',z '(1.)) (setq *wtrace* nil) (setq *ptrace* t) 1.)
	X        ((equal ',z '(2.)) (setq *wtrace* t) (setq *ptrace* t) 2.)
	X        ((equal ',z '(3.))
	X         (setq *wtrace* t)
	X         (setq *ptrace* t)
	X         '(2. -- conflict set trace not supported))
	X        ((and (atom ',z) (null *ptrace*)) 0.)
	X        ((and (atom ',z) (null *wtrace*)) 1.)
	X        ((atom ',z) 2.)
	X        (t 'what\?))) 
	X
	X(defun external  (&quote &rest z) (catch (external2 z) '!error!))
	X
	X(defun external2 (z) (mapc (function external3) z))
	X
	X(defun external3 (x) 
	X  (cond ((symbolp x) (putprop x t 'external-routine)
	X		     (setq *externals* (enter x *externals*)))
	X	(t (%error '|not a legal function name| x))))
	X
	X(defun externalp (x)
	X  (cond ((symbolp x) (get x 'external-routine))
	X	(t (%warn '|not a legal function name| x) nil)))
	X
	X(defmacro pbreak (&rest z)
	X  `(cond ((atom ',z) (terpri) *brkpts*)
	X	(t (mapc (function pbreak2) ',z) nil)))
	X
	X(defun pbreak2 (rule)
	X  (cond ((not (symbolp rule)) (%warn '|illegal name| rule))
	X	((not (get rule 'topnode)) (%warn '|not a production| rule))
	X	((memq rule *brkpts*) (setq *brkpts* (rematm rule *brkpts*)))
	X	(t (setq *brkpts* (cons rule *brkpts*)))))
	X
	X(defun rematm (atm list)
	X  (cond ((atom list) list)
	X	((eq atm (car list)) (rematm atm (cdr list)))
	X	(t (cons (car list) (rematm atm (cdr list))))))
	X
	X(defun broken (rule) (memq rule *brkpts*))
	X
	X
	XPRTOWER.OPS
	X
	X(i-g-v)
	X; **************************************************************
	X; TOWERS OF HANOI problem for 3 disks including printing of towers
	X;     Version 2
	X; This program was translated from a version written by Jeff Shrager and
	X; Adele Howe in the production system language PRISM.
	X
	X;  The algorithm is fairly simple minded and certainly not optimal, but it 
	X;  works. The idea is to cycle through the pegs from the start peg to the end
	X;  peg picking up on disk at a time and putting it in the next legal spot. 
	X;  Only one disk can be 'picked up' at a time (holding ^disk). Productions 
	X;  alternate between time-to-act (picking up and putting down), time-to-move
	X;  (looking at next peg), and time-to-print (printing the state of the
	X;  towers). The towers are printed after a disk is put down. 
	X
	X;  The goal is to move from the peg on one end to the peg on the other. 
	X;  The goal has been reached when no pegs other than the goal peg have
	X;     disks on them.
	X
	X; It requires 128 firings to solve the problem for 3 disks.
	X; ************************************************************
	X
	X; elements are:
	X
	X; setup information
	X;   start state
	X(literalize goal from to)
	X;   end state
	X(literalize end is)
	X
	X; given info about the peg world
	X;    relationships between entities
	X(literalize follows peg1 peg2)
	X(literalize smaller disk1 disk2)
	X
	X; state information 
	X;   program has three states : moving, acting, or printing
	X;   only one state is valid at a given time
	X(literalize time-to-act)
	X(literalize time-to-move)
	X(literalize time-to-print)
	X
	X; current state of peg world
	X(literalize top disk peg)
	X(literalize under disk1 disk2)
	X(literalize holding disk)
	X(literalize on peg)
	X
	X; peg/disks vector holds the printing state of each peg
	X(literalize peg name disks)
	X(vector-attribute disks)
	X
	X; declare lisp function
	X(external print-towers)
	X
	X; start-task does what you think it does.
	X
	X(p start-task
	X	{ (goal ^from <p1> ^to <p2>) <exp0> }
	X    -->
	X	(remove <exp0>)
	X	(make time-to-act)	; start act/move cycle
	X	(make on ^peg <p1>)	; set the starting point
	X	(make end ^is <p2>))	; define the end peg
	X
	X
	X; stop-task determines when the end has been reached
	X
	X(p stop-task				; end is reached when:
	X	(on ^peg <p>)			;   on a peg
	X	(end ^is <p>)			;   which is the end peg
	X	(follows ^peg1 <p> ^peg2 <p1>)  ;   which follows peg p1
	X	(follows ^peg1 <p2> ^peg2 <p>)	;   is followed by peg p2
	X	-(top ^disk <d> ^peg <p1>)	;   both other pegs 
	X	-(top ^disk <e> ^peg <p2>)	;      are empty
	X        (time-to-move)
	X--> 
	X	(owrite (crlf) all finished (crlf))
	X	(halt))
	X
	X
	X; state-change is used to skip pegs that either don't have disks on them
	X; 	or can't have the current disk put on it, i.e. if forces a move to
	X; 	the next peg when nothing else can be done.
	X
	X(p state-change
	X	{ (time-to-act) <exp0> }
	X-->
	X	(remove <exp0>)
	X	(make time-to-move))
	X
	X
	X
	X; pick-up-a-disk-from-a-full-peg picks up a disk from a peg with 3 disks
	X; 	pick-up and put-down productions must be separated because the
	X; 	peg stack is handled differently
	X
	X(p pick-up-a-disk-from-a-full-peg
	X	(on ^peg <p>)				; current peg
	X	{ (top ^disk <d> ^peg <p>) <exp0> }	; find the top disk
	X        { (under ^disk1 <e> ^disk2 <d>) <exp1> }	; is there one under it?
	X	{ (time-to-act) <exp2> }			; is it time-to-act?
	X	{ (peg ^name <p> ^disks <d> <e> <f>) <exp3> }  ; get peg stack
	X	-(holding ^disk <x>)			; not already holding a disk?
	X-->
	X	(make top ^disk <e> ^peg <p>)		; reset top disk
	X	(remove <exp0> <exp1> <exp2> <exp3>)
	X	(make holding ^disk <d>) 		; now holding disk
	X	(make peg ^name <p> ^disks 0 <e> <f>) 	; update peg stack
	X	(make time-to-move))			; toggle act/move
	X
	X
	X; pick-up-a-disk-from-a-part-full-peg picks up a disk from a peg with 2 disks
	X
	X(p pick-up-a-disk-from-a-part-full-peg
	X	(on ^peg <p>)				; current peg
	X	{ (top ^disk <d> ^peg <p>) <exp0> }	; find top disk
	X        { (under ^disk1 <e> ^disk2 <d>) <exp1> }  ; something under the top
	X	{ (time-to-act) <exp2> }			; time-to-act?
	X	{ (peg ^name <p> ^disks 0 <d> <e>) <exp3> } ; get part full peg stack
	X	-(holding ^disk <x>)			; not holding a disk already?
	X-->
	X	(remove <exp0> <exp1> <exp2> <exp3>)
	X	(make top ^disk <e> ^peg <p>)		; reset top disk
	X	(make peg ^name <p> ^disks 0 0 <e>)	; reset peg stack
	X	(make holding ^disk <d>)		; now holding disk
	X	(make time-to-move))			; toggle move/act
	X
	X; pick-up-a-disk-from-an-empty-peg takes a disk off a peg with 1 disk on it
	X
	X(p pick-up-a-disk-from-an-empty-peg
	X	(on ^peg <p>)				; as above...
	X	{ (top ^disk <d> ^peg <p>) <exp0> }	;  except for peg stack with
	X	{ (time-to-act) <exp1> }			;  with only one disk
	X	{ (peg ^name <p> ^disks 0 0 <d>) <exp2> }
	X	-(under ^disk1 <d> ^disk2 <e>)
	X	-(holding ^disk <x>)
	X-->
	X	(remove <exp0> <exp1> <exp2>)
	X	(make holding ^disk <d>)
	X	(make peg ^name <p> ^disks 0 0 0)	; no disks on peg stack
	X	(make time-to-move))
	X
	X
	X; look-at-next-peg moves forward a peg and toggles move to act
	X
	X(p look-at-next-peg
	X	{ (on ^peg <p>) <exp0> }
	X	(follows ^peg1 <next> ^peg2 <p>)
	X	{ (time-to-move) <exp1> }
	X-->
	X	(remove <exp0> <exp1>)
	X	(make on ^peg <next>)
	X	(make time-to-act))
	X
	X
	X; put-on-a-full-peg puts a disk down on a peg that has 2 disks on it.
	X
	X(p put-on-a-full-peg
	X	{ (holding ^disk <d>) <exp0> }
	X	(on ^peg <p>)
	X	{ (top ^disk <top> ^peg <p>) <exp1> }
	X	(smaller ^disk1 <d> ^disk2 <top>)
	X	{ (time-to-act) <exp2> }
	X	{ (peg ^name <p> ^disks 0 <top> <bot>) <exp3> }
	X-->
	X 	(remove <exp0> <exp1> <exp2> <exp3>)
	X	(make top ^disk <d> ^peg <p>)
	X	(make under ^disk1 <top> ^disk2 <d>)
	X	(make peg ^name <p> ^disks <d> <top> <bot>)
	X	(make time-to-print))
	X
	X
	X; put-on-a-part-full-peg puts a disk on a peg that has only one disk on it
	X
	X(p put-on-a-part-full-peg
	X	{ (holding ^disk <d>) <exp0> }
	X	(on ^peg <p>)
	X	{ (top ^disk <top> ^peg <p>) <exp1> }
	X	(smaller ^disk1 <d> ^disk2 <top>)
	X	{ (time-to-act) <exp2> }
	X	{ (peg ^name <p> ^disks 0 0 <top>) <exp3> }
	X-->
	X 	(remove <exp0> <exp1> <exp2> <exp3>)
	X	(make top ^disk <d> ^peg <p>)
	X	(make under ^disk1 <top> ^disk2 <d>)
	X	(make peg ^name <p> ^disks 0 <d> <top>)
	X	(make time-to-print))
	X
	X
	X; put-on-an-empty-peg puts the disk being held on an empty peg by making it
	X; the top disk on the peg and updating the pegs print state
	X
	X(p put-on-an-empty-peg
	X	{ (holding ^disk <d>) <exp0> }
	X	(on ^peg <p>)
	X	{ (time-to-act) <exp1> }
	X	-(top ^disk <e> ^peg <p>)
	X	{ (peg ^name <p> ^disks 0 0 0) <exp2> }
	X-->
	X	(remove <exp0> <exp1> <exp2>)
	X	(make peg ^name <p> ^disks 0 0 <d>)
	X	(make top ^disk <d> ^peg <p>)
	X	(make time-to-print))
	X
	X
	X; print-peg-state takes the vector representation of the pegs and passes it
	X; to a franz function that prints them out
	X
	X(p print-peg-state
	X	{ (time-to-print) <exp0> }
	X        (peg ^name a ^disks <d1> <d4> <d7>)
	X        (peg ^name b ^disks <d2> <d5> <d8>)
	X        (peg ^name c ^disks <d3> <d6> <d9>)
	X	(peg ^name base ^disks <b1> <b2> <b3>)
	X-->
	X	(call print-towers <d1> <d2> <d3> <d4> <d5> <d6> <d7> <d8> <d9> <b1> <b2> <b3>)
	X	(remove <exp0>)
	X	(make time-to-move))
	X
	X
	X; the following are the 'facts' of the problem
	X; pegs are ordered a b c 
	X(make follows ^peg1 b ^peg2 a)
	X(make follows ^peg1 c ^peg2 b)
	X(make follows ^peg1 a ^peg2 c)
	X
	X; disks are stacked 1 2 3
	X(make top ^disk 1 ^peg a)
	X(make under ^disk1 2 ^disk2 1)
	X(make under ^disk1 3 ^disk2 2)
	X
	X; 1is the smallest disk and 2 is the medium disk
	X(make smaller ^disk1 1 ^disk2 2)
	X(make smaller ^disk1 2 ^disk2 3)
	X(make smaller ^disk1 1 ^disk2 3)
	X
	X; goal is to move the disks from peg a to peg c
	X(make goal ^from a ^to c)
	X
	X; peg a has the three disks on it
	X(make peg ^name a ^disks 1 2 3)
	X; the other pegs are empty
	X(make peg ^name b ^disks 0 0 0)
	X(make peg ^name c ^disks 0 0 0)
	X(make peg ^name base ^disks ----- ----- -----)
	X
	X;**************************************************
	X; Lisp program for printing out towers 
	X
	X; purpose of this program is to demonstrate that ops5 CAN talk to franz
	X; 	under duress and to give an example of how its done.
	X; final result of printing is like the following:
	X; 
	X;      	=       |       |
	X;      ===	    |       |
	X;     =====	    |       |
	X;     -----   -----   -----
	X
	X; positioning in the vector is from left to right and then top to bottom
	X; values in the vector are
	X		; 0 for the peg,
	X	 	; 1 for small disk,
	X		; 2 for medium disk,
	X		; 3 for large disk,
	X		; and who cares for the peg base.
	X
	X(defun print-towers()
	X    (format t "~%~%~%")
	X
	X; loop to print out all 12 positions of the towers
	X; 	parameters are passed from ops to franz in a vector
	X
	X    (do ((cnt 1 (add1 cnt)))
	X	((> cnt ($parametercount)))	; $parametercount is the
	X					; number of parameters
	X					; passed from ops
	X
	X	(let ((nxt ($parameter cnt)))	; $parameter gets to each position
	X					; in the vector - cnt indicates
	X					; relative position
	X	     (cond ((eq nxt 0) (format t "    |    "))
	X		   ((eq nxt 1) (format t "    =    "))
	X		   ((eq nxt 2) (format t "   ===   "))
	X		   ((eq nxt 3) (format t "  =====  "))
	X		   (t          (format t "  -----  "))))
	X	(cond ((or (eq 3 cnt) (eq 6 cnt) (eq 9 cnt))
	X             (terpri)))))
	X
	X
	XOPS5 NOTES:
	X
	XOPS5 is has been made public domain by C. Lanny Forgy. There are, I believe, some 
	Xrestrictions on transporting OPS5 to some foreign countries (which countries is pretty 
	Xobvious).  The code is copyrighted by Forgy, and anyone considering using it for 
	Xcommercial purposes should probably contact him at CMU first. 
	X
	XThe Vax Common Lisp and TI Explorer versions were ported by Dan Neiman of the
	XUniversity of Massachusetts, COINS Dept.  They are *not* guaranteed to be 100%
	Xbug free, particularly in the I/O functions, but any bugs found should be
	Xmostly syntactic in nature.  The TI Explorer takes advantage of some non-standard
	Xfeatures not normally in Common Lisp (such as the &quote keyword) and is somewhat
	Xcleaner; the Vax Lisp version is more generic and will run on more systems.
	XThe Common Lisp versions are far from optimized, the major emphasis was on getting 
	Xthem working and there are many idioms which could be expressed more compactly
	Xand efficiently.
	X
	XModifications to OPS itself.  The ported versions of OPS are faithful to the manual with
	Xthe following exceptions, Common Lisp already possesses functions remove, write, and
	Xcall; the OPS5 functions have been renamed oremove, owrite, and ocall respectively.
	XThe OPS5 compilation functions have been modified to perform this renaming 
	Xautomagically for RHS functions.  The user will have to remember to use oremove
	Xwhen removing working memory from the top level.
	X
	XTest programs:  There are not a lot of OPS5 benchmark programs available.  The 
	Xmonkey and bananas program was included in the original distribution.
	XThe sort and Towers of Hanoi problems demonstrate OPS5, but are not particularly good
	Xexemplars of the tasks that you want to solve using a production system.
	X
	X
	XQuestions about these versions of OPS5 can be directed to Dan Neiman, at electronic mail
	Xaddresses CSNET: dann@cs.umass.edu, dann@umass-cs.csnet
	X          CompuServe: 72277,2604
	X          Real Mail: COINS Dept.
	X                     Lederle Graduate Research Center
	X                     UMass
	X                     Amherst, MA 01003  
	X
	X
	X
echo shar: "a missing newline was added to 'OPSNET.JAN'"
echo shar: "114 control characters may be missing from 'OPSNET.JAN'"
SHAR_EOF
if test 359936 -ne "`wc -c < 'OPSNET.JAN'`"
then
	echo shar: "error transmitting 'OPSNET.JAN'" '(should have been 359936 characters)'
fi
fi
echo shar: "extracting 'PERCEP.JAN'" '(13440 characters)'
if test -f 'PERCEP.JAN'
then
	echo shar: "will not over-write existing file 'PERCEP.JAN'"
else
sed 's/^	X//' << \SHAR_EOF > 'PERCEP.JAN'
	X
	X
	X                         Perceptrons & Neural Nets
	X              (Two slightly different versions of the program)
	X                          January 1987 AI EXPERT
	X                              by Peter Reece
	X
	X
	XListing 1
	X
	X5 ' PERCEPTRON VISION SYSTEM SIMULATION, Peter Reece 1986
	X10 '
	X11 '
	X12 DEFINT A-X
	X13 ' IMAGE()    = the sensory grid array
	X14 ' NEURALNET  = the associative net - neural interconnections
	X15 ' SIZE**2    = number of cells in the sensory grid
	X16 ' SCAN       = number of cells required to construct an 8-bit address
	X17 '              into the array NEURALNET()
	X18 ' LOOPSCAN   = the number of iterations for scanning the sensory
	X19 '              grid - i.e. we look at scan cells at random 
	X20 '              loopscan times
	X21 SIZE=16:SCAN=8:LOOPSCAN=SIZE*SIZE/SCAN
	X22 DIM IMAGE(SIZE,SIZE),NEURALNET(LOOPSCAN*SIZE*SIZE,1):CLS
	X30 PRINT"  This program demonstrates how a very simple"
	X40 PRINT"pecpeptron is capable of analysing visual information."
	X45 PRINT:PRINT:PRINT
	X50 PRINT"  Proceed as follows: "
	X51 PRINT:PRINT
	X60 PRINT" 1) Draw an object and decide if that object is a member of"
	X70 PRINT"    a ojbect class one or two. Eg. A cup, saucer, and "
	X80 PRINT"    plate might be class 1, a crayon class 2."
	X81 PRINT" 2) Train the perceptron to recognize objects"
	X82 PRINT"    of a particular class by drawing various objects"
	X83 PRINT"    from both classes."
	X84 PRINT" 3) Present various objects to the perceptron, (some"
	X85 PRINT"    old objects may be used, as well as those that it"
	X86 PRINT"    has never seen before), and see how successfully it"
	X87 PRINT"    classifies new ojects as beloging to the correct class."
	X88 PRINT:PRINT
	X90 Q$="Press [enter] to begin a training session.":GOSUB 3000:CLS
	X98 '
	X99 '
	X100 '
	X110 '********** Reach here to begin a training session. *********
	X120 CLS:FOR I=1 TO SIZE:FOR J=1 TO SIZE:IMAGE(I,J)=0:NEXT:NEXT
	X130 LOCATE 10,50:PRINT"===    TRAINING SESSION    ===="
	X135 LOCATE 11,50:INPUT"Draw class 1 or 2";CLASS
	X136 IF CLASS=1 THEN CLASS=0 ELSE CLASS=1
	X140 '
	X145 GOSUB 1000
	X150 FOR I=1 TO LOOPSCAN:GOSUB 2000
	X160 NEURALNET(INDEX,CLASS)=1
	X210 NEXT
	X220 LOCATE 2,5:Q$="Want to conduct another training session"
230 GOSUB 3000:IF Q$="Y" THEN 110
	X231 '
	X232 '
	X233 '
	X400 ' *********** Here to classify an object ************
	X410 FOR I=1 TO SIZE:FOR J=1 TO SIZE:IMAGE(I,J)=0:NEXT:NEXT
	X420 CLS:LOCATE 10,50:PRINT"=== CLASSIFICATION SESSION ===="
	X422 '
	X450 GOSUB 1000:MEMBER=0:NONMEMBER=0
	X500 FOR I=1 TO LOOPSCAN:GOSUB 2000
	X540 IF NEURALNET(INDEX,0)=1 THEN MEMBER=MEMBER+1
	X550 IF NEURALNET(INDEX,1)=1 THEN NONMEMBER=NONMEMBER+1
	X560 NEXT
	X571 LOCATE 23,2:PRINT SPC(78)
	X573 LOCATE 12,50: PRINT"Ratio is ";MEMBER;"/";NONMEMBER
	X574 LOCATE 13,50: PRINT " favoring class ";
	X576 IF MEMBER<NONMEMBER THEN 580
	X577 PRINT"One":GOTO 590
	X580 PRINT"Two"
	X590 LOCATE 14,50:Q$="Classify another object":GOSUB 3000
	X600 IF Q$="Y" THEN 400
	X601'
	X610 CLS:?:?:?:?:Q$="Want to see NEURALNET":GOSUB 3000
	X620 IF Q$="N" THEN  670
	X630 K=0:KK=0:KZ=0:FOR I=1 TO LOOPSCAN*SIZE*SIZE
	X640 FOR J=0 TO 1
	X650 A=NEURALNET(I,J):IF A=1 THEN ?"*"; ELSE ?".";
	X660 K=K+1:IF K>SIZE THEN K=0:KZ=KZ+1:?"  ";
	X661 IF KZ>3 THEN KZ=0:?:KK=KK+1
	X662 IF KK>SIZE THEN KK=0:?
	X665 NEXT:NEXT
	X670 ?"Emptying Neural Network...":FOR I=1 TO LOOPSIZE*SIZE*SIZE
	X680 FOR J=0 TO 1
	X690 NEURALNET(I,J)=0:NEXT:NEXT:GOTO 100
	X700 :CLS:PRINT"Bye!":STOP
	X998 '
	X999 '
	X1000 ' *********** Interactive Object drawing ***********
	X1005 RR=5:CC=20:ROW=1:CLM=1
	X1006 LOCATE 23,2
	X1010 PRINT"[D],[U],[L],[R] to move. [.] to plot, [ ] to erase, [S] to stop."
	X1061 FOR I=1 TO SIZE+1
	X1062 LOCATE RR+I,CC:PRINT "|";:LOCATE RR+I,CC+17:PRINT "|";
	X1063 LOCATE RR,CC+I:PRINT "-";:LOCATE RR+17,CC+I:PRINT"-";
	X1064 NEXT
	X1070 LOCATE ROW+RR,CLM+CC
	X1080 A$=INKEY$:IF A$="" THEN 1080
	X1090 IF A$="U" THEN ROW=ROW-1
	X1100 IF A$="D" THEN ROW=ROW+1
	X1110 IF A$="R" THEN CLM=CLM-1
	X1120 IF A$="L" THEN CLM=CLM+1
	X1130 IF CLM > SIZE THEN CLM=SIZE
	X1140 IF CLM < 1 THEN CLM=1
	X1160 IF ROW < 1 THEN ROW=1
	X1170 IF ROW > SIZE THEN ROW=SIZE
1171 LOCATE 5,5:PRINT "ROW=";ROW;" CLM=";CLM;
	X1190 LOCATE ROW+RR,CLM+CC
	X1191 IF A$="." THEN PRINT"*":LOCATE ROW+RR,CLM+CC:IMAGE(ROW,CLM)=1
	X1194 IF A$=" " THEN PRINT" ":LOCATE ROW+RR,CLM+CC:IMAGE(ROW,CLM)=0
	X1196 IF A$="S" THEN LOCATE 10,1:PRINT"Object completed":GOTO 1210
	X1205 GOTO 1080
	X1210 PRINT "ONE MOMENT...":RETURN
	X1999'
	X2000 ' Calculate an SCAN digit address into NEURALNET()
	X2001 ' by scanning any 8 cells of IMAGE() at random
	X2002 ' If a cell has an active pixel, it is considered on,
	X2003 ' else it is considered off. Hence a SCAN digit binary address.
	X2005 INDEX=SIZE*SIZE*(I-1)
	X2010 FOR J=1 TO SCAN
	X2020 FIRST=INT(RND*SIZE+1):SECOND=INT(RND*SIZE+1)
	X2040 INDEX=INDEX+IMAGE(FIRST,SECOND)*2^J
	X2050 NEXT:RETURN
	X2999 '
	X3000 PRINT Q$;:INPUT " ";Q$
	X3010 Q$=LEFT$(Q$,1):RETURN
	X
	X
	XListing 2
	X
	X10' Simulation of a Simple Neural Net 
	X20 ' IMAGE      = the sensory grid array
	X30 ' NEURALNET  = the associative net - neural interconnections
	X40 ' SIZE^2     = number of cells in the sensory grid
	X50 ' SCAN       = number of cells required to construct an 8-bit address
	X60 '              into the array NEURALNET()
	X70 ' LSCAN      = the number of iterations for scanning the sensory
	X80 '              grid - i.e. we look at scan cells at random 
	X90 '              loopscan times
	X100 DEFINT A-Z:SIZE=16:SCAN=8:LSCAN=(SIZE^2)/SCAN
	X120 DIM IMAGE(SIZE,SIZE),NEURALNET(LSCAN*(SIZE^2),2)
	X130 GOSUB 6000:'                                   Intro message
	X140 '
	X150 '************ Training session. ************
	X155 RANDOMIZE 5:'                                  Init random
	X160 CLS: LOCATE 10,50:PRINT"===    TRAINING SESSION    ===="
	X161 LOCATE 12,50:'                                 Put up a prompt
	X162 Q$="Automatic training"
	X163 GOSUB 3000:'                                   Select Training
	X164 IF Q$<>"Y" THEN 170:'                          Manual Training
	X165 GOSUB 4000:GOTO 400:'                          Automatic Training
	X166 '
	X170 LOCATE 11,50
	X175 INPUT"Draw class 1 or 2";CLASS:'               Select a class
	X180 IF CLASS>2 THEN CLASS=2:'                      for this object
	X190 IF CLASS<2 THEN CLASS=1:'                      within range
	X200 GOSUB 1000:'                                   Draw an object 
	X210 FOR I=1 TO LSCAN:'                             Calculate 
	X220   GOSUB 2000:'                                 indicies into
	X230   NEURALNET(INDEX,CLASS)=1:'                   neuralnet
	X240 NEXT:'                                         for this class
250 LOCATE 2,5
	X260 Q$="Want to conduct more training":'           loop through more
	X270 GOSUB 3000:IF Q$="Y" THEN 160:'                training 
	X271 '
	X272 '
	X273 '
	X400 ' *********** Classification Session ************
	X420 CLS:LOCATE 10,50:PRINT"=== CLASSIFICATION SESSION ===="
	X430 '
	X431 RANDOMIZE 5:'                                  Init random
	X440 GOSUB 1000:'                                   Draw an object
	X450 MEMBER=0:NONMEMBER=0:'                         Init member count
	X500 FOR I=1 TO LSCAN:'                             Calculate 
	X510   GOSUB 2000:'                                 indicies 
	X540   IF NEURALNET(INDEX,1)=1 THEN MEMBER=MEMBER+1
	X550   IF NEURALNET(INDEX,2)=1 THEN NONMEMBER=NONMEMBER+1
	X551   IF NEURALNET(INDEX,1)=0 AND NEURALNET(INDEX,2)=0 THEN 553
	X552   GOTO 560
	X553   I=I-1:'                                       Null class found
	X560 NEXT
	X571 LOCATE 23,2:PRINT SPC(78)
	X573 LOCATE 12,50: PRINT"Ratio is ";MEMBER;"/";NONMEMBER
	X574 LOCATE 13,50: PRINT " favouring class ";
	X576 IF MEMBER<NONMEMBER THEN 580
	X577 PRINT"Two.";:GOTO 588
	X580 PRINT"One.";
	X588 IF ABS(MEMBER-NONMEMBER)>1 THEN 590
	X589 LOCATE 9,50:?" * Ratios is close. *"
	X590 LOCATE 14,50:Q$="Classify another object":GOSUB 3000
	X600 IF Q$="Y" THEN 400
	X601'
	X610 CLS:?:?:?:?:Q$="Want to see NEURALNET":GOSUB 3000
	X620 IF Q$="Y" THEN GOSUB 7000
	X670 ?"Emptying Neural Network..."
	X671 FOR I=1 TO LSCAN*(SIZE^2)
	X680   FOR J=1 TO 2
	X690   NEURALNET(I,J)=0
	X691   NEXT
	X692 NEXT:GOTO 150
	X998 '
	X999 '
	X1000 ' *********** Interactive Object drawing ***********
	X1002 FOR I=1 TO SIZE:FOR J=1 TO SIZE:IMAGE(I,J)=0:NEXT:NEXT
	X1005 RR=5:CC=20:ROW=1:CLM=1
	X1006 LOCATE 23,2
	X1010 PRINT"[D],[U],[L],[R] to move. [.] to plot, [ ] to erase, [S] to stop."
	X1061 FOR I=1 TO SIZE+1
	X1062   LOCATE RR+I,CC:PRINT "|";:LOCATE RR+I,CC+17:PRINT "|";
	X1063   LOCATE RR,CC+I:PRINT "-";:LOCATE RR+17,CC+I:PRINT"-";
	X1064 NEXT
	X1070 LOCATE ROW+RR,CLM+CC
	X1080 A$=INKEY$:IF A$="" THEN 1080
	X1090 IF A$="U" THEN ROW=ROW-1
	X1100 IF A$="D" THEN ROW=ROW+1
	X1110 IF A$="R" THEN CLM=CLM-1
1120 IF A$="L" THEN CLM=CLM+1
	X1130 IF CLM > SIZE THEN CLM=SIZE
	X1140 IF CLM < 1 THEN CLM=1
	X1160 IF ROW < 1 THEN ROW=1
	X1170 IF ROW > SIZE THEN ROW=SIZE
	X1171 LOCATE 5,5:PRINT "ROW=";ROW;" CLM=";CLM;
	X1190 LOCATE ROW+RR,CLM+CC
	X1191 IF A$="." THEN PRINT CHR$(219):LOCATE ROW+RR,CLM+CC:IMAGE(CLM,ROW)=1
	X1194 IF A$=" " THEN PRINT" ":LOCATE ROW+RR,CLM+CC:IMAGE(CLM,ROW)=0
	X1196 IF A$="S" THEN LOCATE 10,1:PRINT"Object completed":GOTO 1210
	X1205 GOTO 1080
	X1210 PRINT "ONE MOMENT...":RETURN
	X1998'
	X1999'
	X2000 ' Calculate a SCAN digit address into NEURALNET()
	X2001 ' by scanning any SCAN cells of IMAGE() at random
	X2002 ' If a cell has an active pixel, it is considered on,
	X2003 ' else it is considered off. Hence a SCAN digit binary address.
	X2004 ' Resultant index is in the range 0 and up in size^2 
	X2005 ' blocks. The address within a block is determined by 
	X2006 ' the image(a,b) as a power of 2 (line 2040).
	X2009 INDEX=(SIZE^2)*(I-1)
	X2010 FOR J=0 TO SCAN-1
	X2020   FIRST=INT(RND*SIZE)+1:SECOND=INT(RND*SIZE)+1
	X2040   INDEX=INDEX+IMAGE(FIRST,SECOND)*2^J
	X2050 NEXT:RETURN
	X2999 '
	X3000' Issue a prompt using q$, and return q$=Y/N
	X3001 PRINT Q$;:INPUT Q$
	X3010 Q$=LEFT$(Q$,1):
	X3050 RETURN
	X3099'
	X4000' Train the neural net on vertical vs. horizontal lines
	X4001 ?"Note: It takes a while to scan each object, but more "
	X4002 ?"      ojects mean more accurate classification."
	X4003 CLASS=1:RANDOMIZE 5
	X4004 INPUT"How many objects of Class One ";KNT
	X4010     FOR KLOOP=1 TO KNT:CLS: LOCATE 10,30:?KLOOP;" of ";KNT
	X4011     FOR I=1 TO SIZE+1
	X4012       LOCATE I,SIZE:?"|";:LOCATE SIZE,I:? "-";
	X4013     NEXT
	X4014     ?"Object Class One";
	X4015 '     Create one horizontal line of length k
	X4019       FOR I=1 TO SIZE:FOR J=1 TO SIZE:IMAGE(I,J)=0:NEXT:NEXT
	X4020       KLEN=INT(RND*SIZE+1):IF KLEN<2 THEN 4020
	X4021       MPOS=INT(RND*SIZE)+1:NPOS=INT(RND*SIZE)+1
	X4022       IF NPOS+KLEN>SIZE THEN 4020
	X4023       IF NPOS>=KLEN THEN 4020
	X4025       FOR A=NPOS TO KLEN
	X4026          IMAGE(A,MPOS)=1:LOCATE MPOS,A:?CHR$(223);
	X4027       NEXT
	X4029       'Now place this image into nerualnet
	X4030       LOCATE 11,30:?"Scanning object"
	X4032       LOCATE 12,30:?"Len=";KLEN;" Start=";NPOS;",";MPOS;
	X4090       FOR I=1 TO LSCAN:GOSUB 2000
4091           NEURALNET(INDEX,CLASS)=1
	X4092       NEXT
	X4094     NEXT:CLS
	X4100 INPUT"How many objects of Class Two ";KNT
	X4105 CLASS=2:RANDOMIZE 5
	X4110      FOR KLOOP=1 TO KNT:CLS:LOCATE 10,30:?KLOOP;" of ";KNT
	X4111     FOR I=1 TO SIZE+1
	X4112       LOCATE I,SIZE:?"|";:LOCATE SIZE,I:? "-";
	X4113     NEXT
	X4114     ?"Object Class Two";
	X4120       FOR I=1 TO SIZE:FOR J=1 TO SIZE:IMAGE(I,J)=0:NEXT:NEXT
	X4130       KLEN=INT(RND*SIZE+1):IF KLEN<2 THEN 4130
	X4135       MPOS=INT(RND*SIZE)+1:NPOS=INT(RND*SIZE)+1
	X4140       IF NPOS+KLEN>SIZE THEN 4130
	X4141       IF NPOS>=KLEN THEN 4130
	X4145       FOR A=NPOS TO KLEN
	X4150          IMAGE(MPOS,A)=1:LOCATE A,MPOS:?CHR$(219);
	X4153       NEXT
	X4154       'Now place this image into nerualnet
	X4155       LOCATE 11,30:?"Scanning object"
	X4156       LOCATE 12,30:?"Len=";KLEN;" Start=";NPOS;",";MPOS;
	X4160       FOR I=1 TO LSCAN:GOSUB 2000
	X4170           NEURALNET(INDEX,CLASS)=1
	X4180       NEXT
	X4190     NEXT:CLS
	X4200 RETURN
	X4998'
	X4999'
	X6000' Put up an intro message
	X6010 CLS:PRINT"  This program demonstrates how a very simple"
	X6040 PRINT"pecpeptron is capable of analysing visual information."
	X6045 PRINT:PRINT:PRINT
	X6050 PRINT"  Proceed as follows: "
	X6051 PRINT:PRINT
	X6060 PRINT" 1) Draw an object and decide if that object is a member of"
	X6070 PRINT"    a ojbect class one or two. Try vertical versus"
	X6080 PRINT"    horizontal lines to start."
	X6081 PRINT" 2) Train the neural net to recognize objects"
	X6082 PRINT"    of a particular class by drawing various objects"
	X6083 PRINT"    from both classes. (This may be done automatically)."
	X6084 PRINT" 3) Present various objects to the net, (some"
	X6085 PRINT"    old objects may be used, as well as those that it"
	X6086 PRINT"    has never seen before), and see how successfully it"
	X6087 PRINT"    classifies new ojects as belonging to the correct class."
	X6088 PRINT"    This simple simulation will make mistakes, but should"
	X6089 PRINT"    perform better or even much better than at random."
	X6090 PRINT:PRINT
	X6091 Q$="Ready.":GOSUB 3000:CLS
	X6100 RETURN
	X6999'
	X7000' Display the contents of the neural network
	X7030 K=0:KK=0:KZ=0
	X7031 FOR I=1 TO LSCAN*SIZE^2
	X7040   FOR J=1 TO 2
	X7050     A=NEURALNET(I,J):IF A=1 THEN ?"*"; ELSE ?".";
7060     K=K+1:IF K>SIZE THEN K=0:KZ=KZ+1:?"  ";
	X7061     IF KZ>3 THEN KZ=0:?:KK=KK+1
	X7062     IF KK>SIZE THEN KK=0:?
	X7065   NEXT
	X7066 NEXT
	X7070 RETURN
	X
	X
echo shar: "a missing newline was added to 'PERCEP.JAN'"
echo shar: "74 control characters may be missing from 'PERCEP.JAN'"
SHAR_EOF
if test 13440 -ne "`wc -c < 'PERCEP.JAN'`"
then
	echo shar: "error transmitting 'PERCEP.JAN'" '(should have been 13440 characters)'
fi
fi
exit 0
#	End of shell archive
-- 
---------------
C'est la vie, C'est la guerre, C'est la pomme de terre
Mail:	Imagen Corp. 2650 San Tomas Expressway Santa Clara, CA 95052-8101 
UUCP:	...{decvax,ucbvax}!decwrl!imagen!turner      AT&T: (408) 986-9400