module sfgen;   % Handy functions used by the special functions package.

% Author: Chris Cannam.

exports sq2bf!*,bfprin!:roundup,sf!*eval;

symbolic procedure sf!*assoc(compare,val,alist);
   (if null alist then nil
    else if not lispeval list(compare,car car alist,val)
      	 then car alist
      	 else sf!*assoc(compare,val,cdr alist));

symbolic procedure sf!*multi!*assoc!*comparator(compare,vals,entry);
   (if null entry
    then (null vals)
    else (not null vals)
      and (lispeval list(compare,list('quote,car vals),
      	       	     	      	 list('quote,car entry)))
      and (sf!*multi!*assoc!*comparator(compare,cdr vals,cdr entry)));

symbolic procedure sf!*multi!*assoc(compare,vals,alist);
   (if null alist then nil
    else if sf!*multi!*assoc!*comparator(compare,vals,car car alist)
      	 then car alist
      	 else sf!*multi!*assoc(compare,vals,cdr alist));

symbolic procedure sf!*do!*eval(expression);
   begin scalar prepre, result;
      prepre := precision 0;
      precision (prepre + 3);
      result := aeval expression;
      precision prepre;
      return result;
   end;


% It's a finite state automaton!  It's a big nested if..then..else
% construct!  It's repulsive repetitive code!  It's easy to compile
% and run quickly!  It's longer than it needs to be!  It's all of
% this and more...!   (But at least it works.)

symbolic procedure sf!*eval(name,args);
   begin scalar part1, part2, result;
      args := cdr args;
      if (part1 := assoc((name . !*complex),sf!-alist))
      then if (part2 := sf!*assoc('lessp,c!:prec!:(),cdr part1))
	   then if (result :=
		       sf!*multi!*assoc('evalequal,args,cdr part2))
      	        then result := cdr result
      	       	else if !*savesfs
      	       	     then setq(cdr part2,
			  (args . (result := sf!*do!*eval(name . args)))
      	       	     	    . cdr part2)
      	       	     else result := sf!*do!*eval(name . args)
      	   else if !*savesfs
      	        then setq(cdr part1,
      	       	      (c!:prec!:()
      	       	         . list ((args .
      	       	     	      (result := sf!*do!*eval(name . args)))))
      	       	       . cdr part1)
      	        else result := sf!*do!*eval(name . args)
      else if !*savesfs
      	   then sf!-alist :=
      	         ((name . !*complex) .
      	       	  list ((c!:prec!:() .
      	       	       list ((args .
      	       	     	      (result := sf!*do!*eval(name . args))
      	       	     	     ))))) . sf!-alist
      	   else result := sf!*do!*eval(name . args);
      return result;
   end;

algebraic procedure complex!*off!*switch;
   if symbolic !*complex then
      if symbolic !*msg then
         << off msg; off complex; on msg >>
      else off complex
   else t;

algebraic procedure complex!*restore!*switch(fl);
   if not fl then
      if symbolic !*msg then
         << off msg;
            if symbolic !*complex then
               off complex
            else on complex;
            on msg >>
      else if symbolic !*complex then
            off complex
         else on complex;

endmodule;

end;


