【问题标题】:ANTLR parser, can I stop at first match?ANTLR 解析器,我可以在第一次匹配时停止吗?
【发布时间】:2011-12-28 11:34:48
【问题描述】:

我正在使用 ANTLR 编写 PDF 对象结构的解析器,但在解析混合了 PDF Reference 和 Integer 的字符串流时遇到了问题。

基本上,PDF 参考是这样的字符串:“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”:结果=“97”

  • 如果输入=“10 0 R 100 101”:结果=“10 0 R”

无需遍历整个字符串流。只需匹配第一条规则,然后停止。

我是 ANTLR 的新手,不知道该怎么做。 我正在使用 ANTLRWorks 1.4.3 和 antlr-dotnet-csharpruntime-3.4.1.9004。

感谢任何帮助!

【问题讨论】:

    标签: antlr antlr3


    【解决方案1】:

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

    但是REF 不应该是一个词法分析器规则,而是一个解析器规则:

    ref
     : INTEGER SPACE INTEGER SPACE 'R'
     ;
    

    编辑

    我在 Linux 上,因此无法测试 C# 目标(至少,我从未能够让 CSharp3 目标在 MonoDevelop 中运行)。但这里有一个 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'
    

    这和我预期的完全一样。

    【讨论】:

    • 我将 REF 更改为 ref,但它不起作用。虽然有些不同,但现在标记变成了:97、SPACE、98、SPACE、10、SPACE、0、SPACE、'R'、SPACE、101、EOF。它只识别 INTEGER,而不识别 ref。
    • @sun1991,当我测试它时一切正常。请参阅我的编辑
    • @Kiers,我可以在我的机器上的 C# 输出下复制结果,这对我来说是一大步,谢谢!抱歉,我的问题没有说清楚,但我的初衷不是使用规则 r:(...)* 来遍历所有字符串流。我希望 r() 只返回它匹配的第一个规则,无论是 ref 还是 INTEGER。如果输入为“10 0 R 100 101”,则返回“ref=10 0 R”并停止,如果输入为“97 98 10 0 R”,则返回“INTEGER=97”并停止。我尝试删除规则 r 周围的括号和 *,但同样,它没有返回任何内容。
    猜你喜欢
    • 2020-11-09
    • 1970-01-01
    • 2014-12-04
    • 2022-12-03
    相关资源
    最近更新 更多