编译原理实验二-逆波兰式生成程序
一、实验目的和要求:
1. 掌握语法分析的基本思想,并用高级语言编写逆波兰式生成程序
2. 要求利用逆波兰式生成算法编写程序,将从键盘上输入的算术表达式
(中缀表达式)转化成逆波兰式
二、实验平台:
Java语言
三、主要实验内容及结果:
实验内容:
逆波兰表达式是算术表达式的后缀表示形式,逆波兰表达式生成算法的关 键在于比较当前运算符与栈顶运算符的优先关系,若当前运算符的优先级高于 栈顶运算符,则当前运算符入栈,若当前运算符的优先级低于栈顶运算符,则 栈顶运算符退栈。
程序代码:
import java.util.ArrayList;
public class InversePolish {
// 存放运算符优先关系矩阵
private String[][] chars;
// 存放运算符栈(index=0表示栈底,index=size()-1表示栈顶)
private ArrayList<String> stack;
// 存放输入串
private ArrayList<String> inStr;
// 存放输出串
private ArrayList<String> outStr;
public static void main(String[] args) {
InversePolish inversePolish = new InversePolish();
String str = "a*(b+c)/d";
inversePolish.init(str);
inversePolish.mainFunc();
for (String currentChar : inversePolish.outStr) {
System.out.print(currentChar);
}
}
private void mainFunc() {
// 从左往右扫描中缀表达式
label1: for (String currentChar : this.inStr) {
// 输入串为空?
if (currentChar.equals("#")) {
// 栈为空?
while (true) {
if (this.stack.get(this.stack.size() - 1).equals("#")) {
break label1;
} else {
// 退栈输出
this.outStr.add(this.stack.get(this.stack.size() - 1));
this.stack.remove(this.stack.size() - 1);
continue;
}
}
} else {
// 运算符?
if (!this.isChar(currentChar)) {
// 输出
this.outStr.add(currentChar);
continue;
} else {
while (true) {
// 栈是否为空?
if (this.stack.get(this.stack.size() - 1).equals("#")) {
// 入栈
this.stack.add(currentChar);
continue label1;
} else {
// 比较当前运算符与栈顶运算符的优先级
if (isFirst(currentChar)) {
// 入栈
this.stack.add(currentChar);
continue label1;
} else {
// 当前运算符是')'
if (currentChar.equals(")")) {
while (true) {
// 栈顶为'('
if (this.stack.get(this.stack.size() - 1).equals("(")) {
// 退栈
this.stack.remove(this.stack.size() - 1);
continue label1;
} else {
// 栈为空?
if (this.stack.get(this.stack.size() - 1).equals("#")) {
System.out.println("ERROR");
} else {
// 退栈输出
this.outStr.add(this.stack.get(this.stack.size() - 1));
this.stack.remove(this.stack.size() - 1);
continue;
}
}
}
} else {
// 退栈输出
this.outStr.add(this.stack.get(this.stack.size() - 1));
this.stack.remove(this.stack.size() - 1);
continue;
}
}
}
}
}
}
}
}
private void init(String str) {
System.out.println(str);
this.stack = new ArrayList<>();
this.inStr = new ArrayList<>();
this.outStr = new ArrayList<>();
// 输入运算符优先关系矩阵8*7
this.chars = new String[][] { { ">", ">", "<", "<", "<", "<", ">" }, { ">", ">", "<", "<", "<", "<", ">" },
{ ">", ">", ">", ">", "<", "<", ">" }, { ">", ">", ">", ">", "<", "<", ">" },
{ ">", ">", ">", ">", ">", "<", ">" }, { "<", "<", "<", "<", "<", "<", "=" },
{ ">", ">", ">", ">", ">", "", ">" }, { "<", "<", "<", "<", "<", "<", "<" } };
// 输入输入串
String[] temps = str.split("");
for (String temp : temps) {
this.inStr.add(temp);
}
this.inStr.add("#");
// 输入运算符栈
this.stack.add("#");
}
// 运算符?
private boolean isChar(String currentChar) {
return "+-*/↑()".contains(currentChar);
}
// 比较当前运算符与栈顶运算符的优先级
private boolean isFirst(String currentChar) {
String stackChar = this.stack.get(this.stack.size() - 1);
int x = "+-*/↑()#".indexOf(stackChar);
int y = "+-*/↑()#".indexOf(currentChar);
return this.chars[x][y].equals("<");
}
}
运行结果:
四、心得体会
实现逆波兰式的算法,难度并不大,之所以要将看似简单的中缀表达式转换为复杂的逆波兰式,原因就在于这个简单是相对人类的思维结构来说的,对计算机而言中序表达式是非常复杂的结构。相对的,逆波兰式在计算机看来却是比较简单易懂的结构。因为计算机普遍采用的内存结构是栈式结构,它执行先进后出的顺序。