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

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

Issue 171713005: Experimental parser: add backtracking (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/parser
Patch Set: Created 6 years, 10 months 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/gyp/v8.gyp ('k') | tools/lexer_generator/code_generator.jinja » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright 2014 the V8 project authors. All rights reserved.
2 # Redistribution and use in source and binary forms, with or without
3 # modification, are permitted provided that the following conditions are
4 # met:
5 #
6 # * Redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer.
8 # * Redistributions in binary form must reproduce the above
9 # copyright notice, this list of conditions and the following
10 # disclaimer in the documentation and/or other materials provided
11 # with the distribution.
12 # * Neither the name of Google Inc. nor the names of its
13 # contributors may be used to endorse or promote products derived
14 # from this software without specific prior written permission.
15 #
16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
27
28 from transition_key import TransitionKey
29 from automaton import Term, Action, Automaton
30 from dfa import Dfa
31
32 class BacktrackingGenerator(object):
33
34 @staticmethod
35 def generate(dfa, default_action):
36 return BacktrackingGenerator(dfa, default_action, None).__generate()
37
38 def __init__(self, dfa, default_action, log):
39 self.__dfa = dfa
40 self.__default_action = default_action
41 self.__log = log
42
43 def __generate(self):
44 dfa = self.__dfa
45 default_action = self.__default_action
46 terminal_set = dfa.terminal_set()
47 # Collect states that terminate currently.
48 action_states = {}
49 omega_states = set()
50 def f(state, acc):
51 omega_state = state.omega_transition()
52 if omega_state == None:
53 if not state in terminal_set:
54 state.key_iter().next() # should have at least one transition
55 return
56 assert omega_state in terminal_set
57 assert not state in terminal_set
58 assert not list(omega_state.key_iter())
59 omega_states.add(omega_state)
60 match_action = omega_state.action()
61 if not match_action:
62 match_action = default_action
63 action_states[state] = match_action
64 dfa.visit_all_states(f)
65 assert omega_states == terminal_set
66 # Find nodes that need backtracking edges
67 incoming_transitions = dfa.build_incoming_transitions_map()
68 backtracking_map = {}
69 store_states = set()
70 # Start node may be an edge case.
71 start_state = dfa.start_state()
72 if (not start_state in incoming_transitions and
73 not start_state in action_states):
74 action_states[start_state] = default_action
75 for state in incoming_transitions.iterkeys():
76 if state in omega_states or state in action_states:
77 continue
78 assert not state.omega_transition()
79 seen = set([state])
80 unchecked = set([state])
81 match_edge = set()
82 while unchecked:
83 next = set()
84 for unchecked_state in unchecked:
85 if not unchecked_state in incoming_transitions:
86 assert unchecked_state == start_state
87 match_edge.add(unchecked_state)
88 continue
89 for (incoming_key, incoming_state) in incoming_transitions[unchecked_s tate]:
90 assert not incoming_state in omega_states
91 assert not incoming_key == TransitionKey.omega()
92 if incoming_state in seen:
93 continue
94 if incoming_state in action_states:
95 match_edge.add(incoming_state)
96 seen.add(incoming_state)
97 else:
98 next.add(incoming_state)
99 seen |= unchecked
100 unchecked = next - seen
101 # accumulate unique actions
102 actions = set(map(lambda x : action_states[x].term(), match_edge))
103 assert actions
104 if not len(actions) == 1:
105 # TODO(dcarney): need to warn here after second pass
106 # actions = set([default_action])
107 continue
108 action = iter(actions).next()
109 # don't install default actions
110 if action == default_action.term():
111 continue
112 store_states |= match_edge
113 backtracking_map[state.node_number()] = (action, match_edge)
114 def install_backtracking_action(new_states, node_number):
115 omega_state_id = str(node_number) + '_bt'
116 key = TransitionKey.omega()
117 new_states[str(node_number)]['transitions'][key] = omega_state_id
118 # install new state
119 old_action = backtracking_map[node_number][0]
120 new_states[omega_state_id] = {
121 'transitions' : {},
122 'action' : Action(Term('backtrack', old_action), 0),
123 'terminal' : True,
124 }
125 def new_state_action(old_state):
126 action = old_state.action()
127 if not old_state in store_states:
128 return action
129 term = Term('store_lexing_state')
130 if action:
131 # TODO(dcarney): split target state instead
132 term = Term('chain', term, action.term())
133 return Action(term, 0)
134 # Now generate the new dfa.
135 def convert(old_state, new_states):
136 node_number = old_state.node_number()
137 # Clone existing state.
138 new_states[str(node_number)] = {
139 'transitions' : {
140 k : str(v.node_number()) for (k, v) in old_state.key_state_iter() },
141 'action' : new_state_action(old_state),
142 'terminal' : old_state in terminal_set
143 }
144 # install a backtracking action
145 if node_number in backtracking_map:
146 install_backtracking_action(new_states, node_number)
147 return new_states
148 new_states = dfa.visit_all_states(convert, {})
149 return Dfa(dfa.encoding(), str(start_state.node_number()), new_states)
OLDNEW
« no previous file with comments | « tools/gyp/v8.gyp ('k') | tools/lexer_generator/code_generator.jinja » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698