Java 實現《編譯原理》中間代碼生成 -逆波蘭式生成與計算 - 程序解析
編譯原理學習筆記
(一)逆波蘭式是什么?
逆波蘭式(Reverse Polish notation,RPN,或逆波蘭記法),也叫 后綴表達式(將運算符寫在操作數之后)
一般的表達式又稱 中綴表達式,這種表達式的二元運算符放在兩個運算量 之間。而逆波蘭表達式又稱 后綴表達式,這種表達式把運算符放在運算量 后面。
比如如 a+b 的逆波蘭式表示為 ab+
注意:逆波蘭式是一個無括號表達式;逆波蘭式的運算符出現的順序就是原表達式的運算順序。
(二)逆波蘭式編譯原理有什么關系?
逆波蘭式,三元式,四元式等是編譯原理 - 中間代碼生成階段的常見的中間代碼形式。
(三)本篇任務
通過設計,使用 Java 語言編寫一個逆波蘭式生成程序,測試效果:
(四)Java 源代碼
package com.java997.analyzer.rpn;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.Stack;
/**
* <p>
* 逆波蘭式
*
* @author XiaoPengwei
* @since 2019-06-19
*/
public class RpnMain {
/**
* 檢查算術表達術括號是否匹配, 語法是否正確
*
* @param s 算術表達術
* @return boolean
*/
public boolean isMatch(String s) {
//括號符號棧
Stack<Character> charStack = new Stack<>();
//將表達式的字符串轉換成數組
char[] charArray = s.toCharArray();
//遍歷數組
for (char aChar : charArray) {
if (aChar == '(') {
charStack.push(aChar);
} else if (aChar == ')') {
//如果是 ) , 且棧為空則返回 false
if (charStack.isEmpty()) {
return false;
} else {
//如果是 ) , 且棧不為空則返回 false
//peek() 是返回棧頂的值, 不做其他操作
if (charStack.peek() == '(') {
//把棧頂的值刪除
charStack.pop();
}
}
}
}
//走到這里, 棧為空則表達式正確
return charStack.empty();
}
/**
* 判斷是否為操作符 + - * /
*
* @param charAt
* @return boolean
*/
public boolean isOperator(char charAt) {
return charAt == '+' || charAt == '-' || charAt == '*' || charAt == '/';
}
/**
* 根據正確的表達式, 獲取逆波蘭式
*
* @param input
* @return java.lang.String
*/
public StringBuilder getRpn(String input) {
//結果
StringBuilder sb = new StringBuilder();
sb.append("The RPN is: ");
//運算符棧
Stack<Character> opStack = new Stack();
//運算符優先級
Map<Character, Integer> opMap = new HashMap(5);
opMap.put('(', 0);
opMap.put('+', 1);
opMap.put('-', 1);
opMap.put('*', 2);
opMap.put('/', 2);
//處理字符串
for (int i = 0; i < input.length(); i++) {
//如果是'('直接壓棧
if (input.charAt(i) == '(') {
opStack.push('(');
} else if (new RpnMain().isOperator(input.charAt(i))) {
//如果是運算符
char curOp = input.charAt(i);
//如果運算符棧是空,就直接壓棧
if (opStack.isEmpty()) {
opStack.push(curOp);
} else if (opMap.get(curOp) > opMap.get(opStack.peek())) {
//運算符棧不為空,且當當前運算符的優先級比站內第一個運算符的優先級高的時候,壓棧
opStack.push(curOp);
} else {
//棧不為空,且運算符的優先級小於等於棧頂元素
for (int j = 0; j <= opStack.size(); j++) {
//彈出棧內第一個元素
char ch = opStack.pop();
sb.append(ch);
if (opStack.isEmpty()) {
opStack.push(curOp);
break;
} else if (opMap.get(curOp) > opMap.get(opStack.peek())) {
opStack.push(curOp);
break;
}
}
}
} else if (input.charAt(i) == ')') {
//如果是')'就把站內'('上的元素都彈出棧
for (int j = 0; j < opStack.size(); j++) {
char c = opStack.pop();
if (c == '(') {
break;
} else {
sb.append(c);
}
}
} else if ('A'<=input.charAt(i)&&input.charAt(i)<='Z'){
//如果是字母就直接添加
sb.append(input.charAt(i));
}else if ('a'<=input.charAt(i)&&input.charAt(i)<='z'){
//如果是字母就直接添加
sb.append(input.charAt(i));
}else if (Character.isDigit(input.charAt(i))){
//如果是數字
sb.append(input.charAt(i));
}else {
return new StringBuilder("But the expression contains unrecognizable characters");
}
}
//把棧內剩余的運算符都彈出站
for (int i = 0; i <= opStack.size(); i++) {
sb.append(opStack.pop());
}
return sb;
}
public static void main(String[] args) {
RpnMain rpnMain = new RpnMain();
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("==========================\nPlease input an expression:");
String input = sc.nextLine();
if ("q".equals(input)) {
sc.close();
return;
} else {
if (rpnMain.isMatch(input)) {
System.out.println("The expression's brackets are matched");
// 獲取逆波蘭式
System.out.println(rpnMain.getRpn(input));
} else {
System.out.println("Error: The expression's brackets are not matched! Enter 'q' to exit");
}
}
}
}
}
測試: