使用%glr-parser和%合并规则减少野牛减少错误

时间:2016-04-07 16:50:51

标签: parsing bison text-parsing glr

目前我正在尝试为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邮件上写了一个bug报告 野牛名单,但没有回复这一点。 不幸的是,由于新的stackoverflow的restictions 用户,我无法提供此错误报告的链接...

1 个答案:

答案 0 :(得分:0)

预期这种行为。

可以明确地减少

expression,并且可以通过包括值的可能模糊的减少来使用减少的值。请记住,GLR与LR一样,是一个从左到右的解析器。执行减少操作时,所有子减少都已发生。效果与在右侧使用终端没有区别;终端不会被人工复制,以便在使用它的模糊产品中产生不同的实例。

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