递归下降法的语法分析器-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();

}


 

转载于:https://www.cnblogs.com/xjx-user/archive/2012/12/16/2820667.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下降分析 一、实验目的: 根据某一文编制调试下降分析程序,以便对任意输入的符号串进行分析。本次实验的目的主要是加深对下降分析的理解。 二、实验说明 1、下降分析的功能 词分析器的功能是利用函数之间的归调用模拟语法树自上而下的构造过程。 2、下降分析的前提 改造文:消除二义性、消除左归、提取左因子,判断是否为LL(1)文, 3、下降分析实验设计思想及算 为G的每个非终结符号U构造一个归过程,不妨命名为U。 U的产生式的右边指出这个过程的代码结构: (1)若是终结符号,则和向前看符号对照, 若匹配则向前进一个符号;否则出错。 (2)若是非终结符号,则调用与此非终结符对应的过程。当A的右部有多个产生式时,可用选择结构实现。 三、实验要求 (一)准备: 1.阅读课本有关章节, 2.考虑好设计方案; 3.设计出模块结构、测试数据,初步编制好程序。 (二)上课上机: 将源代码拷贝到机上调试,发现错误,再修改完善。第二次上机调试通过。 (三)程序要求: 程序输入/输出示例: 对下列文,用下降分析对任意输入的符号串进行分析: (1)E->eBaA (2)A->a|bAcB (3)B->dEd|aC (4)C->e|dc 输出的格式如下: (1)下降分析程序,编制人:姓名,学号,班级 (2)输入一以#结束的符号串:在此位置输入符号串例如:eadeaa# (3)输出结果:eadeaa#为合符号串 注意: 1.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好); 2.对学有余力的同学,可以详细的输出推导的过程,即详细列出每一步使用的产生式。 (四)程序思路 0.定义部分:定义常量、变量、数据结构。 1.初始化:从文件将输入符号串输入到字符缓冲区中。 2.利用下降分析分析,对每个非终结符编写函数,在主函数中调用文开始符号的函数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值