|
|
1.1 root 1:
2: (* April 1989, Jussi Rintanen, Helsinki University of Technology *)
3:
4: (* This is the signature of a specification generated by ML-Twig *)
5:
6: signature TWIG_SPECIFICATION =
7: sig
8: type cost and tree and result
9: eqtype rule and symbol
10:
11: val get_subtrees : tree -> tree list
12: val node_value : tree -> symbol
13: val cost_less : cost * cost -> bool
14:
15: datatype skeletal = Skeleton of rule * cost * tree * skeletal list
16:
17: exception MatchAbort and InternalError of string
18:
19: val execute_cost : rule * tree * skeletal list -> cost
20: val execute : skeletal -> result
21: val getreplacement : result -> tree
22: val rewriterule : rule -> bool
23: val matches : rule -> int
24:
25: (* Definitions for unit rule matches and the tree pattern matching automaton *)
26:
27: eqtype state
28:
29: datatype matchtree = Chain of rule * symbol * matchtree list
30: val unitmatches : symbol -> matchtree list
31:
32: val childsymbol : int -> symbol
33: val initialstate : state
34: val go : state * symbol -> state
35: val go_f : state * symbol -> (int * rule * symbol) list
36: end;
37:
38: (* This functor maps a specification to a structure containing a complete tree
39: processor program and associated definitions. *)
40:
41: functor MAKEtreeprocessor ( Specification : TWIG_SPECIFICATION) =
42: struct
43: structure Spec : TWIG_SPECIFICATION = Specification
44:
45: open Spec
46:
47: exception NoCover
48:
49: fun internal s = raise InternalError ("FATAL:"^s)
50:
51: (* The structure representation implements a data type for
52: maintaining information of the matching tree pattern
53: matching process. The actual implementation is left
54: unspecified in the signature. However, because of the
55: match mode rewrite, an implementation without side effects
56: is required. *)
57:
58: structure Representation :
59: sig
60: type 's table
61: structure Spec : TWIG_SPECIFICATION
62:
63: val empty_table : unit -> 's table
64: val new_level : 's table -> 's table
65: val contribute0 : 's table * int * Spec.rule * Spec.symbol -> 's table
66: val contribute1 : 's table * int * Spec.rule * Spec.symbol * 's -> 's table
67: val get_level : 's table -> (Spec.symbol * (Spec.rule * int * 's list) list) list * 's table
68: end
69: =
70: struct
71:
72: (* The table is a list, where the head contains the match information
73: for the current node of the user tree. The tail of the list
74: contains the match information for the ancestors of the current
75: node. The match information for a node is an ordered list of pairs,
76: where the first member is the number of the non-terminal, to which
77: the matches in the second member contribute.
78: The matches for a non-terminal are in an ordered list of triples
79: rule * number of matches * children skeletons. *)
80:
81: structure Spec = Spec
82:
83: open Spec
84:
85: type 's table = (symbol * (rule * int * 's list) list) list list
86: fun empty_table () = []
87: fun new_level l = []::l
88: fun insert0' (r:rule,nil) = [(r,1,[])]
89: | insert0' (r:rule,(h as (r',m',s'))::hs) =
90: if r' <> r
91: then h :: insert0' (r,hs)
92: else (r,m'+1,s')::hs
93: fun insert0 (nil,r,t:symbol) = [(t,[(r,1,[])])]
94: | insert0 ((h as (t',a))::hs,r,t) =
95: if t' <> t
96: then h :: insert0 (hs,r,t)
97: else (t,insert0' (r,a))::hs
98: fun insert1' (r:rule,s,nil) = [(r,1,[s])]
99: | insert1' (r,s,(h as (r',m',s'))::hs) =
100: if r' <> r
101: then h :: insert1' (r,s,hs)
102: else (r,m'+1,s::s')::hs
103: fun insert1 (nil,r,t:symbol,s) = [(t,[(r,1,[s])])]
104: | insert1 ((h as (t',a))::hs,r,t,s) =
105: if t' <> t
106: then h :: insert1 (hs,r,t,s)
107: else (t,insert1' (r,s,a)):: hs
108: fun contribute0 (a::l,1,r,t) = insert0 (a,r,t) :: l
109: | contribute0 (a::l,n,r,t) = a::contribute0(l,n-1,r,t)
110: | contribute0 _ = internal "run out of levels"
111: fun contribute1 (a::l,1,r,t,s) = insert1(a,r,t,s) :: l
112: | contribute1 (a::l,n,r,t,s) = a::contribute1(l,n-1,r,t,s)
113: | contribute1 _ = internal "run out of levels"
114: fun get_level (a::l) = (a,l)
115: | get_level _ = internal "run out of levels"
116: end
117:
118: open Representation
119:
120: (* Utility functions *)
121:
122: val accum = revfold
123:
124: fun cost (Skeleton(_,c,_,_)) = c
125:
126: fun insert (i:symbol, s, nil) = [(i,s)]
127: | insert (i, s, (head as (i',s'))::rest) =
128: if i = i'
129: then
130: if cost_less (cost s,cost s')
131: then (i,s)::rest
132: else head::rest
133: else head :: (insert (i,s,rest))
134:
135: fun build_skeleton (ar as (r,t,cs)) = Skeleton (r,execute_cost ar,t,rev cs)
136:
137: (* get_closure takes four arguments. The first is a unit rule tree.
138: The second is the sub-skeleton in the unit rule match. The third
139: is the ir-tree of the current node, and the fourth is the list
140: of skeletons generated so far. The skeleton list consists of pairs:
141: the first element is the number of the non-terminal of the rule,
142: and the second element is the skeleton. *)
143:
144: fun get_closure (ct,ss,t,ac) =
145: accum (fn (Chain(r,n,cs),ac') =>
146: let val skel = build_skeleton(r,t,ss)
147: in
148: get_closure (cs,[skel],t,insert (n,skel,ac'))
149: end handle MatchAbort => ac')
150: ct ac
151:
152: fun someone (t,still_best, nil) = [still_best]
153: | someone (t,still_best, (r,m,cs)::rest) =
154: if matches r = m
155: then
156: let val skel = build_skeleton (r,t,cs)
157: in someone (t,if cost_less (cost skel,cost still_best)
158: then skel
159: else still_best,rest)
160: end handle MatchAbort => someone (t,still_best,rest)
161: else someone(t,still_best,rest)
162:
163: fun still_no_one (t,nil) = nil
164: | still_no_one (t,(r,m,cs)::rest) =
165: if matches r = m
166: then someone (t,build_skeleton (r,t,cs),rest)
167: handle MatchAbort => still_no_one (t,rest)
168: else still_no_one (t,rest)
169:
170: fun leave_best_alone (t,nil) = internal "matcher state inconsistent. lba."
171: | leave_best_alone (t,l) = still_no_one (t,l)
172:
173: fun skeletons_of (state,node,tab) =
174: let val (t,s) =
175: case get_subtrees node of
176: nil =>
177: let val tab' =
178: accum (fn ((h,r,n),t) => contribute0 (t,h-1,r,n))
179: (go_f(state, node_value node)) tab
180: in
181: (tab', get_closure ((unitmatches o node_value) node,[],node,[]))
182: end
183: | ls =>
184: let val state' = go (state, node_value node)
185: val (table, _) =
186: accum (fn (l,(t,i)) =>
187: let val state'' = go (state',childsymbol i)
188: val (t', ss) = skeletons_of (state'',l,t)
189: in (accum (fn ((r,s),t'') =>
190: let val finals = go_f (state'',r)
191: in
192: accum
193: (fn ((h,r,n),t''') =>
194: contribute1 (t''',h-1,r,n,s))
195: finals t''
196: end) ss t',i+1)
197: end)
198: ls
199: (new_level tab, 1)
200: val (toplevel, table') = get_level table
201: in
202: (table',
203: let val unclosurized = accum (fn ((_,nil),l) => l | ((n,[e]),l) => (n,e)::l | _ => internal "inconsistency. 01l")
204: (map (fn (n,sl) => (n,leave_best_alone (node,sl))) toplevel)
205: nil
206: in
207: accum (fn ((n,s),al) =>
208: get_closure (unitmatches n,[s],node,al)) unclosurized unclosurized
209: end)
210: end
211: in
212: case s of
213: [] => (t,[])
214: | [(_,S as Skeleton(r,_,_,_))] =>
215: if rewriterule r
216: then skeletons_of(state,(getreplacement o execute) S,tab)
217: else (t,s)
218: | (_,sk)::rest =>
219: let val best as Skeleton (r,_,_,_) =
220: accum (fn ((n,s),bs) =>
221: if cost_less (cost s,cost bs) then s else bs) rest sk
222: in
223: if rewriterule r
224: then skeletons_of(state,
225: (getreplacement o execute) best,
226: tab)
227: else (t,s)
228: end
229: end
230:
231: fun translate t = execute
232: (case (skeletons_of (initialstate,t,empty_table())) of
233: (_,(_,s)::t) =>
234: accum (fn ((n,s),bs) =>
235: if cost_less (cost s,cost bs) then s else bs) t s
236: | (_,nil) => raise NoCover)
237:
238: end;
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.