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

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

Issue 85413006: Experimental parser: dfa optimization to remove transitions from keyword lexing (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/parser
Patch Set: Created 7 years 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 | tools/lexer_generator/generator.py » ('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 2013 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_keys import TransitionKey
29 from automaton import Action
30 from dfa import Dfa
31
32 class DfaOptimizer(object):
33
34 def __init__(self, dfa, log):
35 self.__dfa = dfa
36 self.__log = log
37
38 @staticmethod
39 def transistions_match(encoding, incoming_key, incoming_state, state):
40 keys = set(state.key_iter())
41 keys.add(incoming_key)
42 disjoint_keys = TransitionKey.disjoint_keys(encoding, keys)
43 for key in disjoint_keys:
44 if not incoming_key.is_superset_of_key(key):
45 continue
46 transition_state = state.transition_state_for_key(key)
47 if incoming_state.transition_state_for_key(key) != transition_state:
48 return False
49 return True
50
51 def replace_tokens_with_gotos(self):
52 '''replace states with no entry action and match action of type 'token(X)'
53 with new states with entry action store_token(X) and match action
54 goto(state_id) which has (far) fewer transitions'''
55
56 dfa = self.__dfa
57 encoding = dfa.encoding()
58
59 incoming_transitions = {}
60 def build_incoming_transitions(state, visitor_state):
61 for key, transition_state in state.key_state_iter():
62 if not transition_state in incoming_transitions:
63 incoming_transitions[transition_state] = []
64 incoming_transitions[transition_state].append((key,state))
65 dfa.visit_all_states(build_incoming_transitions)
66
67 def is_replacement_candidate(state):
68 action = state.action()
69 if not action or action.entry_action() or not action.match_action():
70 return False
71 if (action.match_action()[0] == 'token' or
72 action.match_action()[0] == 'harmony_token'):
73 return True
74 return False
75
76 replacements = {}
77 for state, incoming in incoming_transitions.items():
78 if len(incoming) < 10:
79 continue
80 if not is_replacement_candidate(state):
81 continue
82 # check to see if incoming edges are matched by an outgoing edge
83 def match_filter((incoming_key, incoming_state)):
84 return (incoming_state != state and # drop self transitions
85 is_replacement_candidate(incoming_state) and
86 self.transistions_match(
87 encoding, incoming_key, incoming_state, state))
88 for incoming_key_state in incoming:
89 if not match_filter(incoming_key_state):
90 continue
91 (incoming_key, incoming_state) = incoming_key_state
92 # set this transition as to be replaced
93 if not incoming_state in replacements:
94 replacements[incoming_state] = {}
95 replacements[incoming_state][incoming_key] = state
96 # now see if we can gather other transistions into the goto
97 for key in incoming_state.key_iter():
98 if key == incoming_key:
99 continue
100 if not self.transistions_match(
101 encoding, key, incoming_state, state):
102 continue
103 # this transition can be removed
104 replacements[incoming_state][key] = None
105 if not replacements:
106 return
107 # perform replacement
108 states = {}
109 name = lambda state : str(state.node_number())
110 counters = {'removals' : 0, 'gotos' : 0}
111 store_states = set([])
112 # generate a store action to replace an existing action
113 def replacement_action(old_action, match_action):
114 assert not old_action.entry_action()
115 assert old_action.match_action()
116 if old_action.match_action()[0] == 'token':
117 entry_action = ('store_token', old_action.match_action()[1])
118 elif old_action.match_action()[0] == 'harmony_token':
119 entry_action = ('store_harmony_token', old_action.match_action()[1])
120 else:
121 raise Exception(old_action.match_action())
122 return Action(entry_action, match_action, old_action.precedence())
123 # map the old state to the new state, with fewer transitions and
124 # goto actions
125 def replace_state(state, acc):
126 new_state = {
127 'transitions' : {},
128 'terminal' : state in self.__dfa.terminal_set(),
129 'action' : state.action(),
130 }
131 states[name(state)] = new_state
132 state_replacements = replacements[state] if state in replacements else {}
133 for transition_key, transition_state in state.transitions().items():
134 if not transition_key in state_replacements:
135 new_state['transitions'][transition_key] = name(transition_state)
136 continue
137 replacement = state_replacements[transition_key]
138 del state_replacements[transition_key]
139 # just drop the transition
140 if replacement == None:
141 counters['removals'] += 1
142 continue
143 # do goto replacement
144 counters['gotos'] += 1
145 match_action = ('goto', name(transition_state))
146 new_state['action'] = replacement_action(state.action(), match_action)
147 # will need to patch up transition_state
148 store_states.add(name(transition_state))
149 assert not state_replacements
150 self.__dfa.visit_all_states(replace_state)
151 # now patch up all states with stores
152 for state in store_states:
153 old_action = states[state]['action']
154 match_action = ('do_stored_token', None)
155 states[state]['action'] = replacement_action(old_action, match_action)
156 start_name = name(self.__dfa.start_state())
157 if self.__log:
158 print 'gotos inserted %s' % counters['gotos']
159 print 'transitions removed %s' % counters['removals']
160 print 'do_stored_token actions added %s' % len(store_states)
161 self.__dfa = Dfa(self.__dfa.encoding(), start_name, states)
162
163 @staticmethod
164 def optimize(dfa, log):
165 optimizer = DfaOptimizer(dfa, log)
166 optimizer.replace_tokens_with_gotos()
167 return optimizer.__dfa
OLDNEW
« no previous file with comments | « no previous file | tools/lexer_generator/generator.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698