{ AN OPEN CHALLENGE TO ALL PASCAL COMPILERS: Compile this program correctly and produce the correct output. Send responses, counter-challenges, etc., to: Tom Pennello Computer and Information Sciences University of California Santa Cruz, CA. 95064 } program p(output); type integer = -32767..32768; node = 0..4500; var Debug: boolean; procedure EachUSCC( { of relation R } { Pass in an iterator to generate the nodes to be searched, the relation on the nodes, a procedure to do information propagation when V R W is discovered, a procedure to take each SCC found, and a procedure to yield each node in the graph. We require that the nodes be of a scalar type so that an array may be indexed by them. Also passed in is the upper bound of the node type. } procedure EachUnode(procedure P(T:node)); { Yields each node in graph } procedure EachUnodeUtoUsearch(procedure SearchU(V:node)); procedure R(V:node; procedure DoUsuccessor(W:node)); procedure Propagate(V,W:node); { called when V R W is discovered } procedure TakeUSCC(Root:node; procedure Each(procedure P(T:node))); LastUnode: integer ); type A = array[node] of integer; { range 0..Infinity (below) } var N: ^A; SP: integer; Stack: array[node {1..LastUnode}] of node; Infinity: integer; { LastUnode+1 } procedure P(T:node); begin N^[T] := 0; end; procedure Search(V:node); var I,T:integer; procedure DoUsuccessor(W:node); begin Search(W); if N^[W] < N^[V] then N^[V] := N^[W]; Propagate(V,W); end; { EachUmember is yielded by EachUSCC when an SCC has been found. } procedure EachUmember(procedure P(TU:node)); var I:integer; begin { yield each member of current SCC } for I := SP downto T do P(Stack[I]); end; procedure YieldUSCC; begin if Debug then writeln('YieldUSCC passes',V,' to TakeUSCC'); TakeUSCC(V,EachUmember); end; begin if N^[V] = 0 then begin { stack the node } if Debug then writeln('stacking ',V); SP := SP+1; Stack[SP] := V; N^[V] := SP; if Debug then writeln('Doing successors of ',V); R(V,DoUsuccessor); if Debug then writeln('Now checking if ',V,' is an SCC root'); if V = Stack[N^[V]] then begin { V is root of an SCC } T := N^[V]; if Debug then writeln(V,' is an SCC root; SP=',SP,' T=',T); for I := SP downto T do N^[Stack[I]] := Infinity; if SP <> T then begin if Debug then writeln('Yield SCC should pass ',V,' out to TakeUSCC'); YieldUSCC; end; SP := T-1; end; end; end; begin Infinity := LastUnode+1; new(N); EachUnode(P); SP := 0; EachUnodeUtoUsearch(Search); dispose(N); end; procedure Outer; { needed to produce bug in Berkeley Pascal compiler } procedure q; procedure EachUnodeUtoUsearch(procedure Search(T:node)); begin Search(1); end; procedure EachUnode(procedure P(T:node)); begin P(1); P(2); end; procedure R(V:node; procedure P(W:node)); begin { Defines graph with edges 1->2 and 2->1 } { Thus, the graph contains one SCC: [1,2] } case V of 1: P(2); 2: P(1); end; end; procedure Propagate(V,W:node); begin end; procedure TakeUSCC(Root:node; procedure Each(procedure P(T:node))); procedure P(T:node); begin write(T); end; begin writeln('TakeUSCC receives V=',Root,' from YieldUSCC'); writeln('The SCC''s constituents are:'); Each(P); writeln; end; begin EachUSCC(EachUnode,EachUnodeUtoUsearch,R,Propagate,TakeUSCC,2); end; procedure Doit; begin q; end; begin Doit; end; begin Debug := true; Outer; end. {---------------------------------------------------------------- An alternate version of this program, written in a language supporting iterators, iterators as parameters, iterators as yielded results of iterators, and the ability to yield more than one thing, might be as follows: ---------------------------------------------------------------- iterator EachUSCC( iterator EachUnode:node; iterator EachUnodeUtoUsearch:node; iterator R(V:node):node; procedure Propagate(V,W:node); LastUnode:node ): (Root:node; iterator EachUnodeUinUSCC:node); # EachUSCC yields two results: the Root of the SCC, # and an iterator that yields each member of that SCC. type A = aray[node] of integer; var N: ^A; SP: integer; Stack: array[node] of node; Infinity: integer; procedure Search(V); var T: integer; iterator EachUmember:node; begin for I := SP downto T do P(Stack[I]); end; begin if N^[V] = 0 then begin SP := SP+1; Stack[SP] := V; N^[V] := SP; for W in R(V) do begin # Search successors of V. Search(W); if N^[W] < N^[V] then N^[V] := N^[W]; Propagate(V,W); end; if V = Stack[N^[V]] then begin T := N^[V]; # V is an SCC root. for I := SP downto T do N^[Stack[I]] := Infinity; if SP <> T then # Non-trivial SCC. yield(V,EachUmember); SP := T-1; end; end; end; begin Infinity := LastUnode+1; new(N); for T in EachUnode() do N^[T] := 0; # for loops declare their SP := 0; # control variable as a constant. for V in EachUnodeUtoUsearch() do Search(V); dispose(N); end; # Sample use of EachUSCC: iterator EachUnodeUtoUsearch:node; begin yield(1); end; iterator EachUnode:node; begin yield(1); yield(2); end; iterator R(V:node):node; begin if V = 1 then yield(2) else yield(1); end; procedure Propagate(V,W:node); begin end; procedure UseUEachUSCC; begin for (Root,EachUmember) in EachUSCC(EachUnode,EachUnodeUtoUsearch,R,Propagate,TakeUSCC,2) do begin writeln('Root of received SCC is ',Root); writeln('Constituents of the SCC are:'); for I in EachUmember() do write(I); writeln; end; end; }