Handle mutual recursion in gen_follow
Also an example of a case where SLR1 fails, to lead into LR1 generation.
This commit is contained in:
parent
a2e8a784c2
commit
c4be7bcd9f
1 changed files with 25 additions and 2 deletions
27
parser.py
27
parser.py
|
|
@ -378,7 +378,7 @@ class GenerateSLR1(GenerateLR0):
|
||||||
result = result + self.gen_first(symbols[1:], visited)
|
result = result + self.gen_first(symbols[1:], visited)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def gen_follow(self, symbol):
|
def gen_follow(self, symbol, visited=None):
|
||||||
"""Generate the follow set for the given nonterminal.
|
"""Generate the follow set for the given nonterminal.
|
||||||
|
|
||||||
The follow set for a nonterminal is the set of terminals that can
|
The follow set for a nonterminal is the set of terminals that can
|
||||||
|
|
@ -390,6 +390,14 @@ class GenerateSLR1(GenerateLR0):
|
||||||
return tuple('$')
|
return tuple('$')
|
||||||
|
|
||||||
assert symbol in self.nonterminals
|
assert symbol in self.nonterminals
|
||||||
|
|
||||||
|
# Deal with left-recursion.
|
||||||
|
if visited is None:
|
||||||
|
visited = set()
|
||||||
|
if symbol in visited:
|
||||||
|
return ()
|
||||||
|
visited.add(symbol)
|
||||||
|
|
||||||
follow = ()
|
follow = ()
|
||||||
for production in self.grammar:
|
for production in self.grammar:
|
||||||
for index, prod_symbol in enumerate(production[1]):
|
for index, prod_symbol in enumerate(production[1]):
|
||||||
|
|
@ -399,7 +407,7 @@ class GenerateSLR1(GenerateLR0):
|
||||||
first = self.gen_first(production[1][index+1:])
|
first = self.gen_first(production[1][index+1:])
|
||||||
follow = follow + tuple(f for f in first if f is not None)
|
follow = follow + tuple(f for f in first if f is not None)
|
||||||
if None in first:
|
if None in first:
|
||||||
follow = follow + self.gen_follow(production[0])
|
follow = follow + self.gen_follow(production[0], visited)
|
||||||
|
|
||||||
assert None not in follow # Should always ground out at __start
|
assert None not in follow # Should always ground out at __start
|
||||||
return follow
|
return follow
|
||||||
|
|
@ -570,3 +578,18 @@ table = gen.gen_table()
|
||||||
print(format_table(gen, table))
|
print(format_table(gen, table))
|
||||||
tree = parse(table, ['id', '+', '(', 'id', '[', 'id', ']', ')'])
|
tree = parse(table, ['id', '+', '(', 'id', '[', 'id', ']', ')'])
|
||||||
print(format_node(tree) + "\n")
|
print(format_node(tree) + "\n")
|
||||||
|
|
||||||
|
# SLR1 can't handle this.
|
||||||
|
grammar_aho_ullman = [
|
||||||
|
('S', ['L', '=', 'R']),
|
||||||
|
('S', ['R']),
|
||||||
|
('L', ['*', 'R']),
|
||||||
|
('L', ['id']),
|
||||||
|
('R', ['L']),
|
||||||
|
]
|
||||||
|
try:
|
||||||
|
gen = GenerateSLR1('S', grammar_aho_ullman)
|
||||||
|
table = gen.gen_table()
|
||||||
|
assert False
|
||||||
|
except ValueError as e:
|
||||||
|
print(e)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue