ANTLR 正确检测第一行模式

ANTLR properly detecting mode for 1st line

我有以下解析器

parser grammar T5Parser ;

options {
    tokenVocab = T5Lexer ;
}

root: line (EOL? line)* EOL? EOF;

line: commandLine | dataLine  ;

dataLine: CDataLine;

commandLine: StartCmd+ command ;

command
    : halt
    | note
    | read
    | end
;

halt    :   CHALT ;
end     :   CEND DataLine? ;
note    :   CNOTE DataLine? ;
read    :   CREAD fileName=StringLiteral ;

和词法分析器

lexer grammar T5Lexer ;

StartCmd: '@';

CDataLine: BOL ~'@' ~[\r\n]+;

EOL:                EOL_F -> mode(DEFAULT_MODE);

WS:     [ \t]+ -> channel(HIDDEN);
BOL :   [\r\n\f]+ ;

DOT:   [.];
COMMA: ',';

CHALT  :  'HALT' ;
CEND   :  'END'  -> pushMode(DataMode);
CNOTE  :  'NOTE' -> pushMode(DataMode);
CREAD  :  'READ';

StringLiteral       :   DblQuotedString | SglQuotedString;

fragment DblQuotedString    :   [C]*'"' ( '\'. | '""' | ~('"'| '\') )* '"';
fragment SglQuotedString    :   [C]*'\'' ('\'. | '\'\'' | ~('\'' | '\'))* '\'';
fragment BackQuotedString   :   [C]*'`' ( '\'. | '``' | ~('`'|'\'))* '`';

//=======================================
mode DataMode     ;

DmPOP :   [ ,] -> popMode;
DmEOL:    EOL_F -> type(EOL), popMode;
DataLine: ( ~[\r\n]*? '-' EOL_F)* ~[\r\n]+;

//=======================================
fragment NL:         '\r'? '\n';
fragment EOL_F:      [ ]* NL;

解析语法的以下方面工作正常

@NOTE 
@NOTE with data
@READ 'file.one'
Test data line
@END
@HALT

也许有更好的方法来匹配“行不以某物开头”,唉,这是我经过数小时的搜索所能想到的最好的方法,但是有了这个解决方案 我无法理解的方面是当“自由格式数据”出现在输入的第一行并且没有 BOL 时。

关于如何解决这个问题的任何提示?

TIA - 亚历克斯

像这样的东西就可以了:

lexer grammar T5Lexer;

CommandStart
 : '@' -> mode(CommandMode)
 ;

DataLine
 : ~[@\r\n] ~[\r\n]*
 ;

EOL
 : [ \t]* ( '\r'? '\n' | '\r' )
 ;

mode CommandMode;

 HALT          : 'HALT' ;
 END           : 'END'  -> mode(DEFAULT_MODE);
 NOTE          : 'NOTE' -> mode(DEFAULT_MODE);
 READ          : 'READ';
 Spaces        : [ \t]+ -> skip;
 StringLiteral : '\'' ( '\'\'' | ~['\r\n] )* '\'';
 CM_NewLine    : EOL -> type(EOL), mode(DEFAULT_MODE);

使用语法分析器:

parser grammar T5Parser;

options {
 tokenVocab=T5Lexer;
}

root
 : line ( EOL+ line )* EOL* EOF
 ;

line
 : commandLine
 | DataLine
 ;

commandLine
 : CommandStart command
 ;

command
 : halt
 | note
 | read
 | end
 ;

halt : HALT;
end  : END DataLine?;
note : NOTE DataLine?;
read : READ StringLiteral;

这将解析输入:

first line
@NOTE 
@NOTE with data
@READ 'file.one'
Test data line
@END
@HALT

像这样: