【问题标题】:Token with several types in BisonBison中具有多种类型的令牌
【发布时间】:2020-12-09 19:53:54
【问题描述】:

我想用 Bison 编写一个解析器,并且我正在尝试解析一个参数值是整数或字符串的文件。换句话说,我想要一个有两种类型的令牌。例如,假设我有以下格式:

<id>:<value>

<value> 可以是整数或字符串。

注意:在 Bison 中,在“.y”文件中,我定义类型如下

%union{
     unsigned number;
     char* string;
}
%token value
%type<"type of value, it can be an integer or a string. The problem is here, what should I define"> value

问:如何实现解析器,其中一个令牌有多种类型?

【问题讨论】:

    标签: c++ parsing bison


    【解决方案1】:

    最常见的是,您不会在词法分析器中将其作为令牌执行,而是在解析器中作为非终端执行。因此,您的词法分析器将识别两个独立的标记 INTSTRING,并且您的解析器将接受其中一个作为 value 并执行适当的操作。所以你最终可能会得到类似的东西:

    %union {
        unsigned number;
        char *string;
        struct Node *node;
    }
    
    %token<number> INT
    %token<string> STRING
    %type<node> value
    

    value : INT { $$ = createValueNodeFromInt($1); }
          | STRING { $$ = createValueNodeFromString($2); }
    

    【讨论】:

      【解决方案2】:

      与您在实现语言中执行此操作的方式相同,因为 bison 只是一个预处理器。

      如果实现语言是C,那么它基本上归结为一个可区分的联合(q.v.);也就是说,struct 包含一个enum 和一个union,其中enum(通常称为“标签”)表示union 的哪些成员处于活动状态。请注意,bison 的并集是没有区别的,不幸的是,bison 没有提供自动设置标签的语法,所以最好的办法是定义 getter 和 setter 函数。

      在 C++ 中,只要您使用 C++ 代码生成器,您就可以使用 std::variant(或 boost::variant,如果您的 C++ 版本不够新)。 (C 堆栈不能包含非平凡的 C++ 类型。)Bison 的 C++ 生成器可以提供变体类,但与 C 联合一样,它没有区别,因此无法在此应用程序中为您提供帮助。 (std::variant 和其他非平凡的 C++ 类型的性能通过使用移动语义大大增强。最近的野牛版本确实提供了自动插入 std::move 的机制,这可以帮助很多。但需要一定的小心以避免使用无效值。有关详细信息,请参阅野牛手册。)

      在 AST 的 C 实现中使用可区分联合是很常见的,在这种情况下,使用相同的数据类型在扫描器和解析器之间进行通信是很自然的。但这会在两个组件之间产生额外的依赖关系。此外,相同的词法模式匹配两种不同数据类型的对象是非常罕见的,因此变体类型对扫描器没有多大用处,如@ChrisDodd says in another answer。因此,您经常会发现使用变体类型的解析器最终会在单元产生式中包装标记,以便将值引入内部类型。

      对某些语义类型使用可区分联合往往会感染整个项目。因此,如果您从这条路开始,请准备好自始至终使用它。

      【讨论】:

        猜你喜欢
        • 2014-11-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-03
        • 1970-01-01
        • 1970-01-01
        • 2021-02-01
        相关资源
        最近更新 更多