【问题标题】:Bison error output野牛错误输出
【发布时间】:2011-08-04 21:46:57
【问题描述】:

我正在使用 Bison,并且生成了一个非常复杂的语法。问题是我的第一个测试用例失败了——但 Bison 只会说“语法错误”。有没有办法让Bison输出匹配失败的规则和有问题的token?我用过

%define parse.trace true

但仍然只能得到syntax error 作为输出。

【问题讨论】:

    标签: bison


    【解决方案1】:

    当出现问题时,没有一个基于 Yacc 的解析器比“语法错误”做得更好;这在很大程度上取决于您自己的改进。

    有几件事你可以很容易地做到。

    一种是检测您的词法分析器,以便在将找到的标记返回给正确的解析器时打印出它们。这会告诉您语法在哪个标记上失败,以及预先提供了哪些标记。

    另一种是编译开启Yacc调试,然后开启。这需要-DYYDEBUG=1 并将变量yydebug 设置为非零值(通常为1)。第一步将额外的信息编译成语法;第二步启用输出。

    来自 Bison 2.4.3 手册:

    §8.2 跟踪解析器

    如果 Bison 语法编译正确,但在运行时没有执行您想要的操作,则 yydebug 解析器跟踪功能可以帮助您找出原因。

    有几种方法可以启用跟踪工具的编译:

    • YYDEBUG

      在编译解析器时,将宏 YYDEBUG 定义为非零值。 这符合 POSIX Yacc。您可以使用-DYYDEBUG=1 作为编译器 选项,或者您可以将#define YYDEBUG 1 放在语法的序言中 文件(参见第 3.1.1 节 [序言],第 47 页)。

    • 选项-t--debug

      在运行 Bison 时使用 -t 选项(参见第 9 章 [调用 Bison], 第 117 页)。这也符合 POSIX。

    • 指令%debug

      添加%debug 指令(参见第 3.7.12 节 [Bison 声明摘要], 第 72 页)。这是一个 Bison 扩展,当 Bison 将 不使用预处理器的语言的输出解析器。除非 POSIX 和 Yacc 的可移植性对你很重要,这是首选的解决方案。

    我们建议您始终启用调试选项,以便始终可以进行调试。

    跟踪工具通过YYFPRINTF (stderr, format, args) 形式的宏调用输出消息,其中formatargs 是通常的printf 格式和可变参数。 如果将YYDEBUG 定义为非零值但未定义YYFPRINTF,则<stdio.h> 被自动包含,YYFPRINTF 被定义为fprintf

    一旦你用跟踪工具编译了程序,请求跟踪的方法是 在变量yydebug 中存储一个非零值。您可以通过使 C 代码执行此操作 它(可能在 main 中),或者您可以使用 C 调试器更改该值。

    yydebug 为非零时,解析器执行的每一步都会产生一行或两行跟踪 信息,写在stderr。跟踪消息会告诉您以下信息:

    • 解析器每次调用yylex,读取的令牌类型。
    • 每次移动令牌时,状态堆栈的深度和完整内容(请参阅 第 5.5 节 [解析器状态],第 95 页)。
    • 每减少一条规则,是哪条规则,状态的完整内容 之后堆叠。

    【讨论】:

    • 在 yylex() 中输出令牌是我的 winrar。
    【解决方案2】:

    使用%error-verbose 指令来帮助您。它会给你一个解析器期望的标记的提示。请注意,可能有多个潜在规则无法匹配。

    【讨论】:

    • Bison 现在推荐%define parse.error verbose,但上述方法仍然有效!
    【解决方案3】:

    如果您将全局变量yydebug 设置为非零值,bison 将在运行时输出调试信息,其中包含有关解析堆栈的外观、处于什么状态、正在使用什么规则等信息。我通常会调试这些类型的错误。

    【讨论】:

      【解决方案4】:

      这里有点混乱。

      "%define parse.trace""%debug" 完全相同:它将生成的解析器用于运行时跟踪,显示解析器在工作(但您仍然必须设置yydebug 变量,请参阅Jonathan Leffler 转载的文档)。

      为了使错误消息更准确(在这方面 Jonathan 是错误的),Bison 可以做得更好,这要感谢 Alek 报告的 "%define error-verbose"

      【讨论】: