Import Upstream version 20180207
[hcoop/debian/mlton.git] / mlyacc / src / shrink.sml
CommitLineData
7f918cf1
CE
1(* ML-Yacc Parser Generator (c) 1991 Andrew W. Appel, David R. Tarditi *)
2
3signature SORT_ARG =
4 sig
5 type entry
6 val gt : entry * entry -> bool
7 end
8signature SORT =
9 sig
10 type entry
11 val sort : entry list -> entry list
12 end
13signature EQUIV_ARG =
14 sig
15 type entry
16 val gt : entry * entry -> bool
17 val eq : entry * entry -> bool
18 end
19signature EQUIV =
20 sig
21 type entry
22
23 (* equivalences: take a list of entries and divides them into
24 equivalence classes numbered 0 to n-1.
25
26 It returns a triple consisting of:
27
28 * the number of equivalence classes
29 * a list which maps each original entry to an equivalence
30 class. The nth entry in this list gives the equivalence
31 class for the nth entry in the original entry list.
32 * a list which maps equivalence classes to some representative
33 element. The nth entry in this list is an element from the
34 nth equivalence class
35 *)
36
37 val equivalences : entry list -> (int * int list * entry list)
38 end
39
40(* An O(n lg n) merge sort routine *)
41
42functor MergeSortFun(A : SORT_ARG) : SORT =
43 struct
44 type entry = A.entry
45
46 (* sort: an O(n lg n) merge sort routine. We create a list of lists
47 and then merge these lists in passes until only one list is left.*)
48
49 fun sort nil = nil
50 | sort l =
51 let (* merge: merge two lists *)
52
53 fun merge (l as a::at,r as b::bt) =
54 if A.gt(a,b)
55 then b :: merge(l,bt)
56 else a :: merge(at,r)
57 | merge (l,nil) = l
58 | merge (nil,r) = r
59
60 (* scan: merge pairs of lists on a list of lists.
61 Reduces the number of lists by about 1/2 *)
62
63 fun scan (a :: b :: rest) = merge(a,b) :: scan rest
64 | scan l = l
65
66 (* loop: calls scan on a list of lists until only
67 one list is left. It terminates only if the list of
68 lists is nonempty. (The pattern match for sort
69 ensures this.) *)
70
71 fun loop (a :: nil) = a
72 | loop l = loop (scan l)
73
74 in loop (map (fn a => [a]) l)
75 end
76 end
77
78(* an O(n lg n) routine for placing items in equivalence classes *)
79
80functor EquivFun(A : EQUIV_ARG) : EQUIV =
81 struct
82 val sub = Array.sub
83 infix 9 sub
84
85 (* Our algorithm for finding equivalence class is simple. The basic
86 idea is to sort the entries and place duplicates entries in the same
87 equivalence class.
88
89 Let the original entry list be E. We map E to a list of a pairs
90 consisting of the entry and its position in E, where the positions
91 are numbered 0 to n-1. Call this list of pairs EP.
92
93 We then sort EP on the original entries. The second elements in the
94 pairs now specify a permutation that will return us to EP.
95
96 We then scan the sorted list to create a list R of representative
97 entries, a list P of integers which permutes the sorted list back to
98 the original list and a list SE of integers which gives the
99 equivalence class for the nth entry in the sorted list .
100
101 We then return the length of R, R, and the list that results from
102 permuting SE by P.
103 *)
104
105 type entry = A.entry
106
107 val gt = fn ((a,_),(b,_)) => A.gt(a,b)
108
109 structure Sort = MergeSortFun(type entry = A.entry * int
110 val gt = gt)
111 val assignIndex =
112 fn l =>
113 let fun loop (index,nil) = nil
114 | loop (index,h :: t) = (h,index) :: loop(index+1,t)
115 in loop (0,l)
116 end
117
118 local fun loop ((e,_) :: t, prev, class, R , SE) =
119 if A.eq(e,prev)
120 then loop(t,e,class,R, class :: SE)
121 else loop(t,e,class+1,e :: R, (class + 1) :: SE)
122 | loop (nil,_,_,R,SE) = (rev R, rev SE)
123 in val createEquivalences =
124 fn nil => (nil,nil)
125 | (e,_) :: t => loop(t, e, 0, [e],[0])
126 end
127
128 val inversePermute = fn permutation =>
129 fn nil => nil
130 | l as h :: _ =>
131 let val result = Array.array(length l,h)
132 fun loop (elem :: r, dest :: s) =
133 (Array.update(result,dest,elem); loop(r,s))
134 | loop _ = ()
135 fun listofarray i =
136 if i < Array.length result then
137 (result sub i) :: listofarray (i+1)
138 else nil
139 in loop (l,permutation); listofarray 0
140 end
141
142 fun makePermutation x = map (fn (_,b) => b) x
143
144 val equivalences = fn l =>
145 let val EP = assignIndex l
146 val sorted = Sort.sort EP
147 val P = makePermutation sorted
148 val (R, SE) = createEquivalences sorted
149 in (length R, inversePermute P SE, R)
150 end
151end
152
153functor ShrinkLrTableFun(structure LrTable : LR_TABLE) : SHRINK_LR_TABLE =
154 struct
155 structure LrTable = LrTable
156 open LrTable
157 val gtAction = fn (a,b) =>
158 case a
159 of SHIFT (STATE s) =>
160 (case b of SHIFT (STATE s') => s>s' | _ => true)
161 | REDUCE i => (case b of SHIFT _ => false | REDUCE i' => i>i'
162 | _ => true)
163 | ACCEPT => (case b of ERROR => true | _ => false)
164 | ERROR => false
165 structure ActionEntryList =
166 struct
167 type entry = (term, action) pairlist * action
168 local
169 fun eqlist (EMPTY, EMPTY) = true
170 | eqlist (PAIR (T t,d,r),PAIR(T t',d',r')) =
171 t=t' andalso d=d' andalso eqlist(r,r')
172 | eqlist _ = false
173 fun gtlist (PAIR _,EMPTY) = true
174 | gtlist (PAIR(T t,d,r),PAIR(T t',d',r')) =
175 t>t' orelse (t=t' andalso
176 (gtAction(d,d') orelse
177 (d=d' andalso gtlist(r,r'))))
178 | gtlist _ = false
179 in
180 fun eq ((l,a): entry, (l',a'): entry) =
181 a = a' andalso eqlist (l,l')
182 fun gt ((l,a): entry, (l',a'): entry) =
183 gtAction(a,a') orelse (a=a' andalso gtlist(l,l'))
184 end
185 end
186(* structure GotoEntryList =
187 struct
188 type entry = (nonterm,state) pairlist
189 val rec eq =
190 fn (EMPTY,EMPTY) => true
191 | (PAIR (t,d,r),PAIR(t',d',r')) =>
192 t=t' andalso d=d' andalso eq(r,r')
193 | _ => false
194 val rec gt =
195 fn (PAIR _,EMPTY) => true
196 | (PAIR(NT t,STATE d,r),PAIR(NT t',STATE d',r')) =>
197 t>t' orelse (t=t' andalso
198 (d>d' orelse (d=d' andalso gt(r,r'))))
199 | _ => false
200 end *)
201 structure EquivActionList = EquivFun(ActionEntryList)
202 val states = fn max =>
203 let fun f i=if i<max then STATE i :: f(i+1) else nil
204 in f 0
205 end
206 val length : ('a,'b) pairlist -> int =
207 fn l =>
208 let fun g(EMPTY,len) = len
209 | g(PAIR(_,_,r),len) = g(r,len+1)
210 in g(l,0)
211 end
212 val size : (('a,'b) pairlist * 'c) list -> int =
213 fn l =>
214 let val c = ref 0
215 in (app (fn (row,_) => c := !c + length row) l; !c)
216 end
217 val shrinkActionList =
218 fn (table,verbose) =>
219 case EquivActionList.equivalences
220 (map (describeActions table) (states (numStates table)))
221 of result as (_,_,l) => (result,if verbose then size l else 0)
222end;