ANTLR4:一次性匹配所有输入备选方案

ANTLR4:一次性匹配所有输入备选方案,antlr4,Antlr4,在ANTLR中,我怎样才能制定一个规则,在任何顺序中只匹配所有备选方案一次 i、 e 我希望“示例”和“示例2”只匹配一次,然后再转到下一条规则 应匹配以下各项的输入: example example2 example example example2 或 但不包括: example example2 example example example2 在ANTLR中,我怎样才能制定一个规则,在任何顺序中只匹配所有备选方案一次 “所有备选方案只需一次”只是规则:altA altB altC

在ANTLR中,我怎样才能制定一个规则,在任何顺序中只匹配所有备选方案一次

i、 e

我希望“示例”和“示例2”只匹配一次,然后再转到下一条规则

应匹配以下各项的输入:

example
example2
example
example
example2

但不包括:

example
example2
example
example
example2
在ANTLR中,我怎样才能制定一个规则,在任何顺序中只匹配所有备选方案一次

“所有备选方案只需一次”只是
规则:altA altB altC…
。这是最简单的部分。要求
规则
接受任何安排中的所有备选方案
altA
altB
altC
等意味着适应每种安排。对于小数字来说,手动处理这个问题非常简单(
规则:(altA altB | altB altA);
)。但我知道没有自动的快捷方式来自动处理所有的排列

这里有一些方法,以防没有内置的方法,并且假设您不能放松您的需求。注意事项:我不知道你的问题的全部范围;我不知道你的语法;我不知道你为什么想要你想要的东西;我不知道您更喜欢哪一类解决方案,除了您可能希望它比这些选项更简单之外


首先,您可以咬紧牙关,自己生成匹配的所有置换,可以手动生成,也可以运行置换生成器生成。然后,ANTLR将以其理解的方式获得您想要的东西。它很粗糙但很有效:它是直接的ANTLR语法,因此没有像下面的选项那样涉及外部代码

例如,假设您有一个规则
字段
,该字段处理输入,如
“public static final x”
,需要所有三个修饰符,但没有特定顺序。排列如下所示:

field : modifiers ID EOF;

modifiers
    : PUBLIC STATIC FINAL //ABC
    | PUBLIC FINAL STATIC //ACB
    | STATIC PUBLIC FINAL //BAC
    | STATIC FINAL PUBLIC //BCA
    | FINAL PUBLIC STATIC //CAB
    | FINAL STATIC PUBLIC //CBA
    ;
到此为止。没有外部代码,没有谓词,什么都没有


其次,您可以在语法中使用语义谓词,以确保提供并匹配所有匹配项,而不存在重复项。编写谓词本身有多种方法,但归根结底是跟踪匹配的内容(以防止重复),然后测试规则是否匹配了它所期望的所有部分。以下是一个基本示例,遵循与前一个相同的要求:

field 
    locals [java.util.HashSet<String> names = new java.util.HashSet<String>();]
    : modifiers ID EOF;

modifiers
    //Ensure that the full number of modifiers have been provided
    : {$field::names.size() < 3}? modifier modifiers
    | {$field::names.size() == 3}? //match nothing once we have (any) three modifiers
    ;

modifier
    //Ensure that no duplicates have been provided
    : {!$field::names.contains("public")}? PUBLIC {$field::names.add("public");}
    | {!$field::names.contains("static")}? STATIC {$field::names.add("static");}
    | {!$field::names.contains("final")}? FINAL {$field::names.add("final");}
    ;

//调用代码的片段
//初始化lexer和解析器
addParseListener(新的MyGrammarBaseListener(){
@凌驾
public void exitField(FieldContext ctx){
//字段规则已完成。让我们验证是否没有修饰符
//这是重复的。
//要检查重复项,请确保指定了所有修饰符。
//TODO相应地记录错误。
}
});
//调用解析器。
parser.field();
语法保持干净。修饰符可以在输入中以任意数量和顺序出现在
ID
之前。调用代码通过它选择的任何方式执行测试,记录它想要的任何错误


下面是一个例子,它将我提到的三个选项结合在一起,让我对我所说的有一个更清晰的概念

修饰语
语法修饰语;
//硬编码版本:指定所有排列//
置换字段:置换修饰符ID EOF;
置换修饰语
:PUBLIC STATIC FINAL//ABC
|公共最终静态//ACB
|静态公开决赛//BAC
|静态最终公共//BCA
|最终公共静态模拟
|最终静态公共//CBA
;
//谓词版本:使用语义谓词防止重复,并确保提供了所有修饰符//
谓词字段
locals[java.util.HashSet name=new java.util.HashSet();]
:谓词修改器ID EOF;
谓词修饰词
//确保已提供全部数量的修改器
:{$predicateField::names.size()<3}?谓词修改器谓词修改器
|{$predicateField::names.size()==3}//当我们有(任意)三个修饰符时,不匹配任何内容
;
谓词修改器
//确保未提供任何副本
:{!$predicateField::names.contains(“public”)}?PUBLIC{$predicateField::names.add(“PUBLIC”);}
|{!$predicateField::names.contains(“static”)}?静态{$predicateField::names.add(“STATIC”);}
|{!$predicateField::names.contains(“final”)}?FINAL{$predicateField::names.add(“FINAL”);}
;
//监听器版本:当解析器调用监听器时,测试所有内容//
listenerField:listenerModifier*ID EOF;
李斯特修饰语
:公众
|静止的
|决赛
;
公众:"公众";;
静态:“静态”;
决赛:“决赛”;
福:‘福’;
ID:[a-zA-Z]+;
WS:[\r\n\t]+->跳过;
ModifiersTest.java
import java.util.ArrayList;
导入java.util.HashSet;
导入java.util.List;
导入org.antlr.v4.runtime.antlInputStream;
导入org.antlr.v4.runtime.BaseErrorListener;
导入org.antlr.v4.runtime.CommonTokenStream;
导入org.antlr.v4.runtime.RecognitionException;
导入org.antlr.v4.runtime.Recognizer;
导入org.antlr.v4.runtime.misc.Nullable;
公共类修饰符测试{
公共静态void main(字符串[]args){
运行(“公共静态最终x”,“确定”);
运行(“最终静态公共x”,“确定”);
运行(“静态公共静态最终x”,“修改器太多”);
运行(“静态x”,“缺少修改器”);
运行(“最终x”,“缺少和重复的修改器”);
}
私有静态无效运行(字符串代码、字符串标题){
System.out.printf(“%n---%n**输入:%s**%n%n\t%s%n%n”,标题,代码);
System.out.println(“**置换输出**\n”);
运行置换测试(代码);
System.out.println();
System.out.println(“**谓词输出**\n”);
运行谓词测试(代码);
System.out.println();
System.out.println(“**侦听器输出**\n”);
runListenerTest(代码);
System.out.println();
}
专用静态无效运行置换测试(字符串代码){
//partial grammar

field : modifier* ID EOF; //accept any modifiers in any order

modifier  
    : PUBLIC
    | STATIC
    | FINAL
    ;
public static final x
(done)
(done)
(No duplicate modifiers detected)
(No missing modifiers detected)
(done)
final static public x
(done)
(done)
(No duplicate modifiers detected)
(No missing modifiers detected)
(done)
static public static final x
extraneous input 'static' expecting 'final' at (1, 14)
(done)
no viable alternative at input 'static' at (1, 14)
(done)
Detected duplicate modifiers : [static]
(No missing modifiers detected)
(done)
static x
no viable alternative at input 'staticx' at (1, 7)
(done)
no viable alternative at input 'x' at (1, 7)
(done)
(No duplicate modifiers detected)
Detected missing modifiers : [final, public]
(done)
final final x
no viable alternative at input 'finalfinal' at (1, 6)
(done)
no viable alternative at input 'final' at (1, 6)
(done)
Detected duplicate modifiers : [final]
Detected missing modifiers : [static, public]
(done)
items : (a | b | c)*;
@Override
public void enterItems(ItemsContext ctx) {
    if (ctx.a().size() != 1) {
        // report error
    } else if (ctx.b().size() != 1) {
        // report error
    } else ...
}