熟悉Parse Generator

/*Powered by Keamou@CS@CITS@NKU */

1.         将所有的词法分析功能均放在yygettoken函数内实现,为+-*/()每个运算符及整数分别定义一个单词类别,在yygettoken内实现代码,能识别这些单词,并将单词类别返回给词法分析程序。

答:

定义单词类别定义如下:

 

记号

类别名

+

ADD

-

SUB

*

MUL

/

DIV

(

LE

)

RE

数字

NUMBER

字母

LETTER

文件尾

FEND

 

Yacc程序获得输入的字符是通过int yygettoken(void) 函数获得的,因此可以在int yygettoken(void)函数里先分析输入字符,根据上表返回相应的类别名。

符号定义段里:

%token NUMBER    

%token ADD

%token SUB

%token MUL

%token DIV

%token LETTER

%token LE      //左括号

%token RE      //右括号

%token FEND    //文件尾标志

 

%left ADD SUB

%left MUL DIV

%right UMINUS

因此,例如,中缀变后缀的语法定义段程序为:

lines     :      lines expr     FEND { fprintf(fc, "Here is the postfix expr : %s/n", $2); printf("/nHere is the postfix expr : %s/n", $2);  exit(1); }

             |     lines FEND       { exit(1); }

             |

             ;

 

expr      :      expr ADD expr    { strcpy($$, $1); strcat($$, $3); strcat($$,"+"); }

             |     expr SUB expr     { strcpy($$, $1); strcat($$, $3); strcat($$,"-"); }

             |     expr MUL expr    { strcpy($$, $1); strcat($$, $3); strcat($$,"*"); }

             |     expr DIV expr      { strcpy($$, $1); strcat($$, $3); strcat($$,"/"); }

             |     LE expr RE   { strcpy($$, $2); }

             |     SUB expr %prec UMINUS       { strcpy($$, $2); strcat($$,"-"); }

             |   alpha           { strrev( $$ );   }    //符号逆转

             |     digit           { strrev( $$ );   }    //符号逆转

             ;

 

alpha:       LETTER             { sprintf($$,"%c",pchar); }

        |    alpha  LETTER      { sprintf($$,"%s%c",$1,pchar); }

        ;

 

digit   :   NUMBER             { itoa( num - '0' ,$$ ,10 ); }

        |   digit NUMBER       { itoa( num - '0' ,$$ ,10 ); strcat($$ , $1); }

        ;

int yygettoken(void) 里识别词素并返回词素类别,代码如下:

int yygettoken(void)

{

      // place your token retrieving code here

      int token;

      token = fgetc(fp);

      while ( token == ' ' || token == '/n' || token == '/t' )  //如果是空格、回车、制表符,则再读取文件的下一个字符

      {

           token = fgetc(fp);

      }

      if(feof(fp))          //如果到了文件尾,则返回符号FEND

      {

          return FEND ;

      }

      printf("%c",token);   //在屏幕上输出从文件读出的非空白符的字符

      switch(token)

      {

         case '+':

              return ADD;

              break;

         case '-':

              return SUB;

              break;

         case '*':

              return MUL;

              break;

         case '/':

              return DIV;

              break;

         case '(':

              return LE;

              break;

         case ')':

              return RE;

              break;

         case '0':

         case '1':

         case '2':

         case '3':

         case '4':

         case '5':

         case '6':

         case '7':

         case '8':

         case '9':

              num = token ;

              return NUMBER;

              break;

         default:

              if( ( token >= 'a' && token <= 'z' ) || ( token >= 'A' && token <= 'Z' ) )

              {

                  pchar = token ;

                  return LETTER;

              }

              else

                  return token;

      }

}

2.         实现功能更强的词法分析程序,可识别并忽略空格、制表符、回车等空白符,能识别多位十进制整数。

答:

修改int yygettoken(void)函数以支持忽略空格、制表符、回车:

int yygettoken(void)

{

       int token;

       token = getchar();

       while(token == ' ' || token == '/n' || token == '/t' )

          token = getchar();

       return token;

}

在语法规则段里添加如下代码可实现多位十进制整数的算术运算

DIGIT   :   NUMBER            { $$ = $1; }

        |   NUMBER DIGIT      { $$ = $1 * 10 + $2;}

        ;

若添加如下代码则可实现多位十进制整数的字符串表示:

digit   :    NUMBER            { strcpy($$, $1); }

        |   NUMBER digit       { strcpy($$, $1); strcat($$, $2);}

        |

        ;

 

3.         修改Yacc程序,不进行表达式的计算,而是实现中缀表达式到后缀表达式的转换。

答:

由于老师已经把实现中缀表达式到后缀表达式的转换的Yacc程序上传了,为了使本题更有趣,我将上面两所实现功能都在本题里体现

除此之外,为了体验在Yacc里的文件操作以及输入的方便,我还实现了文件读写的功能。用fp指针打开输入文件,读取expr.txt文件(此文件储存要转换的中缀表达式),用fc打开输出文件,结果把转换后的后缀表达式储存在postfix.txt文件中。只所以不采用main(argc,argv[])的方法是因为这样比较方便,不用多次输入文件名。

同时,也将输入和输出的内容在屏幕上显示,以随时便捷地验证结果的正确。

 

(思考)实现符号表功能。

答:

通过定义结构将遇到的符号和其值添加到符号表中

struct tokenlist        //符号表结构

{

    char token[30];

    float value;

    struct tokenlist * next ;

}*head,*temp;

当遇到一个符号时,先判断是否已经在符号表里,在将其值添加或修改。如果是数字,则直接存储其值,如果是字母,若尚无存储,则初值为0。代码如下:

void storetoken(char* tn, float tv )

{

    temp = head ;

    while (temp != NULL )    //首先判断一下要存储的符号是否已经在符号表里

    {

        if( strcmp ( temp->token , tn ) == 0 )

        {

           temp->value = tv ;

           return;

        }

        temp = temp->next ;

    }

    temp = head ;

    head = (struct tokenlist*)malloc(sizeof (struct tokenlist));

    strcpy(head->token , tn) ;

    head->value = tv ;

    head->next = temp;

}   

为了从符号表里取出符号的值,编写了如下代码:

float findtoken(char* tn)

{

    temp = head ;

    while (temp != NULL )

    {

        if( strcmp ( temp->token , tn ) == 0 )

           return temp->value ;

        temp = temp->next ;

    }

    return 0 ;

}

为了能显示符号表的内容,编写了如下代码:

void displaylist()

{

    temp = head ;

    printf("---------The Token List-----------/n");

    while ( temp != NULL )

    {

      printf("%s/t%lf/n",temp->token,temp->value);

      temp = temp->next ;

    }

    printf("--------------End-----------------/n");

}

在编译的过程中,实现无用的符号从符号表里删除

void deletetoken(char* tn)

{

    temp = head ;

    if( temp != NULL )

       if ( strcmp ( temp->token , tn ) == 0 )

       {

           head = temp->next ;

           free( temp ) ;

           return;

       }

    while ( temp->next != NULL )

    {

         if ( strcmp ( temp->next->token , tn ) == 0 )

         {

              struct tokenlist * othertmp = temp->next ;

              temp->next = temp->next->next ;

              free( othertmp ) ;

              return;

         }

         temp = temp->next ;

    }

    return;

}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值