Lex&Yacc词法语法分析Yacc(三)

来源:互联网 发布:面试linux运维故障处理 编辑:程序博客网 时间:2024/05/29 16:31
第二部分
在本段中我们要扩展前一段中的计算器以便加入一些新功能。新特性包括算术操作乘法和除
法。圆括号可以用于改变操作的优先顺序,并且可以在外部定义单字符变量的值。下面举例说明了
输入量和计算器的输出:
user: 3 * (4 + 5)
calc: 27
user: x = 3 * (4 + 5)
user: y = 5
user: x
calc: 27
user: y
calc: 5
user: x + 2*y
calc: 37
词汇解释器将返回VARIABLE和INTEGER标志。对于变量, yylval 指定一个到我们的符号表
sym中的索引。对于这个程序,sym仅仅保存对应变量的值。当返回INTEGER标志时, yylval 保存
扫描到的数值。这里是lex 输入文件:
%{
#include <stdlib.h>
void yyerror(char *);
#include "y.tab.h"
%}
%%
[az]
{
yylval = *yytext '
a';
return VARIABLE;
}
[09]+
{
yylval = atoi(yytext);
return INTEGER;
}
[+()=
[ \t] ;
. yyerror("invalid character");
%%
int yywrap(void) {
return 1;
}
接下来是yacc的输入文件。 yacc 利用 INTEGER和VARIABLE的标记在y.tab.h中生成
#defines以便在lex 中使用。这跟在算术操作符定义之后。我们可以指定% left,表示左结合,或者
用%right 表示右结合。最后列出的定义拥有最高的优先权。因此乘法和除法拥有比加法和减法更
高的优先权。所有这四个算术符都是左结合的。运用这个简单的技术,我们可以消除文法的歧义。
%token INTEGER VARIABLE
%left '+' ''
%left '*' '/'
%{
void yyerror(char *);
int yylex(void);
int sym[26];
%}
%%
program:
program statement '\n'
|
;
statement:
expr { printf("%d\n", $1); }
| VARIABLE '=' expr { sym[$1] = $3; }
;
expr:
INTEGER
| VARIABLE { $$ = sym[$1]; }
| expr '+' expr { $$ = $1 + $3; }
| expr ''
expr { $$ = $1 $
3; }
| expr '*' expr { $$ = $1 * $3; }
| expr '/' expr { $$ = $1 / $3; }
| '(' expr ')' { $$ = $2; }
;
%%
void yyerror(char *s) {
fprintf(stderr, "%s\n", s);
return 0;
}
int main(void) {
yyparse();
return 0;
}
原创粉丝点击