用python写一个能够提取左公共因子、消除直接左递归、判断是否为ll1文法、能够利用预测分析表来判断句子能否产生的完整可运行代码
时间: 2023-12-30 20:06:52 浏览: 114
下面是一个能够提取左公共因子、消除直接左递归、判断是否为 LL(1) 文法、利用预测分析表来判断句子能否产生的完整 Python 代码:
```python
from collections import defaultdict
def extract_left_factor(grammar):
non_terminals = grammar.keys()
for A in non_terminals:
productions = grammar[A]
first_symbols = set([production[0] for production in productions])
for a in first_symbols:
common_prefix = []
for production in productions:
if production[0] == a:
common_prefix.append(production)
if len(common_prefix) > 1:
# extract left factor
new_non_terminal = A + "'"
new_productions = [(common_prefix[0][0], new_non_terminal)]
for production in common_prefix:
new_productions.append((production[1:],))
grammar[new_non_terminal] = new_productions
grammar[A] = [production for production in productions if production not in common_prefix]
grammar[A].append((a, new_non_terminal))
return True
return False
def eliminate_left_recursion(grammar):
non_terminals = grammar.keys()
for i, A in enumerate(non_terminals):
productions = grammar[A]
for j, beta in enumerate(productions):
if beta[0] == A:
# eliminate left recursion
new_non_terminal = A + "'"
new_productions = [production[1:] + (new_non_terminal,) for production in productions[:j]]
new_productions.append((new_non_terminal,))
for production in productions[j+1:]:
new_productions.append(production[1:] + (new_non_terminal,))
grammar[A] = [(production[1:], A+"'") for production in new_productions]
grammar[new_non_terminal] = [(production[1:], A+"'") for production in productions if production[0] != A] + [((),)]
return True
return False
def is_ll1_grammar(grammar):
first_sets = compute_first_sets(grammar)
follow_sets = compute_follow_sets(grammar, first_sets)
for A in grammar.keys():
productions = grammar[A]
for i in range(len(productions)):
for j in range(i+1, len(productions)):
if first_sets[A][i].intersection(first_sets[A][j]):
return False
if set(productions[i][1:]).intersection(follow_sets[A]).intersection(set(productions[j][1:])):
return False
return True
def compute_first_sets(grammar):
first_sets = defaultdict(lambda: set())
for A in grammar.keys():
productions = grammar[A]
for beta in productions:
if beta == ():
first_sets[A].add(())
elif beta[0] not in grammar.keys():
first_sets[A].add(beta[0])
else:
for symbol in beta:
if symbol not in grammar.keys():
first_sets[A].add(symbol)
break
if () not in grammar[symbol]:
first_sets[A] = first_sets[A].union(first_sets[symbol])
break
else:
first_sets[A] = first_sets[A].union(first_sets[symbol].difference({()}))
if symbol != beta[-1]:
continue
else:
first_sets[A].add(())
break
return first_sets
def compute_follow_sets(grammar, first_sets):
follow_sets = defaultdict(lambda: set())
start_symbol = list(grammar.keys())[0]
follow_sets[start_symbol].add('$')
while True:
is_updated = False
for A in grammar.keys():
productions = grammar[A]
for beta in productions:
for i, B in enumerate(beta):
if B in grammar.keys():
if i == len(beta) - 1:
follow_sets[B] = follow_sets[B].union(follow_sets[A])
else:
for b in first_sets[beta[i+1]]:
if b != ():
if b not in follow_sets[B]:
follow_sets[B].add(b)
is_updated = True
if () in first_sets[beta[i+1]] and i == len(beta) - 2:
follow_sets[B] = follow_sets[B].union(follow_sets[A])
is_updated = True
if not is_updated:
break
return follow_sets
def construct_predictive_table(grammar):
first_sets = compute_first_sets(grammar)
follow_sets = compute_follow_sets(grammar, first_sets)
table = defaultdict(lambda: defaultdict(list))
for A in grammar.keys():
productions = grammar[A]
for i, beta in enumerate(productions):
for a in first_sets[A][i]:
table[A][a].append(i)
if () in first_sets[A][i]:
for b in follow_sets[A]:
table[A][b].append(i)
return table
def parse_sentence(sentence, table):
stack = ['$']
sentence = sentence.split()
sentence.append('$')
current_symbol = stack[-1]
i = 0
while True:
if current_symbol == sentence[i]:
stack.pop()
i += 1
else:
if current_symbol not in table.keys():
return False
if sentence[i] not in table[current_symbol].keys():
return False
production = table[current_symbol][sentence[i]][0]
stack.pop()
if grammar[current_symbol][production] != ():
stack += list(reversed(grammar[current_symbol][production]))
if stack == ['$'] and sentence[i] == '$':
return True
elif stack == [] or i >= len(sentence):
return False
else:
current_symbol = stack[-1]
# example grammar
grammar = {
'S': [('A', 'B'), ('B', 'a')],
'A': [('A', 'c'), ()],
'B': [('B', 'b'), ()]
}
# extract left factor
while extract_left_factor(grammar):
pass
# eliminate left recursion
while eliminate_left_recursion(grammar):
pass
# check if it is LL(1) grammar
if is_ll1_grammar(grammar):
table = construct_predictive_table(grammar)
print(table)
# parse sentence
sentence = 'a b $'
is_accepted = parse_sentence(sentence, table)
print(is_accepted)
else:
print("Not an LL(1) grammar")
```
在上面的代码中,我们首先定义了四个函数:
- `extract_left_factor`:用于提取左公共因子;
- `eliminate_left_recursion`:用于消除直接左递归;
- `is_ll1_grammar`:用于判断是否为 LL(1) 文法;
- `compute_first_sets` 和 `compute_follow_sets`:用于计算 First 集和 Follow 集。
然后,我们使用给定的文法进行左公共因子提取和直接左递归消除,如果得到的文法是 LL(1) 文法,则构造预测分析表,并使用给定的句子进行语法分析,判断该句子是否能够被该文法所接受。
阅读全文