[编译原理] 算符优先分析实验报告

1.实验原理

算符优先分析法(Operator Precedence Parsing)是一种用于解析表达式的语法分析方法。它通过确定运算符之间的优先级和结合性来分析和构建表达式的语法树。

算符优先分析法的基本思想是,为每个运算符赋予一个优先级,然后利用这些优先级来确定运算符之间的顺序。在算符优先分析法中,每个运算符都有一个左优先级和一个右优先级,用来指示它在与相邻运算符结合时的优先级。通常,左结合性指示运算符与其左边的运算符结合,右结合性指示运算符与其右边的运算符结合。

算符优先分析法的优点是简单而高效,特别适用于具有相对简单运算符优先级关系的表达式。然而,对于包含复杂优先级规则的表达式,算符优先分析法可能无法适应,需要使用其他更复杂的语法分析方法。

2.设计思想

在这里插入图片描述

3.实验算法及流程图

在这里插入图片描述

4.实验代码

友情提示: 有bug, 基本能跑, 谨慎CV

OPP.java

import java.util.*;

public class OPP {

    /**
     * 优先级常量
     */
    final int STATE1 = 1; // less than
    final int STATE2 = 2; // same as
    final int STATE3 = 3; // bigger than
    final int ERORR = 4; // error


    /**
     * 栈
     */
    Stack<String> S = new Stack<>();

    /**
     * 语法表
     */
    Map<String, ArrayList<String>> grammarMap = new HashMap<>();

    /**
     * 算符优先表
     */
    Map<String, HashMap<String, Integer>> OPPMap = new HashMap<>();

    Scanner scanner = new Scanner(System.in);

    public OPP(){
        init();
    }

    /**
     * 算符优先分析核心算法
     * @return 句子是否正确
     */
    boolean parse(){
        S.push("#");
        while(true){
            int j;
            String a = loadCharacter(); // 输入串的首字符
            if(isVT(S.peek())){
                j = topIndex(S);
            } else {
                j = topIndex(S)-1;
            }
            if (jdg(S.get(j), a) == ERORR) {
                return false;
            }
            while(jdg(S.get(j), a) == STATE3){
                while (true) {
                    String Q = S.get(j);
                    if(isVT(S.get(j-1))){
                        j = j-1;
                    } else {
                        j = j-2;
                    }
                    if(jdg(S.get(j), Q) == STATE1){
                        break;
                    }
                }
                // 进行归约
                String N = reduce(j+1);
                if(N.equals("@")) return false;
                S.push(N);
            }
            if(jdg(S.get(j), a) == STATE1 || jdg(S.get(j), a) == STATE2){
                S.push(a);
            }
            if(a.equals("#")){
                break;
            }
        }
        return true;
    }

    /**
     * 一些初始化工作
     */
    private void init() {
        // 初始文法的构建
        grammarMap.put("A", new ArrayList<>());
        grammarMap.get("A").add("A+B");
        grammarMap.get("A").add("B");
        grammarMap.get("A").add("C+C");
        grammarMap.get("A").add("C*C");
        grammarMap.put("B", new ArrayList<>());
        grammarMap.get("B").add("B*C");
        grammarMap.get("B").add("C");
        grammarMap.put("C", new ArrayList<>());
        grammarMap.get("C").add("i");
        grammarMap.get("C").add("n");
        grammarMap.get("C").add("(A)");
        grammarMap.put("D", new ArrayList<>());
        grammarMap.get("D").add("+");
        grammarMap.get("D").add("-");
        grammarMap.put("D", new ArrayList<>());
        grammarMap.get("D").add("*");
        grammarMap.get("D").add("/");

        // 算符优先表构建
        OPPMap.put("+", new HashMap<>());
        OPPMap.get("+").put("+",3);
        OPPMap.get("+").put("*",1);
        OPPMap.get("+").put("i",1);
        OPPMap.get("+").put("(",1);
        OPPMap.get("+").put(")",3);
        OPPMap.get("+").put("#",3);

        OPPMap.put("*", new HashMap<>());
        OPPMap.get("*").put("+",3);
        OPPMap.get("*").put("*",3);
        OPPMap.get("*").put("i",1);
        OPPMap.get("*").put("(",1);
        OPPMap.get("*").put(")",3);
        OPPMap.get("*").put("#",3);

        OPPMap.put("i", new HashMap<>());
        OPPMap.get("i").put("+",3);
        OPPMap.get("i").put("*",3);
//        OPPMap.get("i").put("i",1);
//        OPPMap.get("i").put("(",1);
        OPPMap.get("i").put(")",3);
        OPPMap.get("i").put("#",3);

        OPPMap.put("(", new HashMap<>());
        OPPMap.get("(").put("+",1);
        OPPMap.get("(").put("*",1);
        OPPMap.get("(").put("i",1);
        OPPMap.get("(").put("(",1);
        OPPMap.get("(").put(")",2);
//        OPPMap.get("(").put("#",3);

        OPPMap.put(")", new HashMap<>());
        OPPMap.get(")").put("+",3);
        OPPMap.get(")").put("*",3);
//        OPPMap.get(")").put("i",1);
//        OPPMap.get(")").put("(",1);
        OPPMap.get(")").put(")",3);
        OPPMap.get(")").put("#",3);

        OPPMap.put("#", new HashMap<>());
        OPPMap.get("#").put("+",1);
        OPPMap.get("#").put("*",1);
        OPPMap.get("#").put("i",1);
        OPPMap.get("#").put("(",1);
//        OPPMap.get("#").put(")",2);
        OPPMap.get("#").put("#",2);
    }

    private int cnt = 0;
    /**
     * 读一个字符
     * @return 当前字符
     */
    private String loadCharacter() {
        //if (scanner.hasNext()) {
        cnt ++;
        if (cnt != 8) {
            String binarySet = scanner.next();
            StringBuilder word = new StringBuilder();
            for ( int i = 1; binarySet.charAt(i)!=','; i++){
                word.append(binarySet.charAt(i));
            }
            String description = String.valueOf(word);
            if(description.equals("plus")) return "+";
            if(description.equals("minus")) return "-";
            if(description.equals("times")) return "*";
            if(description.equals("slash")) return "/";
            if(description.equals("number")) return "n";
            if(description.equals("ident")) return "i";
            if(description.equals("lparen")) return "(";
            if(description.equals("rparen")) return ")";
            throw new RuntimeException("unknown character");
        } else {
            return "#";
        }
    }

    /**
     * 寻找归约语句
     * @param l 从栈顶字符到下标为l的字符进行归约
     * @return 归约结果
     */
    private String reduce(int l){
        // 从栈中获取待归约字符串
        StringBuilder stringBuilder = new StringBuilder();
        int stackSize = topIndex(S);
        for( int i = l; i<=stackSize; i++){ // todo:这里真的是这样吗
            stringBuilder.append(S.get(i));
        }
        // 先把字符串提出来在把它从栈中删除
        for ( int i = l; i<=stackSize; i++){
            S.pop();
        }
        String str = stringBuilder.toString();
        // 遍历语法表找到可归约的串
        for (Map.Entry<String, ArrayList<String>> entry : grammarMap.entrySet()){
            if (entry.getValue().contains(str)) {
                return entry.getKey();
            }
        }
        return "@";
    }

    /**
     * 比较两个算符的优先级
     * @param a
     * @param b
     * @return 比较结果
     */
    private int jdg(String a, String b){
        a = simplify(a);
        b = simplify(b);
        if(OPPMap.get(a).get(b) == null){
            return ERORR;
        } else {
            return OPPMap.get(a).get(b);
        }
    }

    private String simplify(String a) {
        String temp = "";
        switch(a){
            case "-": temp = "+";break;
            case "/": temp = "*";break;
            case "n": temp = "i";break;
            default: temp = a;
        }
        return temp;
    }

    /**
     * 返回栈顶索引
     * @param s
     * @return 栈顶索引
     */
    private int topIndex(Stack<String> s) {
        return s.size()-1;
    }

    /**
     * 判断是否是非终结符
     * @param s
     * @return 结果
     */
    private boolean isVT(String s) {
        return !(s.charAt(0) >= 'A' && s.charAt(0) <= 'Z');
    }
}

OPPDemo.java


public class OPPDemo {
    public static void main(String[] args){
        OPP opp = new OPP();
        if(opp.parse()){
            System.out.println("Yes,it is correct.");
        } else {
            System.out.println("No,it is wrong.");
        }
    }
}

5.实验结果与分析

输入:
(lparen,()
(ident,a)
(plus,+)
(number,15)
(rparen,))
(times,*)
(ident,b)
预计输出:
Yes,it is correct.
实际输出:
在这里插入图片描述

输入:
(lparen,()
(ident,a)
(plus,+)
(number,15)
(rparen,))
(plus,+)
(times,*)
(ident,b)
预计输出:
No,it is wrong.
实际输出:
在这里插入图片描述

  • 0
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值