语法语义分析(算符优先分析) (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<String, Integer> table;
    HashMap<Character, Integer> operatorPriorityTable;
    HashMap<String, String> 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<String> 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;
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 226,488评论 6 524
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 97,466评论 3 411
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 174,084评论 0 371
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 62,024评论 1 305
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,882评论 6 405
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 54,395评论 1 318
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 42,539评论 3 433
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 41,670评论 0 282
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 48,194评论 1 329
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 40,173评论 3 352
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 42,302评论 1 362
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,872评论 5 354
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 43,581评论 3 342
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,984评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 35,179评论 1 278
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,888评论 3 385
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 47,306评论 2 369

推荐阅读更多精彩内容

  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,856评论 0 38
  • 递归 - 词法分析与语法分析的分界 一般来说,决定词法分析和语法分析的界限是是否需要递归。词法分析是将输入的符号流...
    Jtag特工阅读 3,163评论 1 11
  • 第2章 基本语法 2.1 概述 基本句法和变量 语句 JavaScript程序的执行单位为行(line),也就是一...
    悟名先生阅读 4,170评论 0 13
  • 我像一只苯笨的蜗牛 背负着沉重的行囊爬行 在苍山绿野间 没有停步的可能 就着鸟鸣风啸 把思念吞进肚肠。 9点起床,...
    谁动了我的魔芋豆腐阅读 343评论 4 2
  • 其实我对朋友的要求很简单,我是一个特别缺乏安全感的人,大概跟我从小的性格以及一直单身的缘故有关,我希望的朋友不要总...
    浅陌芳草香阅读 163评论 0 0