用java实现一个任意文法的FirstVt,并附上测试用例以及加上注释
时间: 2024-02-09 14:12:00 浏览: 20
好的,以下是用Java实现一个任意文法的FirstVt算法的示例代码,包含注释和测试用例:
```java
import java.util.*;
public class FirstVt {
// 存储文法规则
private Map<String, List<String>> grammar;
// 存储FirstVt集合
private Map<String, Set<String>> firstVt;
/**
* 构造函数,初始化文法规则和FirstVt集合
* @param grammar 文法规则
*/
public FirstVt(Map<String, List<String>> grammar) {
this.grammar = grammar;
this.firstVt = new HashMap<>();
// 初始化FirstVt集合,将非终结符号对应的FirstVt集合设为空集
for (String nonTerminal : grammar.keySet()) {
firstVt.put(nonTerminal, new HashSet<>());
}
}
/**
* 计算FirstVt集合
*/
public void computeFirstVt() {
// 对每个非终结符号,求其FirstVt集合
for (String nonTerminal : grammar.keySet()) {
computeFirstVtForNonTerminal(nonTerminal);
}
}
/**
* 计算指定非终结符号的FirstVt集合
* @param nonTerminal 非终结符号
*/
private void computeFirstVtForNonTerminal(String nonTerminal) {
// 如果FirstVt集合已经求出来了,直接返回
if (!firstVt.get(nonTerminal).isEmpty()) {
return;
}
// 遍历该非终结符号对应的所有产生式,求出其FirstVt集合
for (String production : grammar.get(nonTerminal)) {
// 如果产生式为空串,则将空串加入FirstVt集合
if (production.equals("")) {
firstVt.get(nonTerminal).add("");
}
// 如果产生式的第一个符号是终结符号,则将其加入FirstVt集合
else if (isTerminal(production.charAt(0))) {
firstVt.get(nonTerminal).add(production.substring(0, 1));
}
// 如果产生式的第一个符号是非终结符号,则递归求出其FirstVt集合
else {
// 递归求出第一个符号的FirstVt集合
String firstSymbol = production.substring(0, 1);
computeFirstVtForNonTerminal(firstSymbol);
// 将第一个符号的FirstVt集合中的所有符号加入该非终结符号的FirstVt集合
firstVt.get(nonTerminal).addAll(firstVt.get(firstSymbol));
// 如果产生式可以推导出空串,则继续处理后面的符号
if (canDeriveEmpty(production, 0)) {
// 如果产生式只有一个符号,并且可以推导出空串,则将空串加入该非终结符号的FirstVt集合
if (production.length() == 1) {
firstVt.get(nonTerminal).add("");
}
// 如果产生式有多个符号,则继续处理后面的符号
else {
// 求出剩余符号的FirstVt集合
String restProduction = production.substring(1);
Set<String> restFirstVt = computeFirstVtForSymbolString(restProduction);
// 将剩余符号的FirstVt集合中的所有符号加入该非终结符号的FirstVt集合
firstVt.get(nonTerminal).addAll(restFirstVt);
}
}
}
}
}
/**
* 计算指定符号串的FirstVt集合
* @param symbolString 符号串
* @return FirstVt集合
*/
private Set<String> computeFirstVtForSymbolString(String symbolString) {
Set<String> result = new HashSet<>();
// 如果符号串为空,则将空串加入FirstVt集合
if (symbolString.equals("")) {
result.add("");
}
// 如果符号串的第一个符号是终结符号,则将其加入FirstVt集合
else if (isTerminal(symbolString.charAt(0))) {
result.add(symbolString.substring(0, 1));
}
// 如果符号串的第一个符号是非终结符号,则求出其FirstVt集合
else {
// 递归求出第一个符号的FirstVt集合
String firstSymbol = symbolString.substring(0, 1);
Set<String> firstVtOfFirstSymbol = new HashSet<>(firstVt.get(firstSymbol));
// 将第一个符号的FirstVt集合中的所有符号加入结果集合
result.addAll(firstVtOfFirstSymbol);
// 如果符号串可以推导出空串,则继续处理后面的符号
if (canDeriveEmpty(symbolString, 0)) {
// 如果符号串只有一个符号,并且可以推导出空串,则将空串加入结果集合
if (symbolString.length() == 1) {
result.add("");
}
// 如果符号串有多个符号,则继续处理后面的符号
else {
// 求出剩余符号的FirstVt集合
String restSymbolString = symbolString.substring(1);
Set<String> restFirstVt = computeFirstVtForSymbolString(restSymbolString);
// 将剩余符号的FirstVt集合中的所有符号加入结果集合
result.addAll(restFirstVt);
}
}
}
return result;
}
/**
* 判断指定符号是否是终结符号
* @param symbol 符号
* @return 是否是终结符号
*/
private boolean isTerminal(char symbol) {
return !grammar.containsKey(String.valueOf(symbol));
}
/**
* 判断指定符号串是否可以推导出空串
* @param symbolString 符号串
* @param startIndex 起始下标
* @return 是否可以推导出空串
*/
private boolean canDeriveEmpty(String symbolString, int startIndex) {
// 如果下标越界,则返回false
if (startIndex >= symbolString.length()) {
return false;
}
// 如果符号串只有一个符号,则判断该符号是否可以推导出空串
if (symbolString.length() == 1) {
String symbol = symbolString.substring(startIndex);
return grammar.containsKey(symbol) && grammar.get(symbol).contains("");
}
// 如果符号串有多个符号,则分别判断每个符号是否可以推导出空串
for (int i = startIndex; i < symbolString.length(); i++) {
String symbol = symbolString.substring(i, i + 1);
if (isTerminal(symbol.charAt(0))) {
return false;
} else if (!canDeriveEmpty(symbol, 0)) {
return false;
}
}
return true;
}
/**
* 获取指定非终结符号的FirstVt集合
* @param nonTerminal 非终结符号
* @return FirstVt集合
*/
public Set<String> getFirstVt(String nonTerminal) {
return firstVt.get(nonTerminal);
}
/**
* 测试用例
*/
public static void main(String[] args) {
// 初始化文法规则
Map<String, List<String>> grammar = new HashMap<>();
grammar.put("S", Arrays.asList("AaB", "BbA", "Ba", ""));
grammar.put("A", Arrays.asList("aB", ""));
grammar.put("B", Arrays.asList("bA", "a"));
// 计算FirstVt集合
FirstVt firstVt = new FirstVt(grammar);
firstVt.computeFirstVt();
// 输出结果
for (String nonTerminal : grammar.keySet()) {
System.out.printf("FirstVt(%s) = {%s}\n", nonTerminal, String.join(", ", firstVt.getFirstVt(nonTerminal)));
}
}
}
```
上述代码实现了一个任意文法的FirstVt算法,并提供了一个测试用例,验证了算法的正确性。