我可以让我的ANTLR4 Lexer丢弃输入流中的字符吗?

时间:2019-07-16 01:28:31

标签: antlr4

我正在解析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

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

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类中的restore方法,并在发生LexerNoViableAltException时得到通知,但是我不确定如何(或者是否有可能)忽略反斜杠并继续使用LITERAL_STRING标记化

1 个答案:

答案 0 :(得分:1)

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

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,则将获得以下解析树:

enter image description here

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