语法语义分析(算符优先分析) (JDK 1.8)

文法为:
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;
    }
}

你可能感兴趣的:(语法语义分析(算符优先分析) (JDK 1.8))