Scala的解析器组合器在解析之前进行比较

时间:2019-02-18 12:47:38

标签: scala parsing

我正在寻找一种使用Scala解析器组合器的方法来与正则表达式匹配,然后再对其进行解析。

示例:

import scala.util.parsing.combinator.RegexParsers

object MetaCommandParser extends RegexParsers with App {

  def parseSub: Parser[Object] = (parseElement <~ "=>") ~ parseExpression.*

  def parseElement: Parser[Object] = """\w+""".r

  def parseOr: Parser[Object] = listElements

  def listElements: Parser[Object] = parseExpression ~ opt("|" ~ listElements)

  def parseExpression: Parser[Object] = parseElement | parseOr

  def parseMetaCommand(s: String) = {
    MetaCommandParser.parseAll(parseSub, s) match {
      case Success(result, _) => result
      case Failure(msg, _)    => throw new Exception("FAILURE: " + msg)
      case Error(msg, _)      => throw new Exception("ERROR: " + msg)
    }
  }

  println(parseMetaCommand("operation => test"));
}

类型:

sealed trait Command;
case class Sub(tag: Word, sub: List[Expression]) extends Command;
case class ReplaceBy(tag: Word, sub: List[Expression]) extends Command;

sealed trait Expression;
case class Or(elements: Set[Expression]) extends Expression;
case class Reference(tag: String) extends Expression;
case class Option(element: Expression) extends Expression;
case class Word(tag: String) extends Expression;
case object Empty extends Expression;

如果我使用以下表达式在parseSub上执行解析器: “操作=>测试”

我有一个StackOverflow。我的解析器很好地解析了Sub(Word(operation),Word(test)),但之后出现了错误。我认为解析器试图在parseExpression上计算一个空字符串以结束“ parseExpression。*”,但是在listElements中循环。如果我可以确保在调用parseExpression之前输入的内容有效,那么我认为它可以解决我的问题(parseValidString函数)!

因此,我试图验证我的条目与该正则表达式匹配,以避免无限循环,但我不知道如何做到这一点:/

谢谢!

1 个答案:

答案 0 :(得分:2)

您的parseExpressionlistElements规则是相互左递归的(通过parseOr)。在我的评论中,我建议这可能不会在这里引起堆栈溢出,因为parseElementlistElements之前被尝试过,这意味着listElements将永远无法到达(这是另一个问题。和本身)。

但是,由于您在parseExpression循环中使用*,因此它将重复应用,直到失败为止,这意味着最后将尝试使用其所有替代方法。因此将达到listElements,并且左递归确实会导致堆栈溢出。您还可以从以下事实中看到这一点:如果您将| parseOr中的parseExpression注释掉,堆栈溢出就会消失。