-
Notifications
You must be signed in to change notification settings - Fork 1
/
left_recursion_eliminator.py
80 lines (66 loc) · 2.46 KB
/
left_recursion_eliminator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#!/usr/bin/env python
from grammar import Grammar, Production
class _EliminateLeftRecursion:
def __init__(self, grammar: Grammar):
self.grammar = grammar
self.nterms = tuple(grammar.prods.keys())
for elim_idx, elim in enumerate(self.nterms):
prods = self.grammar.prods[elim]
prods = self.elim_indirect(elim, elim_idx, prods)
prods = self.elim_direct(elim, prods)
self.grammar.prods[elim] = prods
def elim_direct(self, elim, elim_prods):
recur_prods = list()
nonrecur_prods = list()
for prod in elim_prods:
if prod.syms[0] == elim:
recur_prods.append(prod)
else:
nonrecur_prods.append(prod)
if not recur_prods:
return nonrecur_prods
new_nterm = self.grammar.get_alt_nonterminal(elim)
for recur_prod in recur_prods:
syms = list(recur_prod.syms[1:])
syms.append(new_nterm)
self.grammar.add_production(new_nterm, syms)
self.grammar.add_production(new_nterm, '@')
new_prods = list()
for prod in nonrecur_prods:
syms = list(prod.syms)
syms.append(new_nterm)
new_prods.append(Production(elim, syms))
return new_prods
def elim_indirect(self, elim, elim_idx, elim_prods):
new_prods = list()
replaced = [False] * len(elim_prods)
for chk in self.nterms[:elim_idx]:
chk_prods = self.grammar.prods[chk]
for prod_idx, prod in enumerate(elim_prods):
if prod.syms[0] == chk:
# Replace prod.nterm -> chk other_syms
# with prod.nterm -> chk.syms other_syms
for chk_prod in chk_prods:
new_syms = chk_prod.syms + prod.syms[1:]
new_prods.append(Production(elim, new_syms))
replaced[prod_idx] = True
for prod_idx, prod in enumerate(elim_prods):
if not replaced[prod_idx]:
new_prods.append(prod)
return new_prods
def eliminate(grammar: Grammar):
dup = grammar.duplicate()
elim = _EliminateLeftRecursion(dup)
return elim.grammar
def main():
bnf = '''
S := X a | b
X := X c | S d | @
'''
from bnf_parser import parse
grammar = parse(bnf)
elim_grammar = eliminate(grammar)
print(grammar)
print(elim_grammar)
if __name__ == '__main__':
main()