我可以让我的 ANTLR4 词法分析器从输入流中丢弃一个字符吗?

Can I make my ANTLR4 Lexer discard a character from the input stream?

我正在解析 PDF 流。在关于文字字符串对象的第 7.3.4.2 节中,PDF Reference 表示文字字符串中的反斜杠后面没有行尾字符、一到三个八进制数字或字符之一 "nrtbf()\" 应该被忽略。有没有办法让我的词法分析器中的 recover 方法在这种情况下忽略反斜杠?

这是我的简化解析器:

parser grammar PdfStreamParser;

options { tokenVocab=PdfSteamLexer; } 

array: LBRACKET object* RBRACKET ;
dictionary: LDOUBLEANGLE (NAME object)* RDOUBLEANGLE ;
string: (LITERAL_STRING | HEX_STRING) ;
object
    : NULL
    | array
    | dictionary
    | BOOLEAN
    | NUMBER
    | string
    | NAME
    ;

content : stat* ;

stat
    : tj
    ;

tj: ((string Tj) | (array TJ)) ; // Show text

这是词法分析器。 (根据 中的建议,我没有使用单独的字符串模式):

lexer grammar PdfStreamLexer;

Tj: 'Tj' ;
TJ: 'TJ' ;

NULL: 'null' ;

BOOLEAN: ('true'|'false') ;

LBRACKET: '[' ;
RBRACKET: ']' ;
LDOUBLEANGLE: '<<' ;
RDOUBLEANGLE: '>>' ;

NUMBER: ('+' | '-')? (INT | FLOAT) ;

NAME: '/' ID ;

// A sequence of literal characters enclosed in parentheses.
LITERAL_STRING: '(' ( ~[()\]+ | ESCAPE_SEQUENCE | LITERAL_STRING )* ')' ; 

// Escape sequences that can occur within a LITERAL_STRING
fragment ESCAPE_SEQUENCE 
    : '\' ( [\r\nnrtbf()\] | [0-7] [0-7]? [0-7]? )
    ;

HEX_STRING: '<' [0-9A-Za-z]+ '>' ; // Hexadecimal data enclosed in angle brackets

fragment INT: DIGIT+ ; // match 1 or more digits

fragment FLOAT:  DIGIT+ '.' DIGIT*  // match 1. 39. 3.14159 etc...
    |         '.' DIGIT+  // match .1 .14159
    ;

fragment DIGIT:   [0-9] ;        // match single digit

// Accept all characters except whitespace and defined delimiters ()<>[]{}/%
ID: ~[ \t\r\n\u000C\u0000()<>[\]{}/%]+ ;

WS: [ \t\r\n\u000C\u0000]+ -> skip ; // PDF defines six whitespace characters

我可以覆盖 PdfStreamLexer class 中的 recover 方法并在 LexerNoViableAltException 发生时得到通知,但我不确定如何(或者如果可能的话)忽略反斜杠和继续 LITERAL_STRING 标记化。

为了能够跳过部分字符串,您需要使用词法模式。这是一个快速演示:

lexer grammar DemoLexer;

STRING_OPEN
 : '(' -> pushMode(STRING_MODE)
 ;

SPACES
 : [ \t\r\n] -> skip
 ;

OTHER
 : .
 ;

mode STRING_MODE;

  STRING_CLOSE
   : ')' -> popMode
   ;

  ESCAPE
   : '\' ( [nrtbf()\] | [0-7] [0-7] [0-7] )
   ;

  STRING_PART
   : ~[\()]
   ;

  NESTED_STRING_OPEN
   : '(' -> type(STRING_OPEN), pushMode(STRING_MODE)
   ;

  IGNORED_ESCAPE
   : '\' . -> skip
   ;

可以在解析器中使用如下:

parser grammar DemoParser;

options {
  tokenVocab=DemoLexer;
}

parse
 : ( string | OTHER )* EOF
 ;

string
 : STRING_OPEN ( ESCAPE | STRING_PART | string )* STRING_CLOSE
 ;

如果您现在解析字符串 FU(abc(def)\@\))BAR,您将得到以下解析树:

如您所见,\) 留在树中,但省略了 \@