ANTLR解析器,我可以在第一场比赛时停止吗?

时间:2011-12-28 11:34:49

标签: antlr antlr3

我正在使用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。

感谢任何帮助!

1 个答案:

答案 0 :(得分:1)

backtrack=true仅适用于解析器规则:不是lexer规则。因此,当词法分析器偶然发现INTEGER SPACE后跟其他而不是INTEGER时,词法分析器将抛出错误/异常:它将 REF规则中回溯并改为创建INTEGERSPACE令牌。

但是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'

这与我的预期完全一样。