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

functor mkVerbose(structure Errs : LR_ERRS) : VERBOSE =
struct
   structure Errs = Errs
   open Errs Errs.LrTable
   val mkPrintAction = fn print =>
	let val printInt = print o (Int.toString : int -> string)
	in fn (SHIFT (STATE i)) =>
			(print "\tshift ";
		 	 printInt i;
		 	print "\n")
	     | (REDUCE rulenum) =>
			(print "\treduce by rule ";
		 	 printInt rulenum;
		 	 print "\n")
	     | ACCEPT => print "\taccept\n"
	     | ERROR => print "\terror\n"
	end
   val mkPrintGoto = fn (printNonterm,print) =>
      let val printInt = print o (Int.toString : int -> string)
      in fn (nonterm,STATE i) =>
		(print "\t";
		 printNonterm nonterm;
		 print "\tgoto ";
		 printInt i;
		 print "\n")
      end

   val mkPrintTermAction = fn (printTerm,print) =>
 	let val printAction = mkPrintAction print
	in fn (term,action) =>
		(print "\t";
		 printTerm term;
		 printAction action)
	end
   val mkPrintGoto = fn (printNonterm,print) =>
	fn (nonterm,STATE i) =>
	    let val printInt = print o (Int.toString : int -> string)
	    in (print "\t";
		printNonterm nonterm;
		print "\tgoto ";
		printInt i;
		print "\n")
	    end
   val mkPrintError = fn (printTerm,printRule,print) =>
     let val printInt = print o (Int.toString : int -> string)
	 val printState = fn STATE s => (print " state "; printInt s)
     in fn (RR (term,state,r1,r2)) =>
		(print "error: ";
		 printState state;
		 print ": reduce/reduce conflict between rule ";
		 printInt r1;
		 print " and rule ";
		 printInt r2;
		 print " on ";
		 printTerm term;
		 print "\n")
	 | (SR (term,state,r1)) =>
		(print "error: ";
		 printState state;
		 print ": shift/reduce conflict ";
		 print "(shift ";
		 printTerm term;
		 print ", reduce by rule ";
		 printInt r1;
		 print ")\n")
	 | NOT_REDUCED i =>
		(print "warning: rule <";
		 printRule i;
		 print "> will never be reduced\n")
	 | START i => 
	        (print "warning: start symbol appears on the rhs of ";
	         print "<";
	         printRule i;
		 print ">\n")
	 | NS (term,i) =>
	        (print "warning: non-shiftable terminal ";
		 printTerm term;
		 print  "appears on the rhs of ";
	         print "<";
	         printRule i;
		 print ">\n")
      end
   structure PairList : sig 
                          val app : ('a * 'b -> unit) -> ('a,'b) pairlist -> unit
                          val length : ('a,'b) pairlist -> int
                        end
       =
      struct
         val app = fn f =>
	     let fun g EMPTY = ()
                   | g (PAIR(a,b,r)) = (f(a,b); g r)
             in g
             end
         val length = fn l =>
	     let fun g(EMPTY,len) = len
                   | g(PAIR(_,_,r),len) = g(r,len+1)
             in g(l,0)
             end
      end
   val printVerbose =
	fn {termToString,nontermToString,table,stateErrs,entries:int,
	    print,printRule,errs,printCores} =>
	   let 
		val printTerm = print o termToString
		val printNonterm = print o nontermToString

		val printCore = printCores print
		val printTermAction = mkPrintTermAction(printTerm,print)
		val printAction = mkPrintAction print
		val printGoto = mkPrintGoto(printNonterm,print)
		val printError = mkPrintError(printTerm,printRule print,print)

		val gotos = LrTable.describeGoto table
		val actions = LrTable.describeActions table
		val states = numStates table

                val gotoTableSize = ref 0
                val actionTableSize = ref 0
		
		val _ = if length errs > 0 
			   then (printSummary print errs;
			         print "\n";
				 app printError errs)
			   else ()  
		fun loop i =
		  if i=states then ()
		  else let val s = STATE i
		       in (app printError (stateErrs s);
			   print "\n";
			   printCore s;
			   let val (actionList,default) = actions s
			       val gotoList = gotos s
			   in (PairList.app printTermAction actionList;
			       print "\n";
			       PairList.app printGoto gotoList;
			       print "\n";
			       print "\t.";
			       printAction default;
			       print "\n";
			       gotoTableSize:=(!gotoTableSize)+
			                      PairList.length gotoList;
			       actionTableSize := (!actionTableSize) +
			                       PairList.length actionList + 1
			       ) 
			   end;
			   loop (i+1))
			end
	  in loop 0;
	      print (Int.toString entries ^ " of " ^
		     Int.toString (!actionTableSize)^
		     " action table entries left after compaction\n");
	      print (Int.toString (!gotoTableSize)^ " goto table entries\n")
	  end
end;


