如何使用 Antlr4 停用令牌
How to deactivate tokens with Antlr4
我必须用 antlr4 解析一个由许多数据块组成的文本文件,每个数据块都有一个数据块 Header(一行)和几个数据行,(1..*) 行。
数据块 Header 始终在该行的第一个位置加上星号“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”都不会被解析作为数字。
问题在于,当解析器运行位于任何其他位置的“1”时,仍然标识为 ONE_AT_FIRST_POS 并抛出以下消息:
运行之后:
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>`
我想你在添加谓词后忘记重新生成解析器 类。
我必须用 antlr4 解析一个由许多数据块组成的文本文件,每个数据块都有一个数据块 Header(一行)和几个数据行,(1..*) 行。
数据块 Header 始终在该行的第一个位置加上星号“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”都不会被解析作为数字。
问题在于,当解析器运行位于任何其他位置的“1”时,仍然标识为 ONE_AT_FIRST_POS 并抛出以下消息:
运行之后:
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>`
我想你在添加谓词后忘记重新生成解析器 类。