simplified elimination of chain productions
authorclasohm
Thu, 02 Feb 1995 13:11:51 +0100
changeset 890 2b7275b13bef
parent 889 e87c01fd0351
child 891 a5ad535a241a
simplified elimination of chain productions
src/Pure/Syntax/parser.ML
--- a/src/Pure/Syntax/parser.ML	Fri Jan 27 13:40:07 1995 +0100
+++ b/src/Pure/Syntax/parser.ML	Thu Feb 02 13:11:51 1995 +0100
@@ -40,11 +40,11 @@
   Nonterminal of string * int;
 
 datatype refsymb = Term of token | Nonterm of rhss_ref * int
-                                (*reference to production list instead of name*)
+                               (*reference to production list instead of name*)
 and gram = Gram of (string * (symb list * string * int)) list *
                    (string * rhss_ref) list
-withtype rhss_ref = (token option * (refsymb list * string * int) list) list ref
-                                      (*lookahead table: token and productions*)
+withtype rhss_ref = (token option * (refsymb list * string *int) list) list ref
+                                     (*lookahead table: token and productions*)
 
 (* convert productions to reference grammar with lookaheads and eliminate
    chain productions *)
@@ -69,65 +69,59 @@
             end;
 
       (*convert prod list to (string * rhss_ref) list
-        without computing lookaheads*)
-      fun mk_ref_gram [] ref_prods = ref_prods
-        | mk_ref_gram ((lhs, (rhs, name, prec)) :: ps) ref_prods =
+        without computing lookaheads; at the same time filter out chains*)
+      fun mk_ref_gram [] ref_prods chains = (ref_prods, chains)
+        | mk_ref_gram ((lhs, ([Nonterminal (id, ~1)], _, ~1)) :: ps)
+                      ref_prods chains =                   (*chain production*)
+            let val (rhss_ref, ref_prods') = get_rhss ref_prods lhs;
+                val (rhss_ref2, ref_prods'') = get_rhss ref_prods' id;
+            in mk_ref_gram ps ref_prods'' ((rhss_ref, rhss_ref2) :: chains)
+            end
+        | mk_ref_gram ((lhs, (rhs, name, prec)) :: ps) ref_prods chains =
             let val (rhs', ref_prods') = get_rhss ref_prods lhs;
                 val (dummy, rhss) = hd (!rhs');
                 val (ref_symbs, ref_prods'') = mk_refsymbs ref_prods' rhs [];
             in rhs' := [(dummy, (ref_symbs, name, prec) :: rhss)];
-               mk_ref_gram ps ref_prods''
+               mk_ref_gram ps ref_prods'' chains
             end;
 
-      (*eliminate chain productions*)
-      fun elim_chain ref_gram =
-        let (*make a list of pairs representing chain productions and delete
-              these productions*)
-            fun list_chain [] = []
-              | list_chain ((_, rhss_ref) :: ps) =
-                  let fun lists [] new_rhss chains = (new_rhss, chains)
-                        | lists (([Nonterm (id2, ~1)], _, ~1) :: rs) 
-                                new_rhss chains =
-                            lists rs new_rhss ((rhss_ref, id2) :: chains)
-                        | lists (rhs :: rs) new_rhss chains = 
-                            lists rs (rhs :: new_rhss) chains;
+      (*expand chain productions*)
+      fun exp_chain (ref_gram, chains) =
+        let (*convert a list of pairs to an association list
+              by using the first element as the key*)
+            fun mk_assoc pairs =
+              let fun mk [] result = result
+                    | mk ((id1, id2) :: ps) result =
+                       mk ps 
+                       (overwrite (result, (id1, id2 :: (assocs result id1))));
+              in mk pairs [] end;
 
-                      val (dummy, rhss) = hd (!rhss_ref);
-
-                      val (new_rhss, chains) = lists rhss [] [];
-                  in rhss_ref := [(dummy, new_rhss)];
-                     chains @ (list_chain ps)
+            (*sort chains in the order they have to be expanded *)
+            fun sort [] [] result = result
+              | sort [] todo result = sort todo [] result
+              | sort ((chain as (nt, nts)) :: chains) todo result =
+                  let fun occurs _ [] = false
+                        | occurs id ((_, nts) :: chains) =
+                            if id mem nts then true
+                            else occurs id chains
+                  in if occurs nt chains then
+                       sort chains (chain :: todo) result
+                     else
+                       sort chains todo (chain :: result)
                   end;
 
-            (*convert a list of pairs to an association list
-              by using the first element as the key*)
-            fun mk_assoc pairs =
-              let fun doit [] result = result
-                    | doit ((id1, id2) :: ps) result =
-                        doit ps 
-                        (overwrite (result, (id1, id2 :: (assocs result id1))));
-              in doit pairs [] end;
-
-            (*replace reference by list of rhss in chain pairs*)
-            fun deref (id1, ids) =
-              let fun deref1 [] = []
-                    | deref1 (id :: ids) =
-                        let val (_, rhss) = hd (!id);
-                        in rhss @ (deref1 ids) end;
-              in (id1, deref1 ids) end;
-
-            val chain_pairs = 
-               map deref (transitive_closure (mk_assoc (list_chain ref_gram)));
+            (*replace reference by list of rhss*)
+            fun deref (id:rhss_ref) = #2 (hd (!id));
 
             (*add new rhss to productions*)
-            fun elim (rhss_ref, rhss) =
+            fun expand (rhss_ref, rhss) =
               let val (dummy, old_rhss) = hd (!rhss_ref);
-              in rhss_ref := [(dummy, old_rhss @ rhss)] end;
-        in map elim chain_pairs;
+              in rhss_ref := [(dummy, old_rhss @ (flat (map deref rhss)))] end;
+        in map expand (sort (mk_assoc chains) [] []);
            ref_gram
         end;
 
-      val ref_gram = elim_chain (mk_ref_gram prods []);
+      val ref_gram = exp_chain (mk_ref_gram prods [] []);
 
       (*make a list of all lambda NTs 
         (i.e. nonterminals that can produce lambda)*)
@@ -248,7 +242,6 @@
 
              val (_, rhss) = hd (!rhss_ref);
         in rhss_ref := look_rhss rhss [] end;
-
   in map mk_lookahead ref_gram;
      Gram (prods, ref_gram)
   end;