| OLD | NEW |
| 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 transition_keys import TransitionKey | 28 from transition_keys import TransitionKey |
| 29 from automaton import Action | 29 from automaton import Term, Action |
| 30 from dfa import Dfa | 30 from dfa import Dfa |
| 31 | 31 |
| 32 # --- Optimization: Replacing tokens with gotos --- | 32 # --- Optimization: Replacing tokens with gotos --- |
| 33 # | 33 # |
| 34 # This optimization reduces the code size for grammars which have constructs | 34 # This optimization reduces the code size for grammars which have constructs |
| 35 # similar to keywords and identifiers. Consider the following grammar: | 35 # similar to keywords and identifiers. Consider the following grammar: |
| 36 # | 36 # |
| 37 # "baz" <|token(BAZ)|> | 37 # "baz" <|token(BAZ)|> |
| 38 # "bazz" <|token(BAZZ)|> | 38 # "bazz" <|token(BAZZ)|> |
| 39 # | 39 # |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 168 for key, transition_state in state.key_state_iter(): | 168 for key, transition_state in state.key_state_iter(): |
| 169 if not transition_state in incoming_transitions: | 169 if not transition_state in incoming_transitions: |
| 170 incoming_transitions[transition_state] = [] | 170 incoming_transitions[transition_state] = [] |
| 171 incoming_transitions[transition_state].append((key,state)) | 171 incoming_transitions[transition_state].append((key,state)) |
| 172 dfa.visit_all_states(build_incoming_transitions) | 172 dfa.visit_all_states(build_incoming_transitions) |
| 173 | 173 |
| 174 def is_replacement_candidate(state): | 174 def is_replacement_candidate(state): |
| 175 action = state.action() | 175 action = state.action() |
| 176 if not action or not action.match_action(): | 176 if not action or not action.match_action(): |
| 177 return False | 177 return False |
| 178 if (action.match_action()[0] == 'token' or | 178 if (action.match_action().name() == 'token' or |
| 179 action.match_action()[0] == 'harmony_token'): | 179 action.match_action().name() == 'harmony_token'): |
| 180 return True | 180 return True |
| 181 return False | 181 return False |
| 182 | 182 |
| 183 replacements = {} | 183 replacements = {} |
| 184 for state, incoming in incoming_transitions.items(): | 184 for state, incoming in incoming_transitions.items(): |
| 185 if len(incoming) < 10: | 185 if len(incoming) < 10: |
| 186 continue | 186 continue |
| 187 if not is_replacement_candidate(state): | 187 if not is_replacement_candidate(state): |
| 188 continue | 188 continue |
| 189 # check to see if incoming edges are matched by an outgoing edge | 189 # check to see if incoming edges are matched by an outgoing edge |
| (...skipping 28 matching lines...) Expand all Loading... |
| 218 'removals' : 0, | 218 'removals' : 0, |
| 219 'goto_start' : 0, | 219 'goto_start' : 0, |
| 220 'store_token_and_goto' : 0, | 220 'store_token_and_goto' : 0, |
| 221 'store_harmony_token_and_goto' : 0, | 221 'store_harmony_token_and_goto' : 0, |
| 222 } | 222 } |
| 223 store_states = set([]) | 223 store_states = set([]) |
| 224 # generate a store action to replace an existing action | 224 # generate a store action to replace an existing action |
| 225 def replacement_action(old_action, transition_state): | 225 def replacement_action(old_action, transition_state): |
| 226 assert old_action.match_action() | 226 assert old_action.match_action() |
| 227 state_id = name(transition_state) | 227 state_id = name(transition_state) |
| 228 if old_action.match_action()[0] == 'token': | 228 if old_action.match_action().name() == 'token': |
| 229 old_token = old_action.match_action()[1] | 229 old_token = old_action.match_action().args()[0] |
| 230 if (transition_state.action().match_action()[0] == 'token' and | 230 if (transition_state.action().match_action().name() == 'token' and |
| 231 transition_state.action().match_action()[1] == old_token): | 231 transition_state.action().match_action().args()[0] == old_token): |
| 232 # no need to store token | 232 # no need to store token |
| 233 match_action = ('goto_start', (state_id,)) | 233 match_action = Term('goto_start', state_id) |
| 234 counters['goto_start'] += 1 | 234 counters['goto_start'] += 1 |
| 235 else: | 235 else: |
| 236 counters['store_token_and_goto'] += 1 | 236 counters['store_token_and_goto'] += 1 |
| 237 match_action = ('store_token_and_goto', (old_token, state_id)) | 237 match_action = Term('store_token_and_goto', old_token, state_id) |
| 238 elif old_action.match_action()[0] == 'harmony_token': | 238 elif old_action.match_action().name() == 'harmony_token': |
| 239 match_action = ('store_harmony_token_and_goto', | 239 new_args = list(old_action.match_action().args()) + [state_id] |
| 240 (old_action.match_action()[1][0], | 240 match_action = Term('store_harmony_token_and_goto', *new_args) |
| 241 old_action.match_action()[1][1], | |
| 242 old_action.match_action()[1][2], | |
| 243 state_id)) | |
| 244 counters['store_harmony_token_and_goto'] += 1 | 241 counters['store_harmony_token_and_goto'] += 1 |
| 245 else: | 242 else: |
| 246 raise Exception(old_action.match_action()) | 243 raise Exception(old_action.match_action()) |
| 247 return Action(old_action.entry_action(), match_action, | 244 return Action(old_action.entry_action(), match_action, |
| 248 old_action.precedence()) | 245 old_action.precedence()) |
| 249 # map the old state to the new state, with fewer transitions and | 246 # map the old state to the new state, with fewer transitions and |
| 250 # goto actions | 247 # goto actions |
| 251 def replace_state(state, acc): | 248 def replace_state(state, acc): |
| 252 new_state = { | 249 new_state = { |
| 253 'transitions' : {}, | 250 'transitions' : {}, |
| (...skipping 17 matching lines...) Expand all Loading... |
| 271 new_state['action'] = replacement_action(state.action(), replacement) | 268 new_state['action'] = replacement_action(state.action(), replacement) |
| 272 # will need to patch up transition_state | 269 # will need to patch up transition_state |
| 273 store_states.add(name(transition_state)) | 270 store_states.add(name(transition_state)) |
| 274 assert not state_replacements | 271 assert not state_replacements |
| 275 self.__dfa.visit_all_states(replace_state) | 272 self.__dfa.visit_all_states(replace_state) |
| 276 # now patch up all states with stores | 273 # now patch up all states with stores |
| 277 start_name = name(self.__dfa.start_state()) | 274 start_name = name(self.__dfa.start_state()) |
| 278 for state_id in store_states: | 275 for state_id in store_states: |
| 279 old_action = states[state_id]['action'] | 276 old_action = states[state_id]['action'] |
| 280 assert not old_action.entry_action() | 277 assert not old_action.entry_action() |
| 281 assert old_action.match_action()[0] == 'token', 'unimplemented' | 278 assert old_action.match_action().name() == 'token', 'unimplemented' |
| 282 entry_action = ('store_token', old_action.match_action()[1]) | 279 entry_action = Term('store_token', old_action.match_action().args()[0]) |
| 283 match_action = ('do_stored_token', state_id) | 280 match_action = Term('do_stored_token', state_id) |
| 284 precedence = old_action.precedence() | 281 precedence = old_action.precedence() |
| 285 states[state_id]['action'] = Action( | 282 states[state_id]['action'] = Action( |
| 286 entry_action, match_action, precedence) | 283 entry_action, match_action, precedence) |
| 287 # The state might be only reachable via gotos; make sure it's connected in | 284 # The state might be only reachable via gotos; make sure it's connected in |
| 288 # the state graph by adding a bogus transition from the start state. This | 285 # the state graph by adding a bogus transition from the start state. This |
| 289 # transition doens't match any character. | 286 # transition doens't match any character. |
| 290 states[start_name]['transitions'][ | 287 states[start_name]['transitions'][ |
| 291 TransitionKey.unique('no_match')] = state_id | 288 TransitionKey.unique('no_match')] = state_id |
| 292 | 289 |
| 293 if self.__log: | 290 if self.__log: |
| 294 print 'goto_start inserted %s' % counters['goto_start'] | 291 print 'goto_start inserted %s' % counters['goto_start'] |
| 295 print 'store_token_and_goto inserted %s' % ( | 292 print 'store_token_and_goto inserted %s' % ( |
| 296 counters['store_token_and_goto']) | 293 counters['store_token_and_goto']) |
| 297 print 'store_harmony_token_and_goto %s' % ( | 294 print 'store_harmony_token_and_goto %s' % ( |
| 298 counters['store_harmony_token_and_goto']) | 295 counters['store_harmony_token_and_goto']) |
| 299 print 'transitions removed %s' % counters['removals'] | 296 print 'transitions removed %s' % counters['removals'] |
| 300 print 'do_stored_token actions added %s' % len(store_states) | 297 print 'do_stored_token actions added %s' % len(store_states) |
| 301 self.__dfa = Dfa(self.__dfa.encoding(), start_name, states) | 298 self.__dfa = Dfa(self.__dfa.encoding(), start_name, states) |
| 302 | 299 |
| 303 @staticmethod | 300 @staticmethod |
| 304 def optimize(dfa, log): | 301 def optimize(dfa, log): |
| 305 optimizer = DfaOptimizer(dfa, log) | 302 optimizer = DfaOptimizer(dfa, log) |
| 306 optimizer.replace_tokens_with_gotos() | 303 optimizer.replace_tokens_with_gotos() |
| 307 return optimizer.__dfa | 304 return optimizer.__dfa |
| OLD | NEW |