如何将flex与我自己的解析器一起使用
How to use flex with my own parser?
我想把词法分析留给lex,但自己开发解析器。
我做了一个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
(作为全局(,并在解析器中的某个地方定义它。
但是现代编程风格已经从使用全局变量(有充分的理由(转移,事实上,如果需要,即使是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);
使用"%选项野牛位置",将添加两个参数:
int yylex(YYSTYPE *yylval_param,
YYLTYPE *yylloc_param,
yyscan_t scanner);
语义类型YYSTYPE
和位置类型YYLTYPE
不是由 Flex 生成的代码声明的。它们必须显示在您 #include 到扫描仪中的token.h
标题中。
bison-bridge 参数的目的是提供一种机制,将语义值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
中所述,一旦调用返回,它很可能是一个悬而未决的指针。
- 没有为自己的结构调用列表推回方法
- 要与"if constexpr"一起使用的编译时消息(在预处理器之后)
- 在他自己的方法中,有可能将一个对象取消引用到另一个对象吗
- 在c++中为我自己的基于指针的数组分配内存的正确方法
- 将 ctypes 与 tesserac-ocr 一起使用的例外 TessPageIteratorBoundingBox.
- C++从对象自己的类中删除对象
- 使用 std::optional,而不是自己的结构
- 子轴围绕父轴而不是他自己的轴旋转
- 这个C++编译器优化(在自身的实例上调用对象自己的构造函数)的名称是什么,它是如何工作的?
- C++ 如何为自己的迭代器类从迭代器转换为const_iterator?
- 重载 + 自己的类和 std::string 的运算符
- 类无法访问自己的私有静态 constexpr 方法 - Clang bug?
- 如何实现自己的生成器以与 std 发行版一起使用
- (如何)在提升几何中创建自己的多边形类型并与之一起使用multi_polygon类型?
- 将自己的迭代器与 std::string 一起使用
- 如何将"<<"与我自己的结构一起使用?
- 如何将flex与我自己的解析器一起使用
- 如何将TortoiseOverlays与我自己的处理程序一起使用
- 如何将 gst-rtsp-server 与自己的管道一起使用
- 如何将 json c++ 与我自己的对象一起使用