在ANTLR4中解析非常大的表达式时出现堆栈溢出
我正在ANTLR4中重新实现现有的DSL。现有的源代码主体有一些非常大的表达式。似乎ALL(*)逻辑中的递归意味着我可以解析的表达式的大小有一个限制 示例语法:(刚好可以在此处复制错误错误) 样本输入:在ANTLR4中解析非常大的表达式时出现堆栈溢出,antlr4,Antlr4,我正在ANTLR4中重新实现现有的DSL。现有的源代码主体有一些非常大的表达式。似乎ALL(*)逻辑中的递归意味着我可以解析的表达式的大小有一个限制 示例语法:(刚好可以在此处复制错误错误) 样本输入: V0 AND 0 OR V1 AND 1 OR ... (MANY rows elided) V3999 AND 3999 OR V4000 AND 4000 堆栈跟踪: Exception in thread "main" java.lang.reflect.Invoc
V0 AND 0 OR
V1 AND 1 OR
... (MANY rows elided)
V3999 AND 3999 OR
V4000 AND 4000
堆栈跟踪:
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.antlr.v4.runtime.misc.TestRig.process(TestRig.java:249)
at org.antlr.v4.runtime.misc.TestRig.process(TestRig.java:211)
at org.antlr.v4.runtime.misc.TestRig.main(TestRig.java:143)
Caused by: java.lang.StackOverflowError
at java.util.Arrays.equals(Arrays.java:1869)
at org.antlr.v4.runtime.atn.ArrayPredictionContext.equals(ArrayPredictionContext.java:101)
at java.util.HashMap.getEntry(HashMap.java:471)
at java.util.LinkedHashMap.get(LinkedHashMap.java:301)
at org.antlr.v4.runtime.misc.DoubleKeyMap.get(DoubleKeyMap.java:62)
at org.antlr.v4.runtime.atn.PredictionContext.mergeArrays(PredictionContext.java:418)
at org.antlr.v4.runtime.atn.PredictionContext.merge(PredictionContext.java:199)
at org.antlr.v4.runtime.atn.ATNConfigSet.add(ATNConfigSet.java:175)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closure_(ParserATNSimulator.java:1126)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closureCheckingStopState(ParserATNSimulator.java:1111)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closure_(ParserATNSimulator.java:1164)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closureCheckingStopState(ParserATNSimulator.java:1111)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closure_(ParserATNSimulator.java:1164)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closureCheckingStopState(ParserATNSimulator.java:1111)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closure_(ParserATNSimulator.java:1164)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closureCheckingStopState(ParserATNSimulator.java:1111)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closure_(ParserATNSimulator.java:1164)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closureCheckingStopState(ParserATNSimulator.java:1111)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closure_(ParserATNSimulator.java:1164)
限制表达式的大小不是一个选项。他们用当前的技术编译得很好,所以我们必须支持它
为了避免极高的堆栈利用率,我是否必须排除这个问题上的左递归?或者,有一个更简单的答案吗?ANTLR 4.2将通过合并来改善这种情况。由于ANTLR 4尚未发布,我建议从源代码构建最新版本的ANTLR 4,并再次尝试您的输入。您可以尝试更大的JVM堆栈:我已经这样做了,这会有所不同,但最终只是将突破点推了一点,所以我很难称之为解决方案。看起来很有希望。我来看看。我已经删除了左递归,在一个简单的测试中,我对性能的提高感到震惊,所以我希望只保留没有左递归的版本。您的更改是否会使性能接近我通过删除左递归得到的结果?如果有性能的话,我更愿意回到更简单的语法(和更简单的AST),我已经在GitHub上从源代码构建了最新的语法。看起来这可能会防止(或肯定会改善)堆栈溢出的情况。我现在正在编译单个表达式,java内存利用率正在逐渐增加。这就是说,看起来我可能是在创造一个强迫性的案例,让O(n4)(或接近那个)表现。带左递归分解的语法运行得非常快(可能是次秒;我还没有计时);但是,使用左递归语法运行已经运行了6个多小时,仍然没有完成。@MikeCargal您能给我发送您的语法和演示问题的示例输入吗?我想对它进行一些测试。而且,唯一的O(n⁴) 我们能够创建的案例涉及一个非常明显的结构不良的模糊规则。我们所见过的最糟糕的模糊语法是O(n³).使用您的示例语法和最新的ANTLR 4.2工作输入,我发现即使输入的大小是您在第一篇文章中列出的输入的400倍,也可以在15秒内完成。感谢您的帮助。我不确定我做错了什么。在重新完成构建过程后,我能够再次运行测试并完成测试很明显,我没有正确地构建一些东西,或者没有正确地指出我的构建结果。现在效果很好。
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.antlr.v4.runtime.misc.TestRig.process(TestRig.java:249)
at org.antlr.v4.runtime.misc.TestRig.process(TestRig.java:211)
at org.antlr.v4.runtime.misc.TestRig.main(TestRig.java:143)
Caused by: java.lang.StackOverflowError
at java.util.Arrays.equals(Arrays.java:1869)
at org.antlr.v4.runtime.atn.ArrayPredictionContext.equals(ArrayPredictionContext.java:101)
at java.util.HashMap.getEntry(HashMap.java:471)
at java.util.LinkedHashMap.get(LinkedHashMap.java:301)
at org.antlr.v4.runtime.misc.DoubleKeyMap.get(DoubleKeyMap.java:62)
at org.antlr.v4.runtime.atn.PredictionContext.mergeArrays(PredictionContext.java:418)
at org.antlr.v4.runtime.atn.PredictionContext.merge(PredictionContext.java:199)
at org.antlr.v4.runtime.atn.ATNConfigSet.add(ATNConfigSet.java:175)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closure_(ParserATNSimulator.java:1126)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closureCheckingStopState(ParserATNSimulator.java:1111)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closure_(ParserATNSimulator.java:1164)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closureCheckingStopState(ParserATNSimulator.java:1111)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closure_(ParserATNSimulator.java:1164)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closureCheckingStopState(ParserATNSimulator.java:1111)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closure_(ParserATNSimulator.java:1164)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closureCheckingStopState(ParserATNSimulator.java:1111)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closure_(ParserATNSimulator.java:1164)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closureCheckingStopState(ParserATNSimulator.java:1111)
at org.antlr.v4.runtime.atn.ParserATNSimulator.closure_(ParserATNSimulator.java:1164)