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

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

Issue 184423002: Experimental parser: cleanup BacktrackingGenerator (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/parser
Patch Set: Created 6 years, 9 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 | « no previous file | 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 2014 the V8 project authors. All rights reserved. 1 # Copyright 2014 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 15 matching lines...) Expand all
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 transition_key import TransitionKey 28 from transition_key import TransitionKey
29 from automaton import Term, Action, Automaton 29 from automaton import Term, Action, Automaton
30 from dfa import Dfa 30 from dfa import Dfa
31 31
32 class BacktrackingGenerator(object): 32 class BacktrackingGenerator(object):
33 33
34 @staticmethod 34 @staticmethod
35 def generate(dfa, default_action): 35 def generate(dfa, default_action):
36 return BacktrackingGenerator(dfa, default_action, None).__generate() 36 return BacktrackingGenerator(dfa, default_action).__generate()
37 37
38 def __init__(self, dfa, default_action, log): 38 def __init__(self, dfa, default_action):
39 self.__dfa = dfa 39 self.__dfa = dfa
40 self.__default_action = default_action 40 self.__default_action = default_action
41 self.__log = log
42 41
43 @staticmethod 42 @staticmethod
44 def __process_error_states(dfa, error_map, action_state_map): 43 def __print_ambiguous_paths(dfa, error_map, action_state_map):
45 path_map = { k : [] for k in error_map.iterkeys()} 44 path_map = { k : [] for k in error_map.iterkeys()}
46 error_states = set(error_map.iterkeys()) 45 error_states = set(error_map.iterkeys())
47 for path, states_in_path, terminal in dfa.path_iter(): 46 for path, states_in_path, terminal in dfa.path_iter():
48 matching = error_states & states_in_path 47 matching = error_states & states_in_path
49 if not matching: 48 if not matching:
50 continue 49 continue
51 last_action = None 50 last_action = None
52 path_length = 0 51 path_length = 0
53 for (key, state) in path: 52 for (key, state) in path:
54 if state in error_states: 53 if state in error_states:
55 assert last_action != None 54 assert last_action != None
56 path_map[state].append([k for k, s in path[1:path_length]]) 55 path_map[state].append([k for k, s in path[1:path_length]])
57 elif state in action_state_map: 56 elif state in action_state_map:
58 last_action = state 57 last_action = state
59 path_length += 1 58 path_length += 1
60 print reduce(lambda acc, x : acc + len(x), path_map.itervalues(), 0) 59 print reduce(lambda acc, x : acc + len(x), path_map.itervalues(), 0)
61 for state, key_paths in path_map.iteritems(): 60 for state, key_paths in path_map.iteritems():
62 count = 0 61 count = 0
63 action_str = map(str, error_map[state][0]) 62 action_str = map(str, error_map[state][0])
64 for key_path in key_paths: 63 for key_path in key_paths:
65 print "path %d %s %s" % ( 64 print "path %d %s %s" % (
66 state.node_number(), 65 state.node_number(),
67 action_str, 66 action_str,
68 " --> ".join(map(str, key_path))) 67 " --> ".join(map(str, key_path)))
69 count += 1 68 count += 1
70 if count > 10: 69 if count > 10:
71 break 70 break
72 71
73 def __generate(self): 72 @staticmethod
74 dfa = self.__dfa 73 def __compute_action_states(dfa, default_action):
75 default_action = self.__default_action
76 terminal_set = dfa.terminal_set() 74 terminal_set = dfa.terminal_set()
77 # Collect states that terminate currently. 75 # Collect states that terminate currently.
78 action_states = {} 76 action_states = {}
79 omega_states = set() 77 omega_states = set()
80 def f(state, acc): 78 def f(state, acc):
81 omega_state = state.omega_transition() 79 omega_state = state.omega_transition()
82 if omega_state == None: 80 if omega_state == None:
83 if not state in terminal_set: 81 if not state in terminal_set:
84 state.key_iter().next() # should have at least one transition 82 state.key_iter().next() # should have at least one transition
85 return 83 return
86 assert omega_state in terminal_set 84 assert omega_state in terminal_set
87 assert not state in terminal_set 85 assert not state in terminal_set
88 assert not list(omega_state.key_iter()) 86 assert not list(omega_state.key_iter())
89 omega_states.add(omega_state) 87 omega_states.add(omega_state)
90 match_action = omega_state.action() 88 match_action = omega_state.action()
91 if not match_action: 89 if not match_action:
92 match_action = default_action 90 match_action = default_action
93 action_states[state] = match_action 91 action_states[state] = match_action
94 dfa.visit_all_states(f) 92 dfa.visit_all_states(f)
95 assert omega_states == terminal_set 93 assert omega_states == terminal_set
96 # Find nodes that need backtracking edges 94 return action_states, omega_states
95
96 @staticmethod
97 def __build_backtracking_map(
98 dfa, default_action, action_states, omega_states):
97 incoming_transitions = dfa.build_incoming_transitions_map() 99 incoming_transitions = dfa.build_incoming_transitions_map()
98 backtracking_map = {} 100 backtracking_map = {}
99 store_states = set() 101 store_states = set()
100 # Start node may be an edge case. 102 # Start node may be an edge case.
101 start_state = dfa.start_state() 103 start_state = dfa.start_state()
102 if (not start_state in incoming_transitions and 104 if (not start_state in incoming_transitions and
103 not start_state in action_states): 105 not start_state in action_states):
104 action_states[start_state] = default_action 106 action_states[start_state] = default_action
105 error_map = {} 107 error_map = {}
106 for state in incoming_transitions.iterkeys(): 108 for state in incoming_transitions.iterkeys():
(...skipping 27 matching lines...) Expand all
134 assert actions 136 assert actions
135 if not len(actions) == 1: 137 if not len(actions) == 1:
136 error_map[state] = actions, match_edge 138 error_map[state] = actions, match_edge
137 continue 139 continue
138 action = iter(actions).next() 140 action = iter(actions).next()
139 # don't install default actions 141 # don't install default actions
140 if action == default_action.term(): 142 if action == default_action.term():
141 continue 143 continue
142 store_states |= match_edge 144 store_states |= match_edge
143 backtracking_map[state.node_number()] = (action, match_edge) 145 backtracking_map[state.node_number()] = (action, match_edge)
144 # Bail if error occurred. 146 return backtracking_map, store_states, error_map
145 if error_map: 147
146 self.__process_error_states(dfa, error_map, action_states) 148 @staticmethod
147 raise Exception('ambiguous backtracking') 149 def __construct_dfa_with_backtracking(dfa, backtracking_map, store_states):
148 # Now install backtracking everywhere.
149 def install_backtracking_action(new_states, node_number): 150 def install_backtracking_action(new_states, node_number):
150 omega_state_id = str(node_number) + '_bt' 151 omega_state_id = str(node_number) + '_bt'
151 key = TransitionKey.omega() 152 key = TransitionKey.omega()
152 new_states[str(node_number)]['transitions'][key] = omega_state_id 153 new_states[str(node_number)]['transitions'][key] = omega_state_id
153 # install new state 154 # install new state
154 old_action = backtracking_map[node_number][0] 155 old_action = backtracking_map[node_number][0]
155 new_states[omega_state_id] = { 156 new_states[omega_state_id] = {
156 'transitions' : {}, 157 'transitions' : {},
157 'action' : Action(Term('backtrack', old_action), 0), 158 'action' : Action(Term('backtrack', old_action), 0),
158 'terminal' : True, 159 'terminal' : True,
159 } 160 }
160 def new_state_action(old_state): 161 def new_state_action(old_state):
161 action = old_state.action() 162 action = old_state.action()
162 if not old_state in store_states: 163 if not old_state in store_states:
163 return action 164 return action
164 term = Term('store_lexing_state') 165 term = Term('store_lexing_state')
165 if action: 166 if action:
166 # TODO(dcarney): split target state instead 167 # TODO(dcarney): split target state instead
167 term = Term('chain', term, action.term()) 168 term = Term('chain', term, action.term())
168 return Action(term, 0) 169 return Action(term, 0)
169 # Now generate the new dfa. 170 # Now generate the new dfa.
171 terminal_set = dfa.terminal_set()
170 def convert(old_state, new_states): 172 def convert(old_state, new_states):
171 node_number = old_state.node_number() 173 node_number = old_state.node_number()
172 # Clone existing state. 174 # Clone existing state.
173 new_states[str(node_number)] = { 175 new_states[str(node_number)] = {
174 'transitions' : { 176 'transitions' : {
175 k : str(v.node_number()) for (k, v) in old_state.key_state_iter() }, 177 k : str(v.node_number()) for (k, v) in old_state.key_state_iter() },
176 'action' : new_state_action(old_state), 178 'action' : new_state_action(old_state),
177 'terminal' : old_state in terminal_set 179 'terminal' : old_state in terminal_set
178 } 180 }
179 # install a backtracking action 181 # Install a backtracking action.
180 if node_number in backtracking_map: 182 if node_number in backtracking_map:
181 install_backtracking_action(new_states, node_number) 183 install_backtracking_action(new_states, node_number)
182 return new_states 184 return new_states
183 new_states = dfa.visit_all_states(convert, {}) 185 return dfa.visit_all_states(convert, {})
186
187 def __generate(self):
188 dfa = self.__dfa
189 default_action = self.__default_action
190 # Find nodes that have actions.
191 action_states, omega_states= self.__compute_action_states(
192 dfa, default_action)
193 # Find nodes that need backtracking edges.
194 backtracking_map, store_states, error_map = self.__build_backtracking_map(
195 dfa, default_action, action_states, omega_states)
196 # Bail if error occurred.
197 if error_map:
198 self.__print_ambiguous_paths(dfa, error_map, action_states)
199 raise Exception('ambiguous backtracking')
200 # Now install backtracking everywhere.
201 new_states = self.__construct_dfa_with_backtracking(
202 dfa, backtracking_map, store_states)
203 start_state = dfa.start_state()
184 return Dfa(dfa.encoding(), str(start_state.node_number()), new_states) 204 return Dfa(dfa.encoding(), str(start_state.node_number()), new_states)
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698