如何在 `bison/yacc` 中重新定义 `YYSTYPE`?

How to redefine `YYSTYPE` in `bison/yacc`?

我定义了一个用户 class 来保存所有对象。但是yacc要做一个头文件,yylval的类型必须是YYSTYPE。如果我不使用 %union,它将把它保存为一个整数。但是如果我使用 %union,它将成为一个联合。联合是丑陋的——它不能容纳 class 或 shared_ptr(可以但不是一个好主意),它只希望我使用指针。

我只想让 YYSTYPE 有一个类型作为用户 class 类型。我该怎么做?

如您所见,lexyacc制作的源文件需要yacc制作的header文件。

header 很短,所以我们可以在其中寻找一些解决方案。

定义yylval类型的部分是这样的:

/* Value type.  */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef int YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif


extern YYSTYPE yylval;

所以我们可以在包含 yacc 的 header 文件之前定义 YYSTYPE,看起来像:

#include "your-header-file-that-define-the-class.h"
#define YYSTYPE your-class-type
#include "the-header-file-that-made-by-yacc.h"

不要使用 YYSTYPE

使用 bison——这是您实际用作 yacc 实现的东西——定义语义值类型的正确方法是

%define api.value.type { MyType }

如果您需要包含一个或多个头文件以使声明有效,请将它们放在 %code requires 块中:

%code requires {
   #include "MyType.h"
}

这两个指令生成的代码被复制到bison生成的头文件中,所以其他文件只需要包含生成的头文件。

警告:请注意,除非您使用 bison 的 C++ 接口,否则语义值类型必须是普通可复制的,这将消除大多数标准 C++ 库类型。不遵守此规则将产生未定义的行为,在您尝试解析足够复杂的输入之前,这些行为可能不会被发现。换句话说,使用简单输入的测试可能无法揭示错误。