我正在使用 Flex 和 Bison 编写扫描器/解析器组合,如果可能的话,我想避免使用这两个程序的 C++ 特定功能,但是我仍然需要从 Bison 生成的源文件访问 C++ 库。目前我正在将 Flex 生成的源文件编译为 C 程序。
我认为我可以做的一件事是在 Bison 的 %union
语句中声明 STL 类型成员,例如:
%union {
std::string str;
};
我很快意识到这行不通,因为这会产生一个包含在 Flex 源文件中的 union 。然后我想我也可以用 C++ 编译器编译它,但是上面的语句在运行 bison 时已经被拒绝了:
error: expected specifier-qualifier-list before ‘std’
我真的不想经历在整个解析器中使用 C stdlib 函数复制和连接字符串的麻烦。我该怎么做才能使扫描器将 STL 类型返回给解析器?
编辑:链接的拷贝并没有真正回答我的问题,那个答案只显示了如何使用 C++ 编译器编译这两个文件,这不是我的问题。
最佳答案
您当然可以使用 C++ 编译生成的扫描器和解析器,即使您使用默认的 C 框架(我同意 C++ 框架的文档很糟糕并且过于复杂)。所以没有什么可以阻止您在解析器中使用 std::string
。
但是,这不会让您将 std::string
放入 union
中,因为您不能只使用非平凡的析构函数扔掉一个类到一个 union
中。可以通过显式声明语义类型并提供显式构造函数和析构函数来解决此限制,但这将需要大量工作,而且可能不值得。
这仍然给您留下了几个选择。一种是使用指向 std::string
的指针,这意味着您的扫描器操作必须执行如下操作:
[[:alpha:]][[:alnum:]_]* yylval.strval = new std::string(yytext);
另一种是只使用 C 字符串,导致:
[[:alpha:]][[:alnum:]_]* yylval.strval = strdup(yytext);
在这两种情况下,您最终都必须手动管理分配的内存; C++ 的智能指针不会帮助你,因为它们也有非平凡的析构函数,所以它们也不能轻易地塞进语义 union 中。
既然看起来您最终要将 token 变成 std::string
,那么您最好从一开始就使用上面的第一个选项。由于大多数标记都很短,而且大多数 C++ 库现在都实现了短字符串优化,new std::string(yytext)
将经常只需要一次内存分配(如果需要两次,库将透明地处理第二个)。
关于c++ - 将 STL 容器从 Flex 传递到 Bison,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51390618/