Artifact f13818d24e630facfdf851eca5246bb7e364e89e6aae7c908e96cd40352573d9:
- Executable file
r38/packages/rlisp/forstat.red
— part of check-in
[f2fda60abd]
at
2011-09-02 18:13:33
on branch master
— Some historical releases purely for archival purposes
git-svn-id: https://svn.code.sf.net/p/reduce-algebra/code/trunk/historical@1375 2bfe0521-f11c-4a00-b80e-6202646ff360 (user: arthurcnorman@users.sourceforge.net, size: 9698) [annotate] [blame] [check-ins using] [more...]
module forstat; % Definition of REDUCE FOR loops. % Author: Anthony C. Hearn. % Copyright (c) 1993 The RAND Corporation. All rights reserved. fluid '(!*blockp !*fastfor !*modular); global '(cursym!* foractions!*); Comment the syntax of the FOR statement is as follows: {step i3 until} {i := i1 { } i2 } { { : } } for { } <action> <expr> { { in } } { each i { } <list> } { on } In all cases, the <expr> is evaluated algebraically within the scope of the current value of i. If <action> is DO, then nothing else happens. In other cases, <action> is a binary operator that causes a result to be built up and returned by FOR. In each case, the loop is initialized to a default value. The test for the end condition is made before any action is taken. The effect of the definition here is to replace all for loops by semantically equivalent blocks. As a result, none of the mapping functions are needed in REDUCE. To declare a set of actions, one says; foractions!* := '(do collect conc product sum); remflag(foractions!*,'delim); % For bootstrapping purposes. % To associate a binary function with an action, one says: deflist('((product times) (sum plus)),'bin); % And to give these an initial value in a loop: deflist('((product 1) (sum 0)),'initval); % NB: We need to reset for and let delims if an error occurs. It's % probably best to do this in the begin1 loop. % flag('(for),'nochange); symbolic procedure forstat; begin scalar !*blockp; return if scan() eq 'all then forallstat() else if cursym!* eq 'each then foreachstat() else forloop() end; put('for,'stat,'forstat); symbolic procedure forloop; begin scalar action,bool,incr,var,x; if flagp('step,'delim) then bool := t else flag('(step),'delim); x := errorset!*('(xread1 'for),t); if null bool then remflag('(step),'delim) else bool := nil; if errorp x then error1() else x := car x; if not eqcar(x,'setq) or not idp(var := cadr x) then symerr('for,t); x := caddr x; if cursym!* eq 'step then <<if flagp('until,'delim) then bool := t else flag('(until),'delim); incr := xread t; if null bool then remflag('(until),'delim) else bool := nil; if not(cursym!* eq 'until) then symerr('for,t)>> else if cursym!* eq '!*colon!* then incr := 1 else symerr('for,t); if flagp(car foractions!*,'delim) then bool := t % nested loop else flag(foractions!*,'delim); incr := list(x,incr,xread t); if null bool then remflag(foractions!*,'delim); if not((action := cursym!*) memq foractions!*) then symerr('for,t); return list('for,var,incr,action,xread t) end; symbolic procedure formfor(u,vars,mode); begin scalar action,algp,body,endval,incr,initval,var,x; scalar !*!*a2sfn; % ALGP is used to determine if the loop calculation must be % done algebraically or not. !*!*a2sfn := 'aeval!*; var := cadr u; incr := caddr u; incr := list(formc(car incr,vars,mode), formc(cadr incr,vars,mode), formc(caddr incr,vars,mode)); if not atsoc(var,vars) then if intexprnp(car incr,vars) and intexprnp(cadr incr,vars) then vars := (var . 'integer) . vars else vars := (var . mode) . vars; action := cadddr u; body := formc(car cddddr u,vars,mode); initval := car incr; endval := caddr incr; incr := cadr incr; algp := algmodep initval or algmodep incr or algmodep endval; if algp then <<endval := unreval endval; incr := unreval incr>>; x := if algp then list('list,''difference,endval,var) else list(if !*fastfor then 'idifference else 'difference, endval,var); if incr neq 1 then x := if algp then list('list,''times,incr,x) else list('times,incr,x); % We could consider simplifying X here (via reval). x := if algp then list('aminusp!:,x) else list(if !*fastfor then 'iminusp else 'minusp,x); return forformat(action,body,initval,x, if algp then list('aeval!*,list('list,''plus,incr)) else list(if !*fastfor then 'iplus2 else 'plus2, incr), var,vars,mode) end; put('for,'formfn,'formfor); symbolic procedure algmodep u; not atom u and car u memq '(aeval aeval!*); symbolic procedure aminusp!: u; % This is only used in loop tests. We must make sure we are not in a % modular domain (where the difference will always be positive!). begin scalar oldmode,v; if !*modular then oldmode := setdmode('modular,nil); v := errorset2 list('aminusp!:1,mkquote u); if oldmode then setdmode('modular,t); if errorp v then typerr(u,"arithmetic expression") else return car v end; symbolic procedure aminusp!:1 u; begin scalar x; u := aeval!* u; x := u; if fixp x then return minusp x else if not eqcar(x,'!*sq) then msgpri(nil,reval u,"invalid in FOR statement",nil,t); x := cadr x; if fixp car x and fixp cdr x then return minusp car x else if not(cdr x = 1) or not (atom(x := car x) or atom car x) % Should be DOMAINP, but SMACROs not yet defined. then msgpri(nil,reval u,"invalid in FOR statement",nil,t) else return apply1('!:minusp,x) end; symbolic procedure foreachstat; begin scalar w,x,y,z; if not idp(x := scan()) or not((y := scan()) memq '(in on)) then symerr("FOR EACH",t) else if flagp(car foractions!*,'delim) then w := t else flag(foractions!*,'delim); z := xread t; if null w then remflag(foractions!*,'delim); w := cursym!*; if not(w memq foractions!*) then symerr("FOR EACH",t); return list('foreach,x,y,z,w,xread t) end; put('foreach,'stat,'foreachstat); symbolic procedure formforeach(u,vars,mode); begin scalar action,body,lst,mod1,var; var := cadr u; u := cddr u; mod1 := car u; u := cdr u; lst := formc(car u,vars,mode); u := cdr u; if not(mode eq 'symbolic) then lst := list('getrlist,lst); action := car u; u := cdr u; body := formc(car u,(var . mode) . vars,mode); % was FORMC if mod1 eq 'in then body := list(list('lambda,list var,body),list('car,var)) else if not(mode eq 'symbolic) then typerr(mod1,'action); return forformat(action,body,lst, list('null,var),list 'cdr,var,vars,mode) end; put('foreach,'formfn,'formforeach); symbolic procedure forformat(action,body,initval, testexp,updform,var,vars,mode); begin scalar result; % Next test is to correct structure generated by formfor. if algmodep updform and length cadr updform > 2 then <<result:=gensym(); updform:= list list('lambda, list result, list('aeval!*, caadr updform . cadadr updform . result . cddadr updform))>>; result := gensym(); return sublis(list('body2 . if mode eq 'symbolic or intexprnp(body,vars) then list(get(action,'bin),body,result) else list('aeval!*,list('list,mkquote get(action,'bin), unreval body,result)), 'body3 . if mode eq 'symbolic then body else list('getrlist,body), 'body . body, 'initval . initval, 'nillist . if mode eq 'symbolic then nil else '(makelist nil), 'result . result, 'initresult . get(action,'initval), 'resultlist . if mode eq 'symbolic then result else list('cons,''list,result), 'testexp . testexp, 'updfn . car updform, 'updval . cdr updform, 'var . var), if action eq 'do then '(prog (var) (setq var initval) lab (cond (testexp (return nil))) body (setq var (updfn var . updval)) (go lab)) else if action eq 'collect then '(prog (var result endptr) (setq var initval) (cond (testexp (return nillist))) (setq result (setq endptr (cons body nil))) looplabel (setq var (updfn var . updval)) (cond (testexp (return resultlist))) (rplacd endptr (cons body nil)) (setq endptr (cdr endptr)) (go looplabel)) else if action eq 'conc then '(prog (var result endptr) (setq var initval) startover (cond (testexp (return nillist))) (setq result body) (setq endptr (lastpair resultlist)) (setq var (updfn var . updval)) (cond ((atom endptr) (go startover))) looplabel (cond (testexp (return result))) (rplacd endptr body3) (setq endptr (lastpair endptr)) (setq var (updfn var . updval)) (go looplabel)) else '(prog (var result) (setq var initval) (setq result initresult) lab1 (cond (testexp (return result))) (setq result body2) (setq var (updfn var . updval)) (go lab1))) end; symbolic procedure lastpair u; % Return the last pair of the list u. if atom u or atom cdr u then u else lastpair cdr u; symbolic procedure unreval u; % Remove spurious aeval or reval in inner expression. if atom u or null(car u memq '(aeval reval)) then u else cadr u; remprop('conc,'newnam); put('join,'newnam,'conc); % alternative for CONC endmodule; end;