如何在Antlr中使用嵌套的字符串定界符来解析PDF字符串?

时间:2019-07-12 19:08:14

标签: pdf antlr4

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

  

文字字符串应写成用括号括起来的任意数量的字符。除不平衡括号(左括号(28h)和右括号(29h))和反斜杠(RESOLE SOLIDUS(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 ;

parser grammar PdfStringParser;

options { tokenVocab=PdfStringLexer; } 

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

当我处理此文件时:

(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'

Parse tree

因此,pushMode可能不会将重复模式推入堆栈。如果没有,处理嵌套括号的方式将是什么?


编辑

我省略了有关字符串中转义序列的说明:

  

在文字字符串中,REVERSE SOLIDUS用作转义字符。如表3所示,REVERSE SOLIDUS之后的字符确定其精确解释。如果REVERSE SOLIDUS之后的字符不是表3中所示的字符之一,则应忽略REVERSE SOLIDUS。

表3列出了\n\r\t\b退格键(08h),\f换页(FF),\(\)\\\ddd字符代码 ddd (八进制)

  

出现在文字字符串中且没有前面的RESOLE SOLIDUS的行尾标记应被视为字节值(0Ah),无论该行尾标记是否为CARRIAGE RETURN(0Dh), LINE FEED(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
 : '(' ( ~[()]+ | STRING )* ')'
 ;

在我的代码中没有模式并处理转义序列,还是为字符串创建词法分析器模式并在语法中处理转义序列?

1 个答案:

答案 0 :(得分:1)

您可以使用词法模式执行此操作,但是在这种情况下,并不需要它。您可以像这样简单地定义词法分析器规则:

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

使用转义序列,您可以尝试:

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

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