faster: gen closure iterative
This commit is contained in:
parent
e1240759eb
commit
ade859d6a0
1 changed files with 26 additions and 22 deletions
|
|
@ -5,9 +5,9 @@ This version has some performance work done.
|
||||||
|
|
||||||
2023
|
2023
|
||||||
"""
|
"""
|
||||||
|
import functools
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# LR0
|
# LR0
|
||||||
#
|
#
|
||||||
|
|
@ -113,6 +113,14 @@ class GenerateLR0(object):
|
||||||
# rule, and in the set of states and table and whatever the first
|
# rule, and in the set of states and table and whatever the first
|
||||||
# element is always the starting state/position.
|
# element is always the starting state/position.
|
||||||
self.grammar = [('__start', [start])] + grammar
|
self.grammar = [('__start', [start])] + grammar
|
||||||
|
|
||||||
|
# Convert the grammar into fully immutable tuples so we can hash
|
||||||
|
# everything.
|
||||||
|
self.grammar = tuple(
|
||||||
|
(name, tuple(symbols))
|
||||||
|
for name, symbols in self.grammar
|
||||||
|
)
|
||||||
|
|
||||||
self.nonterminals = {rule[0] for rule in grammar}
|
self.nonterminals = {rule[0] for rule in grammar}
|
||||||
self.terminals = {
|
self.terminals = {
|
||||||
sym
|
sym
|
||||||
|
|
@ -155,21 +163,21 @@ class GenerateLR0(object):
|
||||||
if rule[0] == config.next
|
if rule[0] == config.next
|
||||||
)
|
)
|
||||||
|
|
||||||
def gen_closure(self, config, closure):
|
def gen_closure(self, seeds):
|
||||||
"""Compute the closure for the specified config and unify it with the
|
"""Compute the closure for the specified configs. We have replaced a
|
||||||
existing closure.
|
recursive version with an iterative one."""
|
||||||
|
closure = set()
|
||||||
|
pending = list(seeds)
|
||||||
|
while len(pending) > 0:
|
||||||
|
config = pending.pop()
|
||||||
|
if config in closure:
|
||||||
|
continue
|
||||||
|
|
||||||
If the provided config is already in the closure then nothing is
|
closure.add(config)
|
||||||
done. (We assume that the closure of the config is *also* already in
|
|
||||||
the closure.)
|
|
||||||
"""
|
|
||||||
if config in closure:
|
|
||||||
return closure
|
|
||||||
else:
|
|
||||||
new_closure = tuple(closure) + (config,)
|
|
||||||
for next_config in self.gen_closure_next(config):
|
for next_config in self.gen_closure_next(config):
|
||||||
new_closure = self.gen_closure(next_config, new_closure)
|
pending.append(next_config)
|
||||||
return new_closure
|
|
||||||
|
return tuple(closure) # TODO: Why tuple?
|
||||||
|
|
||||||
def gen_successor(self, config_set, symbol):
|
def gen_successor(self, config_set, symbol):
|
||||||
"""Compute the successor state for the given config set and the
|
"""Compute the successor state for the given config set and the
|
||||||
|
|
@ -184,10 +192,7 @@ class GenerateLR0(object):
|
||||||
if config.at_symbol(symbol)
|
if config.at_symbol(symbol)
|
||||||
]
|
]
|
||||||
|
|
||||||
closure = ()
|
closure = self.gen_closure(seeds)
|
||||||
for seed in seeds:
|
|
||||||
closure = self.gen_closure(seed, closure)
|
|
||||||
|
|
||||||
return closure
|
return closure
|
||||||
|
|
||||||
def gen_all_successors(self, config_set):
|
def gen_all_successors(self, config_set):
|
||||||
|
|
@ -216,8 +221,7 @@ class GenerateLR0(object):
|
||||||
def gen_all_sets(self):
|
def gen_all_sets(self):
|
||||||
"""Generate all of the configuration sets for the grammar."""
|
"""Generate all of the configuration sets for the grammar."""
|
||||||
initial_set = self.gen_closure(
|
initial_set = self.gen_closure(
|
||||||
Configuration.from_rule(self.grammar[0]),
|
[ Configuration.from_rule(self.grammar[0]) ]
|
||||||
(),
|
|
||||||
)
|
)
|
||||||
return self.gen_sets(initial_set, ())
|
return self.gen_sets(initial_set, ())
|
||||||
|
|
||||||
|
|
@ -601,8 +605,7 @@ class GenerateLR1(GenerateSLR1):
|
||||||
symbol to '$'.
|
symbol to '$'.
|
||||||
"""
|
"""
|
||||||
initial_set = self.gen_closure(
|
initial_set = self.gen_closure(
|
||||||
Configuration.from_rule(self.grammar[0], lookahead=('$',)),
|
[ Configuration.from_rule(self.grammar[0], lookahead=('$',)) ],
|
||||||
(),
|
|
||||||
)
|
)
|
||||||
return self.gen_sets(initial_set, ())
|
return self.gen_sets(initial_set, ())
|
||||||
|
|
||||||
|
|
@ -750,6 +753,7 @@ def examples():
|
||||||
|
|
||||||
gen = GenerateLR0('E', grammar_simple)
|
gen = GenerateLR0('E', grammar_simple)
|
||||||
table = gen.gen_table()
|
table = gen.gen_table()
|
||||||
|
print(format_table(gen, table))
|
||||||
tree = parse(table, ['id', '+', '(', 'id', ')'])
|
tree = parse(table, ['id', '+', '(', 'id', ')'])
|
||||||
print(format_node(tree) + "\n")
|
print(format_node(tree) + "\n")
|
||||||
print()
|
print()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue