module str;  % Routines for structuring expressions.

% Author: Anthony C. Hearn.

% Copyright (c) 1991 The RAND Corporation. All rights reserved.

fluid '(!*fort !*nat !*savestructr scountr svar svarlis);

global '(varnam!*);

varnam!* := 'ans;

switch savestructr;

flag('(structr),'intfn);        % To fool the supervisor into printing
				% results of STRUCTR.

% ***** two essential uses of RPLACD occur in this module.

symbolic procedure structr u;
   begin scalar scountr,fvar,svar,svarlis;
      % SVARLIS is a list of elements of form:
      % (<unreplaced expression> . <newvar> . <replaced exp>);
      scountr :=0;
      fvar := svar := varnam!*;
      if cdr u
        then <<fvar := svar := cadr u; if cddr u then fvar := caddr u>>;
      u := structr1 aeval car u;
      if !*fort then svarlis := reversip!* svarlis
       else if not !*savestructr
	then <<assgnpri(u,nil,'only);
	       if not eqcar(u,'mat) then terpri(); % MAT already has eol
               if scountr=0 then return nil
                else <<if null !*nat then terpri();
		       prin2t "   where">>>>;
      if !*fort or not !*savestructr
	then for each x in svarlis do
	     <<terpri!* t;
	       if null !*fort then prin2!* "      ";
	       assgnpri(cddr x,list cadr x,t)>>;
      if !*fort then assgnpri(u,list fvar,t)
       else if !*savestructr
	then return 'list . u .
			foreach x in svarlis
			   collect list('equal,cadr x,
					       mkquote cddr x)
   end;

rlistat '(structr);

symbolic procedure structr1 u;
   % This routine considers special case STRUCTR arguments. It could be
   % easily generalized.
   if atom u then u
    else if car u eq 'mat
     then car u .
	(for each j in cdr u collect for each k in j collect structr1 k)
    else if car u eq 'list
     then 'list . for each j in cdr u collect structr1 j
    else if car u eq 'equal then list('equal,cadr u,structr1 caddr u)
    else if car u eq '!*sq
     then mk!*sq(structf numr cadr u ./ structf denr cadr u)
    else if getrtype u then typerr(u,"STRUCTR argument")
    else u;

symbolic procedure structf u;
   if null u then nil
    else if domainp u then u
    else begin scalar x,y;
        x := mvar u;
        if sfp x then if y := assoc(x,svarlis) then x := cadr y
                else x := structk(prepsq!*(structf x ./ 1),
                                  structvar(),x)
%        else if not atom x and not atomlis cdr x
	  else if not atom x
	     and not(atom car x and flagp(car x,'noreplace))
          then if y := assoc(x,svarlis) then x := cadr y
                else x := structk(x,structvar(),x);
% Suggested patch by Rainer Schoepf to cache powers.
%       if ldeg u = 1
%         then return x .** ldeg u .* structf lc u .+ structf red u;
%       z := retimes exchk list (x .** ldeg u);
%       if y := assoc(z,svarlis) then x := cadr y
%        else x := structk(z, structvar(), z);
%       return x .** 1 .* mystructf lc u .+ mystructf red u
        return x .** ldeg u .* structf lc u .+ structf red u
     end;

symbolic procedure structk(u,id,v);
   begin scalar x;
      if x := subchk1(u,svarlis,id)
        then rplacd(x,(v . id . u) . cdr x)
       else if x := subchk2(u,svarlis)
        then svarlis := (v . id . x) . svarlis
       else svarlis := (v . id . u) . svarlis;
      return id
   end;

symbolic procedure subchk1(u,v,id);
   begin scalar w;
      while v do
       <<smember(u,cddar v)
            and <<w := v; rplacd(cdar v,subst(id,u,cddar v))>>;
         v := cdr v>>;
      return w
   end;

symbolic procedure subchk2(u,v);
   begin scalar bool;
      for each x in v do
       smember(cddr x,u)
          and <<bool := t; u := subst(cadr x,cddr x,u)>>;
      if bool then return u else return nil
   end;

symbolic procedure structvar;
   begin
      scountr := scountr + 1;
      return if arrayp svar then list(svar,scountr)
       else intern compress append(explode svar,explode scountr)
   end;

endmodule;

end;
