• 编译原理:实验二 递归下降语法分析


    一、实验目的

      利用C语言编制递归下降分析程序,并对简单语言进行语法分析。

      编制一个递归下降分析程序,实现对词法分析程序所提供的单词序列的语法检查和结构分析。

    二、实验原理

      每个非终结符都对应一个子程序。

      该子程序根据下一个输入符号(SELECT集)来确定按照哪一个产生式进行处理,再根据该产生式的右端:

    • 每遇到一个终结符,则判断当前读入的单词是否与该终结符相匹配,若匹配,再读取下一个单词继续分析;不匹配,则进行出错处理
    • 每遇到一个非终结符,则调用相应的子程序

    三、实验要求说明

      输入单词串,以“#”结束,如果是文法正确的句子,则输出成功信息,打印“success”,否则输出“error”,并指出语法错误的类型及位置。

    例如:

      输入begin a:=9;x:=2*3;b:=a+x end #

      输出success

      输入x:=a+b*c  end #

      输出‘end' error

    四、实验步骤

      1.待分析的语言的语法(参考P90)

      2.将其改为文法表示,至少包含

    • –语句
    • –条件
    • –表达式

      3. 消除其左递归

      4. 提取公共左因子

      5. SELECT集计算

      6. LL(1)文法判断

      7. 递归下降分析程序

    程序词法分析代码:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    //函数申明 
    void match();          //匹配的方法
    void Bparser();     //匹配begin
    void Pre();           //对语法进行预处理
    void statement();   //匹配语法声明
    void expression();  //匹配运算符 
    void term();        //匹配*/运算符 
    void factor();      //匹配括号 
    
    char temp[500],test[500];
    char ch;
    const char *keyword[6]= {"begin","if","then","while","do","end"};   //存储保留字
    int i=0,num,n,ednum=0,bnum=0,k=0;
    
    //匹配的方法
    void match() {
        ch=temp[i++];
        while(ch==' ') {
            ch=temp[i++];
        }
        if((ch>='A'&&ch<='Z')||(ch>='a'&&ch<='z')) {        //保留字与标识符判断
            n=0;
            num=10;
            char a=ch;
    
            while((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')||(ch>='0'&&ch<='9')) { //字符串数组复制
                test[n++]=ch;
                ch=temp[i++];
            }
    
            test[n++]='';
    
            for(n=0; n<6; n++) {
                if(strcmp(test,keyword[n])==0) {  //判断两个字符串是否一致
                    num=n+1;
                    printf("[%s,%d]
    ",test,num);
                    if(num==1) {
                        bnum=1;//begin存在 
                    }
                    if(num==6) {
                        ednum=1;//end存在 
                    }
                    break;
                }
            }
            i--;
            if(num==10) {
                ch=a;
                printf("[%c,%d]
    ",ch,num);
            }
        }
    
        if(ch>='0'&&ch<='9') {    //数字判断
            num=11;
            printf("[%c,%d]
    ",ch,num);
    
        } else {
            switch(ch) {    //运算符界符的判断
                case '#':
                    num=0;printf("[%c,%d]
    ",ch,num);break;
                case '+':
                    num=13;printf("[%c,%d]
    ",ch,num);break;
                case '-':
                    num=14;printf("[%c,%d]
    ",ch,num);break;
                case '*':
                    num=15;printf("[%c,%d]
    ",ch,num);break;
                case '/':
                    num=16;printf("[%c,%d]
    ",ch,num);break;
                case ':':
                    ch=temp[i++];
                    if(ch=='=') {
                        num=18;
                        printf("[:%c,%d]
    ",ch,num);
                    } else {
                        i--;
                        ch=temp[i];
                        num=17;
                        printf("[%c,%d]
    ",ch,num);
                    }
                    break;
                    
                case '<':
                    ch=temp[i++];
                    if(ch=='=') {
                        num=21;
                        printf("[<%c,%d]
    ",ch,num);
                    } else if(ch='>') {
                        num=22;
                        printf("[<%c,%d]
    ",ch,num);
                    } else {
                        i--;
                        ch=temp[i];
                        num=20;
                        printf("[%c,%d]
    ",ch,num);
                    }
                    break;
    
                case '>':
                    ch=temp[i++];
                    if(ch=='=') {
                        num=24;
                        printf("[>%c,%d]
    ",ch,num);
                    } else {
                        i--;
                        ch=temp[i];
                        num=23;
                        printf("[%c,%d]
    ",ch,num);
                    }
                    break;
                case '=':
                    num=25;printf("[%c,%d]
    ",ch,num);break;
                case ';':
                    num=26;printf("[%c,%d]
    ",ch,num);break;
                case '(':
                    num=27;printf("[%c,%d]
    ",ch,num);break;
                case ')':
                    num=28;printf("[%c,%d]
    ",ch,num);break;
            }
        }
    }
    
    //对语法进行预处理,当匹配到分号时,进行一次match匹配下一个字符 
    void Pre() {   
        statement();
        while(num==26) {
            match();
            statement();
        }
        return;
    }
    
    //匹配begin、end 
    void Bparser() {   
        if(num==1) { //begin
            match();
            Pre();
            if(num==6){ //end
                match();
                if(num==0 && k==0){
                    printf("【Success】分析完成!
    "); 
                }
            }else if(num==0 && ednum!=1){
                printf("【error】缺失'end'
    ");
                k=1; 
            }
        }else{
            Pre(); 
            printf("【error】缺失'begin'
    ");
        }
        return;
    }
    
    //匹配语法声明
    void statement() {  
        if (num==10) {   
            match();
            if(num==18) { //为 :=
                match();
                expression();
            } else {
                printf("【error】缺失符号':='
    ");
                k=1;
            }
        }else{
            printf("【error】'表达式错误'
    ");
            k=1;
        }
        return;
    }
    
    //匹配+-运算符 
    void expression() {  
        term();
        while(num==13||num==14) {
            match();
            term();
        }
        return;
    }
    
    //匹配*/运算符 
    void term() {   
        factor();
        while(num==15||num==16) {
            match();
            factor();
        }
        return;
    }
    
    //为标识符或整常数时,读下一个单词符号
    void factor() {  
        if(num==10||num==11) {
            match();
        } else if(num==27) {
            match();
            expression();
            if(num==28) {
                match();
            } else {
                printf(" 【error】缺失')' 
    ");
                k=1;
            }
        } else {
            printf("【error】'表达式错误'
    ");
            k=1;
        }
        return;
    }
    
    int main() {
        printf("	
    请输入程序,以#号结束:
    ");
        ch=getchar();
        while(ch!='#') {
            temp[i]=ch;
            ch=getchar();
            i++;
        }
        temp[i]='#';
        i++;
        temp[i]='';
        i=0;
        match();
        Bparser();
    }

    执行程序会输出如下结果:

  • 相关阅读:
    android逆向奇技淫巧五:x音fiddler抓包分析协议字段
    windows:3环自行加载PE文件实现进程隐藏
    android逆向奇技淫巧四:模拟器检测和反检测
    android逆向奇技淫巧三:MT管理器替代android killer修改和重新编译smail代码/frida hook 更改so层代码
    windows运算符和数据类型重载反CE查询搜索
    android逆向奇技淫巧二:uiautomatorviewer&method profiling定位x音java层的关键代码和方法
    android逆向奇技淫巧一:去掉开屏广告
    xx课堂m3u8加密视频下载
    Python接口自动化之logging日志
    Python接口自动化之pymysql数据库操作
  • 原文地址:https://www.cnblogs.com/zhif97/p/11940312.html
Copyright © 2020-2023  润新知