Compiler construction 带ANTLR 3的两级语法
我有一个语法(如果你把它简化一点)如下:Compiler construction 带ANTLR 3的两级语法,compiler-construction,antlr,antlr3,Compiler Construction,Antlr,Antlr3,我有一个语法(如果你把它简化一点)如下: options { backtrack=true; } // parser text: (TEXT)+; and_level2_thing: text | '(' and_thing ')'; and_thing: and_level2_thing (OP_AND and_level2_thing)*; and_expression: and_thing (OP_AND and_thing)*; parse_starts_here: a
options
{
backtrack=true;
}
// parser
text: (TEXT)+;
and_level2_thing: text | '(' and_thing ')';
and_thing: and_level2_thing (OP_AND and_level2_thing)*;
and_expression: and_thing (OP_AND and_thing)*;
parse_starts_here: and_expression EOF;
// lexer
OP_AND : 'AND';
TEXT : ( '"' (~'"')* '"' );
它有两种类型的表达式组顶级(和_-thing
)和内部级别(和_-level2 _-thing
),适用不同的规则,但这两种级别都必须支持,例如顶级类型表达式和顶级类型表达式
,以及
顶部类型表达式和(内部类型表达式和内部类型表达式)
当我具有以下形式的值时:
(TOP_TYPE_表达式和(TOP_TYPE_表达式和(TOP_TYPE_表达式和(TOP_TYPE_表达式)))
时间在嵌套级别上开始呈指数增长,这可能是因为AND是不明确的。此表达式立即计算:
TOP_-TYPE_表达式和TOP_-TYPE_表达式以及TOP_-TYPE_表达式和TOP_-TYPE_表达式
如果你说这不是一种设计良好的语言——我完全同意,但这就是我现在所拥有的:)。有没有办法避免这个问题?添加memoize“修复”这个问题。但我相信有更好的解决方案或更有趣的讨论
options
{
backtrack=true;
memoize=true;
}
你的语法模棱两可:
"a" AND "b"
可匹配为
parse_starts_here
and_expression
and_thing
and_level2_thing
text
OP_AND
and_level2_thing
text
或作为
通常,ANTLR会警告您这种模糊性,但通过声明backtrack=true
,您可以有效地告诉ANTLR尝试所有备选方案,并首先使用匹配的
在明确的语法上,ANTLR在线性时间内运行。使用回溯会导致潜在的指数时间memoize=true
用于减少恢复线性的时间,但会消耗更多内存
我建议删除backtrack=true
选项。然后,ANTLR将告诉您语法不明确的地方。您可以消除歧义,或者如果不可能,则仅在需要时使用语法谓词,以使一种可能的匹配优于另一种<如果最终使用语法谓词,code>memoize=true仍然会有帮助
编辑-关于为什么即使两个备选方案匹配也会出现回溯: 它不会倒退,但时间仍将是指数级的 问题是,ANTLR直到实际尝试匹配它时才知道它可以匹配第一个备选方案(因为您没有给它任何提示)。因此,它将首先尝试匹配该规则,如果成功,它将实际匹配该规则并执行所有相关操作(
memoize
选项通过记住给定输入位置的特定成功规则,而不是重复整个匹配过程来避免这一点)
例如:
"a" AND ( "b" AND "c" )
为此,ANTLR必须:
- 匹配
“a”
- 确定是否可以使用内部规则匹配
和
- 为此,它尝试匹配内部规则
匹配,和
表示转到(
和_thing
- 要匹配
,它必须:和\u thing
- 匹配
和(
“b”
- 确定是否可以使用内部规则匹配
和
- 为此,它尝试将内部规则与
和“c”匹配
- 谓词成功-
与内部规则匹配且“c”
- 为此,它尝试将内部规则与
- 将内部规则与
和“c”匹配
- 匹配
)
- 匹配
- 谓词成功-
匹配内部规则和(“b”和“c”)
- 将内部规则与
和(“b”和“c”)
匹配,和
表示转到(
和_thing
- 要匹配
,它必须:和\u thing
- 匹配
和(
“b”
- 确定是否可以使用内部规则匹配
和
- 为此,它尝试将内部规则与
和“c”匹配
- 谓词成功-
与内部规则匹配且“c”
- 为此,它尝试将内部规则与
- 将内部规则与
和“c”匹配
- 匹配
)
- 匹配
和“c”
匹配四次才能匹配输入,而嵌套有一个级别。如果有另一个级别,整个流程将重复两次,因此ANTLR将解析最后一部分八次
一个相关的注释-如果您使用语法谓词而不是回溯选项,您可以微调谓词包含的内容-在某些情况下,它不需要包含整个谓词规则。在上面的示例中,您可以告诉ANLTR在遇到
OP\u和时使用OP\u和和级别2\u事物规则无需检查和_level2_thing
是否匹配。请注意,您只能这样做,因为您知道和_level2_thing
将匹配,或者其他替代方案也将失败。如果您这样做错误,解析器将丢失并拒绝一个如果选择正确的替代方案则有效的输入tive.非常感谢@Jiri tusek。“然后ANTLR会告诉您语法不明确的地方。”-您是说在编译时,对吗?这里有一些关于删除回溯的信息。“告诉ANTLR尝试所有替代方法并首先使用匹配的方法”生成语法时,它会报告这些情况(不是在程序的编译时,而是在生成Java解析器类时)。我编辑了这篇文章,回答“如果第一个选项匹配,为什么它仍然回溯”——它不会回溯,但时间仍然是指数级的。
"a" AND ( "b" AND "c" )