Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(364)

Side by Side Diff: tools/lexer_generator/nfa.py

Issue 54223002: Experimental parser: cleanup (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/parser
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/lexer_generator/dfa.py ('k') | tools/lexer_generator/transition_keys.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2013 the V8 project authors. All rights reserved. 1 # Copyright 2013 the V8 project authors. All rights reserved.
2 # Redistribution and use in source and binary forms, with or without 2 # Redistribution and use in source and binary forms, with or without
3 # modification, are permitted provided that the following conditions are 3 # modification, are permitted provided that the following conditions are
4 # met: 4 # met:
5 # 5 #
6 # * Redistributions of source code must retain the above copyright 6 # * Redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer. 7 # notice, this list of conditions and the following disclaimer.
8 # * Redistributions in binary form must reproduce the above 8 # * Redistributions in binary form must reproduce the above
9 # copyright notice, this list of conditions and the following 9 # copyright notice, this list of conditions and the following
10 # disclaimer in the documentation and/or other materials provided 10 # disclaimer in the documentation and/or other materials provided
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 assert self.is_closed() 47 assert self.is_closed()
48 assert self.__epsilon_closure == None 48 assert self.__epsilon_closure == None
49 self.__epsilon_closure = frozenset(closure) 49 self.__epsilon_closure = frozenset(closure)
50 50
51 def transitions(self): 51 def transitions(self):
52 assert self.is_closed() 52 assert self.is_closed()
53 return self.__transitions 53 return self.__transitions
54 54
55 def get_epsilon_transitions(self): 55 def get_epsilon_transitions(self):
56 key = TransitionKey.epsilon(); 56 key = TransitionKey.epsilon();
57 if not self.__transitions.has_key(key): return frozenset() 57 if not key in self.__transitions: return frozenset()
58 return frozenset(self.__transitions[key]) 58 return frozenset(self.__transitions[key])
59 59
60 def __add_transition(self, key, value): 60 def __add_transition(self, key, value):
61 if value == None: 61 if value == None:
62 assert not self.is_closed(), "already closed" 62 assert not self.is_closed(), "already closed"
63 self.__unclosed.add(key) 63 self.__unclosed.add(key)
64 return 64 return
65 if not self.__transitions.has_key(key): 65 if not key in self.__transitions:
66 self.__transitions[key] = set() 66 self.__transitions[key] = set()
67 self.__transitions[key].add(value) 67 self.__transitions[key].add(value)
68 68
69 def add_unclosed_transition(self, key): 69 def add_unclosed_transition(self, key):
70 assert key != TransitionKey.epsilon() 70 assert key != TransitionKey.epsilon()
71 self.__add_transition(key, None) 71 self.__add_transition(key, None)
72 72
73 def add_epsilon_transition(self, state): 73 def add_epsilon_transition(self, state):
74 assert state != None 74 assert state != None
75 self.__add_transition(TransitionKey.epsilon(), state) 75 self.__add_transition(TransitionKey.epsilon(), state)
76 76
77 def is_closed(self): 77 def is_closed(self):
78 return self.__unclosed == None 78 return self.__unclosed == None
79 79
80 def close(self, end): 80 def close(self, end):
81 assert not self.is_closed() 81 assert not self.is_closed()
82 if end == None: 82 if end == None:
83 assert not self.__unclosed 83 assert not self.__unclosed
84 else: 84 else:
85 for key in self.__unclosed: 85 for key in self.__unclosed:
86 self.__add_transition(key, end) 86 self.__add_transition(key, end)
87 if not self.__unclosed: 87 if not self.__unclosed:
88 self.add_epsilon_transition(end) 88 self.add_epsilon_transition(end)
89 self.__unclosed = None 89 self.__unclosed = None
90 90
91 def __matches(self, match_func, value): 91 def __matches(self, match_func, value):
92 matches = set() 92 f = lambda acc, (k, vs): acc | vs if match_func(k, value) else acc
93 for key, values in self.__transitions.items(): 93 return reduce(f, self.__transitions.items(), set())
94 if match_func(key, value):
95 matches |= values
96 return matches
97 94
98 def char_matches(self, value): 95 def char_matches(self, value):
99 return self.__matches((lambda k, v : k.matches_char(v)), value) 96 return self.__matches((lambda k, v : k.matches_char(v)), value)
100 97
101 def key_matches(self, value): 98 def key_matches(self, value):
102 return self.__matches((lambda k, v : k.matches_key(v)), value) 99 return self.__matches((lambda k, v : k.matches_key(v)), value)
103 100
104 @staticmethod 101 @staticmethod
105 def gather_transition_keys(state_set): 102 def gather_transition_keys(state_set):
106 keys = set() 103 f = lambda acc, state: acc | set(state.__transitions.keys())
107 for state in state_set: 104 return TransitionKey.merge_key_set(reduce(f, state_set, set()))
108 keys |= set(state.__transitions.keys())
109 return TransitionKey.merge_key_set(keys)
110 105
111 class NfaBuilder: 106 class NfaBuilder:
112 107
113 def __init__(self): 108 def __init__(self):
114 self.__operation_map = {} 109 self.__operation_map = {}
115 self.__members = getmembers(self) 110 self.__members = getmembers(self)
116 111
117 def __new_state(self): 112 def __new_state(self):
118 node_number = self.node_number 113 node_number = self.node_number
119 self.node_number = self.node_number + 1 114 self.node_number = self.node_number + 1
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
166 161
167 def __not_class(self, graph): 162 def __not_class(self, graph):
168 return self.__key_state(TransitionKey.character_class(True, graph[1])) 163 return self.__key_state(TransitionKey.character_class(True, graph[1]))
169 164
170 def __any(self, graph): 165 def __any(self, graph):
171 return self.__key_state(TransitionKey.any()) 166 return self.__key_state(TransitionKey.any())
172 167
173 def __process(self, graph): 168 def __process(self, graph):
174 assert type(graph) == TupleType 169 assert type(graph) == TupleType
175 method = "_NfaBuilder__" + graph[0].lower() 170 method = "_NfaBuilder__" + graph[0].lower()
176 if (not self.__operation_map.has_key(method)): 171 if not method in self.__operation_map:
177 matches = [func for (name, func) in self.__members if name == method] 172 matches = filter((lambda (name, func): name == method), self.__members)
178 assert len(matches) == 1 173 assert len(matches) == 1
179 self.__operation_map[method] = matches[0] 174 self.__operation_map[method] = matches[0][1]
180 return self.__operation_map[method](graph) 175 return self.__operation_map[method](graph)
181 176
182 def __patch_ends(self, ends, new_end): 177 def __patch_ends(self, ends, new_end):
183 for end in ends: 178 for end in ends:
184 end.close(new_end) 179 end.close(new_end)
185 180
186 def nfa(self, graph): 181 def nfa(self, graph):
187 self.node_number = 0 182 self.node_number = 0
188 (start, ends) = self.__process(graph) 183 (start, ends) = self.__process(graph)
189 end = self.__new_state() 184 end = self.__new_state()
190 self.__patch_ends(ends, end) 185 self.__patch_ends(ends, end)
191 end.close(None) 186 end.close(None)
192 return Nfa(start, end, self.node_number) 187 return Nfa(start, end, self.node_number)
193 188
194 class Nfa: 189 class Nfa:
195 190
196 def __init__(self, start, end, nodes_created): 191 def __init__(self, start, end, nodes_created):
197 self.__start = start 192 self.__start = start
198 self.__end = end 193 self.__end = end
199 self.__epsilon_closure_computed = False 194 self.__epsilon_closure_computed = False
200 self.__verify(nodes_created) 195 self.__verify(nodes_created)
201 196
202 @staticmethod 197 @staticmethod
203 def __visit_edges(edge, compute_next_edge, visitor, state): 198 def __visit_edges(edge, compute_next_edge, visitor, state):
204 visited = set() 199 visited = set()
205 while edge: 200 while edge:
206 next_edge = set() 201 f = lambda (next_edge, state), node: (
207 for node in edge: 202 next_edge | compute_next_edge(node),
208 next_edge |= compute_next_edge(node) 203 visitor(node, state))
209 state = visitor(node, state) 204 (next_edge, state) = reduce(f, edge, (set(), state))
210 visited |= edge 205 visited |= edge
211 edge = next_edge - visited 206 edge = next_edge - visited
212 return state 207 return state
213 208
214 def __visit_all_edges(self, function, state): 209 def __visit_all_edges(self, visitor, state):
215 edge = set([self.__start]) 210 edge = set([self.__start])
216 def next_edge(node): 211 def next_edge(node):
217 next = set() 212 f = lambda acc, values: acc | values
218 for values in node.transitions().values(): 213 return reduce(f, node.transitions().values(), set())
219 next |= values 214 return Nfa.__visit_edges(edge, next_edge, visitor, state)
220 return next
221 return Nfa.__visit_edges(edge, next_edge, function, state)
222 215
223 def __verify(self, nodes_created): 216 def __verify(self, nodes_created):
224 def f(node, node_list): 217 def f(node, node_list):
225 assert node.is_closed() 218 assert node.is_closed()
226 node_list.append(node) 219 node_list.append(node)
227 return node_list 220 return node_list
228 node_list = self.__visit_all_edges(f, []) 221 node_list = self.__visit_all_edges(f, [])
229 assert len(node_list) == nodes_created 222 assert len(node_list) == nodes_created
230 223
231 def __compute_epsilon_closures(self): 224 def __compute_epsilon_closures(self):
232 if self.__epsilon_closure_computed: 225 if self.__epsilon_closure_computed:
233 return 226 return
234 self.__epsilon_closure_computed = True 227 self.__epsilon_closure_computed = True
235 def outer(node, state): 228 def outer(node, state):
236 def inner(node, closure): 229 def inner(node, closure):
237 closure.add(node) 230 closure.add(node)
238 return closure 231 return closure
239 next_edge = lambda node : node.get_epsilon_transitions() 232 next_edge = lambda node : node.get_epsilon_transitions()
240 edge = next_edge(node) 233 edge = next_edge(node)
241 closure = Nfa.__visit_edges(edge, next_edge, inner, set()) 234 closure = Nfa.__visit_edges(edge, next_edge, inner, set())
242 node.set_epsilon_closure(closure) 235 node.set_epsilon_closure(closure)
243 self.__visit_all_edges(outer, None) 236 self.__visit_all_edges(outer, None)
244 237
245 @staticmethod 238 @staticmethod
246 def __close(states): 239 def __close(states):
247 closure = set(states) 240 f = lambda acc, node: acc | node.epsilon_closure()
248 for node in states: 241 return reduce(f, states, set(states))
249 closure |= node.epsilon_closure()
250 return closure
251 242
252 def matches(self, string): 243 def matches(self, string):
253 self.__compute_epsilon_closures() 244 self.__compute_epsilon_closures()
254 valid_states = Nfa.__close(set([self.__start])) 245 valid_states = Nfa.__close(set([self.__start]))
255 for c in string: 246 for c in string:
256 next_valid_states = set() 247 f = lambda acc, state: acc | state.char_matches(c)
257 for valid_state in valid_states: 248 valid_states = Nfa.__close(reduce(valid_states, f, set()))
258 next_valid_states |= valid_state.char_matches(c)
259 valid_states = Nfa.__close(next_valid_states)
260 if not valid_states: 249 if not valid_states:
261 return False 250 return False
262 return self.__end in valid_states 251 return self.__end in valid_states
263 252
264 @staticmethod 253 @staticmethod
265 def __to_dfa(nfa_state_set, dfa_builder): 254 def __to_dfa(nfa_state_set, builder):
266 nfa_state_set = Nfa.__close(nfa_state_set) 255 nfa_state_set = Nfa.__close(nfa_state_set)
267 name = str([x.node_number() for x in nfa_state_set]) 256 name = str([x.node_number() for x in nfa_state_set])
268 (dfa_nodes, end_nodes, end_node) = dfa_builder 257 (dfa_nodes, end_nodes, end_node) = builder
269 if dfa_nodes.has_key(name): 258 if name in dfa_nodes:
270 return name 259 return name
271 dfa_node = {} 260 dfa_node = {}
272 dfa_nodes[name] = dfa_node 261 dfa_nodes[name] = dfa_node
273 for key in NfaState.gather_transition_keys(nfa_state_set): 262 for key in NfaState.gather_transition_keys(nfa_state_set):
274 reachable_set = set() 263 f = lambda acc, state: acc | state.key_matches(key)
275 for nfa_state in nfa_state_set: 264 dfa_node[key] = Nfa.__to_dfa(reduce(f, nfa_state_set, set()), builder)
276 reachable_set |= nfa_state.key_matches(key)
277 dfa_node[key] = Nfa.__to_dfa(reachable_set, dfa_builder)
278 if end_node in nfa_state_set: 265 if end_node in nfa_state_set:
279 end_nodes.add(name) 266 end_nodes.add(name)
280 return name 267 return name
281 268
282 def compute_dfa(self): 269 def compute_dfa(self):
283 self.__compute_epsilon_closures() 270 self.__compute_epsilon_closures()
284 dfa_nodes = {} 271 dfa_nodes = {}
285 end_nodes = set() 272 end_nodes = set()
286 dfa_builder = (dfa_nodes, end_nodes, self.__end) 273 dfa_builder = (dfa_nodes, end_nodes, self.__end)
287 start_name = self.__to_dfa(set([self.__start]), dfa_builder) 274 start_name = self.__to_dfa(set([self.__start]), dfa_builder)
(...skipping 17 matching lines...) Expand all
305 digraph finite_state_machine { 292 digraph finite_state_machine {
306 rankdir=LR; 293 rankdir=LR;
307 node [shape = circle, style=filled, bgcolor=lightgrey]; S_%s 294 node [shape = circle, style=filled, bgcolor=lightgrey]; S_%s
308 node [shape = doublecircle, style=unfilled]; S_%s 295 node [shape = doublecircle, style=unfilled]; S_%s
309 node [shape = circle]; 296 node [shape = circle];
310 %s 297 %s
311 } 298 }
312 ''' % (self.__start.node_number(), 299 ''' % (self.__start.node_number(),
313 self.__end.node_number(), 300 self.__end.node_number(),
314 "\n".join(node_content)) 301 "\n".join(node_content))
OLDNEW
« no previous file with comments | « tools/lexer_generator/dfa.py ('k') | tools/lexer_generator/transition_keys.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698