【问题标题】:ANTLR 2.7 Get a Stream of Objects from the ParserANTLR 2.7 从解析器获取对象流
【发布时间】:2011-07-28 16:23:29
【问题描述】:

我正在使用 ANTLR 2.7.6 来解析另一个应用程序的混乱输出。可悲的是,我没有能力升级到 ANTLR 3,尽管它已经推出了很长一段时间。我将要解析的那种日志文件比对象树更好地概念化为对象列表,并且可能非常大(>100 MB),因此将其全部读入一个 AST 是不切实际的。 (我的应用程序是多线程的,将一次处理六到十几个这样的文件,所以内存会很快填满。)我希望能够从流中读取这些对象中的每一个,这样我就可以处理它们一个一个。请注意,对象本身可以概念化为小树。有没有办法让我的 ANTLR 解析器像对象流、迭代器或类似的东西一样工作?

[见Javadoc for ANTLR 2。]

编辑:这是我想用解析器做什么的概念示例。

import java.io.FileReader;
import antlr.TokenStream;
import antlr.CharBuffer;
//...
FileReader fileReader = new FileReader(filepath);
TokenStream lexer = new MyExampleLexer(new CharBuffer(fileReader));
MyExampleParser parser = new MyExampleParser(lexer);
for (Object obj : parser)
{
    processObject(obj);
}

我是否使用了错误的 Antlr 解析器范例? (我意识到解析器没有实现Iterator;但这在概念上是我正在寻找的那种行为。)

【问题讨论】:

    标签: parsing antlr inputstream


    【解决方案1】:

    AFAIK,ANTLR v2.x 缓冲令牌的创建。 parser takes a TokenBuffer,在its turn takes a TokenStream。当解析器需要更多令牌时,然后通过其nextToken() method 轮询此TokenStream

    换句话说,如果您将输入源作为文件提供,ANTLR 不会读取整个文件并为其创建令牌,而是仅在需要时创建(并丢弃)令牌。

    请注意,我从未使用过 ANTLR 2.x,所以我可能是错的。你观察到不同的东西吗?如果是这样,您如何向 ANTLR 提供源代码:作为文件还是作为大字符串?如果是后者,我建议改为提供文件。

    编辑

    假设您要解析一个文件,该文件由带有数字的行组成,由空格分隔(您想忽略它)。您还希望解析器逐行处理文件,因为一次收集所有数字会导致内存问题。

    您可以通过让您的主解析器规则 parse 返回每​​行的数字列表来做到这一点。如果到达 EOF(文件结尾),您只需返回 null 而不是列表。

    使用 ANTLR 2.7.6 的演示:

    文件:My.g

    class MyParser extends Parser;
    
    parse returns [java.util.List<Integer> numbers]
    {
      numbers = new java.util.ArrayList<Integer>();
    }
      :  (n:Number {numbers.add(Integer.valueOf(n.getText()));})+ LineBreak
      |  EOF {numbers = null;}
      ;
    
    class MyLexer extends Lexer; 
    
    Number
      :  ('0'..'9')+
      ;
    
    LineBreak
      :  ('\r')? '\n'
      ;
    
    Space
      :  (' ' | '\t') {$setType(Token.SKIP);}
      ;
    

    文件:Main.java

    import antlr.*;
    
    public class Main {
      public static void main(String[] args) throws Exception {
        MyLexer lexer = new MyLexer(new java.io.StringReader("1 2 3\n4 5 6 7 8\n9 10\n"));
        MyParser parser = new MyParser(new TokenBuffer(lexer));
        int line = 0;
        java.util.List<Integer> numbers = null;
        while((numbers = parser.parse()) != null) {
          line++;
          System.out.println("line " + line + " = " + numbers);
        }
      }
    }
    

    要运行演示:

    *尼克斯

    java -cp antlr-2.7.6.jar antlr.Tool My.g
    javac -cp antlr-2.7.6.jar *.java
    java -cp .:antlr-2.7.6.jar Main
    

    或开启:

    窗口

    java -cp antlr-2.7.6.jar antlr.Tool My.g
    javac -cp antlr-2.7.6.jar *.java
    java -cp .;antlr-2.7.6.jar Main
    

    这将产生以下输出:

    line 1 = [1, 2, 3]
    line 2 = [4, 5, 6, 7, 8]
    line 3 = [9, 10]
    

    警告

    任何尝试此代码的人,请注意这使用的是 ANTLR 2.7.6。除非您有非常令人信服的理由使用此版本,否则强烈建议使用 ANTLR 的最新稳定版本(在撰写本文时为 v3.3)。

    【讨论】:

    • 感谢您的回复。我看到你回答了很多关于 Antlr 的问题,所以我很高兴收到你的意见。也许这表明了一种更根本的无知。 AFAIK,你说的是对的;但是我如何利用解析器的结果呢?我是否在解析器本身中定义该代码?我宁愿让另一个类以类似于解析器使用 TokenStream 的方式使用解析器。
    • @Kazark,对不起,但我不确定我是否理解你。您能否编辑您的原始问题并提供一个(小)用例来说明您希望如何解析某些输入?
    • 哇,你太棒了。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2015-04-18
    • 2023-03-19
    • 2011-01-20
    • 2016-07-02
    • 1970-01-01
    • 2015-11-08
    • 1970-01-01
    • 2018-05-09
    相关资源
    最近更新 更多