问题描述
我正在用 JavaScript 分析 Antlr4 生成的解析器。我有一些与 ID | STRING
匹配的规则。
词法分析器
ID
: [a-zA-Z_] [a-zA-Z_0-9]*
;
STRING
: '"' (~["\r\n] | '""')* ('"'|[\r\n])?
;
解析器
name: ID | STRING ;
rule1: some other rules;
rule2: different rules
some: ID | STRING ;
different: ID | STRING ;
如果我将 some
更改为 some: name;
并将 different
更改为 different: 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"
- 1
- 2
我在标题中陈述的假设是否正确?
解决方法
30% 似乎很多(但在一个非常简单的例子中这可能是人为的)
使用递归下降解析器,在调用名称规则而不是识别两个标记中的任何一个时会一些开销是有意义的。
我认为在更大的比赛中整体影响可以忽略不计,除非这是你语法中非常基本的部分,并且被大量使用。
如果您对它的性能感到痛苦,那么“展开”它可能是有意义的。当然,您会在生成的解析树中丢失“名称”上下文。这可能是好事也可能是坏事,这取决于您想如何处理事情。 (有时,那些额外的解析树节点只是您感觉不舒服的噪音,而有时,它们是重要的信息)。