Lex和Yacc使用学习笔记(二)

Yacc

       yacc的文法由一个使用BNF文法(Backus-Naur form 的变量描述。文法规则最初由 John Backus Peter Naur 发明,并且用于描述Algol60 语言。 BNF 能够用于表达上下文无关语言。现代程序语言中的大多数结构可以用BNF 文法来表达。例如,数值相乘和相加的文法是:

E > E + E

E > E * E

E > id

E (表达式)这样出现在左边的结构叫非终结符(nonterminal)。像 id(标识符)这样的结构叫终结符(terminal,由lex 返回的标记),它们只出现在右边。

yacc的输入文件格式与lex类似,给出一个例子,计算加减乘除的简单计算器,yacclex结合使用。

 

Lex的输入文件:

%{

/****************************************************************************

calclexer.l

ParserWizard generated Lex file.

 

Date: 2008 10 13

****************************************************************************/

#include <stdlib.h>

void yyerror(char *);

#include "calcparser.h"

extern YYSTYPE yylval;

%}

 

/

// declarations section

 

// place any declarations here

 

%%

 

/

// rules section

 

// place your Lex rules here

[0-9]+     {

                     yylval = atoi(yytext);

                     return INTEGER;

              }

[-+*//n]   return *yytext;

[ /t]  ; /* skip whitespace */

.             yyerror("invalid character");

%%

 

/

// programs section

 

int yywrap(void) {

return 1;

}

Yacc的输入文件:

%{

/****************************************************************************

calcparser.y

ParserWizard generated YACC file.

 

Date: 2008 10 13

****************************************************************************/

 

#include "calclexer.h"

int yylex(void);

void yyerror(char *);

%}

 

/

// declarations section

 

// attribute type

%include {

#ifndef YYSTYPE

#define YYSTYPE int

#endif

}

 

// place any declarations here

%token INTEGER

%left '+' '-'

%left '*' '/'

%%

 

/

// rules section

 

// place your YACC rules here (there must be at least one)

 

program:

       program expr '/n' { printf("%d/n", $2); }

       |

       ;

expr:

       INTEGER { $$ = $1; }

       | expr '+' expr { $$ = $1 + $3; }

       | expr '-' expr { $$ = $1 - $3; }

       | expr '*' expr { $$ = $1 * $3; }

       | expr '/' expr { $$ = $1 / $3; }

       ;

%%

 

/

// programs section

 

void yyerror(char *s)

{

       fprintf(stderr, "%s/n", s);

}

 

int main(void)

{

       yyparse();

       return 0;

}

需要注意以下几点:

l         在计算+-的时候,文法本身是有移近-规约冲突(shift-reduce conflict)的,例如 10-2-2 ,到底是先计算10-2,还是先计算2-2。默认是移近,就会先计算2-2,结果是不正确的。可以通过%left%right指定结合顺序来解决冲突,即【%left '+' '-' 】,最后列出的定义拥有最高的优先权。因此乘法和除法拥有比加法和减法更高的优先权。

l         yylval是在yacc的输出文件中定义的,在lex中使用时需要先用extern将其引入【extern YYSTYPE yylval;

l         yacc 在内部维护着两个堆栈;一个分析栈和一个内容栈。分析栈中保存着终结符和非终结符,并且代表当前剖析状态。内容栈是一个YYSTYPE 元素的数组,对于分析栈中的每一个元素都保存着一个对应的值。例如,当yylex 返回一个INTEGER 标记时,yacc 把这个标记移入分析栈。同时,相应的yylval 值将会被移入内容栈中。分析栈和内容栈的内容总是同步的,因此从栈中找到对应于一个标记的值是很容易实现的。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值