Bison 将参数传递给yylex
我正试图修改.l和.y文件,使扫描器和解析器可重入。根据GNU文档等,我将其放在了.y文件中:Bison 将参数传递给yylex,bison,flex-lexer,Bison,Flex Lexer,我正试图修改.l和.y文件,使扫描器和解析器可重入。根据GNU文档等,我将其放在了.y文件中: %define api.pure %lex-param { YYSTYPE *yylval } %parse-param { astNodePtr *programTree } 此外,我还在.l文件中添加了可重入和野牛桥选项 但是,在我使用bison-dv parser.y构建parser.tab.h和parser.tab.c之后,我注意到parser.tab.c包含声明 int yylex(voi
%define api.pure
%lex-param { YYSTYPE *yylval }
%parse-param { astNodePtr *programTree }
此外,我还在.l文件中添加了可重入
和野牛桥
选项
但是,在我使用bison-dv parser.y
构建parser.tab.h和parser.tab.c之后,我注意到parser.tab.c包含声明
int yylex(void);
但后来涉及到诸如
yychar = yylex (&yylval, yylval);
此外,试图编译flex创建的.c文件会产生各种各样的错误,这些错误集中在一个名为yyg
的变量上
是否有其他标志/我需要添加到.l或.y文件中的任何内容?请记住,flex和bison是两个完全独立的处理器,它们接收两个完全独立的输入文件并生成两个完全独立的程序,然后分别编译。Bison和flex不读取彼此的输入文件(或输出文件),也不读取程序员的想法。因此,生成的程序之间的任何互操作性都是存在的,因为作为程序员,您已经为此做出了安排 对于默认(不可重入)生成的扫描仪和解析器,您可以通过
- 确保bison生成的标题是
#在flex生成的扫描仪中包含
d,以及
- 在bison生成的解析器中声明
的原型yylex
yylex
的原型通常是
int yylex(void);
您可以让flex使用不同的原型,甚至不同的名称生成yylex
,但如果这样做,您需要告诉bison如何调用yylex
(因为它无法知道您在扫描仪中更改了原型)
如果您在parser.tab.c
文件中找到该行,几乎可以肯定是因为您将其插入了parser.y
文件的代码块中,因为这是编译不可重入解析器所必需的,并且在修改文件以生成可重入解析器时忘记删除它
默认情况下,解析器和词法分析器使用全局变量yylval
相互通信,以保存词法标记的语义值。(如果位置也在通信,则使用全局变量yylloc
)。Bison在生成的解析器中定义这些全局变量,并在生成的头中声明它们,因此只要生成的头是#将
d包含到生成的扫描程序中,两个程序就可以互操作
但这并不是一种共享数据的好方法,现代编码风格不赞成使用全局变量。通过生成可重入解析器,您可以启用另一种机制,在这种机制中,解析器将扫描指针传递到自己的本地yylval
(和yyloc
,如果使用)。这解决了可重入性问题,但现在您需要传达对flex的渴望,这样将生成一个yylex
,它需要这些参数。方法是将%bison桥
(可能还有%bison位置
)插入到flex输入文件中
这样做将调整yylex
的调用约定,但实际上不会生成可重入扫描程序。它只生成一个扫描器,它不依赖全局变量与解析器通信。扫描器依靠许多其他全局变量来维持其自身状态。如果需要可重入扫描程序,还需要在flex文件中插入%reentrant
声明,这将导致它生成一个扫描程序,将其“全局”状态保持在不透明类型的上下文对象中yyscan\t
。该上下文对象必须作为参数传递给yylex
(位于yylex
的参数列表末尾)。%reentrant
flex声明生成了一个yylex
,它需要该参数,但现在bison已退出循环;再一次,你有责任把这个事实告诉野牛
分配一个可以传递给lexer的yyscan\u t
对象也是您的责任。但是你不能直接给扫描仪打电话。您调用解析器(yyparse
),必要时它调用扫描器
Flex允许您将任意代码添加到扫描仪中(通过将其缩进到第一条规则之前)。但不幸的是,野牛没有这样的设施。将新变量注入解析器的唯一方法是将其添加到yyparse
参数列表中(使用%parse param
声明)。因此,您需要自己创建yyscan\t
对象,并将其传递给yyparse
。然后,您需要告诉bison在调用yylex
时使用该对象,这是您使用%lex param
声明所做的
应该相当清楚的是,上面提到的%parse param
和%lex param
声明几乎总是相同的。参数通过yyparse
传递到yylex
的唯一方法是,添加了%parse param
的参数与添加了%lex param
的参数具有相同的名称。既然如此,bison非常明智地允许您将%parse param
和%lex param
组合成一个%param
声明
现在你只有一个小问题。需要通过yyparse
进入yylex
的参数具有不透明类型yyscan\u t
。由于该参数是yyparse
的参数,因此类型yyscan\t
需要在生成的bison报头中可见。但是,yylex
被调用(因此必须声明)并带有其他参数,类型为YYSTYPE*
和YYLTYPE*
,这些类型在bi中声明
typedef void* yyscan_t;