faster: first symbol cache

This commit is contained in:
John Doty 2024-04-13 13:16:26 -07:00
parent 9cf9880bd1
commit e1240759eb

View file

@ -423,6 +423,10 @@ class GenerateSLR1(GenerateLR0):
means they need to know how to generate 'first(A)', which is most of the means they need to know how to generate 'first(A)', which is most of the
code in this class. code in this class.
""" """
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._first_symbol_cache = {}
def gen_first_symbol(self, symbol, visited): def gen_first_symbol(self, symbol, visited):
"""Compute the first set for a single symbol. """Compute the first set for a single symbol.
@ -447,6 +451,10 @@ class GenerateSLR1(GenerateLR0):
assert symbol in self.nonterminals assert symbol in self.nonterminals
visited.add(symbol) visited.add(symbol)
cached_result = self._first_symbol_cache.get(symbol, None)
if cached_result:
return cached_result
# All the firsts from all the productions. # All the firsts from all the productions.
firsts = [ firsts = [
self.gen_first(rule[1], visited) self.gen_first(rule[1], visited)
@ -455,7 +463,9 @@ class GenerateSLR1(GenerateLR0):
] ]
result = {f for fs in firsts for f in fs} result = {f for fs in firsts for f in fs}
return tuple(sorted(result, key=lambda x: (x is None, x))) result = tuple(sorted(result, key=lambda x: (x is None, x)))
self._first_symbol_cache[symbol] = result
return result
def gen_first(self, symbols, visited=None): def gen_first(self, symbols, visited=None):
"""Compute the first set for a sequence of symbols. """Compute the first set for a sequence of symbols.