【问题标题】:Make Bison accept an alternative EOF token让 Bison 接受替代的 EOF 令牌
【发布时间】:2017-09-27 05:58:19
【问题描述】:

我正在用 C++ 编写一个带有 flex 和 bison 的 ansi-C 解析器;这很复杂。

我遇到的问题是编译错误。错误如下,这是因为yy_terminate 返回了YY_NULL,它被定义为(一个int)0,而yylex 的返回类型为yy::AnsiCParser::symbol_typeyy_terminate(); 是 flex 生成的扫描器中 <<EOF>> 令牌的自动操作。显然这会导致类型问题。

我的扫描仪不会为 EOF 生成任何特殊标记,因为 EOF 在 C 语法中没有用途。我可以为<<EOF>> 创建一个令牌规则,但如果我忽略它,则扫描仪在YY_STATE_EOF(INITIAL) 案例中的yylex 中无限循环挂起。

编译错误,

ansi-c.yy.cc: In function ‘yy::AnsiCParser::symbol_type yylex(AnsiCDriver&)’:
ansi-c.yy.cc:145:17: error: could not convert ‘0’ from ‘int’ to ‘yy::AnsiCParser::symbol_type {aka yy::AnsiCParser::basic_symbol<yy::AnsiCParser::by_type>}’
ansi-c.yy.cc:938:30: note: in expansion of macro ‘YY_NULL’
ansi-c.yy.cc:1583:2: note: in expansion of macro ‘yyterminate’

此外,Bison 为我的起始规则 (translation_unit) 和 EOF ($end) 生成此规则。

$accept: translation_unit $end

所以yylex 必须为 EOF 返回一些东西,否则解析器将永远不会停止等待输入,但我的语法不支持 EOF 标记。有没有办法让 Bison 在不修改我的语法的情况下识别 0 以外的 $end 条件?

或者,我是否可以从扫描器中的 &lt;&lt;EOF&gt;&gt; 令牌返回一些东西以满足 Bison $end 条件?

【问题讨论】:

    标签: c++ bison flex-lexer


    【解决方案1】:

    通常,您不会在词法分析器中包含显式 EOF 规则,不是因为它没有任何用途,而是因为默认值正是您想要做的。 (它的作用是表明输入是完整的;否则,解析器会接受某些无效程序的有效前缀。)

    不幸的是,C++ 接口破坏了默认 EOF 操作的简单便利,即返回 0(或 NULL)。我从您的问题描述中假设您已要求 bison 使用 complete symbols 生成解析器。在这种情况下,您不能简单地从 yylex 返回 0,因为解析器需要一个完整的符号,这是一个比 int 更复杂的类型(虽然报告 EOF 的标记通常没有语义值,但它确实如果您使用的是 locaitons,则有一个位置。)对于其他令牌类型,bison 将自动生成一个生成令牌的函数,命名为 make_FOO_TOKEN 之类的名称,您将在扫描仪操作中调用该函数以获取 FOO_TOKEN

    虽然 C 野牛解析器会自动定义文件结束标记(称为 END),但 C++ 接口似乎没有。所以你需要在你的野牛输入文件的%token声明中手动定义它:

    %token END 0 "end of file"
    

    (定义标记类型END,整数值为0,人类可读标签“文件结束”。值0是强制性的。)

    完成此操作后,您可以在 flex 输入文件中添加显式 EOF 规则:

    <<EOF>> return make_END();
    

    如果您使用位置,您还必须给 make_END 一个位置参数。

    【讨论】:

    • 谢谢!我尝试了几种定义%token END 的变体,但我从未尝试将其定义为%token END 0。假设 0 只是令牌在令牌表中的位置,$end 在索引 0 处,对吗?
    • @matutter:实际上,是的。
    【解决方案2】:

    这是防止编译器错误could not convert 0 from int to ...symbol_type 的另一种方法 - 将 yyterminate 宏的重新定义放在重新定义 YY_DECL 的位置下方

    // change curLocation to the name of the location object used in yylex
    // qualify symbol_type with the bison namespace used
    #define yyterminate() return symbol_type(YY_NULL, curLocation)
    

    启用野牛位置时会显示编译器错误,例如使用%define locations - 这使得野牛在其symbol_type 构造函数中添加一个location 参数,因此构造函数没有位置

    symbol_type(int tok)
    

    用位置变成这个

    symbol_type(int tok, location_type l)
    

    渲染它不再可能将int 转换为symbol_type,这是在未启用野牛位置时,flex 中yyterminate 的默认定义能够执行的操作

    #define yyterminate() return YY_NULL
    

    使用此解决方法,如果您不需要,则无需在 flex 中处理 EOF - 如果您不需要,则无需在 bison 中使用多余的 END 令牌

    【讨论】:

      猜你喜欢
      • 2018-01-15
      • 2020-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-22
      • 2018-11-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多