当前位置:  开发笔记 > 编程语言 > 正文

如何在flex规则中引用lex或parse参数?

如何解决《如何在flex规则中引用lex或parse参数?》经验,为你挑选了1个好方法。

我知道我可以%parse-param {struct my_st *arg}.y文件中声明.所以yyparse()改变了yyparse(struct my_st *arg).但是我如何引用flex规则中的参数?例如:

[0-9]+  { do_work(arg); return NUMBER; }

我想制作一个可重入的解析器,所以我需要这样做.请帮帮我,谢谢!



1> rici..:

你需要将参数传递给yylex.这需要修改bison解析器描述,以便解析器调用yylex所需的参数和flex扫描器描述,以便扫描器生成yylex所需的参数.

Bison和flex不会相互通信,也不会看到彼此的源文件.但是,扫描程序对#includebison生成的头文件是正常的,而bison允许将代码直接插入此头文件中.这使得将整个配置放入bison文件成为可能.

在野外,您可以指定yylex使用该%lex-param指令的其他参数.但是你需要知道额外的参数,如果你这些参数也会添加到调用中%define api.pure.

如果你最近使用bison 3.0或更多,你可以使用

%param { struct my_st *arg }

作为的缩写

%lex-param { struct my_st *arg }
%parse-param { struct my_st *arg }

使用单个指令是有意义的(如果你的bison足够新),因为无法在yyparse函数中插入局部变量声明.因此,唯一可以传递给yylex的变量是全局变量和参数yyparse.[注1]

请记住,这是你的责任,声明yylexyyerror在野牛文件.即使你使用%lex-param,野牛也不会自动生成声明yylex.[笔记2]

Flex通常会为其生成声明yylex,因此您不能简单地将声明放入bison生成的头文件中,然后将#include其放入扫描程序中.但是,如果定义了YY_DECL宏,那么flex生成的扫描程序将不会向前声明yylex,并且它将YY_DECL在定义中使用宏yylex.您可以使用此功能将声明yylex放入野牛描述中,以便将其传递给灵活扫描器.

在bison中,您可以使用部分或部分向生成的标头添加声明.区别在于,在声明之前和之前,段在头文件中较早.如果你使用纯解析器,原型通常会引用(如果你使用位置),所以它需要进入一个部分.为了优雅地与flex接口,您可以使用宏来生成声明.%code requires%code providesrequiresYYSTYPEYYLTYPEyylexYYSTYPEYYLTYPE%code providesYY_DECLyylex

所以你最终会得到如下内容:[注3]

文件:mylanguage.y

%code requires {
  #include 

  typedef struct Context { ... } Context;

  /* structs used in the %union declaration would go here */
}

%define api.pure full
%locations
%parse-param { Context* context }
%lex-param { Context* context }

%code provides {
   #define YY_DECL \
       int yylex(YYSTYPE* yylvalp, YYLTYPE* yyllocp, Context* context)
   YY_DECL;

   int yyerror(YYLTYPE* yyllocp, Context* context, const char* message);
}

然后,您只需以正常方式将生成的标头插入Flex文件:

file:mylanguage.l

%{
   /* System library includes */
   #include "mylanguage.tab.h"
%}

%define api.pure full野牛声明避免了全局变量的需求yylvalyylloc.但是,flex生成的扫描程序使用了许多其他内部全局变量; 为了使扫描仪真正可重入,您需要添加%option reentrant到Flex文件中.使用该选项,yylex预计包含参数yyscan_t yyscanner(与flex定义的所有其他词法分析器相关的函数一样).您需要管理该yyscanner值,因此需要将其传递yyparseyylex上述内容.您还需要初始化并销毁它,如flex手册中所述.(如果要使用原型生成原型,则其名称yylex必须正确.)yyscanneryylexYY_DECL

如果您还想传递自己的上下文对象,则可以向yyparse和添加两个参数yylex,或者您可以在对象内包含上下文yyscan_t对象,如"额外数据"的Flex手册部分所述.

最后,如果您使用bison纯解析器API,则需要更改编写flex操作的方式.您需要通过作为参数传递的指针进行分配,而不是分配给全局yylval(例如yylval.integer = atol(yytext);)yylvalp->integer = atol(yytext);.(参数的名称取决于你;我在这里使用的是我上面指定的那个.)


笔记

    较旧的实现允许您yylex通过定义宏来指定参数YYLEX_PARAM.bison 3.0不再支持此功能,因此您不应该使用它.

    如果使用%parse-param,还会添加附加参数yyerror.如果你%define api-pure full,yyerror也会收到一个位置对象.您的yyerror需求声明必须一致.

    %locations指令强制bison生成存储每个令牌的位置信息的代码.我在这里使用它是因为它使原型可预测.没有它,原型YYLTYPE只有在您实际引用语义操作中的某个位置时才会包含参数.如果您不打算使用令牌位置,则可能更愿意删除该%locations指令和所有YYLTYPE参数.但通常位置信息很有用.

推荐阅读
郑谊099_448
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有