- Try to do better pretty printing when array elements are individually
[bpt/coccinelle.git] / bundles / menhirLib / menhir-20120123 / src / lr1.ml
diff --git a/bundles/menhirLib/menhir-20120123/src/lr1.ml b/bundles/menhirLib/menhir-20120123/src/lr1.ml
deleted file mode 100644 (file)
index b872197..0000000
+++ /dev/null
@@ -1,1044 +0,0 @@
-(**************************************************************************)
-(*                                                                        *)
-(*  Menhir                                                                *)
-(*                                                                        *)
-(*  François Pottier, INRIA Rocquencourt                                  *)
-(*  Yann Régis-Gianas, PPS, Université Paris Diderot                      *)
-(*                                                                        *)
-(*  Copyright 2005-2008 Institut National de Recherche en Informatique    *)
-(*  et en Automatique. All rights reserved. This file is distributed      *)
-(*  under the terms of the Q Public License version 1.0, with the change  *)
-(*  described in file LICENSE.                                            *)
-(*                                                                        *)
-(**************************************************************************)
-
-open Grammar
-
-(* This module constructs an LR(1) automaton by following Pager's method, that
-   is, by merging states on the fly when they are weakly compatible. *)
-
-(* ------------------------------------------------------------------------ *)
-(* Nodes. *)
-
-type node = {
-
-    (* A node number, assigned during construction. *)
-
-    raw_number: int;
-
-    (* A node number, assigned after conflict resolution has taken
-       place and after inacessible nodes have been removed. This
-       yields sequential numbers, from the client's point of view. *)
-
-    mutable number: int;
-
-    (* Each node is associated with a state. This state can change
-       during construction as nodes are merged. *)
-
-    mutable state: Lr0.lr1state;
-
-    (* Each node carries information about its outgoing transitions
-       and about its reductions. *)
-
-    mutable transitions: node SymbolMap.t;
-    mutable reductions: Production.index list TerminalMap.t;
-
-    (* Tokens for which there are several possible behaviors are
-       conflict tokens. *)
-
-    mutable conflict_tokens: TerminalSet.t;
-
-    (* Transitions are also stored in reverse, so as to allow reverse
-       traversals of the automaton. *)
-
-    mutable predecessors: node list;
-
-    (* If a node has any incoming transitions, then they all carry
-       the same symbol. This is it. *)
-
-    mutable incoming_symbol: Symbol.t option;
-
-    (* Transient marks are used during construction and traversal. *)
-
-    mutable mark: Mark.t;
-
-    (* (New as of 2012/01/23.) This flag records whether a shift/reduce
-       conflict in this node was solved in favor of neither (%nonassoc).
-       This is later used to forbid a default reduction at this node. *)
-
-    mutable forbid_default_reduction: bool;
-
-  }
-
-module Node = struct
-  type t = node
-  let compare node1 node2 =
-    node1.number - node2.number
-end
-
-module NodeSet =
-  Set.Make (Node)
-
-module NodeMap =
-  Map.Make (Node)
-
-(* ------------------------------------------------------------------------ *)
-
-(* Output debugging information if [--follow-construction] is enabled. *)
-
-let follow_transition (again : bool) (source : node) (symbol : Symbol.t) (state : Lr0.lr1state) =
-  if Settings.follow then
-    Printf.fprintf stderr
-      "%s transition out of state r%d along symbol %s.\nProposed target state:\n%s"
-      (if again then "Re-examining" else "Examining")
-      source.raw_number
-      (Symbol.print symbol)
-      (Lr0.print_closure state)
-
-let follow_state (msg : string) (node : node) (print : bool) =
-  if Settings.follow then
-    Printf.fprintf stderr
-      "%s: r%d.\n%s\n"
-      msg
-      node.raw_number
-      (if print then Lr0.print_closure node.state else "")
-
-(* ------------------------------------------------------------------------ *)
-
-(* The following two mutually recursive functions are invoked when the state
-   associated with an existing node grows. The node's descendants are examined
-   and grown into a fixpoint is reached.
-
-   This work is performed in an eager manner: we do not attempt to build any
-   new transitions until all existing nodes have been suitably grown. Indeed,
-   building new transitions requires making merging decisions, and such
-   decisions cannot be made on a sound basis unless all existing nodes have
-   been suitably grown. Otherwise, one could run into a dead end where two
-   successive, incompatible merging decisions are made, because the
-   consequences of the first decision (growing descendant nodes) were not made
-   explicit before the second decision was taken. This was a bug in versions
-   of Menhir ante 20070520.
-
-   Although I wrote this code independently, I later found out that it seems
-   quite similar to the code in Karl Schimpf's Ph.D. thesis (1981), page 35.
-
-   It is necessary that all existing transitions be explicit before the [grow]
-   functions are called. In other words, if it has been decided that there will
-   be a transition from [node1] to [node2], then [node1.transitions] must be
-   updated before [grow] is invoked. *)
-
-(* [grow node state] grows the existing node [node], if necessary, so that its
-   associated state subsumes [state]. If this represents an actual (strict)
-   growth, then [node]'s descendants are grown as well. *)
-
-let rec grow node state =
-  if Lr0.subsume state node.state then
-    follow_state "Target state is unaffected" node false
-   else begin
-
-     (* In versions of Menhir prior to June 2008, I wrote this:
-
-         If I know what I am doing, then the new state that is being
-         merged into the existing state should be compatible, in
-         Pager's sense, with the existing node. In other words,
-         compatibility should be preserved through transitions.
-
-        and the code contained this assertion:
-
-         assert (Lr0.compatible state node.state);
-         assert (Lr0.eos_compatible state node.state);
-
-       However, this was wrong. See, for instance, the sample grammars
-       cocci.mly and boris-mini.mly. The problem is particularly clearly
-       apparent in boris-mini.mly, where it only involves inclusion of
-       states -- the definition of Pager's weak compatibility does not
-       enter the picture. Here is, roughly, what is going on.
-
-       Assume we have built some state A, which, along some symbol S,
-       has a transition to itself. This means, in fact, that computing
-       the successor of A along S yields a *subset* of A, that is,
-       succ(A, S) <= A.
-
-       Then, we wish to build a new state A', which turns out to be a
-       superset of A, so we decide to grow A. (The fact that A is a
-       subset of A' implies that A and A' are Pager-compatible.) As
-       per the code below, we immediately update the state A in place,
-       to become A'. Then, we inspect the transition along symbol S.
-       We find that the state succ(A', S) must be merged into A'.
-
-       In this situation, the assertions above require succ(A', S)
-       to be compatible with A'. However, this is not necessarily
-       the case. By monotonicity of succ, we do have succ(A, S) <=
-       succ(A', S). But nothing says that succ(A', S) are related
-       with respect to inclusion, or even Pager-compatible. The
-       grammar in boris-mini.mly shows that they are not.
-
-     *)
-
-    (* Grow [node]. *)
-
-    node.state <- Lr0.union state node.state;
-    follow_state "Growing existing state" node true;
-
-    (* Grow [node]'s successors. *)
-
-    grow_successors node
-
-  end
-
-(* [grow_successors node] grows [node]'s successors. *)
-
-(* Note that, if there is a cycle in the graph, [grow_successors] can be
-   invoked several times at a single node [node], with [node.state] taking on
-   a new value every time. In such a case, this code should be correct,
-   although probably not very efficient. *)
-
-and grow_successors node =
-  SymbolMap.iter (fun symbol (successor_node : node) ->
-    let successor_state = Lr0.transition symbol node.state in
-    follow_transition true node symbol successor_state;
-    grow successor_node successor_state
-  ) node.transitions
-
-(* ------------------------------------------------------------------------ *)
-
-(* Data structures maintained during the construction of the automaton. *)
-
-(* A queue of pending nodes, whose outgoing transitions have not yet
-   been built. *)
-
-let queue : node Queue.t =
-  Queue.create()
-
-(* A mapping of LR(0) node numbers to lists of nodes. This allows us to
-   efficiently find all existing nodes that are core-compatible with a
-   newly found state. *)
-
-let map : node list array =
-  Array.create Lr0.n []
-
-(* A counter that allows assigning raw numbers to nodes. *)
-
-let num =
-  ref 0
-
-(* ------------------------------------------------------------------------ *)
-
-(* [create state] creates a new node that stands for the state [state].
-   It is expected that [state] does not subsume, and is not subsumed by,
-   any existing state. *)
-
-let create (state : Lr0.lr1state) : node =
-
-  (* Allocate a new node. *)
-
-  let node = {
-    state = state;
-    transitions = SymbolMap.empty;
-    reductions = TerminalMap.empty;
-    conflict_tokens = TerminalSet.empty;
-    raw_number = Misc.postincrement num;
-    number = 0; (* temporary placeholder *)
-    mark = Mark.none;
-    predecessors = [];
-    incoming_symbol = None;
-    forbid_default_reduction = false;
-  } in
-
-  (* Update the mapping of LR(0) cores to lists of nodes. *)
-
-  let k = Lr0.core state in
-  assert (k < Lr0.n);
-  map.(k) <- node :: map.(k);
-
-  (* Enqueue this node for further examination. *)
-
-  Queue.add node queue;
-
-  (* Debugging output. *)
-
-  follow_state "Creating a new state" node false;
-
-  (* Return the freshly created node. *)
-
-  node
-
-(* ------------------------------------------------------------------------ *)
-
-(* Materializing a transition turns its target state into a (fresh or
-   existing). There are three scenarios: the proposed new state can be
-   subsumed by an existing state, compatible with an existing state, or
-   neither. *)
-
-exception Subsumed of node
-
-exception Compatible of node
-
-let materialize (source : node) (symbol : Symbol.t) (target : Lr0.lr1state) : unit =
-  try
-
-    (* Debugging output. *)
-
-    follow_transition false source symbol target;
-
-    (* Find all existing core-compatible states. *)
-
-    let k = Lr0.core target in
-    assert (k < Lr0.n);
-    let similar = map.(k) in
-
-    (* Check whether one of these states subsumes the candidate new state. If
-       so, there is no need to create a new node: just reuse the existing
-       one. *)
-
-    (* 20110124: require error compatibility in addition to subsumption. *)
-
-    List.iter (fun node ->
-      if Lr0.subsume target node.state &&
-         Lr0.error_compatible target node.state then
-       raise (Subsumed node)
-    ) similar;
-
-    (* Check whether one of the existing states is compatible, in Pager's
-       sense, with the new state. If so, there is no need to create a new
-       state: just merge the new state into the existing one. *)
-
-    (* 20110124: require error compatibility in addition to the existing
-       compatibility criteria. *)
-
-    if Settings.pager then
-      List.iter (fun node ->
-       if Lr0.compatible target node.state &&
-          Lr0.eos_compatible target node.state &&
-          Lr0.error_compatible target node.state then
-         raise (Compatible node)
-      ) similar;
-
-    (* Both of the above checks have failed. Create a new node. Two states
-       that are in the subsumption relation are also compatible. This implies
-       that the newly created node does not subsume any existing states. *)
-
-    source.transitions <- SymbolMap.add symbol (create target) source.transitions
-
-  with
-
-  | Subsumed node ->
-
-      (* Join an existing target node. *)
-
-      follow_state "Joining existing state" node false;
-      source.transitions <- SymbolMap.add symbol node source.transitions
-
-  | Compatible node ->
-
-      (* Join and grow an existing target node. It seems important that the
-        new transition is created before [grow_successors] is invoked, so
-        that all transition decisions made so far are explicit. *)
-
-      node.state <- Lr0.union target node.state;
-      follow_state "Joining and growing existing state (Pager says, fine)" node true;
-      source.transitions <- SymbolMap.add symbol node source.transitions;
-      grow_successors node
-
-(* ------------------------------------------------------------------------ *)
-
-(* The actual construction process. *)
-
-(* Populate the queue with the start nodes and store them in an array. *)
-
-let entry : node ProductionMap.t =
-  ProductionMap.map (fun (k : Lr0.node) ->
-    create (Lr0.start k)
-  ) Lr0.entry
-
-(* Pick a node in the queue, that is, a node whose transitions have not yet
-   been built. Build these transitions, and continue. *)
-
-(* Note that building a transition can cause existing nodes to grow, so
-   [node.state] is not necessarily invariant throughout the inner loop. *)
-
-let () =
-  Misc.qiter (fun node ->
-    List.iter (fun symbol ->
-      materialize node symbol (Lr0.transition symbol node.state)
-    ) (Lr0.outgoing_symbols (Lr0.core node.state))
-  ) queue
-
-(* Record how many nodes were constructed. *)
-
-let n =
-  !num
-
-let () =
-  Error.logA 1 (fun f -> Printf.fprintf f "Built an LR(1) automaton with %d states.\n" !num)
-
-(* ------------------------------------------------------------------------ *)
-(* We now perform one depth-first traversal of the automaton,
-   recording predecessor edges, numbering nodes, sorting nodes
-   according to their incoming symbol, building reduction tables, and
-   finding out which nodes have conflicts. *)
-
-(* A count of all nodes. *)
-
-let () =
-  num := 0
-
-(* A list of all nodes. *)
-
-let nodes : node list ref =
-  ref []
-
-(* A list of nodes with conflicts. *)
-
-let conflict_nodes : node list ref =
-  ref []
-
-(* Counts of nodes with shift/reduce and reduce/reduce conflicts. *)
-
-let shift_reduce =
-  ref 0
-
-let reduce_reduce =
-  ref 0
-
-(* Count of the shift/reduce conflicts that could be silently
-   resolved. *)
-
-let silently_solved =
-  ref 0
-
-(* A mapping of symbols to lists of nodes that admit this incoming
-   symbol. *)
-
-let incoming : node list SymbolMap.t ref =
-  ref SymbolMap.empty
-
-(* Go ahead. *)
-
-let () =
-
-  let marked = Mark.fresh() in
-
-  let rec visit node =
-    if not (Mark.same node.mark marked) then begin
-      node.mark <- marked;
-      nodes := node :: !nodes;
-
-      (* Number this node. *)
-
-      let number = !num in
-      num := number + 1;
-      node.number <- number;
-
-      (* Insertion of a new reduce action into the table of reductions. *)
-
-      let addl prod tok reductions =
-       let prods =
-         try
-           TerminalMap.lookup tok reductions
-         with Not_found ->
-           []
-       in
-       TerminalMap.add tok (prod :: prods) reductions
-      in
-
-      (* Build the reduction table. Here, we gather all potential
-         reductions, without attempting to solve shift/reduce
-         conflicts on the fly, because that would potentially hide
-         shift/reduce/reduce conflicts, which we want to be aware
-         of. *)
-
-      let reductions =
-       List.fold_left (fun reductions (toks, prod) ->
-         TerminalSet.fold (addl prod) toks reductions
-        ) TerminalMap.empty (Lr0.reductions node.state)
-      in
-
-      (* Detect conflicts. Attempt to solve shift/reduce conflicts
-        when unambiguously allowed by priorities. *)
-
-      let has_shift_reduce = ref false
-      and has_reduce_reduce = ref false in
-
-      node.reductions <-
-       TerminalMap.fold (fun tok prods reductions ->
-         if SymbolMap.mem (Symbol.T tok) node.transitions then begin
-
-           (* There is a transition in addition to the reduction(s). We
-              have (at least) a shift/reduce conflict. *)
-
-           assert (not (Terminal.equal tok Terminal.sharp));
-           match prods with
-           | [] ->
-               assert false
-           | [ prod ] ->
-               begin
-
-                 (* This is a single shift/reduce conflict. If priorities tell
-                    us how to solve it, we follow that and modify the automaton. *)
-
-                 match Precedence.shift_reduce tok prod with
-
-                 | Precedence.ChooseShift ->
-
-                     (* Suppress the reduce action. *)
-
-                     incr silently_solved;
-                     reductions
-
-                 | Precedence.ChooseReduce ->
-
-                     (* Record the reduce action and suppress the shift transition.
-                        The automaton is modified in place. This can have the subtle
-                        effect of making some nodes unreachable. Any conflicts in these
-                        nodes will then be ignored (as they should be). *)
-
-                     incr silently_solved;
-                     node.transitions <- SymbolMap.remove (Symbol.T tok) node.transitions;
-                     TerminalMap.add tok prods reductions
-
-                 | Precedence.ChooseNeither ->
-
-                     (* Suppress the reduce action and the shift transition. *)
-
-                     incr silently_solved;
-                     node.transitions <- SymbolMap.remove (Symbol.T tok) node.transitions;
-                     node.forbid_default_reduction <- true;
-                     reductions
-
-                 | Precedence.DontKnow ->
-
-                     (* Priorities don't allow concluding. Record the
-                        existence of a shift/reduce conflict. *)
-
-                     node.conflict_tokens <- Grammar.TerminalSet.add tok node.conflict_tokens;
-                     has_shift_reduce := true;
-                     TerminalMap.add tok prods reductions
-
-               end
-
-           | prod1 :: prod2 :: _ ->
-
-               (* This is a shift/reduce/reduce conflict. If the priorities
-                  are such that each individual shift/reduce conflict is solved
-                  in favor of shifting or in favor of neither, then solve the entire
-                  composite conflict in the same way. Otherwise, report the conflict. *)
-
-               let choices = List.map (Precedence.shift_reduce tok) prods in
-
-               if List.for_all (fun choice ->
-                 match choice with
-                 | Precedence.ChooseShift -> true
-                 | _ -> false
-                ) choices then begin
-
-                 (* Suppress the reduce action. *)
-
-                 silently_solved := !silently_solved + List.length prods;
-                 reductions
-
-               end
-               else if List.for_all (fun choice ->
-                 match choice with
-                 | Precedence.ChooseNeither -> true
-                 | _ -> false
-                ) choices then begin
-
-                 (* Suppress the reduce action and the shift transition. *)
-
-                 silently_solved := !silently_solved + List.length prods;
-                 node.transitions <- SymbolMap.remove (Symbol.T tok) node.transitions;
-                 reductions
-
-               end
-               else begin
-
-                 (* Record a shift/reduce/reduce conflict. Keep all reductions. *)
-
-                 node.conflict_tokens <- Grammar.TerminalSet.add tok node.conflict_tokens;
-                 has_shift_reduce := true;
-                 has_reduce_reduce := true;
-                 TerminalMap.add tok prods reductions
-
-               end
-
-         end
-         else
-           let () = 
-             match prods with
-             | []
-             | [ _ ] ->
-                 ()
-             | prod1 :: prod2 :: _ ->
-
-                 (* There is no transition in addition to the reduction(s). We
-                    have a pure reduce/reduce conflict. Do nothing about it at
-                    this point. *)
-
-                 node.conflict_tokens <- Grammar.TerminalSet.add tok node.conflict_tokens;
-                 has_reduce_reduce := true
-
-           in
-           TerminalMap.add tok prods reductions
-
-      ) reductions TerminalMap.empty;
-
-      (* Record statistics about conflicts. *)
-
-      if not (TerminalSet.is_empty node.conflict_tokens) then begin
-       conflict_nodes := node :: !conflict_nodes;
-       if !has_shift_reduce then
-         incr shift_reduce;
-       if !has_reduce_reduce then
-         incr reduce_reduce
-      end;
-
-      (* Continue the depth-first traversal. Record predecessors edges
-         as we go. No ancestor appears twice in a list of
-         predecessors, because two nodes cannot be related by two
-         edges that carry distinct symbols. *)
-
-      SymbolMap.iter (fun symbol son ->
-        begin
-         match son.incoming_symbol with
-         | None ->
-             son.incoming_symbol <- Some symbol;
-             let others =
-               try
-                 SymbolMap.find symbol !incoming
-               with Not_found ->
-                 []
-             in
-             incoming := SymbolMap.add symbol (son :: others) !incoming
-         | Some symbol' ->
-             assert (Symbol.equal symbol symbol')
-       end;
-       son.predecessors <- node :: son.predecessors;
-       visit son
-      ) node.transitions
-    end
-  in
-  
-  ProductionMap.iter (fun _ node -> visit node) entry
-
-let nodes =
-  List.rev !nodes (* list is now sorted by increasing node numbers *)
-
-let conflict_nodes =
-  !conflict_nodes
-
-let incoming =
-  !incoming
-
-let () =
-  if !silently_solved = 1 then
-    Error.logA 1 (fun f -> Printf.fprintf f "One shift/reduce conflict was silently solved.\n")
-  else if !silently_solved > 1 then
-    Error.logA 1 (fun f -> Printf.fprintf f "%d shift/reduce conflicts were silently solved.\n" !silently_solved);
-  if !num < n then
-    Error.logA 1 (fun f -> Printf.fprintf f "Only %d states remain after resolving shift/reduce conflicts.\n" !num)
-
-let () =
-  Grammar.diagnostics()
-
-let n =
-  !num
-
-let forbid_default_reduction node =
-  node.forbid_default_reduction
-
-(* ------------------------------------------------------------------------ *)
-(* Breadth-first iteration over all nodes. *)
-
-let bfs =
-  let module B = Breadth.Make (struct
-    type vertex = node
-    type label = Symbol.t
-    let set_mark node m = node.mark <- m
-    let get_mark node = node.mark
-    let entry f = ProductionMap.iter (fun _ node -> f node) entry
-    let successors f node = SymbolMap.iter f node.transitions
-  end) in
-  B.search
-
-(* ------------------------------------------------------------------------ *)
-(* Iteration over all nodes. *)
-
-let fold f accu =
-  List.fold_left f accu nodes
-
-let iter f =
-  fold (fun () node -> f node) ()
-
-let map f =
-  List.map f nodes
-
-let foldx f =
-  fold (fun accu node ->
-          match node.incoming_symbol with
-            | None -> accu
-            | Some _ -> f accu node)
-
-let iterx f =
-  iter (fun node -> 
-    match node.incoming_symbol with 
-      | None -> () 
-      | Some _ -> f node)
-(* -------------------------------------------------------------------------- *)
-(* Our output channel. *)
-
-let out =
-  lazy (open_out (Settings.base ^ ".automaton"))
-
-(* ------------------------------------------------------------------------ *)
-(* If requested, dump a verbose description of the automaton. *)
-
-let () =
-  Time.tick "Construction of the LR(1) automaton";
-  if Settings.dump then begin
-    fold (fun () node ->
-      let out = Lazy.force out in
-      Printf.fprintf out "State %d%s:\n%s"
-       node.number
-       (if Settings.follow then Printf.sprintf " (r%d)" node.raw_number else "")
-       (Lr0.print node.state);
-      SymbolMap.iter (fun symbol node ->
-       Printf.fprintf out "-- On %s shift to state %d\n"
-         (Symbol.print symbol) node.number
-      ) node.transitions;
-      TerminalMap.iter (fun tok prods ->
-       List.iter (fun prod ->
-         (* TEMPORARY factoriser les symboles qui conduisent a reduire une meme production *)
-         Printf.fprintf out "-- On %s " (Terminal.print tok);
-         match Production.classify prod with
-         | Some nt ->
-             Printf.fprintf out "accept %s\n" (Nonterminal.print false nt)
-         | None ->
-             Printf.fprintf out "reduce production %s\n" (Production.print prod)
-       ) prods
-      ) node.reductions;
-      if not (TerminalSet.is_empty node.conflict_tokens) then
-       Printf.fprintf out "** Conflict on %s\n" (TerminalSet.print node.conflict_tokens);
-      Printf.fprintf out "\n%!"
-    ) ();
-    Time.tick "Dumping the LR(1) automaton"
-  end
-
-(* ------------------------------------------------------------------------ *)
-(* [reverse_dfs goal] performs a reverse depth-first search through
-   the automaton, starting at node [goal], and marking the nodes
-   traversed. It returns a function that tells whether a node is
-   marked, that is, whether a path leads from that node to the goal
-   node. *)
-
-let reverse_dfs goal =
-
-  let mark = Mark.fresh() in
-
-  let marked node =
-    Mark.same node.mark mark
-  in
-
-  let rec visit node =
-     if not (marked node) then begin
-       node.mark <- mark;
-       List.iter visit node.predecessors
-     end
-  in
-
-  visit goal;
-  marked
-
-(* ------------------------------------------------------------------------ *)
-(* Iterating over all nodes that are targets of edges carrying a
-   certain symbol. The sources of the corresponding edges are also
-   provided. *)
-
-let targets f accu symbol =
-  let targets =
-    try
-      SymbolMap.find symbol incoming
-    with Not_found ->
-      (* There are no incoming transitions on the start symbols. *)
-      []
-  in
-  List.fold_left (fun accu target ->
-    f accu target.predecessors target
-  ) accu targets
-
-(* ------------------------------------------------------------------------ *)
-(* Converting a start node into the single item that it contains. *)
-
-let start2item node =
-  let state : Lr0.lr1state = node.state in
-  let core : Lr0.node = Lr0.core state in
-  let items : Item.Set.t = Lr0.items core in
-  assert (Item.Set.cardinal items = 1);
-  Item.Set.choose items
-
-(* ------------------------------------------------------------------------ *)
-(* Accessors. *)
-
-let number node =
-  node.number
-
-let state node =
-  node.state
-
-let transitions node =
-  node.transitions
-
-let reductions node =
-  node.reductions
-
-let conflicts f =
-  List.iter (fun node ->
-    f node.conflict_tokens node
-  ) conflict_nodes
-
-let incoming_symbol node =
-  node.incoming_symbol
-
-let predecessors node =
-  node.predecessors
-
-(* ------------------------------------------------------------------------ *)
-
-(* This inverts a mapping of tokens to productions into a mapping of
-   productions to sets of tokens. *)
-
-(* This is needed, in [CodeBackend], to avoid producing two (or more)
-   separate branches that call the same [reduce] function. Instead,
-   we generate just one branch, guarded by a [POr] pattern. *)
-
-let invert reductions : TerminalSet.t ProductionMap.t =
-  TerminalMap.fold (fun tok prods inverse ->
-    let prod = Misc.single prods in
-    let toks =
-      try
-       ProductionMap.lookup prod inverse
-      with Not_found ->
-       TerminalSet.empty
-    in
-    ProductionMap.add prod (TerminalSet.add tok toks) inverse
-  ) reductions ProductionMap.empty
-    
-(* ------------------------------------------------------------------------ *)
-(* Computing which terminal symbols a state is willing to act upon.
-
-   This function is currently unused, but could be used as part of an error
-   reporting system.
-
-   One must keep in mind that, due to the merging of states, a state might be
-   willing to perform a reduction on a certain token, yet the reduction can
-   take us to another state where this token causes an error. In other words,
-   the set of terminal symbols that is computed here is really an
-   over-approximation of the set of symbols that will not cause an error. And
-   there seems to be no way of performing an exact computation, as we would
-   need to know not only the current state, but the contents of the stack as
-   well. *)
-
-let acceptable_tokens (s : node) =
-
-  (* If this state is willing to act on the error token, ignore it -- we do
-     not wish to report that an error would be accepted in this state :-) *)
-
-  let transitions =
-    SymbolMap.remove (Symbol.T Terminal.error) (transitions s)
-  and reductions =
-    TerminalMap.remove Terminal.error (reductions s)
-  in
-
-  (* Accumulate the tokens carried by outgoing transitions. *)
-
-  let covered =
-    SymbolMap.fold (fun symbol _ covered ->
-      match symbol with
-      | Symbol.T tok ->
-         TerminalSet.add tok covered
-      | Symbol.N _ ->
-         covered
-    ) transitions TerminalSet.empty
-  in
-
-  (* Accumulate the tokens that permit reduction. *)
-
-  let covered =
-    ProductionMap.fold (fun _ toks covered ->
-      TerminalSet.union toks covered
-    ) (invert reductions) covered
-  in
-
-  (* That's it. *)
-
-  covered
-
-(* ------------------------------------------------------------------------ *)
-(* Report statistics. *)
-
-(* Produce the reports. *)
-
-let () =
-  if !shift_reduce = 1 then
-    Error.grammar_warning [] "one state has shift/reduce conflicts."
-  else if !shift_reduce > 1 then
-    Error.grammar_warning [] (Printf.sprintf "%d states have shift/reduce conflicts." !shift_reduce);
-  if !reduce_reduce = 1 then
-    Error.grammar_warning [] "one state has reduce/reduce conflicts."
-  else if !reduce_reduce > 1 then
-    Error.grammar_warning [] (Printf.sprintf "%d states have reduce/reduce conflicts." !reduce_reduce)
-
-(* There is a global check for errors at the end of [Invariant], so we do
-   not need to check & stop here. *)
-
-(* ------------------------------------------------------------------------ *)
-(* When requested by the code generator, apply default conflict
-   resolution to ensure that the automaton is deterministic. *)
-
-(* [best prod prods] chooses which production should be reduced
-   among the list [prod :: prods]. It fails if no best choice
-   exists. *)
-
-let rec best choice = function
-  | [] ->
-      choice
-  | prod :: prods ->
-      match Precedence.reduce_reduce choice prod with
-      | Some choice ->
-         best choice prods
-      | None ->
-         Error.signal
-           (Production.positions choice @ Production.positions prod)
-           (Printf.sprintf
-              "will not resolve reduce/reduce conflict between\n\
-                productions that originate in distinct source files:\n%s\n%s"
-                  (Production.print choice)
-                  (Production.print prod));
-         choice (* dummy *)
-
-(* Go ahead. *)
-
-let default_conflict_resolution () =
-
-  let shift_reduce =
-    ref 0
-  and reduce_reduce =
-    ref 0
-  in
-
-  List.iter (fun node ->
-
-    node.reductions <-
-      TerminalMap.fold (fun tok prods reductions ->
-       try
-         let (_ : node) =
-           SymbolMap.find (Symbol.T tok) node.transitions
-         in
-         (* There is a transition at this symbol, so this
-            is a (possibly multiway) shift/reduce conflict.
-            Resolve in favor of shifting by suppressing all
-            reductions. *)
-         shift_reduce := List.length prods + !shift_reduce;
-          reductions
-       with Not_found ->
-         (* There is no transition at this symbol. Check
-            whether we have multiple reductions. *)
-         match prods with
-         | [] ->
-             assert false
-         | [ _ ] ->
-             TerminalMap.add tok prods reductions
-         | prod :: ((_ :: _) as prods) ->
-             (* We have a reduce/reduce conflict. Resolve, if
-                possible, in favor of a single reduction.
-                This reduction must be preferrable to each
-                of the others. *)
-             reduce_reduce := List.length prods + !reduce_reduce;
-             TerminalMap.add tok [ best prod prods ] reductions
-
-      ) node.reductions TerminalMap.empty
-
-  ) conflict_nodes;
-
-  if !shift_reduce = 1 then
-    Error.warning [] "one shift/reduce conflict was arbitrarily resolved."
-  else if !shift_reduce > 1 then
-    Error.warning [] (Printf.sprintf "%d shift/reduce conflicts were arbitrarily resolved." !shift_reduce);
-  if !reduce_reduce = 1 then
-    Error.warning [] "one reduce/reduce conflict was arbitrarily resolved."
-  else if !reduce_reduce > 1 then
-    Error.warning [] (Printf.sprintf "%d reduce/reduce conflicts were arbitrarily resolved." !reduce_reduce);
-
-  (* Now, ensure that states that have a reduce action at the
-     pseudo-token "#" have no other action. *)
-
-  let ambiguities =
-    ref 0
-  in
-
-  fold (fun () node ->
-    
-    try
-      let prods, reductions = TerminalMap.lookup_and_remove Terminal.sharp node.reductions in
-      let prod = Misc.single prods in
-
-      (* This node has a reduce action at "#". Determine whether there
-        exist other actions. If there exist any other actions,
-        suppress this reduce action, and signal an ambiguity.
-
-        We signal an ambiguity even in the case where all actions at
-        this node call for reducing a single production. Indeed, in
-        that case, even though we know that this production must be
-        reduced, we do not know whether we should first discard the
-        current token (and call the lexer). *)
-
-      let has_ambiguity = ref false in
-      let toks = ref TerminalSet.empty in
-
-      TerminalMap.iter (fun tok prods ->
-       node.reductions <- reductions;
-       has_ambiguity := true;
-       toks := TerminalSet.add tok !toks
-      ) reductions;
-
-      SymbolMap.iter (fun symbol _ ->
-       match symbol with
-       | Symbol.N _ ->
-           ()
-       | Symbol.T tok ->
-           node.reductions <- reductions;
-           has_ambiguity := true;
-           toks := TerminalSet.add tok !toks
-      ) node.transitions;
-
-      if !has_ambiguity then begin
-       incr ambiguities;
-       if Settings.dump then begin
-         Printf.fprintf (Lazy.force out)
-           "State %d has an end-of-stream conflict. There is a tension between\n\
-            (1) %s\n\
-            without even requesting a lookahead token, and\n\
-            (2) checking whether the lookahead token is %s%s,\n\
-             which would require some other action.\n\n"
-            (number node)
-            (match Production.classify prod with
-           | Some nt ->
-               Printf.sprintf "accepting %s" (Nonterminal.print false nt)
-           | None ->
-               Printf.sprintf "reducing production %s" (Production.print prod))
-            (if TerminalSet.cardinal !toks > 1 then "one of " else "")
-            (TerminalSet.print !toks)
-       end
-      end
-
-    with Not_found ->
-      ()
-
-  ) ();
-
-  if !ambiguities = 1 then
-    Error.grammar_warning [] "one state has an end-of-stream conflict."
-  else if !ambiguities > 1 then
-    Error.grammar_warning [] (Printf.sprintf "%d states have an end-of-stream conflict." !ambiguities)
-