![](/img/trans.png)
[英]Problem with my parser.y (FLEX/BISON). How to declare '$4'?
[英]How to use flex with my own parser?
我想将词法分析留给词法分析,但自己开发解析器。
我制作了一个token.h标头,其中包含令牌类型的枚举和简单的类层次结构,
对于lex规则:
[0-9]+ {yylval = new NumToken(std::stoi(yytext));return NUM;}
如何从解析器代码中获取NumToken指针? 假设我只想打印出令牌。
while(true)
{
auto t = yylex();
//std::cout <<yylval.data<<std::endl; // What goes here ?
}
我可以使用yacc / bison进行此操作,但是找不到有关如何手动执行此操作的任何文档或示例。
在传统的bison / flex解析器中, yylval
是在bison生成的解析器中定义的全局变量,并在bison生成的头文件中声明(应在包含在生成的扫描器中#include)。 因此,一个简单的解决方案就是复制它:在token.h
声明yylval
(作为全局token.h
并在解析器中的某个位置定义它。
但是现代编程风格已经从使用全局变量转变了(有充分的理由),实际上,如果需要,甚至flex
也会生成不依赖于全局状态的扫描程序。 要请求这样的扫描仪,请指定
%option reentrant
在您的扫描仪定义中。 默认情况下,这会将yylex
的原型更改为:
int yylex(yyscan_t yyscanner);
其中yyscan_t
是不透明的指针。 (这是C,所以意味着它是一个void*
。)您可以在Flex手册中阅读有关细节; 最重要的要点是,您可以要求flex还生成一个头文件(带有%option header-file
),以便其他翻译单元可以引用各种函数来创建,销毁和操作yyscan_t
,并且您需要最少创建一个,以便yylex
在某处存储其状态。 (理想情况下,您也将其销毁。)[注1]。
使用扫描仪折返从预期的方式bison
是启用%option bison-bridge
(和%option bison-location
,如果你的词法分析器每个令牌生成源位置信息)。 这将为yylex
原型添加一个附加参数:
int yylex(YYSTYPE *yylval_param, yyscan_t scanner);
使用`%option bison-locations',添加了两个参数:
int yylex(YYSTYPE *yylval_param,
YYLTYPE *yylloc_param,
yyscan_t scanner);
flex生成的代码未声明语义类型YYSTYPE
和位置类型YYLTYPE
。 它们必须出现在您#include到扫描仪中的token.h
标头中。
野牛桥参数的目的是提供一种将语义值yylval
返回给调用方(即解析器)的机制。 由于yylval
实际上与参数yylval_param
[注2]相同,因此它将是指向实际语义值的指针 ,因此您需要在flex动作中编写(例如) yylval->data = ...
所以这是做到这一点的一种方法。
替代bison-bridge
一种可能更简单的选择是仅提供您自己的yylex
原型,您可以使用宏YY_DECL
。 例如,您可以执行以下操作(如果YYSTYPE很简单):
#define YY_DECL std::pair<int, YYSTYPE> yylex(yyscan_t yyscanner)
然后一条规则可以返回该对:
[0-9]+ {return std::make_pair(NUM, new NumToken(std::stoi(yytext));}
显然,此主题有很多变体。
不幸的是,生成的标头包含很多不必要的包,,包括一堆用于标准“全局变量”的宏定义,这些宏定义将不起作用,因为在可重入的扫描器中,这些变量只能在flex动作中使用。
用bison-bridge
生成的扫描器将yylval
定义为一个宏,该宏引用不透明状态结构中的一个字段,并将yylval_param
存储到该字段中。 yyget_lval
和yyset_lval
函数是为了从yylex
外部获取或设置此字段。 我不知道为什么; 似乎介于不必要和危险之间,因为状态将包含指向 yylex
调用中提供的值的指针,一旦调用返回,它很可能是悬空的指针。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.