编译原理语法分析器实验报告

编号:

实习 总评 教师签名
成绩

 

第一部分 语言语法规则

Mini语言包含程序设计所需要的最基本语言成分,包括

  • 程序定义语句 :以 program 开头 end 结尾,中间需要有 main()函数

  • 赋值语句 :var 标识符 = 表达式;

  • 算数表达式:包含 + - * / ()运算

  • 逻辑表达式:包含 II && ! ()运算

  • if-else 语句:if (逻辑表达式或变量)begin 程序体 end else begin 程序体 end

  • while 循环语句:while(逻辑表达式或变量)begin 循环体 end

  • break 语句:break;

第二部分 文法定义

简化后的单词编码表为

单词符号 编码 单词符号 编码
main 1 + 15
if 2 - 16
else 3 * 17
while 4 / 18
program 5 = 19
begin 6 && 20
end 7 || 21
var 8 ! 22
break 9 == 23
true 10 整数常量表 24
false 11 浮点数常量表 25
( 12 标识符表 26
) 13
; 14

先有词法分析器将程序扫描一遍,得到Token串,例如main转为<1,->,if转为<2,->...!转为<22,->,特别的标识符,整数常量,浮点数常量有两个表分别转换为<23,i>.<24,i>,<25,i>.

但是在语法分析的文法中,为了方便理解,这里依然用main等字符串,而不是使用<1,->进行分析,其中标识符用id表示,整数常量用wholenum表示,浮点数用floatnum表示。

得到如下的上下文无关文法G(S),(小写表示终结符号,大写表示非终结符号)


  • S ->PROGRAM //PROGRAM为整个语法程序

  • PROGRAM -> program PROBODY end

    //PROBODY为程序体

  • PROBODY -> main begin PROSTATEMENT end

    //PROSTATEMENT为程序语句

  • PROSTATEMENT -> ASSIGNMENT PROSTATEMENT | CONDITION PROSTATEMENT | LOOP PROSTATEMENT | BREAK PROSTATEMENT | ε //ASSIGNMENT为赋值语句 COUNT 为算数表达式 LOGIC 为逻辑表达式 CONDITION 为if else 分支语句 LOOP 为while循环语句 BREAK 为break语句,用于跳出循环//

  • ASSIGNMENT -> var id = VALUE ;

    //VAlUE 为赋值语句可以赋的值,id为变量,属于词法分析器中单词编码表中的标识符

  • VALUE -> id | COUNT | LOGIC

  • COUNT -> TF F -> +T | -T | ε T -> GH H -> *G | /G | ε G -> (COUNT) | wholenum | floatunm | id

    //wholenum 为词法分析器中单词编码表中的整数,floatnum为词法分析器中词法编码表中的浮点数,整个算术运算符表达,每个算数单元可以是数字也可以是变量

  • LOGIC -> IJ J -> ||I | ==I | ε I -> KL L -> &&K |ε K -> !M | M M -> (LOGIC) | true | false | id

    //这里是逻辑表达式,每个逻辑单元可以是true false 也可以是变量

  • CONDITION -> if (LOGIC) begin PROSTATEMENT end ELSE

    //ELSE是else语句

  • ELSE -> begin PROSTATEMENT end | ε

    //if else语句中,先进行逻辑语句的判读,然后进入程序语句,else是可空的

  • LOOP -> while (LOGIC) begin PROSTATEMENT end

    //循环语句

  • BREAK -> break ;

    //break跳出语句


第三部分 语法分析算法

使用递归下降算法,结合词法分析器,用get_nexttoken();函数表示取到下一个token串,用w.nexttoken();表示w后面的token串,用Token数据结构表示token串,所有的终结符号都使用Token进行定义,由于这些字符原本就是c语言的关键字,所以为了区分,将所有Mini文法中的关键字在程序表达中都加上s,边界符使用S+所对应的数字表示,如‘(’用S12表示。

Token mains = new Token(1);
Token ifs = new Token(1);
Token elses = new Token(1);
Token whiles = new Token(1);
.
.
.
Token S12 = new Token(12);
Token S13 = new Token(13);
Token S14 = new Token(14);
Token S15 = new Token(15);
.
.
.
Token id = new Token(26);
Token wholenum = new Token(24);
Token floatnum = new Token(25);

get_nexttoken(w);从词法分析器中取下一个token串,存放在全局变量w中

每个非终结符号都是一个函数,如下所示

void PROGRAM (){
    if(w==programs) 
    {
        get_nexttoken(w);
        PROBODY();
        if(w==end){
            print("程序正确!");
        }
        else{
            error(0);
        }
    }
    else error(0);
}
void PROBODY (){
    if(w==mains){
        get_nexttoken(w);
        if(w==begins){
            get_nexttoken(w);
            PROSTATEMENT();
            if(w==ends){
                get_nexttoken(w);
            }
            else error(1);
        }
        else error(1);
    }
    else error(1);
}
void PROSTATEMENT (){
    if(w==vars) { 
        ASSIGNMEN();
        PROSTATEMENT ();
    }
    else if(w==ifs) {
        CONDITION();
        PROSTATEMENT ();
    }
    else if(w==whiles) {
        LOOP();
        PROSTATEMENT ();
    }
    else if(w==breaks) {
        BREAK();
        PROSTATEMENT ();
    }
    else if(w==ends);
    else error(2);
}
void ASSIGNMENT (){
    if(w==var){
        get_nexttoken(w);
        if(w==id){
            get_nexttoken(w);
            if(w==S19){
                get_nexttoken(w);
                VALUE();
                if(w==S14)
                get_nexttoken(w);
                else error(3);
            }
            else error(3);
        }
        else error(3);
    }
    else error(3);
}
void VALUE (){
    if(w==wholenum)  COUNT();
    else if(w==floatnum) COUNT();
    else if(w==trues) LOGIC();
    else if(w==falses) gLOGIC();
    else if(w==id&&w.nexttoken==S14) get_nexttoken(w);
    else if (!(w==id&&w.nexttoken==S14)||w==S12||w==id){
            if(w==S12&&w.nexttoken==id){
                if(w.nexttoken.nexttoken==(S15||S16||S17||S18){
                    COUNT();
                }
                else if(w.nexttoken.nexttoken==(S20||S21||S23){
                    LOGIC();
                }
                else error(4);
            }
             else if(w==S12&&(w.nexttoken==(wholenum||floatnum))){
                 COUNT();
             }
             else if (w==S12&&(w.nexttoken==(true||false))){
                 LOGIC();
             }
               else if(w==id&&(w.nexttoken==(S15||S16||S17||S18)){
                    COUNT();
                }
                else if(w==id&&(w.nexttoken==S20||S21||S23)){
                    LOGIC();
                }
                 else error(4);
                     
    }
       
         else error(4);
}
void COUNT(){
    T();
    F();
}
void F(){
    if(w==S15||w==S16){
        get_nexttoken(w);
        T();
    }
    
}
void T(){
    G();
    H();
}
void H(){
    if(w==S17||w==S18){
        get_nettoken(w);
        G();
    }
}
void G(){
    if(w==S12){
        get_nexttoken(w);
        COUNT();
        if(w==S13){
            get_nexttoken(w);
        }
        else error(5);
    }
    else if(w==(wholenum||floatnum||id)){
        get_nexttoken(w);
    }
    else error(5);
}
void LOGIC(){
    I();
    J();
}
void J(){
    if(w==(S21||23)){
        get_nexttoken(w);
        I();
    }
}
void I(){
    K();
    L();
}
void L(){
    if(w==S20)
    {
        get_nexttoken(w);
        K();
    }
}
void K(){
    if(w==!){
        get_nexttoken(w);
        M();
    }
    else{
        M();
    }
}
void M(){
    if(w==S11){
        get_nexttoken(w);
        LOGIC();
        if(w==S12){
            get_nexttoken(w);
        }
        else error(6);
    }
    else if(w==(trues||falses||id)){
        get_nexttoken(w);
    }
    else error(6);
}
void CONDITION(){
    if(w==ifs){
        get_nexttoken(w);
        if(w==S12){
            get_nexttoken(w);
            LOGIC();
            if(w==S13){
                get_nexttoken(w);
                if(w==begins){
                    get_nexttoken(w);
                    PROSTATEMNT();
                    if(w==ends){
                        get_nexttoken(w);
                        ELSE();
                    }
                    else error(7);
                }
                else error(7);
            }
            else error(7);
        }
        else error(7);
    }
    else error(7);
}
​
void ELSE(){
    if(w==begins){
        get_nexttoken(w);
        PROSTATEMENT();
        if(w==ends){
            get_nexttoken(w);
        }
        else{
            error(7);
        }
    }
}
void LOOP(){
    if(w==whiles&&(w.nexttoken==S12)){
        get_nexttoken(w);
        get_nexttoken(w);
        LOGIC();
        if(w==begins){
            get_nexttoken(w);
            PROSTATEMENT();
            if(w==ends){
                get_nexttoken(w);
            }
            else error(8);
        }
        else error(8);
    }
    else error(8);
}
void BREAK(){
    if(w==breaks&&(w.nexttoken==S14)){
        get_nexttoken(w);
        get_nexttoken(w);
    }
    else{
        error(9);
    }
}

第四部分 出错处理出口

程序出错时,其实w记录了出错所在的token串,只需用另一个变量记录token串所在整个程序的位置,在使用get_nettoken()取到下一个token串时,变量加一,就可以判断程序出错的位置。

错误函数 错误产生式 错误类型
error(0) PROGRAM -> program PROBODY end 程序定义错误
error(1) PROBODY -> main begin PROSTATEMENT end 程序体定义错误
error(2) PROSTATEMENT -> ASSIGNMENT | CONDITION | LOOP | BREAK | ε 语句定义不合法
error(3) ASSIGNMENT -> var id = VALUE ; 赋值语句格式错误
error(4) VALUE -> id | COUNT | LOGIC 赋值语句右值不正确
error(5) G -> (COUNT) | wholenum | floatunm | id 算数表达式格式错误
error(6) M -> (LOGIC) | true | false | id 逻辑表达式格式错误
error(7) CONDITION -> if (LOGIC) begin PROSTATEMENT end ELSE 条件语句错误
error(8) LOOP -> while (LOGIC) begin PROSTATEMENT end 循环语句错误
error(9) BREAK -> break ; 跳出语句错误

第五部分 测试计划

测试用例中所包括的语法单位应该尽可能覆盖Mini语言的文法中的所有非终结符包括程序定义变量声明if-else语句赋值语句条件语句循环语句跳出语句算数表达式逻辑表达式

测试用例如下

program 
    main begin 
    var logic=true;
    var i=0;
    while(i<10)
        begin
        if(logic&&(!(!true)))
            begin
            i=i+1;
            logic=!logic;
            end
        else
            begin
            logic=!logic;
            end
        end
    end
end

测试结果,无错误!

你可能感兴趣的:(编译原理,c++)