【问题标题】:Stack overflow when using parser combinators使用解析器组合器时的堆栈溢出
【发布时间】:2015-12-27 21:10:37
【问题描述】:
import scala.util.parsing.combinator._

object ExprParser extends JavaTokenParsers {
    lazy val name: Parser[_] = "a" ~ rep("a" | "1") | function_call
    lazy val function_call = name ~ "(" ~> name <~ ")"
}

对于function_call.parseAll("aaa(1)") 无限期重复。很明显是因为1不能intername,name进入function_call,它尝试name,进入funciton调用。您如何解决此类情况?

有一个解决方案可以将名称简化为简单的标识符

def name = rep1("a" | "1") 
def function_call = name ~ "(" ~ (function_call | name) ~ ")"

但我不喜欢这样做,因为name ::= identifier | function_call 在 VHDL 规范中是 BNF-ed,而function_call 可能在其他地方共享。出于同样的原因,左递归消除found here 是不可取的

def name: Parser[_] = "a" ~ rep("a" | "1") ~ pared_name
def pared_name: Parser[_] = "(" ~> name <~ ")" | ""

顺便说一句,我也想知道,如果我修复了错误,name.parseAll 会仅使用“aaa”作为名称规则中的第一个替代项还是使用整个“aaa(1)”?如何在仅消费 aaa 之前命名以消费整个 aaa(1)?我想我应该将 function_call 放在名称中的第一个替代项,但在这种情况下它会更加急切地堆栈溢出?

【问题讨论】:

    标签: scala parsing parser-combinators left-recursion


    【解决方案1】:

    一个简单的解决方案是使用 packrat 解析器:

    object ExprParser extends JavaTokenParsers with PackratParsers {
      lazy val name: PackratParser[_] = "a" ~ rep("a" | "1") | function_call
      lazy val function_call: PackratParser[_] = name ~ "(" ~> name <~ ")"
    }
    

    输出:

    scala> ExprParser.parseAll(ExprParser.function_call, "aaa(1)")
    res0: ExprParser.ParseResult[Any] =
    [1.5] failure: Base Failure
    
    aaa(1)
        ^
    

    【讨论】:

    • 为什么这会突然解决问题?
    猜你喜欢
    • 1970-01-01
    • 2015-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-26
    • 2023-04-11
    • 2012-01-11
    • 2020-08-20
    相关资源
    最近更新 更多