如何使用antlr中的嵌套字符串分隔符解析PDF字符串?

如何使用antlr中的嵌套字符串分隔符解析PDF字符串?,pdf,antlr4,Pdf,Antlr4,我正在解析PDF内容流。字符串由括号分隔,但可以包含嵌套的未转义括号。从PDF参考文件: 文字字符串应写为括号内任意数量的字符。除不平衡括号(左括号(28h)和右括号(29h))和反斜杠(反斜杠(5Ch))外,任何字符都可以出现在字符串中,应按照本款的规定进行特殊处理。字符串中平衡的括号对不需要特殊处理 例1: The following are valid literal strings: (This is a string) (Strings may contain newlines an

我正在解析PDF内容流。字符串由括号分隔,但可以包含嵌套的未转义括号。从PDF参考文件:

文字字符串应写为括号内任意数量的字符。除不平衡括号(左括号(28h)和右括号(29h))和反斜杠(反斜杠(5Ch))外,任何字符都可以出现在字符串中,应按照本款的规定进行特殊处理。字符串中平衡的括号对不需要特殊处理

例1:

The following are valid literal strings: 
(This is a string)
(Strings may contain newlines
and such.)
(Strings may contain balanced parentheses ( ) and special characters (*!&}^% and so on).)
似乎将lexer模式推到堆栈上就是解决这个问题的方法。这是我的词法分析器和解析器的精简版本

lexer grammar PdfStringLexer;

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.
OPEN_PAREN: '(' -> more, pushMode(STR) ; 

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

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

mode STR;

LITERAL_STRING : ')' -> popMode ;
STRING_OPEN_PAREN: '(' -> more, pushMode(STR) ; 
TEXT : . -> more ;
处理此文件时:

(Oliver’s Army) Tj
((What’s So Funny ’Bout) Peace, Love, and Understanding) Tj
我收到此错误并解析树:

line 2:24 extraneous input ' Peace, Love, and Understanding)' expecting 'Tj'

因此,
pushMode
可能不会将重复模式推送到堆栈上。如果不是,处理嵌套括号的方法是什么


编辑 我遗漏了关于字符串中转义序列的说明:

在文字字符串中,反向SOLIDUS用作转义字符。紧跟在索利多金币背面的字符决定了其精确解释,如表3所示。如果反向索利多线后面的字符不是表3所示的字符之一,则应忽略反向索利多线

表3列出了
\n
\r
\t
\b
退格(08h),
\f
格式提要(FF),
\(
\)
\
,以及
\ddd
字符码ddd(八进制)

出现在文字字符串中且没有前面的反向索利多士的行尾标记应被视为字节值(0Ah),无论行尾标记是回车符(0Dh)、换行符(0Ah)还是两者兼而有之

例2:

(These \
two strings \
are the same.)
(These two strings are the same.)
例3:

(This string has an end-of-line at the end of it. 
)
(So does this one.\n)
我是否应该使用此字符串定义:

STRING
 : '(' ( ~[()]+ | STRING )* ')'
 ;

在我的代码中不使用模式并处理转义序列,或者为字符串创建一个lexer模式并在语法中处理转义序列?

您可以使用词汇模式来实现这一点,但在这种情况下并不需要。您可以简单地定义如下所示的lexer规则:

STRING
 : '(' ( ~[()]+ | STRING )* ')'
 ;
使用转义序列,您可以尝试:

STRING
 : '(' ( ~[()\\]+ |  ESCAPE_SEQUENCE | STRING )* ')'
 ;

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

很漂亮,谢谢。我没有在字符串中包含有关转义序列的说明:在文字字符串中,反向索利多金币用作转义字符。紧跟在索利多金币背面的字符决定了其精确解释,如表3所示。如果反向索利多线后面的字符不是表3中所示的字符之一,则应忽略反向索利多线。“您是否会在代码中而不是在解析器中处理转义序列?(或者我应该对此提出一个新问题?)@SSteve请随意编辑您的原始问题,添加反斜杠。请确保包含具体的例子。
STRING
 : '(' ( ~[()\\]+ |  ESCAPE_SEQUENCE | STRING )* ')'
 ;

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