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


得到预期的结果。

你可能感兴趣的:(C++,c,C#,D语言)