zoukankan      html  css  js  c++  java
  • 实验二 递归下降语法分析

    实验二 递归下降语法分析

    一、实验目的:

    利用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;
    }

    六、运行结果与分析

     

  • 相关阅读:
    [算法] 堆栈
    [刷题] PTA 02-线性结构3 Reversing Linked List
    java IO流 (八) RandomAccessFile的使用
    java IO流 (七) 对象流的使用
    java IO流 (六) 其它的流的使用
    java IO流 (五) 转换流的使用 以及编码集
    java IO流 (四) 缓冲流的使用
    java IO流 (三) 节点流(或文件流)
    java IO流 (二) IO流概述
    java IO流 (一) File类的使用
  • 原文地址:https://www.cnblogs.com/cyxxixi/p/11954689.html
Copyright © 2011-2022 走看看