yacc 和 lex的上手(3)

本文介绍了一个简单的恒温器控制系统的设计过程,利用lex和yacc工具实现语法解析和命令处理,能够识别并响应如开关加热器及设定目标温度等操作。
昨天看完了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


得到预期的结果。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值