rlisp.red 65 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224
  1. %*********************************************************************
  2. %*********************************************************************
  3. % THE REDUCE TRANSLATOR
  4. %*********************************************************************
  5. %********************************************************************;
  6. %Copyright (c) 1983 The Rand Corporation;
  7. SYMBOLIC; %Most of REDUCE is defined in symbolic mode;
  8. %*********************************************************************
  9. % NON-LOCAL VARIABLES USED IN TRANSLATOR
  10. %********************************************************************;
  11. %The following are used as non-local variables in this section;
  12. FLUID '(DFPRINT!* LREADFN!* SEMIC!* TSLIN!* !*BACKTRACE !*DEFN !*ECHO
  13. !*MODE !*OUTPUT !*RAISE !*SLIN !*TIME);
  14. GLOBAL '(BLOCKP!* CMSG!* CRBUFLIS!* CRBUF!* CRBUF1!* EOF!* ERFG!*
  15. FNAME!* FTYPES!* INITL!* INPUTBUFLIS!* LETL!* MOD!* OTIME!*
  16. OUTL!* PRECLIS!* PROMPTEXP RESULTBUFLIS!* TTYPE!* TYPL!*
  17. STATCOUNTER !*NAT NAT!*!* CRCHAR!* CURSYM!* IFL!* IPL!* KEY!*
  18. !*FORCE NXTSYM!* OFL!* OPL!* PROGRAM!* PROGRAML!* WS !*FORT
  19. TECHO!* !*BLANKNOTOK!* !*COMPOSITES !*CREF !*DEMO !*EXTRAECHO
  20. !*INT !*LOSE !*MSG !*PRET !*!*ESC);
  21. % These non-local variables divide into two classes. The first
  22. %class are those which must be initialized at the top level of the
  23. %program. These are as follows;
  24. %BLOCKP!* := NIL; %keeps track of which block is active;
  25. %CRBUFLIS!* := NIL; %terminal input buffer;
  26. %CMSG!* := NIL; %shows that continuation msg has been printed;
  27. %DFPRINT!* := NIL; %used to define special output process;
  28. %EOF!* := NIL; %flag indicating an end-of-file;
  29. %ERFG!* := NIL; %indicates that an input error has occurred;
  30. INITL!* := '(BLOCKP!* OUTL!*);
  31. %list of variables initialized in BEGIN1;
  32. %INPUTBUFLIS!* := NIL; %association list for storing input commands;
  33. KEY!* := 'SYMBOLIC; %stores first word read in command;
  34. %LETL!* := NIL; %used in algebraic mode for special delimiters;
  35. %LREADFN!* := NIL; %used to define special reading function;
  36. %MOD!* := NIL; %modular base, NIL for integer arithmetic;
  37. %OUTL!* := NIL; %storage for output of input line;
  38. PRECLIS!*:= '(OR AND NOT MEMBER MEMQ EQUAL NEQ EQ GEQ GREATERP LEQ
  39. LESSP PLUS DIFFERENCE TIMES QUOTIENT EXPT CONS);
  40. %precedence list of infix operators;
  41. %RESULTBUFLIS!* := NIL; %association list for storing command outputs;
  42. STATCOUNTER := 0; %terminal statement counter;
  43. %TECHO!* := NIL; %terminal echo status;
  44. %TSLIN!* := NIL; %stack of input reading functions;
  45. %!*BACKTRACE := NIL; %if ON, prints a LISP backtrace;
  46. %!*BLANKNOTOK!* := NIL; %if ON, disables blank as CEDIT character;
  47. %!*COMPOSITES := NIL; %used to indicate the use of composite numbers;
  48. %!*CREF := NIL; %used by cross-reference program;
  49. %!*DEFN := NIL; %indicates that LISP code should be output;
  50. %!*ECHO := NIL; %indicates echoing of input;
  51. %!*FORCE := NIL; %causes all macros to expand;
  52. !*LOSE := T; %determines whether a function flagged LOSE
  53. %is defined;
  54. %!*MSG:=NIL; %flag to indicate whether messages should be
  55. %printed;
  56. %!*NAT := NIL; %used in algebraic mode to denote 'natural'
  57. %output. Must be on in symbolic mode to
  58. %ensure input echoing;
  59. %NAT!*!* := NIL; %temporary variable used in algebraic mode;
  60. !*OUTPUT := T; %used to suppress output;
  61. !*RAISE := T; %causes lower to be converted to upper case;
  62. %!*SLIN := NIL; %indicates that LISP code should be read;
  63. %!*TIME := NIL; %used to indicate timing should be printed;
  64. % The second class are those non-local variables which are
  65. %initialized within some function, although they do not appear in that
  66. %function's variable list. These are;
  67. % CRCHAR!* next character in input line
  68. % CURSYM!* current symbol (i. e. identifier, parenthesis,
  69. % delimiter, e.t.c,) in input line
  70. % FNAME!* name of a procedure being read
  71. % FTYPES!* list of regular procedure types
  72. % IFL!* input file/channel pair - set in BEGIN to NIL
  73. % IPL!* input file list- set in BEGIN to NIL
  74. % NXTSYM!* next symbol read in TOKEN
  75. % OFL!* output file/channel pair - set in BEGIN to NIL
  76. % OPL!* output file list- set in BEGIN to NIL
  77. % PROGRAM!* current input program
  78. % PROGRAML!* stores input program when error occurs for a
  79. % later restart
  80. % PROMPTEXP expression used for command prompt
  81. % SEMIC!* current delimiter character (used to decide
  82. % whether to print result of calculation)
  83. % TTYPE!* current token type
  84. % WS used in algebraic mode to store top level value
  85. % !*FORT used in algebraic mode to denote FORTRAN output
  86. % !*INT indicates interactive system use
  87. % !*MODE current mode of calculation
  88. % !*PRET indicates REDUCE prettyprinting of input;
  89. COMMENT THE FOLLOWING IS USED AS A FLUID VARIABLE;
  90. FLUID '(!*S!*);
  91. %*********************************************************************
  92. % GO TO STATEMENT
  93. %********************************************************************;
  94. % It is necessary to introduce the GO TO statement at this
  95. %point as part of the boot-strapping process. A general description
  96. %of the method of statement implementation is given later;
  97. SYMBOLIC PROCEDURE GOSTAT;
  98. BEGIN SCALAR VAR;
  99. VAR := IF EQ(SCAN(),'TO) THEN SCAN() ELSE CURSYM!*;
  100. SCAN();
  101. RETURN LIST('GO,VAR)
  102. END;
  103. PUT('GO,'STAT,'GOSTAT);
  104. PUT('GOTO,'NEWNAM,'GO);
  105. %*********************************************************************
  106. % INITIALIZATION OF INFIX OPERATORS
  107. %********************************************************************;
  108. % Several operators in REDUCE are used in an infix form (e.g.,
  109. %+,- ). The internal alphanumeric names associated with these
  110. %operators are introduced by the function NEWTOK defined below.
  111. %This association, and the precedence of each infix operator, is
  112. %initialized in this section. We also associate printing characters
  113. %with each internal alphanumeric name as well;
  114. DEFLIST ('(
  115. (NOT NOT)
  116. (PLUS PLUS)
  117. (DIFFERENCE MINUS)
  118. (MINUS MINUS)
  119. (TIMES TIMES)
  120. (QUOTIENT RECIP)
  121. (RECIP RECIP)
  122. ), 'UNARY);
  123. FLAG ('(AND OR !*COMMA!* PLUS TIMES),'NARY);
  124. FLAG ('(CONS SETQ PLUS TIMES),'RIGHT);
  125. DEFLIST ('((MINUS PLUS) (RECIP TIMES)),'ALT);
  126. SYMBOLIC PROCEDURE MKPREC;
  127. BEGIN SCALAR X,Y,Z;
  128. X := '!*COMMA!* . ('SETQ . PRECLIS!*);
  129. Y := 1;
  130. A: IF NULL X THEN RETURN NIL;
  131. PUT(CAR X,'INFIX,Y);
  132. PUT(CAR X,'OP,LIST LIST(Y,Y)); %for RPRINT;
  133. IF Z := GET(CAR X,'UNARY) THEN PUT(Z,'INFIX,Y);
  134. IF AND(Z,NULL FLAGP(Z,'NARY)) THEN PUT(Z,'OP,LIST(NIL,Y));
  135. X := CDR X;
  136. Y := ADD1 Y;
  137. GO TO A
  138. END;
  139. MKPREC();
  140. SYMBOLIC PROCEDURE ATSOC(U,V);
  141. IF NULL V THEN NIL
  142. ELSE IF U EQ CAAR V THEN CAR V
  143. ELSE ATSOC(U,CDR V);
  144. SYMBOLIC PROCEDURE CONSESCC U;
  145. IF NULL U THEN NIL ELSE '!! . CAR U . CONSESCC CDR U;
  146. SYMBOLIC PROCEDURE LSTCHR(U,V);
  147. IF NULL CDR U THEN CAR U . (NIL . V)
  148. ELSE LIST(CAR U,LIST LSTCHR(CDR U,V));
  149. SYMBOLIC PROCEDURE NEWTOK U;
  150. BEGIN SCALAR V,X,Y,Z;
  151. V := CDR U;
  152. U := CAR U;
  153. Y := U;
  154. IF NULL(X:= GET(CAR Y,'SWITCH!*)) THEN GO TO D;
  155. Y := CDR Y;
  156. A: IF NULL Y THEN GO TO E
  157. ELSE IF NULL CAR X
  158. THEN PROGN(RPLACA(X,LIST LSTCHR(Y,V)),GO TO C)
  159. ELSE IF NULL(Z := ATSOC(CAR Y,CAR X)) THEN GO TO B1;
  160. B: Y := CDR Y;
  161. X := CDR Z;
  162. GO TO A;
  163. B1: RPLACA(X,APPEND(CAR X,LIST LSTCHR(Y,V)));
  164. C: X := INTERN COMPRESS CONSESCC U;
  165. IF CDR V THEN IF CDDR V THEN Y:= LIST(CADR V,CADDR V)
  166. ELSE Y:= LIST(CADR V,X)
  167. ELSE Y:= LIST(X,X); %the print list;
  168. PUT(CAR V,'PRTCH,Y);
  169. IF X := GET(CAR V,'UNARY) THEN PUT(X,'PRTCH,Y);
  170. RETURN NIL;
  171. D: PUT(CAR Y,'SWITCH!*,CDR LSTCHR(Y,V));
  172. GO TO C;
  173. E: IF !*MSG THEN LPRIM LIST(COMPRESS CONSESCC U,"redefined");
  174. %test on MSG is for bootstrapping purposes;
  175. RPLACD(X,V);
  176. GO TO C
  177. END;
  178. NEWTOK '((!$) !*SEMICOL!*);
  179. NEWTOK '((!;) !*SEMICOL!*);
  180. NEWTOK '((!+) PLUS ! !+! );
  181. NEWTOK '((!-) DIFFERENCE ! !-! );
  182. NEWTOK '((!*) TIMES);
  183. NEWTOK '((!* !*) EXPT);
  184. NEWTOK '((!/) QUOTIENT);
  185. NEWTOK '((!=) EQUAL);
  186. NEWTOK '((!,) !*COMMA!*);
  187. NEWTOK '((!() !*LPAR!*);
  188. NEWTOK '((!)) !*RPAR!*);
  189. NEWTOK '((!:) !*COLON!*);
  190. NEWTOK '((!: !=) SETQ ! !:!=! );
  191. NEWTOK '((!.) CONS);
  192. NEWTOK '((!<) LESSP);
  193. NEWTOK '((!< !=) LEQ);
  194. NEWTOK '((!< !<) !*LSQB!*);
  195. NEWTOK '((!>) GREATERP);
  196. NEWTOK '((!> !=) GEQ);
  197. NEWTOK '((!> !>) !*RSQB!*);
  198. FLAG('(NEWTOK),'EVAL);
  199. %*********************************************************************
  200. % REDUCE SUPERVISOR
  201. %********************************************************************;
  202. % The true REDUCE supervisory function is BEGIN, again defined in
  203. %the system dependent part of this program. However, most of the work
  204. %is done by BEGIN1, which is called by BEGIN for every file
  205. %encountered on input;
  206. SYMBOLIC PROCEDURE ERRORP U;
  207. %returns true if U is an ERRORSET error format;
  208. ATOM U OR CDR U;
  209. SYMBOLIC PROCEDURE FLAGP!*!*(U,V);
  210. IDP U AND FLAGP(U,V);
  211. SYMBOLIC PROCEDURE PRINTPROMPT U;
  212. %Prints the prompt expression for input;
  213. PROGN(IF OFL!* THEN WRS NIL, PRIN2 U, IF OFL!* THEN WRS CDR OFL!*);
  214. SYMBOLIC PROCEDURE BEGIN1;
  215. BEGIN SCALAR MODE,PARSERR,RESULT;
  216. A0: CURSYM!* := '!*SEMICOL!*;
  217. OTIME!* := TIME();
  218. A: IF NULL TERMINALP() THEN GO TO A2
  219. ELSE IF STATCOUNTER>0 THEN ADD2BUFLIS();
  220. STATCOUNTER := STATCOUNTER + 1;
  221. PROMPTEXP
  222. := COMPRESS('!! . APPEND(EXPLODE STATCOUNTER,EXPLODE '!:! ));
  223. SETPCHAR PROMPTEXP;
  224. A2: PARSERR := NIL;
  225. IF !*TIME THEN EVAL '(SHOWTIME); %Since a STAT;
  226. IF !*OUTPUT AND NULL OFL!* AND TERMINALP() AND NULL !*DEFN
  227. THEN TERPRI();
  228. IF TSLIN!*
  229. THEN PROGN(!*SLIN := CAR TSLIN!*,
  230. LREADFN!* := CDR TSLIN!*,
  231. TSLIN!* := NIL);
  232. MAPCAR(INITL!*,FUNCTION SINITL);
  233. IF !*INT THEN ERFG!* := NIL; %to make editing work properly;
  234. IF CURSYM!* EQ 'END THEN GO TO ND0;
  235. IF TERMINALP() AND NULL(KEY!* EQ 'ED)
  236. THEN PRINTPROMPT PROMPTEXP;
  237. PROGRAM!* := ERRORSET('(COMMAND),T,!*BACKTRACE);
  238. CONDTERPRI();
  239. IF ERRORP PROGRAM!* THEN GO TO ERR1;
  240. PROGRAM!* := CAR PROGRAM!*;
  241. IF PROGRAM!* EQ !$EOF!$ AND TTYPE!*=3 THEN GO TO ND1
  242. ELSE IF CURSYM!* EQ 'END THEN GO TO ND0
  243. ELSE IF EQCAR(PROGRAM!*,'RETRY) THEN PROGRAM!* := PROGRAML!*
  244. ELSE IF PROGRAM!* EQ 'ED AND GETD 'CEDIT
  245. THEN PROGN(CEDIT NIL,GO TO A2)
  246. ELSE IF EQCAR(PROGRAM!*,'ED) AND GETD 'CEDIT
  247. THEN PROGN(CEDIT CDR PROGRAM!*,GO TO A2);
  248. %The following section decides what the target mode should be.
  249. %That mode is also assumed to be the printing mode;
  250. IF IDP KEY!* AND GET(KEY!*,'STAT) EQ 'MODESTAT
  251. THEN MODE := KEY!*
  252. ELSE IF NULL ATOM PROGRAM!* AND NULL(CAR PROGRAM!* EQ 'QUOTE)
  253. AND (NULL(IDP CAR PROGRAM!*
  254. AND (FLAGP(CAR PROGRAM!*,'NOCHANGE)
  255. OR FLAGP(CAR PROGRAM!*,'INTFN)
  256. OR CAR PROGRAM!* EQ 'LIST))
  257. OR CAR PROGRAM!* MEMQ '(SETQ SETEL)
  258. AND EQCAR(CADDR PROGRAM!*,'QUOTE))
  259. THEN MODE := 'SYMBOLIC
  260. ELSE MODE := !*MODE;
  261. PROGRAM!* := CONVERTMODE1(PROGRAM!*,NIL,'SYMBOLIC,MODE);
  262. ADD2INPUTBUF PROGRAM!*;
  263. IF !*DEFN THEN GO TO D;
  264. B: IF !*OUTPUT AND IFL!* AND !*ECHO THEN TERPRI();
  265. RESULT := ERRORSET(PROGRAM!*,T,!*BACKTRACE);
  266. IF ERRORP RESULT OR ERFG!*
  267. THEN PROG2(PROGRAML!* := PROGRAM!*,GO TO ERR2)
  268. ELSE IF !*DEFN THEN GO TO A;
  269. RESULT := CAR RESULT;
  270. IF NULL(MODE EQ 'SYMBOLIC) AND RESULT THEN ADD2RESULTBUF RESULT;
  271. C: IF NULL !*OUTPUT THEN GO TO A
  272. ELSE IF SEMIC!* EQ '!;
  273. THEN IF MODE EQ 'SYMBOLIC
  274. THEN IF NULL RESULT AND NULL(!*MODE EQ 'SYMBOLIC)
  275. THEN NIL
  276. ELSE BEGIN TERPRI(); PRINT RESULT END
  277. ELSE IF RESULT THEN VARPRI(RESULT,SETVARS PROGRAM!*,'ONLY);
  278. GO TO A;
  279. D: IF ERFG!* THEN GO TO A
  280. ELSE IF FLAGP!*!*(KEY!*,'IGNORE) OR EQCAR(PROGRAM!*,'QUOTE)
  281. THEN GO TO B;
  282. IF PROGRAM!* THEN DFPRINT PROGRAM!*;
  283. IF FLAGP!*!*(KEY!*,'EVAL) THEN GO TO B ELSE GO TO A;
  284. ND0:COMM1 'END;
  285. ND1: EOF!* := NIL;
  286. IF NULL IPL!* %terminal END;
  287. THEN BEGIN
  288. IF OFL!* THEN PROGN(WRS NIL,OFL!* := NIL);
  289. AA: IF NULL OPL!* THEN RETURN NIL;
  290. CLOSE CDAR OPL!*;
  291. OPL!* := CDR OPL!*;
  292. GO TO AA
  293. END;
  294. RETURN NIL;
  295. ERR1:
  296. IF EOF!* OR PROGRAM!* EQ !$EOF!$ AND TTYPE!*=3 THEN GO TO ND1
  297. ELSE IF PROGRAM!* EQ "BEGIN invalid" THEN GO TO A
  298. ELSE IF PROGRAM!* EQ !*!*ESC AND TTYPE!*=3 THEN GO TO A0;
  299. PARSERR := T;
  300. ERR2:
  301. RESETPARSER(); %in case parser needs to be modified;
  302. ERFG!* := T;
  303. IF NULL !*INT THEN GO TO E;
  304. RESULT := PAUSE1 PARSERR;
  305. IF RESULT THEN RETURN NULL EVAL RESULT;
  306. ERFG!* := NIL;
  307. GO TO A;
  308. E: !*DEFN := T; %continue syntax analyzing but not evaluation;
  309. !*ECHO := T;
  310. IF NULL CMSG!* THEN LPRIE "Continuing with parsing only ...";
  311. CMSG!* := T;
  312. GO TO A
  313. END;
  314. SYMBOLIC PROCEDURE ADD2BUFLIS;
  315. BEGIN
  316. CRBUF!* := REVERSIP CRBUF!*; %put in right order;
  317. A: IF CAR CRBUF!* EQ !$EOL!$
  318. OR (!*BLANKNOTOK!* AND CAR CRBUF!* EQ '! )
  319. THEN PROG2(CRBUF!* := CDR CRBUF!*, GO TO A);
  320. CRBUFLIS!* := (STATCOUNTER . CRBUF!*) . CRBUFLIS!*;
  321. CRBUF!* := NIL
  322. END;
  323. SYMBOLIC PROCEDURE ADD2INPUTBUF U;
  324. BEGIN
  325. IF TERMINALP()
  326. THEN INPUTBUFLIS!* := (STATCOUNTER . U) . INPUTBUFLIS!*
  327. END;
  328. SYMBOLIC PROCEDURE ADD2RESULTBUF U;
  329. BEGIN
  330. WS := U;
  331. IF TERMINALP()
  332. THEN RESULTBUFLIS!* := (STATCOUNTER . U) . RESULTBUFLIS!*
  333. END;
  334. SYMBOLIC PROCEDURE CONDTERPRI;
  335. !*OUTPUT AND !*ECHO AND !*EXTRAECHO AND (NULL !*INT OR IFL!*)
  336. AND NULL !*DEFN AND TERPRI();
  337. SYMBOLIC PROCEDURE RESETPARSER;
  338. %resets the parser after an error;
  339. IF NULL !*SLIN THEN COMM1 T;
  340. SYMBOLIC PROCEDURE SETVARS U;
  341. IF ATOM U THEN NIL
  342. ELSE IF CAR U MEMQ '(SETEL SETK)
  343. THEN CADR U . SETVARS CADDR U
  344. ELSE IF CAR U EQ 'SETQ THEN MKQUOTE CADR U . SETVARS CADDR U
  345. ELSE NIL;
  346. SYMBOLIC PROCEDURE TERMINALP;
  347. %true if input is coming from an interactive terminal;
  348. !*INT AND NULL IFL!*;
  349. SYMBOLIC PROCEDURE DFPRINT U;
  350. %Looks for special action on a form, otherwise prettyprints it;
  351. IF DFPRINT!* THEN APPLY(DFPRINT!*,LIST U)
  352. ELSE IF CMSG!* THEN NIL
  353. ELSE IF NULL EQCAR(U,'PROGN) THEN PRETTYPRINT U
  354. ELSE BEGIN
  355. A: U := CDR U;
  356. IF NULL U THEN RETURN NIL;
  357. DFPRINT CAR U;
  358. GO TO A
  359. END;
  360. SYMBOLIC PROCEDURE SHOWTIME;
  361. BEGIN SCALAR X;
  362. X := OTIME!*;
  363. OTIME!* := TIME();
  364. X := OTIME!*-X;
  365. % IF NULL TERMINALP() THEN TERPRI();
  366. TERPRI();
  367. PRIN2 "TIME: "; PRIN2 X; PRIN2T " MS";
  368. % IF TERMINALP() THEN TERPRI();
  369. END;
  370. SYMBOLIC PROCEDURE SINITL U;
  371. SET(U,GET(U,'INITL));
  372. FLAG ('(IN OUT ON OFF SHUT),'IGNORE);
  373. %*********************************************************************
  374. % IDENTIFIER AND RESERVED CHARACTER READING
  375. %********************************************************************;
  376. % The function TOKEN defined below is used for reading
  377. %identifiers and reserved characters (such as parentheses and infix
  378. %operators). It is called by the function SCAN, which translates
  379. %reserved characters into their internal name, and sets up the output
  380. %of the input line. The following definitions of TOKEN and SCAN are
  381. %quite general, but also inefficient. THE READING PROCESS CAN OFTEN
  382. %BE SPEEDED UP BY A FACTOR OF AS MUCH AS FIVE IF THESE FUNCTIONS
  383. %(ESPECIALLY TOKEN) ARE CODED IN ASSEMBLY LANGUAGE;
  384. SYMBOLIC PROCEDURE PRIN2X U;
  385. OUTL!*:=U . OUTL!*;
  386. SYMBOLIC PROCEDURE MKQUOTE U; LIST('QUOTE,U);
  387. SYMBOLIC PROCEDURE REVERSIP U;
  388. BEGIN SCALAR X,Y;
  389. A: IF NULL U THEN RETURN Y;
  390. X := CDR U; Y := RPLACD(U,Y); U := X;
  391. GO TO A
  392. END;
  393. SYMBOLIC PROCEDURE MKSTRNG U;
  394. %converts the uninterned id U into a string;
  395. %if strings are not constants, this should be replaced by
  396. %LIST('STRING,U);
  397. U;
  398. CRCHAR!* := '! ;
  399. SYMBOLIC PROCEDURE READCH1;
  400. BEGIN SCALAR X;
  401. IF NULL TERMINALP() THEN RETURN READCH()
  402. ELSE IF CRBUF1!*
  403. THEN BEGIN X := CAR CRBUF1!*; CRBUF1!* := CDR CRBUF1!* END
  404. ELSE X := READCH();
  405. CRBUF!* := X . CRBUF!*;
  406. RETURN X
  407. END;
  408. SYMBOLIC PROCEDURE TOKEN1;
  409. BEGIN SCALAR X,Y,Z;
  410. X := CRCHAR!*;
  411. A: IF SEPRP X THEN GO TO SEPR
  412. ELSE IF DIGIT X THEN GO TO NUMBER
  413. ELSE IF LITER X THEN GO TO LETTER
  414. ELSE IF X EQ '!% THEN GO TO COMENT
  415. ELSE IF X EQ '!! THEN GO TO ESCAPE
  416. ELSE IF X EQ '!' THEN GO TO QUOTE
  417. ELSE IF X EQ '!" THEN GO TO STRING;
  418. TTYPE!* := 3;
  419. IF X EQ !$EOF!$ THEN GO TO EOF;
  420. NXTSYM!* := X;
  421. IF DELCP X THEN GO TO D;
  422. A1: CRCHAR!* := READCH1();
  423. GO TO C;
  424. ESCAPE:
  425. Z := !*RAISE;
  426. !*RAISE := NIL;
  427. Y := X . Y;
  428. X := READCH1();
  429. !*RAISE := Z;
  430. LETTER:
  431. TTYPE!* := 0;
  432. LET1:
  433. Y := X . Y;
  434. IF DIGIT (X := READCH1()) OR LITER X THEN GO TO LET1
  435. ELSE IF X EQ '!! THEN GO TO ESCAPE;
  436. NXTSYM!* := INTERN COMPRESS REVERSIP Y;
  437. B: CRCHAR!* := X;
  438. C: RETURN NXTSYM!*;
  439. NUMBER:
  440. TTYPE!* := 2;
  441. NUM1:
  442. Y := X . Y;
  443. Z := X;
  444. IF DIGIT (X := READCH1())
  445. OR X EQ '!.
  446. OR X EQ 'E
  447. OR Z EQ 'E
  448. THEN GO TO NUM1;
  449. NXTSYM!* := COMPRESS REVERSIP Y;
  450. GO TO B;
  451. QUOTE:
  452. CRCHAR!* := READCH1();
  453. NXTSYM!* := MKQUOTE RREAD();
  454. TTYPE!* := 4;
  455. GO TO C;
  456. STRING:
  457. Z := !*RAISE;
  458. !*RAISE := NIL;
  459. STRINX:
  460. Y := X . Y;
  461. IF NULL((X := READCH1()) EQ '!") THEN GO TO STRINX;
  462. Y := X . Y;
  463. NXTSYM!* := MKSTRNG COMPRESS REVERSIP Y;
  464. !*RAISE := Z;
  465. TTYPE!* := 1;
  466. GO TO A1;
  467. COMENT:
  468. IF NULL(READCH1() EQ !$EOL!$) THEN GO TO COMENT;
  469. SEPR:
  470. X := READCH1();
  471. GO TO A;
  472. D: CRCHAR!* := '! ;
  473. GO TO C;
  474. EOF:CRCHAR!* := '! ;
  475. FILENDERR()
  476. END;
  477. SYMBOLIC PROCEDURE TOKEN;
  478. %This provides a hook for a faster TOKEN;
  479. TOKEN1();
  480. SYMBOLIC PROCEDURE FILENDERR;
  481. BEGIN
  482. EOF!* := T;
  483. ERROR(99,IF IFL!* THEN LIST("EOF read in file",CAR IFL!*)
  484. ELSE LIST "EOF read")
  485. END;
  486. SYMBOLIC PROCEDURE PTOKEN;
  487. BEGIN SCALAR X;
  488. X := TOKEN();
  489. IF X EQ '!) AND EQCAR(OUTL!*,'! ) THEN OUTL!*:= CDR OUTL!*;
  490. %an explicit reference to OUTL!* used here;
  491. PRIN2X X;
  492. IF NULL ((X EQ '!() OR (X EQ '!))) THEN PRIN2X '! ;
  493. RETURN X
  494. END;
  495. SYMBOLIC PROCEDURE RREAD1;
  496. BEGIN SCALAR X,Y;
  497. X := PTOKEN();
  498. IF NULL (TTYPE!*=3) THEN RETURN X
  499. ELSE IF X EQ '!( THEN RETURN RRDLS()
  500. ELSE IF NULL (X EQ '!+ OR X EQ '!-) THEN RETURN X;
  501. Y := PTOKEN();
  502. IF NULL NUMBERP Y
  503. THEN PROGN(NXTSYM!* := " ",
  504. SYMERR("Syntax error: improper number",NIL))
  505. ELSE IF X EQ '!- THEN Y := APPLY('MINUS,LIST Y);
  506. %we need this construct for bootstrapping purposes;
  507. RETURN Y
  508. END;
  509. SYMBOLIC PROCEDURE RRDLS;
  510. BEGIN SCALAR X,Y;
  511. X := RREAD1();
  512. IF NULL (TTYPE!*=3) THEN GO TO A
  513. ELSE IF X EQ '!) THEN RETURN NIL
  514. ELSE IF NULL (X EQ '!.) THEN GO TO A;
  515. X := RREAD1();
  516. Y := PTOKEN();
  517. IF NULL (TTYPE!*=3) OR NULL (Y EQ '!))
  518. THEN PROGN(NXTSYM!* := " ",SYMERR("Invalid S-expression",NIL))
  519. ELSE RETURN X;
  520. A: RETURN (X . RRDLS())
  521. END;
  522. SYMBOLIC PROCEDURE RREAD;
  523. PROGN(PRIN2X " '",RREAD1());
  524. SYMBOLIC PROCEDURE SCAN;
  525. BEGIN SCALAR X,Y;
  526. IF NULL (CURSYM!* EQ '!*SEMICOL!*) THEN GO TO B;
  527. A: NXTSYM!* := TOKEN();
  528. B: IF NULL ATOM NXTSYM!* THEN GO TO Q1
  529. ELSE IF NXTSYM!* EQ 'ELSE OR CURSYM!* EQ '!*SEMICOL!*
  530. THEN OUTL!* := NIL;
  531. PRIN2X NXTSYM!*;
  532. C: IF NULL IDP NXTSYM!* THEN GO TO L
  533. ELSE IF (X:=GET(NXTSYM!*,'NEWNAM)) AND
  534. (NULL (X=NXTSYM!*)) THEN GO TO NEW
  535. ELSE IF NXTSYM!* EQ 'COMMENT OR NXTSYM!* EQ '!% AND TTYPE!*=3
  536. THEN GO TO COMM
  537. ELSE IF NULL(TTYPE!* = 3) THEN GO TO L
  538. ELSE IF NXTSYM!* EQ !*!*ESC THEN ERROR(9999,!*!*ESC)
  539. ELSE IF NXTSYM!* EQ !$EOF!$ THEN RETURN FILENDERR()
  540. ELSE IF NXTSYM!* EQ '!' THEN GO TO QUOTE
  541. ELSE IF NULL (X:= GET(NXTSYM!*,'SWITCH!*)) THEN GO TO L
  542. ELSE IF CADR X EQ '!*SEMICOL!* THEN GO TO DELIM;
  543. SW1: NXTSYM!* := TOKEN();
  544. IF NULL(TTYPE!* = 3) THEN GO TO SW2
  545. ELSE IF NXTSYM!* EQ !$EOF!$ THEN RETURN FILENDERR()
  546. ELSE IF CAR X THEN GO TO SW3;
  547. SW2: CURSYM!*:=CADR X;
  548. IF CURSYM!* EQ '!*RPAR!* THEN GO TO L2
  549. ELSE RETURN CURSYM!*;
  550. SW3: IF NULL (Y:= ATSOC(NXTSYM!*,CAR X)) THEN GO TO SW2;
  551. PRIN2X NXTSYM!*;
  552. X := CDR Y;
  553. GO TO SW1;
  554. COMM: IF DELCP CRCHAR!* THEN GO TO COM1;
  555. CRCHAR!* := READCH();
  556. GO TO COMM;
  557. COM1: CRCHAR!* := '! ;
  558. CONDTERPRI();
  559. GO TO A;
  560. DELIM:
  561. SEMIC!*:=NXTSYM!*;
  562. RETURN (CURSYM!*:='!*SEMICOL!*);
  563. NEW: NXTSYM!* := X;
  564. IF STRINGP X THEN GO TO L
  565. ELSE IF ATOM X THEN GO TO C
  566. ELSE GO TO L;
  567. QUOTE:
  568. NXTSYM!* := MKQUOTE RREAD1();
  569. GO TO L;
  570. Q1: IF NULL (CAR NXTSYM!* EQ 'STRING) THEN GO TO L;
  571. PRIN2X " ";
  572. PRIN2X CADR(NXTSYM!* := MKQUOTE CADR NXTSYM!*);
  573. L: CURSYM!*:=NXTSYM!*;
  574. L1: NXTSYM!* := TOKEN();
  575. IF NXTSYM!* EQ !$EOF!$ AND TTYPE!* = 3 THEN RETURN FILENDERR();
  576. L2: IF NUMBERP NXTSYM!*
  577. OR (ATOM NXTSYM!* AND NULL GET(NXTSYM!*,'SWITCH!*))
  578. THEN PRIN2X " ";
  579. RETURN CURSYM!*;
  580. EOF: FILENDERR()
  581. END;
  582. %*********************************************************************
  583. % EXPRESSION READING
  584. %********************************************************************;
  585. % The conversion of a REDUCE expression to LISP prefix form is
  586. %carried out by the function XREAD. This function initiates the
  587. %scanning process, and then calls the auxiliary function XREAD1 to
  588. %perform the actual parsing. Both XREAD and XREAD1 are used by many
  589. %functions whenever an expression must be read;
  590. FLAG ('(END !*COLON!* !*SEMICOL!*),'DELIM);
  591. SYMBOLIC PROCEDURE EQCAR(U,V);
  592. NULL ATOM U AND CAR U EQ V;
  593. SYMBOLIC PROCEDURE MKSETQ(U,V);
  594. LIST('SETQ,U,V);
  595. SYMBOLIC PROCEDURE MKVAR(U,V); U;
  596. SYMBOLIC PROCEDURE REMCOMMA U;
  597. IF EQCAR(U,'!*COMMA!*) THEN CDR U ELSE LIST U;
  598. SYMBOLIC PROCEDURE ARRAYP U;
  599. GET(U,'ARRAY);
  600. SYMBOLIC PROCEDURE GETTYPE U;
  601. %it might be better to use a table here for more generality;
  602. IF NULL ATOM U THEN 'FORM
  603. ELSE IF NUMBERP U THEN 'NUMBER
  604. ELSE IF ARRAYP U THEN 'ARRAY
  605. ELSE IF GET(U,'SIMPFN) OR GET(U,'MSIMPFN) THEN 'OPERATOR
  606. ELSE IF GET(U,'AVALUE) THEN 'VARIABLE
  607. ELSE IF GETD U THEN 'PROCEDURE
  608. ELSE IF GLOBALP U THEN 'GLOBAL
  609. ELSE IF FLUIDP U THEN 'FLUID
  610. ELSE IF GET(U,'MATRIX) THEN 'MATRIX
  611. ELSE IF FLAGP(U,'PARM) THEN 'PARAMETER
  612. ELSE NIL;
  613. SYMBOLIC PROCEDURE XREAD1 U;
  614. BEGIN SCALAR V,W,X,Y,Z,Z1,Z2;
  615. % V: EXPRESSION BEING BUILT
  616. % W: PREFIX OPERATOR STACK
  617. % X: INFIX OPERATOR STACK
  618. % Y: INFIX VALUE OR STAT PROPERTY
  619. % Z: CURRENT SYMBOL
  620. % Z1: NEXT SYMBOL
  621. % Z2: TEMPORARY STORAGE;
  622. A: Z := CURSYM!*;
  623. A1: IF NULL IDP Z THEN NIL
  624. ELSE IF Z EQ '!*LPAR!* THEN GO TO LPAREN
  625. ELSE IF Z EQ '!*RPAR!* THEN GO TO RPAREN
  626. ELSE IF Y := GET(Z,'INFIX) THEN GO TO INFX
  627. ELSE IF NXTSYM!* EQ '!: THEN NIL
  628. ELSE IF FLAGP(Z,'DELIM) THEN GO TO DELIMIT
  629. ELSE IF Y := GET(Z,'STAT) THEN GO TO STAT;
  630. A2: Y := NIL;
  631. A3: W := Z . W;
  632. NEXT: Z := SCAN();
  633. GO TO A1;
  634. LPAREN:
  635. Y := NIL;
  636. IF SCAN() EQ '!*RPAR!* THEN GO TO LP1;
  637. %function of no args;
  638. Z := XREAD1 IF EQCAR(W,'MAT)
  639. THEN PROGN(TYPL!* := UNION('(MATP),TYPL!*),'MAT)
  640. ELSE 'PAREN;
  641. IF U EQ 'MAT THEN GO TO LP2
  642. ELSE IF NULL EQCAR(Z,'!*COMMA!*) THEN GO TO A3
  643. ELSE IF NULL W
  644. THEN (IF U EQ 'LAMBDA THEN GO TO A3
  645. ELSE SYMERR("Improper delimiter",NIL))
  646. ELSE W := (CAR W . CDR Z) . CDR W;
  647. GO TO NEXT;
  648. LP1: IF W THEN W := LIST CAR W . CDR W; %function of no args;
  649. GO TO NEXT;
  650. LP2: Z := REMCOMMA Z;
  651. GO TO A3;
  652. RPAREN:
  653. IF NULL U OR U EQ 'GROUP OR U EQ 'PROC
  654. THEN SYMERR("Too many right parentheses",NIL)
  655. ELSE GO TO END1;
  656. INFX: IF Z EQ '!*COMMA!* OR NULL ATOM (Z1 := SCAN())
  657. OR NUMBERP Z1 THEN GO TO IN1
  658. ELSE IF Z1 EQ '!*RPAR!*%infix operator used as variable;
  659. OR Z1 EQ '!*COMMA!*
  660. OR FLAGP(Z1,'DELIM)
  661. THEN GO TO IN2
  662. ELSE IF Z1 EQ '!*LPAR!*%infix operator in prefix position;
  663. AND NULL ATOM(Z1 := XREAD 'PAREN)
  664. AND CAR Z1 EQ '!*COMMA!*
  665. AND (Z := Z . CDR Z1)
  666. THEN GO TO A1;
  667. IN1: IF W THEN GO TO UNWIND
  668. ELSE IF NULL(Z := GET(Z,'UNARY))
  669. THEN SYMERR("Redundant operator",NIL);
  670. V := '!*!*UN!*!* . V;
  671. GO TO PR1;
  672. IN2: Y := NIL;
  673. W := Z . W;
  674. IN3: Z := Z1;
  675. GO TO A1;
  676. UNWIND:
  677. Z2 := MKVAR(CAR W,Z);
  678. UN1: W:= CDR W;
  679. IF NULL W THEN GO TO UN2
  680. ELSE IF NUMBERP CAR W THEN SYMERR("Missing Operator",NIL);
  681. Z2 := LIST(CAR W,Z2);
  682. GO TO UN1;
  683. UN2: V:= Z2 . V;
  684. PRECED:
  685. IF NULL X THEN IF Y=0 THEN GO TO END2 ELSE NIL
  686. ELSE IF Y<CAAR X
  687. OR (Y=CAAR X
  688. AND ((Z EQ CDAR X AND NULL FLAGP(Z,'NARY)
  689. AND NULL FLAGP(Z,'RIGHT))
  690. OR GET(CDAR X,'ALT)))
  691. THEN GO TO PR2;
  692. PR1: X:= (Y . Z) . X;
  693. IF NULL(Z EQ '!*COMMA!*) THEN GO TO IN3
  694. ELSE IF CDR X OR NULL U OR U MEMQ '(LAMBDA MAT PAREN)
  695. THEN GO TO NEXT
  696. ELSE GO TO END2;
  697. PR2: %IF CDAR X EQ 'SETQ THEN GO TO ASSIGN ELSE;
  698. IF CADR V EQ '!*!*UN!*!*
  699. THEN (IF CAR V EQ '!*!*UN!*!* THEN GO TO PR1
  700. ELSE Z2 := LIST(CDAR X,CAR V))
  701. ELSE Z2 := CDAR X .
  702. IF EQCAR(CAR V,CDAR X) AND FLAGP(CDAR X,'NARY)
  703. THEN (CADR V . CDAR V)
  704. ELSE LIST(CADR V,CAR V);
  705. X:= CDR X;
  706. V := Z2 . CDDR V;
  707. GO TO PRECED;
  708. STAT: IF NULL(FLAGP(Z,'GO)
  709. OR NULL(U EQ 'PROC) AND (FLAGP(Y,'ENDSTAT)
  710. OR (NULL DELCP NXTSYM!* AND NULL (NXTSYM!* EQ '!,))))
  711. THEN GO TO A2;
  712. W := APPLY(Y,NIL) . W;
  713. Y := NIL;
  714. GO TO A;
  715. DELIMIT:
  716. IF Z EQ '!*COLON!* AND NULL(U EQ 'FOR)
  717. AND (NULL BLOCKP!* OR NULL W OR NULL ATOM CAR W OR CDR W)
  718. OR FLAGP(Z,'NODEL)
  719. AND (NULL U OR U EQ 'GROUP AND NULL Z EQ '!*RSQB!*)
  720. THEN SYMERR("Improper delimiter",NIL)
  721. ELSE IF U MEMQ '(MAT PAREN)
  722. THEN SYMERR("Too few right parentheses",NIL);
  723. END1: IF Y THEN SYMERR("Improper delimiter",NIL)
  724. ELSE IF NULL V AND NULL W AND NULL X THEN RETURN NIL;
  725. Y := 0;
  726. GO TO UNWIND;
  727. END2: IF NULL CDR V THEN RETURN CAR V
  728. ELSE SYMERR("Improper delimiter",NIL)
  729. END;
  730. %SYMBOLIC PROCEDURE GETELS U;
  731. % GETEL(CAR U . !*EVLIS CDR U);
  732. %SYMBOLIC PROCEDURE !*EVLIS U;
  733. % MAPCAR(U,FUNCTION EVAL);
  734. FLAG ('(ENDSTAT MODESTAT RETSTAT),'ENDSTAT);
  735. FLAG ('(ELSE UNTIL),'NODEL);
  736. FLAG ('(BEGIN),'GO);
  737. SYMBOLIC PROCEDURE XREAD U;
  738. PROGN(SCAN(),XREAD1 U);
  739. FLAG('(XREAD),'OPFN); %to make it an operator;
  740. SYMBOLIC PROCEDURE COMMAND;
  741. BEGIN SCALAR X;
  742. IF !*DEMO AND (X := IFL!*)
  743. THEN PROGN(TERPRI(),RDS NIL,READCH(),RDS CDR X);
  744. IF NULL !*SLIN
  745. THEN PROGN(SCAN(),KEY!* := CURSYM!*,X := XREAD1 NIL)
  746. ELSE PROGN(KEY!* := (SEMIC!* := '!;),
  747. X := IF LREADFN!* THEN APPLY(LREADFN!*,NIL)
  748. ELSE READ(),
  749. IF KEY!* EQ '!;
  750. THEN KEY!* := IF ATOM X THEN X ELSE CAR X);
  751. IF !*PRET THEN PROGN(TERPRI(),RPRINT X);
  752. IF NULL !*SLIN THEN X := FORM X;
  753. RETURN X
  754. END;
  755. FLAG ('(DEFLIST FLAG FLUID GLOBAL REMFLAG REMPROP UNFLUID),'EVAL);
  756. %*********************************************************************
  757. % GENERAL FUNCTIONS
  758. %********************************************************************;
  759. SYMBOLIC PROCEDURE ACONC(U,V);
  760. %adds element V to the tail of U. U is destroyed in process;
  761. NCONC(U,LIST V);
  762. SYMBOLIC PROCEDURE PRIN2T U; PROGN(PRIN2 U, TERPRI(), U);
  763. SYMBOLIC PROCEDURE UNION(X,Y);
  764. IF NULL X THEN Y
  765. ELSE UNION(CDR X,IF CAR X MEMBER Y THEN Y ELSE CAR X . Y);
  766. SYMBOLIC PROCEDURE XN(U,V);
  767. IF NULL U THEN NIL
  768. ELSE IF CAR U MEMBER V THEN CAR U . XN(CDR U,DELETE(CAR U,V))
  769. ELSE XN(CDR U,V);
  770. SYMBOLIC PROCEDURE U>=V; NOT(U<V);
  771. SYMBOLIC PROCEDURE U<=V; NOT(U>V);
  772. SYMBOLIC PROCEDURE U NEQ V; NOT(U=V);
  773. %*********************************************************************
  774. % FUNCTIONS FOR PRINTING DIAGNOSTIC AND ERROR MESSAGES
  775. %********************************************************************;
  776. SYMBOLIC PROCEDURE LPRI U;
  777. BEGIN
  778. A: IF NULL U THEN RETURN NIL;
  779. PRIN2 CAR U;
  780. PRIN2 " ";
  781. U := CDR U;
  782. GO TO A
  783. END;
  784. SYMBOLIC PROCEDURE LPRIW (U,V);
  785. BEGIN SCALAR X;
  786. U := U . IF V AND ATOM V THEN LIST V ELSE V;
  787. IF OFL!* AND (!*FORT OR NOT !*NAT OR !*DEFN) THEN GO TO C;
  788. TERPRI();
  789. A: LPRI U;
  790. TERPRI();
  791. IF NULL X THEN GO TO B;
  792. WRS CDR X;
  793. RETURN NIL;
  794. B: IF NULL OFL!* THEN RETURN NIL;
  795. C: X := OFL!*;
  796. WRS NIL;
  797. GO TO A
  798. END;
  799. SYMBOLIC PROCEDURE LPRIM U;
  800. !*MSG AND LPRIW("***",U);
  801. SYMBOLIC PROCEDURE LPRIE U;
  802. BEGIN SCALAR X;
  803. IF !*INT THEN GO TO A;
  804. X:= !*DEFN;
  805. !*DEFN := NIL;
  806. A: ERFG!* := T;
  807. LPRIW ("*****",U);
  808. IF NULL !*INT THEN !*DEFN := X
  809. END;
  810. SYMBOLIC PROCEDURE PRINTTY U;
  811. BEGIN SCALAR OFL;
  812. IF NULL !*FORT AND !*NAT THEN PRINT U;
  813. IF NULL OFL!* THEN RETURN NIL;
  814. OFL := OFL!*;
  815. WRS NIL;
  816. PRINT U;
  817. WRS CDR OFL
  818. END;
  819. SYMBOLIC PROCEDURE REDERR U;
  820. BEGIN LPRIE U; ERROR1() END;
  821. FLAG('(REDERR),'OPFN);
  822. SYMBOLIC PROCEDURE SYMERR(U,V);
  823. BEGIN SCALAR X;
  824. ERFG!* := T;
  825. IF NUMBERP CURSYM!* OR NOT(X := GET(CURSYM!*,'PRTCH))
  826. THEN X := CURSYM!*
  827. ELSE X := CAR X;
  828. TERPRI();
  829. IF !*ECHO THEN TERPRI();
  830. OUTL!*:=CAR OUTL!* . '!$!$!$ . CDR OUTL!*;
  831. COMM1 T;
  832. MAPCAR(REVERSIP OUTL!*,FUNCTION PRIN2);
  833. TERPRI();
  834. OUTL!* := NIL;
  835. IF NULL V THEN REDERR U
  836. ELSE REDERR(X . ("invalid" .
  837. (IF U THEN LIST("in",U,"statement") ELSE NIL)))
  838. END;
  839. SYMBOLIC PROCEDURE TYPERR(U,V); REDERR LIST(U,"invalid as",V);
  840. %*********************************************************************
  841. % STATEMENTS
  842. %********************************************************************;
  843. % With the exception of assignment statements, which are
  844. %handled by XREAD, statements in REDUCE are introduced by a key-word,
  845. %which initiates a reading process peculiar to that statement. The
  846. %key-word is recognized (in XREAD1) by the indicator STAT on its
  847. %property list. The corresponding property is the name of the
  848. %function (of no arguments) which carries out the reading sequence. We
  849. %begin by introducing several statements which are necessary in a
  850. %basic system. Later on, we introduce statements which are part of the
  851. %complete system, but may be omitted if the corresponding
  852. %constructions are not required.
  853. % System users may add new statements to REDUCE by putting the
  854. %name of the statement reading function on the property list of the
  855. %new key-word with the indicator STAT. The reading function could be
  856. %defined as a new function or be a function already in the system.
  857. %Several applications only require that the arguments be grouped
  858. %together and quoted (such as IN, OUT, etc). To help with this, the
  859. %following two general statement reading functions are available. They
  860. %are used in this translator by ARRAY defined later. The function RLIS
  861. %reads a list of arguments and returns it as one argument;
  862. SYMBOLIC PROCEDURE RLIS;
  863. BEGIN SCALAR X;
  864. X := CURSYM!*;
  865. RETURN IF FLAGP!*!*(SCAN(),'DELIM) THEN LIST(X,NIL)
  866. ELSE X . REMCOMMA XREAD1 'LAMBDA
  867. END;
  868. SYMBOLIC PROCEDURE FLAGOP U; BEGIN FLAG(U,'FLAGOP); RLISTAT U END;
  869. SYMBOLIC PROCEDURE RLISTAT U;
  870. BEGIN
  871. A: IF NULL U THEN RETURN NIL;
  872. PUT(CAR U,'STAT,'RLIS);
  873. U := CDR U;
  874. GO TO A
  875. END;
  876. RLISTAT '(FLAGOP);
  877. %*********************************************************************
  878. % COMMENTS
  879. %********************************************************************;
  880. SYMBOLIC PROCEDURE COMM1 U;
  881. BEGIN SCALAR BOOL;
  882. IF U EQ 'END THEN GO TO B;
  883. A: IF CURSYM!* EQ '!*SEMICOL!*
  884. OR U EQ 'END
  885. AND CURSYM!* MEMQ
  886. '(END ELSE THEN UNTIL !*RPAR!* !*RSQB!*)
  887. THEN RETURN NIL
  888. ELSE IF U EQ 'END AND NULL BOOL
  889. THEN PROGN(LPRIM LIST("END-COMMENT NO LONGER SUPPORTED"),
  890. BOOL := T);
  891. B: SCAN();
  892. GO TO A
  893. END;
  894. %*********************************************************************
  895. % CONDITIONAL STATEMENT
  896. %********************************************************************;
  897. SYMBOLIC PROCEDURE FORMCOND(U,VARS,MODE);
  898. 'COND . FORMCOND1(U,VARS,MODE);
  899. SYMBOLIC PROCEDURE FORMCOND1(U,VARS,MODE);
  900. IF NULL U THEN NIL
  901. ELSE LIST(FORMBOOL(CAAR U,VARS,MODE),FORMC(CADAR U,VARS,MODE))
  902. . FORMCOND1(CDR U,VARS,MODE);
  903. PUT('COND,'FORMFN,'FORMCOND);
  904. SYMBOLIC PROCEDURE IFSTAT;
  905. BEGIN SCALAR CONDX,CONDIT;
  906. FLAG(LETL!*,'DELIM);
  907. A: CONDX := XREAD T;
  908. REMFLAG(LETL!*,'DELIM);
  909. IF NOT CURSYM!* EQ 'THEN THEN GO TO C;
  910. CONDIT := ACONC(CONDIT,LIST(CONDX,XREAD T));
  911. IF NOT CURSYM!* EQ 'ELSE THEN GO TO B
  912. ELSE IF SCAN() EQ 'IF THEN GO TO A
  913. ELSE CONDIT := ACONC(CONDIT,LIST(T,XREAD1 T));
  914. B: RETURN ('COND . CONDIT);
  915. C: IF NOT CURSYM!* MEMQ LETL!* THEN SYMERR('IF,T);
  916. RETURN IFLET CONDX
  917. END;
  918. PUT('IF,'STAT,'IFSTAT);
  919. FLAG ('(THEN ELSE),'DELIM);
  920. %*********************************************************************
  921. % COMPOUND STATEMENT
  922. %********************************************************************;
  923. SYMBOLIC PROCEDURE DECL U;
  924. BEGIN SCALAR VARLIS,W;
  925. A: IF CURSYM!* EQ '!*SEMICOL!* THEN GO TO C
  926. ELSE IF NOT FLAGP!*!*(CURSYM!*,'TYPE) THEN RETURN VARLIS
  927. ELSE IF CURSYM!* EQ 'DCL THEN GO TO DCL;
  928. W := CURSYM!*;
  929. IF SCAN() EQ 'PROCEDURE THEN RETURN PROCSTAT1 W;
  930. VARLIS := APPEND(VARLIS,PAIRVARS(REMCOMMA XREAD1 NIL,NIL,W));
  931. B: IF NOT CURSYM!* EQ '!*SEMICOL!* THEN SYMERR(NIL,T)
  932. ELSE IF NULL U THEN RETURN LIST('DCL,MKQUOTE VARLIS);
  933. %top level declaration;
  934. C: SCAN();
  935. GO TO A;
  936. DCL: VARLIS := APPEND(VARLIS,DCLSTAT1());
  937. GO TO B
  938. END;
  939. FLAG ('(DCL REAL INTEGER SCALAR),'TYPE);
  940. SYMBOLIC PROCEDURE DCLSTAT; LIST('DCL,MKQUOTE DCLSTAT1());
  941. SYMBOLIC PROCEDURE DCLSTAT1;
  942. BEGIN SCALAR X,Y;
  943. A: X := XREAD NIL;
  944. IF NOT CURSYM!* EQ '!*COLON!* THEN SYMERR('DCL,T);
  945. Y := APPEND(Y,PAIRVARS(REMCOMMA X,NIL,SCAN()));
  946. IF SCAN() EQ '!*SEMICOL!* THEN RETURN Y
  947. ELSE IF NOT CURSYM!* EQ '!*COMMA!* THEN SYMERR('DCL,T)
  948. ELSE GO TO A
  949. END;
  950. GLOBAL '(!*VARS!*);
  951. SYMBOLIC PROCEDURE DCL U;
  952. %U is a list of (id, mode) pairs, which are declared as global vars;
  953. BEGIN SCALAR X;
  954. !*VARS!* := APPEND(U,!*VARS!*);
  955. X := MAPCAR(U,FUNCTION CAR);
  956. GLOBAL X;
  957. FLAG(X,'SHARE);
  958. A: IF NULL U THEN RETURN NIL;
  959. SET(CAAR U,GET(CDAR U,'INITVALUE));
  960. U := CDR U;
  961. GO TO A
  962. END;
  963. PUT('INTEGER,'INITVALUE,0);
  964. PUT('DCL,'STAT,'DCLSTAT);
  965. SYMBOLIC PROCEDURE MKPROG(U,V);
  966. 'PROG . (U . V);
  967. SYMBOLIC PROCEDURE SETDIFF(U,V);
  968. IF NULL V THEN U ELSE SETDIFF(DELETE(CAR V,U),CDR V);
  969. SYMBOLIC PROCEDURE PAIRVARS(U,VARS,MODE);
  970. BEGIN SCALAR X;
  971. A: IF NULL U THEN RETURN APPEND(REVERSIP X,VARS);
  972. X := (CAR U . MODE) . X;
  973. U := CDR U;
  974. GO TO A
  975. END;
  976. SYMBOLIC PROCEDURE FORMBLOCK(U,VARS,MODE);
  977. 'PROG . APPEND(INITPROGVARS CAR U,
  978. FORMPROG1(CDR U,APPEND(CAR U,VARS),MODE));
  979. SYMBOLIC PROCEDURE INITPROGVARS U;
  980. BEGIN SCALAR X,Y,Z;
  981. A: IF NULL U THEN RETURN(REVERSIP X . REVERSIP Y)
  982. ELSE IF Z := GET(CDAR U,'INITVALUE)
  983. THEN Y := MKSETQ(CAAR U,Z) . Y;
  984. X := CAAR U . X;
  985. U := CDR U;
  986. GO TO A
  987. END;
  988. SYMBOLIC PROCEDURE FORMPROG(U,VARS,MODE);
  989. 'PROG . CAR U . FORMPROG1(CDR U,PAIRVARS(CAR U,VARS,MODE),MODE);
  990. SYMBOLIC PROCEDURE FORMPROG1(U,VARS,MODE);
  991. IF NULL U THEN NIL
  992. ELSE IF ATOM CAR U THEN CAR U . FORMPROG1(CDR U,VARS,MODE)
  993. ELSE IF IDP CAAR U AND GET(CAAR U,'STAT) EQ 'MODESTAT
  994. THEN FORMC(CADAR U,VARS,CAAR U) . FORMPROG1(CDR U,VARS,MODE)
  995. ELSE FORMC(CAR U,VARS,MODE) . FORMPROG1(CDR U,VARS,MODE);
  996. PUT('BLOCK,'FORMFN,'FORMBLOCK);
  997. PUT('PROG,'FORMFN,'FORMPROG);
  998. SYMBOLIC PROCEDURE BLOCKSTAT;
  999. BEGIN SCALAR X,HOLD,VARLIS;
  1000. BLOCKP!* := NIL . BLOCKP!*;
  1001. SCAN();
  1002. IF CURSYM!* MEMQ '(NIL !*RPAR!*) THEN REDERR "BEGIN invalid";
  1003. VARLIS := DECL T;
  1004. A: IF CURSYM!* EQ 'END AND NOT NXTSYM!* EQ '!: THEN GO TO B;
  1005. X := XREAD1 NIL;
  1006. IF EQCAR(X,'END) THEN GO TO C;
  1007. NOT CURSYM!* EQ 'END AND SCAN();
  1008. IF X THEN HOLD := ACONC(HOLD,X);
  1009. GO TO A;
  1010. B: COMM1 'END;
  1011. C: BLOCKP!* := CDR BLOCKP!*;
  1012. RETURN MKBLOCK(VARLIS,HOLD)
  1013. END;
  1014. SYMBOLIC PROCEDURE MKBLOCK(U,V); 'BLOCK . (U . V);
  1015. PUTD('BLOCK,'MACRO,
  1016. '(LAMBDA (U) (CONS 'PROG
  1017. (CONS (MAPCAR (CADR U) (FUNCTION CAR)) (CDDR U)))));
  1018. SYMBOLIC PROCEDURE DECSTAT;
  1019. %only called if a declaration occurs at the top level or not first
  1020. %in a block;
  1021. BEGIN SCALAR X,Y,Z;
  1022. IF BLOCKP!* THEN SYMERR('BLOCK,T);
  1023. X := CURSYM!*;
  1024. Y := NXTSYM!*;
  1025. Z := DECL NIL;
  1026. IF Y NEQ 'PROCEDURE THEN REDERR LIST(X,"invalid outside block");
  1027. RETURN Z
  1028. END;
  1029. PUT('INTEGER,'STAT,'DECSTAT);
  1030. PUT('REAL,'STAT,'DECSTAT);
  1031. PUT('SCALAR,'STAT,'DECSTAT);
  1032. PUT('BEGIN,'STAT,'BLOCKSTAT);
  1033. %*********************************************************************
  1034. % RETURN STATEMENT
  1035. %********************************************************************;
  1036. SYMBOLIC PROCEDURE RETSTAT;
  1037. IF NOT BLOCKP!* THEN SYMERR(NIL,T)
  1038. ELSE LIST('RETURN,
  1039. IF FLAGP!*!*(SCAN(),'DELIM) THEN NIL ELSE XREAD1 T);
  1040. PUT('RETURN,'STAT,'RETSTAT);
  1041. %*********************************************************************
  1042. % EVALUATION MODE STATEMENT
  1043. %********************************************************************;
  1044. SYMBOLIC PROCEDURE MODESTAT;
  1045. BEGIN SCALAR X;
  1046. X:= CURSYM!*;
  1047. RETURN IF FLAGP!*!*(SCAN(),'DELIM) THEN PROGN(!*MODE := X, NIL)
  1048. ELSE LIST(X,XREAD1 T)
  1049. END;
  1050. %*********************************************************************
  1051. % LAMBDA STATEMENT
  1052. %********************************************************************;
  1053. SYMBOLIC PROCEDURE FORMLAMB(U,VARS,MODE);
  1054. LIST('LAMBDA,CAR U,FORM1(CADR U,PAIRVARS(CAR U,VARS,MODE),MODE));
  1055. PUT('LAMBDA,'FORMFN,'FORMLAMB);
  1056. SYMBOLIC PROCEDURE LAMSTAT;
  1057. BEGIN SCALAR X,Y;
  1058. X:= XREAD 'LAMBDA;
  1059. % X := FLAGTYPE(IF NULL X THEN NIL ELSE REMCOMMA X,'SCALAR);
  1060. IF X THEN X := REMCOMMA X;
  1061. Y := LIST('LAMBDA,X,XREAD T);
  1062. % REMTYPE X;
  1063. RETURN Y
  1064. END;
  1065. PUT ('LAMBDA,'STAT,'LAMSTAT);
  1066. %*********************************************************************
  1067. % GROUP STATEMENT
  1068. %********************************************************************;
  1069. SYMBOLIC PROCEDURE FORMPROGN(U,VARS,MODE);
  1070. 'PROGN . FORMCLIS(U,VARS,MODE);
  1071. PUT('PROGN,'FORMFN,'FORMPROGN);
  1072. SYMBOLIC PROCEDURE MKPROGN;
  1073. %Expects a list of statements terminated by a >>;
  1074. BEGIN SCALAR LST;
  1075. A: LST := ACONC(LST,XREAD 'GROUP);
  1076. IF NULL(CURSYM!* EQ '!*RSQB!*) THEN GO TO A;
  1077. SCAN();
  1078. RETURN 'PROGN . LST
  1079. END;
  1080. PUT('!*LSQB!*,'STAT,'MKPROGN);
  1081. FLAG('(!*RSQB!*),'DELIM);
  1082. FLAG('(!*RSQB!*),'NODEL);
  1083. %*********************************************************************
  1084. % EXPRESSION MODE ANALYSIS
  1085. %********************************************************************;
  1086. COMMENT This module is required at this point for bootstrapping
  1087. purposes;
  1088. SYMBOLIC PROCEDURE EXPDRMACRO U;
  1089. %returns the macro form for U if expansion is permitted;
  1090. BEGIN SCALAR X;
  1091. IF NULL(X := GETRMACRO U) THEN RETURN NIL
  1092. ELSE IF NULL !*CREF AND (NULL !*DEFN OR CAR X EQ 'SMACRO)
  1093. OR FLAGP(U,'EXPAND) OR !*FORCE AND NULL FLAGP(U,'NOEXPAND)
  1094. THEN RETURN X
  1095. ELSE RETURN NIL
  1096. END;
  1097. SYMBOLIC PROCEDURE GETRMACRO U;
  1098. %returns a Reduce macro definition for U, if one exists,
  1099. %in GETD format;
  1100. BEGIN SCALAR X;
  1101. RETURN IF NOT IDP U THEN NIL
  1102. ELSE IF (X := GETD U) AND CAR X EQ 'MACRO THEN X
  1103. ELSE IF (X := GET(U,'SMACRO)) THEN 'SMACRO . X
  1104. % ELSE IF (X := GET(U,'NMACRO)) THEN 'NMACRO . X;
  1105. ELSE NIL
  1106. END;
  1107. SYMBOLIC PROCEDURE APPLMACRO(U,V,W);
  1108. APPLY(U,LIST(W . V));
  1109. %SYMBOLIC PROCEDURE APPLNMACRO(U,V,W);
  1110. % APPLY(U,IF FLAGP(W,'NOSPREAD) THEN LIST V ELSE V);
  1111. SYMBOLIC PROCEDURE APPLSMACRO(U,V,W);
  1112. %We could use an atom sublis here, eg SUBLA;
  1113. SUBLIS(PAIR(CADR U,V),CADDR U);
  1114. PUT('MACRO,'MACROFN,'APPLMACRO);
  1115. %PUT('NMACRO,'MACROFN,'APPLNMACRO);
  1116. PUT('SMACRO,'MACROFN,'APPLSMACRO);
  1117. FLAG('(ED GO QUOTE),'NOFORM);
  1118. SYMBOLIC PROCEDURE FORM1(U,VARS,MODE);
  1119. BEGIN SCALAR X,Y;
  1120. IF ATOM U
  1121. THEN RETURN IF U EQ 'ED THEN LIST U
  1122. ELSE IF NOT(IDP U AND (X:= GET(MODE,'IDFN))) THEN U
  1123. ELSE APPLY(X,LIST(U,VARS))
  1124. ELSE IF NOT ATOM CAR U THEN RETURN FORMLIS(U,VARS,MODE)
  1125. ELSE IF NOT IDP CAR U
  1126. THEN TYPERR(CAR U,"operator")
  1127. ELSE IF FLAGP(CAR U,'NOFORM) THEN RETURN U
  1128. ELSE IF ARRAYP CAR U
  1129. AND (MODE EQ 'SYMBOLIC OR INTEXPRLISP(CDR U,VARS))
  1130. THEN RETURN LIST('GETEL,INTARGFN(U,VARS))
  1131. ELSE IF GET(CAR U,'STAT) EQ 'MODESTAT
  1132. THEN RETURN CONVERTMODE(CADR U,VARS,MODE,CAR U)
  1133. ELSE IF (X := GET(CAR U,'FORMFN))
  1134. THEN RETURN MACROCHK(APPLY(X,LIST(CDR U,VARS,MODE)),MODE)
  1135. ELSE IF GET(CAR U,'STAT) EQ 'RLIS
  1136. THEN RETURN MACROCHK(FORMRLIS(U,VARS,MODE),MODE);
  1137. X := FORMLIS(CDR U,VARS,MODE);
  1138. Y := IF X=CDR U THEN U ELSE CAR U . X;
  1139. RETURN IF MODE EQ 'SYMBOLIC
  1140. OR GET(CAR U,'STAT) OR CDR U AND EQCAR(CADR U,'QUOTE)
  1141. OR INTEXPRNP(Y,VARS) AND NULL !*COMPOSITES AND NULL MOD!*
  1142. THEN MACROCHK(Y,MODE)
  1143. ELSE IF NOT(MODE EQ 'ALGEBRAIC)
  1144. THEN CONVERTMODE(Y,VARS,MODE,'ALGEBRAIC)
  1145. ELSE ('LIST . MKQUOTE CAR U . X)
  1146. END;
  1147. SYMBOLIC PROCEDURE FORMLIS(U,VARS,MODE);
  1148. MAPCAR(U,FUNCTION (LAMBDA X; FORM1(X,VARS,MODE)));
  1149. SYMBOLIC PROCEDURE FORMCLIS(U,VARS,MODE);
  1150. MAPCAR(U,FUNCTION (LAMBDA X; FORMC(X,VARS,MODE)));
  1151. SYMBOLIC PROCEDURE FORM U; FORM1(U,!*VARS!*,!*MODE);
  1152. SYMBOLIC PROCEDURE MACROCHK(U,MODE);
  1153. BEGIN SCALAR Y;
  1154. %expands U if CAR U is a macro and expansion allowed;
  1155. IF ATOM U THEN RETURN U
  1156. ELSE IF (Y := EXPDRMACRO CAR U)
  1157. AND (MODE EQ 'SYMBOLIC OR IDP CAR U AND FLAGP(CAR U,'OPFN))
  1158. THEN RETURN APPLY(GET(CAR Y,'MACROFN),LIST(CDR Y,CDR U,CAR U))
  1159. ELSE RETURN U
  1160. END;
  1161. PUT('SYMBOLIC,'IDFN,'SYMBID);
  1162. SYMBOLIC PROCEDURE SYMBID(U,VARS); U;
  1163. % IF ATSOC(U,VARS) OR FLUIDP U OR GLOBALP U OR U MEMQ '(NIL T)
  1164. % OR FLAGP(U,'SHARE) THEN U
  1165. % ELSE <<LPRIM LIST(U,"Non-Local Identifier");% U>>;
  1166. PUT('ALGEBRAIC,'IDFN,'ALGID);
  1167. SYMBOLIC PROCEDURE ALGID(U,VARS);
  1168. IF ATSOC(U,VARS) OR FLAGP(U,'SHARE) THEN U ELSE MKQUOTE U;
  1169. PUT('INTEGER,'IDFN,'INTID);
  1170. SYMBOLIC PROCEDURE INTID(U,VARS);
  1171. BEGIN SCALAR X,Y;
  1172. RETURN IF (X := ATSOC(U,VARS))
  1173. THEN IF CDR X EQ 'INTEGER THEN U
  1174. ELSE IF Y := GET(CDR X,'INTEGER)
  1175. THEN APPLY(Y,LIST(U,VARS))
  1176. ELSE IF CDR X EQ 'SCALAR THEN !*!*A2I(U,VARS)
  1177. ELSE REDERR LIST(CDR X,"not convertable to INTEGER")
  1178. ELSE !*!*A2I(MKQUOTE U,VARS)
  1179. END;
  1180. SYMBOLIC PROCEDURE CONVERTMODE(EXPRN,VARS,TARGET,SOURCE);
  1181. CONVERTMODE1(FORM1(EXPRN,VARS,SOURCE),VARS,TARGET,SOURCE);
  1182. SYMBOLIC PROCEDURE CONVERTMODE1(EXPRN,VARS,TARGET,SOURCE);
  1183. BEGIN SCALAR X;
  1184. % EXPRN := FORM1(EXPRN,VARS,SOURCE);
  1185. IF TARGET EQ SOURCE THEN RETURN EXPRN
  1186. ELSE IF IDP EXPRN AND (X := ATSOC(EXPRN,VARS))
  1187. AND NOT(CDR X EQ 'SCALAR) AND NOT(CDR X EQ SOURCE)
  1188. THEN RETURN CONVERTMODE(EXPRN,VARS,TARGET,CDR X)
  1189. ELSE IF NOT (X := GET(SOURCE,TARGET))
  1190. THEN TYPERR(SOURCE,TARGET)
  1191. ELSE RETURN APPLY(X,LIST(EXPRN,VARS))
  1192. END;
  1193. PUT('ALGEBRAIC,'SYMBOLIC,'!*!*A2S);
  1194. PUT('SYMBOLIC,'ALGEBRAIC,'!*!*S2A);
  1195. FLUID '(!*!*A2SFN);
  1196. !*!*A2SFN := 'AEVAL;
  1197. SYMBOLIC PROCEDURE !*!*A2S(U,VARS);
  1198. IF NULL U OR CONSTANTP U AND NULL FIXP U
  1199. OR INTEXPRNP(U,VARS) AND NULL !*COMPOSITES AND NULL MOD!*
  1200. OR NOT ATOM U AND IDP CAR U
  1201. AND FLAGP(CAR U,'NOCHANGE) AND NOT(CAR U EQ 'GETEL)
  1202. THEN U
  1203. ELSE IF U = '(QUOTE NIL) THEN NIL
  1204. ELSE LIST(!*!*A2SFN,U);
  1205. SYMBOLIC PROCEDURE !*!*S2A(U,VARS); U;
  1206. SYMBOLIC PROCEDURE FORMC(U,VARS,MODE);
  1207. %this needs to be generalized;
  1208. IF MODE EQ 'ALGEBRAIC AND INTEXPRNP(U,VARS) THEN U
  1209. ELSE CONVERTMODE(U,VARS,'SYMBOLIC,MODE);
  1210. SYMBOLIC PROCEDURE INTARGFN(U,VARS);
  1211. %transforms U into a function with integer arguments.
  1212. %We assume that the analysis is done in algebraic mode;
  1213. 'LIST . FORM1(CAR U,VARS,'ALGEBRAIC) .
  1214. MAPCAR(CDR U,
  1215. FUNCTION (LAMBDA X;
  1216. CONVERTMODE(X,VARS,'INTEGER,'ALGEBRAIC)));
  1217. PUT('ALGEBRAIC,'INTEGER,'!*!*A2I);
  1218. SYMBOLIC PROCEDURE !*!*A2I(U,VARS);
  1219. IF INTEXPRNP(U,VARS) THEN U ELSE LIST('!*S2I,LIST('REVAL,U));
  1220. PUT('SYMBOLIC,'INTEGER,'!*!*S2I);
  1221. SYMBOLIC PROCEDURE !*!*S2I(U,VARS);
  1222. IF NUMBERP U AND FIXP U THEN U ELSE LIST('!*S2I,U);
  1223. SYMBOLIC PROCEDURE !*S2I U;
  1224. IF NUMBERP U AND FIXP U THEN U ELSE TYPERR(U,"integer");
  1225. PUT('INTEGER,'SYMBOLIC,'IDENTITY);
  1226. SYMBOLIC PROCEDURE IDENTITY(U,VARS); U;
  1227. SYMBOLIC PROCEDURE FORMBOOL(U,VARS,MODE);
  1228. IF MODE EQ 'SYMBOLIC THEN FORM1(U,VARS,MODE)
  1229. ELSE IF ATOM U THEN IF NOT IDP U OR ATSOC(U,VARS) OR U EQ 'T
  1230. THEN U
  1231. ELSE FORMC!*(U,VARS,MODE)
  1232. ELSE IF INTEXPRLISP(CDR U,VARS) AND GET(CAR U,'BOOLFN) THEN U
  1233. ELSE IF IDP CAR U AND GET(CAR U,'BOOLFN)
  1234. THEN GET(CAR U,'BOOLFN) . FORMCLIS(CDR U,VARS,MODE)
  1235. ELSE IF IDP CAR U AND FLAGP(CAR U,'BOOLEAN)
  1236. THEN CAR U .
  1237. MAPCAR(CDR U,FUNCTION (LAMBDA X;
  1238. IF FLAGP(CAR U,'BOOLARGS)
  1239. THEN FORMBOOL(X,VARS,MODE)
  1240. ELSE FORMC!*(X,VARS,MODE)))
  1241. ELSE FORMC!*(U,VARS,MODE);
  1242. SYMBOLIC PROCEDURE FORMC!*(U,VARS,MODE);
  1243. BEGIN SCALAR !*!*A2SFN;
  1244. !*!*A2SFN := 'REVAL;
  1245. RETURN FORMC(U,VARS,MODE)
  1246. END;
  1247. SYMBOLIC PROCEDURE FORMSETQ(U,VARS,MODE);
  1248. BEGIN SCALAR TARGET,X,Y;
  1249. IF EQCAR(CADR U,'QUOTE) THEN MODE := 'SYMBOLIC;
  1250. IF IDP CAR U
  1251. AND (Y := ATSOC(CAR U,VARS)) AND NOT(CDR Y EQ 'SCALAR)
  1252. THEN TARGET := CDR Y
  1253. ELSE TARGET := 'SYMBOLIC;
  1254. X := CONVERTMODE(CADR U,VARS,TARGET,MODE);
  1255. RETURN IF NOT ATOM CAR U
  1256. THEN IF NOT IDP CAAR U THEN TYPERR(CAR U,"assignment")
  1257. ELSE IF ARRAYP CAAR U
  1258. AND (MODE EQ 'SYMBOLIC OR INTEXPRLISP(CDAR U,VARS))
  1259. THEN LIST('SETEL,INTARGFN(CAR U,VARS),X)
  1260. ELSE IF Y := GET(CAAR U,'SETQFN)
  1261. THEN FORM1((Y . APPEND(CDAR U,CDR U)),VARS,MODE)
  1262. ELSE LIST('SETK,FORM1(CAR U,VARS,MODE),X)
  1263. ELSE IF NOT IDP CAR U THEN TYPERR(CAR U,"assignment")
  1264. ELSE IF MODE EQ 'SYMBOLIC OR Y OR FLAGP(CAR U,'SHARE)
  1265. OR EQCAR(X,'QUOTE)
  1266. THEN MKSETQ(CAR U,X)
  1267. ELSE LIST('SETK,MKQUOTE CAR U,X)
  1268. END;
  1269. PUT('CAR,'SETQFN,'RPLACA);
  1270. PUT('CDR,'SETQFN,'RPLACD);
  1271. PUT('SETQ,'FORMFN,'FORMSETQ);
  1272. SYMBOLIC PROCEDURE FORMFUNC(U,VARS,MODE);
  1273. IF IDP CAR U THEN IF GETRMACRO CAR U
  1274. THEN REDERR LIST("Macro",CAR U,"Used as Function")
  1275. ELSE LIST('FUNCTION,CAR U)
  1276. ELSE LIST('FUNCTION,FORM1(CAR U,VARS,MODE));
  1277. PUT('FUNCTION,'FORMFN,'FORMFUNC);
  1278. SYMBOLIC PROCEDURE FORMRLIS(U,VARS,MODE);
  1279. IF NOT FLAGP(CAR U,'FLAGOP)
  1280. THEN LIST(CAR U,'LIST . FORMLIS(CDR U,VARS,'ALGEBRAIC))
  1281. ELSE MKPROG(NIL,LIST('FLAG,MKQUOTE CDR U,MKQUOTE CAR U)
  1282. . GET(CAR U,'SIMPFG));
  1283. SYMBOLIC PROCEDURE MKARG(U,VARS);
  1284. %returns the "unevaled" form of U;
  1285. IF NULL U OR CONSTANTP U THEN U
  1286. ELSE IF ATOM U THEN IF ATSOC(U,VARS) THEN U ELSE MKQUOTE U
  1287. ELSE IF CAR U EQ 'QUOTE THEN MKQUOTE U
  1288. ELSE 'LIST . MAPCAR(U,FUNCTION (LAMBDA X; MKARG(X,VARS)));
  1289. %*********************************************************************
  1290. % PROCEDURE STATEMENT
  1291. %********************************************************************;
  1292. FTYPES!* := '(EXPR FEXPR MACRO);
  1293. FLUID '(!*COMP);
  1294. SYMBOLIC PROCEDURE PUTC(NAME,TYPE,BODY);
  1295. %defines a non-standard function, such as an smacro. Returns NAME;
  1296. BEGIN
  1297. IF !*COMP AND FLAGP(TYPE,'COMPILE) THEN COMPD(NAME,TYPE,BODY)
  1298. ELSE PUT(NAME,TYPE,BODY);
  1299. RETURN NAME
  1300. END;
  1301. SYMBOLIC PROCEDURE PAIRXVARS(U,V,VARS,MODE);
  1302. %Pairs procedure variables and their modes, taking into account
  1303. %the convention which allows a top level prog to change the mode
  1304. %of such a variable;
  1305. BEGIN SCALAR X,Y;
  1306. A: IF NULL U THEN RETURN APPEND(REVERSIP X,VARS) . V
  1307. ELSE IF (Y := ATSOC(CAR U,V))
  1308. THEN <<V := DELETE(Y,V);
  1309. IF NOT(CDR Y EQ 'SCALAR) THEN X := (CAR U . CDR Y) . X
  1310. ELSE X := (CAR U . MODE) . X>>
  1311. ELSE X := (CAR U . MODE) . X;
  1312. U := CDR U;
  1313. GO TO A
  1314. END;
  1315. SYMBOLIC PROCEDURE FORMPROC(U,VARS,MODE);
  1316. BEGIN SCALAR BODY,NAME,TYPE,VARLIS,X,Y;
  1317. NAME := CAR U;
  1318. IF CADR U THEN MODE := CADR U; %overwrite previous mode;
  1319. U := CDDR U;
  1320. TYPE := CAR U;
  1321. IF FLAGP(NAME,'LOSE) AND (!*LOSE OR NULL !*DEFN)
  1322. THEN RETURN PROGN(LPRIM LIST(NAME,
  1323. "not defined (LOSE flag)"),
  1324. NIL);
  1325. VARLIS := CADR U;
  1326. U := CADDR U;
  1327. X := IF EQCAR(U,'BLOCK) THEN CADR U ELSE NIL;
  1328. Y := PAIRXVARS(VARLIS,X,VARS,MODE);
  1329. IF X THEN RPLACA(CDR U,CDR Y);
  1330. BODY:= FORM1(U,CAR Y,MODE);
  1331. IF TYPE EQ 'EXPR THEN BODY := LIST('DE,NAME,VARLIS,BODY)
  1332. ELSE IF TYPE EQ 'FEXPR THEN BODY := LIST('DF,NAME,VARLIS,BODY)
  1333. ELSE IF TYPE EQ 'MACRO THEN BODY := LIST('DM,NAME,VARLIS,BODY)
  1334. ELSE IF TYPE EQ 'EMB THEN RETURN EMBFN(NAME,VARLIS,BODY)
  1335. ELSE BODY := LIST('PUTC,
  1336. MKQUOTE NAME,
  1337. MKQUOTE TYPE,
  1338. MKQUOTE LIST('LAMBDA,VARLIS,BODY));
  1339. IF NOT(MODE EQ 'SYMBOLIC)
  1340. THEN BODY := LIST('PROGN,
  1341. LIST('FLAG,MKQUOTE LIST NAME,MKQUOTE 'OPFN),
  1342. BODY);
  1343. IF !*DEFN AND TYPE MEMQ '(MACRO SMACRO)
  1344. THEN EVAL BODY;
  1345. RETURN BODY
  1346. END;
  1347. PUT('PROCEDURE,'FORMFN,'FORMPROC);
  1348. SYMBOLIC PROCEDURE PROCSTAT1 MODE;
  1349. BEGIN SCALAR BOOL,U,TYPE,X,Y,Z;
  1350. BOOL := ERFG!*;
  1351. IF FNAME!* THEN GO TO B
  1352. ELSE IF CURSYM!* EQ 'PROCEDURE THEN TYPE := 'EXPR
  1353. ELSE PROGN(TYPE := CURSYM!*,SCAN());
  1354. IF NOT CURSYM!* EQ 'PROCEDURE THEN GO TO C;
  1355. X := ERRORSET('(XREAD (QUOTE PROC)),NIL,!*BACKTRACE);
  1356. IF ERRORP X THEN GO TO A
  1357. ELSE IF ATOM (X := CAR X) THEN X := LIST X; %no arguments;
  1358. FNAME!* := CAR X; %function name;
  1359. IF IDP FNAME!* %AND NOT(TYPE MEMQ FTYPES!*);
  1360. THEN IF NULL FNAME!* OR (Z := GETTYPE FNAME!*)
  1361. AND NOT Z MEMQ '(PROCEDURE OPERATOR)
  1362. THEN GO TO D
  1363. ELSE IF NOT GETD FNAME!* THEN FLAG(LIST FNAME!*,'FNC);
  1364. %to prevent invalid use of function name in body;
  1365. U := CDR X;
  1366. Y := U;
  1367. X := CAR X . Y;
  1368. A: Z := ERRORSET('(XREAD T),NIL,!*BACKTRACE);
  1369. IF NOT ERRORP Z THEN Z := CAR Z;
  1370. IF NULL ERFG!* THEN Z:=LIST('PROCEDURE,CAR X,MODE,TYPE,Y,Z);
  1371. REMFLAG(LIST FNAME!*,'FNC);
  1372. FNAME!*:=NIL;
  1373. IF ERFG!* THEN PROGN(Z := NIL,IF NOT BOOL THEN ERROR1());
  1374. RETURN Z;
  1375. B: BOOL := T;
  1376. C: ERRORSET('(SYMERR (QUOTE PROCEDURE) T),NIL,!*BACKTRACE);
  1377. GO TO A;
  1378. D: TYPERR(LIST(Z,FNAME!*),"procedure");
  1379. GO TO A
  1380. END;
  1381. SYMBOLIC PROCEDURE PROCSTAT; PROCSTAT1 NIL;
  1382. DEFLIST ('((PROCEDURE PROCSTAT) (EXPR PROCSTAT) (FEXPR PROCSTAT)
  1383. (EMB PROCSTAT)
  1384. (MACRO PROCSTAT) (SMACRO PROCSTAT)),
  1385. 'STAT);
  1386. DEFLIST ('((ALGEBRAIC MODESTAT) (SYMBOLIC MODESTAT)),
  1387. 'STAT);
  1388. DEFLIST('((LISP SYMBOLIC)),'NEWNAM);
  1389. COMMENT Defining GEQ, LEQ and NEQ as SMACROS;
  1390. SMACRO PROCEDURE U>=V; NOT(U<V);
  1391. SMACRO PROCEDURE U<=V; NOT(U>V);
  1392. SMACRO PROCEDURE U NEQ V; NOT(U=V);
  1393. %*********************************************************************
  1394. % END STATEMENT
  1395. %********************************************************************;
  1396. SYMBOLIC PROCEDURE ENDSTAT;
  1397. %This procedure can also be used for any key-words which take no
  1398. %arguments;
  1399. BEGIN SCALAR X;
  1400. X := CURSYM!*;
  1401. COMM1 'END;
  1402. RETURN LIST X
  1403. END;
  1404. PUT('END,'STAT,'ENDSTAT);
  1405. PUT('BYE,'STAT,'ENDSTAT);
  1406. PUT('QUIT,'STAT,'ENDSTAT);
  1407. FLAG('(BYE QUIT),'EVAL);
  1408. PUT('SHOWTIME,'STAT,'ENDSTAT);
  1409. %*********************************************************************
  1410. %*********************************************************************
  1411. % MODULAR STATEMENTS
  1412. %*********************************************************************
  1413. %********************************************************************;
  1414. % The remaining statements defined in this section are truly
  1415. %modular, and any may be omitted if desired.
  1416. %*********************************************************************
  1417. % FUNCTIONS FOR INTRODUCING NEW INFIX OPERATORS
  1418. %********************************************************************;
  1419. SYMBOLIC PROCEDURE INFIX X;
  1420. BEGIN SCALAR Y;
  1421. IF !*MODE EQ 'ALGEBRAIC THEN MAPCAR(X,FUNCTION MKOP);
  1422. IF Y := XN(X,PRECLIS!*) THEN LPRIM APPEND(Y,'(REDEFINED));
  1423. PRECLIS!* := APPEND(REVERSE X,SETDIFF(PRECLIS!*,X));
  1424. MKPREC()
  1425. END;
  1426. SYMBOLIC PROCEDURE PRECEDENCE U;
  1427. BEGIN SCALAR X,Y,Z;
  1428. PRECLIS!* := DELETE(CAR U,PRECLIS!*);
  1429. Y := CADR U;
  1430. X := PRECLIS!*;
  1431. A: IF NULL X THEN REDERR LIST (Y,"not found")
  1432. ELSE IF Y EQ CAR X THEN GO TO B;
  1433. Z := CAR X . Z;
  1434. X := CDR X;
  1435. GO TO A;
  1436. B: PRECLIS!* := NCONC(REVERSIP Z,CAR X . (CAR U . CDR X));
  1437. MKPREC()
  1438. END;
  1439. RLISTAT '(INFIX PRECEDENCE);
  1440. FLAG('(INFIX PRECEDENCE),'EVAL);
  1441. %*********************************************************************
  1442. % FOR STATEMENT
  1443. %********************************************************************;
  1444. %REMPROP('FOR,'STAT); %in case rebuilding system on top of itself;
  1445. SYMBOLIC PROCEDURE FORLOOP;
  1446. BEGIN SCALAR ACTION,BODY,INCR,VAR,X;
  1447. X := XREAD1 'FOR;
  1448. IF ATOM X OR NOT CAR X MEMQ '(EQUAL SETQ) THEN SYMERR('FOR,T);
  1449. VAR := CADR X;
  1450. X := CADDR X;
  1451. IF NOT IDP VAR THEN SYMERR('FOR,T);
  1452. % VAR := CAR FLAGTYPE(LIST VAR,'INTEGER);
  1453. IF CURSYM!* EQ 'STEP
  1454. THEN <<INCR := XREAD T;
  1455. IF NOT CURSYM!* EQ 'UNTIL THEN SYMERR('FOR,T)>>
  1456. ELSE IF CURSYM!* EQ '!*COLON!* THEN INCR := 1
  1457. ELSE SYMERR('FOR,T);
  1458. INCR := LIST(X,INCR,XREAD T);
  1459. IF NOT GET(ACTION := CURSYM!*,'BIN) AND NOT ACTION EQ 'DO
  1460. THEN SYMERR('FOR,T);
  1461. BODY := XREAD T;
  1462. % REMTYPE LIST VAR;
  1463. RETURN LIST('FOR,VAR,INCR,ACTION,BODY)
  1464. END;
  1465. SYMBOLIC PROCEDURE FORMFOR(U,VARS,MODE);
  1466. LIST('FOR,CAR U,
  1467. MAPCAR(CADR U,FUNCTION (LAMBDA X; FORMC(X,VARS,MODE))),
  1468. CADDR U,
  1469. FORMC(CADDDR U,
  1470. (CAR U . IF INTEXPRLISP(CADR U,VARS)
  1471. THEN 'INTEGER ELSE MODE) . VARS,MODE));
  1472. PUT('FOR,'FORMFN,'FORMFOR);
  1473. SYMBOLIC PROCEDURE INTEXPRNP(U,VARS);
  1474. %determines if U is an integer expression;
  1475. IF ATOM U THEN IF NUMBERP U THEN FIXP U
  1476. ELSE IF (U := ATSOC(U,VARS)) THEN CDR U EQ 'INTEGER
  1477. ELSE NIL
  1478. ELSE IDP CAR U AND FLAGP(CAR U,'INTFN) AND INTEXPRLISP(CDR U,VARS);
  1479. SYMBOLIC PROCEDURE INTEXPRLISP(U,VARS);
  1480. NULL U OR INTEXPRNP(CAR U,VARS) AND INTEXPRLISP(CDR U,VARS);
  1481. FLAG('(DIFFERENCE EXPT MINUS PLUS TIMES),'INTFN);
  1482. SYMBOLIC MACRO PROCEDURE FOR U;
  1483. BEGIN SCALAR ACTION,ALGP,BODY,EXP,INCR,LAB1,LAB2,RESULT,TAIL,VAR,X;
  1484. %ALGP is used to determine if the loop calculation must be
  1485. %done algebraically or not;
  1486. VAR := CADR U;
  1487. INCR := CADDR U;
  1488. ACTION := CADDDR U;
  1489. BODY := CAR CDDDDR U;
  1490. IF ALGMODEP CAR INCR OR ALGMODEP CADR INCR
  1491. OR ALGMODEP CADDR INCR THEN ALGP := T;
  1492. RESULT := LIST LIST('SETQ,VAR,CAR INCR);
  1493. INCR := CDR INCR;
  1494. X := IF ALGP THEN LIST('LIST,MKQUOTE 'DIFFERENCE,CADR INCR,VAR)
  1495. ELSE LIST('DIFFERENCE,CADR INCR,VAR);
  1496. IF CAR INCR NEQ 1
  1497. THEN X := IF ALGP THEN LIST('LIST,MKQUOTE 'TIMES,CAR INCR,X)
  1498. ELSE LIST('TIMES,CAR INCR,X);
  1499. IF NOT ACTION EQ 'DO
  1500. THEN <<ACTION := GET(ACTION,'BIN);
  1501. EXP := GENSYM();
  1502. BODY := LIST('SETQ,EXP,
  1503. LIST(CAR ACTION,LIST('SIMP,BODY),EXP));
  1504. RESULT := LIST('SETQ,EXP,MKQUOTE CDR ACTION) . RESULT;
  1505. TAIL := LIST LIST('RETURN,LIST('MK!*SQ,EXP));
  1506. EXP := LIST EXP>>;
  1507. LAB1 := GENSYM();
  1508. LAB2 := GENSYM();
  1509. X := IF ALGP THEN LIST('AMINUSP!:,X) ELSE LIST('MINUSP,X);
  1510. RESULT := NCONC(RESULT,
  1511. LAB1 .
  1512. LIST('COND,LIST(X,LIST('GO,LAB2))) .
  1513. BODY .
  1514. LIST('SETQ,VAR,
  1515. IF ALGP
  1516. THEN LIST('AEVAL,
  1517. LIST('LIST,MKQUOTE 'PLUS,VAR,CAR INCR))
  1518. ELSE LIST('PLUS2,VAR,CAR INCR)) .
  1519. LIST('GO,LAB1) .
  1520. LAB2 .
  1521. TAIL);
  1522. RETURN MKPROG(VAR . EXP,RESULT)
  1523. END;
  1524. SYMBOLIC PROCEDURE ALGMODEP U; EQCAR(U,'AEVAL);
  1525. SYMBOLIC PROCEDURE AMINUSP!: U;
  1526. BEGIN SCALAR X;
  1527. U := AEVAL U;
  1528. X := U;
  1529. IF FIXP X THEN RETURN MINUSP X
  1530. ELSE IF NOT EQCAR(X,'!*SQ)
  1531. THEN MSGPRI(NIL,REVAL U,"invalid in FOR statement",NIL,T);
  1532. X := CADR X;
  1533. IF FIXP CAR X AND FIXP CDR X THEN RETURN MINUSP CAR X
  1534. ELSE IF NOT CDR X = 1
  1535. OR NOT DOMAINP (X := CAR X)
  1536. THEN MSGPRI(NIL,REVAL U,"invalid in FOR statement",NIL,T)
  1537. ELSE RETURN APPLY('!:MINUSP,LIST X)
  1538. END;
  1539. FLAG('(FOR),'NOCHANGE);
  1540. SYMBOLIC PROCEDURE FORSTAT;
  1541. IF SCAN() EQ 'ALL THEN FORALLSTAT()
  1542. ELSE IF CURSYM!* EQ 'EACH THEN FOREACHSTAT()
  1543. ELSE FORLOOP();
  1544. PUT('FOR,'STAT,'FORSTAT);
  1545. FLAG ('(STEP DO UNTIL),'DELIM);
  1546. %*********************************************************************
  1547. % FOR EACH STATEMENT
  1548. %********************************************************************;
  1549. SYMBOLIC PROCEDURE FORMFOREACH(U,VARS,MODE);
  1550. LIST('FOREACH,CAR U,CADR U,FORMC(CADDR U,VARS,MODE),CADDDR U,
  1551. FORMC(CAR CDDDDR U,(CAR U . MODE) . VARS,MODE));
  1552. PUT('FOREACH,'FORMFN,'FORMFOREACH);
  1553. SYMBOLIC PROCEDURE FOREACHSTAT;
  1554. BEGIN SCALAR W,X,Y,Z;
  1555. X := SCAN();
  1556. Y := SCAN();
  1557. IF NOT Y MEMQ '(IN ON) THEN SYMERR("FOR EACH",T);
  1558. IF FLAGP('CONC,'DELIM) THEN W := T
  1559. ELSE FLAG('(COLLECT CONC),'DELIM);
  1560. Z := XREAD T;
  1561. IF NULL W THEN REMFLAG('(COLLECT CONC),'DELIM);
  1562. W := CURSYM!*;
  1563. IF NOT W MEMQ '(DO COLLECT CONC)
  1564. THEN SYMERR("FOR EACH",T);
  1565. RETURN LIST('FOREACH,X,Y,Z,W,XREAD T)
  1566. END;
  1567. PUT('FOREACH,'STAT,'FOREACHSTAT);
  1568. SYMBOLIC MACRO PROCEDURE FOREACH U;
  1569. BEGIN SCALAR ACTION,BODY,FN,LST,MOD,VAR;
  1570. VAR := CADR U; U := CDDR U;
  1571. MOD := CAR U; U := CDR U;
  1572. LST := CAR U; U := CDR U;
  1573. ACTION := CAR U; U := CDR U;
  1574. BODY := CAR U;
  1575. FN := IF ACTION EQ 'DO THEN IF MOD EQ 'IN THEN 'MAPC ELSE 'MAP
  1576. ELSE IF ACTION EQ 'CONC
  1577. THEN IF MOD EQ 'IN THEN 'MAPCAN ELSE 'MAPCON
  1578. ELSE IF ACTION EQ 'COLLECT
  1579. THEN IF MOD EQ 'IN THEN 'MAPCAR ELSE 'MAPLIST
  1580. ELSE REDERR LIST(ACTION,"invalid in FOREACH statement");
  1581. RETURN LIST(FN,LST,LIST('FUNCTION,LIST('LAMBDA,LIST VAR,BODY)))
  1582. END;
  1583. %*********************************************************************
  1584. % REPEAT STATEMENT
  1585. %********************************************************************;
  1586. SYMBOLIC PROCEDURE FORMREPEAT(U,VARS,MODE);
  1587. LIST('REPEAT,FORMC(CAR U,VARS,MODE),FORMBOOL(CADR U,VARS,MODE));
  1588. PUT('REPEAT,'FORMFN,'FORMREPEAT);
  1589. SYMBOLIC PROCEDURE REPEATSTAT;
  1590. BEGIN SCALAR BODY;
  1591. BODY:= XREAD T;
  1592. IF NOT CURSYM!* EQ 'UNTIL THEN SYMERR('REPEAT,T);
  1593. RETURN LIST('REPEAT,BODY,XREAD T);
  1594. END;
  1595. PUT('REPEAT,'STAT,'REPEATSTAT);
  1596. MACRO PROCEDURE REPEAT U;
  1597. BEGIN SCALAR BODY,BOOL,LAB;
  1598. BODY := CADR U; BOOL := CADDR U;
  1599. LAB := GENSYM();
  1600. RETURN MKPROG(NIL,LIST(LAB,BODY,
  1601. LIST('COND,LIST(LIST('NOT,BOOL),LIST('GO,LAB)))))
  1602. END;
  1603. FLAG('(REPEAT),'NOCHANGE);
  1604. %*********************************************************************
  1605. % WHILE STATEMENT
  1606. %********************************************************************;
  1607. SYMBOLIC PROCEDURE FORMWHILE(U,VARS,MODE);
  1608. LIST('WHILE,FORMBOOL(CAR U,VARS,MODE),FORMC(CADR U,VARS,MODE));
  1609. PUT('WHILE,'FORMFN,'FORMWHILE);
  1610. SYMBOLIC PROCEDURE WHILSTAT;
  1611. BEGIN SCALAR BOOL;
  1612. BOOL := XREAD T;
  1613. IF NOT CURSYM!* EQ 'DO THEN SYMERR('WHILE,T);
  1614. RETURN LIST('WHILE,BOOL,XREAD T)
  1615. END;
  1616. PUT('WHILE,'STAT,'WHILSTAT);
  1617. MACRO PROCEDURE WHILE U;
  1618. BEGIN SCALAR BODY,BOOL,LAB;
  1619. BOOL := CADR U; BODY := CADDR U;
  1620. LAB := GENSYM();
  1621. RETURN MKPROG(NIL,LIST(LAB,LIST('COND,LIST(LIST('NOT,BOOL),
  1622. LIST('RETURN,NIL))),BODY,LIST('GO,LAB)))
  1623. END;
  1624. FLAG('(WHILE),'NOCHANGE);
  1625. %*********************************************************************
  1626. % ARRAY STATEMENT
  1627. %********************************************************************;
  1628. SYMBOLIC PROCEDURE GETEL U;
  1629. %returns the value of the array element U;
  1630. GETEL1(GET(CAR U,'ARRAY),CDR U);
  1631. SYMBOLIC PROCEDURE GETEL1(U,V);
  1632. IF NULL V THEN U ELSE GETEL1(GETV(U,CAR V),CDR V);
  1633. SYMBOLIC PROCEDURE SETEL(U,V);
  1634. %Sets array element U to V and returns V;
  1635. SETEL1(GET(CAR U,'ARRAY),CDR U,V);
  1636. SYMBOLIC PROCEDURE SETEL1(U,V,W);
  1637. IF NULL CDR V THEN PUTV(U,CAR V,W)
  1638. ELSE SETEL1(GETV(U,CAR V),CDR V,W);
  1639. SYMBOLIC PROCEDURE DIMENSION U;
  1640. GET(U,'DIMENSION);
  1641. COMMENT further support for REDUCE arrays;
  1642. SYMBOLIC PROCEDURE TYPECHK(U,V);
  1643. BEGIN SCALAR X;
  1644. IF (X := GETTYPE U) EQ V OR X EQ 'PARAMETER
  1645. THEN LPRIM LIST(V,U,"REDEFINED")
  1646. ELSE IF X THEN TYPERR(LIST(X,U),V)
  1647. END;
  1648. SYMBOLIC PROCEDURE ARRAYFN(U,V);
  1649. %U is the defining mode, V a list of lists, assumed syntactically
  1650. %correct.
  1651. %ARRAYFN declares each element as an array unless a semantic
  1652. %mismatch occurs;
  1653. BEGIN SCALAR Y;
  1654. FOR EACH X IN V DO
  1655. <<TYPECHK(CAR X,'ARRAY);
  1656. Y := ADD1LIS FOR EACH Z IN CDR X COLLECT EVAL Z;
  1657. IF ERFG!* THEN RETURN NIL;
  1658. PUT(CAR X,'ARRAY,MKARRAY Y);
  1659. PUT(CAR X,'DIMENSION,Y)>>
  1660. END;
  1661. SYMBOLIC PROCEDURE ADD1LIS U;
  1662. IF NULL U THEN NIL ELSE (CAR U+1) . ADD1LIS CDR U;
  1663. SYMBOLIC PROCEDURE MKARRAY U;
  1664. %U is a list of positive integers representing array bounds.
  1665. %Value is an array structure;
  1666. IF NULL U THEN NIL
  1667. ELSE BEGIN INTEGER N; SCALAR X;
  1668. N := CAR U-1;
  1669. X := MKVECT N;
  1670. FOR I:=0:N DO PUTV(X,I,MKARRAY CDR U);
  1671. RETURN X
  1672. END;
  1673. RLISTAT '(ARRAY);
  1674. FLAG ('(ARRAY),'EVAL);
  1675. SYMBOLIC PROCEDURE FORMARRAY(U,VARS,MODE);
  1676. BEGIN SCALAR X;
  1677. X := U;
  1678. WHILE X DO <<IF ATOM X THEN TYPERR(X,"Array List")
  1679. ELSE IF ATOM CAR X OR NOT IDP CAAR X
  1680. OR NOT LISTP CDAR X
  1681. THEN TYPERR(CAR X,"Array");
  1682. X := CDR X>>;
  1683. U := FOR EACH Z IN U COLLECT INTARGFN(Z,VARS);
  1684. %ARRAY arguments must be returned as quoted structures;
  1685. RETURN LIST('ARRAYFN,MKQUOTE MODE,'LIST . U)
  1686. END;
  1687. SYMBOLIC PROCEDURE LISTP U;
  1688. %returns T if U is a top level list;
  1689. NULL U OR NOT ATOM U AND LISTP CDR U;
  1690. PUT('ARRAY,'FORMFN,'FORMARRAY);
  1691. %*********************************************************************
  1692. % ON/OFF STATEMENTS
  1693. %********************************************************************;
  1694. SYMBOLIC PROCEDURE ON U; ONOFF(U,T);
  1695. SYMBOLIC PROCEDURE OFF U; ONOFF(U,NIL);
  1696. SYMBOLIC PROCEDURE ONOFF(U,BOOL);
  1697. BEGIN SCALAR X;
  1698. FOR EACH J IN U DO
  1699. IF NOT IDP J THEN TYPERR(J,"ON/OFF argument")
  1700. ELSE <<SET(INTERN COMPRESS APPEND(EXPLODE '!*,EXPLODE J),BOOL);
  1701. IF X := ATSOC(BOOL,GET(J,'SIMPFG))
  1702. THEN EVAL MKPROG(NIL,CDR X)>>
  1703. END;
  1704. RLISTAT '(OFF ON);
  1705. %*********************************************************************
  1706. % DEFINE STATEMENT
  1707. %********************************************************************;
  1708. SYMBOLIC PROCEDURE DEFSTAT;
  1709. BEGIN SCALAR X,Y,Z;
  1710. A: X := SCAN();
  1711. B: IF FLAGP!*!*(X,'DELIM) THEN RETURN MKPROG(NIL,Z)
  1712. ELSE IF X EQ '!*COMMA!* THEN GO TO A
  1713. ELSE IF NOT IDP X THEN GO TO ER;
  1714. Y := SCAN();
  1715. IF NOT Y EQ 'EQUAL THEN GO TO ER;
  1716. Z := ACONC(Z,LIST('PUT,MKQUOTE X,MKQUOTE 'NEWNAM,
  1717. MKQUOTE XREAD T));
  1718. X := CURSYM!*;
  1719. GO TO B;
  1720. ER: SYMERR('DEFINE,T)
  1721. END;
  1722. PUT('DEFINE,'STAT,'DEFSTAT);
  1723. FLAG('(DEFINE),'EVAL);
  1724. %*********************************************************************
  1725. % WRITE STATEMENT
  1726. %********************************************************************;
  1727. RLISTAT '(WRITE);
  1728. SYMBOLIC PROCEDURE FORMWRITE(U,VARS,MODE);
  1729. BEGIN SCALAR BOOL1,BOOL2,X,Y,Z;
  1730. BOOL1 := MODE EQ 'SYMBOLIC;
  1731. WHILE U DO
  1732. <<X := FORMC(CAR U,VARS,MODE);
  1733. Z := (IF BOOL1 THEN LIST('PRIN2,X)
  1734. ELSE LIST('VARPRI,X,MKARG(SETVARS X,VARS),
  1735. IF NOT CDR U THEN IF NOT BOOL2 THEN MKQUOTE 'ONLY ELSE T
  1736. ELSE IF NOT BOOL2 THEN MKQUOTE 'FIRST ELSE NIL)) .
  1737. Z;
  1738. BOOL2 := T;
  1739. U := CDR U>>;
  1740. RETURN MKPROG(NIL,REVERSIP Z)
  1741. END;
  1742. PUT('WRITE,'FORMFN,'FORMWRITE);
  1743. %*********************************************************************
  1744. %*********************************************************************
  1745. % REDUCE FUNCTIONS FOR HANDLING INPUT AND OUTPUT OF FILES
  1746. %*********************************************************************
  1747. %********************************************************************;
  1748. GLOBAL '(CONTL!*);
  1749. SYMBOLIC PROCEDURE IN U;
  1750. BEGIN SCALAR CHAN,ECHO,ECHOP,TYPE;
  1751. ECHOP := SEMIC!* EQ '!;; %record echo character from input;
  1752. ECHO := !*ECHO; %save current echo status;
  1753. IF NULL IFL!* THEN TECHO!* := !*ECHO; %terminal echo status;
  1754. FOR EACH FL IN U DO
  1755. <<IF FL EQ 'T THEN FL := NIL;
  1756. IF NULL FL THEN <<!*ECHO := TECHO!*; IFL!* := NIL>>
  1757. ELSE <<CHAN := OPEN(FL := MKFIL FL,'INPUT);
  1758. IFL!* := FL . CHAN>>;
  1759. IPL!* := IFL!* . IPL!*; %add to input file stack;
  1760. RDS (IF IFL!* THEN CDR IFL!* ELSE NIL);
  1761. !*ECHO := ECHOP;
  1762. TYPE := FILETYPE FL;
  1763. IF TYPE AND (TYPE := GET(TYPE,'ACTION)) THEN EVAL LIST TYPE
  1764. ELSE BEGIN1();
  1765. IF CHAN THEN CLOSE CHAN;
  1766. IF FL EQ CAAR IPL!* THEN IPL!* := CDR IPL!*
  1767. ELSE ERRACH LIST("FILE STACK CONFUSION",FL,IPL!*)>>;
  1768. !*ECHO := ECHO; %restore echo status;
  1769. IF IPL!* AND NULL CONTL!* THEN IFL!* := CAR IPL!*
  1770. ELSE IFL!* := NIL;
  1771. RDS(IF IFL!* THEN CDR IFL!* ELSE NIL)
  1772. END;
  1773. SYMBOLIC PROCEDURE OUT U;
  1774. %U is a list of one file;
  1775. BEGIN INTEGER N; SCALAR CHAN,FL,X;
  1776. N := LINELENGTH NIL;
  1777. IF NULL U THEN RETURN NIL
  1778. ELSE IF CAR U EQ 'T THEN RETURN <<WRS(OFL!* := NIL); NIL>>;
  1779. FL := MKFIL CAR U;
  1780. IF NOT (X := ASSOC(FL,OPL!*))
  1781. THEN <<CHAN := OPEN(FL,'OUTPUT);
  1782. OFL!* := FL . CHAN;
  1783. OPL!* := OFL!* . OPL!*>>
  1784. ELSE OFL!* := X;
  1785. WRS CDR OFL!*;
  1786. LINELENGTH N
  1787. END;
  1788. SYMBOLIC PROCEDURE SHUT U;
  1789. %U is a list of names of files to be shut;
  1790. BEGIN SCALAR FL1;
  1791. FOR EACH FL IN U DO
  1792. <<IF FL1 := ASSOC((FL := MKFIL FL),OPL!*)
  1793. THEN <<OPL!* := DELETE(FL1,OPL!*);
  1794. IF FL1=OFL!* THEN <<OFL!* := NIL; WRS NIL>>;
  1795. CLOSE CDR FL1>>
  1796. ELSE IF NOT (FL1 := ASSOC(FL,IPL!*))
  1797. THEN REDERR LIST(FL,"not open")
  1798. ELSE IF FL1 NEQ IFL!*
  1799. THEN <<CLOSE CDR FL1; IPL!* := DELETE(FL1,IPL!*)>>
  1800. ELSE REDERR LIST("Cannot shut current input file",CAR FL1)>>
  1801. END;
  1802. DEFLIST ('((IN RLIS) (OUT RLIS) (SHUT RLIS)),'STAT);
  1803. %*********************************************************************
  1804. % FUNCTIONS HANDLING INTERACTIVE FEATURES
  1805. %********************************************************************;
  1806. %GLOBAL Variables referenced in this Section;
  1807. GLOBAL '(FLG!* CLOC!* EDIT!*);
  1808. CONTL!* := NIL;
  1809. SYMBOLIC PROCEDURE PAUSE;
  1810. %Must appear at the top-most level;
  1811. IF KEY!* EQ 'PAUSE THEN PAUSE1 NIL
  1812. ELSE %TYPERR('PAUSE,"lower level command");
  1813. PAUSE1 NIL; %Allow at lower level for now;
  1814. SYMBOLIC PROCEDURE PAUSE1 BOOL;
  1815. BEGIN
  1816. IF BOOL THEN
  1817. % IF NULL IFL!*
  1818. % THEN RETURN NIL ELSE;
  1819. IF GETD 'EDIT1 AND ERFG!* AND CLOC!* AND YESP "Edit?"
  1820. THEN RETURN <<CONTL!* := NIL;
  1821. IF OFL!* THEN <<LPRIM LIST(CAR OFL!*,'SHUT);
  1822. CLOSE CDR OFL!*;
  1823. OPL!* := DELETE(OFL!*,OPL!*);
  1824. OFL!* := NIL>>;
  1825. EDIT1(CLOC!*,NIL)>>
  1826. ELSE IF FLG!* THEN RETURN (EDIT!* := NIL);
  1827. IF NULL IFL!* OR YESP "Cont?" THEN RETURN NIL;
  1828. CONTL!* := IFL!* . !*ECHO . CONTL!*;
  1829. RDS (IFL!* := NIL);
  1830. !*ECHO := TECHO!*
  1831. END;
  1832. SYMBOLIC PROCEDURE YESP U;
  1833. BEGIN SCALAR BOOL,IFL,OFL,X,Y,Z;
  1834. IF IFL!* THEN <<IFL:= IFL!*; RDS NIL>>;
  1835. IF OFL!* THEN <<OFL:= OFL!*; WRS NIL>>;
  1836. TERPRI();
  1837. IF ATOM U THEN PRIN2 U ELSE LPRI U;
  1838. PRIN2T " (Y or N)";
  1839. TERPRI();
  1840. Z := SETPCHAR '!?;
  1841. A: X := READ();
  1842. IF (Y := (X EQ 'Y)) OR X EQ 'N THEN GO TO B;
  1843. IF NULL BOOL THEN PRIN2T "TYPE Y OR N";
  1844. BOOL := T;
  1845. GO TO A;
  1846. B: SETPCHAR Z;
  1847. IF OFL THEN WRS CDR OFL;
  1848. IF IFL THEN RDS CDR IFL;
  1849. CURSYM!* := '!*SEMICOL!*;
  1850. RETURN Y
  1851. END;
  1852. SYMBOLIC PROCEDURE CONT;
  1853. BEGIN SCALAR FL,TECHO;
  1854. IF IFL!* THEN RETURN NIL %CONT only active from terminal;
  1855. ELSE IF NULL CONTL!* THEN REDERR "No file open";
  1856. FL := CAR CONTL!*;
  1857. TECHO := CADR CONTL!*;
  1858. CONTL!* := CDDR CONTL!*;
  1859. IF FL=CAR IPL!* THEN <<IFL!* := FL;
  1860. RDS IF FL THEN CDR FL ELSE NIL;
  1861. !*ECHO := TECHO>>
  1862. ELSE <<EOF!* :=T; LPRIM LIST(FL,"not open"); ERROR1()>>
  1863. END;
  1864. DEFLIST ('((PAUSE ENDSTAT) (CONT ENDSTAT) (RETRY ENDSTAT)),'STAT);
  1865. PUT('RETRY,'STAT,'ENDSTAT);
  1866. FLAG ('(CONT),'IGNORE);
  1867. END;