编译原理——语法分析

一、实验目的:

  1. 了解语法分析的主要任务。
  2. 实现基本的递归下降分析器,能够分析任意的符号串是否为该文法所定义的合法算术表达式。

二、实验内容:

对LL(1)文法采用递归下降子程序实现语法分析

三、实验过程:

1)示范,示例LL(1)文法如下:
G[A]:
(1)S::=pA
(2)S::=qB
(3)A::=cAd
(4)A::=a
(5)B::=dB
(6)B::=b
对应每条规则的选择集如下:
(1){p}
(2){q}
(3){c}
(4){a}
(5){d}
(6){b}
上述LL(1)递归下降子程序示例代码如附录1。
任务:验证递归下降子程序
2)下面是简化的四则运算的语法规则,递归下降子程序法不能直接用这组规则进行语法分析
G[E]:
E::=E+T
E::=T
T::=T*F
T::=F
F::=(E)
F::=i
但是我们可以通过改造文法后,构建一等价文法,可以利用递归下降子程序发进行语法分析,该等价文法如下:
1.E::=TA
2.A::=+TA
3.A::=
4.T::=FB
5.B::=FB
6.B::=
7.F::=(E)
8.F::=i
对应规则的选择集如下:
1.{(,i}
2.{+}
3.{),#}
4.{(,i}
5.{
}
6.{+,),#}
7.{(}
8.{i}
任务:编写递归下降子程序进行语法分析

四、实验结果:

任务一:

  1. 原理:

对每一个非终结符(分别代表一个语法单位)按其产生方式结构构造相应的语法子程序,以完成非终结符号所对应的语法单位的分析和识别任务。其中终结符号产生匹配命令,而非终结符号则产生过程调用命令。因为文法可以递归,相应子程序也是递归的。

  1. 注释:
    对附录代码进行稍作修改以及注释成功编译运行:
    在这里插入图片描述
    在这里插入图片描述
    代码注释版本:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SourceMaxLength 10000
//声明函数
void error();
void S();
void A();
void B();

//结构体存放待比较字符串
struct sourceStr{
    char source[SourceMaxLength];//缓存字符串
    int pointer;//字符串下表指针
};
struct sourceStr sour;
char token;//存放当前比较的字符
int flag=1;//编译成功标记
char getToken()//获取当前字符
{
    token=sour.source[sour.pointer];
    sour.pointer++;
    return token;
}

int main()
{
    sour.pointer=0;
    strcpy(sour.source,"pcad");//将字符串复制给sour.source
    //首先执行初始非终结符
    S();

    if(flag==1)
    {
        printf("success!");
    }
    else
    {
        printf("error");
    }
    return 0;
}
void error()//错误输出操作
{
    flag=0;
    printf("error;");
}
void S()//开始判断函数
{
    token=getToken();
    if(token != 'p' && token!='q')//如果下一个当前取得的字符不为p\q,则字符串错误
        error();
    else
    {
        if(token == 'p')//如果当前字符为p
        {
            A();//执行非终结符A的判断
        }
        else//否则执行非终结符B的判断
        {
            B();
        }
    }
}
void A()//执行非终结符A的判断
{
    token=getToken();
    if(token!='c'&&token!='a')//如果当前字符不符合,输出错误
        error();
    else{
        if(token=='c')//如果为c,则执行A判断
        {
            A();
            //判断下一个字符是否为d
            token=getToken();
            if(token!='d')
                error();
        }
        else{
            ;
        }
    }
}
void B()//执行非终结符A的判断
{
    token=getToken();
    if(token!='d'&&token!='b')//如果当前字符不符合,输出错误
        error();
    else{
        if(token=='d')//如果为d,执行B函数
        {
            B();
        }
        else
        {
            ;
        }
    }
}

  1. 心得:
    首先更加清晰的理解了语法分析的主要任务,它是在词法分析的基础上将单词组合起来,组成一些语句,比如说在Java中,public static void main(String[]args);方法中,如果void写在public前面编译器就会报错,那是因为编译器已经做好了语法分析的工作,说白了对源代码在结构是否正确这就是语法分析的任务。

任务二:

注释:
代码编译运行:
在这里插入图片描述
代码注释版本:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SourceMaxLength 10000
//声明函数
void A();
void B();
void F();
void T();

//字符串结构体
struct sourceStr{
    char source[SourceMaxLength];//缓存字符串
    int pointer;//字符串下表指针
};

struct sourceStr sour;
char token;//存放当前比较的字符
int flag=1;//编译成功标记
char getToken()//获取当前字符
{
    token=sour.source[sour.pointer];
    sour.pointer++;
    return token;
}
void getSource(FILE *fp)//用于从文件中获取字符串
{

}
void error()//错误输出操作
{
    flag=0;
    printf("error;");
}
void E()//开始判断函数
{
    token=getToken();
    if(token != '(' && token!='i')//如果下一个当前取得的字符不为(、i,则字符串错误
        error();
    else{
        if(token=='('){//如果为(,执行(),并取下一个字符
            E();
            token=getToken();
            if(token!=')')
                error();

        }
        B();
        A();
    }
}

void T()//非终结符T判断
{
    token=getToken();
    if(token != '(' && token!='i')//如果下一个当前取得的字符不为(、i,则字符串错误
        error();
    else
    {
        if(token=='('){
            E();
            token=getToken();
            if(token!=')')
                error();

        }
        B();
    }
}

void F()//非终结符F判断
{
    token=getToken();
    if(token != '(' && token!='i')
        error();
    else
    {
        if(token=='('){
            E();
            token=getToken();
            if(token!='(') error();
        }
        else{
            ;
        }
    }
}

void A()//非终结符A判断
{
    token=getToken();
    if(token!='+'&&token!=')'&&token!='#')//如果当前字符不符合,输出错误
        error();
    else{
        if(token=='+')
        {
            T();
            A();
        }else{//如果A终结符为空,字符串指针回溯一个
            sour.pointer--;
        }
    }
}
void B()
{
    token=getToken();
    if(token!='*'&&token!='+'&&token!=')'&&token!='#')//如果当前字符不符合,输出错误
        error();
    else{
        if(token=='*')
        {
            F();
            B();
        }else{//如果B终结符为空,字符串指针回溯一个
            sour.pointer--;
        }
    }
}

int main()
{
    sour.pointer=0;
    strcpy(sour.source,"(i+i*i)+i*i#");//将字符串复制给sour.source

    //首先执行初始非终结符
    E();
    if(flag==1)
    {
        printf("success!");
    }
    else
    {
        printf("error");
    }
    return 0;
}

心得:
理解了递归下降分析法,它是一种自顶向下的分析,根据文法来构造C函数,遇到终结符时通过和自己在屏幕中录入的数据作比较,若相同修改数组索引,这个终结符后面若是一个非终结符则调用这个非终结符的函数。一层一层的向下分析,有时会在函数体中调用自己,这就形成了递归

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值