2016-11-13 93 views
0

我在ANTLR的语法分析器我Xamarin.ios C#项目如下:ANTLR的解析器StackOverflowException

mathToken 
    : DIGIT    #Digit 
    | NULL    #Null 
    | LESSTHAN   #LessThan 
    | GREATERTHAN  #GreaterThan 
    | anyLessThanOrEqual #LessThanOrEqual 
    // about 30 more options here 

mathTokenList 
    : mathToken mathTokenList #CompoundMathTokens 
    | mathToken     #SingleMathToken 
    ; 

这对于10代币,100,甚至1000的列表但是,一旦名单的伟大工程得到足够长的时间,它会导致一个StackOverflowException,所生成的MathTokenList递归调用自身,一些听众代码顶部:

MyNamespace.HandleToken(MyTokenClass parserToken, List<MyOtherTokenClass> buildingList) in MyNamespace.ManualFileParser.cs:58 
MyNamespace.CustomStringReaderParseListener.VisitDefault(Antlr4.Runtime.Tree.TerminalNodeImpl node) in MyNamespace.CustomStringReaderParseListener.cs:228 
MyNamespace.CustomStringReaderParseListener.VisitTerminal(Antlr4.Runtime.Tree.TerminalNodeImpl node) in MyNamespace.CustomStringReaderParseListener.cs:94 
Antlr4.Runtime.Parser.Consume() 
Antlr4.Runtime.Parser.Match(int ttype) 
Antlr.StringReaderParser.mathToken() 
Antlr.StringReaderParser.mathTokenList() // lots of calls here . . . seems to be 
Antlr.StringReaderParser.mathTokenList() // one for each token. 
Antlr.StringReaderParser.mathTokenList() // (in antlr generated code) 

是否有可能进行重组解析器语法来避免这种问题?或者我需要做更多的事情,以便解析器永远不会看到很长的mathTokens列表?

在解析器看到它们之前,我可以通过组合数字列表来为这个问题提供创可贴。但它最终可能会与其他一些令牌类型一起发生。

+1

什么,当你尝试这种情况: 'mathTokenList :mathToken mathToken + #CompoundMathTokens | mathToken #SingleMathToken ;' ? –

回答

1

你不能完全避免这个问题。每个规则调用实际上是生成的解析器中的函数调用(递归下降解析器原理)。如果你的输入只够复杂,你肯定会达到可用的堆栈限制。在大多数(所有?)编译器中,您可以增加应用程序的堆栈空间,但这也仅在某种程度上有所帮助。

但是,@BartKiers建议您可以通过使用循环而不是递归来降低调用计数(这是编程中常用的一个原则)。 mathTokenList规则看起来很像您将如何在yacc/bison中定义列表。在ANTLR你可以使用循环运营商代替,使这个更好的阅读和更少的资源密集型:

mathTokenList: mathToken+; 

是去这里的路。这将在您的mathTokenList方法中执行的循环中结束(查看生成的解析器代码,有时非常有启发性)。