算符优先分析法-java实现

算符优先分析器-java实现

一、判断是否是算符文法

算符文法定义:一个文法,如果它的任一产生式的右部都不含两个相继(并列)的非终结符,即不含如下形式的产生式右部:…QR…,则称该文法为算符文法

二、求Firstvt和Lastvt(…为终结符和非终结符组成的任意序列,包括空字)

Firstvt

(1)若有产生式P->a…或P->Qa…,则a ∈FIRSTVT§;

(2)若a∈FIRSTVT(Q),且有产生式P->Q…,则a∈FIRSTVT§。

即:

若有P->a.....,即以终结符开头,该终结符入Firstvt
若有P->Q.....,即以非终结符开头,该非终结符的Firstvt加入P的Firstvt
若有P->Qa....,即先以非终结符开头,紧跟终结符,则终结符入Firstvt
Lastvt

(1)P->…a或P->aQ,则a∈LASTVT§。

(2)若a∈LASTVT(Q),且有产生式P->…Q,则a∈LASTVT§。

即:

若有P->....a,即以终结符结尾,该终结符入Lastvt
若有P->....Q,即以非终结符结尾,该非终结符的Lastvt入P的Lastvt
若有P->....aQ,即先以非终结符结尾,前面是终结符,则终结符入Lastvt

三、构造优先关系表

规则:
1.对形如P->…ab…和形如P->…aQb…有a=b

2.对形如P->…aR…,而b ∈FIRSTV®,有a<b

3.对形如P->…Rb…,而a∈LASTVT®,有a>b;

4.对于S和结束符#,有#<FIRST(S),LASTVT(S)>#,且对#S#,有#=#。

四、利用算符优先分析算法进行分析

分析过程:

过程:
k:=1; 
S[k]:= ‘#’;
REPEAT
     把下一个输入符号读进 a 中; 
     IF S[k] ∈ Vt THEN j:=k ELSE j:= k-1;
     WHILE S[j] > a DO 
           BEGIN
           REPEAT
                Q:=S[j]; 
                IF S[j-1]∈ VT THEN j:j-1 ELSE j:j-2
           UNTIL S[j] < Q;
           把 S[j+1]…S[k]归约为某个 N;
           k:=j+1;
           S[k]:=N;
           END OF WHILE;
      IF S[j] < a OR s[j] = a THEN
           BEGIN k:=k+1;S[k]:=N; END
      ELSE ERROR
UNTIL a = ‘#’ 

在上述算法的工作过程中,若出现j减1后的值小于等于0时,则意味着输入串有错。在正确的情况下,算法工作完毕时,符号栈应呈现:# N #
注意:把 S[j+1]…S[k]归约为某个 N;在规约的时候,自左至右,始终为终结符对终结符,非终结符对非终结符,对应的终结符是必须相等的,比如,a必须对应a;而非终结符是对应即可,如E对应P都可,因为非终结符对规约没有影响。

五、代码实现

import java.util.*;

/**
 * @Classname analyze
 * @Description TODO
 * @Date 19-11-19 下午4:51
 * @Created by xns
 */
public class analyze {

    /**
     * FIRSTVT集合
     */
    private static Map<Character, Set<Character>> firstVt = new HashMap<>();
    /**
     * LASTVT集合
     */
    private static Map<Character, Set<Character>> lastVt = new HashMap<>();
    /**
     * 输入的文法
     */
    private static List<String> input = new ArrayList<>();

    /**
     * 终结符
     */
    private static Set<Character> End = new LinkedHashSet<>();

    /**
     *非终结符
     */
    private static Set<Character> NoEnd = new LinkedHashSet<>();

    /**
     * 算符矩阵
     */
    private static Map<String, Character> matrix = new HashMap<>();

    private static Scanner in = new Scanner(System.in);

    /**
     * 文法的左右分割一一对应
     */
    private static Map<Character, List<String>> produce = new HashMap<>();


    /**
     * 获得firstVt集合
     */
    private static void getFirstVT(Character s, Set<Character> fvt) {
        String str = null;
        int i = 0;
        for (i = 0; i < input.size(); i++) {
            if (input.get(i).charAt(0) == s) {
                str = input.get(i);
            }
        }
        for (i = 3; i < str.length(); i++) {
            if (str.charAt(i) < 65 || str.charAt(i) > 90) {
                //P->a.....,即以终结符开头,该终结符入Firstvt
                if ((str.charAt(i - 1) == '>' && str.charAt(i - 2) == '-') || str.charAt(i - 1) == '|') {
                    fvt.add(str.charAt(i));
                }
                //P->Qa....,即先以非终结符开头,紧跟终结符,则终结符入Firstvt
                if ((str.charAt(i - 2) == '|' || (str.charAt(i - 2) == '>' && str.charAt(i - 3) == '-')) && str.charAt(i - 1) >= 65 && str.charAt(i - 1) <= 90) {
                    fvt.add(str.charAt(i));
                }
            }
            //若有P->Q.....,即以非终结符开头,该非终结符的Firstvt加入P的Firstvt
            if (str.charAt(i - 1) == '|' && str.charAt(i) >= 65 && str.charAt(i) <= 90) {
                if (str.charAt(i) == str.charAt(0)) {
                    continue;
                }
                //递归
                getFirstVT(str.charAt(i), fvt);
            }
        }
    }

    /**
     * 获得lastVt集合
     */
    private static void getLastVT(Character s, Set<Character> lvt) {
        String str = null;
        int i = 0;
        for (i = 0; i < input.size(); i++) {
            if (input.get(i).charAt(0) == s) {
                str = input.get(i);
            }
        }
        for (i = 3; i < str.length(); i++) {
            if (str.charAt(i) < 65 || str.charAt(i) > 90) {
                //P->....aQ,即先以非终结符结尾,前面是终结符,则终结符入Lastvt,Q处于产生式最后一位的情况
                if (i == str.length() - 1 || (i == str.length() - 2 && str.charAt(i + 1) >= 65 && str.charAt(i + 1) <= 90 && str.charAt(i) != '|' && (str.charAt(i) != '>' && str.charAt(i) != '-'))) {
                    lvt.add(str.charAt(i));
                }
                if (i < str.length() - 2) {
                    //P->....aQ,即先以非终结符结尾,前面是终结符,则终结符入Lastvt
                    if (str.charAt(i + 1) == '|' || (str.charAt(i + 2) == '|' && str.charAt(i + 1) >= 65 && str.charAt(i + 1) <= 90)) {
                        lvt.add(str.charAt(i));
                    }
                }
            } else {
                //P->....Q,即以非终结符结尾,该非终结符的Lastvt入P的Lastvt
                if (i == str.length() - 1) {
                    if (str.charAt(i) == str.charAt(0)) {
                        continue;
                    }
                    getLastVT(str.charAt(i), lvt);
                } else if (str.charAt(i + 1) == '|') {
                    if (str.charAt(i) == str.charAt(0)) {
                        continue;
                    }
                    //P->....Q,即以非终结符结尾,该非终结符的Lastvt入P的Lastvt
                    getLastVT(str.charAt(i), lvt);
                }
            }
        }
    }

    /**
     * 显示firstVt集合和lastVt集合
     */
    private static void DisplayFirstVT_LastVT() {
        for (int i = 0; i < input.size(); i++) {
            Set<Character> fvt = new HashSet<>();
            getFirstVT(input.get(i).charAt(0), fvt);
            firstVt.put(input.get(i).charAt(0), fvt);
        }
        for (int i = 0; i < input.size(); i++) {
            Set<Character> lvt = new HashSet<>();
            getLastVT(input.get(i).charAt(0), lvt);
            lastVt.put(input.get(i).charAt(0), lvt);
        }
        System.out.println("firstVt集合如下:");
        for (Map.Entry<Character, Set<Character>> entry : firstVt.entrySet()) {
            System.out.print("firstVt(" + entry.getKey() + "): {");
            int flag = 0;
            for (Character value : entry.getValue()) {
                flag++;
                System.out.print(value);
                if (flag != entry.getValue().size()) {
                    System.out.print(",");
                }
            }
            System.out.println("}");
        }
        System.out.println("lastVt集合如下:");
        for (Map.Entry<Character, Set<Character>> entry : lastVt.entrySet()) {
            System.out.print("lastVt(" + entry.getKey() + "): {");
            int flag = 0;
            for (Character value : entry.getValue()) {
                flag++;
                System.out.print(value);
                if (flag != entry.getValue().size()) {
                    System.out.print(",");
                }
            }
            System.out.println("}");
        }
    }


    /**
     * 获取所有终结符
     */
    private static void getEnd() {
        for (int i = 0; i < input.size(); i++) {
            String temp = input.get(i);
            for (int j = 3; j < temp.length(); j++) {
                if (temp.charAt(j) < 65 || temp.charAt(j) > 90 && temp.charAt(j) != '|') {
                    End.add(temp.charAt(j));
                }
            }
        }
        End.add('#');
    }

    /**
     * 获取所有非终结符
     */
    private static void getNoEnd() {
        for (int i = 0; i < input.size(); i++) {
            String temp = input.get(i);
            for (int j = 3; j < temp.length(); j++) {
                if (temp.charAt(j) >= 65 && temp.charAt(j) <= 90) {
                    NoEnd.add(temp.charAt(j));
                }
            }
        }
    }

    /**
     * 将每一行的文法分离,如E->E+T|T分离成E和E+T,T
     */
    private static void getProduce() {
        for (int i = 0; i < input.size(); i++) {
            List<String> list = new ArrayList<>();
            String str = input.get(i);
            StringBuffer a = new StringBuffer();
            for (int j = 3; j < str.length(); j++) {
                if (str.charAt(j) != '|') {
                    a.append(str.charAt(j));
                } else {
                    list.add(a.toString());
                    //清空a
                    a.delete(0, a.length());
                }
            }
            list.add(a.toString());
            produce.put(str.charAt(0), list);
        }
    }

    /**
     * 错误
     */
    public static void partError() {
        matrix.put(")(", 'b');
        matrix.put("((", 'b');
        matrix.put("(#", 'a');
    }


    /**
     * 构造算符优先矩阵并打印
     * 用Map<String,Character>存,String中存优先变得行值和列值,Character表示String中所存行列的大小关系如"++"表示行为'+',列为'+'的时候,关系为Character中的值
     * @return
     */
    private static void priorityMatrix() {
        for (int i = 0; i < input.size(); i++) {
            String str = input.get(i);
            for (int j = 3; j < input.get(i).length(); j++) {
                if ((str.charAt(j) < 65 || str.charAt(j) > 90) && (str.charAt(j) != '|')) {
                    if (j < str.length() - 1 && (str.charAt(j + 1) < 65 || str.charAt(j + 1) > 90)) {
                        String temp = str.charAt(j) + "" + str.charAt(j + 1);
                        matrix.put(temp, '=');
                    } else {
                        if (j < str.length() - 2 && (str.charAt(j + 2) < 65 || str.charAt(j + 2) > 90) && (str.charAt(j + 2) != '|')) {
                            matrix.put(str.charAt(j) + "" + str.charAt(j + 2), '=');
                        }
                    }
                    if (j < str.length() - 1 && str.charAt(j + 1) >= 65 && str.charAt(j + 1) <= 90) {
                        Set<Character> coll = firstVt.get(str.charAt(j + 1));
                        for (Character value : coll) {
                            matrix.put(str.charAt(j) + "" + value, '<');
                        }
                    }
                    if (j - 1 != 2 && str.charAt(j - 1) >= 65 && str.charAt(j - 1) <= 90) {
                        Set<Character> coll = lastVt.get(str.charAt(j - 1));
                        for (Character value : coll) {
                            matrix.put(value + "" + str.charAt(j), '>');
                        }
                    }
                }
            }
        }
        Set<Character> coll = firstVt.get(input.get(0).charAt(0));
        for (Character value : coll) {
            matrix.put('#' + "" + value, '<');
        }
        Set<Character> coll1 = lastVt.get(input.get(0).charAt(0));
        for (Character value : coll1) {
            matrix.put(value + "" + '#', '>');
        }
        partError();
        for (Character value : End) {
            for (Character value1 : End) {
                if (matrix.get(value + "" + value1) == null) {
                    matrix.put(value + "" + value1, 'b');
                }
            }
        }
        matrix.put("##", '=');

/*        for (Map.Entry<String, Character> entry : matrix.entrySet()) {
            System.out.println(entry.getKey()+"   "+entry.getValue());
        }*/
        getEnd();
        System.out.println("\n构造的算符优先关系表如下:");
        int kong = 0;
        for (Character value : End) {
            if (kong == 0) {
                System.out.print("   ");
            }
            kong++;
            System.out.print(value);
            if (kong != End.size()) {
                System.out.print("  ");
            }
        }
        System.out.println();
        for (Character value : End) {
            System.out.print(value);
            for (Character value1 : End) {
                Character ch = matrix.get(value + "" + value1);
                if (ch != null) {
                    System.out.print("  " + ch);
                } else {
                    System.out.print("  " + " ");
                }
            }
            System.out.println();
        }
    }

    /**
     * 判断其是不是算符文法
     *如果没有连个连续非终结符号相连的就是算符优先文法
     * @return
     */
    private static boolean isOperator() {
        int i;
        for (i = 0; i < input.size(); i++) {
            for (int j = 0; j < input.get(i).length() - 1; j++) {
                String str = input.get(i);
                if (str.charAt(j) >= 65 && str.charAt(j) <= 90) {
                    if ((str.charAt(j + 1) >= 65 && str.charAt(j + 1) <= 90)) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    /**
     * 判断其是不是终结符
     *
     * @return
     */
    private static boolean isEnd(Character ch) {
        for (Character value : End) {
            if (value.equals(ch)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断其是不是非终结符
     *
     * @return
     */
    private static boolean isNoEnd(Character ch) {
        for (Character value : NoEnd) {
            if (value.equals(ch)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 根据产生式右部分返回左边
     *
     * @return
     */
    private static char retLeft(String str) {
        char ch = 0;
        for (Map.Entry<Character, List<String>> map : produce.entrySet()) {
            ch = map.getKey();
            for (String value : map.getValue()) {
                if (value.length() != str.length()) {
                    continue;
                }
                int i;
                for (i = 0; i < str.length(); i++) {

                    if (str.charAt(i) >= 65 && str.charAt(i) <= 90) {
                        if (value.charAt(i) >= 65 && value.charAt(i) <= 90) {
                        } else {
                            break;
                        }
                    } else {
                        if (value.charAt(i) != str.charAt(i)) {
                            break;
                        }
                    }
                }
                if (i == str.length()) {
                    return ch;
                }
            }
        }
        return 0;
    }

    /**
     * 将字符数组转换成字符串
     * @param list
     * @return
     */
    public static String replaceToString(List<Character> list) {
        StringBuffer a = new StringBuffer();
        for (Character value : list) {
            if (value != ',' && value != '[' && value != ']') {
                a.append(value);
            }
        }
        return a.toString();
    }

    /**
     * 算符优先分析过程
     * 使用一个符号栈,用它寄存终结符和非终结符,k代表符号栈的深度
     * 在正常情况下,算法工作完毕时,符号栈S应呈现:#N
     */
    public static void analysisProcess() {
        int status = 0;
        int count = 0;
        int k = 0;
        int j = 0;
        int step = 0;
        String gui = null;
        System.out.println("请输入要分析的句子(注意:记得以'#'结束)");
        String sentence = null;
        sentence = in.nextLine();
        if (sentence.charAt(sentence.length() - 1) != '#') {
            sentence = sentence + "#";
        }
        List<Character> listStack = new ArrayList<>();
        System.out.printf("%-8s%-20s%-8s%-10s%-8s\n", "步骤", "栈", "a读入", "剩余串", "操作");
        listStack.add('#');
        char a = sentence.charAt(step++);
        do {
            if (status == 0) {
                if (count != 0) {
                    System.out.printf("%-8s\n%-8d %-20s %-8c %-10s", "移进", count, replaceToString(listStack), a, sentence.substring(step));
                } else {
                    System.out.printf("%-8d %-20s %-8c %-10s", count, replaceToString(listStack), a, sentence.substring(step));
                }
            } else {
                System.out.printf("%-8s\n%-8d %-20s %-8c %-10s", gui, count, replaceToString(listStack), a, sentence.substring(step));
            }
            char ch = listStack.get(k);
            if (isEnd(ch)) {
                j = k;
            } else if (j >= 1) {
                j = k - 1;
            }
            char temp = 0;
            if (matrix.get(listStack.get(j) + "" + a) != null) {
                //规约
                while (matrix.get(listStack.get(j) + "" + a).equals('>')) {
                    if (listStack.size() == 2 && a == '#') {
                        break;
                    }
                    StringBuffer judge = new StringBuffer();
                    do {
                        temp = listStack.get(j);
                        if (isEnd(listStack.get(j - 1))) {
                            j = j - 1;
                        } else {
                            j = j - 2;
                        }
                    } while (!matrix.get(listStack.get(j) + "" + temp).equals('<'));
                    for (int i = j + 1; i < listStack.size(); i++) {
                        judge.append(listStack.get(i));
                    }
                    int te = listStack.size();
                    for (int t = j + 1; t < te; t++) {
                        listStack.remove(j + 1);
                    }
                    char res = retLeft(judge.toString());
                    if (res != 0) {
                        count++;
                        k = j + 1;
                        listStack.add(res);
                        status = 1;
                        gui = "用" + res + "->" + judge.toString() + "规约";
                        if (status == 0) {
                            System.out.printf("%-8s\n%-8d %-20s %-8c %-10s", "移进", count, replaceToString(listStack), a, sentence.substring(step));
                        } else {
                            System.out.printf("%-8s\n%-8d %-20s %-8c %-10s", gui, count, replaceToString(listStack), a, sentence.substring(step));
                        }
                    }
                }
            }
            //移进
            if (matrix.get(listStack.get(j) + "" + a).equals('<') || matrix.get(listStack.get(j) + "" + a).equals('=')) {
                count++;
                k++;
                status = 0;
                listStack.add(a);
            }else{
                switch (matrix.get(listStack.get(j) + "" + a)){
                    case 'a':
                        System.out.print("非法左括号! ");
                        return;
                    case 'b':
                        System.out.print("缺少运算符! ");
                        return
                    case 'c':
                        System.out.print("缺少表达式! ");
                        return;
                    default:
                        break;
                }
            }
            if (listStack.size() == 2 && a == '#') {
                break;
            }
            if (step < sentence.length()) {
                a = sentence.charAt(step++);
            } else {
                break;
            }
        } while (listStack.size() != 2 || a != '#');
        System.out.printf("%-8s\n", "分析成功");
    }


    /**
     * 主函数
     * @param args
     */
    public static void main(String[] args) {
        int flag = 1;
        String a;
        System.out.println("请输入文法:");
        while (flag != 0) {
            while (!(a = in.nextLine()).equals("")) {
                input.add(a);
            }
            if (isOperator()) {
                System.out.println("此文法是算符文法!");
                flag = 0;
            } else {
                System.out.println("此文法不是算符文法!请重新输入:");
                input.clear();
            }
        }
        getEnd();
        getNoEnd();
        getProduce();
        DisplayFirstVT_LastVT();
        priorityMatrix();
        analysisProcess();
    }
}

运行结果:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 22
    点赞
  • 102
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
优先分析(Operator-precedence parsing)是一种自底向上的语分析,用于判断一个表达式是否合语规则。它通过比较运之间的优先级来确定表达式的结构,从而构建语树。 以下是优先分析的基本思路: 1. 定义运之间的优先级关系,通常用数字表示,数字越大表示优先级越高。 2. 从左到右扫描表达式,遇到操作数则将其压入栈中,遇到操作则进行以下操作: - 如果栈为空,则将操作压入栈中。 - 如果栈顶是左括号,则将操作压入栈中。 - 如果操作优先级高于栈顶元素,则将操作压入栈中。 - 如果操作优先级低于或等于栈顶元素,则将栈顶元素弹出,直到栈为空或栈顶元素优先级低于该操作,然后将操作压入栈中。 - 如果操作是右括号,则将栈顶元素弹出,直到遇到左括号为止。 3. 扫描结束后,将栈中剩余的元素依次弹出,构建语树。 下面是一个简单的优先分析实现,用于计表达式的值: ```c++ #include <iostream> #include <stack> #include <map> #include <string> using namespace std; // 定义运优先级 map<char, int> priority = { {'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}, {'(', 0} }; // 计表达式的值 int calculate(int left, int right, char op) { switch (op) { case '+': return left + right; case '-': return left - right; case '*': return left * right; case '/': return left / right; default: return 0; } } // 优先分析 int operator_precedence(string expr) { stack<int> nums; // 存放操作数的栈 stack<char> ops; // 存放运的栈 for (int i = 0; i < expr.size(); i++) { char c = expr[i]; if (isdigit(c)) { // 如果是数字,将其转化为整数并压入栈中 int num = c - '0'; while (i + 1 < expr.size() && isdigit(expr[i + 1])) { num = num * 10 + (expr[i + 1] - '0'); i++; } nums.push(num); } else if (c == '(') { // 如果是左括号,将其压入栈中 ops.push(c); } else if (c == ')') { // 如果是右括号,将栈顶的运弹出,直到遇到左括号为止 while (ops.top() != '(') { char op = ops.top(); ops.pop(); int right = nums.top(); nums.pop(); int left = nums.top(); nums.pop(); nums.push(calculate(left, right, op)); } ops.pop(); // 弹出左括号 } else { // 如果是运 while (!ops.empty() && priority[c] <= priority[ops.top()]) { char op = ops.top(); ops.pop(); int right = nums.top(); nums.pop(); int left = nums.top(); nums.pop(); nums.push(calculate(left, right, op)); } ops.push(c); // 将运压入栈中 } } while (!ops.empty()) { // 将栈中剩余的运依次弹出 char op = ops.top(); ops.pop(); int right = nums.top(); nums.pop(); int left = nums.top(); nums.pop(); nums.push(calculate(left, right, op)); } return nums.top(); // 返回最终结果 } int main() { string expr = "3*(2+1)-2*(4-1)"; int result = operator_precedence(expr); cout << "Expression: " << expr << endl; cout << "Result: " << result << endl; return 0; } ``` 运行结果: ``` Expression: 3*(2+1)-2*(4-1) Result: 3 ``` 上面的代码仅支持四则运和括号,如果要支持更多的运,只需在优先级表中添加对应的优先级即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值