【问题标题】:How to make parboiled2 match the whole input?如何使 parboiled2 匹配整个输入?
【发布时间】:2015-02-05 11:41:44
【问题描述】:

我编写了以下 hello-world parboiled2 解析器:

class MyParser(val input: ParserInput) extends Parser {

 /*
  Expr     <- Sum
  Sum      <- Product ('+') Product)*
  Product  <- Value (('*') Value)*
  Value    <- Constant | '(' Expr ')'
  Constant <- [0-9]+
  */

  def Expr: Rule1[Int] = rule { Sum }

  def Sum: Rule1[Int] = rule { oneOrMore(Product).separatedBy(" + ") ~> ((products: Seq[Int]) => products.sum) }

  def Product: Rule1[Int] = rule { oneOrMore(Value).separatedBy(" * ") ~> ((values: Seq[Int]) => values.product) }

  def Value: Rule1[Int] = rule { Constant | ('(' ~ Expr ~ ')') }

  def Constant: Rule1[Int] = rule { capture(oneOrMore(Digit)) ~> ((digits: String) => digits.toInt) }

}

这主要按预期工作,例如它成功地将“1 + 2”解析为 3。

如果我给它输入无效的输入,例如“1 + (2”),我预计解析会失败。但它实际上成功了,结果为 1。

看起来 parboiled2 只是解析输入的一部分,而忽略了它无法解析的其余部分。这是预期的行为吗?有没有办法强制解析器解析整个输入,如果不能解析则失败?

【问题讨论】:

    标签: scala parsing parboiled parboiled2


    【解决方案1】:

    这是预期的行为。 parboiled2 是一个 PEG 解析器,如文档中 Common Mistakes 部分所述,它会吃掉所有能找到的东西。

    为避免此类问题,请确保您希望字符串末尾出现输入结束符号:

    def Expr: Rule1[Int] = rule { Sum ~ EOI }
    

    【讨论】:

    • 谢谢,将~ EOI 添加到根规则是一个不错的简单解决方案。其实我在README里找不到这个,好像很多初学者都会遇到的问题,所以我提交PR来补充一下。
    【解决方案2】:

    如果我输入“1+(2+3*4)+5”,解析将失败。定义另一个根规则并将 Expr 保留原样:

    def InputLine = rule { Expr ~ EOI }
    def Expr: Rule1[Int] = rule { Sum }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多