Javascript 在Antlr4中,重用规则是否总是比使用标记重新定义慢?
我正在用JavaScript分析Antlr4生成的解析器。我有一些规则与Javascript 在Antlr4中,重用规则是否总是比使用标记重新定义慢?,javascript,antlr4,Javascript,Antlr4,我正在用JavaScript分析Antlr4生成的解析器。我有一些规则与ID | STRING匹配 雷克瑟 分析器 如果我将some更改为some:name和不同到不同:名称性能下降约30%。(要将给定代码解析100次,时间从1.5秒增加到2秒左右) 在本例中,name是解析器中的终端节点。因此,我不会自行承担大量开销。我们还有8个地方使用ID | STRING。这30%是在我用name替换了它们之后 测试代码为: x = B."method. {a, b} 1"(1,2)
ID | STRING
匹配
雷克瑟
分析器
如果我将some
更改为some:name代码>和不同
到不同:名称代码>性能下降约30%。(要将给定代码解析100次,时间从1.5秒增加到2秒左右)
在本例中,name
是解析器中的终端节点。因此,我不会自行承担大量开销。我们还有8个地方使用ID | STRING
。这30%是在我用name
替换了它们之后
测试代码为:
x = B."method. {a, b} 1"(1,2)
在上述代码中,以下内容将由“ID | STRING”匹配:
x
B
“梅托德{a,b}1”
一,
二,
我在标题中的假设正确吗?30%似乎很多(但在一个非常简单的例子中,这可能是人为的)
使用递归下降解析器,调用名称规则而不是识别两个标记中的任何一个都会有一些开销,这是有意义的
我认为在一场更大的比赛中,整体的影响可以忽略不计,除非这是你语法中经常使用的一个非常基本的部分
如果您感觉到了围绕它的性能问题,那么“展开”它可能会有一些意义。当然,您将在生成的解析树中丢失“name”上下文。这可能是好事,也可能是坏事,这取决于你想如何处理事情。(有时,这些额外的解析树节点只是噪音,可能会让人感觉不舒服,而其他时候,它们是重要的信息)。我在Intellij IDEA插件的Profile选项卡中也观察到类似的解析时间模式。是的,您发现了Antlr的几种优化技术之一。折叠操作(为RHS符号序列引入新规则)总是会减慢解析调用的运行时间。相反,展开重构会导致更快的解析时间。当然,如果不经常使用规则,展开操作可能不会产生太大影响。还有许多其他重要的优化方法。嗨@kaby76,你能给我指一些关于“许多其他重要优化方法”的帮助内容吗?到目前为止,Google搜索没有返回很多有用的信息,除了这一条。Peng,没有太多好的Antlr优化来源。但托马塞蒂涵盖了很多。也许这很明显,但用Kleene操作符替换递归可以提高解析时间。阅读Parr的论文LL(*)可能是值得的:ANTLR解析器生成器的基础,查看解析器结束回溯的时间。同样值得考虑的是您需要什么样的解析。Antlr构造了一个CST,但是如果需要,您可以构造一个AST,并避免在解析之后从CST转换到AST的时间。是的。这是人为的,我对它进行了100次分析,以得到一个可测量和可比较的结果。然而,我可以说,在这种情况下,这是不可忽视的。我也尝试过在其他地方展开,但并非所有的“展开”都能带来明显的改善。在这种情况下,丢失“name”并不重要,因为我可以在上下文中使用“some”和“different”。我认为这会提高性能,因为我们“重用”了一个规则,它可以被“缓存”。我完全错误地理解了antlr4中“缓存”的工作原理。我用解析的代码更新了这个问题。在您的示例代码中,似乎几乎所有的输入都属于这个规则。因此,这肯定符合大量使用它来解析输入的条件。因此,我并不惊讶于看到它有很大的不同(但可能不会打赌30%)。有了这样一个简单的语法和输入,几乎所有的事情都会符合解析器规则,因此额外规则的开销是可以检测到的,这并不奇怪。有趣的线程都一样。
name: ID | STRING ;
rule1: some other rules;
rule2: different rules
some: ID | STRING ;
different: ID | STRING ;
x = B."method. {a, b} 1"(1,2)