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

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

Issue 63863004: Experimental parser: subclass for common code (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') | no next file » | 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
11 # with the distribution. 11 # with the distribution.
12 # * Neither the name of Google Inc. nor the names of its 12 # * Neither the name of Google Inc. nor the names of its
13 # contributors may be used to endorse or promote products derived 13 # contributors may be used to endorse or promote products derived
14 # from this software without specific prior written permission. 14 # from this software without specific prior written permission.
15 # 15 #
16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28 from types import TupleType 28 from types import TupleType
29 from transition_keys import TransitionKey 29 from transition_keys import TransitionKey
30 from automaton import *
30 from inspect import getmembers 31 from inspect import getmembers
31 32
32 class NfaState: 33 class NfaState(AutomatonState):
33 34
34 def __init__(self, node_number): 35 def __init__(self, node_number):
36 super(NfaState, self).__init__(node_number)
35 self.__transitions = {} 37 self.__transitions = {}
36 self.__unclosed = set() 38 self.__unclosed = set()
37 self.__node_number = node_number
38 self.__epsilon_closure = None 39 self.__epsilon_closure = None
39 self.__transition_action = None 40 self.__transition_action = None
40 41
41 def node_number(self):
42 return self.__node_number
43
44 def epsilon_closure(self): 42 def epsilon_closure(self):
45 return self.__epsilon_closure 43 return self.__epsilon_closure
46 44
47 def set_epsilon_closure(self, closure): 45 def set_epsilon_closure(self, closure):
48 assert self.is_closed() 46 assert self.is_closed()
49 assert self.__epsilon_closure == None 47 assert self.__epsilon_closure == None
50 self.__epsilon_closure = frozenset(closure) 48 self.__epsilon_closure = frozenset(closure)
51 49
52 def set_transition_action(self, action): 50 def set_transition_action(self, action):
53 assert not self.is_closed() 51 assert not self.is_closed()
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 f = lambda acc, (k, vs): acc | vs if match_func(k, value) else acc 100 f = lambda acc, (k, vs): acc | vs if match_func(k, value) else acc
103 return reduce(f, self.__transitions.items(), set()) 101 return reduce(f, self.__transitions.items(), set())
104 102
105 def char_matches(self, value): 103 def char_matches(self, value):
106 return self.__matches(lambda k, v : k.matches_char(v), value) 104 return self.__matches(lambda k, v : k.matches_char(v), value)
107 105
108 def key_matches(self, value): 106 def key_matches(self, value):
109 return self.__matches(lambda k, v : k.matches_key(v), value) 107 return self.__matches(lambda k, v : k.matches_key(v), value)
110 108
111 def __str__(self): 109 def __str__(self):
112 return "NfaState(" + str(self.__node_number) + ")" 110 return "NfaState(" + str(self.node_number()) + ")"
113 111
114 @staticmethod 112 @staticmethod
115 def gather_transition_keys(state_set): 113 def gather_transition_keys(state_set):
116 f = lambda acc, state: acc | set(state.__transitions.keys()) 114 f = lambda acc, state: acc | set(state.__transitions.keys())
117 return TransitionKey.disjoint_keys(reduce(f, state_set, set())) 115 return TransitionKey.disjoint_keys(reduce(f, state_set, set()))
118 116
119 class NfaBuilder: 117 class NfaBuilder:
120 118
121 def __init__(self): 119 def __init__(self):
122 self.__node_number = 0 120 self.__node_number = 0
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
248 __modifer_map = { 246 __modifer_map = {
249 '+': 'ONE_OR_MORE', 247 '+': 'ONE_OR_MORE',
250 '?': 'ZERO_OR_ONE', 248 '?': 'ZERO_OR_ONE',
251 '*': 'ZERO_OR_MORE', 249 '*': 'ZERO_OR_MORE',
252 } 250 }
253 251
254 @staticmethod 252 @staticmethod
255 def apply_modifier(modifier, graph): 253 def apply_modifier(modifier, graph):
256 return (NfaBuilder.__modifer_map[modifier], graph) 254 return (NfaBuilder.__modifer_map[modifier], graph)
257 255
258 class Nfa: 256 class Nfa(Automaton):
259 257
260 def __init__(self, start, end, nodes_created): 258 def __init__(self, start, end, nodes_created):
259 super(Nfa, self).__init__()
261 self.__start = start 260 self.__start = start
262 self.__end = end 261 self.__end = end
263 self.__epsilon_closure_computed = False 262 self.__epsilon_closure_computed = False
264 self.__verify(nodes_created) 263 self.__verify(nodes_created)
265 264
266 @staticmethod
267 def __visit_edges(edge, compute_next_edge, visitor, state):
268 visited = set()
269 while edge:
270 f = lambda (next_edge, state), node: (
271 next_edge | compute_next_edge(node),
272 visitor(node, state))
273 (next_edge, state) = reduce(f, edge, (set(), state))
274 visited |= edge
275 edge = next_edge - visited
276 return state
277
278 def __visit_all_edges(self, visitor, state): 265 def __visit_all_edges(self, visitor, state):
279 edge = set([self.__start]) 266 edge = set([self.__start])
280 next_edge = lambda node: node.next_states(lambda x : True) 267 next_edge = lambda node: node.next_states(lambda x : True)
281 return Nfa.__visit_edges(edge, next_edge, visitor, state) 268 return self.visit_edges(edge, next_edge, visitor, state)
282 269
283 def __verify(self, nodes_created): 270 def __verify(self, nodes_created):
284 def f(node, node_list): 271 def f(node, node_list):
285 assert node.is_closed() 272 assert node.is_closed()
286 node_list.append(node) 273 node_list.append(node)
287 return node_list 274 return node_list
288 node_list = self.__visit_all_edges(f, []) 275 node_list = self.__visit_all_edges(f, [])
289 assert len(node_list) == nodes_created 276 assert len(node_list) == nodes_created
290 277
291 def __compute_epsilon_closures(self): 278 def __compute_epsilon_closures(self):
292 if self.__epsilon_closure_computed: 279 if self.__epsilon_closure_computed:
293 return 280 return
294 self.__epsilon_closure_computed = True 281 self.__epsilon_closure_computed = True
295 def outer(node, state): 282 def outer(node, state):
296 def inner(node, closure): 283 def inner(node, closure):
297 closure.add(node) 284 closure.add(node)
298 return closure 285 return closure
299 is_epsilon = lambda k: k == TransitionKey.epsilon() 286 is_epsilon = lambda k: k == TransitionKey.epsilon()
300 next_edge = lambda node : node.next_states(is_epsilon) 287 next_edge = lambda node : node.next_states(is_epsilon)
301 edge = next_edge(node) 288 edge = next_edge(node)
302 closure = Nfa.__visit_edges(edge, next_edge, inner, set()) 289 closure = self.visit_edges(edge, next_edge, inner, set())
303 node.set_epsilon_closure(closure) 290 node.set_epsilon_closure(closure)
304 self.__visit_all_edges(outer, None) 291 self.__visit_all_edges(outer, None)
305 292
306 @staticmethod 293 @staticmethod
307 def __close(states): 294 def __close(states):
308 f = lambda acc, node: acc | node.epsilon_closure() 295 f = lambda acc, node: acc | node.epsilon_closure()
309 return reduce(f, states, set(states)) 296 return reduce(f, states, set(states))
310 297
311 def matches(self, string): 298 def matches(self, string):
312 self.__compute_epsilon_closures() 299 self.__compute_epsilon_closures()
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 dfa_nodes[name]['transitions'][key] = (transition_state, action) 342 dfa_nodes[name]['transitions'][key] = (transition_state, action)
356 return name 343 return name
357 344
358 def compute_dfa(self): 345 def compute_dfa(self):
359 self.__compute_epsilon_closures() 346 self.__compute_epsilon_closures()
360 dfa_nodes = {} 347 dfa_nodes = {}
361 start_name = self.__to_dfa(set([self.__start]), dfa_nodes, self.__end) 348 start_name = self.__to_dfa(set([self.__start]), dfa_nodes, self.__end)
362 return (start_name, dfa_nodes) 349 return (start_name, dfa_nodes)
363 350
364 def to_dot(self): 351 def to_dot(self):
365 352 iterator = lambda visitor, state: self.__visit_all_edges(visitor, state)
366 def f(node, node_content): 353 return self.generate_dot(self.__start, set([self.__end]), iterator)
367 for key, values in node.transitions().items():
368 if key == TransitionKey.epsilon():
369 key = "ε"
370 key = str(key).replace('\\', '\\\\')
371 for value in values:
372 if value[1]:
373 node_content.append(
374 " S_%d -> S_%d [ label = \"%s {%s} -> %s\" ];" %
375 (node.node_number(), value[0].node_number(), key, value[1][1],
376 value[1][2]))
377 else:
378 node_content.append(
379 " S_%d -> S_%d [ label = \"%s\" ];" %
380 (node.node_number(), value[0].node_number(), key))
381 return node_content
382
383 node_content = self.__visit_all_edges(f, [])
384
385 return '''
386 digraph finite_state_machine {
387 rankdir=LR;
388 node [shape = circle, style=filled, bgcolor=lightgrey]; S_%s
389 node [shape = doublecircle, style=unfilled]; S_%s
390 node [shape = circle];
391 %s
392 }
393 ''' % (self.__start.node_number(),
394 self.__end.node_number(),
395 "\n".join(node_content))
OLDNEW
« no previous file with comments | « tools/lexer_generator/dfa.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698