用Yacc实现语法分析器-4-编译原理

 Yacc实现语法分析器

 

一、实验目的

掌握语法分析器的构造原理,掌握Yacc的编程方法。

 

二、实验内容

Yacc编写一个语法分析程序,使之与词法分析器结合,能够根据语言的上下文无关文法,识别输入的单词序列是否文法的句子。

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 

 

 

三、实验步骤及结果

实验环境:unix

实验结果:按归约的先后顺序显示每次归约时所使用的产生式。

部分代码:

用于产生flex输入的代码

View Code
Test.l:[a-zA-Z_][a-zA-Z_0-9]* {return ID;}

[0-9]+\.[0-9]+ {return REAL;}

[0-9]+ {return NUM;}

"||" {return OR;}

"&&" {return AND;}

"|" {return '|';}

"&" {return '&';}

"<=" {return LE;}

"<" { return '<';}

">=" {return GE;}

">" {return '>';}

"!=" {return NE;}

"=" { return '=';}

"==" {return EQ;}

"\+"  {return '+';}

"\-" {return '-';}

"\*" {return '*';}

"\/" {return '/';}

"(" {return '(';}

")" {return ')';}

";" {return ';';}

"{" {return '{';}

"}" {return '}';}

"[" {return '['; }

"]" {return ']';}

Test.y:rel : expr '<' expr { printf("rel-->expr<expr\n"); }

    | expr LE expr { printf("rel-->expr<=expr\n"); }

       | expr GE expr { printf("rel-->expr>=expr\n"); }

       | expr '>' expr { printf("rel-->expr>expr\n"); }

       | expr { printf("rel-->expr\n"); }

       ;

expr : expr '+' term { printf("expr-->expr+term\n"); }

     | expr '-' term { printf("expr-->expr-term\n"); } 

        | term { printf("expr-->term\n"); }

        ;

term : term '*' unary { printf("term-->term*unary\n"); }

     | term '/' unary { printf("term-->term/unary\n"); }

        | unary { printf("term-->unary\n"); }

        ;

unary : '!' unary { printf("unary-->!unary\n"); }

      | '-' unary %prec UMINUS{ printf("unary-->-unary\n"); }

         | factor { printf("unary-->factor\n"); }

         ;

factor : '(' bool ')' { printf("factor-->(bool)\n"); }

       | loc { printf("factor-->loc\n"); }

          | NUM { printf("factor-->num\n"); }

          | REAL { printf("factor-->real\n"); }

          | TRUE { printf("factor-->true\n"); }

          | FALSE { printf("factor-->false\n"); }

Flex生成代码:

View Code
Test.l:[a-zA-Z_][a-zA-Z_0-9]* {return ID;}

[0-9]+\.[0-9]+ {return REAL;}

[0-9]+ {return NUM;}

"||" {return OR;}

"&&" {return AND;}

"|" {return '|';}

"&" {return '&';}

"<=" {return LE;}

"<" { return '<';}

">=" {return GE;}

">" {return '>';}

"!=" {return NE;}

"=" { return '=';}

"==" {return EQ;}

"\+"  {return '+';}

"\-" {return '-';}

"\*" {return '*';}

"\/" {return '/';}

"(" {return '(';}

")" {return ')';}

";" {return ';';}

"{" {return '{';}

"}" {return '}';}

"[" {return '['; }

"]" {return ']';}

Test.y:rel : expr '<' expr { printf("rel-->expr<expr\n"); }

    | expr LE expr { printf("rel-->expr<=expr\n"); }

       | expr GE expr { printf("rel-->expr>=expr\n"); }

       | expr '>' expr { printf("rel-->expr>expr\n"); }

       | expr { printf("rel-->expr\n"); }

       ;

expr : expr '+' term { printf("expr-->expr+term\n"); }

     | expr '-' term { printf("expr-->expr-term\n"); } 

        | term { printf("expr-->term\n"); }

        ;

term : term '*' unary { printf("term-->term*unary\n"); }

     | term '/' unary { printf("term-->term/unary\n"); }

        | unary { printf("term-->unary\n"); }

        ;

unary : '!' unary { printf("unary-->!unary\n"); }

      | '-' unary %prec UMINUS{ printf("unary-->-unary\n"); }

         | factor { printf("unary-->factor\n"); }

         ;

factor : '(' bool ')' { printf("factor-->(bool)\n"); }

       | loc { printf("factor-->loc\n"); }

          | NUM { printf("factor-->num\n"); }

          | REAL { printf("factor-->real\n"); }

          | TRUE { printf("factor-->true\n"); }

          | FALSE { printf("factor-->false\n"); }

Yacc生成部分代码:

View Code
#line 1334 "y.tab.c"

  yyvsp -= yylen;

  yyssp -= yylen;

  YY_STACK_PRINT (yyss, yyssp);

  *++yyvsp = yyval;

  /* Now `shift' the result of the reduction.  Determine what state

     that goes to, based on the state we popped back to and the rule

     number reduced by.  */

 

  yyn = yyr1[yyn];

 

  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;

  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)

    yystate = yytable[yystate];

  else

    yystate = yydefgoto[yyn - YYNTOKENS];

 

  goto yynewstate;

 

 

/*------------------------------------.

| yyerrlab -- here on detecting error |

`------------------------------------*/

yyerrlab:

  /* If not already recovering from an error, report this error.  */

  if (!yyerrstatus)

    {

      ++yynerrs;

#if YYERROR_VERBOSE

      yyn = yypact[yystate];

 

      if (YYPACT_NINF < yyn && yyn < YYLAST)

       {

         YYSIZE_T yysize = 0;

         int yytype = YYTRANSLATE (yychar);

         const char* yyprefix;

         char *yymsg;

         int yyx;

 

         /* Start YYX at -YYN if negative to avoid negative indexes in

            YYCHECK.  */

         int yyxbegin = yyn < 0 ? -yyn : 0;

 

         /* Stay within bounds of both yycheck and yytname.  */

         int yychecklim = YYLAST - yyn;

         int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;

         int yycount = 0;

 

         yyprefix = ", expecting ";

         for (yyx = yyxbegin; yyx < yyxend; ++yyx)

           if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)

             {

              yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]);

              yycount += 1;

              if (yycount == 5)

                {

                  yysize = 0;

                  break;

                }

             }

         yysize += (sizeof ("syntax error, unexpected ")

                   + yystrlen (yytname[yytype]));

         yymsg = (char *) YYSTACK_ALLOC (yysize);

         if (yymsg != 0)

           {

             char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");

             yyp = yystpcpy (yyp, yytname[yytype]);

 

             if (yycount < 5)

              {

                yyprefix = ", expecting ";

                for (yyx = yyxbegin; yyx < yyxend; ++yyx)

                  if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)

                    {

                     yyp = yystpcpy (yyp, yyprefix);

                     yyp = yystpcpy (yyp, yytname[yyx]);

                     yyprefix = " or ";

                    }

              }

             yyerror (yymsg);

             YYSTACK_FREE (yymsg);

           }

         else

           yyerror ("syntax error; also virtual memory exhausted");

       }

      else

例如,程序片断

{

       i = 2;

       while (i <=100)

       {

              sum = sum + i;

              i = i + 2;

       }

}

 (注:原本是在windwos环境下编程,最后到unix环境下,发现速度快了,灵活性高了,同时方便了很多。(flex,bison))

test.l

View Code
%option noyywrap
%{
#include<stdlib.h>
#include<ctype.h>
#include<stdio.h>
%}
%%
"if" {return IF;} 
"while" {return WHILE;} 
"do" {return DO;} 
"break" {return BREAK;}
"int"|"float"|"bool"|"char" {return BASIC;}
"true" {return TRUE;}
"false" {return FALSE;}
"else"  {return ELSE;}
[a-zA-Z_][a-zA-Z_0-9]* {return ID;}
[0-9]+\.[0-9]+ {return REAL;}
[0-9]+ {return NUM;}
"||" {return OR;}
"&&" {return AND;}
"|" {return '|';}
"&" {return '&';}
"<=" {return LE;}
"<" { return '<';}
">=" {return GE;}
">" {return '>';}
"!=" {return NE;}
"=" { return '=';}
"==" {return EQ;}
"\+"  {return '+';}
"\-" {return '-';}
"\*" {return '*';}
"\/" {return '/';}
"(" {return '(';}
")" {return ')';}
";" {return ';';}
"{" {return '{';}
"}" {return '}';}
"[" {return '['; }
"]" {return ']';}
"//".*  {}
[ \n\t] {}
%%

test.y

View Code
%{
#include<ctype.h>
#include<stdio.h>
%}
%left '+' '-'
%left '*' '/'
%nonassoc UMINUS
%token NUM AND BASIC BREAK DO ELSE EQ FALSE GE
%token ID IF INDEX LE MINUS NE OR REAL TRUE WHILE
KET
 %token  RIGHT_BRA
%%
program : block { printf("program-->block\n"); }
        ;
block : '{' decls stmts '}' { printf("block-->{decls stmts}\n"); }
      ;
decls : decls decl { printf("decls-->decls decl\n"); }
      | /*empty*/
      ;
decl : type ID ';' { printf("decl-->type id;\n"); }
     ;
type : type '[' NUM ']' { printf("type-->type[num]\n"); }
     | BASIC { printf("type-->basic\n"); }
     ;
stmts : stmts stmt { printf("stmts-->stmts stmt\n"); }
     | /*empty*/
     ;
stmt : DO stmt WHILE '(' bool ')' ';' { printf("stmt-->do stmt while(bool);\n"); }
     | IF '(' bool ')' stmt { printf("stmt--if(bool)stmt\n"); }
     | IF '(' bool ')' stmt ELSE stmt { printf("stmt-->if(bool)stmt else stmt\n"); }
     | WHILE '(' bool ')' stmt { printf("stmt-->while(bool)stmt\n"); }
     | BREAK ';' { printf("stmt-->break;\n"); }
     | block { printf("stmt-->block\n"); }
     | loc '=' bool ';' { printf("stmt-->loc=bool;\n"); }
     ;
loc : loc '[' bool ']' { printf("loc-->loc[bool]\n"); }
    | ID { printf("loc-->id\n"); }
    ;
bool : bool OR join { printf("bool-->bool||join\n"); }
     | join { printf("bool-->join\n"); }
     ;
join : join AND equality { printf("join-->join&&equality\n"); }
     | equality { printf("join-->equality\n"); }
     ;
equality : equality EQ rel { printf("equality-->equality==rel\n"); }
         | equality NE rel { printf("equality-->equality!=rel\n"); }
         | rel { printf("equality-->rel\n"); }
         ;
rel : expr '<' expr { printf("rel-->expr<expr\n"); }
    | expr LE expr { printf("rel-->expr<=expr\n"); } 
    | expr GE expr { printf("rel-->expr>=expr\n"); }
    | expr '>' expr { printf("rel-->expr>expr\n"); }
    | expr { printf("rel-->expr\n"); }
    ;
expr : expr '+' term { printf("expr-->expr+term\n"); }
     | expr '-' term { printf("expr-->expr-term\n"); }  
     | term { printf("expr-->term\n"); }
     ;
term : term '*' unary { printf("term-->term*unary\n"); }
     | term '/' unary { printf("term-->term/unary\n"); }
     | unary { printf("term-->unary\n"); }
     ;
unary : '!' unary { printf("unary-->!unary\n"); }
      | '-' unary %prec UMINUS{ printf("unary-->-unary\n"); }
      | factor { printf("unary-->factor\n"); }
      ;
factor : '(' bool ')' { printf("factor-->(bool)\n"); }
       | loc { printf("factor-->loc\n"); }
       | NUM { printf("factor-->num\n"); }
       | REAL { printf("factor-->real\n"); }
       | TRUE { printf("factor-->true\n"); }
       | FALSE { printf("factor-->false\n"); }
       ;
       
%%
#include "lex.yy.c"
int  main()
{
 extern FILE *yyin;
 yyin=fopen("b.txt","r");
 yyparse();
 return 0;
}
yyerror(char *s)
{
    printf("%s error!\n",s);
}

b.txt

View Code
{
    i = 2;
    while (i <=100)
    {
        sum = sum + i;
        i = i + 2;
    }
}

在unix可以生成a.out就能直接用。

《Lex与Yacc》中文第二版(带源码)_yacc_flex_两份文档:http://pan.baidu.com/share/link?shareid=167248&uk=1678594189

实验4 secomd time 晋级版():http://pan.baidu.com/share/link?shareid=167252&uk=1678594189

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LR语法分析器编译原理中的一种语法分析方法,它可以根据给定的文法规则,对输入的程序代码进行分析和解析。LR语法分析器使用自底向上的分析方法,通过构建一个状态机来识别输入的符号串是否符合给定的文法规则。 LR语法分析器实现通常使用工具,如Bison(Yacc的GNU版本),它可以根据给定的文法规则自动生成相应的语法分析器。LR语法分析器的工作原理如下: 1. 构建LR分析表:根据给定的文法规则,LR语法分析器会构建一个分析表,该表记录了在不同状态下,对应不同输入符号的移进、规约或接受操作。 2. 状态转移:LR语法分析器通过状态转移来处理输入符号串。它从初始状态开始,根据当前状态和下一个输入符号,查找分析表中对应的操作,并执行相应的移进或规约操作。 3. 移进操作:当遇到终结符号时,LR语法分析器会将该符号移入栈中,并读取下一个输入符号。 4. 规约操作:当遇到非终结符号时,LR语法分析器会根据文法规则进行规约操作,将栈中的符号按照规约规则进行替换。 5. 接受操作:当输入符号串被完全分析并符合文法规则时,LR语法分析器会执行接受操作,表示输入符号串被成功地分析和解析。 通过使用LR语法分析器,可以对程序代码进行语法分析,并生成相应的抽象语法树(AST)。抽象语法树可以用于后续的语义分析和代码生成等编译过程。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值