Java实现LL1语法分析器

该实验旨在加深对语法分析器工作原理的理解,通过预测分析法编写Java实现的LL1语法分析程序。实验内容包括定义语法规则,求解预测分析表,实现错误处理,并对测试用例进行语法分析。实验步骤涉及消除左递归、求解FIRST和FOLLOW集、创建分析表及设计LL1解析栈。实验结果显示,对于合法和不合法的输入,分析程序能正确识别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实验内容要求

一、实验目的 加深对语法分析器工作过程的理解;加强对预测分析法实现语法分析程序的掌握;能够 采用一种编程语言实现简单的语法分析程序;能够使用自己编写的分析程序对简单的程序段 进行语法翻译。

二、实验内容 用预测分析法编制语法分析程序,语法分析程序的实现可以采用任何一种编程语言和工 具。

三、实验要求: 1. 对语法规则有明确的定义; 2. 编写的分析程序能够对测试用例进行正确的语法分析; 3. 对于遇到的语法错误,能够做出简单的错误处理,给出简单的错误提示,保证顺 利完成语法分析过程; 4. 实验报告要求用文法的形式对语法定义做出详细说明,说明语法分析程序的工作 过程,说明错误处理的实现。

四、实验步骤 1. 定义目标语言的语法规则; 2. 求解预测分析方法需要的符号集和分析表; 3. 依次读入测试用例,根据预测分析的方法进行语法分析,直到源程序结束; 4. 对遇到的语法错误做出错误处理。

实验步骤

设计一个主类用来进行文件的输入,和结果的输出;然后按照四步走的策略来创建相对于的类操作。
第一步:创建LeftRecursion类来消除左递归,获取原始的产生式、终结符、非终结符;消除左递归之后的产生式、终结符和非终结符。然后简化产生式,每一个产生式只包含一个候选式。
第二步:创建FirstAndFollow类来求FIRST集和FOLLOW集。
第三步:创建AnalyzeTable类来获取分析表。
第四步:创建LL1Stack类来对测试用例进行入栈操作求解结果。
为了完成以上的任务,还需要创建一个Grammar类保存数据。以上就是设计的主要方案。

  • LL1 .java
import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;

/*
* 实验的主要方法:
* 1、消除左递归
*       1.1构造出终结符集、非终结符集
*       1.2把消除左递归得到的产生式进行简化,即一条产生式里面只有一个候选式
* 2、构造FIRST集和FOLLOW集
* 3、构造预测分析表
* 4、构造符号栈和输入串栈进行测试实例分析
* */

public class LL1 {
   

    //原始的产生式
    static ArrayList<String> expression;
    //语法器
    static Grammar grammar;

    public static void main(String []args) throws FileNotFoundException {
   

        grammar=new Grammar();
        expression=new ArrayList<>();

        //采用文件读入的方式
        File file=new File("E:\\code\\bytest\\test11\\test4.txt");
        try(Scanner input=new Scanner(file)) {
   
            while (input.hasNextLine()){
   
                String line=input.nextLine();
                if (line.equals("")){
   //采用空一行这种方式,下一行就是测试用例
                    grammar.setTestEx(input.nextLine());
                    break;
                }else {
   
                    expression.add(line);
                }
            }
        }

        //消除左递归
        LeftRecursion leftRecursion=new LeftRecursion();
        leftRecursion.setExpression(expression);
        leftRecursion.work();

        //分别给语法器开始设置非终结符集、终结符集、文法开始符号、简化之后的产生式
        grammar.setNa(leftRecursion.getNa());
        grammar.setNt(leftRecursion.getNt());
        grammar.setStart(leftRecursion.getStart());
        grammar.setSimpleExpression(leftRecursion.getSimpleExpression());

        System.out.println();
        System.out.println("--------------------------------------------------");
        System.out.println("消除左递归");
        System.out.println();

        System.out.println("产生式");
        for(Map.Entry<Character, ArrayList<String>> entry : grammar.getSimpleExpression().entrySet()){
   
            for (String s:entry.getValue()){
   
                System.out.println(entry.getKey()+"->"+s);
            }
        }

        System.out.println("--------------------------------------------------");
        System.out.println("非终结符");
        for (Character na:grammar.getNa().keySet()){
   
            System.out.printf("%-10c",na);
        }
        System.out.println();

        System.out.println("--------------------------------------------------");
        System.out.println("终结符");
        for (Character nt:grammar.getNt().keySet()){
   
            System.out.printf("%-10c",nt);
        }
        System.out.println();
        System.out.println("--------------------------------------------------");
        System.out.println("读取测试用例");
        System.out.println(grammar.getTestEx());

        //开始构造FIRST集和FOLLOW集
        FirstAndFollow firstAndFollow=new FirstAndFollow(grammar);
        firstAndFollow.work();
        grammar.setFirst(firstAndFollow.getFirst());
        grammar.setFollow(firstAndFollow.getFollow());

        System.out.println("--------------------------------------------------");
        System.out.println("FIRST集");
        for (Character na:grammar.getNa().keySet()){
   
            String FirstSet=grammar.getFirst().get(na).toString().replace("[","");
            FirstSet=FirstSet.replace("]","");
            System.out.println("FIRST("+na+")={"+FirstSet+"}");
        }
        System.out.println("--------------------------------------------------");
        System.out.println("FOLLOW集");
        for (Character na:grammar.getNa().keySet()){
   
            String FollowSet=grammar.getFollow().get(na).toString().replace("[","");
            FollowSet=FollowSet.replace("]","");
            System.out.println("FOLLOW("+na+")={"+FollowSet+"}");
        }

        //构造预测分析表
        AnalyzeTable analyzeTable=new AnalyzeTable(grammar);
        analyzeTable.work();
        grammar.setAnalyzeTable(analyzeTable.getAnalyzeTable());
        System.out.println("--------------------------------------------------");
        System.out.println("预测分析表");
        System.out.printf("%-11s","");
        for (Character nt:grammar.getNt().keySet()){
   
            if (nt!='ε') {
   
                System.out.printf("%-10s", nt);
            }
        }
        System.out.println();
        for (Character na:grammar.getNa().keySet()){
   
            System.out.printf("%-10s",na);
            for (int i=1;i<=grammar.getNt().size();i++){
   
                if(grammar.getAnalyzeTable()[grammar.getNa().get(na)][i]!=null){
   
                    System.out.printf("%-10s",na+"->"+ grammar.getAnalyzeTable()[grammar.getNa().get(na)][i]);
                }else{
   
                    System.out.printf("%-10s","");
                }
            }
            System.out.println("");
        }
        System.out.println("--------------------------------------------------");
        System.out.println("预测分析步骤");
        System.out.println();

        //利用LL1开始测试测试用例
        LL1Stack stack=new LL1Stack(grammar);
        stack.work();
    }
}
  • Grammar.java
import java.util.*;

public class Grammar {
   
    //非终结符
    /*
    * 这里解释一下为什么要采用Map,而不是采用Set,因为我觉得采用map方便生成预测分析表,可以利用键对应的值,找到产生式在
    * 分析表中的位置。如 E->FA.要找到它在分析表中的位置,先要确定E在哪一行,直接判断FIRST(E)对应的符号所在哪一列,才可
    * 以确定表达式的位置,这样也有利于最后的测试用例测试。
    * */
    private Map<Character,Integer> Na;
    //终结符
    private Map<Character,Integer> Nt;
    //原始的产生式
    private ArrayList<String> expression;
    //简化之后的产生式
    private Map<Character,ArrayList<String>> simpleExpression;
    //开始符
    private Character start;
    //测试实例
    private String testEx;
    //分析表
    private String[][] analyzeTable;


    //first集
    private Map<Character, HashSet<Character>> First;
    //Follow集
    private Map<Character, HashSet<Character>> Follow;

    public Grammar() {
   
        Na=new LinkedHashMap<>();
        Nt=new LinkedHashMap<>();
        simpleExpression=new LinkedHashMap<>();
        Follow=new HashMap<>();
        First=
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值