编译原理:语法分析

实验三 语法分析

实验目的

  • 给出 PL/0 文法规范,要求编写 PL/0 语言的语法分析程序。
  • 通过设计、编制、调试一个典型的语法分析程序,实现对词法分析 程序所提供的单词序列进行语法检查和结构分析,进一步掌握常用 的语法分析方法。
  • 选择一种语法分析方法(递归子程序法、LL(1)分析法、算符优先分 析法、SLR(1)分析法);选择常见程序语言都具备的语法结构,如赋 值语句,特别是表达式,作为分析对象。

主要思想:

我们使用LL(1)分析法进行语法分析。上一次实验我们已经获得了词法分析器,其结果是本次实验的输入,因此我们直接在上一次实验的基础上做改造。因为我们使用LL(1)进行语法分析,因此在本次实验中,我们首先计算出First集、Follow集、select集,然后根据select集画出预测分析表。

如下图所示,首先我们写出题目要求的最基本的文法:

s->add0
add0->add0 opt1 mul0|mul0
mul0->mul0 opt2 exp|exp
opt1->+|-
opt2->*|/
exp->(add0)|a

可以看出上述文法表示了一个四则运算的算数表达式。但是上述文法中存在诸如add0->add0的左递归,我们应当消除左递归。消除后文法如下:

s->add0
add0-> mul0 add1
add1->opt1 mul0 add1|空
mul0->exp mul1
mul1->opt2 exp mul1|空
opt1->+|-
opt2->*|/
exp->(add0)|a

根据该文法的表达式,我们可以计算三个集合,并且做出如下的预测分析表:

image-20230519143234141

在上表中,各行分别代表状态为行索引的状态时,输入为各符号时下一个状态是什么。如第一行就代表了当前状态为初始态S时,当输入为符号alpha(也就是包括0-9与变量标识符)时,状态会变为add0;当遇到 ( 时,状态会变为add0。其余以此类推。

由此,我们只需要通过程序实现该表格即可。

主要代码

  • 状态转移函数:重要的功能代码就是实现该表的状态转换,这一点用switch-case即可实现。由于该函数代码过长,截断其中三个case输出:
int stateChange(Symbol sym) { //返回状态有三种:-1代表匹配失败,0代表匹配成功且是非终结符,1代表匹配成功且是终结符
          switch (parsingStack.peek()) {
              case START:
                  switch (sym) {
                      case ALPHA:
                      case LPARN:
                          parsingStack.pop();
                          parsingStack.push(GRAMMAR.ADD0);
                          return 0;
                      default:
                          return -1;
                  }
              case ADD0:
                  switch (sym){
                      case ALPHA:
                      case LPARN:
                          parsingStack.pop();
                          parsingStack.push(GRAMMAR.ADD1);
                          parsingStack.push(GRAMMAR.MUL0);
                          return 0;
                      default:
                          return -1;
                  }
              case ADD1:
                  switch (sym) {
                      case RPARN:
                      case END:
                          parsingStack.pop();
                          parsingStack.push(GRAMMAR.BLANK);
                          return 0;
                      case OPT1:
                          parsingStack.pop();
                          parsingStack.push(GRAMMAR.ADD1);
                          parsingStack.push(GRAMMAR.MUL0);
                          parsingStack.push(GRAMMAR.OPT1);
                          return 0;
                      default:
                          return -1;
                  }
  • 匹配函数。每次状态转移后,都应该检测是否转移到“终态”,即应当匹配缓冲串和状态是否一致,一致就都弹出,重新回到初态。

    boolean check(List<Symbol> input){
            parsingStack.push(GRAMMAR.START);
            int index = 0;
            while(index<input.size()&&!parsingStack.empty()){
                if (!parsingStack.empty()) {
                    //System.out.println("现在匹配:" + index + " INPUT为:" + input.get(index).name());
                    System.out.println(parsingStack);
                }
                int flag = stateChange(input.get(index));
                if(flag==-1) {
                    System.out.println("没有可用的语法,匹配失败");
                    return false;
                }
                else if(flag==0){//状态已经转变,可以继续下一次循环
                    continue;
                }
                else //flag == 1,比较栈顶和输入符号
                {
                    if(input.get(index).name().equals(parsingStack.peek().name())) {//说明栈顶和INPUT字符相等,可以消去
                        parsingStack.pop();
                        index++;
                    }
                    else {
                        System.out.println("栈顶和INPUT字符不相等,匹配失败");
                        return false;
                    }
                }
    
            }
            if(parsingStack.empty()&&index==input.size()-1&&input.get(index).name()=="END")
            {
                System.out.println("匹配成功");
                return true;
            }
            else
            {
                System.out.println("未同时为空,匹配失败");
                return false;}
    
        }
    

运行结果

测试样例:

3 + 5
a + 1 + 5+ num
12+23*3
((((1+1)*a)*4)/4)+4+2
a +
a
+
(3+3)*(4 +
+ 4 +s

运行结果:

匹配成功
accept
匹配成功
accept
匹配成功
accept
匹配成功
accept
没有可用的语法,匹配失败
deny
匹配成功
accept
没有可用的语法,匹配失败
deny
没有可用的语法,匹配失败
deny
没有可用的语法,匹配失败
deny

可以看到运行结果正确。

posted @ 2023-06-10 20:14  丘丘王  阅读(163)  评论(0编辑  收藏  举报
鼠标点击页面特效

尝试在空白处点击鼠标