• 实验二 递归下降语法分析


    实验二 递归下降语法分析

    一、实验目的:

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

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

    二、实验原理

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

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

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

    三、实验要求说明

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

    例如:

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

    输出success

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

    输出‘end' error

    四、实验步骤

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

    令语句为A,条件为B,表达式为C,项为D,因子为E

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

    语句

    A-><id>:=<C>|if B then A|while B do A|begin A; end|ε

    条件

    B->C=C|C<C|C<=C|C>=C|C>C

    B->oddC

    表达式

    C->+D|-D|D+D|D-D

    D->E|E*E|E/E

    因子

    E-><id>

    E-><integer>

    E->’(’C’)’

    3. 消除其左递归

    4. 提取公共左因子

    5. SELECT集计算

     FIRST

     FOLLOW

     SELECT

    FIRST(A-><id>:=<C>)={<id>}

    FIRST(A->if B then A)={if}

    FIRST(A->while B do A)={while}

    FIRST(A->begin A; end)={begin}

    FIRST(A->ε)={ε}

    FIRST(B->C=C|C<C|C<=C|C>=C|C>C)={=,<<=,>,>=}

    FIRST(B->oddC)={odd}

    FIRST(C->+D|-D|D+D|D-D)={+/-}

    FIRST(D->E|E*E|E/E)={*,/}

    FIRST(E-><id>)=<id>

    FIRST(E-><integer>)=<integer>

    FIRST(E->’(’C’)’)=<’C’>

     

    FOLLOW(A)={end,#}

    FOLLOW(B)={then,do}

    FOLLOW(C)={=,<<=,>,>=,)}

    FOLLOW(D)={+,-}

    FOLLOW(E)={*,/}

     

    SELECT(A-><id>:=<C>)={<id>}

    SELECT(A->if B then A)={if}

    SELECT(A->while B do A)={while}

    SELECT(A->begin A; end)={begin}

    SELECT(A->ε)={end,#}

    SELECT(B->C=C|C<C|C<=C|C>=C|C>C)={=,<<=,>,>=}

    SELECT(B->oddC)={odd}

    SELECT(C->+D|-D|D+D|D-D)={+/-}

    SELECT(D->E|E*E|E/E)={*,/}

    SELECT(E-><id>)=<id>

    SELECT(E-><integer>)=<integer>

    SELECT(E->’(’C’)’)=<’C’>

     

     

    6. LL(1)文法判断

    其文法SELECT集没有交集,所以为LL(1)文法。

    7. 递归下降分析程序

    实验源程序

     

    #include<string.h>
    #include<stdio.h>
    #include<stdlib.h>
    void lrparser();
    void yucu();
    void scaner(); //词法分析
    void statement();//语句
    void condition();//条件
    void expression();//表达式
    void term();//
    void factor();//因子
    int kk=0;
    char prog[100],token[10];//输入程序段数组,大小为80
    int syn,i=0,ks=0,js=0,m,n,sum=0,k=0;
    char ch;
    const char *blz[7]= {"begin","if","then","while","do","end","odd"};//保留字
    
    int main() {
    //    for(n=0;n<7;n++){
    //        printf("%s",blz[n]); 
    //    }
        printf("********************语法分析程序***************
    ");
        printf("请输入源程序,以#结束:
    ");
        ch=getchar();
        while(ch!='#') {
            prog[i]=ch;
            ch=getchar();
            i++;
        }
        prog[i]='#';
        i++;
        prog[i]='';
        i=0;
        scaner();
        lrparser();
        printf("语法分析结束!
    ");
    
    }
    
    void scaner() {
        printf("%c",ch);
        ch=prog[i++];
        while(ch == ' ' || ch == 10 || ch == 9||ch== 13) {//忽略空格换行回车和tab
            ch=prog[i++];
        }
    
        if((ch>='a' && ch<='z') ||(ch>='A' && ch<='Z')) {//判断是保留字还是标识符
            n=0;
            syn=10;//字母数字码为10
            char a=ch;
            while((ch>='a' && ch<='z') ||(ch>='A' && ch<='Z')||(ch>='0' && ch<='9')) {
                token[n++]=ch;
                ch=prog[i++];
            }
            token[n++]='';
            for(n=0; n<7; n++) {
                if(strcmp(token,blz[n])==0) {
                    syn=n+1;//给保留字赋值,begin为1,if为2,then为3,while为4,do为5,end为6,odd为7
                    printf("<%s,%d>
    ",token,syn);
                    if(syn==1) {
                        ks=1;
                    }
                    if(syn==6) {
                        js=6;
                    }
                    break;
                }
            }
            i--;
            if(syn==10) {
                ch=a;
                printf("<%c,%d>
    ",ch,syn);
            }
    
        } else if(ch>='0' && ch<='9') {//数字判断
            syn=11;
            printf("<%c,%d>
    ",ch,syn);
        } else {
            switch(ch) {//运算符,界符判断
                case '<':
                    ch=prog[i++];
                    if(ch=='>') {
                        syn=21;//当为<>时,数字码为21
                        printf("<%c,%d>
    ",ch,syn);
                    } else if(ch=='=') {
                        syn=22;//当为<=时,数字码为22
                        printf("<%c,%d>
    ",ch,syn);
                    } else {
                        i=i-1;
                        ch=token[i];
                        syn=20;//当为<时,数字码为20
                        printf("<%c,%d>
    ",ch,syn);
                    }
                    break;
                case '>':
                    ch=prog[i++];
                    if(ch=='=') {
                        syn=24;//当为>=时,数字码为24
                        printf("<%c,%d>
    ",ch,syn);
                    } else {
                        i=i-1;
                        ch=prog[i];
                        syn=23;//当为>时,数字码为23
                        printf("<%c,%d>
    ",ch,syn);
                    }
                    break;
                case ':':
                    ch=prog[i++];
                    if(ch=='=') {
                        syn=18;//当为:=时,数字码为18
                        printf("<%c,%d>
    ",ch,syn);
                    } else {
                        syn=17;//当为:时,数字码为17
                        i=i-1;
                        ch=prog[i];
                        printf("<%c,%d>
    ",ch,syn);
                    }
                    break;
                case '+':
                    syn=13;//当为+时,数字码为13
                    printf("<%c,%d>
    ",ch,syn);
                    break;
                case '-'://当为-时,数字码为14
                    syn=14;
                    printf("<%c,%d>
    ",ch,syn);
                    break;
                case '*':
                    syn=15;//当为*时,数字码为15
                    printf("<%c,%d>
    ",ch,syn);
                    break;
                case '/':
                    syn=16;//当为<>时,数字码为21
                    printf("<%c,%d>
    ",ch,syn);
                    break;
                case ';':
                    syn=26;//当为;时,数字码为26
                    printf("<%c,%d>
    ",ch,syn);
                    break;
                case '(':
                    syn=27;//当为(时,数字码为27
                    printf("<%c,%d>
    ",ch,syn);
                    break;
                case ')'://当为)时,数字码为28
                    syn=28;
                    printf("<%c,%d>
    ",ch,syn);
                    break;
                case '='://当为=时,数字码为25
                    syn=25;
                    break;
                case '#'://当为#时,数字码为0
                    syn=0;
                    printf("<%c,%d>
    ",ch,syn);
                    break;
                default:
                    syn=-1;
            }
        }
    }
    void lrparser() {
        if(ks==1) {
            scaner();
            yucu();
        } else {
            yucu();
            printf("语法错误缺失'begin'
    ");
        }
        return;
    }
    
    void yucu() {
        statement();
        while(syn==26) {
            scaner();
            statement();
        }
        return;
    }
    
    void statement() {
        if (syn==10) { //为标识符
            scaner();
            if (syn==18||syn==25) { //为 :=
                scaner();
                expression();
            } else {
                printf("error!
    ");
            }
        } else {
            if(syn==0&&ks==1&&js==6)
                printf("Success!语法无错误!分析完成
    ");  //当匹配到#且begin、end存在时,输出语法无错误
            else if(syn==0&&js!=1) {
                printf("语法错误,缺失'end'
    ");
            }
        }
        return;
    }
    void condition(){
        expression();
        if(syn==25||syn==20||syn==22||syn==23||syn==24)
        expression();
        while(syn==7){
            expression();
        }
        return;
    }
    
    void expression() {
        if(syn==13 || syn==14) {//为+或-时
            scaner();
            term();//处理项
        } else {
            term();
        }
        while(syn==13||syn==14) { //处理{(+|-)<项>}
            scaner();
            term();
        }
        return;
    }
    
    
    void term() {
        factor();
        while(syn==15 || syn==16) {//处理*|/时
            scaner();
            factor();
        }
        return;
    }
    void factor() {
        if(syn==10)
            scaner();
        else if(syn==11)
            scaner();
        else if(syn==27) {//左括号
            expression();
            if(syn==28)
                scaner();
            else {
                printf(" ')' 错误
    ");
                kk=1;
            }
        }
        return;
    }

    六、运行结果与分析

     

  • 相关阅读:
    一道编程题: 在1~n之间选择若干个数,使其和为m
    关于raft算法
    程序员算法基础——动态规划
    c++中两个类互相引用的问题
    c++ 之模板进阶
    jmeter分布式操作-远程启动功能探索
    linux下安装不同版本的jdk
    Jmeter插件监控服务器性能
    测试开发面试-技术持续累积
    python:Jpype安装和使用
  • 原文地址:https://www.cnblogs.com/cyxxixi/p/11954689.html
Copyright © 2020-2023  润新知