请用java实现LR(0)分析表的构造及测试例子
时间: 2024-01-01 12:05:10 浏览: 23
好的,下面是LR(0)分析表的构造及测试例子的Java代码:
```
import java.util.*;
public class LR0Parser {
private List<String[]> productions;
private Map<String, Set<String>> firstSets;
private Map<String, Set<String>> followSets;
private Map<String, Map<String, String>> actionTable;
private Map<String, Map<String, Integer>> gotoTable;
private String startSymbol;
public LR0Parser(List<String[]> productions, String startSymbol) {
this.productions = productions;
this.startSymbol = startSymbol;
this.firstSets = computeFirstSets();
this.followSets = computeFollowSets();
this.actionTable = computeActionTable();
this.gotoTable = computeGotoTable();
}
public boolean parse(List<String> input) {
Stack<String> stack = new Stack<>();
stack.push("0");
int inputIndex = 0;
while (!stack.isEmpty()) {
String state = stack.peek();
String symbol = inputIndex < input.size() ? input.get(inputIndex) : "$";
String action = actionTable.get(state).getOrDefault(symbol, "");
if (action.isEmpty()) {
return false;
} else if (action.startsWith("s")) {
int nextState = Integer.parseInt(action.substring(1));
stack.push(symbol);
stack.push(Integer.toString(nextState));
inputIndex++;
} else if (action.startsWith("r")) {
int productionIndex = Integer.parseInt(action.substring(1));
String[] production = productions.get(productionIndex);
int numSymbolsToRemove = production[1].split("\\s+").length;
for (int i = 0; i < numSymbolsToRemove * 2; i++) {
stack.pop();
}
String prevState = stack.peek();
String nonterminal = production[0];
int nextState = gotoTable.get(prevState).get(nonterminal);
stack.push(nonterminal);
stack.push(Integer.toString(nextState));
} else if (action.equals("acc")) {
return true;
}
}
return false;
}
private Map<String, Set<String>> computeFirstSets() {
Map<String, Set<String>> firstSets = new HashMap<>();
for (String[] production : productions) {
String nonterminal = production[0];
if (!firstSets.containsKey(nonterminal)) {
firstSets.put(nonterminal, new HashSet<>());
}
}
boolean changed;
do {
changed = false;
for (String[] production : productions) {
String nonterminal = production[0];
String[] symbols = production[1].split("\\s+");
for (String symbol : symbols) {
if (symbol.equals("epsilon")) {
changed |= firstSets.get(nonterminal).add("epsilon");
break;
} else if (isTerminal(symbol)) {
changed |= firstSets.get(nonterminal).add(symbol);
break;
} else {
Set<String> symbolFirstSet = firstSets.get(symbol);
for (String symbolFirst : symbolFirstSet) {
if (!symbolFirst.equals("epsilon")) {
changed |= firstSets.get(nonterminal).add(symbolFirst);
}
}
if (!symbolFirstSet.contains("epsilon")) {
break;
}
}
}
}
} while (changed);
return firstSets;
}
private Map<String, Set<String>> computeFollowSets() {
Map<String, Set<String>> followSets = new HashMap<>();
for (String[] production : productions) {
String nonterminal = production[0];
if (!followSets.containsKey(nonterminal)) {
followSets.put(nonterminal, new HashSet<>());
}
}
followSets.get(startSymbol).add("$");
boolean changed;
do {
changed = false;
for (String[] production : productions) {
String nonterminal = production[0];
String[] symbols = production[1].split("\\s+");
for (int i = 0; i < symbols.length; i++) {
String symbol = symbols[i];
if (isNonterminal(symbol)) {
Set<String> symbolFirstSet = firstSets.get(symbol);
for (String symbolFirst : symbolFirstSet) {
if (!symbolFirst.equals("epsilon")) {
changed |= followSets.get(symbol).add(symbolFirst);
}
}
if (symbolFirstSet.contains("epsilon") || i == symbols.length - 1) {
Set<String> nonterminalFollowSet = followSets.get(nonterminal);
for (String nonterminalFollow : nonterminalFollowSet) {
changed |= followSets.get(symbol).add(nonterminalFollow);
}
}
}
}
}
} while (changed);
return followSets;
}
private Map<String, Map<String, String>> computeActionTable() {
Map<String, Map<String, String>> actionTable = new HashMap<>();
for (int i = 0; i < productions.size(); i++) {
String[] production = productions.get(i);
String nonterminal = production[0];
String[] symbols = production[1].split("\\s+");
Set<String> followSet = followSets.get(nonterminal);
for (String symbol : followSet) {
if (!actionTable.containsKey(Integer.toString(i))) {
actionTable.put(Integer.toString(i), new HashMap<>());
}
actionTable.get(Integer.toString(i)).put(symbol, "r" + i);
}
}
for (int i = 0; i < productions.size(); i++) {
String[] production = productions.get(i);
String[] symbols = production[1].split("\\s+");
for (int j = 0; j < symbols.length; j++) {
String symbol = symbols[j];
if (isNonterminal(symbol)) {
int nextState = findNextState(i, symbol);
if (!actionTable.containsKey(Integer.toString(i))) {
actionTable.put(Integer.toString(i), new HashMap<>());
}
if (actionTable.get(Integer.toString(i)).containsKey(symbol)) {
if (!actionTable.get(Integer.toString(i)).get(symbol).equals("s" + nextState)) {
throw new RuntimeException("Reduce/shift conflict detected.");
}
} else {
actionTable.get(Integer.toString(i)).put(symbol, "s" + nextState);
}
} else if (isTerminal(symbol)) {
int nextState = findNextState(i, symbol);
if (!actionTable.containsKey(Integer.toString(i))) {
actionTable.put(Integer.toString(i), new HashMap<>());
}
if (actionTable.get(Integer.toString(i)).containsKey(symbol)) {
if (!actionTable.get(Integer.toString(i)).get(symbol).equals("s" + nextState)) {
throw new RuntimeException("Reduce/shift conflict detected.");
}
} else {
actionTable.get(Integer.toString(i)).put(symbol, "s" + nextState);
}
}
}
}
for (int i = 0; i < productions.size(); i++) {
if (!actionTable.containsKey(Integer.toString(i))) {
actionTable.put(Integer.toString(i), new HashMap<>());
}
if (productions.get(i)[0].equals(startSymbol)) {
actionTable.get(Integer.toString(i)).put("$", "acc");
}
}
return actionTable;
}
private Map<String, Map<String, Integer>> computeGotoTable() {
Map<String, Map<String, Integer>> gotoTable = new HashMap<>();
for (int i = 0; i < productions.size(); i++) {
String[] production = productions.get(i);
String[] symbols = production[1].split("\\s+");
for (int j = 0; j < symbols.length; j++) {
String symbol = symbols[j];
if (isNonterminal(symbol)) {
int nextState = findNextState(i, symbol);
if (!gotoTable.containsKey(Integer.toString(i))) {
gotoTable.put(Integer.toString(i), new HashMap<>());
}
gotoTable.get(Integer.toString(i)).put(symbol, nextState);
}
}
}
return gotoTable;
}
private int findNextState(int state, String symbol) {
for (int i = state + 1; i < productions.size(); i++) {
String[] production = productions.get(i);
if (production[0].equals(symbol)) {
return i;
}
}
return -1;
}
private boolean isTerminal(String symbol) {
return !isNonterminal(symbol);
}
private boolean isNonterminal(String symbol) {
return symbol.matches("[A-Z].*");
}
}
```
下面是一个测试例子,假设我们有以下文法:
```
S -> E
E -> E + T
E -> E - T
E -> T
T -> T * F
T -> T / F
T -> F
F -> ( E )
F -> id
```
我们可以使用以下代码来测试:
```
import java.util.*;
public class Main {
public static void main(String[] args) {
List<String[]> productions = new ArrayList<>();
productions.add(new String[] { "S", "E" });
productions.add(new String[] { "E", "E + T" });
productions.add(new String[] { "E", "E - T" });
productions.add(new String[] { "E", "T" });
productions.add(new String[] { "T", "T * F" });
productions.add(new String[] { "T", "T / F" });
productions.add(new String[] { "T", "F" });
productions.add(new String[] { "F", "( E )" });
productions.add(new String[] { "F", "id" });
LR0Parser parser = new LR0Parser(productions, "S");
List<String> input = Arrays.asList("id", "+", "id", "*", "id", "$");
if (parser.parse(input)) {
System.out.println("Accepted");
} else {
System.out.println("Rejected");
}
}
}
```
这个测试例子中,我们使用了一个包含加减乘除和括号的简单的表达式,用来测试LR(0)分析表的构造和使用。