comparison python/pyyacc.py @ 218:494828a7adf1

added some sort of cache to assembler
author Windel Bouwman
date Fri, 05 Jul 2013 15:30:22 +0200
parents 37ac6c016e0f
children 6259856841a0
comparison
equal deleted inserted replaced
217:8b2e5f3cd579 218:494828a7adf1
1 """ 1 """
2 Parser generator script 2 Parser generator script
3 """ 3 """
4 4
5 import shelve
6 import hashlib
5 from ppci import Token 7 from ppci import Token
6 8
7 EPS = 'EPS' 9 EPS = 'EPS'
8 EOF = 'EOF' 10 EOF = 'EOF'
9 SHIFT = 1 11 SHIFT = 1
158 for production in self.productions: 160 for production in self.productions:
159 for symbol in production.symbols: 161 for symbol in production.symbols:
160 if symbol not in self.Symbols + [EPS]: 162 if symbol not in self.Symbols + [EPS]:
161 raise ParserGenerationException('Symbol {0} undefined'.format(symbol)) 163 raise ParserGenerationException('Symbol {0} undefined'.format(symbol))
162 164
163 165 def getSignature(self):
166 m = hashlib.md5()
167 m.update((str(self.productions) + str(self.start_symbol)).encode('ascii'))
168 signature = m.hexdigest()
169
164 def genParser(self): 170 def genParser(self):
165 """ Generates a parser from the grammar """ 171 """ Generates a parser from the grammar (using a caching algorithm) """
172 signature = self.getSignature()
173 cache = shelve.open('__grammar_cache__.shelve')
174 # TODO: fix caching.
175 if ('signature1' in cache) and cache['signature'] == signature:
176 goto_table = cache['goto_table']
177 action_table = cache['action_table']
178 else:
179 action_table, goto_table = self.doGenerate()
180 cache['goto_table'] = goto_table
181 cache['action_table'] = action_table
182 cache['signature'] = signature
183 cache.close()
184 p = LRParser(action_table, goto_table, self.start_symbol)
185 p.grammar = self
186 return p
187
188 def doGenerate(self):
166 self.checkSymbols() 189 self.checkSymbols()
167 action_table = {} 190 action_table = {}
168 goto_table = {} 191 goto_table = {}
169 iis = self.initialItemSet() 192 iis = self.initialItemSet()
170 193
179 return 'Reduce {0}'.format(p) 202 return 'Reduce {0}'.format(p)
180 return 'Other' 203 return 'Other'
181 204
182 def setAction(state, t, action): 205 def setAction(state, t, action):
183 key = (state, t) 206 key = (state, t)
207 assert type(state) is int
208 assert type(t) is str
184 if key in action_table: 209 if key in action_table:
185 action2 = action_table[key] 210 action2 = action_table[key]
186 if action != action2: 211 if action != action2:
187 if (action2[0] == REDUCE) and (action[0] == SHIFT): 212 if (action2[0] == REDUCE) and (action[0] == SHIFT):
188 # Automatically resolve and do the shift action! 213 # Automatically resolve and do the shift action!
207 nextstate = transitions[(states.index(state), item.Next)] 232 nextstate = transitions[(states.index(state), item.Next)]
208 setAction(states.index(state), item.Next, (SHIFT, nextstate)) 233 setAction(states.index(state), item.Next, (SHIFT, nextstate))
209 if item.IsReduce: 234 if item.IsReduce:
210 if item.production.name == self.start_symbol and item.look_ahead == EOF: 235 if item.production.name == self.start_symbol and item.look_ahead == EOF:
211 # Rule 3: accept: 236 # Rule 3: accept:
212 setAction(states.index(state), item.look_ahead, (ACCEPT, item.production)) 237 setAction(states.index(state), item.look_ahead, (ACCEPT, self.productions.index(item.production)))
213 else: 238 else:
214 # Rule 2, reduce item: 239 # Rule 2, reduce item:
215 setAction(states.index(state), item.look_ahead, (REDUCE, item.production)) 240 setAction(states.index(state), item.look_ahead, (REDUCE, self.productions.index(item.production)))
216 for nt in self.nonterminals: 241 for nt in self.nonterminals:
217 key = (states.index(state), nt) 242 key = (states.index(state), nt)
218 if key in transitions: 243 if key in transitions:
219 goto_table[key] = transitions[key] 244 goto_table[key] = transitions[key]
220 245 return action_table, goto_table
221 return LRParser(action_table, goto_table, self.start_symbol)
222 246
223 247
224 class Production: 248 class Production:
225 """ Production rule for a grammar """ 249 """ Production rule for a grammar """
226 def __init__(self, name, symbols, f=None): 250 def __init__(self, name, symbols, f=None):
322 if not key in self.action_table: 346 if not key in self.action_table:
323 raise ParserException('Error parsing at character {0}'.format(look_ahead)) 347 raise ParserException('Error parsing at character {0}'.format(look_ahead))
324 action, param = self.action_table[key] 348 action, param = self.action_table[key]
325 if action == REDUCE: 349 if action == REDUCE:
326 f_args = [] 350 f_args = []
351 param = self.grammar.productions[param]
327 for s in param.symbols: 352 for s in param.symbols:
328 stack.pop() 353 stack.pop()
329 stack.pop() 354 stack.pop()
330 f_args.append(r_data_stack.pop()) 355 f_args.append(r_data_stack.pop())
331 f_args.reverse() 356 f_args.reverse()
346 look_ahead = Token(EOF, EOF) 371 look_ahead = Token(EOF, EOF)
347 assert type(look_ahead) is Token 372 assert type(look_ahead) is Token
348 elif action == ACCEPT: 373 elif action == ACCEPT:
349 # Pop last rule data off the stack: 374 # Pop last rule data off the stack:
350 f_args = [] 375 f_args = []
376 param = self.grammar.productions[param]
351 for s in param.symbols: 377 for s in param.symbols:
352 stack.pop() 378 stack.pop()
353 stack.pop() 379 stack.pop()
354 f_args.append(r_data_stack.pop()) 380 f_args.append(r_data_stack.pop())
355 f_args.reverse() 381 f_args.reverse()