zip ddocall dtimer dtimes dCTYPE dmisc dqsort dTK dASCII dMATH dstandiodprimitidindex x >ÿ6pÌ+ ò>ÿ'Dp(ÜÉ>ÿÆ{T ÿáµÛ ÀÁ>ÿQÀ ÿ"¹U ÿM´| ÿ³¶° µ>ÿ÷ >ÿè½ $copy DFS::2.D.zip zip._rif.zip $copy DFS::2.D.docall zip.docall $copy DFS::2.D.timer zip._c.timer $copy DFS::2.D.times zip._aof.timer $copy DFS::2.D.CTYPE zip._h.CTYPE $copy DFS::2.D.misc zip._cmd.misc $copy DFS::2.D.qsort zip._pro.qsort $copy DFS::2.D.TK zip._h.TK $copy DFS::2.D.ASCII zip._h.ASCII $copy DFS::2.D.MATH zip._h.MATH $copy DFS::2.D.standio zip._zap.standio $copy DFS::2.D.primiti zip._aof.primitive PbE2 primitive 1985-08-28 12:38:29 Lattice Logic C 2.2-2.33-2.6 unifyatomic primhandle clref2 _C_handler fatality processortrap fatality unchain dealloc unifyatomic prseetell prseentold getch putch compare tokenread tokenalpha prcom1 prcom3 prcom0 prcm11 tokenother tokenput % longjmp & findfunct ( findproc ) improc , cvtboxlis - cvtintlis . cvtlisint / cvtlisbox 0 findatom 1 saveimage 2 restimage 3 processortrap TRTOP currsee currtell clref M1 clatom ! clarity " chtype # T1 $ jump_env ' modptr * modstk + syswords |סð ëÁ|Ç¡` |êhÇ¡p :WÁ|Wà ÿÿÿG± unifyatomic >|ô£ claimclause $$0L À|k@ |4¦ | doerase 8ßÀ| ~ xסð ëÁxÇ¡` xêh+¦ ÿÿÿx×µ ëÅx_¹" NwÀxÎÏÀl lêh߸×Ål" lêh_¸×Ål" lêhÎ ÆT`×Á`×} ×Á`ÎÝ} ×Á`ÎÝ} ×Á`ÎÝ} ×Á`ÎÝ} ~ lסð ëÁlÇ¡` lêhÎ À`×E ~(lסð ëÁlÇ¡` WÀl×À`ÎÍ ^,lסð ëÁlÇ¡` WÀlWÁ`ÎM n0lסð ëÁlÇ¡` V4lסð ëÁlÇ¡` ~ lסð ëÁlÇ¡` lêh×Ålë¥ ~ lסð ëÁlÇ¡` f$hסð ëÁhÇ¡` hêh×Åh×Ål" ǽÎÏ ~ xסð ëÁxÇ¡` xêh×Åxë¥ ÿÿÿ" h×Ål_¹" ×Åhß¹" ~ lסð ëÁlÇ¡` lêh×Ål" ~ lסð ëÁlÇ¡` lêh_ÀHÇ¡@ ~ lסð ëÁlÇ¡` lêh×Ål" ~ lסð ëÁlÇ¡` lêh×Ål" _À|ê _À|ê xסð ëÁxÇ¡` v$tסð ëÁtÇ¡` têh×Åtë¥ ÿÿÿ×Åx" _À|ê x×Áx ¿ò×=߸" "_¸ß¸" ;×µ# ߸çµ$ "%ǽê ~ lסð ëÁlÇ¡` lê¿è f$xסð ëÁxÇ¡` xê¿è߸×Åxë¥ ÿÿÿ×Ål"&|¥ô߸ױ' "(|¥ô ~(hסð ëÁhÇ¡` hê¿èÎÏÀh WÁl[ ~ lסð ëÁlÇ¡` lê¿è×° ^$xסð ëÁxÇ¡` xê¿è V(hסð ëÁhÇ¡` hê¿è߸×Åxë¥ ÿÿÿ×Ål"&|¥ô×Åh× ")Ç½× ßÀp×± ~ lסð ëÁlÇ¡` lê¿è'¶* ×Ád'~ dÇÃl _Àpê¿ä_Àx )W°' z '® '®?x×Åx_¹" n lW¡ð kÁlG¡` lê¿è p×°' §]|' ³_À|ê _¹çµ$ "%ǽê n_ÀxW± n lW¡ð kÁlG¡` lê¿è Ål+< &W¡ð kÁlG¡P lê¿Ù_À|ê¿Ó 1×Åx_¹" _À|W± n$lW¡ð kÁlG¡` lê¿èG¡p lê¿è WÀl ×Ål",Ç ×Ål"-Ç lê¿è primhandle p8LLLL ,( 8 $<0@@ Y×Ål".Ç 5×Ål"/Ç )"0× _À|ê D_À| lê¿è ÎÏÀl ÎØå³" M_À| lê¿è Àl×E _¸_¹" U_À| lê¿è Àl×U ߸_¹" index succeed primitive 16 vararg 9 vararg 13 depart 5 3 exit xrtable f var 2 p char_class 2 p tokenread 3 f = 2 p clause read_tokens 2 12 enter 12 immed 32 firvararg 10 firvararg 11 call 0 vararg 10 constnil vararg 10 call 1 cut 12 vararg 9 vararg 10 proequal vararg 8 glovar 11 proequal exit xrtable p read_tokens 3 p append 3 endxrtable endclause clause read_tokens 2 10 keyf '.' 2 conslist functor 0 1 constant 1 pop constnil pop constnil return 10 xrtable f atom 1 a end_of_file endxrtable endclause clause read_tokens 3 11 keyi 26 immed 26 void lastconslist functor 0 1 constant 1 pop constnil enter 11 cut 11 exit xrtable f atom 1 a end_of_file endxrtable endclause clause read_tokens 3 14 enter 14 eval 8 11 pushv 11 pushb 32 cut 14 vararg 8 firvararg 12 firvararg 13 call 0 glovar 13 vararg 9 vararg 10 depart 1 3 exit xrtable p tokenread 3 p read_tokens 3 endxrtable endclause clause read_tokens 3 13 keyi 37 immed 37 enter 13 cut 13 immed 37 firvararg 11 firvararg 12 call 0 glovar 12 vararg 9 vararg 10 depart 1 3 exit xrtable p tokenread 3 p read_tokens 3 endxrtable endclause clause read_tokens 3 13 keyi 47 immed 47 enter 13 cut 13 immed 47 firvararg 11 firvararg 12 call 0 glovar 11 glovar 12 vararg 9 vararg 10 depart 1 4 exit xrtable p tokenread 3 p after_sl 4 endxrtable endclause clause read_tokens 3 13 keyi 33 immed 33 void lastconslist functor 0 1 constant 1 pop firstvar 11 enter 13 cut 13 firvararg 12 call 2 glovar 12 vararg 9 vararg 11 depart 3 3 exit xrtable f atom 1 a ! p get0 1 p read_after_atom 3 endxrtable endclause clause read_tokens 3 13 keyi 40 immed 40 void lastconslist constant 0 firstvar 11 enter 13 cut 13 firvararg 12 call 1 glovar 12 vararg 9 vararg 11 depart 2 3 exit xrtable a ' (' p get0 1 p read_tokens 3 endxrtable endclause clause read_tokens 3 13 keyi 41 immed 41 void lastconslist constant 0 firstvar 11 enter 13 cut 13 firvararg 12 call 1 glovar 12 vararg 9 vararg 11 depart 2 3 exit xrtable a ')' p get0 1 p read_tokens 3 endxrtable endclause clause read_tokens 3 13 keyi 44 immed 44 void lastconslist constant 0 firstvar 11 enter 13 cut 13 firvararg 12 call 1 glovar 12 vararg 9 vararg 11 depart 2 3 exit xrtable a ',' p get0 1 p read_tokens 3 endxrtable endclause clause read_tokens 3 13 keyi 59 immed 59 void lastconslist functor 0 1 constant 1 pop firstvar 11 enter 13 cut 13 firvararg 12 call 2 glovar 12 vararg 9 vararg 11 depart 3 3 exit xrtable f atom 1 a ; p get0 1 p read_tokens 3 endxrtable endclause clause read_tokens 3 13 keyi 91 immed 91 void lastconslist constant 0 firstvar 11 enter 13 cut 13 firvararg 12 call 1 glovar 12 vararg 9 vararg 11 depart 2 3 exit xrtable a '[' p get0 1 p read_tokens 3 endxrtable endclause clause read_tokens 3 13 keyi 93 immed 93 void lastconslist constant 0 firstvar 11 enter 13 cut 13 firvararg 12 call 1 glovar 12 vararg 9 vararg 11 depart 2 3 exit xrtable a ']' p get0 1 p read_tokens 3 endxrtable endclause clause read_tokens 3 13 keyi 123 immed 123 void lastconslist constant 0 firstvar 11 enter 13 cut 13 firvararg 12 call 1 glovar 12 vararg 9 vararg 11 depart 2 3 exit xrtable a '{' p get0 1 p read_tokens 3 endxrtable endclause clause read_tokens 3 13 keyi 124 immed 124 void lastconslist constant 0 firstvar 11 enter 13 cut 13 firvararg 12 call 1 glovar 12 vararg 9 vararg 11 depart 2 3 exit xrtable a '|' p get0 1 p read_tokens 3 endxrtable endclause clause read_tokens 3 13 keyi 125 immed 125 void lastconslist constant 0 firstvar 11 enter 13 cut 13 firvararg 12 call 1 glovar 12 vararg 9 vararg 11 depart 2 3 exit xrtable a '}' p get0 1 p read_tokens 3 endxrtable endclause clause read_tokens 3 13 keyi 46 immed 46 enter 13 cut 13 immed 46 firvararg 11 firvararg 12 call 0 glovar 11 glovar 12 vararg 9 vararg 10 depart 1 4 exit xrtable p tokenread 3 p after_fs 4 endxrtable endclause clause read_tokens 3 14 keyi 34 immed 34 void lastconslist functor 0 1 firstvar 11 pop firstvar 12 enter 14 cut 14 vararg 11 immed 34 firvararg 13 call 1 glovar 13 vararg 9 vararg 12 depart 2 3 exit xrtable f string 1 p read_string 3 p read_tokens 3 endxrtable endclause clause read_tokens 3 14 keyi 39 immed 39 void lastconslist functor 0 1 firstvar 11 pop firstvar 12 enter 14 cut 14 immed 39 vararg 11 firvararg 13 call 1 glovar 13 vararg 9 vararg 12 depart 2 3 exit xrtable f atom 1 p tokenread 3 p read_after_atom 3 endxrtable endclause clause read_tokens 3 17 voidn 2 lastconslist functor 0 2 firstvar 11 firstvar 12 pop firstvar 13 enter 17 vararg 8 firvararg 14 call 1 eval 14 15 pushb 2 pushv 15 pushv 15 pushb 3 cut 17 vararg 8 vararg 12 firvararg 16 call 2 vararg 9 lastfunctor 3 2 var 12 var 11 call 4 cut 17 glovar 16 vararg 9 vararg 13 depart 5 3 exit xrtable f var 2 p char_class 2 p tokenread 3 f = 2 p read_lookup 2 p read_tokens 3 endxrtable endclause clause read_tokens 3 15 voidn 2 lastconslist functor 0 1 firstvar 11 pop firstvar 12 enter 15 eval 8 13 pushb 48 pushv 13 pushv 13 pushb 57 cut 15 vararg 8 vararg 11 firvararg 14 call 1 glovar 14 vararg 9 vararg 12 depart 2 3 exit xrtable f integer 1 p tokenread 3 p read_tokens 3 endxrtable endclause clause read_tokens 3 15 voidn 2 lastconslist functor 0 1 firstvar 11 pop firstvar 12 enter 15 eval 8 13 pushv 13 pushb 97 pushv 13 pushb 122 cut 15 vararg 8 vararg 11 firvararg 14 call 1 glovar 14 vararg 9 vararg 12 depart 2 3 exit xrtable f atom 1 p tokenread 3 p read_after_atom 3 endxrtable endclause clause read_tokens 3 14 voidn 2 lastconslist functor 0 1 firstvar 11 pop firstvar 12 enter 14 vararg 8 vararg 11 firvararg 13 call 1 glovar 13 vararg 9 vararg 12 depart 2 3 exit xrtable f atom 1 p tokenread 3 p read_after_atom 3 endxrtable endclause clause read_after_atom 3 13 keyi 40 immed 40 void lastconslist constant 0 firstvar 11 enter 13 cut 13 firvararg 12 call 1 glovar 12 vararg 9 vararg 11 depart 2 3 exit xrtable a '(' p get0 1 p read_tokens 3 endxrtable endclause clause read_after_atom 3 11 enter 11 vararg 8 vararg 9 vararg 10 depart 0 3 exit xrtable p read_tokens 3 endxrtable endclause clause read_string 3 12 enter 12 firvararg 11 call 0 glovar 11 vararg 8 vararg 9 vararg 10 depart 1 4 exit xrtable p get0 1 p read_string 4 endxrtable endclause clause read_string 4 12 keyi 26 immed 26 constnil void immed 26 enter 12 cut 12 exit xrtable endxrtable endclause clause read_string 4 13 voidn 2 var 8 enter 13 firvararg 12 call 0 glovar 12 vararg 8 vararg 9 vararg 11 depart 1 4 exit xrtable p get0 1 p more_string 4 endxrtable endclause clause read_string 4 13 void conslist var 8 firstvar 12 pop enter 13 vararg 12 vararg 10 vararg 11 depart 0 3 exit xrtable p read_string 3 endxrtable endclause clause more_string 4 13 void var 8 conslist var 8 firstvar 12 pop enter 13 cut 13 vararg 12 vararg 8 vararg 11 depart 0 3 exit xrtable p read_string 3 endxrtable endclause clause more_string 4 12 voidn 2 constnil var 8 return 12 xrtable endxrtable endclause clause after_sl 4 12 enter 12 proint 8 cut 12 vararg 9 vararg 10 vararg 11 depart 0 3 exit xrtable p read_tokens 3 endxrtable endclause clause after_sl 4 13 voidn 3 lastconslist functor 0 1 var 8 pop firstvar 12 enter 13 vararg 9 vararg 10 vararg 12 depart 1 3 exit xrtable f atom 1 p read_after_atom 3 endxrtable endclause clause after_fs 4 12 void immed 26 void constnil enter 12 cut 12 exit xrtable endxrtable endclause clause after_fs 4 13 voidn 3 constnil enter 13 eval 9 12 pushv 12 pushb 32 cut 13 exit xrtable endxrtable endclause clause after_fs 4 13 voidn 3 lastconslist functor 0 1 var 8 pop firstvar 12 enter 13 vararg 9 vararg 10 vararg 12 depart 1 3 exit xrtable f atom 1 p read_after_atom 3 endxrtable endclause clause read_lookup 2 10 void lastfunctor 0 2 constant 1 enter 10 cut 10 exit xrtable f = 2 a '_' endxrtable endclause clause read_lookup 2 10 keyf '.' 2 conslist var 9 void pop enter 10 cut 10 exit xrtable endxrtable endclause clause read_lookup 2 11 keyf '.' 2 conslist void firstvar 10 pop enter 11 vararg 10 vararg 9 depart 0 2 exit xrtable p read_lookup 2 endxrtable endclause clause read 1 10 enter 10 vararg 8 glofirvar 9 depart 0 2 exit xrtable p read 2 endxrtable endclause clause read 2 12 enter 12 call 0 firvararg 10 vararg 9 call 1 vararg 10 firvararg 11 call 2 cut 12 vararg 8 glovar 11 proequal exit xrtable p repeat 0 p read_tokens 2 p read_catch 2 endxrtable endclause clause read_catch 2 11 enter 11 vararg 8 constant 0 vararg 9 firvararg 10 call 1 glovar 10 depart 2 1 exit xrtable i 1200 p read 4 p all_read 1 endxrtable endclause clause read_catch 2 10 enter 10 vararg 8 depart 0 1 exit xrtable p syntax_error 1 endxrtable endclause clause all_read 1 9 keya '[]' constnil enter 9 cut 9 exit xrtable endxrtable endclause clause all_read 1 9 enter 9 immed 1 constant 0 vararg 8 depart 1 3 exit xrtable a no_culprit p syntax_error 3 endxrtable endclause clause expect 3 11 void conslist var 8 var 10 pop enter 11 cut 11 exit xrtable endxrtable endclause clause expect 3 11 enter 11 immed 2 vararg 8 vararg 9 depart 0 3 exit xrtable p syntax_error 3 endxrtable endclause clause read 4 14 keyf '.' 2 conslist firstvar 12 firstvar 13 pop enter 14 vararg 12 vararg 13 vararg 9 vararg 10 vararg 11 depart 0 5 exit xrtable p read 5 endxrtable endclause clause read 4 12 keya '[]' constnil enter 12 immed 3 constant 0 constnil depart 1 3 exit xrtable a no_culprit p syntax_error 3 endxrtable endclause clause read 5 14 keyf var 2 functor 0 2 firstvar 13 void pop enter 14 cut 14 vararg 9 vararg 13 vararg 10 vararg 11 vararg 12 depart 1 5 exit xrtable f var 2 p exprtl0 5 endxrtable endclause clause read 5 17 keyf atom 1 functor 0 1 constant 1 pop conslist functor 2 1 firstvar 13 pop firstvar 14 pop enter 17 eval 13 15 pushv 15 neg firstresult 16 cut 17 vararg 14 vararg 16 vararg 10 vararg 11 vararg 12 depart 3 5 exit xrtable f atom 1 a - f integer 1 p exprtl0 5 endxrtable endclause clause read 5 21 keyf atom 1 functor 0 1 firstvar 13 pop conslist constant 1 firstvar 14 pop enter 21 cut 21 vararg 14 constant 2 firvararg 15 firvararg 16 call 3 vararg 16 firvararg 17 firvararg 18 immed 1 firvararg 19 call 4 firvararg 20 vararg 13 vararg 19 profunctor immed 1 vararg 20 vararg 15 proarg vararg 17 immed 2 vararg 20 call 5 cut 21 glovar 18 glovar 20 vararg 10 vararg 11 vararg 12 depart 6 5 exit xrtable f atom 1 a '(' i 999 p read 4 p read_args 5 p fillrest 3 p exprtl0 5 endxrtable endclause clause read 5 18 keyf atom 1 functor 0 1 firstvar 13 pop enter 18 vararg 13 firvararg 14 firvararg 15 firvararg 16 firvararg 17 constant 1 call 2 cut 18 vararg 13 glovar 15 glovar 14 vararg 9 vararg 10 vararg 11 vararg 12 depart 3 7 exit xrtable f atom 1 a prefix p current_op 6 p after_prefix_op 7 endxrtable endclause clause read 5 14 keyf atom 1 functor 0 1 firstvar 13 pop enter 14 cut 14 vararg 9 vararg 13 vararg 10 vararg 11 vararg 12 depart 1 5 exit xrtable f atom 1 p exprtl0 5 endxrtable endclause clause read 5 14 keyf integer 1 functor 0 1 firstvar 13 pop enter 14 cut 14 vararg 9 vararg 13 vararg 10 vararg 11 vararg 12 depart 1 5 exit xrtable f integer 1 p exprtl0 5 endxrtable endclause clause read 5 14 keya '[' constant 0 conslist constant 1 firstvar 13 pop enter 14 cut 14 vararg 13 constnil vararg 10 vararg 11 vararg 12 depart 2 5 exit xrtable a '[' a ']' p exprtl0 5 endxrtable endclause clause read 5 17 keya '[' constant 0 enter 17 cut 17 vararg 9 constant 1 firvararg 13 firvararg 14 call 2 vararg 14 firvararg 15 firvararg 16 call 3 cut 17 glovar 16 conslist var 13 var 15 poparg vararg 10 vararg 11 vararg 12 depart 4 5 exit xrtable a '[' i 999 p read 4 p read_list 3 p exprtl0 5 endxrtable endclause clause read 5 16 keya '(' constant 0 enter 16 cut 16 vararg 9 constant 1 firvararg 13 firvararg 14 call 2 constant 3 vararg 14 firvararg 15 call 4 cut 16 glovar 15 glovar 13 vararg 10 vararg 11 vararg 12 depart 5 5 exit xrtable a '(' i 1200 p read 4 a ')' p expect 3 p exprtl0 5 endxrtable endclause clause read 5 16 keya ' (' constant 0 enter 16 cut 16 vararg 9 constant 1 firvararg 13 firvararg 14 call 2 constant 3 vararg 14 firvararg 15 call 4 cut 16 glovar 15 glovar 13 vararg 10 vararg 11 vararg 12 depart 5 5 exit xrtable a ' (' i 1200 p read 4 a ')' p expect 3 p exprtl0 5 endxrtable endclause clause read 5 14 keya '{' constant 0 conslist constant 1 firstvar 13 pop enter 14 cut 14 vararg 13 constant 2 vararg 10 vararg 11 vararg 12 depart 3 5 exit xrtable a '{' a '}' a '{}' p exprtl0 5 endxrtable endclause clause read 5 16 keya '{' constant 0 enter 16 cut 16 vararg 9 constant 1 firvararg 13 firvararg 14 call 2 constant 3 vararg 14 firvararg 15 call 4 cut 16 glovar 15 functor 5 1 var 13 poparg vararg 10 vararg 11 vararg 12 depart 6 5 exit xrtable a '{' i 1200 p read 4 a '}' p expect 3 f '{}' 1 p exprtl0 5 endxrtable endclause clause read 5 14 keyf string 1 functor 0 1 firstvar 13 pop enter 14 cut 14 vararg 9 vararg 13 vararg 10 vararg 11 vararg 12 depart 1 5 exit xrtable f string 1 p exprtl0 5 endxrtable endclause clause read 5 13 enter 13 immed 4 vararg 8 vararg 9 depart 0 3 exit xrtable p syntax_error 3 endxrtable endclause clause fillrest 3 11 keya '[]' constnil voidn 2 return 11 xrtable endxrtable endclause clause fillrest 3 14 keyf '.' 2 conslist firstvar 11 firstvar 12 pop enter 14 vararg 9 vararg 10 vararg 11 proarg vararg 9 firvararg 13 prosucc vararg 12 glovar 13 vararg 10 depart 0 3 exit xrtable p fillrest 3 endxrtable endclause clause read_args 5 18 keyf '.' 2 conslist constant 0 firstvar 13 pop conslist firstvar 14 firstvar 15 pop enter 18 cut 18 vararg 13 constant 1 vararg 14 firvararg 16 call 2 cut 18 vararg 11 firvararg 17 prosucc glovar 16 vararg 15 vararg 10 glovar 17 vararg 12 depart 3 5 exit xrtable a ',' i 999 p read 4 p read_args 5 endxrtable endclause clause read_args 5 13 keyf '.' 2 conslist constant 0 var 10 pop constnil voidn 2 var 11 enter 13 cut 13 exit xrtable a ')' endxrtable endclause clause read_args 5 13 enter 13 immed 5 constant 0 vararg 8 depart 1 3 exit xrtable a no_culprit p syntax_error 3 endxrtable endclause clause read_list 3 15 keyf '.' 2 conslist constant 0 firstvar 11 pop conslist firstvar 12 firstvar 13 pop enter 15 cut 15 vararg 11 constant 1 vararg 12 firvararg 14 call 2 cut 15 glovar 14 vararg 13 vararg 10 depart 3 3 exit xrtable a ',' i 999 p read 4 p read_list 3 endxrtable endclause clause read_list 3 13 keyf '.' 2 conslist constant 0 firstvar 11 pop enter 13 cut 13 vararg 11 constant 1 vararg 9 firvararg 12 call 2 cut 13 constant 3 glovar 12 vararg 10 depart 4 3 exit xrtable a '|' i 999 p read 4 a ']' p expect 3 endxrtable endclause clause read_list 3 11 keyf '.' 2 conslist constant 0 var 10 pop constnil enter 11 cut 11 exit xrtable a ']' endxrtable endclause clause read_list 3 11 enter 11 immed 6 constant 0 vararg 8 depart 1 3 exit xrtable a no_culprit p syntax_error 3 endxrtable endclause clause after_prefix_op 7 17 enter 17 eval 12 15 eval 9 16 pushv 15 pushv 16 cut 17 immed 7 functor 0 2 var 8 var 12 poparg vararg 11 depart 1 3 exit xrtable f ',' 2 p syntax_error 3 endxrtable endclause clause after_prefix_op 7 16 enter 16 vararg 11 firvararg 15 call 0 vararg 15 vararg 9 call 1 glovar 15 vararg 9 vararg 8 vararg 12 vararg 13 vararg 14 depart 2 6 exit xrtable p peepop 2 p prefix_is_atom 2 p exprtl 6 endxrtable endclause clause after_prefix_op 7 18 enter 18 vararg 11 vararg 10 firvararg 15 firvararg 16 call 0 firvararg 17 vararg 8 immed 1 profunctor immed 1 vararg 17 vararg 15 proarg cut 18 glovar 16 vararg 9 glovar 17 vararg 12 vararg 13 vararg 14 depart 1 6 exit xrtable p read 4 p exprtl 6 endxrtable endclause clause peepop 2 12 keyf '.' 2 conslist functor 0 1 firstvar 10 pop conslist constant 1 firstvar 11 pop pop lastconslist functor 0 1 var 10 pop lastconslist constant 1 var 11 enter 10 cut 10 exit xrtable f atom 1 a '(' endxrtable endclause clause peepop 2 16 keyf '.' 2 conslist functor 0 1 firstvar 10 pop firstvar 15 pop lastconslist functor 1 4 var 10 firstvar 11 firstvar 12 firstvar 13 pop var 15 enter 15 vararg 10 vararg 11 vararg 12 vararg 13 glofirvar 14 constant 2 depart 3 6 exit xrtable f atom 1 f infixop 4 a infix p current_op 6 endxrtable endclause clause peepop 2 16 keyf '.' 2 conslist functor 0 1 firstvar 10 pop firstvar 15 pop lastconslist functor 1 3 var 10 firstvar 11 firstvar 12 pop var 15 enter 15 vararg 10 vararg 11 vararg 12 glofirvar 13 glofirvar 14 constant 2 depart 3 6 exit xrtable f atom 1 f postfixop 3 a postfix p current_op 6 endxrtable endclause clause peepop 2 10 void var 8 return 10 xrtable endxrtable endclause clause prefix_is_atom 2 11 keyf '.' 2 conslist firstvar 10 void pop enter 11 vararg 10 vararg 9 depart 0 2 exit xrtable p prefix_is_atom 2 endxrtable endclause clause prefix_is_atom 2 13 keyf infixop 4 functor 0 4 void firstvar 10 voidn 2 pop enter 13 eval 10 11 eval 9 12 pushv 11 pushv 12 exit xrtable f infixop 4 endxrtable endclause clause prefix_is_atom 2 13 keyf postfixop 3 functor 0 3 void firstvar 10 void pop enter 13 eval 10 11 eval 9 12 pushv 11 pushv 12 exit xrtable f postfixop 3 endxrtable endclause clause prefix_is_atom 2 10 keya ')' constant 0 void return 10 xrtable a ')' endxrtable endclause clause prefix_is_atom 2 10 keya ']' constant 0 void return 10 xrtable a ']' endxrtable endclause clause prefix_is_atom 2 10 keya '}' constant 0 void return 10 xrtable a '}' endxrtable endclause clause prefix_is_atom 2 11 keya '|' constant 0 enter 11 eval 9 10 pushi 1 pushv 10 exit xrtable a '|' i 1100 endxrtable endclause clause prefix_is_atom 2 11 keya ',' constant 0 enter 11 eval 9 10 pushi 1 pushv 10 exit xrtable a ',' i 1000 endxrtable endclause clause prefix_is_atom 2 10 keya '[]' constnil void return 10 xrtable endxrtable endclause clause exprtl0 5 23 keyf '.' 2 conslist functor 0 1 firstvar 13 pop firstvar 14 pop enter 23 vararg 13 firvararg 15 firvararg 16 firvararg 17 firvararg 18 constant 1 call 2 vararg 13 firvararg 19 firvararg 20 firvararg 21 firvararg 22 constant 3 call 2 cut 23 disjunct 31 conslist functor 4 4 var 13 var 19 var 20 var 21 poparg var 14 poparg immed 0 vararg 9 vararg 10 vararg 11 vararg 12 depart 5 6 continue 28 endor conslist functor 6 3 var 13 var 15 var 16 poparg var 14 poparg immed 0 vararg 9 vararg 10 vararg 11 vararg 12 depart 5 6 exit xrtable f atom 1 a postfix p current_op 6 a infix f infixop 4 p exprtl 6 f postfixop 3 endxrtable endclause clause exprtl0 5 19 keyf '.' 2 conslist functor 0 1 firstvar 13 pop firstvar 14 pop enter 19 vararg 13 firvararg 15 firvararg 16 firvararg 17 firvararg 18 constant 1 call 2 cut 19 conslist functor 3 4 var 13 var 15 var 16 var 17 poparg var 14 poparg immed 0 vararg 9 vararg 10 vararg 11 vararg 12 depart 4 6 exit xrtable f atom 1 a infix p current_op 6 f infixop 4 p exprtl 6 endxrtable endclause clause exprtl0 5 19 keyf '.' 2 conslist functor 0 1 firstvar 13 pop firstvar 14 pop enter 19 vararg 13 firvararg 15 firvararg 16 firvararg 17 firvararg 18 constant 1 call 2 cut 19 conslist functor 3 3 var 13 var 15 var 16 poparg var 14 poparg immed 0 vararg 9 vararg 10 vararg 11 vararg 12 depart 4 6 exit xrtable f atom 1 a postfix p current_op 6 f postfixop 3 p exprtl 6 endxrtable endclause clause exprtl0 5 17 keyf '.' 2 conslist constant 0 firstvar 13 pop enter 17 eval 10 14 pushv 14 pushi 1 cut 17 vararg 13 constant 1 firvararg 15 firvararg 16 call 2 cut 17 glovar 16 constant 1 functor 3 2 var 9 var 15 poparg vararg 10 vararg 11 vararg 12 depart 4 6 exit xrtable a ',' i 1000 p read 4 f ',' 2 p exprtl 6 endxrtable endclause clause exprtl0 5 17 keyf '.' 2 conslist constant 0 firstvar 13 pop enter 17 eval 10 14 pushv 14 pushi 1 cut 17 vararg 13 constant 1 firvararg 15 firvararg 16 call 2 cut 17 glovar 16 constant 1 functor 3 2 var 9 var 15 poparg vararg 10 vararg 11 vararg 12 depart 4 6 exit xrtable a '|' i 1100 p read 4 f ; 2 p exprtl 6 endxrtable endclause clause exprtl0 5 16 keyf '.' 2 conslist firstvar 13 firstvar 14 pop enter 16 vararg 13 firvararg 15 call 0 cut 16 immed 8 glovar 15 lastconslist var 13 var 14 depart 1 3 exit xrtable p cant_follow_expr 2 p syntax_error 3 endxrtable endclause clause exprtl0 5 13 voidn 3 var 9 var 8 return 13 xrtable endxrtable endclause clause cant_follow_expr 2 10 keyf atom 1 functor 0 1 void pop constant 1 return 10 xrtable f atom 1 a atom endxrtable endclause clause cant_follow_expr 2 10 keyf var 2 functor 0 2 voidn 2 pop constant 1 return 10 xrtable f var 2 a variable endxrtable endclause clause cant_follow_expr 2 10 keyf integer 1 functor 0 1 void pop constant 1 return 10 xrtable f integer 1 a integer endxrtable endclause clause cant_follow_expr 2 10 keyf string 1 functor 0 1 void pop constant 1 return 10 xrtable f string 1 a string endxrtable endclause clause cant_follow_expr 2 10 keya ' (' constant 0 constant 1 return 10 xrtable a ' (' a bracket endxrtable endclause clause cant_follow_expr 2 10 keya '(' constant 0 constant 1 return 10 xrtable a '(' a bracket endxrtable endclause clause cant_follow_expr 2 10 keya '[' constant 0 constant 1 return 10 xrtable a '[' a bracket endxrtable endclause clause cant_follow_expr 2 10 keya '{' constant 0 constant 1 return 10 xrtable a '{' a bracket endxrtable endclause clause exprtl 6 26 keyf '.' 2 conslist functor 0 4 firstvar 14 firstvar 15 firstvar 16 firstvar 17 pop firstvar 18 pop enter 26 eval 11 19 eval 16 20 pushv 19 pushv 20 eval 9 21 eval 15 22 pushv 21 pushv 22 cut 26 vararg 18 vararg 17 firvararg 23 firvararg 24 call 1 firvararg 25 vararg 14 immed 2 profunctor immed 1 vararg 25 vararg 10 proarg immed 2 vararg 25 vararg 23 proarg glovar 24 vararg 16 glovar 25 vararg 11 vararg 12 vararg 13 depart 2 6 exit xrtable f infixop 4 p read 4 p exprtl 6 endxrtable endclause clause exprtl 6 24 keyf '.' 2 conslist functor 0 3 firstvar 14 firstvar 15 firstvar 16 pop firstvar 17 pop enter 24 eval 11 18 eval 16 19 pushv 18 pushv 19 eval 9 20 eval 15 21 pushv 20 pushv 21 cut 24 firvararg 22 vararg 14 immed 1 profunctor immed 1 vararg 22 vararg 10 proarg vararg 17 firvararg 23 call 1 glovar 23 vararg 16 glovar 22 vararg 11 vararg 12 vararg 13 depart 2 6 exit xrtable f postfixop 3 p peepop 2 p exprtl 6 endxrtable endclause clause exprtl 6 19 keyf '.' 2 conslist constant 0 firstvar 14 pop enter 19 eval 11 15 pushv 15 pushi 1 eval 9 16 pushv 16 pushi 1 cut 19 vararg 14 constant 1 firvararg 17 firvararg 18 call 2 glovar 18 constant 1 functor 3 2 var 10 var 17 poparg vararg 11 vararg 12 vararg 13 depart 4 6 exit xrtable a ',' i 1000 p read 4 f ',' 2 p exprtl 6 endxrtable endclause clause exprtl 6 19 keyf '.' 2 conslist constant 0 firstvar 14 pop enter 19 eval 11 15 pushv 15 pushi 1 eval 9 16 pushv 16 pushi 1 cut 19 vararg 14 constant 1 firvararg 17 firvararg 18 call 2 glovar 18 constant 1 functor 3 2 var 10 var 17 poparg vararg 11 vararg 12 vararg 13 depart 4 6 exit xrtable a '|' i 1100 p read 4 f ; 2 p exprtl 6 endxrtable endclause clause exprtl 6 14 voidn 4 var 10 var 8 return 14 xrtable endxrtable endclause clause syntax_error 3 14 enter 14 constant 0 call 1 vararg 8 firvararg 11 call 2 vararg 11 call 1 call 3 vararg 9 call 4 vararg 10 firvararg 12 call 5 constant 6 functor 7 1 var 12 poparg firvararg 13 call 8 cut 14 fail exit xrtable a 'Syntax Error: ' p tokenput 1 p error_message 2 p nl 0 p show_culprit 1 p length 2 a syntax_error f length 1 p recordz 3 endxrtable endclause clause show_culprit 1 9 keya no_culprit constant 0 enter 9 cut 9 exit xrtable a no_culprit endxrtable endclause clause show_culprit 1 9 enter 9 constant 0 call 1 vararg 8 call 2 depart 3 0 exit xrtable a 'Culprit: ' p tokenput 1 p display_token 1 p nl 0 endxrtable endclause clause syntax_error 1 20 enter 20 constant 0 functor 1 1 firstvar 9 poparg firvararg 10 call 2 vararg 10 call 3 vararg 8 firvararg 11 call 4 eval 11 12 eval 9 13 pushv 12 pushv 13 sub firstresult 14 constant 5 call 6 vararg 8 vararg 14 call 7 immed 1 firvararg 15 firvararg 16 firvararg 17 firvararg 18 firvararg 19 call 8 vararg 15 vararg 16 vararg 17 call 9 call 10 cut 20 fail exit xrtable a syntax_error f length 1 p recorded 3 p erase 1 p length 2 a 'Context: ' p tokenput 1 p display_list 2 p get_file_status 6 p read_info 3 p nl 0 endxrtable endclause clause display_list 2 10 void immed 0 enter 10 constant 0 call 1 cut 10 vararg 8 constant 2 depart 3 2 exit xrtable a '<>' p tokenput 1 i 9999 p display_list 2 endxrtable endclause clause display_list 2 13 keyf '.' 2 conslist firstvar 10 firstvar 11 pop enter 13 vararg 10 call 0 immed 32 call 1 firvararg 12 vararg 9 prosucc vararg 11 glovar 12 depart 2 2 exit xrtable p display_token 1 p primput 1 p display_list 2 endxrtable endclause clause display_list 2 10 keya '[]' constnil enter 10 depart 0 0 exit xrtable p nl 0 endxrtable endclause clause display_token 1 10 keyf atom 1 lastfunctor 0 1 firstvar 9 enter 10 cut 10 vararg 9 depart 1 1 exit xrtable f atom 1 p tokenput 1 endxrtable endclause clause display_token 1 10 keyf var 2 lastfunctor 0 2 void firstvar 9 enter 10 cut 10 vararg 9 depart 1 1 exit xrtable f var 2 p tokenput 1 endxrtable endclause clause display_token 1 10 keyf integer 1 lastfunctor 0 1 firstvar 9 enter 10 cut 10 vararg 9 depart 1 1 exit xrtable f integer 1 p tokenput 1 endxrtable endclause clause display_token 1 10 keyf string 1 lastfunctor 0 1 firstvar 9 enter 10 cut 10 vararg 9 depart 1 1 exit xrtable f string 1 p write 1 endxrtable endclause clause display_token 1 9 enter 9 cut 9 vararg 8 depart 0 1 exit xrtable p display 1 endxrtable endclause clause display 1 10 enter 10 vararg 8 constant 0 constant 1 constant 2 glofirvar 9 depart 3 5 exit xrtable a display i 1200 a punct p write_out 5 endxrtable endclause clause print 1 10 enter 10 vararg 8 constant 0 constant 1 constant 2 glofirvar 9 depart 3 5 exit xrtable a print i 1200 a punct p write_out 5 endxrtable endclause clause write 1 10 enter 10 vararg 8 constant 0 constant 1 constant 2 glofirvar 9 depart 3 5 exit xrtable a write i 1200 a punct p write_out 5 endxrtable endclause clause writeq 1 10 enter 10 vararg 8 constant 0 constant 1 constant 2 glofirvar 9 depart 3 5 exit xrtable a writeq i 1200 a punct p write_out 5 endxrtable endclause clause maybe_paren 5 15 voidn 4 constant 0 enter 15 eval 8 13 eval 9 14 pushv 13 pushv 14 cut 15 vararg 10 depart 1 1 exit xrtable a punct p put 1 endxrtable endclause clause maybe_paren 5 13 voidn 4 var 11 return 13 xrtable endxrtable endclause clause maybe_space 2 10 keya punct constant 0 enter 10 cut 10 exit xrtable a punct endxrtable endclause clause maybe_space 2 10 void var 8 enter 10 cut 10 immed 32 depart 0 1 exit xrtable p put 1 endxrtable endclause clause maybe_space 2 10 keya quote constant 0 constant 1 enter 10 cut 10 immed 32 depart 2 1 exit xrtable a quote a alpha p put 1 endxrtable endclause clause maybe_space 2 10 voidn 2 return 10 xrtable endxrtable endclause clause write_out 5 13 voidn 4 constant 0 enter 13 provar 8 cut 13 vararg 11 constant 0 call 1 vararg 8 depart 2 1 exit xrtable a alpha p maybe_space 2 p tokenput 1 endxrtable endclause clause write_out 5 13 voidn 4 constant 0 enter 13 proint 8 vararg 8 vararg 11 call 1 cut 13 vararg 8 depart 2 1 exit xrtable a alpha p signed_space 2 p tokenput 1 endxrtable endclause clause write_out 5 14 keyf '%varname%' 1 functor 0 1 firstvar 13 pop voidn 3 constant 1 enter 14 vararg 11 constant 1 call 2 vararg 13 depart 3 1 exit xrtable f '%varname%' 1 a alpha p maybe_space 2 p tokenput 1 endxrtable endclause clause write_out 5 13 void constant 0 voidn 2 constant 1 enter 13 vararg 8 call 2 cut 13 exit xrtable a print a alpha p portray 1 endxrtable endclause clause write_out 5 21 voidn 4 constant 0 enter 21 proatom 8 vararg 8 firvararg 13 firvararg 14 firvararg 15 firvararg 16 firvararg 17 call 1 eval 14 18 eval 10 19 pushv 18 pushv 19 cut 21 immed 40 call 2 initvar 20 disjunct 17 vararg 9 constant 3 proequal vararg 8 vararg 9 constant 0 vararg 20 call 4 continue 5 endor vararg 8 call 5 cut 21 immed 41 depart 2 1 exit xrtable a punct p current_op 6 p put 1 a writeq p write_atom 4 p tokenput 1 endxrtable endclause clause write_out 5 13 enter 13 proatom 8 cut 13 vararg 8 vararg 9 vararg 11 vararg 12 depart 0 4 exit xrtable p write_atom 4 endxrtable endclause clause write_out 5 16 void constant 0 voidn 2 constant 1 enter 16 cut 16 vararg 8 firvararg 13 firvararg 14 profunctor vararg 13 constant 0 vararg 11 firvararg 15 call 2 immed 0 glovar 14 vararg 8 immed 40 constant 0 depart 3 5 exit xrtable a display a punct p write_atom 4 p write_args 5 endxrtable endclause clause write_out 5 15 keyf '{}' 1 functor 0 1 firstvar 13 pop voidn 3 constant 1 enter 15 cut 15 immed 123 call 2 vararg 13 vararg 9 constant 3 constant 1 firvararg 14 call 4 immed 125 depart 2 1 exit xrtable f '{}' 1 a punct p put 1 i 1200 p write_out 5 endxrtable endclause clause write_out 5 16 keyf '.' 2 conslist firstvar 13 firstvar 14 pop voidn 3 constant 0 enter 16 cut 16 immed 91 call 1 vararg 13 vararg 9 constant 2 constant 0 firvararg 15 call 3 vararg 14 vararg 9 depart 4 2 exit xrtable a punct p put 1 i 999 p write_out 5 p write_tail 2 endxrtable endclause clause write_out 5 18 keyf ',' 2 functor 0 2 firstvar 13 firstvar 14 pop enter 18 cut 18 constant 1 vararg 10 immed 40 vararg 11 firvararg 15 call 2 vararg 13 vararg 9 constant 3 vararg 15 firvararg 16 call 4 immed 44 call 5 vararg 14 vararg 9 constant 1 constant 6 firvararg 17 call 4 constant 1 vararg 10 immed 41 glovar 17 vararg 12 depart 2 5 exit xrtable f ',' 2 i 1000 p maybe_paren 5 i 999 p write_out 5 p put 1 a punct endxrtable endclause clause write_out 5 15 enter 15 vararg 8 firvararg 13 firvararg 14 profunctor glovar 14 glovar 13 vararg 8 vararg 9 vararg 10 vararg 11 vararg 12 depart 0 7 exit xrtable p write_out 7 endxrtable endclause clause signed_space 2 12 enter 12 eval 8 10 pushv 10 pushb 0 glofirvar 11 constant 0 depart 1 2 exit xrtable a other p maybe_space 2 endxrtable endclause clause signed_space 2 11 enter 11 glofirvar 10 constant 0 depart 1 2 exit xrtable a alpha p maybe_space 2 endxrtable endclause clause write_out 7 23 keyi 1 immed 1 enter 23 vararg 9 firvararg 15 firvararg 16 firvararg 17 firvararg 18 constant 0 call 1 cut 23 vararg 16 vararg 12 immed 40 vararg 13 firvararg 19 call 2 vararg 9 vararg 11 vararg 19 firvararg 20 call 3 immed 1 vararg 10 firvararg 21 proarg vararg 21 vararg 11 vararg 15 vararg 20 firvararg 22 call 4 glovar 16 vararg 12 immed 41 glovar 22 vararg 14 depart 2 5 exit xrtable a prefix p current_op 6 p maybe_paren 5 p write_atom 4 p write_out 5 endxrtable endclause clause write_out 7 23 keyi 1 immed 1 enter 23 vararg 9 firvararg 15 firvararg 16 firvararg 17 firvararg 18 constant 0 call 1 cut 23 vararg 16 vararg 12 immed 40 vararg 13 firvararg 19 call 2 immed 1 vararg 10 firvararg 20 proarg vararg 20 vararg 11 vararg 15 vararg 19 firvararg 21 call 3 vararg 9 vararg 11 vararg 21 firvararg 22 call 4 glovar 16 vararg 12 immed 41 glovar 22 vararg 14 depart 2 5 exit xrtable a postfix p current_op 6 p maybe_paren 5 p write_out 5 p write_atom 4 endxrtable endclause clause write_out 7 25 keyi 2 immed 2 enter 25 vararg 9 firvararg 15 firvararg 16 firvararg 17 firvararg 18 constant 0 call 1 cut 25 vararg 16 vararg 12 immed 40 vararg 13 firvararg 19 call 2 immed 1 vararg 10 firvararg 20 proarg vararg 20 vararg 11 vararg 15 vararg 19 firvararg 21 call 3 vararg 9 vararg 11 vararg 21 firvararg 22 call 4 immed 2 vararg 10 firvararg 23 proarg vararg 23 vararg 11 vararg 17 vararg 22 firvararg 24 call 3 glovar 16 vararg 12 immed 41 glovar 24 vararg 14 depart 2 5 exit xrtable a infix p current_op 6 p maybe_paren 5 p write_out 5 p write_atom 4 endxrtable endclause clause write_out 7 16 voidn 6 constant 0 enter 16 vararg 9 vararg 11 vararg 13 firvararg 15 call 1 immed 0 vararg 8 vararg 10 immed 40 vararg 11 depart 2 5 exit xrtable a punct p write_atom 4 p write_args 5 endxrtable endclause clause write_atom 4 12 keya ! constant 0 voidn 2 constant 1 enter 12 cut 12 immed 33 depart 2 1 exit xrtable a ! a punct p put 1 endxrtable endclause clause write_atom 4 12 keya ; constant 0 voidn 2 constant 1 enter 12 cut 12 immed 59 depart 2 1 exit xrtable a ; a punct p put 1 endxrtable endclause clause write_atom 4 12 keya '[]' constnil voidn 2 constant 0 enter 12 cut 12 immed 91 call 1 immed 93 depart 1 1 exit xrtable a punct p put 1 endxrtable endclause clause write_atom 4 12 keya '{}' constant 0 voidn 2 constant 1 enter 12 cut 12 immed 123 call 2 immed 125 depart 2 1 exit xrtable a '{}' a punct p put 1 endxrtable endclause clause write_atom 4 12 enter 12 vararg 8 vararg 11 call 0 vararg 10 vararg 11 call 1 vararg 8 call 2 cut 12 exit xrtable p classify 2 p maybe_space 2 p tokenput 1 endxrtable endclause clause write_atom 4 12 void constant 0 void constant 1 enter 12 vararg 10 constant 1 call 2 vararg 8 call 3 cut 12 exit xrtable a writeq a quote p maybe_space 2 p tokenquote 1 endxrtable endclause clause write_atom 4 12 voidn 3 constant 0 enter 12 vararg 8 depart 1 1 exit xrtable a alpha p tokenput 1 endxrtable endclause clause classify 2 10 void constant 0 enter 10 vararg 8 call 1 cut 10 exit xrtable a alpha p tokenalpha 1 endxrtable endclause clause classify 2 10 void constant 0 enter 10 vararg 8 call 1 cut 10 exit xrtable a other p tokenother 1 endxrtable endclause clause write_args 5 13 void var 8 enter 13 cut 13 immed 41 depart 0 1 exit xrtable p put 1 endxrtable endclause clause write_args 5 16 enter 16 vararg 11 call 0 vararg 8 firvararg 13 prosucc vararg 13 vararg 10 firvararg 14 proarg vararg 14 vararg 12 constant 1 constant 2 firvararg 15 call 3 glovar 13 vararg 9 vararg 10 immed 44 vararg 12 depart 4 5 exit xrtable p put 1 i 999 a punct p write_out 5 p write_args 5 endxrtable endclause clause write_tail 2 10 enter 10 provar 8 cut 10 immed 124 call 0 vararg 8 call 1 immed 93 depart 0 1 exit xrtable p put 1 p tokenput 1 endxrtable endclause clause write_tail 2 10 keya '[]' constnil enter 10 cut 10 immed 93 depart 0 1 exit xrtable p put 1 endxrtable endclause clause write_tail 2 13 keyf '.' 2 conslist firstvar 10 firstvar 11 pop enter 13 cut 13 immed 44 call 0 vararg 10 vararg 9 constant 1 constant 2 firvararg 12 call 3 vararg 11 vararg 9 depart 4 2 exit xrtable p put 1 i 999 a punct p write_out 5 p write_tail 2 endxrtable endclause clause write_tail 2 11 enter 11 immed 124 call 0 vararg 8 vararg 9 constant 1 constant 2 firvararg 10 call 3 immed 93 depart 0 1 exit xrtable p put 1 i 999 a punct p write_out 5 endxrtable endclause clause writecl 2 10 void constant 0 enter 10 vararg 8 call 1 immed 46 call 2 call 3 cut 10 exit xrtable a true p writeq 1 p put 1 p nl 0 endxrtable endclause clause writecl 2 10 enter 10 vararg 8 call 0 immed 32 call 1 constant 2 call 3 vararg 9 immed 3 constant 4 call 5 immed 46 call 6 call 7 cut 10 exit xrtable p writeq 1 p primput 1 a :- p tokenput 1 a ',' p writebod 3 p put 1 p nl 0 endxrtable endclause clause writebod 3 11 enter 11 provar 8 cut 11 vararg 10 vararg 9 call 0 vararg 8 depart 1 1 exit xrtable p beforelit 2 p writeq 1 endxrtable endclause clause writebod 3 14 keyf ',' 2 functor 0 2 firstvar 11 firstvar 12 pop enter 14 cut 14 vararg 11 vararg 9 vararg 10 call 1 immed 44 call 2 vararg 10 vararg 9 firvararg 13 call 3 vararg 12 glovar 13 constant 4 depart 1 3 exit xrtable f ',' 2 p writebod 3 p put 1 p aftercomma 3 a ',' endxrtable endclause clause writebod 3 13 keyf ; 2 functor 0 2 firstvar 11 firstvar 12 pop enter 13 cut 13 call 1 lastfunctor 2 2 var 9 immed 2 call 3 immed 40 call 4 vararg 11 vararg 9 constant 5 call 6 immed 59 call 4 vararg 12 vararg 9 constant 7 call 6 immed 32 call 8 immed 41 depart 4 1 exit xrtable f ; 2 p nl 0 f - 2 p tab 1 p put 1 a '(' p writebod 3 a ; p primput 1 endxrtable endclause clause writebod 3 11 enter 11 vararg 10 vararg 9 call 0 vararg 8 depart 1 1 exit xrtable p beforelit 2 p writeq 1 endxrtable endclause clause aftercomma 3 11 keya ',' constant 0 void var 9 enter 11 cut 11 exit xrtable a ',' endxrtable endclause clause aftercomma 3 12 enter 12 eval 9 11 pushv 11 pushb 3 add result 10 exit xrtable endxrtable endclause clause beforelit 2 10 keya '(' constant 0 enter 10 cut 10 immed 32 depart 1 1 exit xrtable a '(' p primput 1 endxrtable endclause clause beforelit 2 10 enter 10 call 0 vararg 9 depart 1 1 exit xrtable p nl 0 p tab 1 endxrtable endclause e commercial and industrial applications. \smallskip\noindent These conflicting requirements have led to th/* * MATH.H * Specs for C-callable mathematical functions * 1.1.0 28-Sep-84 ADC (not all of these entries yet in RTL) extern double acos(), asin(), atan(), atan2(), cabs(); extern int ceil(); extern double cos(), cosh(), exp(), fabs(); extern int floor(); extern double frexp(), hypot(), ldexp(), log(), log10(), modf(), pow(); extern int rand(); extern double sin(), sinh(), sqrt(); extern int srand(); extern double tan(), tanh(); ch they can be removed later. Other long-term data structures are represented as/* ascii.h ASCII character codes Version 1.1 */ #define NUL 0 #define SOH 1 #define STX 2 #define ETX 3 #define EOT 4 #define ENQ 5 #define ACK 6 #define BEL 7 #define BS 8 #define HT 9 #define LF 10 #define VT 11 #define FF 12 #define CR 13 #define SO 14 #define SI 15 #define DLE 16 #define DC1 17 #define DC2 18 #define DC3 19 #define DC4 20 #define NAK 21 #define SYN 22 #define ETB 23 #define CAN 24 #define EM 25 #define SUB 26 #define ESC 27 #define FS 28 #define GS 29 #define RS 30 #define US 31 #define DEL 127 #define TAB HT g a Prolog program are stored in a database from which they can be removed later. Other long-term data structures are represented as/* tk.h version 1.1.0 -- Tiny Kernel SVC numbers */ #define TKWRCH 1 #define TKSTRI 2 #define TKASCI 3 #define TKNEWL 4 #define TKRDCH 5 #define TKBYTE 6 #define TKWORD 7 #define TKCLI 8 #define TKFILE 10 #define TKFIND 11 #define TKARGS 12 #define TKBGET 13 #define TKBPUT 14 #define TKGBPB 15 #define TK_EXIT_PROGRAM 17 #define TK_CALL_DEBUG 18 #define TKRESC 20 #define TK_IMMEDIATE_OUT 21 #define TK_SET_EVENT_HANDLER 30 #define TKRERR 31 #define TK_SET_VDT 40 #define TK_SPLIT 50 #define TK_COMM 51 #define TK_GET_VERSION 52 #define TK_SET_VDU_HANDLER 53 #define TK_READ_CONFIG_SWITCHS 54 mallskip\noindent All clauses comprising a Prolog program are stored in a database from which they can be removed later. Other long-term data structures are represented as/* QSORT: Quicksort of 50 element "random" list init([27,74,17,33,94,18,46,83,65,2, 32,53,28,85,99,47,28,82,6,11, 55,29,39,81,90,37,10,0,66,51, 7,21,85,27,31,63,75,4,95,99, 11,28,61,74,18,92,40,53,59,8]). dummy(L). test(L0) :- qsort(L0,L1,[]). qsort([X|L],R,R0) :- partition(L,X,L1,L2), qsort(L2,R1,R0), qsort(L1,R,[X|R1]). qsort([],R,R). partition([X|L],Y,[X|L1],L2) :- X =< Y, !, partition(L,Y,L1,L2). partition([X|L],Y,L1,[X|L2]) :- partition(L,Y,L1,L2). partition([],_,[],[]). \centerline{CAMBRIDGE CB2 3QG} \bigskip \centerline{SUMMARY} {\narrower\smallskip\noindent All clauses comprising a Prolog program are stored in a database from which they can be removed later. Other long-term data structures are represented ascc -w -O main.c alloc.c check.c compsup.c convert.c fileio.c lowlevel.c primitive.c read.c write.c zip.c -lc cc -w -O main.o alloc.o check.o compsup.o convert.o fileio.o lowlevel.o primitive.o read.o write.o zip.o -lc zap pip.pro.zap rescom.pro.zap standio.pro.zap foreach i (alloc check compsup convert fileio lowlevel main prh primitiv read test write zap zip) cs fetch -to $i.c am21.prologx.c:$i foreach i (zap zip) cs fetch -to $i.h am21.prologx.h:$i \centerline{Corn Exchange S/* * CTYPE.H * 1.1.0 28-Sep-84 ADC #define isupper(c) ('A'<=(c)&&(c)<='Z') #define islower(c) ('a'<=(c)&&(c)<='z') #define isalpha(c) (islower(c)||isupper(c)) #define isdigit(c) ('0'<=(c)&&(c)<='9') #define isalnum(c) (isalpha(c)||isdigit(c)) #define isspace(c) ((c)==' '||(c)==9||(c)==10||(c)=13||(c)=12) #define isascii(c) ((c)<0200) #define iscntrl(c) ((c)<040||(c)=0177) #define isprint(c) (040<=(c)&&(c)<=0176) #define ispunct(c) (isprint(c)&&!isalnum(c)) ambridge} \centerline{Corn Exchange S PbE2 timer 1985-08-28 12:36:01 Lattice Logic C 2.2-2.33-2.6 main _C_handler printf OSWord 'Ædt'Þ tx_Àd_Àh %d %d ×Åh×ÅdçÝ |¥ôçÅdß¹" %d %d )×Åh×ÅdçÝ |¥ôßÀ| À|êtçÅdß¹" %d %d ×Åh×ÅdçÝ main 8 8@ H timer enterline{University of Cambridge} \centerline{Corn Exchange S #include "stdio.h" main() int j; int binarytime[4]; binarytime[0] = 0; binarytime[1] = 0; printf("%d %d\n", binarytime[0], binarytime[1]); OSWord(3, binarytime); printf("%d %d\n", binarytime[0], binarytime[1]); for (j = 1 ; j < 200000; j++); OSWord(3, binarytime); printf("%d %d\n", binarytime[0], binarytime[1]); tation Techniques for Prolog Databases} \bigskip \centerline{W F Clocksin} \centerline{Computer Laboratory} \centerline{University of Cambridge} \centerline{Corn Exchange Sinstall.tex: TeX source of installation instructions. refman.tex: TeX source of reference summary. zip.tex: Draft paper that now appears in New Generation Computing. db.tex: Draft paper that now appears in Software Pract. and Exp. format.tex: header file for above. \magnification=1200 \input format \centerline{\bf Implementation Techniques for Prolog Databases} \bigskip \centerline{W F Clocksin} \centerline{Computer Laboratory} \centerline{University of Cambridge} \centerline{Corn Exchange Street} \centerline{CAMBRIDGE CB2 3QG} \bigskip \centerline{SUMMARY} {\narrower\smallskip\noindent All clauses comprising a Prolog program are stored in a database from which they can be removed later. Other long-term data structures are represented as clauses and are also stored and rem oved from the same database. Implementation techniques for the manipulation of clauses are not well known, and a lack of information has led to incorrect and incomplete implementations. Further previously unresolved issues are apparent when considering the storage of compiled clauses. We describe the way database manipulations are performed in Prolog-X, a new compiler-based Prolog system. We also introduce a new technique for storing the source form of compiled clauses. \medskip\noindent Keywords: Prolog, logic programming, garbage collection. \medskip \section{Introduction} \par Prolog-X is an implemented portable interactive Prolog system in which clauses a incrementally compiled for an abstract virtual machine. At present the virtual machine is emulated by software, but it has been designed to permit easy implementation in microcode or hardware. The advantages of compilation, as contrasted to interpretation, are well known for conventional languages, and compilation is no less of an advantage for Prolog, as demonstrated by the implementation of DEC-10 Prolog (Warren, 1979). In our attempt to advance the Prolog implementation technology, we have needed to design new system components. In this paper we focus on the representation of clauses in the database. \par This paper does not provide a tutorial on Prolog programming, but the very accessible paper by Warren (1980) provides all the background required. More information can be found in a Prolog textbook (Clocksin and Mellish, 1981) and a reference manual for the C-Prolog implementation (Pereira, 1984). \par We shall need to review the procedural semantics of a Prolog system to define the terminology used in the remainder of this paper. Adapted from Warren (1980),\par \noindent{\narrower\smallskip\noindent {\sl execute} a goal, the system searches the database for the first clause whose head {\sl matches} with the goal according to the unification algorithm (Robinson, 1965). If a match is found, the matching clause instance is {\sl claimed}, and it is activated by executing in turn, from left to right, each of the goals in its body (if any). Substitutions of variables performed by the unification algorithm are recorded on a push-down stack called the {\sl trail}. If at any time the system fails to find a match for a goal, it {\sl backtracks}: the most recently claimed clause is unclaimed, and any substitutions performed are undone from the information on the trail. Next it reconsiders the original goal which activated the rejected goal, and tries to find a subsequent clause which also matches the goal.\par \smallskip\noindent} Finally, we need to give the definition of the {\tt erase} predicate. Adapted from Pereira (1984),\par \noindent{\narrower\smallskip\noindent {\tt erase(Ref).} The clause whose database reference is {\tt Ref} is effectively erased from the database. An erased item will no longer be accessible though the predicates that search through the database, but will still be accessible though its database references, if this is available in the execution state after the call to {\tt erase}. Only when all instances of the clause's database reference have been forgotten through database erasures and/or backtracking will the item be actually removed from the database.\par \smallskip} \section{Clause Storage} \par A memory manager which expects to reclaim automatically the storage occupied by unreferenced data structures must use some form of garbage collection (GC). Some Prolog implementations (McCabe, 1984; Mellish and Hardy, 1982) use a heap which is garbage collected by conventional mark-and-sweep techniques. Prolog-X was designed not to use a heap for the following reasons. The usual GC methods for heaps cause inefficient use of available memory transfer bandwidth. Problems do not arise on a system with limited address space or for small applications ($<$ 1 Mbyte of workspace), but realistically la applications ($>$ 4 Mbyte of workspace) are more demanding, and seem to require a more sophisticated treatment of storage management. It is impractical to wait minutes for a garbage collection to finish, and real-time response is desirable in many applications involving interactive editing. Also, the way that memory is used is a factor to consider. Heaps are suitable for Lisp or Smalltalk, in which the turnover of cells is difficult to predict. However, with Prolog's applicative execution model, memory is used in more structured and predictable ways. Memory for stack frames and created structures has a high rate of turnover, and can be reclaimed on backtracking if memory is allocated from stacks rather than from a heap. Furthermore, in a running Prolog system, each instantiation of a variable by the unification algorithm is recorded on the Trail: a transaction journal accessed as a pushdown stack. We shall see below how to use the Trail to aid GC. \par On the other hand, clauses in the database have a low rate of turnover, and are persistent over backtracking. A different style of storage management is called for. There are two ways to reference a clause during the running of a Prolog program. Clauses can be {\sl claimed}; this is analogous to calling a procedure in a conventional language, and not to be confused with `reclaiming' or deallocating a block of storage. As long as a clause is being claimed, the storage it occupies must not be reclaimed by a garbage collector. Second, clauses can also be {\sl referenced} and used as any other data structur The storage for referenced clauses must not be reclaimed. A clause can be both claimed and referenced. \par Clauses are added (using {\tt assert(X)}) to and removed (using {\tt erase(X)}) from the database explicitly, and it is desirable to reclaim the storage occupied by clauses which have been erased, and which are both unreferenced and unclaimed. A reference counting method is ideal, as clauses have a low frequency of turnover, and cycles, if present, are always broken by explicit unreferencing (by using {\tt erase(X)} or by unclaiming by backtracking). Furthermore, if the database is restricted to containing only clauses and not other created data structures (which is the case in Prolog-X), then there is even less need for a general purpose heap, as only clauses require a reference count field. \par Despite these considerations, it is becoming increasingly commonplace to use Prolog programming techniques which create structures without eventually backtracking over them --- simulating systems of communicating processes is one example (Warren, 1982; Shapiro, 1983; Clocksin, 1983). For this, the more general heap storage regime is needed for created data structures, and clauses may as well be stored in this way also. However, the need for an incremental GC method (Baker, 1978; Lieberman and Hewitt, 1983) is even more obvious, and future research should illuminate this area. Applied to Prolog, such a method would do well to exploit the differing rates of turnover between data structures and clauses. \par We shall now describe the clause database management system implemented in Prolog-X. The system described here is similar to undocumented ones used by DEC-10 Prolog and C-Prolog (O'Keefe, 1984). \medskip \noindent Five primitive operations are required, and they make use of the following implementation specific procedures: \ip Incrementing the reference count field of a clause. \ip Decrementing the reference count field of a clause. \ip Deallocating a clause: this means reclaiming the storage space occupied by the clause. The deallocation procedure is also reponsible for {\sl unreferencing} (defined below) any references to clauses originating in the clause being deallocated. \ip Pushing a reference to a clause onto the Trail. \ip Unchaining a clause: remove the clause from the database, but do not deallocate the clause. \medskip\noindent Algorithms for the following five storage management primitives are given below: Claiming a clause. A clause is claimed when the system is committed to using it in a proof. A clause will remain claimed until the system backtracks past it. The key observation is that the Trail can be used to refer to claimed clauses. Thus, a given Trail records not only the instantiation state of the computation in progress, but also which clauses are in use. Once a clause is claimed, with an entry on the trail, it is not necessary to record another Trail entry each time the clause is called recursively. The first entry on the Trail is the `oldest', and the clause remains claimed until backtracking moves over the `oldest' entry. Thus, a one-bit field in the clause is all that is necessary to record whether or not a clause is claimed. Unclaiming a clause. A clause is unclaimed when it is no longer needed during execution. Unclaiming occurs during backtracking, and if backtracking works back to a clause reference in the Trail, then now is the time to check whether the clause is still referenced. Creating a database reference to a clause. A reference to clause {\tt C} is created when some clause referencing {\tt C} is asserted into the database. Any number of other clauses may reference {\tt C} in this manner, so a reference count field is called for. Unreferencing a database reference to a clause. Clause {\tt C} is unreferenced when the space occupied by a clause referencing {\tt C} is reclaimed. Unreferencing occurs ultimately when a clause is {\sl erased}. In the algorithms given below, we shall assume that the {\tt deallocate} primitive (for reclaiming storage) is responsible for unreferencing clauses referenced by the clause being deallocated. Erasing a database reference to a clause. A clause may be explicitly removed from the database by using the {\tt erase} predicate. Of course, the space occupied by the clause must not be reclaimed until no further references to the clause exist. \medskip \noindent We assume that a clause C contains three fields for the use of the database manager: {\parindent=1truein \item{\tt C.REF} A field containing a reference count. In the current implementation of Prolog-X, this field is contains an integer in the range 0..255. \item{\tt C.CLAIMED} A single-bit field which is set if the clause is claimed. \item{\tt C.DOOMED} A single-bit field which is set if the clause has been {\tt erase}d, but has not been deallocated because it is referenced or claimed. \medskip} \noindent All fields are initialised to 0 when a clause is created. The definitions of these primitives are: {\obeylines \noindent {\sl Creating a database reference to clause C:} Increment {\tt C.REF}; \medskip \noindent {\sl Unreferencing a database reference to clause C:} Decrement {\tt C.REF}; If {\tt C.REF} = 0 and {\tt C.DOOMED} and not({\tt C.CLAIMED}) then deallocate C \medskip \noindent {\sl Claim a clause C:} if not ({\tt C.CLAIMED}) then \tab set {\tt C.CLAIMED}; \tab push a pointer to C on the trail stack; \medskip \noindent {\sl Unclaim a clause C:} clear {\tt C.CLAIMED}; if ({\tt C.DOOMED}) then \tab unchain C; \tab if ({\tt C.REF} = 0 then deallocate C; \medskip \noindent {\sl Erase a database reference to clause C:} if not({\tt C.DOOMED}) then \tab set {\tt C.DOOMED}; \tab if not({\tt C.CLAIMED}) then \tab\tab unchain C; \tab\tab if {\tt C.REF} = 0 then deallocate C; \medskip\noindent These algorithms form the basis of the implemented storage management system for Prolog-X. The main advantage gained is that less general, more efficient garbage collection is made possible by exploiting the backtracking execution strategy of Prolog. \smallskip \section{Representing source terms} \par In interactive languages such as LISP, Smalltalk, and Prolog, it is often necessary to retain a copy of the source input, often in the form of a syntax tree (an S-expression in LISP; a term in Prolog). This is useful for debugging and interactive editing, and as such, is not strictly necessary for implementing the primitive language features. However, Prolog has a further requirement: in the definition of the {\tt clause} {\tt retract} predicates for manipulating the database, clauses in the database are accessed by content. This means that the source form of the clause must be retained in case {\tt clause} and {\tt retract} goals are used in a program. This does not present a problem in Prolog interpreters, because the source form (or a trivial transformation of it) constitutes the clause itself as stored in the database. However, when the clause is represented by compiled code, and stored apart from other data structures, it becomes necessary to represent the source form in another way. Because DEC-10 Prolog does not retain the source term for compiled clauses, DEC-10 Prolog does not permit compiled clauses to be manipulated by {\tt clause} and {\tt retract}. This restriction is inconvenient and further emphasises the undesirable discontinuity between interpreted and compiled clauses in that implementation. An improved implementation must retain the source form of the Prolog clauses somehow. We have investigated three methods for retaining the source clause: \smallskip Retain a copy of the source clause. Compiler-based LISPs often do this, placing the S-expression of the function definition on the property list associated with the function name. We could not take this approach in Prolog-X because, unlike the heap-based Prologs mentioned above, general purpose terms cannot be stored in the database: only compiled clause bodies can be. There are two further disadvantages in the Prolog context: source clauses must be copied during unification, and it is difficult to write the clause searching routines in Prolog. The necessary mechanisms are included in interpreter-based implementations, so again this does not present a problem for them. Decompile the compiled clause body into a term when required. This was the first scheme used by Prolog-X. \footnote{$^1$}{The decompiler was written by Lawrence Byrd.} The advantages are that the decompiler can be written in Prolog (only a few non-Prolog support routines are required), and nothing extra need be stored with each clause. The disadvantages are many. The decompilation process is very slow. All target code produced by the compiler must be reversible, and this reduces the opportunities for clever optimisations. The decompiler is nearly as large as the compiler, about two pages of Prolog. A third alternative is the one implemented at present. At the same time as the input clause is compiled, we also compile a unit clause of predicate {\tt source}, in which the input clause appears as one of the arguments of the head of {\tt source}. The advantage of this is that source terms are compactly represented as the abstract machine codes necessary to construct a copy of the source term. Clause searching and matching is done by the usual mechanisms of the abstract machine; no extra routines are required. Further benefits are listed below. The disadvantage is that clauses are effectively compiled twice, a process which almost doubles the time required to compile a file. \par The details of the new scheme are now presented. We use a predicate {\tt source} of arity 5. The term {\tt source(F,A,C,V,R)} is compiled and asserted into the database each time the input clause {\tt C} is compiled an d asserted. The components of {\tt source} are as follows: \item{\tt F} the principle functor of the head of clause {\tt C}; \item{\tt A} the arity of the principle functor of the head of clause {\tt C}; \item{\tt C} clause {\tt C}, the input term; \item{\tt V} a list of variable names used in {\tt C}. \footnote{$^2$}{ The variable list is a list of terms of the form {\tt=(X,A)}, where {\tt X} is a variable sharing with a var iable in the clause, and {\tt A} is the source name of that variable (an atom). The variable list contains such a term for each unique variable name in the clau Many Prolog systems make such a list available at the time an input clause is read. \item{\tt R} a database reference (a pointer) to the compiled input clause. \medskip \noindent Using the above conventions, the standard predicate {\tt clause} may be easily defined in Prolog as follows: \smallskip \centerline{\tt clause(H,B) :- source(\_,\_,H:-B,\_,\_).} \smallskip The next standard predicate to define is {\tt retract}. Here the situation is trickier. We use the {\tt source} database to find a clause matching the argument of {\tt retract}, and simply call {\tt erase} with the reference to the compiled clause. However, we must also {\tt erase} the corresponding {\tt source} clause. We used the {\tt source} clause as a means of finding which compiled clause to erase, so how are we to obtain a database reference to the {\tt source} clause? The answer is that the appropriate database reference will have been found by the Prolog system in order to satisfy the {\tt source} goal in the {\tt retract} predicate. Providing a handle on this clause will solve the problem. We have introduced a new built-in predicate called {\tt eraselast} solely to perform this task. The goal {\tt eraselast} discards the database reference corresponding to the clause that was selected to make the previous subgoal succeed. This in effect modifies the running program, and is used only by the systems programmer for this task. Goal {\tt eraselast} (as well as {\tt erase}) is safe to use because of the storage management facilities discussed in the previous section. Thus, {\tt retract} is defined as follows: \smallskip \centerline{\tt retract(X) :- source(\_,\_,X,\_,R), eraselast, erase(R).} \smallskip The two erased clauses will not be deallocated until no references to both exist. Typical behaviour after calling {\tt retract} is that nothing will be deallocated until that call of {\tt retract} has backtracked or exits determinis tically. Then, the clause corresponding to the {\tt source} goal will be unclaimed, and deallocated (because {\tt eraselast} set the {\tt DOOMED} bit). This in turn causes the compiled code (referenced by R) to be unchained, and deallocated if no further references to it exist. In a similar fashion, the standard predicate {\tt abolish} is defined as follows: \smallskip {\obeylines abolish(F,A) :- source(F,A,\_,\_,R), eraselast, erase(R), fail. abolish(\_,\_). \smallskip Note that for those Prolog implementations which use the first few arguments of a goal as a search key, it is possible to speed up {\tt clause} by using the principal functor of the clause head as a key: \smallskip \centerline{\tt clause(H,B) :- functor(H,F,A), source(F,A,H:-B,\_,\_).} \smallskip Other variations of this scheme are possible, such as storing the source forms not under one master predicate {\tt source} but under predicates whose names are constructed from parts of the name of the principal functor of the input clause head {\tt source\_foo\_17}, for example). When used under most Prolog systems, this essentially becomes a hashing scheme which permits even faster source lookup. In Prolog-X, which has a module system to prevent name clashes, {\tt source} predicates are stored in the same module as their corresponding input clauses. As well as subjecting the source clause to module protection, this technique provides an extra level of indexing leading to more efficient execution. \section{Conclusions} \par The storage management and source term representation techniques used in Prolog- have been presented. These techniques lead to safe and efficient storage management for the clause database, and very convenient implementation of the {\tt clause} and {\tt retract} predicates. Efficiency in storage management is gained by tailoring a reference counting scheme to the backtracking execution model of Prolog. \section{Acknowledgements} The work reported here has benefitted from helpful comments and advice contributed by Lawrence Byrd, Richard O'Keefe, and Fernando Pereira. \section{References} Baker, H G, 1978. List processing in real time on a serial computer, {\sl Communications of the ACM}, {\bf 21}, 280-294. Clocksin, W F, and Mellish, C S, 1981. {\sl Programming in Prolog}, Springer Ver lag. Clocksin, W F, 1983. Real-time functional queue operations using the logical variable, {\sl Information Processing Letters}, {\bf 17}, 173-175. Lieberman, H, and Hewitt, C, 1983. A real-time garbage collector based on the lifetimes of objects, {\sl Communications of the ACM}, {\bf 26}, 419-429. O'Keefe, R, 1984. personal communication, Department of Artificial Intelligence, University of Edinburgh. McCabe, F, 1984. APM specification, Department of Computing, Imperial College, London. Mellish, C S, and Hardy, S, 1982. Integrating Prolog in the POPLOG environment, Cognitive Studies Programme, University of Sussex. Pereira, F C N, 1984. {\sl C-Prolog User's Manual}, SRI International, Menlo Par California. Robinson, J A, 1965. A machine-oriented logic based on the resolution principle, {\sl Journal of the ACM}, {\bf 12}, 23-44. Shapiro, E Y, 1982. A subset of Concurrent Prolog and its interpreter, Technical Report TR-003, Institute for New Generation Computer Technology, Tokyo. Warren, D H D, 1979. Prolog on the DECsystem-10, in {\sl Expert Systems in the Microelectronic Age} (D Michie, ed), Edinburgh University Press. Warren, D H D, 1980. Logic programming and compiler writing, {\sl Software---Practice and Experience}, {\bf 10}, 97-125. Warren, D H D, 1982. Perpetual processes --- An unexploited Prolog technique, {\sl Logic Programming Newsletter}, {\bf 3}, 2. \hsize=5.9truein \hoffset=0.2truein \vsize=9.3truein \raggedbottom \tolerance=1000 \parskip=3pt plus1pt minus1pt \def\\{\char'134} \def\ip{\item{$\bullet$}} \def\sbx{\item{$\bullet$}} \def\tab{\hskip1truein\relax} \def\section#1{ \bigskip \hbox{\bf #1\hfil} \smallskip \def\quote{\par\begingroup\narrower\smallskip\noindent} \def\endquote{\smallskip\endgroup\noindent} \def\block{ \smallskip \begingroup \blkfont \parskip=0pt \advance\leftskip by 0.5truein \obeylines \def\endblock{ \smallskip \endgroup \noindent \def\key#1{\leavevmode\thinspace\hbox{\vrule\vtop{\vbox{\hrule\kern1pt \hbox{\vphantom{\tt/}\thinspace{\tt#1}\thinspace}} \kern1pt\hrule}\vrule}\thinspace} \def\boxit#1{\vbox{\hrule\hbox{\vrule\kern3pt\vbox{\kern3pt#1\kern3pt} \kern3pt\vrule}\hrule}} \def\chapter#1#2{\line{\tf Chapter #1\hfil} \line{\tf #2\hfil}\bigskip\bigskip \magnification=1200 \centerline{Prolog-X Installation Instructions} \centerline{W F Clocksin, 25 May 1984, Version 4: April 1985} \bigskip \medskip The following instructions describe how to install Prolog-X. The instructions and filename conventions are valid for any Unix system. You should first transfer the contents of the distribution medium onto a directory of your choice. Then, follow these instructions. \bigskip \item{0.} If you have been given files named {\tt pip.pro.zap}, {\tt standio.pro.zap}, {\tt rescom.pro.zap}, then go to Step 3. \item{1.} You have come to this step because either (a) you have made your own changes to {\tt *.pro.zap}, or (b) someone has neglected to supply you with {\tt *.pro.zap} files. If (b) is the case, then stop and ask for a copy of {\tt *.pro.zap}. You will need a running Prolog system. C-Prolog, ESL Prolog, and Prolog-X are suitable. Use your Prolog system to consult the file {\tt sacom.pro}. That is, execute the goal \smallskip \centerline{\tt ?-['sacom.pro'].} \item{2.} You will need the ``Prolog in Prolog'' source files. These are {\tt p ip.pro}, {\tt standio.pro}, and {\tt rescom.pro}. Execute the goal \smallskip\centerline{\tt ?- zapify('pip.pro'), zapify('standio.pro'), zapify('r escom.pro').}\smallskip Various printout will be produced, which you should ignore. Exit from Prolog. \item{3.} We now compile the Zip Assembly Program (ZAP), which needs to be done only once. You need {\tt zap.c} and {\tt zap.h}. Execute the Unix commands \smallskip\centerline{\tt cc zap.c ; mv a.out zap} \item{4.}Next we assemble the heap assembly listing. You need the {\tt *.pro.za files. The purpose of this is to produce the machine-readable initial heap image, called {\tt zap.out}. The heap image is read in every time Prolog-X is started up. You only need to produce the heap image once only. Execute the Unix command \smallskip \centerline{\tt sh zapall} Various printout will be produced, which you should ignore. \item{5.}Next we compile the Prolog-X kernel. Execute the Unix commands \smallskip\centerline{\tt sh comp ; mv a.out prologx} \item{6.}Next we run the Prolog-X system. You need {\tt zap.out} made in Step 2 Execute the Unix command \smallskip\centerline{\tt prologx} \item{7.}It should work, printing out a message such as {\tt Prolog-X Version 3} and then print the {\tt ?-} prompt. To exit Prolog, type the Unix end of file character (either control D or control Z, depending on your system). \input format \centerline{\bf Reference Summary of Prolog-X} \centerline{W F Clocksin, Computer Laboratory, University of Cambridge} \centerline{April, 1985} \bigskip \section{Summary} Prolog-X is an implemented portable interactive Prolog system in which clauses are incrementally compiled for a virtual machine. At present, the virtual machine is emulated by software, but it has been designed to permit easy implementation in microcode or hardware. Prolog-X running on the software-based emulator provides performance comparable with existing Prolog systems. \section{Design Goals} The goal of Prolog-X is to provide a high-performance Prolog implementation suitable for large-scale commercial and industrial applications. It is appreciated that applications of this type will run on machines that have a large (at least 16 Mb) directly-addressable virtual memory space. Consequently, Prolog-X can only be run on machines having at least a 32-bit word length, of which at least 24 bits are available for addressing. To provide usable response with heavy memory loading, Prolog-X uses sophisticated implementation techniques to make efficient use of computing time and memory space. The system uses an optimising compiler to convert clauses into a compact byte-code instruction stream for a virtual machine which can be emulated at high speed. Internal operations, such as data structure management, are uniformly designed to be of constant overhead or at least of low complexity, scaling up without disproportionally degrading performance. Furthermore, critical parts of the Prolog-X system are designed in such as way as to imply a straightforward reimplementation in assembly language, hardware, or microcode. Prolog-X is a compiler-based Prolog which, unlike previous such systems, is reasonably portable. Prolog-X has been ported to the HLH Orion, ICL Perq, ICL 2980, IBM 370, and DEC VAX. To demonstrate its efficiency, compatibility, and comprehensiveness of implement ation, Prolog-X has been used to compile and run several large programs written originally for DECsystem-10 Prolog, including {\sl CHAT} and {\sl Press}. The Prolog Library can also be used, which makes available development tools and scientific routines such as an arbitrary-precision rational number arithmetic package. \section{The User Language} The dialect of Prolog available to the user is intended to be compatible with the core language as specified in {\it Programming in Prolog} (Clocksin and Mellish, 1981), of which widespread implementations exist for the DECsystem-10 (Byrd, Pereira, and Warren, 1980), VAX (Pereira, 1981), and PDP-11 (Mellish, 1980). Unrestricted syntax compatible with the DECsystem-10 implementation is used: overloaded operator declarations with precedences in the range 1..1200, curly brackets, etc. To support large-scale applications, Prolog-X also offers lexical modules and easy interface to procedures written in the base language (C). Programs may contain Grammar Rules. \noindent Some relevant deviations from normal practice are as follows: \sbx Debugging facilities are not built-in. Because clauses can be compiled, some of the information needed by a built-in debugger can be lost, and to increa se performance, clauses may be executed in ways not obvious to the user. However, it is possible to use an interpretive debugger (available from the Prolog Library) in the usual way, which imposes a conventional execution strategy. \sbx A normal Prolog ``top level'' is provided. As clauses are compiled, the source clause is also retained in the database together with the names of va riables used within the clause. This may be used, for example, to list clauses (using {\tt listing}) exactly as they were typed in. However, the user has the option to compile clauses without retaining the source clause in the database. The advantage is faster compilation and less memory usage, but such clauses may not be accessed by {\tt clause} or {\tt retract}. \sbx Input must be in upper- and lower-case, so the following syntactic devices are considered obsolete and have been discarded: `{\tt ,..}', `{\tt LC}', `{\tt NOLC}', infix functor `{tt .}'. \sbx Some commonly used predicates defined in various Prolog libraries have been built-in. \section{Implementation Details} \noindent The current implementation includes the following features: \sbx Large address space ($2^{28}$ bytes). \sbx Incremental garbage collection is performed during backtracking, and when clauses are retracted. \sbx All clauses are compiled to a compact byte-code representation, with automatic variable mode analysis and peephole optimisations. Some built-in predicates are open-coded. \sbx Tail recursion optimisation, early detection of determinacy. \sbx Automatic clause indexing on first argument of goals. \sbx Arbitrarily long bit-strings that are tested for equality during unification (for compact strings, big numbers). \smallskip\noindent \section{Data Structures} \noindent Data structures used in Prolog-X programs have the following restrictions: \sbx {\it integers}: are in the range -134217728 to 134217727. Overflow is not checked. An integer to the base $N$ ($0 \leq N \leq 9$) may be represented as standard, but base 0 is reserved for representing character codes (for example, {\tt 0'A == 8'101}). \sbx {\it strings}: these are represented as lists of ASCII codes as per the DECsystem-10 standard. There is an internal data structure used for packed byte strings of arbitrary length, but this is not made available to the u ser. \sbx {\it atoms}: The names of atoms are internally represented as packed byte strings of arbitrary length (limit 16777215 characters). External syntax as per Prolog standard. \sbx {\it variables}: A maximum of 255 differently-named variables may appear in a clause. This restriction can be lifted in later releases by the unlikely event of popular demand. \sbx {\it compound terms}: The maximum arity of a functor is 16777215, but in practice is subject to memory limitations. Only functors having arity less than 256 can be {\tt assert}ed. This restriction can be lifted in later releases by popular demand. \section{Errors} The error handling mechanism is accessible to the user as a Prolog procedure {\tt error\_handler}. The default action for errors is to print a message and a culprit. Additionally, syntax errors cause extra information to be printed. If the current file is not the user, then the file name and line number and column number in the file is printed. After a syntax error, recovery is attempted by skipping to what is likely to be the end of the clause, and reading again. Typing the interrupt key (control-C on Unix systems) causes the procedure {\tt break\_handler} to be entered at the earliest opportunity. The default break handler provides a ``top level'' with the prompt preceded by the word {\tt (Break)}. To exit from the break, type the end-of-file character (control-D or control-Z on Unix systems). The break handler can also be modified by the user. \section{Input and Output} The Unix standard I/O library is used. Output is flushed only (a) when a newline is printed, or (b) when input from the user is requested. The built-in procedure {\tt ttyflush} is provided. There is a limit on the number of files than can be open at any one time. \section{Operator Declarations} These are the same as provided by DEC-10 Prolog. In Prolog-X, operator declarations are subject to {\tt module} scoping, and may be imported in the same way as procedures. \section{Built-in Predicates Exported to the User} The built-in predicates are fully explained in the DECsystem-10 manual, the C-Prolog manual, the Prolog textbook. In the middle column, an X means a predicate new in Prolog-X; L means a Prolog library predicate which has been built-into Prolog-X; means that the compiler open-codes the predicate (emits a specific machine instruction). The `O' entry should not normally concern the user. \smallskip \halign{\tt#\hfil&\quad#\hfil&\quad#\hfil\cr abolish(F,N)&&Retract all clauses for procedure F, arity N.\cr abort&&Abort execution of current directive\cr arg(N,T,A)&O&The Nth argument of term T is A.\cr assert(C)&&Assert clause C.\cr asserta(C)&&Assert C as first clause.\cr assertz(C)&&Assert C as last clause.\cr atom(T)&O&T is an an atom.\cr atomic(T)&O&T is an atom or an integer.\cr bagof(X,P,B)&&The bag of Xs such that P is provable is B.\cr break\_handler&X&Call the break handler.\cr call(P)&O&Call procedure P.\cr clause(P,Q)&&There is a clause, head P, body Q.\cr clause(P,Q,R)&&There is a clause, head P, body Q, ref R.\cr compare(C,X,Y)&&C is the result of comparing terms X and Y.\cr compile(F)&&Extend the program with clauses from file F, do not retain source.\c consult(F)&&Extend the program with clauses from file F.\cr display(T)&&Write term T in prefix form.\cr endmodule(A)&X&End of module A.\cr erase(R)&&Erase the clause with ref R.\cr error\_handler(N,T)&X&Call the error handler with error number N, culprit T.\cr fail&O&Backtrack immediately.\cr findall(T,G,L)&L&Like {\tt bagof(T,G,L)}, but free variables existentially quant ified.\cr findall(T,G,S,L)&L&Like {\tt findall(T,G,L1), append(L1,S,L)}, but cheaper.\cr forall(P,Q)&L&For all P provable, prove Q.\cr functor(T,F,N)&O&The principal functor of term T is F with arity N.\cr get(C)&&The next non-blank input character is C.\cr get0(C)&&The next input character is C.\cr halt&&Abort and exit Prolog.\cr import(P,M)&&Import procedure(s) P from module M.\cr integer(T)&O&T is an integer.\cr Y is X&O&Y is the value of arithmetic expression X.\cr keysort(L,S)&&The list L sorted by key yields S.\cr length(L,M)&L&The length of list L is M.\cr listing(F,A)&&List the clauses of predicate with functor F, arity A.\cr name(A,L)&&The name of atom or string or number A is list L.\cr nl&&Output a newline.\cr nonvar(T)&O&Term T is a non-variable.\cr not(P)&&Like {\tt \\+(P)}, but a warning is printed if P is not ground.\cr numbervars(T,M,N)&&Number the variables in term T from M to N-1.\cr op(P,T,A)&&Make atom A an operator of type T, precedence P.\cr put(C)&&Output the character C.\cr read(T)&&Read term T.\cr read(T,L)&X&Read term T, with variable name list L.\cr recorda(K,T,R)&&Record T first under key K, with ref R.\cr recorded(K,T,R)&&T is recorded under key K, with ref R.\cr recordz(K,T,R)&&Record T last under key K, with ref R.\cr repeat&&Succeed.\cr retract(T)&&Erase the first clause matching T.\cr save(F)&&Save the current state of Prolog in file F.\cr see(F)&&Make file F the current input stream.\cr seeing(F)&&The current input stream is name F.\cr seen&&Close the current input stream, revert to {\tt user}.\cr setof(X,P,S)&&The set of Xs such that P is provable is S.\cr simpleterm(T)&L&Term T is not a compound term.\cr skip(C)&&Skip input characters until after character C.\cr sort(L,S)&&The list L sorted into canonical order is S.\cr succ(M,N)&L&integer N is the successor of integer M.\cr system(P)&L&P is a built-in predicate.\cr tab(N)&&Output N spaces.\cr tell(F)&&Make the current output stream F.\cr telling(F)&&The current output stream is named F.\cr told&&Close the current output stream, revert to {\tt user}.\cr true&&Succeed once.\cr ttyflush&&write out the terminal output buffer.\cr unknown(O,N)&&Set the ``unknown procedure'' action from O to N.\cr var(T)&O&T is a variable.\cr visa(L)&X&Confer permissions on exportable procedures.\cr write(T)&&Write T.\cr writedepth(O,N)&&Set the write depth from O to N.\cr writeq(T)&&Write T, quoting if necessary.\cr writewidth(O,N)&X&Set the output linewidth from O to N.\cr !&O&Cut any choices taken in the current procedure.\cr \\+(P)&&P is not provable.\cr P -> Q ; R&O&If P is provable, the prove Q, else prove R.\cr P -> Q&O&Like {\tt P -> Q ; fail}.\cr X < Y&O&As integer expressions, X is less than Y.\cr X =< Y&O&As integer expressions, X is less than or equal to Y.\cr X > Y&O&As integer expressions, X is greater than Y.\cr X >= Y&O&As integer expressions, X is greater than or equal to Y.\cr X =:= Y&O&As integer expressions, X is equal to Y.\cr X =\\= Y&O&As integer expressions, X is not equal to Y.\cr X = Y&O&X unifies with Y.\cr X \\= Y&&X does not unify with Y.\cr T =.. L&&The functor and arguments of T are elements of list L.\cr X == Y&&Terms X and Y are strictly identical.\cr X \\== Y&&Terms X and Y are not strictly identical.\cr X @< Y&&Term X precedes term Y in the canonical ordering.\cr X @=< Y&&Term X precedes or is identical with Y.\cr X @> Y&&Term X follows term Y.\cr X @>= Y&&Term X follows or is identical with Y.\cr} \section{Arithmetic Expressions} \noindent The following expressions can make up arithmetic expressions to be used on the right-hand side of an {\tt is}. X and Y are expressions. Open-code is generated for arithmetic expressions known at compile-time. Variables in arithmetic expression may be bound to either integers or other arithmetic expressions; in the latter case, the bound expression will be interpreted at run-time. {\sl Arithmetic exceptions are not detected.} \medskip \smallskip \halign{\tt#\hfil&\quad#\hfil\cr +X&Unary addition.\cr -X&Unary subtraction.\cr X + Y&Addition.\cr X - Y&Subtraction.\cr X * Y&Multiplication.\cr X / Y&Division.\cr X mod Y&Remainder.\cr X /\\ ~Y&bit conjunction.\cr X \\/ Y&bit disjunction.\cr X << Y&bit shift X left by Y bits.\cr X >> Y&bit shift X right by Y bits.\cr \\X&bit negation.\cr cputime&CPU time since the start of the session, in milliseconds.\cr calls&Number of Prolog procedure calls since the start of the session.\cr {\it integer}&The value of any integer.\cr {\it list}&The first element of the list is evaluated as an expression.\cr} \magnification=1200 \input format \centerline{\bf Design and Simulation of a Prolog Machine} \smallskip \centerline{W F Clocksin} \bigskip \section{1. Introduction} \par We describe an abstract Prolog machine, called the ZIP machine, which is suitable for implementation in software, microcode, or hardware. The main requirements of the design are that \sbx It should be portable. \sbx It should imply a high-performance implementation suitable for large-scale commercial and industrial applications. \smallskip\noindent These conflicting requirements have led to the design of a system which is a reasonable compromise. The ZIP machine forms the basis of a working Prolog system, called Prolog-X, which has been implemented twice in different computer languages, and which has been transported to several operating systems and three different versions of Unix. Prolog-X contains a resident compiler which compiles Prolog clauses into compact bytecoded instructions which are then emulated by software. Using the software emulator, the ZIP machine runs Prolog programs at a speed fas ter than purpose-built Prolog interpreters, but slower than if programs were compiled into native machine instructions. The primary intention of the software emulator is that it should serve as a model for a microcode or hardware implementation from which one can expect higher performance. \smallskip\noindent Two fundamental principles have guided the design of the ZIP machine: \sbx Despite decreases in the price of memory, compact representations of code and data will continue to be important for languages such as Lisp and Prolog, which generally have poor locality of reference. Compactness should improve locality, which in turn should improve interaction with caches and paging. \sbx It is important to use low-overhead implementation techniques which ``scale up'' well. The performance of the system must not decrease dramatically and disproportionally as the size of the application program increases. \smallskip\noindent Consequences of these principles will be discussed below. The ZIP machine uses a similar principle of operation as the DEC-10 Prolog system of Warren (1977), modified to incorporate tail recursion optimisation (Warren, 1980). The main differences are: \sbx The use of copying instead of structure-sharing as the means of constructing compound terms. \sbx Choice points are created only when required instead of at every procedure call. \sbx Potentially global variables in the final goal of a clause are made global only if required at run-time, instead of by default at compile-time. \sbx Extra checks are made at run-time to detect determinate computations as early as possible. \smallskip\noindent Many aspects of the ZIP machine are similar to a new Prolog machine design independently proposed by Warren (1983). In addition, the Prolog-X system built around the ZIP machine removes several restrictions imposed by the DEC-10 Prolog system: \sbx The user perceives no difference between compiled clauses and interpreted clauses (except for performance). For example, any clause in the database may be examined and modified. \sbx Database references from one clause to another are permitted. \smallskip\noindent The ZIP machine is defined by a word format, a set of registers, the format of storage areas, an instruction set, and assumptions about the layout of data structures in memory. Prolog data-structures are represented by a tagged 32-bit word, and Prolog clauses are represented as sequences of 8-bit bytes. In the Prolog-X system, a resident compiler (written in Prolog) incrementally compiles clauses into a compact bytecode sequence. Each instruction consists of a one-byte operation code followed by from zero to three one-byte arguments. The bytecode emulator consists of a number of small routines that define the different operations. Some instructions can be executed in three different modes, so there is a separate routine for each mode. The first version of the Prolog-X system was written in Pascal under VMS for the DEC VAX in 1982. It was then ported to the ICL 2980 under VME, and the bytecode emulator was subsequently translated into the VME systems programming language S3. The first version was also used as the basis of a separate Prolog implementation design study (Bowen, Byrd, and Clocksin, 1983). The second (and current) version of Prolog-X is a translation of the first version into the C language running on the ICL Perq under PNX (similar to System III Unix). This version has been ported to the HLH Orion and the DEC VAX, both running Berkeley Unix 4.1. To demonstrate its efficiency, compatibility, and comprehensiveness of implementation, Prolog-X has been used to run Chat-80 (Warren and Pereira, 1982) and PRESS (Sterling, {\sl et al.}, 1982), two large programs written originally for DEC-10 Prolog. \section{2. Data Words} Every data structure is represented by a ($t+v$)-bit word which is divided into a {\sl tag} field of $t$ bits in length, and a {\sl val} field of $v$ bits in length. The {\sl tag} field is ideally 8 bits long, but Prolog-X uses only 4, encoding unique tags as unique 4-bit integers. With more bits available, a redundant coding could be used to speed up certain tag tests. The {\sl val} field is ideally 32 bits long so that single-precision floating point numbers can be represented directly. Prolog-X uses a 28-bit val and does not implement floating point numbers at all. Integers in the range $-2^{28}\ldots2^{28}-1$ are represented directly in the {\sl val}, and have tag {\tt INT}. The 16 primitive tagged objects are as follows: \medskip \halign{\indent#\hfil&\quad\tt#\hfil&\quad#\hfil&\quad#\hfil\cr {\bf Tag}&\hfil{\bf Mnemonic}&\hfil{\bf Val}&\hfil{\bf Purpose}\cr 0&INT&integer value&integer\cr 1&FLOAT&float value&single-precision float\cr 2&BOX&pointer to a {\tt BLOCK} cell&byte string\cr 3&ATOM&pointer to an atom cell&atom\cr 4&TERM&pointer to a compound term&compound term\cr 5&LINK&pointer to a variable binding&instantiation\cr 6&{\sl reserved}&&\cr 7&UNDEF&pointer to self&unbound variable\cr 8&FUNCTOR&pointer to a functor cell&functor information\cr 9&BLOCK&byte count&header of null-padded byte string\cr 10&EMPTY&unused&to catch bugs\cr 11&TERMIN&unused&terminate internal chains\cr 12&CLAUSE&pointer to clause cell&clause information\cr 13&TABLE&component count + 1&header for word table\cr 14&TABREF&pointer to {\tt TABLE} cell&vector\cr 15&PROC&pointer to a procedure cell&procedure\cr \medskip A compound term of arity $n$ is represented by a {\tt TERM} pointer to a cell of $n+1$ words. The first word of the cell is a {\tt FUNCTOR}-tagged pointer to the appropriate functor cell. The components of the term follow in the subsequent words. Some of the above tags are not strictly necessary. It is possible to represent procedures, clauses, tables, and functors as compound terms or tables. This would provide a more uniform and simple set of data structures, but would cost more in memory fetches. For example, to test whether something is a clause, we test the tag, which is very fast. Representing a clause as a compound term would mean testing for a clause by fetching and testing its header (a functor pointer). The reserved tag is intended for the implementation of a {\tt CONS} tag for more efficient representation of lists. The present implementation of a list cell is as a compound term having functor `{\tt .}' of arity 2. Thus, a {\tt TERM}-tagged word points to a three-word cell having a {\tt FUNCTOR}-tagged first word followed by the head and tail words. In the future implementation, a {\tt CONS}-tagged word would point to a two-word list cell containing the head and tail. \section{3. Layout of Data Object Cells} In common with other cell representations used in LISP and POP-2, multiword storage cells are accessed by a tagged pointer to the first word in the cell. The most obvious difference is that {\tt LINK} pointers are allowed to point directly to words within a cell. Although constants can be represented as functors of arity 0, ZIP does not use this convention; a functor of arity 0 is consistently represented as an atom, preventing unnecessary construction of functor cells. Any unused component of a cell is occupied by a {\tt TERMIN} word. We now show the layout of each data object understood by ZIP. Some of these objects contain extra fields for debugging and diagnostic purposes not connected with the execution of the ZIP machine. For example, given a compiled clause cell, it is possible to follow back a chain of pointers from its procedure to its functor to its atom, for the purposes of printing its name for diagnostic purposes. \smallskip\noindent {\tt ATOM}. The {\tt ATOM} word points to a three-word cell. \item{(1)}A hash chain, continued by an {\tt ATOM} pointer or terminated by a {\tt TERMIN} word. \item{(2)}A functor chain, continued by a {\tt FUNCTOR} word or terminated by a {\tt TERMIN} word. \item{(3)}The atom name, containing a {\tt BOX} word. \smallskip\noindent {\tt FUNCTOR}. The {\tt FUNCTOR} word points to a cell of four words. \item{(1)}An {\tt ATOM} word to the atom naming this functor. \item{(2)}An {\tt INT} word containing the arity of the functor. \item{(3)}A {\tt FUNCTOR} word pointing to the next functor cell of any other functors of the same name having different arities. \item{(4)}A {\tt PROC} word pointing to the procedure cell, if any. \smallskip\noindent {\tt PROC}. The {\tt PROC} word points to a cell of six words: \item{(1)}An {\tt INT} word containing various flags. \item{(2)}An {\tt ATOM} word naming the module in which the procedure is defined \item{(3)}An {\tt ATOM} word naming the module in which the procedure is visible. \item{(4)}A {\tt FUNCTOR} word pointing to the functor associated with this proc edure. \item{(5)}A {\tt PROC} word pointing to the next procedure with the same functor but with different module characteristics. \item{(6)}The clauses for this procedure. For Primitive Procedures, this is an {\tt INT} word identifying the particular Primitive. For procedures defined by Prolog clauses, this is a {\tt TABREF} word pointing to a two-compone table. The first component is a {\tt CLAUSE} word pointing to the first clause; the second component is a {\tt CLAUSE} word pointing to the last clause. \smallskip\noindent {\tt CLAUSE}. The {\tt CLAUSE} word points to a cell which represents a single Prolog clause. Clauses are bidirectionally chained so that inderting and deleting clauses from the chain can be performed in constant time. A clause is at least seven words in length. The eighth and subsequent words are any Prolog data word. These are used as references to data structures used by the ZIP instructions of the clause, and are accessed by an offset from the XC register, which points to the clause cell of the currently executing clause. The first seven words of the clause cell are: \item{(1)}An {\tt INT} word contains various flags. \item{(2)}A word used as a search key when searching clauses in the database. The key is related to the first argument of the clause. The key is the same as the first argument for constants; is an {\tt UNDEF} word for variables or no first argument; is the principal functor for compound terms. \item{(3)}A {\tt PROC} word pointing to the procedure owning this clause. \item{(4)}A {\tt BOX} word pointing to the byte code block containing the ZIP instructions for this clause. \item{(5)}An {\tt INT} word containing the total size of the clause cell in words. \item{(6)}Either a {\tt CLAUSE} word pointing to the previous clause, or a {\tt TABREF} word. \item{(7)}Either a {\tt CLAUSE} word pointing to the next clause, or a {\tt TERMIN} word. \smallskip\noindent {\tt TERM}. A compound term of arity $n$ is represented by a {\tt TERM} pointer to a cell of length $n+1$. The first word of the cell is a {\tt FUNCTOR} pointer to the appropriate functor cell. Subsequent words are the components of the compound term. \smallskip\noindent {\tt BOX}. The byte string of length $n$ bytes is represented as a {\tt BOX} word pointing to a block cell of length $((n-1) \gg 2)+2$ words. The first word of the block cell has {\sl tag} {\tt BLOCK} and {\sl val} $n$. Subsequent words contain bytes packed four to the word, null-padded to the nearest word. The padding is required because boxes are compared with each other word-at-a-time. \smallskip\noindent {\tt TABREF}. The vector of length $n$ is represented by a {\tt TABREF} word pointing to a table cell of $n+1$ words in length. The first word of the table cell has {\sl tag} {\tt TABLE} and {\sl val} $n+1$. The subsequent $n$ words contain the $n$ components. \section{4. Registers} The current state of a computation is contained in a set of registers, most of which point into the storage areas discussed below. The registers having contents valid at all times are: \smallskip \halign{\indent#\hfil&\qquad#\hfil\cr PM&processor mode\cr XC¤t clause pointer\cr D¤t data pointer\cr PC¤t program counter\cr L¤t (target) local frame\cr CL¤t (source) local frame\cr CP&forward continuation program counter\cr CL0&forward continuation local frame\cr G&global stack allocated top\cr G0&global stack committed top\cr H&heap freelist\cr BL&backtrack continuation local frame\cr BG&backtrack global stack top\cr BP&backtrack continuation clause\cr TR&trail allocated top\cr TR0&trail committed top\cr} \smallskip\noindent Some of the above registers are redundant in that they are caches for slots in t current local frame. Other registers not mentioned here are scratchpad registers whose contents are valid only during the execution of a single ZIP machine instruction. \section{5. Storage Allocation} Storage is allocated in four main areas, although small scratchpad stacks are used for other housekeeping within primitive procedures not a part of the ZIP machine. The four areas are summarised here, and more detailed discussion is given below. \sbx Activation records are allocated on the Local stack, which is implemented as a true stack with contiguous storage but allowing indexing into it. Local stack frames do not require garbage collection, as this is done automatically as a result of certain ZIP instructions which control tail-recursion optimisation. Variable slots in the local frames are the source of all roots to data structures. Variable slots are not initialised upon activation, because the first use of a variable is identified by the compiler, and appropriate action is taken by the generated instruction. \sbx The Global stack, in which most temporary data structures are allocated, should also be a true stack, but it is also necessary to index from arbitrary pointers into the stack. Space is automatically recovered on backtracking, although garbage collection is nowadays considered necessary to recover space in situations where backtracking can never occur. These issues are discussed below. \sbx Persistent data structures are allocated in the Heap, which should be implemented as a heap. Allocations and deallocations are programmed explicitly (by using {\tt assert(X)}, {\tt retract(X)}, and other more primitive predicates). A simple reference-bit garbage collection scheme discussed below is used. The ZIP machine sees the heap only in that registers PC, CP, XC, and BP point into it. \sbx The Trail is an historical record of variable instantiations. When certain variables are instantiated, a pointer to the varia ble is entered on the Trail so that the variable can be reset when backtracking. Only variables occurring previous to the current backtracking point are trailed. The trail also holds other information of a chronological nature required for garbage collection of clauses. This is also a true stack, with pushes and pops being done by the ZIP machine. \smallskip\noindent In addition, the ZIP machine uses a small scratchpad stack when executing code between the \key{functor} and \key{pop} instructions (see below). Local stack frames, called activation records, are offset from register CL. The order of the first eight entries is unimportant but must be consistent. A complete stack frame stores the following entries, although in some cases (determinacy), not all register save entries are used. An ordering could be imposed to increase speed, as registers CP, CL0, XC, and G0 are saved or restored at the same time by several of the machine instructions. An activation record, in order of increasing address, is laid out as: \smallskip \vbox{\offinterlineskip \halign{&\vrule#&\strut\quad\hfil#\hfil\quad&\vrule#\cr \trule &(reserved)&\cr \trule &continuation program counter&\cr \trule &continuation local stack frame&\cr \trule &backtrack clause pointer&\cr \trule &global stack pointer&\cr \trule &backtrack local stack pointer&\cr \trule &trail pointer&\cr \trule ¤t clause pointer&\cr \trule &\pitprop (arguments and local variables)&\cr \trule &\pitprop (temporary local variables)&\cr \trule}} \smallskip\noindent The argument slots hold the actual parameters of the procedure call. If a variable appears at the top-level in the head of a clause, then its value is simply that of the corresponding actual parameter, and there is no need to allocate a variable slot for it. Locals classified by the compiler as temporaries are allocated nearest the top of the stack, so that the stack space occupied by temporaries can be recovered automatically when the neck of a clause is executed. \section{6. ZIP Instructions} The ZIP Machine is always in one of three states called Processor Modes: {\tt ARG}, {\tt COPY}, or {\tt MATCH}. Many of the instructions described here have alternative interpretations dependi on the current Processor Mode. Some of the instructions switch the Processor Mode. Each instruction is encoded by a byte containing a number $0\ldots63$, which is combined with the contents of the PM register (2-bit Processor Mode) to form an 8-bit operation code. Arguments, if any, follow in the subsequent zero, one, two, or three bytes. Arguments of an operation code are of three different types: \sbx An integer in the range $0\ldots255$. This is encoded directly as an argument byte. \sbx A procedure argument or variable within the current clause. All procedure arguments and variables are found in the current stack frame offset from register CL, so the argument is encoded as a byte offset from CL. \sbx A functor, procedure, or constant. These are known as external references and data words referring to them are stored in an area of the clause cell known as the external references table. Register XC always points to the current clause cell, so such arguments are encoded as a byte offset from XC. The instructions described here are generated by an optimising compiler written in Prolog, and residing in the Prolog-X system. The compiler is capable of identifying cases where full unification is not required, where data structures should migrate to other areas, where tail recursion is used, where unit and doublet clauses require less housekeeping, and where certain built-in predicates are translated directly as ZIP instructions (instead of generating calls). Special-purpose instructions are generated in these cases. There are no instructions defined for handling disjunctions. Disjunctions are interpreted using the \key{callx} instruction, which handles interpreted calls to the ``cut'' predicate correctly. Before describing each instruction individually, we shall first show how instructions are generated from Prolog clauses. Suppose we are given terms $t_1,\ldots,t_l$, $u_1,\ldots,u_m$, $v_1,\ldots,v_n$, and predicate symbols {\tt p} of arity $l$, {\tt q} of arity $ {\tt r} of arity $n$, not all necessarily distinct. Then the clause \smallskip \centerline{\tt p($t_1,\ldots,t_l$) :- q($u_1,\ldots,u_n$), r($v_1,\ldots,v_n$)} \smallskip\noindent compiles into the sequence: \block {\sl code for $t_1$} $\vdots$ {\sl code for $t_l$} enter {\sl code for $u_1$} $\vdots$ {\sl code for $u_m$} call $x$ {\sl code for $v_1$} $\vdots$ {\sl code for $v_n$} call $y$ exit \endblock The \key{enter} instruction marks the division between the head and body of the clause, and creates a choice point if necessary. This instruction employs an argument, not shown, giving the size of the local stack frame. Each \key{call} instruction has byte argument which refers to an entry in the external references table which is a reference to the required procedure. Finally, \key{exit} marks the end of the clause, and passes control to the forward continuation. \noindent The compilation of terms proceeds as follows: \sbx If the term is atomic, it is translated as \key{constant $n$}, where $n$ is a byte offset from the external references table. The term is inserted into the $n$th entry of the external references table. \sbx If the term is a variable, it is translated as \key{var $n$}, where $n$ is an offset from the current stack frame register CL. \sbx If the term is compound (consider the compound term {\tt t($a_1,\ldots,a_n$)}, where each $a_i$ is a term), then it is translated as: \block functor $f\quad n$ {\sl code for $a_1$} $\vdots$ {\sl code for $a_n$} \endblock The \key{functor $f\quad n$} instruction refers to an offset $f$ from XC to an entry in the the external references table pointing to the functor cell for the term. The arity $n$ is included for efficiency. Code for the $n$ arguments and a housekeeping instruction follow. \smallskip\noindent The ZIP instruction set contains many optimised variants of the above instructions. For example, integer constants $0\leq n\leq 255$ compile into \key{immed $n$} instead of taking up external reference space. The constant {\tt []}, used to represent the null list, compiles into \key{constnil} for the same reason. The functor `{\tt .}' of arity 2, used as a list constructor, compiles into \key{conslist} instead of \key{functor $n$ 2}, where $n$ would be an XC offset. There are many variants of the \key{var} instruction, generated as a result of a flow analysis of the clause as it is compiled. Details of the general idea are given in Warren (1977), and are relevant despite the fact that Warren uses structure-sharing to represent data structures. A complete list of the instruction set is given in Appendix A. We now give an example of the ZIP instructions into which the Prolog {\tt concatenate} predicate compiles. Associated with each clause is a clause cell as previously described, which contains the external references table. The code sequences shown here constitute only the code body, and are each only a few bytes in length. The {\tt concatenate(X,Y,Z)} goal succeeds when the list {\tt X} concatenated with the list {\tt Y} gives the list {\tt Z}: \block concatenate([],L,L). concatenate([X|L1],L2,[X|L3]) :- concatenate(L1,L2,L3). \endblock The ZIP ``assembly language'' into which {\tt concatenate } compiles is as follows. Two code sequences are shown, one for each clause of {\tt concatenate}. Many of the instructions shown are optimised variants of those introduced above. \smallskip \halign{\tt#\hfil&\qquad\sl#\hfil\cr constnil&unify with {\tt []}\cr skipvar&an optimisation of the first variable L\cr var 9&...because this one does the work\cr return&exit with success, no subgoals\cr &\cr conslist&unify the list constructor\cr firstvar 13&unify the head (variable X)\cr firstvar 11&unify the tail (variable L1)\cr pop&finished with that term\cr skipvar&optimisation for variable {\tt L2}\cr lastconslist&unify list constructor, no \key{pop} needed\cr var 13&head {\tt X}\cr firstvar 12&tail {\tt L3}\cr argmode&an optimised \key{enter} (only 1 subgoal)\cr var 11&push first argument L1\cr var 9&push second argument L2\cr var 12&push third argument L3\cr proceed 1 3&tail-recursive call of {\tt concatenate}\cr \smallskip\noindent The final \key{proceed} instruction takes the procedure cell for {\tt concatenate} from the first entry in the external references table, and performs a tail-recursive call, reusing the current stack frame. The actual operation performed by each instruction depends on the context provided by the PM register. During the execution of the head of a clause, the processor is in {\tt MATCH} mode, and each instruction attempts to unify its argument with the arguments of the goal. Within the code for a term, data structure construction must be performed, so the processor switches to {\tt COPY} mode so that each instruction can construct its argument by copying. During the execution of the body of a clause, the processor is in {\tt ARG} mode, and each instruction passes its argument to the subgoal to be called. Maintaining the correct contents of PM is a simple task performed by some of the instructions. For example, \key{enter} and its optimised form \key{argmode} assign mode {\tt ARG} to PM. The \key{functor} instruction pushes the contents of PM on a scratchpad stack and sets PM to {\tt COPY}. The matching \key{pop} instruction restores PM from the scratchpad. \section{7. Arithmetic Instructions} The Prolog goal {\tt is(X,Y)} is defined to consider the term bound to {\tt Y} as an arithmetic expression, and to evaluate it according to the rules of arithmetic, and to unify the result with X. This goal is normally written in infix form as ``{\tt X is Y}''. Consider the goal \smallskip \centerline{\tt Z is X << 8 + Y.} \smallskip \noindent Evaluation of arithmetic expressions is complicated by the fact that Prolog allows {\tt X} and {\tt Y} to be bound not only to integers, but also to other arithmetic expressions (terms). This can only be detected at run-time, so the usual methods for generating code for arithmetic expressions are not sufficient. The DEC-10 Prolog compiler did not implement this feature, and gave an error when arguments of arithmetic expressio were not integers. This behaviour was different from the DEC-10 Prolog {\sl interpreter}, which evaluated all arithmetic expressions correctly. The solution taken by Prolog-X is to generate a sequence of instructions which tests the tag of the word bound to each unique variable in the expression. If the value is an integer, then execution proceeds normally, using the value in the calculation. If the value is a non-integer, the ZIP machine performs a call to a procedure, written in Prolog, which recursively evaluates the expression and passes the result back. The instruction for performing the run-time test is \key{eval $v_i$ $v_j$}, which for variables (local stack offsets) $v_i$ and $v_j$, evaluates the term bo und to $v_i$, placing the resulting value in $v_j$. During the execution of the \key{eval $v_i$ $v_j$} instruction, if the word at stack offset $v_i$ is not an integer, then the term {\tt is($v_j$,$v_i$)} is constructed on the global stack, and control proceeds to the \key{callx} instruction. Arithmetic operations are compiled into three-address (or two-address for unary operations) code. Temporary registers required during the evaluation of expressions are represented simply as variables. The associated overhead is not high, but the resulting program is not nearly as compact and efficient as it would be if a stack model were used. We had experimented with other designs before deciding on the three-address model with its obvious drawbacks. The main advantage of the model as it is currently implemented is that no special mechanisms (such as extra ZIP registers and conventions) are required. The additional mechanisms required for stack handling of arithmetic expressions within the existing compiler and execution model were too awkward to consider seriously, and contributed disproportionally to the complexi of the ZIP machine. For an example of code generated from arithmetic expressions, using $v_i$ to den ote byte offsets from CL, the above expression compiles into: \smallskip \halign{\tt#\hfil&\qquad\sl#\hfil\cr eval $v_1\quad v_2$&evaluate {\tt X}, move result to $v_2$.\cr movi 8\quad $v_3$&instantiate $v_3$ to a small integer.\cr shl $v_2\quad v_3\quad v_6$&$v_2$ shifted left by $v_3$ gives $v_6$\cr eval $v_4\quad v_5$&evaluate {\tt Y}, move result to $v_5$.\cr add $v_6\quad v_5\quad v_7$&add $v_6$ to $v_5$ giving $v_7$\cr Only one \key{eval} instruction is generated per unique variable, preventing duplicate evaluation of common variables. In addition, constants are also shared in the same way, leading to better efficiency. For example, the expression \smallskip \centerline{\tt Y is 3 * (X << 5) + 5 * (X << 3)} \smallskip\noindent compiles into: \halign{\tt#\hfil&\qquad\sl#\hfil\cr eval $v_1\quad v_2$&evaluate {\tt X}, move result to $v_2$.\cr movi 5\quad $v_3$&instantiate $v_3$ to a small integer.\cr movi 3\quad $v_4$&instantiate $v_4$ to a small integer.\cr shl $v_2\quad v_3\quad v_6$&\cr mul $v_4\quad v_6\quad v_7$&\cr shl $v_2\quad v_4\quad v_8$&\cr mul $v_3\quad v_8\quad v_9$&\cr add $v_7\quad v_9\quad v_10$&\cr \smallskip\noindent The code shown here contains only about 30\% more bytes than the stack code gene rated by the experimental compiler. This is acceptable given the low static occurrenc of arithmetic expressions in typical Prolog programs. There is a considerable increase in execution speed for those arithmetic expressions from which ZIP instructions can be generated. Speed increases by a factor ranging from 10 to 50 compared with the interpretation of expressions by recursive descent with a Prolog program. \smallskip \section{8. Discussion of Storage Allocation} \subsection{8.1 Local Stack} When a goal succeeds determinately, its local frame is discarded. If the procedure is determinate at the point where the last goal in the body of the clause is about to be called, then the frame for that goal replaces the frame for the procedure. This is how tail recursion optimisation is implemented. One problem is as follows. Suppose a goal replaces a frame that has variables that refer to the goal. In this special case, which is detected during compilation, space for the affected variables is migrated to the global stack. The instructions generated to perform this task are \key{glofirvar} and \key{glovar} (see Appendix A). Migration may not in fact be necessary, and a run-time check determines this. \subsection{8.2 Global Stack} As mentioned above, garbage collection is required for the global stack only when inaccessible structures are created in the absence of backtracking. The current implementation of Prolog-X does not perform garbage collection in the absence of backtracking. If it is necessary to garbage collect the global stack, then a normal mark-sweep-reallocate algorithm can be used. References to data in the global stack are rooted in the local stack variables. A refinement of the usual algorithm recognises that it it not strictly necessary to mark accessible structures if it is known that the local variable will not be used subsequently in the current goal. This has the effect of reclaiming much space that normally would not become inaccessible until a determinism has been committed. Other relevant issues are discussed below. \subsection{8.3 Heap} Clauses and database entries (using the {\tt record}{\it x} predicates) are stored in the Heap. They are incrementally garbage collected after they have been {\tt erase}d, but only after they are not being used in a program, and after no database references to them exist. Two bits for each clause are required for this purpose: a {\tt CLAIMED} bit and a {\tt DOOMED} bit. In addition, database references to clauses are permitted, and a reference count field is used for this purpose. The details of the incremental garbage co llection method used are discussed by Clocksin (1984). \section{9. Problems with Storage Management} The strict Prolog execution model permits the use of stack-like memory management, with which storage is reclaimed immediately upon backtracking. Under usual circumstances, this obviates the need for costly allocation and garbage collection of cells from a heap. Also, most heap garbage collectors do not allow pointers to within cell bodies, thus preventing the most efficient way of implementing Prolog variable bindings. Furthermore, allocation from stacks improves compactness. Despite the advantages of stack-like storage management used by Prolog-X, there are two problems with this method. First, certain Prolog programming techniques rely on never backtracking, using Prolog goals to simulate perpetual processes which communicate {\sl via} shared variables. Such techniques (Shapiro, 1982; Warren, 1982) are more popular now than when Prolog-X was first designed, and are likely to form the foundation of future applications written i Prolog. Prolog-X however relies on backtracking to reclaim any redundant data structures constructed, and because no further garbage collection is performed, Prolog-X is unable to reclaim such structures in the absence of backtracking. Implementing a garbage collector for the global stack is only a short-term measure which does not counter the second problem. The second problem arises from another trend, that of mixed-language programming with shared data structures. With systems such as Poplog (Mellish and Hardy, 1982) and LM-Prolog (Kahn, 1983), it is possible to share data structures and call procedures between Lisp and Prolog programs, and this leads to a very attractive programming methodology. Such systems are implemented by the use of a common virtual machine together with a common garbage collected heap. The ZIP machine, on the other hand, is tailored so exclusively to the stack-like execution model of Prolog that it would be impracticable to compile Lisp programs, say, to run under the ZIP machine. It is more reasonable to design a heap-based common virtual machine, considering carefully the interaction with long-term and short-term data structures, and with incremental garbage collection. \section{Acknowledgements} The work reported here owes much to preliminary design effort of Lawrence Byrd, a discussion with David Warren, and to much good advice contributed by Richard O'Keefe. Transporting the first version of Prolog-X to the ICL 2980 under VME was done by Paul Cager, Alan Reiblein, and Jim Doores of ICL. \section{References} \noindent Bowen, D L, Byrd, L M, and Clocksin, W F, 1983. A portable Prolog compiler. {\sl Proceedings of the Logic Programming Workshop}, Albufeira, Portugal. \smallskip\noindent Clocksin, W F, 1984. Implementation techniques for Prolog databases. {\sl Software---Practice and Experience}, to appear. \smallskip\noindent Kahn, K, 1983. Unique Features of LISP Machine Prolog, UPMAIL Report 14, University of Uppsala, Sweden. \smallskip\noindent Mellish, C S, and Hardy, S, 1982. Integrating Prolog in the Poplog Environment, Cognitive Science Research Paper 10, University of Sussex. \smallskip\noindent Shapiro, E Y, 1982. A subset of Concurrent Prolog and its interpreter, Technical Report TR-003. Institute for New Generation Computer Technology, Tokyo. \smallskip\noindent Sterling, L, Bundy, A, Byrd, L, O'Keefe, R, and Silver, B, 1982. Symbolic reasoning with PRESS, in {\sl Computer Algebra} (ed J Calmet), {\sl Lecture Notes in Computer Science 144}, Springer-Verlag. \smallskip\noindent Warren, D H D, 1977. Implementing Prolog -- compiling logic programs. Research Reports 39, 40. Department of Artificial Intelligence, University of Edinburgh. \smallskip\noindent Warren, D H D, 1980. An improved Prolog implementation which optimises tail recursion, {\sl Proceedings of the Logic Programming Workshop}, Debrecen, Hungary. \smallskip\noindent Warren, D H D, 1982. Perpetual processes -- an unexploited Prolog technique, {\sl Logic Programming Newsletter}, {\bf 3}, 2. \smallskip\noindent Warren, D H D, 1983. An abstract Prolog instruction set. Technical Note 300. SRI International, Menlo Park, California. \smallskip\noindent Warren, D H D, and Pereira, F C N, 1982. An efficient easily adaptable system for interpreting natural language queries. {\sl American Journal of Computational Linguistics} {\bf 8}, 110-122. AADDD AADDDDDD ADDD AfffFa Stop Program Arguments ErrorStream SBlockWrite CloseStream FindInput FindOutput FindUpdate SBlockRead GetFileOffset BytesOutstanding SetFileOffset Allocate Store XBlockWrite BlockRead XWriteByte XSelectInput XSelectOutput XDeleteFile File XBytesOutstanding Signal Handler ,×Å|×Õ _:ë=×Å`çÝÀ *0×Õ |¥èסð ëÁ`Ç¡À KÇ¡ 2Ç¡À ØWÃx \`ê¿wWÁ` <×Åxë¥ ÿÿÿ" Ì \'® ÔWÁx T× ð ëÀ`Ç  2Ç À ØWÂx \`꾿 Æx`× ð ëÀ`Ç ° åWÀ` ×Àx xW ð lê5G P +Àxסð êx×Á` `W ð kÀ`G ° ÈÎXQ t× ð ëÀtÇ p ~ xסð ëÁxÇ¡` xêhÇ¡p ¦Ç¡@ x× ð hê4Ç P «ÀxW¡ð êxWÁ` `× ð ëÀ`Ç ° tW ð kÀtG p ¿o×Ð ÈÎÏP |_Àd' Ì \'Ö %×Å|×Õ _¸_¸×Õ À|'V |ÎXP WÀT'N|T ÁT'v|T \ê¿yG  ÆTWÀT'N|T \ê¿`G  &WÀ|'N |ÎØI ÁlWÁlW# &WÁ\'n Á|'f |ÎX` çG  ¹×À|'^ |ÎXX Û1WÁ\W; aסp ÛÁ\WÁ\W; )×Àx×" ÐÇÂh Ä×Âx ê ×Á\×Ãx Â\ê¾MG  P×Á|'~ ÎOÀx Á\'f fWÁ\'n ÎÏÀx Æx¿¼ Æ¿¼¿¸×À|'^ Çx¿¸ 4×Á|'~ À\ÎXx Á\WÁ\W# \ê½UG  Á|'v |ÎXq ÁlWÀlW" ×À\'^ ØÚ¿» Á|'f |×À\'^ \W ` Ôê¼ÅG  ØÚ¾r×Á|'~ x× ð ëÀxÇ ` xêhÇ p VÎOÀx Øj5WÁ\'n Ôê¼>×Á\'~ ê¼)×Á\'~ \×Ãx Á|'v xWÁx'n Á\×À\×" \êaG  Á\×À\×" \ê»È Â\껾G  Á|'f |ÎØ` \껡G  &WÀ\'N ÐÇÃh Ä×Ãx ÔWÁxW3 Ô×À|'^ |ÎXX ÂT×ÁT×Ã\ Á|'f |ÎØ` d꺽 Á|'v |WÁxÎ ÂT×ÀT×Â\ TWÀTWÂd ÿÿÿ'n \êºuG  Á\'f xW ð kÀxG ` xêhG p ÐGÂh ÄWÂx ÂT×ÀT×Â\ TWÁTWÃd d깺G P TWÁTWÃd {WÁ\'n Á|'f |ÎØa ÈWòG ÂT×ÀT×Â\ Ô\WÀ|'N WÁ\'n ÂTWÀTWÂ\ d긺G  øWÁ\ xW¡ð kÁxG¡` xêhG¡p ÔWÀxW* Ô×À|'^ È×óf À|'V dê·ïG¡@ Á|'f |WÀxÎ À|k  ÿÿÿ'N \ê·¼G  ®WÁ\ xW¡ð kÁxG¡` xêhG¡p ÐGÃh ÄWÃx Ô×Àx×: bס@ ÔWÁ\W; ÔWÀ|'N È×òt À|'V dê¶ G  ÔWÁ\W3 dê¶bG  Á|'v tê.G  WÁ|'n |ÎXh Á\'f ÐÇÃh Ä×Ãx 9êµ¥G  À\'V \WÀ|'N WÀ\'N Á|'v |ÎXq ÈWòe êµaG  Á\'f êµJG  ÈlWÀlt¢ ëÁ`Ç¡° 6ÎÏÀ` ×Á|'~ |ÎØx Ì \'® Ðê¿ìê À|ê´QG  Æx¿´ kÁxG¡ð Âh'v l꿬 ÄWÁ|'n Ì \곦G  À|ÎXP WÀ|'N ê³oG  Ð×À|ÎXX |§~ Ì \ê³!G  Ð'~ \ê²õG  `×Á|'~ |ÎXx xê¿è Æx`_Àt 6_¸_¸×Åx" p+ ð ×Åp" |¥ô ×Åp" Àt§ð ëÀ`Ç À jסð ëÁxÇ¡@ ×Át'~ Âl×Àl xW ð kÀxG p .¿°ê Æx¿° Æ¿°¿¬WÁ\'n \Wÿ¬ ê¿´ê ~×À|'^ |ÎXX Øê­¡ À|'V Ì l' Áx'v Àh'F h×Ál'~ Ìê­`G  /WÀ|'N |ÎXI Ì×Â| Øê­+G  Ì \ê Èl×Àlô¢ 6ÎÏÀ` ÄWÂ` ×À|Î Ì \×Ð ê¯âG  WÀ|'N xסð ëÁxÇ¡` xê¿èÇ¡p ×Á|'~ |ÎXx xê¿è Øê¯DG  WÀ|'N xê¿è ê®õG  À|'V |ÎXP xê¿è ?ꮫG  Á|'v |ÎXp xסð ëÁxÇ¡` xê¿èÇ¡p ðÇ¡@ çÇ¡P Þê®JG  Ì \×Á\ xסð ëÁxÇ¡` xê¿è ¿¨ê Î Æx¿¨ Æ¿¨¿¤ Æ¿¤x f×Á\ tסð ëÁtÇ¡` tê¿èÇ¡P ÇÀxz t×Á\ Ì \×Á\ xסð ëÁxÇ¡` xê¿è ë×Á\ tסð ëÁtÇ¡` tê¿èÇ¡p 1×Á\ tסð ëÁtÇ¡` tê¿èÇ¡p DWÁt_h ÐGÃh ÄWÃt ¿ê¬+ í×Á\ tסð ëÁtÇ¡` tê¿èÇ¡p >×Á\ tסð ëÁtÇ¡` tê¿èÇ¡p Át_a Ìê«8 ×ÁxÎ tê¿è GWÁx WÁxGÃt tê¿è HWÀx êª=WÀxGÂt Äêª0 xסð ëÁxÇ¡` xê¿èWÀ\ tסð ëÁtÇ¡` tê¿è ÿÿÿt z×Á\ tסð ëÁtÇ¡` tê¿èÇ¡p îê©Z×Átgñ FסP ÔW p Ì߸×Åt×Åx" |¥ô×Ñ 6x§~ Ô×Át'~ Ôê¿ß Ì \×Á\ xסð ëÁxÇ¡` xê¿è tסð ëÁtÇ¡` tê¿èÇ¡p u_À¿ ê§¹_À¿ xסð ëÁxÇ¡` xê¿è íWÁ\ tסð ëÁtÇ¡` tê¿èÇ¡p u_À¿ ꦿ_À¿|4¦ 6¿xê Î Æx¿x Ì \×Á\ Ö×Á|'~ xW ð kÀxG ` xê¿èWÁ|'n ÎÏÁt Æt¿t Æ¿t¿p×Á\'~ \×ÿp Æx¿l Æ¿l¿h×À\'^ \׿h Á|'v ê¥RG  À|'V |ÎXP .¿dê Î Æx¿d Æ¿d¿` ÂTWÁTWÿ` ê¤ýG  bWÁ|'n |ÎXh xê¿è4¦ >¿\ê Î Æx¿\ Æ¿\¿X ÂT×ÁT×ÿX ×Á|'~ |ÎXx tê¿è ÀT'V|TWÁtÎOS ê£õWÁT'n|TÎ tê£à WÁ|'n ÁT'f|TÎXh ꣱G  ÆTWÀTCJ ÆTWÀTcJ ê£wG  ÆTWÀTÎcJ ê£YG  Ñ'N|T×ÁT ê£,G  ¤'~|T ÀTW@ ê¢ÿG  ÀTNc@ ê¢ÙG  ÆT×ÀTN×Z ꢻG  ÆT×ÀTëZ ÆT×ÀTÛZ ×ÀTN÷Z ê¢fG  ×ÀTNãZ ê¢KG  ×ÀTÇZ ¿'^xTê¢'G  WÀTGJ 'NxTê¢ WÀTGJ| w'NxTê¡ßG  WÀTGJ| S'NxTê¡»G  WÀTGJ| z/'NxTê¡ WÀTGJ| 'NxTê¡uê¡­ -×Å|×Õ |¥èWÐ Äl_Àt ÆlXz xW ð kÀxG p ê¿ÕG ð ç­2" p§¨¾ÿ«Àp 4¦ p ¿©W  Æxtg© ê ×Åx" ×ÅtçÝ Ç½ê 9 Äl_Àt ÆlXz ÆlWÁl xW ð kÀxG p ê¿ÕG ð ç­2" ÎOÁx p'©¾ÿ+ÁpW# 4¦ p ¿©W  Æxtç© Û!W; ê ×Åx" Ä×Ãt ×ÅtçÝ Ç½W¡ð kÁ`G¡° tW ð kÀtG p ^ xW¡ð kÁxG¡` xê¿èG¡p ©G¡@ ×Àx xW ð ¿TG  jê6G P %WÀ` tסð ëÁtÇ¡p ¼êÿÿÞ$×Ñ ÐêÿÿÞ ëÁxÇ¡` xê¿èסð ëÁtÇ¡` tê¿è ÿÿÝí xÇ¡p +ÎOÁt ÎÏÀx P×Áx×Ãt ÐÇÃh Ä×Ãx êÿÿÝfÇ¡p G×Át×Ãx ÐÇÃh Ä×Ãt êÿÿÝ ßÀ¿H Æ¿Dl ëÁxÇ¡` xê¿èסð ëÁtÇ¡` tê¿è ôÎØÀ{§¨ »ÎÏÁt LW ` [8WÁxW ÐGÃh ÄWÃx ×Àt×" ÐÇÂh Ä×Ât E×Áx×Ãt ÐÇÃh Ä×Ãx E×Át×Ãx ÐÇÃh Ä×Ãt o×Áx À¿HÚ% lWÀlW¿L lWÁlWÿH ÿÿÿ'~ ¿P«  ÿÿÿ'V ÁxWa ×À¿P tê½Þ ×Åtë¥ ÿÿÿ×Åxë¥ ÿÿÿ" À¿HÚ% Âl×Ál×ÿP lWÁlWÿL Æx¿P Æt¿L _Á¿H x×À¿L tê½H ÁxÎÏa ÀtÎÏP À¿HÚ% lWÀlW¿L ÿÿÿ'f ¿P«  ÿÿÿ'V WÁ¿P x×Á¿L tê¼Ì Æl¿D ÿÿÙ¿×Ál'~|lWy ¿H×Àl'^|l Àl'V|l ¿L×Á¿P xWÁ¿L tê¼vêÿÿÙx arrive fail reinstate: reinstate: interpret Ld Ld (d àpÇ¡0 %ÎOÁ 1]çu ÿÿÿ" 5Ç¡@ EÎOÁ Æx|j WÁxÎ Àxêgç ÿÿÿ" êÇ¡à ]ÎÏÁ Æx|Ú5×ÁxÎ tW¡ð kÁtG¡ð ×Åt" ê ×Åt" Ç ÀxêI×Å|×Å ÿÿÿ" ~ÎÏÁ Æx|Ú5×ÁxÎ tW¡ð kÁtG¡ð ×Åt" ê ×Åt" Ç ÀxêI×Å|×Å ÿÿÿ" WÎÏÁ xW¡ð kÁxG¡° OÎÏÁ xW¡ð kÁxG¡° xW¡ð kÁ|G¡à G× ð ëÀxÇ ð {Ç ° ]G¡ð ÎÏÀ| ÎÏÀ| xÎOÀx alloc alloc getheap freecell unref dealloc ¿´ê Î Æ¿´¿° WÁd'n|d×h Àd'V|d xWÀd'N|d ÂxWÁ| check blkmov boxcmp compbox compare llà¼Ld $ÜÜT ~ |סð ëÁ|Ç¡` ÎÏÁ| n$xסð ëÁxÇ¡` ÎOÁx xêfê f$xסð ëÁxÇ¡` xêfÇ¡ ~(tסð ëÁtÇ¡` ÎÏÀt ߸×Åtë¥ ÿÿÿ×Åx" xÎÏÁ| _ÀhÜÀg \Àgêh'~ ÿÊ ç­." 8ÎOÀx z*ß¹" Ç z:ÎOP l×Ål" Ç ×Åxë¥ ÿÿÿ×Ål" ÃÅ|" Ç hWÁ|'n Àl'V Àh'F ÀxêkW¡ð .tê n tW¡ð kÁtG¡` têfG¡ n$pW¡ð kÁpG¡` ߸×Åpë¥ ÿÿÿ×Åt" |¥ô߸W± n(xW¡ð kÁxG¡` xêfG¡p f,|W¡ð kÁ|G¡` ÿÿÿ| ߸×Å|×Åx" ÿÿÿ|×° ^4p× ð ëÀpÇ ` pêf×Åp" ^ ê"סð convert makebox makeatom x4,$ initbuff findatom keepchar makeblock (($$$$@ cvtlisint h4\0 cvtlisbox cvtintlis cvtboxlis makefunct findfunct \ @¤ makeproc ,$($ findproc \ @¤ improc need need flags ÇÁ|j |êhç­ ç­ Pß¸çµ |¥èç­ ç­ P_¸çµ |¥è§Ö |×Áx'~ WÁ|'n X'Æ¿¨p'Þ ét'Ö ÀxëP @çÅ¿¨ÎOÀ ¼l×ÅlçÅ¿¨" ×Åx" xê¿y_ WÀ|×M Á|j"WÀ|G |êY_ " ǽ ×=ç­ ×=×Å T'Æ¿¬l'Þ Apç­ @çÅ¿¬×Å |¥ôçÝ EçÅ¿¬" ×Á|×õ· À|êh_À| ×Á|×õ· À|êh'¶ ×Áx×} Âxêl ×Áx×} Âxêl çy$ÇÁxj Áx×e Âxêg Æxtêp×%" Æxtj Áx×e Âxêm Áx×e Âxêl×Õ T'Æ¿¬l'Þ ëpç­ @çÅ¿¬×Å |¥ôçÝ ïçÅ¿¬"!ǽ À|êj_À| À|êj'¶ Âxên Âxên ""WÀxW Âxêi"" Æxtj ""WÀxW Âxêo tWÀt Æxtêp _2Î30W Âxên×Õ ×5ÎØÅ "$ǽ ×5ÎØÅ "$ǽ ×5ÎØÅ "$ǽ ×5ÎØÅ "$ǽ ×5"%Ç Æ||_Àx Àx꿽 fileio initfile initIO boxtostring propenfile prseentold `@$$P prisopen prseetell 0@$8 getch peekch skipch putch saveimage pphh| restimage hh``t putword ¨¨¨¸ getword ÿÿÿ§© ǽ×Å |ÎOÁ| ÿÿÿ×Å " ǽ ÿÿÿçÝ ÿÿÿçÝ Áx'v ×À|'^ À|'V \꿹 XÎOÀ dW ð kÀdG ` dêf×Åd" ÎOÁd dêf×Åd" p×Åp" ç­(" LßÀh Æhlj dêf×Åd" ÆhlÚ. ç­," Àhê¿ ç­)" ǽ_¸çµ ǽ_¸" À|×õРǽçÝ dγ¡ 6|×° dÎó  _*Îs(Îc  dÎs  _"Îó!Îã¡ dÎó¡ >p×=× ×5çÝ |¥ìçÝ ""ǽ o"#Ç PçÅ¿ "$|¥ô wçÅpçÝ uçÅ¿ "%|¥ôÎ _¸"&Ç Áp×u !"#Ç Áp×u \ê¿Pçµ "(ǽ \ê¿? |ô£ À|k@ |4¦ | 8ßÀ| ~ xסð ëÁxÇ¡` xêh+¦ ÿÿÿx×µ ëÅx_¹" NwÀxÎÏÀl lêh߸×Ål" lêh_¸×Ål" lêhÎ ÆT`×Á`×} ×Á`ÎÝ} ×Á`ÎÝ} ×Á`ÎÝ} ×Á`ÎÝ} ~ lסð ëÁlÇ¡` lêhÎ À`×E ~(lסð ëÁlÇ¡` WÀl×À`ÎÍ ^,lסð ëÁlÇ¡` WÀlWÁ`ÎM n0lסð ëÁlÇ¡` V4lסð ëÁlÇ¡` ~ lסð ëÁlÇ¡` lêh×Ålë¥ ~ lסð ëÁlÇ¡` f$hסð ëÁhÇ¡` hêh×Åh×Ål" ǽÎÏ ~ xסð ëÁxÇ¡` xêh×Åxë¥ ÿÿÿ" h×Ål_¹" ×Åhß¹" ~ lסð ëÁlÇ¡` lêh×Ål" ~ lסð ëÁlÇ¡` lêh_ÀHÇ¡@ ~ lסð ëÁlÇ¡` lêh×Ål" ~ lסð ëÁlÇ¡` lêh×Ål" _À|ê _À|ê ~ xסð ëÁxÇ¡` v$tסð ëÁtÇ¡` têh×Åtë¥ ÿÿÿ×Åx" _À|ê x×Áx ¿ò×=߸" "_¸ß¸" ;×µ# ߸çµ$ "%ǽê ~ lסð ëÁlÇ¡` lê¿è f$xסð ëÁxÇ¡` xê¿è߸×Åxë¥ ÿÿÿ×Ål"&|¥ô߸ױ' "(|¥ô ~(hסð ëÁhÇ¡` hê¿èÎÏÀh WÁl[ ~ lסð ëÁlÇ¡` lê¿è×° ^$xסð ëÁxÇ¡` xê¿è V(hסð ëÁhÇ¡` hê¿è߸×Åxë¥ ÿÿÿ×Ål"&|¥ô×Åh× ")Ç½× ßÀp×± ~ lסð ëÁlÇ¡` lê¿è'¶* ×Ád'~ dÇÃl _Àpê¿ä_Àx )W°' z '® '®?x×Åx_¹" n lW¡ð kÁlG¡` lê¿è×°' §]|' ³_À|ê _¹çµ$ "%ǽê n_ÀxW± n lW¡ð kÁlG¡` lê¿è Ål+< &W¡ð kÁlG¡P lê¿Ù_À|ê¿Ó 1×Åx_¹" _À|W± n$lW¡ð kÁlG¡` lê¿èG¡p lê¿è WÀl ×Ål",Ç ×Ål"-Ç lê¿è×Ål".Ç 5×Ål"/Ç )"0× _À|ê D_À| lê¿è ÎÏÀl ÎØå³" M_À| lê¿è Àl×E _¸_¹" U_À| lê¿è Àl×U ߸_¹" primitive unifyatomic claimclause $$0L doerase primhandle p8LLLL ,( 8 $<0@@ index succeed _Àx' xê)" 'FP| ÎãÁxÃÁ| |êh" " xÎØáÐ |êh" êu'¨ '¨ '¨ ߺ"$Ç _»"$Ç read readinteger readatom readquoted readcomment readsymbol readsolidus readfullstop tokenread scan done ×ÀtÎ -WÁ|'n ×Àt'^ ×ÁtÎ -×Á|'~ WÀt'N tÎXI z ×Áx'~ WÀ|'N |ÎØM êfê6×Áx'~ Á|'v t×Åt" ×ÀtÎXà³ ,'ÆTx'Þ |\Àw_Àp4¦ ÜÀwN#Æ ×Àp'^ 'ÃT×Á §Æ-Tê ×Áp'~ pÎØåÇT" ç­<" ÿÿÿ" ç­<" ÿÿÿ" ÿÿÿ" ç­"" _»×Šǽç­"" H߿׊ǽê< ç­'" ߺ׊ǽç­'" ß¿×Å write tokenalpha tokenother writebox writeint tokenput ÿÿÿ«9 C_EXIT C_FLOOR C_HANDLER h\àÐ x×Áx >|×Áx tê¿» pê¿®WÑ ê¿ ×Ål×Åp×Åt" C_INIT "806 À|êeß ×ÅtçÅx" 'Ælp'Þ t\Àm_Àx Ú5ç© 6lê g .lçÅl" ÀxêF _¸×Šǽ߸׊ǽ߸×Å ×À|×] ×Å|" _¹×Å ×Å|" ×Á|׳ 'ÆLl'Þ ùp'ÆLd h×Áh :çÀ[ÇÀd ,Ä£A 'V `ê Æ`\WÀd'N dTÂ\ hêB×Àd'^ »çÅL" ±çÅL" ¨çÅL" Á|ÎØa ß0Û1 çÅx" çÅx" çÅx" Á|×u çÅt" Á|×e vdu: C_IO ÿ§© .ó9 >|NÇ¡ >l×=çÅt" ×Át×Ã| C_MORECORE C_SETJMP C_STARTUP ÎÏ9|'~ WÁxWs 'þ5| ×Åt" |꿤 Æ|xz WÁxGÃ| Ê WÁxG+ GÁ|j xêU×À| WÀ|CR ê WÀxWÂ| tWÀ|'N Àt'F ×Áx'~ Àt'F êc×Å C_ALLOC ßÇ|'~ _Àx> 9J!> gaP> )¾°Áp¾ &p'v 9J$> 'YP> ¾0Áp¾ Çx'n êQWÁ À|×Åx¾ Àh¾°Àp¾0 C_ATOF ßÇ|ê ÎcÁxÎ C!'nPx'v À|Î#Àx C_ATOI zj ' Zj ' C_CASE C_FABS ¾0¦@$ xêiê ¾ ¦@$ xêi¾ C_TENPOWER C_STRCMP |×Á| C_STRLEN C_DATA z N#Æ Á|γÁ ¸'Æ¿HP'Þ LT'Æ¿Hx WÁx'n xTÃp ã'Á¿H _¸×Åxã%×%" |¥ð_Àh Àh'v |'® d '®0d'f |_Àl×À| |WÀ|Î pê1×À|Î Æl`_Àl_ÀX À|×À|Î |WÁ|Î À|×À|Î Æl\'Æ¿Hx ×Åp×ÅX×Å\çÅ¿H¾Ä] Áx'v '® dê xêt'® dê x xç­ ß¸×Å\×Åx×M x xç­ ß¸×Å\×Åx×E x xç­ _¸×Å\×Åx×E x xç­ _¸×Å\×Åx×E x xç­ _¸×Å\×Åx×E x xç­ _¸×Å\×Åx×E x xç­ _¸×Å\×Åx×E x xç­ _¸×Å\×Åx×E x xç­ ß¸×Å\×Åx×} x xç­ _¸×Å\×Åx×E x xç­ _¸×Å\×Åx×E x xç­ _¸×Å\×Åx×E x xç­ _¸×Å\×Åx×E x xç­ _¸×Å\×Åx×E Àx'F ênWÁxcÁt .l×À| Át'æ4x#Æ`l N#Æll×Åd×Å ×Ål×ÅxãÅt×Åt" |¥ì'Æ¿Hx À|êºø'Á¿H _¸×Åxã%×%" C_DOPRNT (4d L(4D | 4_Àx_Àh×Á |_ÀtßÀd 0|j' Î#Át Á|'fPt×À |_Ádê/ _ÀdWÀ ×Å|" |_Ád çÅh×Å ×Åd×Åt×Å|×Ål" Æx\ê ¾G×Å ×Åp" ǽê¾: ×Åp" ê½êê¿° 'Æ¿dt'Þ _ÀP×Å ×Å ×ÅP" _ÀT_ÀX_Àd ßÀd'® l'Æ¿d|_Àh_À` Á|'v Æ¿¼¿¸ Æ¿¸p 9j ' pPpê! p¿©pê Æ\pê À|'F Æ¿´¿° Æ¿°p À|'V Æ¿¬¿¨ Æ¿¨pê¾H N#ÆTT ×Åp" ǽ Á _` Á ß` çÀ¿dÇÀ| À|'F ×ÁdNס >¿¤Ç¡ çÅ¿d" ßÀt×Á Æ|p×ÀpÎØáÓ @ßÀt _Àtê À|ÎØàÐ Ú/×Á Æ`|ê¿© ×Å|" ǽ×Á _Àx×Á Àx'~ ×Á|Î ×À|ÎØáÓ À|êM×À ×Á|'~ |ÎØà× ×Á|'~ C_DOSCAN 4 $D$ &4h  ¾0¦@$ xêiê ¾ ¦@$ xêi¾ xßÀt¾ÄÅ ¾ ¦@$ Çtêj> ¾ ¦@$ Àtêj> x_Àlê ǽ>; l×Ål" ¾°Áx¾  xNãÅ ¾0 ?à Åx?ð ¾ ¦@$ Àl'Ö d_ÀhWÁ (Ú1> ¾°0¾ Ád'f d'@0 êH×À Àd'V çÅ|×Å C_ECVT _¹×Å ×5×Å _Ápê ßÀp×Åp×Å ×Å|×Å x_¹_¸× |¥ôê4 _Áhê _Àh×Åh×Å ß([y _)[y C_ENDOPEN ×Áx'~ xÔÃ| WÁx'n C_FGETS êjç­ êM§© ßÀ|ê |×Å|×} _7«y C_FILBUF Á|ÎÏq C_FINDIOP g©¿¿k1×+ sßÀt×ÅtçÅs×} ê¿®×Á ê¿}g© [y Æxtê&Wy ×-×Å|×} WÁ|'n ×Å|×e ×Å|" ßÇ|×À ßÇ|×À «¢ÿÿÿ C_FLSBUF _Ãh×Å ×Åh¾ÄÅ |×Á| çÅtçÅp×Å Á|'f ÀxÊh N#Æpp Çpêe À|'F ÀxÊh×Á çÅtçÅp×Å Á|'f ÀxÊh×À N#Æxxê §q0Ô3 gi0WÀHT* C_FLTPR d ($$( d($( C_FOPEN çÅ|çÅx×Å ×Áp'~ pÔ£- ÁlWÁt Çlêh Áx£Á ÇxWÁp'n Át'f ×Àp'^ pÔ¢. Àp'V pWÀt'N Àlêe Àp'F N#Æxx×Áp'~ pÔ£- Áp'v WÁp'n ÁxÎ3¡ 'a0T# ×Àp'^ Àxη  §P0Ô ÀxÊ+WÀt Àp'F ÀxWÀp'N pT¢0 êmßÀl j*×Áp'~ Át'v WÁp'n pT£. ÀlêT ×Àp'^ pÔ¢0 Àp'V pWÀp\H C_GCVT D( X( 0(Xd |¥ô´¥ ßÇ|ê C_PRINTF Ætl_Àp×Á ÀpêqçÅ çÅl" C_SCANF ×5ÎØ} ×5×Å ×5ÎØM ×5×Å C_STROUT C_UNGETC §À¿° ]À¿¬çÁ¿°Î çÅa" gÀaÎ j ×u ô×Ñ0Ç{ µÎØÕ ´×Õ(çÕ ð0> ¾µWÐ ¾ª×Õ çÅ]" gÀ]Î À|'¨ ÎØÅ¿ ¾ü|£ '¾xê ïÄx|£ @_¸×Å ç­?çÅA" gÀAÎ ö×4, \À¾ø_8 >|ê1 À¾øÎØÀ¾ø ÇÃx¾øÇÁ¾ô gÀ¾ùÎ 6|ê% \À¾ø_0 6|ê1 À¾øÎXÀ¾ø ÇÁx¾ø gÀ¾ùÎ 6|ê% _ÎXp RÎXp _ÎXp k!G¡ À|z) _ºç­ §p(WÀ À|j*×Å|" v$t_ºç­ ×Åt" _À¾´'¨ §À¾¸gÀ¾´ çž´ç­ @çÅ¿ ¾W_ºç­ L_¸" ¾°'¨ À¾°gÀ¾´ WÀ¾°WòÒ4 _ºç­ L_¸" À|_W _À¾´'¨ §À¾¸gÀ¾´ »xçž´ç­ ¦ ¾¼_ºç­ L_¸" ¾°'¨ À¾°gÀ¾´ WÀ¾°WòÒ _À¾´'¨ §À¾¸gÀ¾´ ºêçž´ç­ ¼Æ]À¾¼_ºç­ L_¸" ¾°'¨ À¾°gÀ¾´ WÀ¾°WòÒ _ºç­ L_¸" À|_W z,ß¸ç­ ¿ª_¹ç­ ¿¢ßºß» ßºç­ _¹_¹ ¶§×Ð,ÇZ çÅ|" ð0> ¶tê8 Ú.×Ð0ÇZ ÎXà~ ×Á|ÇÁx ~×Ñ0Ô£ Tê¿ò :×Ñ0Ô£ ÎØÅ¿ ×Ñ,Î ºÂ×Ñ,WÑ H4_ºç­ L×=" ×Õ " ×Ñ0ÎXy!EÑ ºx×Ñ0 t_ºç­ L×=" ×Õ$" ÿçž À|j)×Å ×Å|" ×Å|" @§À@g ÎØÅ@çÅA×Õ " ×Å|" ´gÀ@Î (_¸" &|ÎØÝ ô×%" ç×Å|" &|×%" #×Å|" '¾|ê GïÄ|'Á¾ýgØ ÎØÅ¾ü×%" Ñ,ÎØ`!ÅÐ '¾|ê GïÄ|'Á¾ýgØ e'¨ ÎØÅ¾ü×%" ÿÿÿÿ ÿÿÿÿ End of file reached NULL: cannot open code= Illegal IMP stream number *** Failed to wind down input: : *** Failed to wind down output: IOLIB >¾üê4 >¾üÎ '®?¾øWÀ¾ø ×Á¾üÇÁ¾ô \À¾À_À¾¼'Æ@¾´Î Æ@¾° À¾°Ú À¾´×Á¾´Î À¾ÀÎ ÇÆ¾¸¾À꿹ßÀ¾¼ À¾ÀÎ §Ä?¾Àê¿ gÀ¾ÁΠ߸×Å Ç|×À ÃÀx'^ ê¿¶_¸ ÿçžù ¾øçžø" ×Õ|/Ô|Î _D×Ñ '®.D À`ÎXÁ` ÇÅD`_¸×Á ÿçŽ ƽ|| \_À¿´×Á ÃÁH'~ ÆT@C Æ@¿° ¦ÿÿÿ [ÎOÀP ¦ÿÿÀ Pê-Î ¾¿WÁ½ ¿¸'n P_À¿¼4¦ 3_À\×ÁP À@çØ D}ïP Qê¾VçÝ êq×ÁP êV_¸×ÅP" ¦ÿÿÿ ×ÅP" ZWÁPÎ P_¸×ÅP" ¦ÿÿÿ _º×ÅP" ÅPÿÿ P_¸×ÅP" »ê¿;WÀP ¿N'¨ ߻߸WÀP>ÛM ÿçŽ ÎXÀ¿ §Áe¿ ¾Ä§© ê¾vç­ ÁP¾Äu ÿçŽ ¾Tg¨" ~×ÁPÎØ} ×Å çÁ½ ÎØÅ½ ×=×Å ×ÅPç ×Å ÃÅ¿¸ »àê¼ ×ÁPÎ ½ÐçÕ d×ÅP »$ê½ ½±×ÅP WÁPÎ ÅPÿÿ ×Å¿¸ÃÅ ×ÅP ºÝê½X×ÀP À¿¼Ú(§ ng¨( _»×ÅP" Æ¿°@꼪§ 6HÎYq hê¼îßÇ¿¨_À¿¬g¨ À¿¨4¦ ØßÀ¿¬ Á¿°Ê _¸×Å¿¨" d×Å¿¨ ¹Üê? ×Å¿¨ ×Å¿¸ÃÅ ×Å¿¨ ¿m×ÁHÇÁ½ ¿Xg¨ Mê»ö V¿¼| ÎXP¾ §Q^¾ Ç|ê¿æ Fç­ ç­ Ð|ãUH" Ð|çU`" Ð|çU¾ Ð|ßP¿´ ¿g¨' _¸×Å .xÎØáÝ ÄÇÁ| K}ïP UWÁxG¡ ߸׵ 2߸׵ $߸׵ ê¿ççÝ ê¿ÞçÝ ê¿±çÝ _¸×Åt" ê¿7çÝ ê¿%çÝ ß¸×Åt" ê¾èçÝ _¸×Åt" ê¿êçÝ ß¸×Åt" _¸×Åt" Ò߸×Åt" ê¿¿çÝ ê¾]çÝ ß¸×Åt" _¸×Åt" ê9çÝ ê1çÝ ê)çÝ ê!çÝ ^_¸" <ÎÄÖ ½'g¨ «ß¸" " ¼öç­ tÎYX Ê¿òÎ CÁPCÁt Æd\×Àd Á\ÎØq Ã8'^ _Àlê? ÀdWÁ`×ÀhãÀx NG þ Ç(Ê¿Ø \À¿¼ ߸×Ål" Á\ÎØu ÿçž½ ¾¼çž¼" ߸×Åp" çÅ¿¼" ÿçž½ ¾¼çž¼" ÁTÎYa ×ÅtÃ} _¸_¸_º×Å|_¸C1×- ´Bg¨ Ú<çÝ _¸×Õ _¸×Ñ ÿçž½ ¾¼çž¼" not assigned invalid ordinal value Chr( unassigned pointer ??? not assigned = 16_ = 16_ (not assigned?) = unprintable real value unprintable real value (disposed) U5E% &6FVf HXuaqhex Event Overflow Integer overflow Real overflow String overflow Division by zero Excess resource Not enough store Output exceeded Time exceeded Data error Symbol value in data Corrupt data Data transmission error Invalid arguments For loop cannot terminate Illegal exponent Array inside-out String inside-out Illegal parameter Out of range Array index ( ) not in bounds Switch index ( Illegal event Charno does not exist is not a character value Resolution fails Undefined value Unassigned variable Switch label ( Corrupt control variable I/O error Input ended Illegal stream NIL pointer used Reference to DISPOSED object'Zero or negative argument for logarithm Significance lost x MOD is not permitted Missing case!Negative argument for square root Disposing NIL pointer Interrupt $Inappropriate parameters for DISPOSE Variant record misused ERROR: Diagnostics being send to Executing IMP Pascal 'C' called from line in starting at line module Stopped at line in PANDIAG çÅm" lçÁ¾ígØ gÀmÎ ÎØÅ¾ì×=" ×=×5 çÅm" gÀmÎ çÅm" lçÁ¾ígØ gÀmÎ ÎØÅ¾ì×=" $ÎYx ×x|4  ÎÝx~Î\x êK4  ×x|4  ÎÝx~Î\x ----> Initialise ----> Stop ----> Exception Exception ----> Exception passed on ----> Diagnose ----> Diagnose passed on ----> Describe frame ----> Describe module data ----> Unwind ----> Unknown handler type LLHAND *******continue*********l SIGNAL ÎÏ9]'~ x_Àt'Ö ÀpÚ7 Æptz ÆptWÁhWÃp Ælh꿼#Æph꿵WÁx xê¿  Ád_` ×%çÅx" ÎÏÁ| À|£À Àp×Q >t×ÁtNãà Àp×Q pê¿eß ¾·×Å Nã{|| Heap failure -- Cannot extend heap Heap Corrupt 3 Heap Corrupt 4 Extend heap logic errorV HEAP xßÀt¾4Æ ¾ ¦@$ Çtêj> ¾ ¦@$ Àtêj \À¾à _À > x_Àlê x¾ÄÅx ¿x'F l×Ål Áx¾°¡@$ ¾ ÆpxNãÅ ¾0 ?à Åx@$ ¾ ¦@$ \À¾à> ¾à>;Æxd À¾à§ d0ÎXÁ¾à 7žàÎ z0çÀ½ágÀ¾á§X §À¾àgÀ½àÎ À¾àÎ §Â.¾à !¾°¡@$ 6x>;6d À¾àg À¾àêH À¾àÎXÁ¾à §Å@¾à À¾àÎØÀ¾à §Ã-¾àê À¾àÎ §Â+¾à_¸NóÅlç­?çŽá" ½à§À`gÀ½àÎ À¾àÎ §Â0¾à À¾àÎXÀ¾à §Á0¾à'Á¾áÎ gÀaÎ X\À¿ _À > ¾øNãÅ ½@¾0 ?à Á¾øz À¾ôÚ >;ƾø¾è_¸×žèç­?çž©" ¾¨'Á¿ gÀ¾©Î z0'Á½©gÀ¿ gÀ½¨Î §Â.¿ À¾è¾ Á¾ø¾ ¾°¡@$ 6¾ø>;6¾è ¾è0Î ÿçÅ¿ ÿçÅ¿ REALIO 'Æpx'Þ ò|ßÀt_Àp _ÀtN#Æ Çp×Á §©0£9WÁp ÇpWÁp §Å-pê ÇpWÁp §Å p §Å-pß'#Á ÇpWÁp §Å pêoN#Æp ÇpWÁp gàÅqÎ ç­?çÅA" @çÅ@" ÿÿÿÿÿÿÿ [BBC.TK413.LIB]ITOS 'Ælx'Þ Ý|_Àl_8 z ' p7pê Çl×Ál ÇÇpl×ÁtÇ¡ Çl×Ál §Ç l rN#Æ Çl×Ál gàÇmÎ ÿçÅ¿ ÿÿÿÿÿÿÿ [BBC.TK413.LIB]ITOX m*¬* þÿÿÿÿÿÿÿ ÿÿÿÿ üÿÿÿ ýÿÿÿ 0123456789ABCDEF ÿÿÿÿÿÿÿÿ Data: ÿÿÿÿ ÿÿÿÿ ERROR: False True Executing ÿÿÿÿÿÿÿÿ E xarorr :° wohsluc_tirp° åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå