123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- module forstat; % Definition of REDUCE FOR loops.
- % Author: Anthony C. Hearn.
- % Copyright (c) 1993 The RAND Corporation. All rights reserved.
- fluid '(!*blockp !*fastfor);
- 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;
- 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;
|