(* ML-Yacc Parser Generator (c) 1989 Andrew W. Appel, David R. Tarditi *)

functor mkGraph(structure IntGrammar : INTGRAMMAR
		structure Core : CORE
		structure CoreUtils : CORE_UTILS
		sharing IntGrammar = Core.IntGrammar = CoreUtils.IntGrammar
		sharing CoreUtils.Core = Core
		) : LRGRAPH =
	struct
		val sub = Array.sub
		infix 9 sub
		structure Core = Core
		structure Grammar = IntGrammar.Grammar
		structure IntGrammar = IntGrammar
		open Core Core.Grammar CoreUtils IntGrammar

		structure NodeSet = RbOrdSet
			(struct
				type elem = core
				val eq = eqCore
				val gt = gtCore
			end)

		open NodeSet
		exception Shift of int * symbol

		type graph = {edges: {edge:symbol,to:core} list array,
			      nodes: core list,nodeArray : core array}
		val edges = fn (CORE (_,i),{edges,...}:graph) => edges sub i
		val nodes = fn ({nodes,...} : graph) => nodes
		val shift = fn ({edges,nodes,...} : graph) => fn a as (i,sym) =>
			let fun find nil = raise (Shift a)
			      | find ({edge,to=CORE (_,state)} :: r) =
					if gtSymbol(sym,edge) then find r
					else if eqSymbol(edge,sym) then state
					else raise (Shift a)
			in find (edges sub i)
			end

		val core = fn ({nodeArray,...} : graph) =>
				 fn i => nodeArray sub i

		val mkGraph = fn (g as (GRAMMAR {start,...})) =>
		   let val {shifts,produces,rules,epsProds} =
				  CoreUtils.mkFuncs g
		       fun add_goto ((symbol,a),(nodes,edges,future,num)) =
				case find(CORE (a,0),nodes)
				  of NONE =>
				     let val core =CORE (a,num)
					 val edge = {edge=symbol,to=core}
				     in (insert(core,nodes),edge::edges,
					 core::future,num+1)
				     end
				   | (SOME c) =>
					let val edge={edge=symbol,to=c}
					in (nodes,edge::edges,future,num)
					end
		       fun f (nodes,node_list,edge_list,nil,nil,num) =
			    let val nodes=rev node_list
			    in {nodes=nodes,
				edges=Array.fromList (rev edge_list),
				nodeArray = Array.fromList nodes
			 	}
			    end
			 | f (nodes,node_list,edge_list,nil,y,num) =
				f (nodes,node_list,edge_list,rev y,nil,num)
			 | f (nodes,node_list,edge_list,h::t,y,num) =
			 	let val (nodes,edges,future,num) =
				   List.foldr add_goto (nodes,[],y,num) (shifts h)
				in f (nodes,h::node_list,
				       edges::edge_list,t,future,num)
				end
		in {graph=
		   let val makeItem = fn (r as (RULE {rhs,...})) =>
						ITEM{rule=r,dot=0,rhsAfter=rhs}
			val initialItemList = map makeItem (produces start)
		        val orderedItemList =
			   List.foldr Core.insert [] initialItemList
 			val initial = CORE (orderedItemList,0)
		   in f(empty,nil,nil,[initial],nil,1)
		   end,
		   produces=produces,
		   rules=rules,
		   epsProds=epsProds}
		end
	val prGraph = fn a as (nontermToString,termToString,print) => fn g =>
	   let val printCore = prCore a
	       val printSymbol = print o nontermToString
	       val nodes = nodes g
	       val printEdges = fn n => 
		 List.app (fn {edge,to=CORE (_,state)} =>
			(print "\tshift on ";
			 printSymbol edge;
			 print " to ";
			 print (Int.toString state);
			 print "\n")) (edges (n,g))
	 in List.app (fn c => (printCore c; print "\n"; printEdges c)) nodes
	 end
end;
