【问题标题】:Faulty bison reduction using %glr-parser and %merge rules使用 %glr-parser 和 %merge 规则减少错误野牛
【发布时间】:2016-04-07 16:50:51
【问题描述】:

目前我正在尝试为 VHDL 构建一个解析器 有一些 C++-Parsers 必须面对的问题。 VHDL 的上下文无关文法产生解析 森林而不是单个解析树,因为它是 关于函数调用和数组订阅的歧义

foo := fun(3) + arr(5);

这个赋值只能在解析器明确解析 会携带一个层次分明的、类型感知的符号表 它可以用来即时解决歧义。

我不想这样做,因为对于像 前面提到,解析森林不会呈指数增长,但是 相当线性取决于函数调用的数量和 数组订阅。

(当然,除非有人会用类似这样的语句来折磨解析器)

foo := fun(fun(fun(fun(fun(4)))));

由于野牛强制用户只创建一个解析树, 我使用 %merge 属性递归地收集所有子树 在单例中的所谓 AMBIG 节点下添加了这些子树 AST。

结果看起来像this

为了产生上述内容,我解析了令牌流“I=I(N);”。 我在 parse.y 文件中使用的语法的实质是 下面收集。它试图类似于 VHDL 的模棱两可的部分:

start: prog
;

/* I cut out every semantic action to make this
   text more readable */
prog: assignment ';'
| prog assignment ';'
;

assignment: 'I' '=' expression
;

expression: function_call   %merge <stmtmerge2>
| array_indexing            %merge <stmtmerge2>
| 'N'
;

function_call: 'I' '(' expression ')'
| 'I'
;

array_indexing: function_call '(' expression ')'   %merge <stmtmerge>
| 'I' '(' expression ')'                           %merge <stmtmerge>
;

The whole sourcecode can be read at this github repository.

现在,让我们开始讨论实际的问题。 正如您在上面生成的解析树中看到的那样, 节点 FCALL1 和 ARRIDX1 指的是同一个 单节点 EXPR1 依次引用 N1 两次。

无论如何,这不应该发生,我也没有 知道为什么。相反应该有路径

FCALL1 -> EXPR2 -> N2
ARRIDX1 -> EXPR1 -> N1

你知道为什么野牛会重复使用上述 节点?

我还写了一份关于官方 gnu 邮件的错误报告 列出野牛,但没有对此作出答复。 不幸的是,由于新 stackoverflow 的限制 用户,我无法提供此错误报告的链接...

【问题讨论】:

    标签: parsing bison text-parsing glr


    【解决方案1】:

    这种行为是意料之中的。

    expression 可以明确地减少,并且该减少的值被包括该值在内的两个可能的模糊减少使用。请记住,与 LR 一样,GLR 是一个从左到右的解析器。当一个归约动作被执行时,所有的子归约都已经发生了。效果与在右侧使用终端没有区别;终端不会被人为复制,以便在使用它的模棱两可的产品中产生不同的实例。

    对于大多数人来说,这将是一个功能而不是一个错误,我并不是在开玩笑。如果没有图形结构的堆栈,GLR 的运行时间是指数级的。如果您真的想在合并解析树时对共享 AST 节点进行深度复制,则必须自己进行,但我建议您找到一种方法来利用解析森林实际上是有向无环的事实图而不是树;您可能会利用没有重复的优势。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多