| 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 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 44 dfa = rule_processor.default_automata().minimal_dfa() | 44 dfa = rule_processor.default_automata().minimal_dfa() |
| 45 else: | 45 else: |
| 46 dfa = rule_processor.default_automata().dfa() | 46 dfa = rule_processor.default_automata().dfa() |
| 47 self.__dfa = dfa | 47 self.__dfa = dfa |
| 48 self.__default_action = rule_processor.default_action | 48 self.__default_action = rule_processor.default_action |
| 49 self.__debug_print = debug_print | 49 self.__debug_print = debug_print |
| 50 self.__start_node_number = self.__dfa.start_state().node_number() | 50 self.__start_node_number = self.__dfa.start_state().node_number() |
| 51 self.__log = log | 51 self.__log = log |
| 52 self.__inline = inline | 52 self.__inline = inline |
| 53 self.__switching = switching | 53 self.__switching = switching |
| 54 self.__jump_table = [] |
| 55 |
| 56 __jump_labels = ['state_entry', 'after_entry_code'] |
| 54 | 57 |
| 55 @staticmethod | 58 @staticmethod |
| 56 def __transform_state(encoding, state): | 59 def __transform_state(encoding, state): |
| 57 # action data | 60 # action data |
| 58 action = state.action() | 61 action = state.action() |
| 59 entry_action = None if not action else action.entry_action() | 62 entry_action = None if not action else action.entry_action() |
| 60 match_action = None if not action else action.match_action() | 63 match_action = None if not action else action.match_action() |
| 61 # generate ordered transitions | 64 # generate ordered transitions |
| 62 transitions = map(lambda (k, v) : (k, v.node_number()), | 65 transitions = map(lambda (k, v) : (k, v.node_number()), |
| 63 state.transitions().items()) | 66 state.transitions().items()) |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 'long_char_transitions' : [], | 107 'long_char_transitions' : [], |
| 105 'unique_transitions' : unique_transitions, | 108 'unique_transitions' : unique_transitions, |
| 106 # state actions | 109 # state actions |
| 107 'entry_action' : entry_action, | 110 'entry_action' : entry_action, |
| 108 'match_action' : match_action, | 111 'match_action' : match_action, |
| 109 # statistics for states | 112 # statistics for states |
| 110 'class_keys' : class_keys, | 113 'class_keys' : class_keys, |
| 111 'distinct_keys' : distinct_keys, | 114 'distinct_keys' : distinct_keys, |
| 112 'ranges' : ranges, | 115 'ranges' : ranges, |
| 113 # record of which entry points will be needed | 116 # record of which entry points will be needed |
| 114 'entry_points' : { | 117 'entry_points' : {k : False for k in CodeGenerator.__jump_labels} |
| 115 'state_entry' : True, | |
| 116 'after_entry_code' : False, | |
| 117 # 'before_match' : False, | |
| 118 # 'before_deferred' : False, | |
| 119 } | |
| 120 } | 118 } |
| 121 | 119 |
| 120 def __register_jump(self, node_id, label): |
| 121 assert label in CodeGenerator.__jump_labels |
| 122 state = self.__dfa_states[node_id]['entry_points'][label] = True |
| 123 self.__jump_table.append((node_id, label)) |
| 124 return len(self.__jump_table) - 1 |
| 125 |
| 122 def __set_inline(self, count, state): | 126 def __set_inline(self, count, state): |
| 123 assert state['inline'] == None | 127 assert state['inline'] == None |
| 124 inline = False | 128 inline = False |
| 125 # inline terminal states | 129 # inline terminal states |
| 126 if not state['transitions']: | 130 if not state['transitions']: |
| 127 inline = True | 131 inline = True |
| 128 # inline next to terminal states with 1 or 2 transitions | 132 # inline next to terminal states with 1 or 2 transitions |
| 129 elif state['distinct_keys'] < 3 and state['class_keys'] == 0: | 133 elif state['distinct_keys'] < 3 and state['class_keys'] == 0: |
| 130 inline = True | 134 inline = True |
| 131 # ensure state terminates in 1 step | 135 # ensure state terminates in 1 step |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 275 state['match_action'][0] == 'do_stored_token'): | 279 state['match_action'][0] == 'do_stored_token'): |
| 276 assert not state['match_action'][1] in goto_map | 280 assert not state['match_action'][1] in goto_map |
| 277 goto_map[state['match_action'][1]] = state['node_number'] | 281 goto_map[state['match_action'][1]] = state['node_number'] |
| 278 mapped_actions = set([ | 282 mapped_actions = set([ |
| 279 'store_harmony_token_and_goto', | 283 'store_harmony_token_and_goto', |
| 280 'store_token_and_goto', | 284 'store_token_and_goto', |
| 281 'goto_start']) | 285 'goto_start']) |
| 282 for state in states: | 286 for state in states: |
| 283 if not state['match_action']: | 287 if not state['match_action']: |
| 284 continue | 288 continue |
| 285 if state['match_action'][0] in mapped_actions: | 289 action = state['match_action'][0] |
| 290 if action in mapped_actions: |
| 286 value = state['match_action'][1] | 291 value = state['match_action'][1] |
| 287 value = tuple(list(value[:-1]) + [goto_map[value[-1]]]) | 292 target_id = goto_map[value[-1]] |
| 288 state['match_action'] = (state['match_action'][0], value) | 293 if action != 'goto_start': |
| 289 if state['match_action'][0] != 'goto_start': | |
| 290 states[value[-1]]['entry_points']['after_entry_code'] = True | |
| 291 state['can_elide_read'] = False | 294 state['can_elide_read'] = False |
| 295 label = 'after_entry_code' |
| 292 else: | 296 else: |
| 293 states[value[-1]]['can_elide_read'] = False | 297 states[target_id]['can_elide_read'] = False |
| 298 label = 'state_entry' |
| 299 jump_label = self.__register_jump(target_id, label) |
| 300 state['match_action'] = (action, tuple(list(value[:-1]) + [jump_label])) |
| 294 | 301 |
| 295 @staticmethod | 302 def __rewrite_transitions_to_jumps(self): |
| 296 def __mark_entry_points(dfa_states): | 303 transition_names = [ |
| 304 'if_transitions', |
| 305 'switch_transitions', |
| 306 'deferred_transitions', |
| 307 'long_char_transitions'] |
| 308 def f((key, target_id)): |
| 309 return (key, self.__register_jump(target_id, 'state_entry')) |
| 310 for state in self.__dfa_states: |
| 311 for name in transition_names: |
| 312 state[name] = map(f, state[name]) |
| 313 |
| 314 def __mark_entry_points(self): |
| 315 # mark the entry point in case there are implicit jumps to it |
| 316 self.__dfa_states[0]['entry_points']['state_entry'] = True |
| 297 # inlined states can write no labels | 317 # inlined states can write no labels |
| 298 for state in dfa_states: | 318 for state in self.__dfa_states: |
| 299 entry_points = state['entry_points'] | 319 entry_points = state['entry_points'] |
| 300 if state['inline']: | 320 if state['inline']: |
| 301 for k in entry_points.keys(): | 321 for k in entry_points.keys(): |
| 302 entry_points[k] = False | 322 entry_points[k] = False |
| 303 | 323 |
| 304 def process(self): | 324 def process(self): |
| 305 | 325 |
| 306 self.__build_dfa_states() | 326 self.__build_dfa_states() |
| 307 self.__rewrite_gotos() | |
| 308 | |
| 309 dfa_states = self.__dfa_states | 327 dfa_states = self.__dfa_states |
| 310 # set nodes to inline | |
| 311 if self.__inline: | |
| 312 inlined = reduce(self.__set_inline, dfa_states, 0) | |
| 313 if self.__log: | |
| 314 print "%s states inlined" % inlined | |
| 315 elif self.__log: | |
| 316 print "no inlining" | |
| 317 # split transitions | 328 # split transitions |
| 318 switched = reduce(self.__split_transitions, dfa_states, 0) | 329 switched = reduce(self.__split_transitions, dfa_states, 0) |
| 319 if self.__log: | 330 if self.__log: |
| 320 print "%s states use switch (instead of if)" % switched | 331 print "%s states use switch (instead of if)" % switched |
| 321 # rewrite deferred transitions | 332 # rewrite deferred transitions |
| 322 for state in dfa_states: | 333 for state in dfa_states: |
| 323 self.__rewrite_deferred_transitions(state) | 334 self.__rewrite_deferred_transitions(state) |
| 335 # rewrite gotos |
| 336 self.__rewrite_gotos() |
| 337 # rewrite transitions to use jumps |
| 338 self.__rewrite_transitions_to_jumps() |
| 339 # set nodes to inline |
| 340 if self.__inline: |
| 341 inlined = reduce(self.__set_inline, dfa_states, 0) |
| 342 if self.__log: |
| 343 print "%s states inlined" % inlined |
| 344 elif self.__log: |
| 345 print "no inlining" |
| 324 # mark all the entry points that will be used | 346 # mark all the entry points that will be used |
| 325 self.__mark_entry_points(dfa_states) | 347 self.__mark_entry_points() |
| 326 | 348 |
| 327 default_action = self.__default_action | 349 default_action = self.__default_action |
| 328 assert(default_action and default_action.match_action()) | 350 assert(default_action and default_action.match_action()) |
| 329 default_action = default_action.match_action() | 351 default_action = default_action.match_action() |
| 330 | 352 |
| 331 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | 353 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) |
| 332 template_env = jinja2.Environment( | 354 template_env = jinja2.Environment( |
| 333 loader = jinja2.PackageLoader('lexer_generator', '.'), | 355 loader = jinja2.PackageLoader('lexer_generator', '.'), |
| 334 undefined = jinja2.StrictUndefined) | 356 undefined = jinja2.StrictUndefined) |
| 335 template = template_env.get_template('code_generator.jinja') | 357 template = template_env.get_template('code_generator.jinja') |
| 336 | 358 |
| 337 encoding = self.__dfa.encoding() | 359 encoding = self.__dfa.encoding() |
| 338 char_types = {'latin1': 'uint8_t', 'utf16': 'uint16_t', 'utf8': 'int8_t'} | 360 char_types = {'latin1': 'uint8_t', 'utf16': 'uint16_t', 'utf8': 'int8_t'} |
| 339 char_type = char_types[encoding.name()] | 361 char_type = char_types[encoding.name()] |
| 340 | 362 |
| 341 return template.render( | 363 return template.render( |
| 342 start_node_number = 0, | 364 start_node_number = 0, |
| 343 debug_print = self.__debug_print, | 365 debug_print = self.__debug_print, |
| 344 default_action = default_action, | 366 default_action = default_action, |
| 345 dfa_states = dfa_states, | 367 dfa_states = dfa_states, |
| 368 jump_table = self.__jump_table, |
| 346 encoding = encoding.name(), | 369 encoding = encoding.name(), |
| 347 char_type = char_type, | 370 char_type = char_type, |
| 348 upper_bound = encoding.primary_range()[1]) | 371 upper_bound = encoding.primary_range()[1]) |
| OLD | NEW |