@@ -202,6 +202,7 @@ def __init__(self, number, name, prod, precedence=('right', 0), func=None, file=
202202 self .file = file
203203 self .line = line
204204 self .prec = precedence
205+ self .lr0_added = 0
205206
206207 # Internal settings used during table construction
207208 self .len = len (self .prod ) # Length of the production
@@ -319,7 +320,7 @@ def __init__(self, p, n):
319320 self .prod = list (p .prod )
320321 self .number = p .number
321322 self .lr_index = n
322- self .lookaheads = {}
323+ self .lookaheads = defaultdict ( set )
323324 self .prod .insert (n , '.' )
324325 self .prod = tuple (self .prod )
325326 self .len = len (self .prod )
@@ -915,9 +916,7 @@ def traverse(x, N, stack, F, X, R, FP):
915916 if N [y ] == 0 :
916917 traverse (y , N , stack , F , X , R , FP )
917918 N [x ] = min (N [x ], N [y ])
918- for a in F .get (y , []):
919- if a not in F [x ]:
920- F [x ].append (a )
919+ F [x ].update (F [y ])
921920 if N [x ] == d :
922921 N [stack [- 1 ]] = MAXINT
923922 F [stack [- 1 ]] = F [x ]
@@ -945,7 +944,10 @@ def __init__(self, grammar):
945944 self .lr_action = {} # Action table
946945 self .lr_goto = {} # Goto table
947946 self .lr_productions = grammar .Productions # Copy of grammar Production array
948- self .lr_goto_cache = {} # Cache of computed gotos
947+
948+ # Cache of computed gotos
949+ self .lr_goto_cache = defaultdict (dict )
950+ self .lr_goto_cache2 = {}
949951 self .lr0_cidhash = {} # Cache of closures
950952 self ._add_count = 0 # Internal counter used to detect cycles
951953
@@ -977,6 +979,11 @@ def __init__(self, grammar):
977979 rules = list (actions .values ())
978980 if len (rules ) == 1 and rules [0 ] < 0 :
979981 self .defaulted_states [state ] = rules [0 ]
982+ # clear cache
983+ self .lr_goto_cache = None
984+ self .lr_goto_cache2 = None
985+ self .lr0_cidhash = None
986+ self .grammar = None
980987
981988 # Compute the LR(0) closure operation on I, where I is a set of LR(0) items.
982989 def lr0_closure (self , I ):
@@ -989,7 +996,7 @@ def lr0_closure(self, I):
989996 didadd = False
990997 for j in J :
991998 for x in j .lr_after :
992- if getattr ( x , ' lr0_added' , 0 ) == self ._add_count :
999+ if x . lr0_added == self ._add_count :
9931000 continue
9941001 # Add B --> .G to J
9951002 J .append (x .lr_next )
@@ -1005,40 +1012,60 @@ def lr0_closure(self, I):
10051012 # objects). With uniqueness, we can later do fast set comparisons using
10061013 # id(obj) instead of element-wise comparison.
10071014
1008- def lr0_goto (self , I , x ):
1015+ def lr0_goto (self , I , x , I_d = None ):
10091016 # First we look for a previously cached entry
1010- g = self .lr_goto_cache . get (( id (I ), x ) )
1017+ g = self .lr_goto_cache [ id (I )]. get ( x )
10111018 if g :
10121019 return g
10131020
10141021 # Now we generate the goto set in a way that guarantees uniqueness
10151022 # of the result
10161023
1017- s = self .lr_goto_cache .get (x )
1024+ s = self .lr_goto_cache2 .get (x )
10181025 if not s :
10191026 s = {}
1020- self .lr_goto_cache [x ] = s
1027+ self .lr_goto_cache2 [x ] = s
10211028
10221029 gs = []
1023- for p in I :
1024- n = p .lr_next
1025- if n and n .lr_before == x :
1030+
1031+ if I_d is None :
1032+ for p in I :
1033+ n = p .lr_next
1034+ if n and n .lr_before == x :
1035+ s1 = s .get (id (n ))
1036+ if not s1 :
1037+ s1 = {}
1038+ s [id (n )] = s1
1039+ gs .append (n )
1040+ s = s1
1041+ else :
1042+ for n in I_d [x ]:
10261043 s1 = s .get (id (n ))
10271044 if not s1 :
10281045 s1 = {}
10291046 s [id (n )] = s1
10301047 gs .append (n )
10311048 s = s1
1049+
10321050 g = s .get ('$end' )
10331051 if not g :
10341052 if gs :
10351053 g = self .lr0_closure (gs )
10361054 s ['$end' ] = g
10371055 else :
10381056 s ['$end' ] = gs
1039- self .lr_goto_cache [( id (I ), x ) ] = g
1057+ self .lr_goto_cache [id (I )][ x ] = g
10401058 return g
10411059
1060+ def get_i_map (self , I ):
1061+ # creates structure for faster search
1062+ I_d = defaultdict (list )
1063+ for p in I :
1064+ n = p .lr_next
1065+ if n :
1066+ I_d [n .lr_before ].append (n )
1067+ return I_d
1068+
10421069 # Compute the LR(0) sets of item function
10431070 def lr0_items (self ):
10441071 C = [self .lr0_closure ([self .grammar .Productions [0 ].lr_next ])]
@@ -1053,14 +1080,16 @@ def lr0_items(self):
10531080 I = C [i ]
10541081 i += 1
10551082
1083+ I_d = self .get_i_map (I )
1084+
10561085 # Collect all of the symbols that could possibly be in the goto(I,X) sets
10571086 asyms = {}
10581087 for ii in I :
10591088 for s in ii .usyms :
10601089 asyms [s ] = None
10611090
10621091 for x in asyms :
1063- g = self .lr0_goto (I , x )
1092+ g = self .lr0_goto (I , x , I_d )
10641093 if not g or id (g ) in self .lr0_cidhash :
10651094 continue
10661095 self .lr0_cidhash [id (g )] = len (C )
@@ -1146,21 +1175,19 @@ def find_nonterminal_transitions(self, C):
11461175 # -----------------------------------------------------------------------------
11471176
11481177 def dr_relation (self , C , trans , nullable ):
1149- dr_set = {}
11501178 state , N = trans
1151- terms = []
1179+ terms = set ()
11521180
11531181 g = self .lr0_goto (C [state ], N )
11541182 for p in g :
11551183 if p .lr_index < p .len - 1 :
11561184 a = p .prod [p .lr_index + 1 ]
11571185 if a in self .grammar .Terminals :
1158- if a not in terms :
1159- terms .append (a )
1186+ terms .add (a )
11601187
11611188 # This extra bit is to handle the start state
11621189 if state == 0 and N == self .grammar .Productions [0 ].prod [0 ]:
1163- terms .append ('$end' )
1190+ terms .add ('$end' )
11641191
11651192 return terms
11661193
@@ -1335,14 +1362,11 @@ def compute_follow_sets(self, ntrans, readsets, inclsets):
13351362
13361363 def add_lookaheads (self , lookbacks , followset ):
13371364 for trans , lb in lookbacks .items ():
1365+ f = followset [trans ]
1366+
13381367 # Loop over productions in lookback
13391368 for state , p in lb :
1340- if state not in p .lookaheads :
1341- p .lookaheads [state ] = set ()
1342-
1343- f = followset .get (trans , [])
1344- for a in f :
1345- p .lookaheads [state ].add (a )
1369+ p .lookaheads [state ].update (f )
13461370
13471371 # -----------------------------------------------------------------------------
13481372 # add_lalr_lookaheads()
@@ -1391,6 +1415,8 @@ def lr_parse_table(self):
13911415
13921416 # Build the parser table, state by state
13931417 for st , I in enumerate (C ):
1418+ I_d = self .get_i_map (I )
1419+
13941420 descrip = []
13951421 # Loop over each production in I
13961422 actlist = [] # List of actions
@@ -1468,7 +1494,7 @@ def lr_parse_table(self):
14681494 i = p .lr_index
14691495 a = p .prod [i + 1 ] # Get symbol right after the "."
14701496 if a in self .grammar .Terminals :
1471- g = self .lr0_goto (I , a )
1497+ g = self .lr0_goto (I , a , I_d )
14721498 j = self .lr0_cidhash .get (id (g ), - 1 )
14731499 if j >= 0 :
14741500 # We are in a shift state
@@ -1524,7 +1550,7 @@ def lr_parse_table(self):
15241550 if s in self .grammar .Nonterminals :
15251551 nkeys [s ] = None
15261552 for n in nkeys :
1527- g = self .lr0_goto (I , n )
1553+ g = self .lr0_goto (I , n , I_d )
15281554 j = self .lr0_cidhash .get (id (g ), - 1 )
15291555 if j >= 0 :
15301556 st_goto [n ] = j
0 commit comments