要匹配的 ANTLR 解析器规则:x 和/或 y 和/或 z 以任何顺序

问题描述

使用 ANTLR,有没有一种方法可以编写解析器规则,以便它可以在不编写 Java 的情况下以任何顺序表达:x 和/或 y 和/或 z。例如,它应该匹配:“x y”、“y z”和“x y z”,但不匹配“x x y”。我能想到的最好的规则是下面的规则,但是我需要在树行者中检查“x x y”。

context = {'latestPost': latest}

解决方法

虽然你可以做一些类似于:

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;

或者(不那么荒谬):

rule: x? y? z?
    | x? z? y?
    | y? x? z?
    | y? z? x?
    | z? x? y?
    | z? y? x?
    ;

我怀疑您的示例比您的实际应用程序简单得多,而且这种方法会变得太乏味(这已经变得很荒谬了)。

您也可以使用语义谓词来研究某些东西,但这会将您的语法锁定到特定的目标语言。 (它也会使你的语法复杂化。)

总的来说,我发现 ANTLR 用户(一般来说是解析器编写者)经常过于努力地将“所有规则”编码到语法中。

这看起来不错,但它会导致语法的很多复杂性,并导致“不太理想”的错误消息(因为它们来自解析器 (ANTLR) 本身)。>

我认为你会发现最好保持一个像你一样的规则,它会创建一个 ParseTree 来准确地表示解释(也就是“解析”)输入的正确方法。然后,您将这样的规则视为语义关注点(而不是句法关注点(解析器的领域))。

这意味着您将编写类似验证侦听器之类的内容,它会针对您的解析树运行,并且您可以多次检查相同子规则的使用情况。如果您遇到它,您可以编写一个对最终用户更有用的非常具体的错误消息。

,

我能想到的最好的办法是......

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();
    }
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...