我正在移植一个来自flex / bison的语法,并且大多数似乎已经启动并运行(特别是,我的令牌流似乎很好,我的解析器语法正在编译和运行),但似乎遇到了堆栈/内存使用失控的问题,即使我的语法输入非常小/中等大小。将同一非终结符的无界序列链接在一起的首选构造是什么?在我的Bison语法中,我有以下形式的制作规则:
statements: statement | statement statements
words: | word words
在ANTLR中,如果我保持相同的规则设置,这似乎在小输入(大约4kB)上表现令人钦佩,但在较大输入(大约100kB)上导致堆栈溢出。在这两种情况下,生成的自动解析树也相当笨拙。
我尝试将这些生产规则更改为明确添加(而不是递归形式):
statements: statement+
words: word*
然而,即使非常小的输入,这似乎导致内存使用量(超过1GB)的绝对可怕爆炸,并且解析器在让它运行20分钟后仍未设法返回解析树。
任何指针都会受到赞赏。
答案 0 :(得分:2)
您重写的语句是您描述的两个规则的最佳ANTLR 4形式(最高性能和最低内存使用率)。以下是您描述的问题的一般性反馈。
我为许多潜在的性能问题开发了一些非常先进的诊断代码。这些代码大部分包含在TestPerformance
中,但它面向专家用户,需要对ANTLR 4的新ALL(*)算法进行相当深入的了解才能解释结果。
Terence和我有兴趣将上述内容变成用户可以使用的工具。如果您提供完整的语法和示例输入,我可以帮助(运行和解释测试),这样我就可以使用该语法和输入对作为评估工具可用性的一部分,从而使分析自动化
确保您使用的是本书中的两阶段解析策略。在许多情况下,这将极大地提高正确输入的解析性能(不正确的输入不会更快)。
我们不喜欢使用比必要更多的内存,但是你应该知道我们正在根据一个非常不同的“过度”定义 - 例如我们使用-Xmx4g
到-Xmx12g
运行我们的测试应用程序,具体取决于测试。
答案 1 :(得分:1)
好的,所以我以下面的方式让它工作了。我的YACC语法有以下结构:
lines: lines | line lines;
words: | word words;
但是,这并没有使递归解析变得快乐,所以我把它重写为:
lines: line+;
words: word*;
这符合@ 280Z28的反馈(以及我原来的猜测)。这挂起了解析器,这就是我首先发布问题的原因,但是我对@ 280Z28的回答中所述的调试过程表明,实际上只有lines
解析导致了问题({ {1}})很好。一时兴起,我尝试了以下重写:
words
(lines : stmt (EOL stmt)+ EOL*;
最初被定义为:
line
)
这似乎工作得很好,即使对于大量输入也是如此。然而,我完全不清楚为什么这是正确的事情(tm),或者为什么它与提出这个问题的修订相比有所不同。关于这个问题的任何反馈仍然会受到赞赏。