文法为:
E -> E+T | E-T | T
T -> T*F | T/F | F
F ->(E)| i
根据预测分析法,对表达式进行语法分析,判断一个表达式是否正确
对于正确的表达式,使用逆序波兰式求值
流程图.png
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
public class OperatorPriorityAnalyst {
HashMap table;
HashMap operatorPriorityTable;
HashMap reduceTable; //栈顶规约表
final String INPUT_PATH = "src/Test/input.txt";
//final String OUTPUT_PATH = "src/Test/output.txt";
final String VT = "i+-*/()#";
final int EXPRESSION_ACCEPT = 0;
final int EXPRESSION_WRONG = 1;
final int SHIFT = -1; //移进
final int REDUCE = 1; //规约
final int EQUAL = 0;
String sequence;
boolean meetZero = false; //计算过程中是否出现0做除数
public void analysis() throws Exception{
int turn = 1;
init();
Scanner scanner = new Scanner(new File(INPUT_PATH));
//FileWriter writer = new FileWriter(new File((OUTPUT_PATH)));
String oriExpression;//original expression
while (scanner.hasNextLine()) {
StringBuffer outputBuffer = new StringBuffer();//output.txt information for each input.txt line
oriExpression = scanner.nextLine();
oriExpression = oriExpression.substring(0, oriExpression.length() - 1);
//gets rid of the ;
String[] words = getAbstractSeq(oriExpression);
//sequence is now initialised.
if (words.length == 1) {
System.out.println((turn++) + " : 正确 值为" + words[0]);
continue;
}
char[] stack = new char[sequence.length()];
int top = -1;
char[] queue = sequence.toCharArray();
int front = 1;
stack[++top] = '#';
int expression_state;
while (true) {
char curWord = queue[front];
char topWord = '.';
int near = top;
for (; near >= 0; --near) {
if (VT.indexOf(stack[near]) >= 0) {
topWord = stack[near];
break;
}
}
if (topWord == '.') {
expression_state = EXPRESSION_WRONG;
outputBuffer.append("未找到离栈顶最近的VT");
break;
}
if (curWord == '#' && topWord == '#') {
expression_state = EXPRESSION_ACCEPT;
break;
} else {
String key = topWord + " " + curWord;
if (!table.containsKey(key)) {
expression_state = EXPRESSION_WRONG;
outputBuffer.append("错误单词为:" + words[front - 1]);
break;
} else {
if (table.get(key) <= 0) { //移进或者相等
stack[++top] = curWord;
++front;
continue;
} else {
//栈顶规约
int start = near - 1; //start是near之前的Vt的下标
while (true) {
if (start < 0) {
expression_state = EXPRESSION_WRONG;
outputBuffer.append("规约过程失败");
break;
}
if (VT.indexOf(stack[start]) < 0) {
--start;
} else { //查表
String key1 = stack[start] + " " + stack[near];
if (table.get(key1) == SHIFT) {
String result = reduceTable.get(String.valueOf(stack, start + 1, top - start));
if (result == null) {
expression_state = EXPRESSION_WRONG;
outputBuffer.append("错误单词为:" + words[front - 1]);
break;
}
//对要规约的单词进行检查
int wrong = -1;
for (int i = start + 1; i <= top; ++i) {
if (!checkWhenReduce(stack[i], stack, i, top, start + 1)) {
wrong = i;
break;
}
}
if (wrong != -1) {
expression_state = EXPRESSION_WRONG;
outputBuffer.append("错误单词为 " + stack[wrong]);
break;
}
top = start;
for (int i = 0; i < result.length(); ++i)
stack[++top] = result.charAt(i);
break;
} else {
near = start;
--start;
}
}
}
}
}
}
}
if (expression_state == EXPRESSION_ACCEPT) {
//writer.write("正确 逆波兰式为 " + getReversePolishExpression(words, value) + " 其值为" + value.value + '\n');
String expression = getReversePolishExpression(words);
System.out.println((turn++) + " : 正确 逆波兰式为 " + expression + " 其值为 " + getReversedPolishValue(expression));
} else {
//writer.write("错误 错误位置是" + outputBuffer.toString() + '\n');
System.out.println((turn++) + " : 错误 " + outputBuffer.toString());
}
}
scanner.close();
//writer.close();
}
private void init() {
table = new HashMap<>();
table.put("# +", SHIFT);
table.put("# -", SHIFT);
table.put("# *", SHIFT);
table.put("# /", SHIFT);
table.put("# (", SHIFT);
table.put("# i", SHIFT);
table.put("+ *", SHIFT);
table.put("+ /", SHIFT);
table.put("+ (", SHIFT);
table.put("+ i", SHIFT);
table.put("- *", SHIFT);
table.put("- /", SHIFT);
table.put("- (", SHIFT);
table.put("- i", SHIFT);
table.put("* i", SHIFT);
table.put("* (", SHIFT);
table.put("/ (", SHIFT);
table.put("/ i", SHIFT);
table.put("( +", SHIFT);
table.put("( -", SHIFT);
table.put("( *", SHIFT);
table.put("( /", SHIFT);
table.put("( (", SHIFT);
table.put("( i", SHIFT);
table.put("+ #", REDUCE);
table.put("+ +", REDUCE);
table.put("+ -", REDUCE);
table.put("+ )", REDUCE);
table.put("- #", REDUCE);
table.put("- +", REDUCE);
table.put("- -", REDUCE);
table.put("- )", REDUCE);
table.put("* #", REDUCE);
table.put("* +", REDUCE);
table.put("* -", REDUCE);
table.put("* *", REDUCE);
table.put("* /", REDUCE);
table.put("* )", REDUCE);
table.put("/ #", REDUCE);
table.put("/ +", REDUCE);
table.put("/ -", REDUCE);
table.put("/ *", REDUCE);
table.put("/ /", REDUCE);
table.put("/ )", REDUCE);
table.put(") #", REDUCE);
table.put(") +", REDUCE);
table.put(") -", REDUCE);
table.put(") *", REDUCE);
table.put(") /", REDUCE);
table.put(") )", REDUCE);
table.put("i #", REDUCE);
table.put("i +", REDUCE);
table.put("i -", REDUCE);
table.put("i *", REDUCE);
table.put("i /", REDUCE);
table.put("i )", REDUCE);
table.put("# #", EQUAL);
table.put("( )", EQUAL);
operatorPriorityTable = new HashMap<>();
operatorPriorityTable.put('+', 1);
operatorPriorityTable.put('-', 1);
operatorPriorityTable.put('/', 2);
operatorPriorityTable.put('*', 2);
operatorPriorityTable.put('(', 0);
operatorPriorityTable.put(')', 4);
reduceTable = new HashMap<>();
reduceTable.put("#X#", "X");
reduceTable.put("X+X", "X");
reduceTable.put("X-X", "X");
reduceTable.put("X", "X");
reduceTable.put("X*X", "X");
reduceTable.put("X/X", "X");
reduceTable.put("(X)", "X");
reduceTable.put("i", "X");
}
private boolean checkWhenReduce (char w, char[] stack, int pos, int upper, int bottom) {
if (w == 'i') {
if ((pos + 1 <= upper && stack[pos + 1] == 'X') && (pos - 1 >= upper && stack[pos - 1] == 'X')) {
return false;
}
} else if (w == ')') { //往前查找
boolean flag = false;//是否遇到(
for (int i = pos - 1; i >= bottom; --i) {
if (!flag && stack[i] == 'X')
return false;
else if (stack[i] == ')') continue;
else return true;
}
} else if (w == '(') {
return true;
} else {
if ((pos - 1 >= bottom && stack[pos - 1] != 'X') || (pos + 1 <= upper && stack[pos + 1] != 'X'))
return false;
}
return true;
}
//简单词法分析器
private String[] getAbstractSeq (String originalExpression) {
StringBuffer buffer = new StringBuffer();//buffer for result sequence
buffer.append('#');
ArrayList list = new ArrayList<>();
char[] S = new char[100];
int top = -1;
for (int i = 0; i < originalExpression.length(); ++i) {
char ch = originalExpression.charAt(i);
if (isBlank(ch)) {
continue;
} else {
if (VT.indexOf(ch) >= 0) {
if (top != -1) {
//If it's an operator
buffer.append("i");
buffer.append(ch);
//clear the stack
String number = new String(S, 0, top + 1);
top = -1;
list.add(number);//add the number
list.add(String.valueOf(ch));//add the operator
} else {
buffer.append(ch);
list.add(String.valueOf(ch));
}
} else {
S[++top] = ch;
}
}
}
if (top != -1) {
String number = new String(S, 0, top + 1);
buffer.append("i");
list.add(number);
}
buffer.append("#");
sequence = buffer.toString();
return list.toArray(new String[list.size()]);
}
private String getReversePolishExpression (String[] words) {
StringBuffer output = new StringBuffer();
char[] operatorStack = new char[words.length];
int top = -1;
for (int i = 0; i < words.length; ++i) {
if (isWordOperator(words[i])) {
/*char operator = words[i].charAt(0);
while (operatorTop != -1 && getPriorityDifference(operator, operatorStack[operatorTop]) <= 0) {
char poppedOperator = operatorStack[operatorTop--];
output.append(poppedOperator + ' ');
}*/
char operator = words[i].charAt(0);
if (operator == '(') {
operatorStack[++top] = operator;
} else if (operator == ')') {
while (operatorStack[top] != '(') {
output.append(operatorStack[top--] + " ");
}
top--;
} else {
//当(栈非空and栈顶不是开括号and栈顶运算符的优先级不低于输入的运算符的优先级)时,反复操作:将栈顶元素出栈输出
while (top != -1 && operatorStack[top] != '(' && getPriorityDifference(operatorStack[top], operator) >= 0) {
output.append(operatorStack[top--] + " ");
}
operatorStack[++top] = operator;
}
} else {
output.append(words[i] + ' ');
}
}
while (top != -1)
output.append(operatorStack[top--] + " ");
return output.toString();
}
private float getReversedPolishValue (String expression) {
float[] stack = new float[expression.length()];
int top = -1;
String[] words = expression.split(" ");
for (String s : words) {
if (isWordOperator(s)) {
float a = stack[top--];
float b = stack[top--];
switch (s) {
case "+" :
stack[++top] = a + b;
break;
case "-" :
stack[++top] = b - a;
break;
case "*" :
stack[++top] = a * b;
break;
case "/" :
if (b == 0) {
meetZero = true;
return Float.MIN_VALUE;
} else {
stack[++top] = b / a;
}
break;
}
} else {
stack[++top] = Float.valueOf(s);
}
}
return stack[0];
}
/*判断两个优先符优先级关系*/
private int getPriorityDifference (char c1, char c2) {
return operatorPriorityTable.get(c1) - operatorPriorityTable.get(c2);
}
/*判断是否是空白*/
private boolean isBlank (char ch) {
if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')
return true;
else return false;
}
private boolean isWordOperator (String word) {
char c = word.charAt(0);
if (c >= '0' && c <= '9') return false;
else return true;
}
}