根据算符优先分析法,对表达式进行语法分析,使其能够判断一个表达式是否正确。通过算符优先分析方法的实现,加深对自下而上语法分析方法的理解。
1、输入文法。可以是如下算术表达式的文法(你可以根据需要适当改变):
E→E+T|E-T|T
T→T*F|T/F|F
F→(E)|i
2、对给定表达式进行分析,输出表达式正确与否的判断。
程序输入/输出示例:
输入:1+2;
输出:正确
输入:(1+2)/3+4-(5+6/7);
输出:正确
输入:((1-2)/3+4
输出:错误
输入:1+2-3+(*4/5)
输出:错误
3、参考数据结构
char *VN=0,*VT=0;//非终结符和终结符数组
char firstvt[N][N],lastvt[N][N],table[N][N];
typedef struct //符号对(P,a)
{
char Vn;
char Vt;
} VN_VT;
typedef struct //栈
{
VN_VT *top;
VN_VT *bollow;
int size;
}stack;
4、根据文法求FIRSTVT集和LASTVT集
5、构造算符优先分析表
6、构造总控程序
7、对给定的表达式,给出准确与否的分析过程
8、给出表达式的计算结果。(本步骤可选作)
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.*;
/**
* @author [25'h]
* @datetime 2022.11.02
*/
public class Reducing {
public static String startLabel;//开始符
public static ArrayList<String> terSymbol = new ArrayList<>();// 终结符
public static ArrayList<String> non_ter = new ArrayList<>();// 非终结符
public static HashMap<String, List<String>> formula = new HashMap<>();//产生式
public static HashMap<String, Set<String>[]> firstvtAndLastvt = new HashMap<>();//FIRST 和 FOLLOW
/*
firstvtAndLastvt的数据含义:
- key : 非终结符
- value : 非终结符对应的FIRSTVT 和 FOLLOWVT 集
- 1 非终结符对应的FIRSTVT
- 2 非终结符对应的FOLLOWVT
*/
public static boolean[] booleansFirst;// 辅助变量
public static boolean[] booleansLast;
public static String[][] table;//优先表
public static String objString;// 目标匹配字符串
public static LinkedList<String> deque;
public static void main(String[] args) {
File file = new File("src/StringToJAVA/test3.txt");
BufferedReader bufferedReader;
try {
// 读取文法和目标式子
bufferedReader = new BufferedReader(new FileReader(file));
startLabel = bufferedReader.readLine();
// 读取非终结符
non_ter.addAll(Arrays.asList(bufferedReader.readLine().split(" ")));
booleansFirst = new boolean[non_ter.size()];// 初始化辅助变量
booleansLast = new boolean[non_ter.size()];
// 初始化firstAndFollow中的Map对象
for (String s : non_ter) {
firstvtAndLastvt.put(s, new HashSet[]{new HashSet(), new HashSet()});
}
// 读取终结符
terSymbol.addAll(Arrays.asList(bufferedReader.readLine().split(" ")));
table = new String[terSymbol.size() + 1][terSymbol.size() + 1];
//将产生式右部或表达式分离
String s;
while ((s = bufferedReader.readLine()).contains("->")) {
String[] split = s.split("->");
formula.put(split[0], Arrays.asList(split[1].split("\\|")));
}
// 赋值目标串
objString = s;
} catch (Exception e) {
e.printStackTrace();
}
// 生成firstvt和lastvt
generateFirstVTAndLastVT();
// 生成优先分析表
generateTable();
// 归约
reducing();
show();
}
private static void reducing() {
// 终结符中添加结尾符号
terSymbol.add("#");
deque = new LinkedList<>();
deque.push("#");
for (int i = 0; i < objString.length(); i++) {
// 取出下一个字符
String sub = objString.substring(i, i + 1);
if (terSymbol.contains(sub)) {// 是终结符
// 栈最上面的终结符是temp
String temp = terSymbol.contains(deque.peek()) ? deque.peek() : deque.get(1);
// 看看跟上一个终结符和sub大优先级关系
String bol = table[terSymbol.indexOf(temp)][terSymbol.indexOf(sub)];
// 是> 就归约
if (bol.equals(">")) {
func(sub);
}
// 归约后终结符入栈
}
deque.push(sub);// 直接压入
showCurStack(i);
}
}
//输出当前的栈状态
private static void showCurStack(int i) {
StringBuffer b = new StringBuffer();
for (int j = deque.size() - 1; j >= 0; j--) {
b = b.append(deque.get(j));
}
if (i != objString.length() - 1)
b = b.append("\t\t\t").append(objString.substring(i + 1));
System.out.println(b.toString());
}
private static void func(String curTer) {
String te;
// 栈顶非终结符读出
if (!terSymbol.contains(deque.peek())) {
deque.pop();
}
do {
te = deque.pop();// 当前规约串的终结符te
// te左的非终结符
if (!terSymbol.contains(deque.peek())) {
deque.pop();
}
} while (!table[terSymbol.indexOf(deque.peek())][terSymbol.indexOf(te)].equals("<"));
// 栈顶终结符
te = deque.peek();
deque.push("N");// 标记
// 若还是>,则递归调用
if (table[terSymbol.indexOf(te)][terSymbol.indexOf(curTer)].equals(">")) {
func(curTer);
}
}
private static void generateTable() {
// 对于每个公式都要取出终结符
for (String non : formula.keySet()) {
List<String> list = formula.get(non);//non这个非终结符对应的生成式
for (String f : list) {// 对于每个式子f
ArrayList<String> li = new ArrayList<>();// 每个式子的终结符记下来,因为他们之间的关系是=
// 对式子f要查找终结符位置
for (int i = 0; i < f.length(); i++) {
// 对于f中每个元素sub
String sub = f.substring(i, i + 1);
// 若是终结符
if (terSymbol.contains(sub)) {
li.add(sub);//几下终结符
// 左边有非终结符
if (i != 0 && non_ter.contains(f.substring(i - 1, i))) {
//赋值“>”
pre(f.substring(i - 1, i), sub);
}
//右边有非终结符
if (i != f.length() - 1 && non_ter.contains(f.substring(i + 1, i + 2))) {
//赋值“<”
post(f.substring(i + 1, i + 2), sub);
}
}
}
// 想等情况赋值,注意是 j = i + 1
for (int i = 0; i < li.size(); i++) {
for (int j = i + 1; j < li.size(); j++) {
table[terSymbol.indexOf(li.get(i))][terSymbol.indexOf(li.get(j))] = "=";
}
}
}
}
// 关于#的赋值
Set<String>[] sets = firstvtAndLastvt.get(startLabel);
for (String s : sets[0]) {
table[terSymbol.size()][terSymbol.indexOf(s)] = "<";
}
for (String s : sets[1]) {
table[terSymbol.indexOf(s)][terSymbol.size()] = ">";
}
table[terSymbol.size()][terSymbol.size()] = "=";
}
private static void post(String non, String ter) {
int index = terSymbol.indexOf(ter);
Set<String> set = firstvtAndLastvt.get(non)[0];
for (String s : set) {
table[index][terSymbol.indexOf(s)] = "<";
}
}
private static void pre(String non, String ter) {
int index = terSymbol.indexOf(ter);
Set<String> set = firstvtAndLastvt.get(non)[1];
for (String s : set) {
table[terSymbol.indexOf(s)][index] = ">";
}
}
//生成firstvt和lastvt
private static void generateFirstVTAndLastVT() {
for (String s : non_ter) {
if (!booleansFirst[non_ter.indexOf(s)])
generateEachFirstVT(s);
if (!booleansLast[non_ter.indexOf(s)]) {
generateEachLastVT(s);
}
}
}
/*
生成每个非终结符non的Lastvt集
*/
private static void generateEachLastVT(String non) {
Set<String> curList = firstvtAndLastvt.get(non)[1];
for (String s : formula.get(non)) {
// lastvt本质就是firstvt反过来的求法
modify(non, curList, new StringBuffer(s).reverse().toString(), 1);
}
booleansLast[non_ter.indexOf(non)] = true;
}
/*
生成每个非终结符non的Firstvt集
*/
private static void generateEachFirstVT(String terNon) {
Set<String> curList = firstvtAndLastvt.get(terNon)[0];
for (String s : formula.get(terNon)) {
modify(terNon, curList, s, 0);
}
booleansFirst[non_ter.indexOf(terNon)] = true;
}
private static void modify(String non, Set<String> curList, String s, int i) {
String firstSub = s.substring(0, 1);
if (terSymbol.contains(firstSub)) {// 终结符开头
curList.add(firstSub);
} else {// 非终结符开头
// 终结符是第二个位置
if (s.length() >= 2 && terSymbol.contains(s.substring(1, 2))) {
curList.add(s.substring(1, 2));
}
// firstSub和non相同,避免栈溢出返回
if (firstSub.equals(non)) return;
if (i == 0) {// 求firstvt,用booleansFirst
if (!booleansFirst[non_ter.indexOf(firstSub)]) {
generateEachFirstVT(firstSub);
}
} else {// 求lastvt,booleansLast
if (!booleansLast[non_ter.indexOf(firstSub)]) {
generateEachLastVT(firstSub);
}
}
curList.addAll(firstvtAndLastvt.get(firstSub)[i]);
}
}
private static void show() {
System.out.println(startLabel);
System.out.println(Arrays.toString(non_ter.toArray()));
System.out.println(Arrays.toString(terSymbol.toArray()));
for (String s : formula.keySet()) {
System.out.println(s + "\t" + Arrays.toString(formula.get(s).toArray()));
}
System.out.println();
for (String s : firstvtAndLastvt.keySet()) {
System.out.println(s + "\t" + Arrays.toString(firstvtAndLastvt.get(s)[0].toArray()) + "\t" + Arrays.toString(firstvtAndLastvt.get(s)[1].toArray()));
}
System.out.println();
for (String[] strings : table) {
System.out.println(Arrays.toString(strings));
}
}
}
test3.txt文件:
E
E T F
i * / + - ( )
E->E+T|E-T|T
T->T*F|T/F|F
F->(E)|i
(1+2)/3+4-(5+6/7)#
输出结果:
"D:\Program Files\Java\jdk1.8.0_291\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2020.1\lib\idea_rt.jar=54769:D:\IntelliJ IDEA 2020.1\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\Java\jdk1.8.0_291\jre\lib\charsets.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\deploy.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\access-bridge-64.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\cldrdata.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\dnsns.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\jaccess.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\jfxrt.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\localedata.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\nashorn.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\sunec.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\sunjce_provider.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\sunmscapi.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\sunpkcs11.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\zipfs.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\javaws.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\jce.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\jfr.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\jfxswt.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\jsse.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\management-agent.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\plugin.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\resources.jar;D:\Program Files\Java\jdk1.8.0_291\jre\lib\rt.jar;D:\code_management\algorithm\out\production\algorithm" StringToJAVA.Reducing
#( 1+2)/3+4-(5+6/7)#
#(1 +2)/3+4-(5+6/7)#
#(1+ 2)/3+4-(5+6/7)#
#(1+2 )/3+4-(5+6/7)#
#(N) /3+4-(5+6/7)#
#N/ 3+4-(5+6/7)#
#N/3 +4-(5+6/7)#
#N+ 4-(5+6/7)#
#N+4 -(5+6/7)#
#N- (5+6/7)#
#N-( 5+6/7)#
#N-(5 +6/7)#
#N-(5+ 6/7)#
#N-(5+6 /7)#
#N-(5+6/ 7)#
#N-(5+6/7 )#
#N-(N) #
#N#
E
[E, T, F]
[i, *, /, +, -, (, ), #]
T [T*F, T/F, F]
E [E+T, E-T, T]
F [(E), i]
T [(, i, *, /] [), i, *, /]
E [(, i, *, +, -, /] [), i, *, +, -, /]
F [(, i] [), i]
[null, >, >, >, >, null, >, >]
[<, >, >, >, >, <, >, >]
[<, >, >, >, >, <, >, >]
[<, <, <, >, >, <, >, >]
[<, <, <, >, >, <, >, >]
[<, <, <, <, <, <, =, null]
[null, >, >, >, >, null, >, >]
[<, <, <, <, <, <, null, =]
Process finished with exit code 0