递归下降法的语法分析器-3.1-编译原理

递归下降法的语法分析器

 

一、实验目的

掌握语法分析器的构造原理,掌握递归下降法的编程方法。

二、实验内容

递归下降法编写一个语法分析程序,使之与词法分析器结合,能够根据语言的上下文无关文法,识别输入的单词序列是否文法的句子。(注意,需要改写文法,消除左递归等)

为减轻实验编程负担,这里只要求实现部分产生式,文法的开始符号为program(完整的源语言的文法定义见教材附录 A.1p394

program      → block

block     →   { stmts }

stmts     → stmt stmts | e

       stmt       →   id= expr ;

                        |      if ( bool ) stmt

                            |      if ( bool) stmt else stmt

|      while (bool) stmt

|      do stmt while (bool ) ;

|      break ;

|      block

bool      expr < expr

|     expr <= expr

|     expr > expr

|     expr >= expr

|     expr

expr      → expr + term

|     expr - term

|     term

term      → term * factor

 |   term / factor

|     factor

factor     → ( expr ) | id| num 

 

 

三、实验要求

1.个人完成,提交实验报告。

2.实验报告中给出采用测试源代码片断,及其对应的最左推导过程(形式可以自行考虑)。

例如,程序片断

{

       i = 2;

       while (i <=100)

       {

              sum = sum + i;

              i = i + 2;

       }

}

    对应的推导过程为:

program      Þ block

Þ { stmts }

Þ { stmtstmts }

Þ { id= expr ; stmts }

Þ { id= num; stmts }

Þ { id= num; stmt stmts }

Þ { id= num; while (bool) stmt stmts }

Þ { id= num; while (expr<= expr) stmt stmts }

Þ { id= num; while (id<= expr) stmt stmts }

Þ { id= num; while (id<= num) stmt stmts }

Þ { id= num; while (id<= num) block stmts }

Þ { id= num; while (id<= num) { stmts }stmts }

Þ  .......

四、实验指导

  1. 1.  词法分析器的说明

可以使用“实验2 用FLEX实现词法分析器”的生成的代码,也可以使用自己编写的词法分析器,来获取词法单元(token)。如果使用FLEX的话,每次调用一次yylex()函数就可以获取一个词法单元。

 

  1. 2.  左递归和公共左因子的处理

上述文法存在左递归和公共左因子,需要考虑改造文法。消除直接左递归参见教材p123。提取公共左因子参见教材p125。

 

  1. 3.  预测分析器

假设已经将上述文法改造为LL(1)文法,可采用带预测的递归下降进行语法分析。预测分析器的伪代码可参见教材p40。

 

  1. 4.  if语句二义性的处理

上述文法中的if语句具有二义性。可以有不同的处理方式:

(1)       第一种方法是改写文法。

stmt ® matched _stmt | unmatched_stmt

matched_stmt ® if ( bool ) matched_stmt else matched_stmt | 其它语句

unmatched_stmt ® if ( bool ) stmt  |  if ( bool ) matched_stmt  else unmatched_stmt

    这种方法要多引进两个非终结符matched_stmtunmatched_stmt,就要多编写两个函数,但编写这两个函数不会花太多时间。

(2)       第二种方法是对产生式加限制。

为了适合LL(1)文法的需要,我们首先对stmt → if ( bool ) stmt | if ( bool ) stmt else stmt提取左公因子,结果如下:

stmtif ( bool ) stmt else_part  | 其它语句

else_partelse stmt | e

但是,这样还是不能消除二义性,还是不能确定该选择else_partelse stmt | e中的哪个产生式,因为First(else stmt ) ÇFollow(else_part)= { else }。我们通过加限制的方法来确定该选哪个产生式:如果lookahead是词法单元else时,使用产生式else_part → else stmt;否则使用产生式else_parte

实际上,因为产生式stmt → if ( bool ) stmt | if ( bool ) stmt else stmt比较特殊(一个产生式的右部是另一个产生式的右部的前缀),所以无需提取左公因子。具体处理如下:当匹配完 if ( bool ) stmt 后,继续读入一个词法单元(token),此时:(a)如果该词法单元是ELSE_TOKEN,那么就继续匹配,也就是说,此时使用产生式stmt ® if ( bool ) stmt else stmt。(b)如果该词法单元不是ELSE_TOKEN,那么就将该词法单元回退(retract)给词法分析器,也就是说,此时使用产生式stmt ® if ( bool ) stmt。

在这种处理下,能满足C语言的“else和最靠近的if结合”的规定,即该方法的效果和上一种方法的效果是一样的。

可见,在二义性文法的基础上加以某些限制(例如“如果有else,则继续匹配”),就可以去除一些我们不希望的语法树,从而只获得一棵语法树,这样就变成了无二义性的文法(对任一个合法的词法单元序列,只有一棵对应的语法树)。

View Code
#include<stdio.h>

#include"yytex.h"

void yytex();

void BeginCompileOneFile( const char * filename );

void EndCompileOneFile(void);

int yylex(void);

void Expr();

int token;

int Lookahead;

extern char *yytext;

//yytext 也就是现在获得的字符。

void program();

void parse()

{//要先lookahean

//     int token;

//     char filename[1000];

       printf("请输入要编译的源程序文件名:");

              //gets(filename);

       //     BeginCompileOneFile( filename );

              //当flex扫描到文件末尾,yylex函数返回0

              //    while( ( token = yylex() ) > 0 ) ;

                     BeginCompileOneFile("a.txt");

              Lookahead=yylex();

                            printf("program=");

              program();//函数调用

              printf("\ngrogram end\n");

       EndCompileOneFile();

       //getchar();

}

 

void match(int t)

{//用来匹配字符 用已经定义的字符比如define if 500 如果match(if) 于是就是词法分析器获得了if 字符串。

       //yylex为返回if字符串对应的500 是要return给yylex函数的。          yytext为if保存字符串的字符数组 yyval 是具体的符号, yylex是类符号

       //match return后面的符号。

       if(Lookahead==t)

       {     Lookahead=yylex();

//     printf("   %d       ",Lookahead);

       }

       else printf("\nmatch() syntax error Lookahead:%d \n",Lookahead);

}

void block();

void program()

{

       printf("\n program->block");

       block();

}

void stmts();

void block()

{

       printf("\nblock->{ ");    printf("stmts ");     printf(" }\n");

match(LEFT_BIBRACKET);

stmts();  

match(RIGHT_BIBRACKET);

return;

}

void stmt();

void stmts()

{

if(Lookahead==ID_TKN||Lookahead==IF_TKN||Lookahead==WHILE_TKN||Lookahead==DO_TKN||Lookahead==BREAK_TKN||Lookahead==LEFT_BIBRACKET)//first follow

       {

                            printf(" stmts->stmt ");  printf("stmts");

              stmt();           

              stmts();

       }

       else if(Lookahead==RIGHT_BIBRACKET) return;

       else printf(" stmts() error lookahead:%d\n",Lookahead);     return;

 

}

void bool_();

void stmt()

{

 

       switch(Lookahead)

       {

       case ID_TKN:

       printf("\nstmt->ID=expr;\n");       match(ID_TKN);match(RELOP_TKN);Expr();match(RELOP_TKN);break;

       case IF_TKN:

       printf("\nstmt->IF(bool) stmt \n");       match(IF_TKN);match(LEFT_BRACKET);bool_();match(RIGHT_BRACKET);stmt();break;

       case WHILE_TKN:

       printf("\nstmt->WHILE (bool) stmt \n");       match(WHILE_TKN);match(LEFT_BRACKET);bool_();match(RIGHT_BRACKET);stmt();break;

       case DO_TKN:

              {

                     printf("\nstmt->DO stmt while(bool)\n");

                     stmt();

                     match(WHILE_TKN);

                     match(LEFT_BRACKET);

                     bool_();

                     match(RIGHT_BRACKET);

                     match(RELOP_SENI);

                     break;

              }

       case BREAK_TKN:

       printf("\nstmt->BREAK ;\n");      match(BREAK_TKN),match(RELOP_TKN);break;

       default:

              printf("stmt->block");

              block();

       }

}

 

void bool_()

{

Expr();

switch(Lookahead){

case RELOP_TKN:

       printf("bool_->RELOP_TKN ");

       match(RELOP_TKN);Expr();break;

default: break;

/*

switch(Lookahead){

case RELOP_LT:

       printf("\nbool_->LT ");

       match(RELOP_LT);Expr();break;

case RELOP_LE:

       printf("\nbool_->LE ");

       match(RELOP_LE);Expr();break;

case RELOP_GT:

       printf("\nbool_->GT ");

       match(RELOP_GT);Expr();break;

case RELOP_GE:

       printf("\nbool_->GE ");

       match(RELOP_GE);Expr();break;

default:

       match(520);

              match(510);*/

 

}

}

 

 

/*void Expr()

{

       Expr();

switch(Lookahead){

       case RELOP_AD:

              ;

       case RELOP_AD:

 

}*/

void Factor()

{

       /*switch( Lookahead ) {

              case '(':

              match('(');

              Expr();

              match(')');break;

              default:  

              match(Lookahead);break;

}*/

 

if(Lookahead=='(')

       {

              match('(');

              Expr();

              match(')');

       }

        if(Lookahead==ID_TKN)   //其中id_tkn与num_tkn为looahead的值 如何取得具体的值num值呢

       {

              //     printf("id ");

       // printf("%s\n",yytext);

              match(Lookahead);

       }

     if(Lookahead==NUM_TKN)

       {

              //printf("num ");

        //printf("%s\n",yytext);

              match(Lookahead);

       }

       //     match(Lookahead);

}

 

void Morefactors();

void Term()

{

       Factor();

       Morefactors();

}

 

void Morefactors()

{

    switch( Lookahead ) {

           case '*':

                     match('*'); Factor(); putchar('*'); Morefactors(); // rest --> + term {print('+')} rest

                     break;

              case '/':

                     match('/'); Term(); putchar('/'); Morefactors(); // rest --> - term {print('-')} rest

                     break;

              default:   // rest --> 空

                     break;

       }

}

 

void Moreterms()

{

       switch( Lookahead ) {

           case '+':

                     match('+'); Term(); putchar('+'); Moreterms(); // rest --> + term {print('+')} rest

                     break;

              case '-':

                     match('-'); Term(); putchar('-'); Moreterms(); // rest --> - term {print('-')} rest

                     break;

              default:   // rest --> 空

                     break;

       }

}

 

void Expr()

{

    Term();

       Moreterms();

}


 

posted @ 2012-12-16 17:30  xjx_user  阅读(2119)  评论(0编辑  收藏  举报