diff 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
line wrap: on
line diff
--- a/python/pyyacc.py	Fri Jul 05 14:13:59 2013 +0200
+++ b/python/pyyacc.py	Fri Jul 05 15:30:22 2013 +0200
@@ -2,6 +2,8 @@
   Parser generator script
 """
 
+import shelve
+import hashlib
 from ppci import Token
 
 EPS = 'EPS'
@@ -160,9 +162,30 @@
                 if symbol not in self.Symbols + [EPS]:
                     raise ParserGenerationException('Symbol {0} undefined'.format(symbol))
 
-
+    def getSignature(self):
+        m = hashlib.md5()
+        m.update((str(self.productions) + str(self.start_symbol)).encode('ascii'))
+        signature = m.hexdigest()
+        
     def genParser(self):
-        """ Generates a parser from the grammar """
+        """ Generates a parser from the grammar (using a caching algorithm) """
+        signature = self.getSignature() 
+        cache = shelve.open('__grammar_cache__.shelve')
+        # TODO: fix caching.
+        if ('signature1' in cache) and cache['signature'] == signature:
+            goto_table = cache['goto_table']
+            action_table = cache['action_table']
+        else:
+            action_table, goto_table = self.doGenerate()
+            cache['goto_table'] = goto_table
+            cache['action_table'] = action_table
+            cache['signature'] = signature
+        cache.close()
+        p = LRParser(action_table, goto_table, self.start_symbol)
+        p.grammar = self
+        return p
+
+    def doGenerate(self):
         self.checkSymbols()
         action_table = {}
         goto_table = {}
@@ -181,6 +204,8 @@
         
         def setAction(state, t, action):
             key = (state, t)
+            assert type(state) is int
+            assert type(t) is str
             if key in action_table:
                 action2 = action_table[key]
                 if action != action2:
@@ -209,16 +234,15 @@
                 if item.IsReduce:
                     if item.production.name == self.start_symbol and item.look_ahead == EOF:
                         # Rule 3: accept:
-                        setAction(states.index(state), item.look_ahead, (ACCEPT, item.production))
+                        setAction(states.index(state), item.look_ahead, (ACCEPT, self.productions.index(item.production)))
                     else:
                         # Rule 2, reduce item:
-                        setAction(states.index(state), item.look_ahead, (REDUCE, item.production))
+                        setAction(states.index(state), item.look_ahead, (REDUCE, self.productions.index(item.production)))
             for nt in self.nonterminals:
                 key = (states.index(state), nt)
                 if key in transitions:
                     goto_table[key] = transitions[key]
-
-        return LRParser(action_table, goto_table, self.start_symbol)
+        return action_table, goto_table
 
 
 class Production:
@@ -324,6 +348,7 @@
             action, param = self.action_table[key]
             if action == REDUCE:
                 f_args = []
+                param = self.grammar.productions[param]
                 for s in param.symbols:
                     stack.pop()
                     stack.pop()
@@ -348,6 +373,7 @@
             elif action == ACCEPT:
                 # Pop last rule data off the stack:
                 f_args = []
+                param = self.grammar.productions[param]
                 for s in param.symbols:
                     stack.pop()
                     stack.pop()