forstat.red 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. module forstat; % Definition of REDUCE FOR loops.
  2. % Author: Anthony C. Hearn.
  3. % Copyright (c) 1993 The RAND Corporation. All rights reserved.
  4. fluid '(!*blockp !*fastfor);
  5. global '(cursym!* foractions!*);
  6. Comment the syntax of the FOR statement is as follows:
  7. {step i3 until}
  8. {i := i1 { } i2 }
  9. { { : } }
  10. for { } <action> <expr>
  11. { { in } }
  12. { each i { } <list> }
  13. { on }
  14. In all cases, the <expr> is evaluated algebraically within the scope of
  15. the current value of i. If <action> is DO, then nothing else happens.
  16. In other cases, <action> is a binary operator that causes a result to be
  17. built up and returned by FOR. In each case, the loop is initialized to
  18. a default value. The test for the end condition is made before any
  19. action is taken.
  20. The effect of the definition here is to replace all for loops by
  21. semantically equivalent blocks. As a result, none of the mapping
  22. functions are needed in REDUCE.
  23. To declare a set of actions, one says;
  24. foractions!* := '(do collect conc product sum);
  25. remflag(foractions!*,'delim); % For bootstrapping purposes.
  26. % To associate a binary function with an action, one says:
  27. deflist('((product times) (sum plus)),'bin);
  28. % And to give these an initial value in a loop:
  29. deflist('((product 1) (sum 0)),'initval);
  30. % NB: We need to reset for and let delims if an error occurs. It's
  31. % probably best to do this in the begin1 loop.
  32. % flag('(for),'nochange);
  33. symbolic procedure forstat;
  34. begin scalar !*blockp;
  35. return if scan() eq 'all then forallstat()
  36. else if cursym!* eq 'each then foreachstat()
  37. else forloop()
  38. end;
  39. put('for,'stat,'forstat);
  40. symbolic procedure forloop;
  41. begin scalar action,bool,incr,var,x;
  42. if flagp('step,'delim) then bool := t else flag('(step),'delim);
  43. x := errorset!*('(xread1 'for),t);
  44. if null bool then remflag('(step),'delim) else bool := nil;
  45. if errorp x then error1() else x := car x;
  46. if not eqcar(x,'setq) or not idp(var := cadr x)
  47. then symerr('for,t);
  48. x := caddr x;
  49. if cursym!* eq 'step
  50. then <<if flagp('until,'delim) then bool := t
  51. else flag('(until),'delim);
  52. incr := xread t;
  53. if null bool then remflag('(until),'delim)
  54. else bool := nil;
  55. if not(cursym!* eq 'until) then symerr('for,t)>>
  56. else if cursym!* eq '!*colon!* then incr := 1
  57. else symerr('for,t);
  58. if flagp(car foractions!*,'delim) then bool := t % nested loop
  59. else flag(foractions!*,'delim);
  60. incr := list(x,incr,xread t);
  61. if null bool then remflag(foractions!*,'delim);
  62. if not((action := cursym!*) memq foractions!*)
  63. then symerr('for,t);
  64. return list('for,var,incr,action,xread t)
  65. end;
  66. symbolic procedure formfor(u,vars,mode);
  67. begin scalar action,algp,body,endval,incr,initval,var,x;
  68. scalar !*!*a2sfn;
  69. % ALGP is used to determine if the loop calculation must be
  70. % done algebraically or not.
  71. !*!*a2sfn := 'aeval!*;
  72. var := cadr u;
  73. incr := caddr u;
  74. incr := list(formc(car incr,vars,mode),
  75. formc(cadr incr,vars,mode),
  76. formc(caddr incr,vars,mode));
  77. if not atsoc(var,vars)
  78. then if intexprnp(car incr,vars) and intexprnp(cadr incr,vars)
  79. then vars := (var . 'integer) . vars
  80. else vars := (var . mode) . vars;
  81. action := cadddr u;
  82. body := formc(car cddddr u,vars,mode);
  83. initval := car incr;
  84. endval := caddr incr;
  85. incr := cadr incr;
  86. algp := algmodep initval or algmodep incr or algmodep endval;
  87. if algp then <<endval := unreval endval; incr := unreval incr>>;
  88. x := if algp then list('list,''difference,endval,var)
  89. else list(if !*fastfor then 'idifference else 'difference,
  90. endval,var);
  91. if incr neq 1
  92. then x := if algp then list('list,''times,incr,x)
  93. else list('times,incr,x);
  94. % We could consider simplifying X here (via reval).
  95. x := if algp then list('aminusp!:,x)
  96. else list(if !*fastfor then 'iminusp else 'minusp,x);
  97. return forformat(action,body,initval,x,
  98. if algp
  99. then list('aeval!*,list('list,''plus,incr))
  100. else list(if !*fastfor then 'iplus2 else 'plus2,
  101. incr),
  102. var,vars,mode)
  103. end;
  104. put('for,'formfn,'formfor);
  105. symbolic procedure algmodep u;
  106. not atom u and car u memq '(aeval aeval!*);
  107. symbolic procedure aminusp!: u;
  108. begin scalar x;
  109. u := aeval!* u;
  110. x := u;
  111. if fixp x then return minusp x
  112. else if not eqcar(x,'!*sq)
  113. then msgpri(nil,reval u,"invalid in FOR statement",nil,t);
  114. x := cadr x;
  115. if fixp car x and fixp cdr x then return minusp car x
  116. else if not(cdr x = 1)
  117. or not (atom(x := car x) or atom car x)
  118. % Should be DOMAINP, but SMACROs not yet defined.
  119. then msgpri(nil,reval u,"invalid in FOR statement",nil,t)
  120. else return apply1('!:minusp,x)
  121. end;
  122. symbolic procedure foreachstat;
  123. begin scalar w,x,y,z;
  124. if not idp(x := scan()) or not((y := scan()) memq '(in on))
  125. then symerr("FOR EACH",t)
  126. else if flagp(car foractions!*,'delim) then w := t
  127. else flag(foractions!*,'delim);
  128. z := xread t;
  129. if null w then remflag(foractions!*,'delim);
  130. w := cursym!*;
  131. if not(w memq foractions!*) then symerr("FOR EACH",t);
  132. return list('foreach,x,y,z,w,xread t)
  133. end;
  134. put('foreach,'stat,'foreachstat);
  135. symbolic procedure formforeach(u,vars,mode);
  136. begin scalar action,body,lst,mod1,var;
  137. var := cadr u; u := cddr u;
  138. mod1 := car u; u := cdr u;
  139. lst := formc(car u,vars,mode); u := cdr u;
  140. if not(mode eq 'symbolic) then lst := list('getrlist,lst);
  141. action := car u; u := cdr u;
  142. body := formc(car u,(var . mode) . vars,mode); % was FORMC
  143. if mod1 eq 'in
  144. then body := list(list('lambda,list var,body),list('car,var))
  145. else if not(mode eq 'symbolic) then typerr(mod1,'action);
  146. return forformat(action,body,lst,
  147. list('null,var),list 'cdr,var,vars,mode)
  148. end;
  149. put('foreach,'formfn,'formforeach);
  150. symbolic procedure forformat(action,body,initval,
  151. testexp,updform,var,vars,mode);
  152. begin scalar result;
  153. % Next test is to correct structure generated by formfor.
  154. if algmodep updform and length cadr updform > 2
  155. then <<result:=gensym();
  156. updform:= list list('lambda,
  157. list result,
  158. list('aeval!*,
  159. caadr updform .
  160. cadadr updform .
  161. result .
  162. cddadr updform))>>;
  163. result := gensym();
  164. return
  165. sublis(list('body2 .
  166. if mode eq 'symbolic or intexprnp(body,vars)
  167. then list(get(action,'bin),body,result)
  168. else list('aeval!*,list('list,mkquote get(action,'bin),
  169. unreval body,result)),
  170. 'body3 .
  171. if mode eq 'symbolic then body
  172. else list('getrlist,body),
  173. 'body . body,
  174. 'initval . initval,
  175. 'nillist .
  176. if mode eq 'symbolic then nil else '(makelist nil),
  177. 'result . result,
  178. 'initresult . get(action,'initval),
  179. 'resultlist . if mode eq 'symbolic then result
  180. else list('cons,''list,result),
  181. 'testexp . testexp,
  182. 'updfn . car updform,
  183. 'updval . cdr updform,
  184. 'var . var),
  185. if action eq 'do
  186. then '(prog (var)
  187. (setq var initval)
  188. lab (cond (testexp (return nil)))
  189. body
  190. (setq var (updfn var . updval))
  191. (go lab))
  192. else if action eq 'collect
  193. then '(prog (var result endptr)
  194. (setq var initval)
  195. (cond (testexp (return nillist)))
  196. (setq result (setq endptr (cons body nil)))
  197. looplabel
  198. (setq var (updfn var . updval))
  199. (cond (testexp (return resultlist)))
  200. (rplacd endptr (cons body nil))
  201. (setq endptr (cdr endptr))
  202. (go looplabel))
  203. else if action eq 'conc
  204. then '(prog (var result endptr)
  205. (setq var initval)
  206. startover
  207. (cond (testexp (return nillist)))
  208. (setq result body)
  209. (setq endptr (lastpair resultlist))
  210. (setq var (updfn var . updval))
  211. (cond ((atom endptr) (go startover)))
  212. looplabel
  213. (cond (testexp (return result)))
  214. (rplacd endptr body3)
  215. (setq endptr (lastpair endptr))
  216. (setq var (updfn var . updval))
  217. (go looplabel))
  218. else '(prog (var result)
  219. (setq var initval)
  220. (setq result initresult)
  221. lab1
  222. (cond (testexp (return result)))
  223. (setq result body2)
  224. (setq var (updfn var . updval))
  225. (go lab1)))
  226. end;
  227. symbolic procedure lastpair u;
  228. % Return the last pair of the list u.
  229. if atom u or atom cdr u then u else lastpair cdr u;
  230. symbolic procedure unreval u;
  231. % Remove spurious aeval or reval in inner expression.
  232. if atom u or null(car u memq '(aeval reval)) then u else cadr u;
  233. remprop('conc,'newnam);
  234. put('join,'newnam,'conc); % alternative for CONC
  235. endmodule;
  236. end;