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

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

Issue 145173011: Experimental parser: cleanup code generator a bit (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/parser
Patch Set: Created 6 years, 11 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 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 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
68 def cmp(left, right): 68 def cmp(left, right):
69 return TransitionKey.canonical_compare(left[0], right[0]) 69 return TransitionKey.canonical_compare(left[0], right[0])
70 transitions = sorted(transitions, cmp) 70 transitions = sorted(transitions, cmp)
71 # map transition keys to disjoint ranges and collect stats 71 # map transition keys to disjoint ranges and collect stats
72 disjoint_keys = [] 72 disjoint_keys = []
73 unique_transitions = {} 73 unique_transitions = {}
74 old_transitions = transitions 74 old_transitions = transitions
75 transitions = [] 75 transitions = []
76 (class_keys, distinct_keys, ranges) = (0, 0, 0) 76 (class_keys, distinct_keys, ranges) = (0, 0, 0)
77 zero_transition = None 77 zero_transition = None
78 total_transitions = 0
78 for key, transition_id in old_transitions: 79 for key, transition_id in old_transitions:
79 keys = [] 80 keys = []
80 for (t, r) in key.range_iter(encoding): 81 for (t, r) in key.range_iter(encoding):
81 if t == 'CLASS': 82 if t == 'CLASS':
82 class_keys += 1 83 class_keys += 1
83 keys.append((t, r)) 84 keys.append((t, r))
84 elif t == 'PRIMARY_RANGE': 85 elif t == 'PRIMARY_RANGE':
85 distinct_keys += r[1] - r[0] + 1 86 distinct_keys += r[1] - r[0] + 1
86 ranges += 1 87 ranges += 1
87 # split 0 out of range, don't bother updating stats 88 # split 0 out of range
88 assert r[0] >= 0 89 assert r[0] >= 0
89 if r[0] == 0: 90 if r[0] == 0:
90 assert zero_transition == None 91 assert zero_transition == None
91 zero_transition = transition_id 92 zero_transition = transition_id
92 if r[0] == r[1]: 93 if r[0] == r[1]:
93 continue 94 continue
94 r = (r[0] + 1, r[1]) 95 r = (r[0] + 1, r[1])
95 keys.append((t, r)) 96 keys.append((t, r))
96 elif t == 'UNIQUE': 97 elif t == 'UNIQUE':
97 assert r == 'no_match' or r == 'eos' 98 assert r == 'no_match' or r == 'eos'
98 assert r not in unique_transitions 99 assert r not in unique_transitions
99 unique_transitions[r] = transition_id 100 unique_transitions[r] = transition_id
101 if r != 'no_match':
102 total_transitions += 1
100 else: 103 else:
101 raise Exception() 104 raise Exception()
102 if keys: 105 if keys:
103 transitions.append((keys, transition_id)) 106 transitions.append((keys, transition_id))
104 # delay zero transition until last 107 # delay zero transition until last
105 if zero_transition != None: 108 if zero_transition != None:
106 transitions.append(([('PRIMARY_RANGE', (0, 0))], transition_id)) 109 transitions.append(([('PRIMARY_RANGE', (0, 0))], transition_id))
110 ranges += 1
111 total_transitions += len(transitions)
107 return { 112 return {
108 'node_number' : None, 113 'node_number' : None,
109 'original_node_number' : state.node_number(), 114 'original_node_number' : state.node_number(),
110 'transitions' : transitions, 115 'transitions' : transitions,
111 # flags for code generator 116 # flags for code generator
112 'can_elide_read' : len(transitions) == 0, 117 'can_elide_read' : total_transitions == 0,
113 'is_eos_handler' : False, 118 'is_eos_handler' : False,
114 'inline' : False, 119 'inline' : False,
115 'must_not_inline' : False, 120 'must_not_inline' : False,
116 # transitions for code generator 121 # transitions for code generator
117 'if_transitions' : [], 122 'if_transitions' : [],
118 'switch_transitions' : [], 123 'switch_transitions' : [],
119 'deferred_transitions' : [], 124 'deferred_transitions' : [],
120 'unique_transitions' : unique_transitions, 125 'unique_transitions' : unique_transitions,
121 # state actions 126 # state actions
122 'entry_action' : entry_action, 127 'entry_action' : entry_action,
123 'match_action' : match_action, 128 'match_action' : match_action,
124 # statistics for states 129 # statistics for state
130 'total_transitions' : total_transitions,
125 'class_keys' : class_keys, 131 'class_keys' : class_keys,
126 'distinct_keys' : distinct_keys, 132 'distinct_keys' : distinct_keys,
127 'ranges' : ranges, 133 'ranges' : ranges,
128 # record of which entry points will be needed 134 # record of which entry points will be needed
129 'entry_points' : {k : False for k in CodeGenerator.__jump_labels} 135 'entry_points' : {k : False for k in CodeGenerator.__jump_labels}
130 } 136 }
131 137
132 def __register_jump(self, node_id, label): 138 def __register_jump(self, node_id, label):
133 if label != 'inline': 139 if label != 'inline':
134 assert label in CodeGenerator.__jump_labels 140 assert label in CodeGenerator.__jump_labels
135 state = self.__dfa_states[node_id]['entry_points'][label] = True 141 state = self.__dfa_states[node_id]['entry_points'][label] = True
136 self.__jump_table.append((node_id, label)) 142 self.__jump_table.append((node_id, label))
137 return len(self.__jump_table) - 1 143 return len(self.__jump_table) - 1
138 144
139 def __set_inline(self, count, state): 145 def __set_inline(self, count, state):
140 inline = False 146 inline = False
141 if state['must_not_inline']: 147 if state['must_not_inline']:
142 inline = False 148 inline = False
143 # inline terminal states 149 # inline terminal states
144 elif not state['transitions']: 150 elif not state['total_transitions']:
145 inline = True 151 inline = True
146 # inline next to terminal states with 1 or 2 transitions 152 # inline next to terminal states with 1 or 2 transitions
147 elif state['distinct_keys'] < 3 and state['class_keys'] == 0: 153 elif state['distinct_keys'] < 3 and state['class_keys'] == 0:
148 inline = True 154 inline = True
149 # ensure state terminates in 1 step 155 # ensure state terminates in 1 step
150 for key, state_id in state['transitions']: 156 for key, state_id in state['transitions']:
151 if self.__dfa_states[state_id]['transitions']: 157 if self.__dfa_states[state_id]['total_transitions']:
152 inline = False 158 inline = False
153 break 159 break
154 state['inline'] = inline 160 state['inline'] = inline
155 return count + 1 if inline else count 161 return count + 1 if inline else count
156 162
157 def __split_transitions(self, split_count, state): 163 def __split_transitions(self, split_count, state):
158 '''Goes through the transitions for 'state' and decides which of them should 164 '''Goes through the transitions for 'state' and decides which of them should
159 use the if statement and which should use the switch statement.''' 165 use the if statement and which should use the switch statement.'''
160 assert not state['switch_transitions'] 166 assert not state['switch_transitions']
161 (distinct_keys, ranges) = (state['distinct_keys'], state['ranges']) 167 (distinct_keys, ranges) = (state['distinct_keys'], state['ranges'])
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 CodeGenerator.__reorder(node_number, id_map, dfa_states) 261 CodeGenerator.__reorder(node_number, id_map, dfa_states)
256 262
257 @staticmethod 263 @staticmethod
258 def __mark_eos_states(dfa_states, eos_states): 264 def __mark_eos_states(dfa_states, eos_states):
259 for state_id in eos_states: 265 for state_id in eos_states:
260 state = dfa_states[state_id] 266 state = dfa_states[state_id]
261 state['is_eos_handler'] = True 267 state['is_eos_handler'] = True
262 state['must_not_inline'] = True 268 state['must_not_inline'] = True
263 assert state['match_action'] 269 assert state['match_action']
264 assert not state['entry_action'] 270 assert not state['entry_action']
265 assert not state['transitions'] 271 assert not state['total_transitions']
266 assert not state['unique_transitions']
267 272
268 def __build_dfa_states(self): 273 def __build_dfa_states(self):
269 dfa_states = [] 274 dfa_states = []
270 self.__dfa.visit_all_states(lambda state, acc: dfa_states.append(state)) 275 self.__dfa.visit_all_states(lambda state, acc: dfa_states.append(state))
271 encoding = self.__dfa.encoding() 276 encoding = self.__dfa.encoding()
272 f = lambda state : CodeGenerator.__transform_state(encoding, state) 277 f = lambda state : CodeGenerator.__transform_state(encoding, state)
273 dfa_states = map(f, dfa_states) 278 dfa_states = map(f, dfa_states)
274 id_map = {x['original_node_number'] : x for x in dfa_states} 279 id_map = {x['original_node_number'] : x for x in dfa_states}
275 dfa_states = [] 280 dfa_states = []
276 CodeGenerator.__reorder(self.__start_node_number, id_map, dfa_states) 281 CodeGenerator.__reorder(self.__start_node_number, id_map, dfa_states)
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 else: 321 else:
317 states[target_id]['can_elide_read'] = False 322 states[target_id]['can_elide_read'] = False
318 label = 'state_entry' 323 label = 'state_entry'
319 jump_label = self.__register_jump(target_id, label) 324 jump_label = self.__register_jump(target_id, label)
320 state['match_action'] = (action, tuple(list(value[:-1]) + [jump_label])) 325 state['match_action'] = (action, tuple(list(value[:-1]) + [jump_label]))
321 326
322 def __inlined_state(self, target_id): 327 def __inlined_state(self, target_id):
323 state = deepcopy(self.__dfa_states[target_id]) 328 state = deepcopy(self.__dfa_states[target_id])
324 state['node_number'] = len(self.__dfa_states) 329 state['node_number'] = len(self.__dfa_states)
325 self.__dfa_states.append(state) 330 self.__dfa_states.append(state)
326 # mark inline as none, to be correctly handled below 331 # mark as just generated, so it will correctly rewritten
327 state['inline'] = None 332 state['just_generated_inline_state'] = True
328 # clear entry points 333 # clear entry points
329 state['entry_points'] = {k : False for k in CodeGenerator.__jump_labels} 334 state['entry_points'] = {k : False for k in CodeGenerator.__jump_labels}
330 return state['node_number'] 335 return state['node_number']
331 336
332 def __rewrite_transitions_to_jumps(self, start_id, count, inline_mapping_in): 337 def __rewrite_transitions_to_jumps(self, start_id, count, inline_mapping_in):
333 # order here should match the order of code generation 338 # order here should match the order of code generation
334 transition_names = [ 339 transition_names = [
335 'switch_transitions', 340 'switch_transitions',
336 'if_transitions', 341 'if_transitions',
337 'deferred_transitions'] 342 'deferred_transitions']
338 end_offset = start_id + count 343 end_offset = start_id + count
339 assert len(self.__dfa_states) == end_offset 344 assert len(self.__dfa_states) == end_offset
340 total_nodes_created = 0 345 total_nodes_created = 0
341 for state_id in range(start_id, end_offset): 346 for state_id in range(start_id, end_offset):
342 state = self.__dfa_states[state_id] 347 state = self.__dfa_states[state_id]
343 # this will be ignored during code generation, 348 if state['inline']:
344 # and it's needed as a template, so don't rewrite 349 if not 'just_generated_inline_state' in state:
345 if state['inline'] == True: 350 # this will be ignored during code generation,
346 continue 351 # and it's needed as a template, so don't rewrite
347 # these is a new inline state, now mark as inline and rewrite 352 continue
348 if state['inline'] == None: 353 # these is a new inline state, rewrite
349 state['inline'] = True 354 del state['just_generated_inline_state']
355 assert not 'just_generated_inline_state' in state
350 inline_mapping = inline_mapping_in.copy() 356 inline_mapping = inline_mapping_in.copy()
351 def generate_jump((key, target_id)): 357 def generate_jump((key, target_id)):
352 jump_type = 'state_entry' 358 jump_type = 'state_entry'
353 if self.__dfa_states[target_id]['inline']: 359 if self.__dfa_states[target_id]['inline']:
354 # generate at most one inline state for all transitions 360 # generate at most one inline state for all transitions
355 if not target_id in inline_mapping: 361 if not target_id in inline_mapping:
356 inline_mapping[target_id] = self.__inlined_state(target_id) 362 inline_mapping[target_id] = self.__inlined_state(target_id)
357 jump_type = 'inline' 363 jump_type = 'inline'
358 target_id = inline_mapping[target_id] 364 target_id = inline_mapping[target_id]
359 else: 365 else:
360 assert not target_id in inline_mapping 366 assert not target_id in inline_mapping
361 return (key, self.__register_jump(target_id, jump_type)) 367 return (key, self.__register_jump(target_id, jump_type))
362 for name in transition_names: 368 for name in transition_names:
363 state[name] = map(generate_jump, state[name]) 369 state[name] = map(generate_jump, state[name])
364 if 'eos' in state['unique_transitions']: 370 if 'eos' in state['unique_transitions']:
365 # eos state is not inlined
366 eos_state_id = state['unique_transitions']['eos'] 371 eos_state_id = state['unique_transitions']['eos']
372 # eos state is not inlined, don't need to look in map
373 assert not self.__dfa_states[eos_state_id]['inline']
367 jump = self.__register_jump(eos_state_id, 'state_entry') 374 jump = self.__register_jump(eos_state_id, 'state_entry')
368 state['unique_transitions']['eos'] = jump 375 state['unique_transitions']['eos'] = jump
369 # now rewrite all nodes created 376 # now rewrite all nodes created
370 nodes_created = len(inline_mapping) - len(inline_mapping_in) 377 nodes_created = len(inline_mapping) - len(inline_mapping_in)
371 assert len(self.__dfa_states) == ( 378 assert len(self.__dfa_states) == (
372 end_offset + total_nodes_created + nodes_created) 379 end_offset + total_nodes_created + nodes_created)
373 if nodes_created == 0: 380 if nodes_created == 0:
374 continue 381 continue
375 created = self.__rewrite_transitions_to_jumps( 382 created = self.__rewrite_transitions_to_jumps(
376 end_offset + total_nodes_created, nodes_created, inline_mapping) 383 end_offset + total_nodes_created, nodes_created, inline_mapping)
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
418 425
419 return template.render( 426 return template.render(
420 start_node_number = 0, 427 start_node_number = 0,
421 debug_print = self.__debug_print, 428 debug_print = self.__debug_print,
422 default_action = default_action, 429 default_action = default_action,
423 dfa_states = dfa_states, 430 dfa_states = dfa_states,
424 jump_table = self.__jump_table, 431 jump_table = self.__jump_table,
425 encoding = encoding.name(), 432 encoding = encoding.name(),
426 char_type = char_type, 433 char_type = char_type,
427 upper_bound = encoding.primary_range()[1]) 434 upper_bound = encoding.primary_range()[1])
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