我正在使用ANTLR 2.7.6来解析另一个应用程序的混乱输出。可悲的是,我没有能力升级到ANTLR 3,即使它已经出现了很长一段时间。我将要解析的类型的日志文件更好地概念化为对象列表而不是对象树,并且可能非常大(> 100 MB)因此将其全部读取到一个AST中是不实际的。 (我的应用程序是多线程的,将同时处理六打到十几个这样的文件,因此内存将快速填满。)我希望能够从流中读出每个对象,以便我可以处理它们一个人。请注意,对象本身可以概念化为小树。有没有办法让我的ANTLR解析器像对象流,迭代器或那种性质的东西一样?
编辑:这是我想要解析器的概念示例。
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
;但这在概念上是我正在寻找的那种行为。)
答案 0 :(得分:1)
AFAIK,ANTLR v2.x缓冲了令牌的创建。 parser takes a TokenBuffer,its turn takes a TokenStream。然后,当解析器需要更多令牌时,此TokenStream
将通过其nextToken() method进行轮询。
换句话说,如果您将输入源作为文件提供,ANTLR不会读取整个文件并创建它的标记,但只有在需要时才创建(并丢弃)标记。
请注意,我从未使用过ANTLR 2.x,所以我错了。你有没有看到不同的东西?如果是这样,你如何向ANTLR提供源:作为文件,还是作为一个大字符串?如果是后者,我建议改为提供文件。
假设你要解析一个由数字行组成的文件,用空格分隔(你想忽略它)。您还希望解析器逐行处理文件,因为一次收集所有数字会导致内存问题。
您可以通过让主解析器规则parse
返回每行的数字列表来执行此操作。如果达到EOF
(文件结尾),则只需返回null
而不是列表。
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);}
;
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)。