首页 > 解决方案 > 如何使用 Antlr4 停用令牌

问题描述

我必须用 antlr4 解析一个由许多数据块组成的文本文件,每个数据块都有一个数据块头(一行)和几个数据行,(1..*)行。

数据块标头始终以位于行的第一个位置的“1”为星号,然后是几个字母数字字段。

DataRow 也是由字母数字字段 (dataFields) 组成,字符 '1' 可以是第一个 dataField 但永远不会位于行的第一个位置。

这是要解析的输入示例:

1   DataHeaderField1 datafield2 DataBlock1
    DB1_Row1_F1 DB1_Row1_F2    DB1_Row1_F3  DataBlock1
    DB1_Row2_F1 DB1_Row2_F2    DB1_Row2_F3  DataBlock1

1   DataHeaderField1 datafield2 DataBlock2
    DB2_Row1_F1 DB2_Row1_F2    DB2_Row1_F3  DataBlock2
    DB2_Row2_F1 DB2_Row2_F2    DB2_Row2_F3  DataBlock2
    DB2_Row3_F1 DB2_Row3_F2    DB2_Row3_F3  DataBlock2

....

我试过的语法是:

grammar ReadDataBlocks;
start_parsing: dataBlock+ EOF;
dataBlock: commonHeader  row+;
commonHeader: ONE_AT_FIRST_POS APLHANUMERIC* NL ;
row: APLHANUMERIC+ NL;

ONE_AT_FIRST_POS:   '1' {getCharPositionInLine() == 1}?;

APLHANUMERIC : (LETTER
                |
                DIGIT)+;
DIGIT: [0-9];
LETTER: [a-zA-Z];
NL: '\r'? '\n';
ESPACES : [ \t]+ -> skip;

为了解析文件,我在词法分析器中停用了标记,如我的语法所示,通过在 DIGIT 标记之前指定标记 ONE_AT_FIRST,因此在任何时候在第一个位置检测到“1”时都不会被解析为 DIGIT。

问题是,当解析器运行位于任何其他位置的“1”时,仍然标识为 ONE_AT_FIRST_POS 并抛出以下消息:

IntelliJ Idea Antlr 插件的输出

标签: javaantlr4dsl

解决方案


运行后:

public class Main {

    public static void main(String[] args) {

        String source = "1   headerData1 headData2 HeadDataN\n    row1Data Row2Data 1 333 rowNData";
        Lexer lexer = new ReadDataBlocksLexer(CharStreams.fromString(source));
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        tokens.fill();

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

我得到以下输出:

ONE_AT_FIRST_POS     `1`
APLHANUMERIC         `headerData1`
APLHANUMERIC         `headData2`
APLHANUMERIC         `HeadDataN`
NL                   `
`
APLHANUMERIC         `row1Data`
APLHANUMERIC         `Row2Data`
APLHANUMERIC         `1`
APLHANUMERIC         `333`
APLHANUMERIC         `rowNData`
EOF                  `<EOF>`

我认为您在添加谓词后忘记重新生成解析器类。


推荐阅读