用Java语言实现预测分析法。给出源代码,首先判断任一给定文法是否为LL(1)文法,然后构造其预测分析表和预测分析程序。 输入:一个文法、一个字符串。 输出:预测分析表、判定结果: (1)是LL1文法,则同时输出分析结果。 (2)不是LL1文法。
时间: 2024-02-12 08:08:51 浏览: 78
基于LL(1)文法的预测分析表法
以下是一个简单的Java实现,包括LL(1)文法的判断、预测分析表的构造和预测分析程序的实现。请注意,此代码只作为参考,可能需要根据实际情况进行修改和完善。
```
import java.util.*;
public class LL1Parser {
private Map<String, Set<String>> firstSet; // FIRST集合
private Map<String, Set<String>> followSet; // FOLLOW集合
private Map<String, Map<String, String>> predictTable; // 预测分析表
private List<String> productionList; // 产生式列表
private String startSymbol; // 起始符号
private List<String> parseStack; // 分析栈
public LL1Parser(Map<String, List<String>> grammar, String startSymbol) {
this.firstSet = new HashMap<>();
this.followSet = new HashMap<>();
this.predictTable = new HashMap<>();
this.productionList = new ArrayList<>();
this.startSymbol = startSymbol;
this.parseStack = new ArrayList<>();
// 构造产生式列表
for (Map.Entry<String, List<String>> entry : grammar.entrySet()) {
String nonTerminal = entry.getKey();
List<String> productions = entry.getValue();
for (String production : productions) {
productionList.add(nonTerminal + "->" + production);
}
}
// 计算FIRST集合
for (String nonTerminal : grammar.keySet()) {
firstSet.put(nonTerminal, calculateFirst(nonTerminal, grammar));
}
// 计算FOLLOW集合
for (String nonTerminal : grammar.keySet()) {
followSet.put(nonTerminal, calculateFollow(nonTerminal, grammar));
}
// 构造预测分析表
for (String production : productionList) {
String[] parts = production.split("->");
String nonTerminal = parts[0];
String[] symbols = parts[1].split("\\s+");
for (String terminal : firstSet.get(symbols[0])) {
if (!terminal.equals("epsilon")) {
addPredictEntry(nonTerminal, terminal, production);
}
}
if (firstSet.get(symbols[0]).contains("epsilon")) {
for (String terminal : followSet.get(nonTerminal)) {
addPredictEntry(nonTerminal, terminal, production);
}
}
if (symbols.length == 1 && symbols[0].equals("epsilon")) {
for (String terminal : followSet.get(nonTerminal)) {
addPredictEntry(nonTerminal, terminal, production);
}
}
}
}
// 计算指定非终结符的FIRST集合
private Set<String> calculateFirst(String nonTerminal, Map<String, List<String>> grammar) {
Set<String> result = new HashSet<>();
for (String production : grammar.get(nonTerminal)) {
String[] symbols = production.split("\\s+");
if (isTerminal(symbols[0])) {
result.add(symbols[0]);
} else if (isNonTerminal(symbols[0])) {
result.addAll(calculateFirst(symbols[0], grammar));
} else {
boolean canEpsilon = true;
for (int i = 0; i < symbols.length && canEpsilon; i++) {
if (isTerminal(symbols[i])) {
result.add(symbols[i]);
canEpsilon = false;
} else if (isNonTerminal(symbols[i])) {
Set<String> first = calculateFirst(symbols[i], grammar);
result.addAll(first);
canEpsilon = first.contains("epsilon");
} else {
throw new IllegalArgumentException("Invalid symbol: " + symbols[i]);
}
}
if (canEpsilon) {
result.add("epsilon");
}
}
}
return result;
}
// 计算指定非终结符的FOLLOW集合
private Set<String> calculateFollow(String nonTerminal, Map<String, List<String>> grammar) {
Set<String> result = new HashSet<>();
if (nonTerminal.equals(startSymbol)) {
result.add("$");
}
for (String production : productionList) {
String[] parts = production.split("->");
String left = parts[0];
String[] right = parts[1].split("\\s+");
for (int i = 0; i < right.length; i++) {
if (right[i].equals(nonTerminal)) {
if (i == right.length - 1) {
result.addAll(followSet.get(left));
} else {
Set<String> first = calculateFirst(right[i + 1], grammar);
result.addAll(first);
if (first.contains("epsilon")) {
result.addAll(followSet.get(left));
}
}
}
}
}
return result;
}
// 添加预测分析表的一项
private void addPredictEntry(String nonTerminal, String terminal, String production) {
if (!predictTable.containsKey(nonTerminal)) {
predictTable.put(nonTerminal, new HashMap<>());
}
Map<String, String> row = predictTable.get(nonTerminal);
if (row.containsKey(terminal)) {
throw new IllegalArgumentException("Conflict in predict table: " + nonTerminal + ", " + terminal);
}
row.put(terminal, production);
}
// 判断指定符号是否为终结符
private boolean isTerminal(String symbol) {
return !symbol.startsWith("<") && !symbol.endsWith(">");
}
// 判断指定符号是否为非终结符
private boolean isNonTerminal(String symbol) {
return symbol.startsWith("<") && symbol.endsWith(">");
}
// 执行预测分析程序
public boolean parse(String input) {
parseStack.clear();
parseStack.add("$");
parseStack.add(startSymbol);
List<String> inputList = Arrays.asList(input.split("\\s+"));
int inputPointer = 0;
while (!parseStack.isEmpty()) {
String top = parseStack.get(parseStack.size() - 1);
String currentInput = inputPointer >= inputList.size() ? "$" : inputList.get(inputPointer);
if (isTerminal(top)) {
if (top.equals(currentInput)) {
parseStack.remove(parseStack.size() - 1);
inputPointer++;
} else {
return false;
}
} else if (isNonTerminal(top)) {
Map<String, String> row = predictTable.get(top);
String production = row.get(currentInput);
if (production != null) {
parseStack.remove(parseStack.size() - 1);
String[] symbols = production.split("\\s+");
for (int i = symbols.length - 1; i >= 0; i--) {
if (!symbols[i].equals("epsilon")) {
parseStack.add(symbols[i]);
}
}
} else {
return false;
}
} else {
throw new IllegalStateException("Invalid symbol on parse stack: " + top);
}
}
return true;
}
}
```
使用示例:
```
Map<String, List<String>> grammar = new HashMap<>();
grammar.put("<S>", Arrays.asList("<A> <B>"));
grammar.put("<A>", Arrays.asList("a", "<B>"));
grammar.put("<B>", Arrays.asList("b", "<A>", "epsilon"));
LL1Parser parser = new LL1Parser(grammar, "<S>");
System.out.println(parser.parse("a b")); // true
System.out.println(parser.parse("a b b")); // true
System.out.println(parser.parse("a b a")); // false
```
在这个例子中,我们定义了一个文法,判断其是否为LL(1)文法并构造预测分析表。然后我们使用预测分析程序来解析输入字符串,判断其是否符合文法规则。
阅读全文