要匹配的ANTLR解析器规则:x和/或y和/或z的任意顺序
使用ANTLR,有没有一种方法可以编写解析器规则,这样它就可以在不编写Java的情况下以任意顺序表示:x和/或y和/或z。例如,它应该匹配:“xy”、“yz”和“xyz”,而不是“xxy”。我能想到的最好的办法是下面的规则,但是我需要在树行者中检查“x x y” 虽然你可以做一些类似于:要匹配的ANTLR解析器规则:x和/或y和/或z的任意顺序,antlr,antlr4,Antlr,Antlr4,使用ANTLR,有没有一种方法可以编写解析器规则,这样它就可以在不编写Java的情况下以任意顺序表示:x和/或y和/或z。例如,它应该匹配:“xy”、“yz”和“xyz”,而不是“xxy”。我能想到的最好的办法是下面的规则,但是我需要在树行者中检查“x x y” 虽然你可以做一些类似于: rule: x | y | z | x y | y x | x z | z x | y z | z y | x y z | x z
rule: x
| y
| z
| x y
| y x
| x z
| z x
| y z
| z y
| x y z
| x z y
| y x z
| y z x
| z x y
| z y x;
或者(稍微不那么荒谬):
我怀疑您的示例比实际应用程序简单得多,而且这种方法会变得太单调乏味(它已经变得荒谬了)
您也可以使用语义谓词研究某些内容,但这会将语法锁定到特定的目标语言。(这也会使你的语法变得复杂。)
总的来说,我发现ANTLR用户(一般来说是解析器编写者)经常试图将“所有规则”编码到语法中
这似乎很好,但它会导致语法的复杂性,并导致“不太理想”的错误消息(因为它们来自解析器(ANTLR)本身)
我认为您会发现,最好保留像您这样的规则,它将创建一个ParseTree,准确地表示正确的解释(也称为“parse”)输入的方法。然后,你认为这样的规则是一个语义关注点(而不是语法关注点(语法分析器的域)。
这意味着您将编写类似于验证侦听器的东西,该侦听器将针对您的解析树运行,并且您可以多次检查同一子规则的使用情况。如果遇到它,您可以编写一条对最终用户更有用的非常具体的错误消息。我能想到的最好方法是
grammar Sandbox;
@members {
boolean a, b, c;
}
start: ( 'test' test )+ EOF ;
test:
{a=b=c=true;} // Reset
( {a}? a {a=false;}
| {b}? b {b=false;}
| {c}? c {c=false;}
)* ;
a: 'a';
b: 'b';
c: 'c';
WS : [ \t\r\n]+ -> skip ;
还有试驾
package sandbox;
import org.antlr.v4.runtime.*;
public class Main {
public static void main(String[] args) {
new Main();
}
private Main() {
System.out.println("Should be OK...");
test("test a b c test c test c b a test c");
System.out.println("Should fail...");
test("test c a a");
}
private void test(String toTest) {
final CharStream cs = CharStreams.fromString(toTest);
final SandboxLexer lexer = new SandboxLexer(cs);
final CommonTokenStream tokens = new CommonTokenStream(lexer);
final SandboxParser parser = new SandboxParser(tokens);
parser.start();
}
}
Thx Mike。遗憾的是,你是对的,有三个例子我想分别对3、4和7个变量使用“技巧”,所以组合方法不太管用!我本来计划在解析器之外处理这个问题,但结果也很困难-我有5个侦听器(!)目前,我希望尽可能多地返回到解析器中。也许现在有人会有一个想法让我不知所措,但我建议有多个侦听器并没有那么糟糕,更像是“ANTLR方式”。我总是发现我需要一个验证侦听器来进行语义错误检查。如果现有侦听器中有一个正在进行验证,我会将其添加到其中。根据您的用例,我不知道5个侦听器是“坏事”,特别是如果它有助于代码的清晰性,从而实现关注点的分离。(TBC)我发现,有时我会故意将某些规则排除在语法之外,只要语法可以给我一个正确解释输入的ParseTree。然后,我就可以提供比仅查看语法规则就可以预期ANTLR生成的更好的错误消息。(另一个技巧是为已知的问题结构实际设置规则,以便您能够识别它们并给出更有意义的错误消息。)我已经在下面添加了一个我能想到的最佳答案,它看起来比我想象的要好。我可以在不同的规则中重用布尔值,我不打算在Java中使用它……这就是我提到的语义谓词解决方案。(并且没有费心写:)).而且,是的,它不像我想象的那么丑陋
grammar Sandbox;
@members {
boolean a, b, c;
}
start: ( 'test' test )+ EOF ;
test:
{a=b=c=true;} // Reset
( {a}? a {a=false;}
| {b}? b {b=false;}
| {c}? c {c=false;}
)* ;
a: 'a';
b: 'b';
c: 'c';
WS : [ \t\r\n]+ -> skip ;
package sandbox;
import org.antlr.v4.runtime.*;
public class Main {
public static void main(String[] args) {
new Main();
}
private Main() {
System.out.println("Should be OK...");
test("test a b c test c test c b a test c");
System.out.println("Should fail...");
test("test c a a");
}
private void test(String toTest) {
final CharStream cs = CharStreams.fromString(toTest);
final SandboxLexer lexer = new SandboxLexer(cs);
final CommonTokenStream tokens = new CommonTokenStream(lexer);
final SandboxParser parser = new SandboxParser(tokens);
parser.start();
}
}