1

我正在尝试在 Bison 中编写一些解析 C 代码的语法。我是野牛新手,我正在尝试从网上找到的示例中学习。我正在编写 AST。如果这是我定义的语法(最基本的用例)

declarator
: IDENTIFIER         { $$ = $1;}
| declarator '(' ')' { $$ = new functionDecl($1); }

现在,当我编译此代码时,会抛出一条错误消息,指出“声明符”没有类型。

我知道我可以使用 %type 声明性来定义类型。但我希望“声明符”与变体类型相关联:

%code {

class Stmt 
{
   public:
     std::string id;
     Stmt(std::string aId)
     : id(aId)
     {}  
};
typedef std::variant<std::string, Stmt> decl_type;
}

%define api.value.type variant
%token <std::string> IDENTIFIER
%type <decl_type> declarator

我也无法编译此代码。它抛出 decl_type 未知的错误。我错过了什么?

4

1 回答 1

3

当你写

%define api.value.type variant

您是在告诉野牛使用自己的变体类型实现来实现语义值。

这在野牛手册中突出显示的注释中突出显示警告::

警告:我们不使用Boost.Variant,有两个原因。Boost首先,在用户的机器上(即编译生成的解析器的机器,而不是运行野牛的机器)似乎是不可接受的。其次,对于每个可能的语义值,Boost.Variant不仅存储该值,还存储一个指定其类型的标记。但是解析器已经“知道”语义值的类型,所以这将是重复信息。

我们也不使用 C++17 的std::variant:我们要支持所有的 C++ 标准,当然std::variant还要存储一个标签来记录当前的类型。

(如果您想使用 Bison 变体,值得阅读有关 Bison 变体的整个部分。)

当然,您可以将野牛的语义类型定义为 a std::variant

%define api.value.type std::variant<std::string, Stmt>

但这可能不是您想要的,因为 bison 对此一无所知std::variant,并且它不会帮助您访问变量值的语法。通常,正如关于 Bison 变体的页面所指出的那样,Bison 可以推断出语法符号的语义值的类型(%type当然,使用您的声明),但是如果您不使用 a unionor Bison 变体类型,那么所有 Bison 都知道是值是 a std::variantstd::variant::get如果您碰巧知道它是一种特定类型(例如,因为您知道终端符号的类型是什么),并且您想使用该类型检查值,则必须使用$2.get<NodeList>.

Bison 邮件列表上有一些关于改进 Bison 对变体类型的处理的讨论。可悲的是,我没有详细关注它,所以你可能想自己看看。

于 2019-06-24T22:33:57.493 回答