我正在使用ANTLR为PDF对象结构编写解析器,但是我遇到了解析混合了PDF Reference和Integer的字符串流的问题。
基本上,PDF Reference是这样的字符串:“10 0 R”(INTEGER SPACE INTEGER SPACE'R')。
这是我的语法文件(简化):
grammar Pdf;
options {
language=CSharp3;
backtrack=true;
}
public r returns [string val]
: ref {$val = $r.text;}
| INTEGER {$val = $r.text;}
;
ref
: INTEGER SPACE INTEGER SPACE 'R';
INTEGER
: DIGIT+;
SPACE: ' ';
fragment DIGIT
: '0'..'9'
;
这是测试代码(在C#中):
byte[] bytes = Encoding.ASCII.GetBytes("97 98 10 0 R 100 101");
MemoryStream stream = new MemoryStream(bytes);
ANTLRInputStream inputStream = new ANTLRInputStream(stream);
PdfLexer lexer = new PdfLexer(inputStream);
CommonTokenStream tokens = new CommonTokenStream(lexer);
PdfParser parser = new PdfParser(tokens);
string result = parser.r();
我希望结果是规则r中匹配的第一条规则(无论是ref还是INTEGER)。
例如:
如果输入=“97 98 10 0 R 100 101”:result =“97”
如果输入=“10 0 R 100 101”:result =“10 0 R”
无需遍历整个字符串流。只需匹配第一条规则,然后停止。
我是ANTLR的新手,无法弄清楚如何做到这一点。 我正在使用ANTLRWorks 1.4.3和antlr-dotnet-csharpruntime-3.4.1.9004。
感谢任何帮助!
答案 0 :(得分:1)
backtrack=true
仅适用于解析器规则:不是lexer规则。因此,当词法分析器偶然发现INTEGER SPACE
后跟其他而不是INTEGER
时,词法分析器将抛出错误/异常:它将 不 在REF
规则中回溯并改为创建INTEGER
和SPACE
令牌。
但是REF
不应该是一个词法分析器规则,而是一个解析器规则:
ref
: INTEGER SPACE INTEGER SPACE 'R'
;
我在Linux上,因此无法测试C#目标(至少,我从来没有能够在MonoDevelop内运行CSharp3
目标)。但这是一个Java演示:
grammar Pdf;
public r
: ( ref {System.out.println("ref = '" + $ref.text + "'");}
| INTEGER {System.out.println("INTEGER = '" + $INTEGER.text + "'");}
| SPACE {System.out.println("SPACE = '" + $SPACE.text + "'");}
)*
EOF
;
ref
: INTEGER SPACE INTEGER SPACE 'R'
;
INTEGER
: DIGIT+;
SPACE
: ' '
;
fragment DIGIT
: '0'..'9'
;
您可以使用类测试解析器:
import org.antlr.runtime.*;
public class Main {
public static void main(String[] args) throws Exception {
PdfLexer lexer = new PdfLexer(new ANTLRStringStream("97 98 10 0 R 100 101"));
PdfParser parser = new PdfParser(new CommonTokenStream(lexer));
parser.r();
}
}
如果您运行此类,则会打印以下内容:
INTEGER = '97'
SPACE = ' '
INTEGER = '98'
SPACE = ' '
ref = '10 0 R'
SPACE = ' '
INTEGER = '100'
SPACE = ' '
INTEGER = '101'
这与我的预期完全一样。