将 STL 容器从 Flex 传递到 Bison

Pass STL containers from Flex to Bison

我正在使用 Flex 和 Bison 编写 scanner/parser 组合,如果可能的话,我想避免使用这两个程序的 C++ 特定功能,但是我需要从生成的源文件访问 C++ 库野牛。目前我正在将Flex生成的源文件编译为C程序。

我认为我可以做的一件事是在 Bison 的 %union 语句中声明 STL 类型成员,例如:

%union {
  std::string str;
};

我很快意识到这行不通,因为这会产生一个包含在 Flex 源文件中的联合。然后我想我也可以用 C++ 编译器编译它,但是当 运行 bison:

时上面的语句已经被拒绝了
error: expected specifier-qualifier-list before ‘std’

我真的不想经历在整个解析器中使用 C stdlib 函数复制和连接字符串的麻烦。我该怎么做才能使扫描器 return STL 类型成为解析器?

编辑:链接的副本并没有真正回答我的问题,那个问题的答案只说明了如何使用 C++ 编译器编译这两个文件,这不是我的问题。

你当然可以用 C++ 编译你生成的扫描器和解析器,即使你使用默认的 C 框架(我同意 C++ 框架的文档很糟糕而且过于复杂)。因此,没有什么可以阻止您在解析器中使用 std::string

但是,这不会让你把 std::string 放在 union 里面,因为你不能只是将带有非平凡析构函数的 class 扔进 union。可以通过显式声明语义类型并提供显式构造函数和析构函数来解决此限制,但这将是相当多的工作,而且可能不值得。

这仍然让您有几个选择。一种是使用指向 std::string 的指针,这意味着您的扫描器操作必须执行如下操作:

[[:alpha:]][[:alnum:]_]*    yylval.strval = new std::string(yytext);

另一种是只使用 C 字符串,导致:

[[:alpha:]][[:alnum:]_]*    yylval.strval = strdup(yytext);

在这两种情况下,您都将不得不手动管理分配的内存; C++ 的智能指针不会帮助你,因为它们也有非平凡的析构函数,所以它们也不能轻易地塞进语义联合中。

既然看起来你最终要将令牌变成 std::string,你不妨从一开始就使用上面的第一个选项。由于大多数标记都很短,而且大多数 C++ 库现在都实现了短字符串优化,new std::string(yytext) 通常只需要一次内存分配(如果需要两次,库将透明地处理第二个)。