yacc 和 lex的上手(3)

昨天看完了lex相关的例子,今天开始看yacc部分的例子

sample 4 一个简单的恒温控制器 (突然记起来大三时候做过的fuzzy logic的东东了)
目标:我们有一个恒温器,想用简单的语言来控制它,就像下面这样

heat on
Heater on!
heat off
Heater off!
target temperature 22
New temperature set!


我们需要识别token:heat, on/off (STATE), target, temperature, NUMBER

首先建立example4.l

%{
#include <stdio.h>
#include "y.tab.h"
%}
%%
[0-9]+ return NUMBER;
heat return TOKHEAT;
on|off return STATE;
target return TOKTARGET;
temperature return TOKTEMPERATURE;
\n /* ignore end of line */;
[ \t]+ /* ignore whitespace */;
%%


和前面相比这里有2个大的变化,一是inlucde y.tab.h ,另一个是不再直接print了,
而是返回token。原来是输出了screen,而现在则输出到yacc去了。

y.tab.h 是下面我们将要创建的文件, 通过yacc的语法文件来生成。

我们看看语法,BNF形式。

commands: /* empty */
| commands command
;

command:
heat_switch
|
target_set
;

heat_switch: /* 加热开关 */
TOKHEAT STATE /* STATE 就是上面lex里面定义的on off */
{
printf("\tHeat turned on or off\n");
}
;

target_set: /*目标温度设定 */
TOKTARGET TOKTEMPERATURE NUMBER
{
printf("\tTemperature set\n");
}
;


编译

lex example4.l
yacc -d example4.y
cc -o example4 lex.yy.c y.tab.c


运行

$ ./example4
heat on
Heat turned on or off
heat off
Heat turned on or off
target temperature 12
Temperature set
target xxx 34
error: syntax error
xxx


我们再来扩展一下这个恒温器,让它能处理参数。

lex匹配到目标的时候,会同时将值赋到yytext中。yacc反过来又从yyval中取得值。
下面是新的lex文件

%{
#include <stdio.h>
#include "y.tab.h"
%}
%%
[0-9]+ yylval=atoi(yytext); return NUMBER;
heat return TOKHEAT;
on|off yylval=!strcmp(yytext,"on"); return STATE;
target return TOKTARGET;
temperature return TOKTEMPERATURE;
\n /* ignore end of line */;
[ \t]+ /* ignore whitespace */;
%%


相应的yacc文件也要修改:

%{
#include <stdio.h>
#include <string.h>

void yyerror(const char *str)
{
fprintf(stderr,"error: %s\n",str);
}

int yywrap()
{
return 1;
}

main()
{
yyparse();
}

%}

%token NUMBER TOKHEAT STATE TOKTARGET TOKTEMPERATURE

%%
commands: /* empty */
| commands command
;

command:
heat_switch
|
target_set
;

heat_switch: /* 这里使用了lex里面设置参数 */
TOKHEAT STATE
{
if($2)
printf("\tHeat turned on\n");
else
printf("\tHeat turned off\n");
}
;

target_set: /* 这里使用了lex里面设置参数 */
TOKTARGET TOKTEMPERATURE NUMBER
{
printf("\tTemperature set to %d\n",$3);
}
;
%%


再次编译

然后运行

$ ./example4
heat on
Heat turned on
heat off
Heat turned off
target temperature 34
Temperature set to 34


得到预期的结果。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值