使用 ANTLR4 解析字符串

Parse a string using ANTLR4

示例:(CHGA/B234A/B231

String:
        a) Designator: 3 LETTERS
        b) Message number (OPTIONAL): 1 to 4 LETTERS, followed by A SLASH (/) followed by 1 to 4 LETTERS, followed by 3 NUMBERS indicating the serial number.
        c) Reference data (OPTIONAL): 1 to 4 LETTERS, followed by A SLASH (/) followed by 1 to 4 LETTERS, followed by 3 NUMBERS indicating the serial number.

Result: 
 CHG
 A/B234
 A/B231

在语法文件中:

/*
 * Parser Rules
 */

tipo3: designador idmensaje? idmensaje?;
designador: PARENTHESIS CHG;
idmensaje: LETTER4 SLASH LETTER4 DIGIT3;

/*
 * Lexer Rules
 */

CHG     : 'CHG' ;

fragment DIGIT      : [0-9] ;
fragment LETTER     : [a-zA-Z] ;

SLASH               : '/' ;
PARENTHESIS         : '(' ;

DIGIT3              : DIGIT DIGIT DIGIT ;
LETTER4             : LETTER LETTER? LETTER? LETTER? ;

但是在测试 tipo3 规则时,它给了我以下信息:

line 1:1 missing 'CHG' at 'CHGA'

如何在 antlr4 中解析该字符串?

当您对为什么某个解析器规则不匹配感到困惑时,请始终从词法分析器开始。转储你的词法分析器在标准输出上产生的标记。方法如下:

// I've placed your grammar in a file called T.g4 (hence the name `TLexer`)
String source = "(CHGA/B234A/B231";
TLexer lexer = new TLexer(CharStreams.fromString(source));
CommonTokenStream stream = new CommonTokenStream(lexer);
stream.fill();

for (Token t : stream.getTokens()) {
  System.out.printf("%-20s `%s`%n",
      TLexer.VOCABULARY.getSymbolicName(t.getType()),
      t.getText().replace("\n", "\n"));
}

如果运行上面的 Java 代码,将打印出:

PARENTHESIS          `(`
LETTER4              `CHGA`
SLASH                `/`
LETTER4              `B`
DIGIT3               `234`
LETTER4              `A`
SLASH                `/`
LETTER4              `B`
DIGIT3               `231`
EOF                  `<EOF>`

如您所见,CHGA 变成了单个 LETTER4,而不是 CHG + LETTER4 标记。尝试将 LETTER4 更改为 LETTER4 : LETTER; 和 re-test。现在您将获得预期的结果。

在您当前的语法中 CHGA 将始终成为单个 LETTER4。这就是 ANTLR 的工作方式(词法分析器尝试为单个规则消耗尽可能多的字符)。您无法更改此设置。

你可以做什么,它将 multi-letter 规则的构造移动到解析器而不是词法分析器:

tipo3       : designador idmensaje? idmensaje?;
designador  : PARENTHESIS CHG;
idmensaje   : letter4 SLASH letter4 DIGIT3;
letter4     : LETTER LETTER? LETTER? LETTER?
            | CHG
            ;

CHG         : 'CHG' ;
LETTER      : [a-zA-Z] ;
SLASH       : '/';
PARENTHESIS : '(';
DIGIT3      : DIGIT DIGIT DIGIT;

fragment DIGIT : [0-9];

导致: