编译原理 实验二 简单计算器的设计与实现

Posted _DiMinisH

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了编译原理 实验二 简单计算器的设计与实现相关的知识,希望对你有一定的参考价值。

实验二 简单计算器的设计与实现 

一、实验目的

  综合运行词法分析器、语法分析器等原理实现一个具有加、乘功能的简单计算器,该计算器满足乘法优先级高于加法优先级,且仅处理非负整数。

二、实验内容

  1. 对输入的符号串首先进行词法分析,提取操作数及操作符,以输出的单词符号为输入进行语法分析。
  2. 要求以算符优先分析的方法完成语法分析工作,识别输入串是否是文法描述语言的句子
  3. 对句子进行求值,求值方式可以是遍历语法树或者是建立一个逆波兰式,对逆波兰式进行求值。

三、实验要求

  1. 从文件读入算术表达式/或者从终端输入;
  2. 词法分析,用二元组表示输出结果;
  3. 语法分析,算符优先分析方法进行自下而上的语法分析并构造语法树;
  4. 识别出的句子进行求值,遍历语法树求值或者先建立逆波兰式再求值;

四、代码

词法分析器代码链接:词法分析器

下面是算符优先分析法代码
代码在更新中…
目前实现计算FirstVt和LastVt集合

package main.experiment2;

import lombok.Getter;

import java.util.*;
import java.util.function.BiFunction;
import java.util.stream.Collectors;

/**
 * @author Diminish
 * @version 1.0
 * @since 17
 */
@Getter
public class TGrammar 

    /**
     * firstVt 集合
     * Key : 非终结符
     * Value : 集合内容
     * */
    private final Map<String, List<String>> firstTerminators = new TreeMap<>();

    /**
     * lastVt 集合
     * Key : 非终结符
     * Value : 集合内容
     * */
    private final Map<String, List<String>> lastTerminators = new TreeMap<>();

    /**
     * 非终结符集合
     * */
    private List<String> nonTerminators = new ArrayList<>();

    /**
     * 终结符集合
     * */
    private List<String> terminators = new ArrayList<>();

    /**
     * <p>语法</p>
     * */
    private final Map<String, List<String>> grammar = new HashMap<>();

    /**
     * 语法开始符号
     * */
    private String startTerminator = null;
    
    /**
     * <p>默认语法:</p>
     *      <p>A -> A+B | B</p>
     *      <p>B -> B*C | C</p>
     *      <p>C -> i</p>
     * */
    TGrammar() 
        grammar.put("A", List.of("A+B", "B"));
        grammar.put("B", List.of("C*C", "C"));
        grammar.put("C", List.of("i"));
        startTerminator = "A";
        initializeGrammar();
    

    /**
     * <p>构造指定语法</p>
     * @param start 每个句型的开始符号
     * @param generateExpression 每个开始符号对应的表达式
     * */
    TGrammar(List<String> start, List<List<String>> generateExpression) 
        for (int i = 0; i < start.size(); i++) 
            grammar.put(start.get(i), generateExpression.get(i));
            if (startTerminator == null) 
                startTerminator = start.get(i);
            
        
        initializeGrammar();
    

    /**
     * 构造终结符 非终结符 firstVt lastVt集合
     * */
    private void initializeGrammar () 
        constructNonTerminator(this);
        constructTerminator(this);
        constructFirstTerminator();
        constructLastTerminator();
    

    /**
     * 打印输出语法
     * */
    public void showGrammar () 
        for (var i : grammar.entrySet()) 
            System.out.print(i.getKey() + " -> ");
            for (var v = 0 ; v < i.getValue().size(); v++) 
                if (v + 1 == i.getValue().size()) 
                    System.out.println(i.getValue().get(v));
                 else 
                    System.out.print(i.getValue().get(v) + " | ");
                

            
        
    

    /**
     * 打印输出非终结符
     * */
    public void showNonTerminator () 
        System.out.print("非终结符: ");
        for (var v : nonTerminators) 
            System.out.print(v + " ");
        
        System.out.println();
    

    /**
     * 打印输出终结符
     * */
    public void showTerminator () 
        System.out.print("终结符: ");
        for (var v : terminators) 
            System.out.print(v + " ");
        
        System.out.println();
    

    /**
     * 打印输出 firstVt集合
     * */
    public void showFirstTerminators () 
        var entryArrayList = sort(firstTerminators);
        for (var firstTerminator : entryArrayList) 
            System.out.print("firstVt(" + firstTerminator.getKey() + ")" + " : ");
            show(firstTerminator);
        
    

    /**
     * 打印输出 lastVt集合
     * */
    public void showLastTerminators () 
        var entryArrayList = sort(lastTerminators);
        for (var lastTerminator : entryArrayList) 
            System.out.print("lastVt(" + lastTerminator.getKey() + ")" + " : ");
            show(lastTerminator);
        
    

    private void show (Map.Entry<String, List<String>> lastTerminator) 
        int length = lastTerminator.getValue().size();
        for (int i = 0; i < length; i++) 
            if (i + 1 >= length) 
                System.out.print(lastTerminator.getValue().get(i));
             else 
                System.out.print(lastTerminator.getValue().get(i) + " , ");
            
        
        System.out.println();
    

    /**
     * 排序, 根据值的长度排序, 按照值的长度从大到小排序
     * @return 排好序的链表
     */
    private List<Map.Entry<String, List<String>>> sort (Map<String, List<String>> firstOrLastTerminators) 
        var entryArrayList = new ArrayList<>(firstOrLastTerminators.entrySet());
        entryArrayList.sort((o1, o2) -> o2.getValue().size() - o1.getValue().size());
        return entryArrayList;
    

    /**
     * 判断是不是终结符
     * @param c 需要判断的符号
     * @return 判断结果
     * */
    private boolean isTerminator (String c) 
        return terminators.stream().anyMatch(terminator -> terminator.equals(c));
    

    /**
     * 判断是不是非终结符
     * @param c 需要判断的符号
     * @return 判断结果
     * */
    private boolean isNonTerminator (String c) 
        return nonTerminators.stream().anyMatch(nonTerminator -> nonTerminator.equals(c));
    

    /**
     * 构造非终结符
     * */
    private void constructNonTerminator(TGrammar grammar) 
        for (var i : grammar.grammar.entrySet()) 
            nonTerminators.add(i.getKey());
        
        nonTerminators = nonTerminators.stream().distinct().collect(Collectors.toList());
    

    /**
     * 构造终结符, 除大写字母以外的字符都是终结符
     * */
    private void constructTerminator(TGrammar grammar) 
        for (var i : grammar.grammar.entrySet()) 
            for (var v : i.getValue()) 
                for (int index = 0; index < v.length(); index++) 
                    if (v.substring(index, index + 1).matches("[^A-Z]|")) 
                        terminators.add(v.substring(index, index + 1));
                    
                
            
        
        terminators = terminators.stream().distinct().collect(Collectors.toList());
    

    /**
     * 构造 firstVt 集合
     * */
    private void constructFirstTerminator() 
        // 求出来的firstVt集合
        Map<String, List<String>> firstTerminators = this.firstTerminators;
        List<String> nonTerminators = this.nonTerminators;
        // 初始化firstVt集合
        for (var i : nonTerminators) 
            firstTerminators.put(i, new ArrayList<>());
        
        // 记录是否完成
        boolean isFinished = false;
        // 集合表示对应的非终结符是否求出了firstVt集合, 求出后对应的元素置为true
        Map<String, Boolean> flags = new HashMap<>(8);
        // 初始化集合, 表示开始时所有的非终结符的firstVt集合没有求出, 所有默认是false
        for (var i : firstTerminators.entrySet()) 
            flags.put(i.getKey(), false);
        
        int index = 0;
        while (!isFinished) 
            // 记录一个产生式是否计算完了firstVt
            boolean isBreak = false;
            // index循环
            if (index > nonTerminators.size() - 1) 
                index = 0;
            
            // 获取index位置上的非终结符Vn
            String Vn = nonTerminators.get(index);
            // 判断Vn对应的flag值, 不为true进行计算, 为true表示计算出来了
            if (!flags.get(Vn)) 
                // 获取Vn的产生式
                List<String> generateExpressions = grammar.get(Vn);
                // 逐一进行判断
                for (String generateExpression : generateExpressions) 
                    // P -> a...
                    // 判断文法产生式是不是以终结符开头,是的话就把该终结符加入 firstVt集合
                    // a是第一个位置的元素
                    String a = generateExpression.substring(0, 1);
                    // 判断 a是不是终结符
                    if (isTerminator(a)) 
                        // 是, 即 P 的产生式以终结符开头
                        // 满足 P -> a.. 把 a 加入 firstVt(P)集合
                        firstTerminators.get(Vn).add(a);
                    
                    // 如果产生式不是以终结符开头
                    // 判断 P -> Qa... 成立
                    // 即 判断文法产生式是不是以 非终结符 终结符 开头,是的话就把该终结符加入 firstVt(P)集合
                    else 
                        // Q 是产生式第一个元素
                        String Q = generateExpression.substring(0, 1);
                        // a 是产生式第二个元素
                        // 判断一下是否有第二个元素, 即判断是否越界
                        try 
                            a = generateExpression.substring(1, 2);
                         catch (Exception e) 
                            a = "";
                        
                        // 判读 P -> Qa... 成立
                        boolean pCanGetQa = isNonTerminator(Q) && isTerminator(a);
                        // 如果 P 的产生式以 Qa开头
                        if (pCanGetQa) 
                            // 将 a加入到firstVt(P)中
                            firstTerminators.get(Vn).add(a);
                        
                        // 匹配第二条件
                        // 若 a ∈ firstVt(Q) 且 P -> Q... 则 a ∈ firstVt(P)
                        // 判断 P != Q
                        if (!Q.equals(Vn)) 
                            // 判断 P -> Q... 中, Q是非终结符
                            boolean QisNotTerminator = isNonTerminator(Q);
                            // 判读 Q 的 firstVt(Q) 是否已经算出来
                            boolean qFirstVtIsDone = flags.get(Q);
                            // Q 是 非终结符
                            if (QisNotTerminator) 
                                // Q 的 firstVt(Q) 是否已经算出来
                                if (qFirstVtIsDone) 
                                    // 算出来了
                                    // 将 firstVt(Q) 中的元素加入 firstVt(P)
                                    List<String> firstVtQ = firstTerminators.get(Q);
                                    List<String> firstVtP = firstTerminators.get(Vn);
                                    firstVtP.addAll(firstVtQ);
                                
                                // 没有算出来直接到下一个进行计算
                                else 
                                    isBreak = true;
                                    break;
                                
                            
                        
                    
                
                // 没有计算出来就会调到这里
                // index++ 后直接下一个产生式扫描
                index++;
                if (isBreak) 
                    continue;
                
                // 计算出了 firstVt
                flags.put(Vn, true);
             else 
                index++;
            
            // 判断是不是都计算完了firstVt集合
            boolean result = true;
            for (var flag : flags.entrySet()) 
                result = result && flag.getValue();
            
            isFinished = result;
        
        // 去重
        for (var i : firstTerminators.entrySet()) 
            i.setValue(i.getValue().stream().distinct().collect(Collectors.toList()));
        
    

    /**
     * 构造 lastVt 集

以上是关于编译原理 实验二 简单计算器的设计与实现的主要内容,如果未能解决你的问题,请参考以下文章

编译原理 LL语法分析器的设计与实现

编译原理 LL语法分析器的设计与实现

编译原理 LL语法分析器的设计与实现

编译原理 LL语法分析器的设计与实现

编译原理实验:实验一 简单词法分析程序设计(必修)(Python实现)

编译原理--语法分析之LR分析法的简单实现