如何让这个简单的正则表达式解析器捕获一个布尔表达式?

时间:2017-01-17 15:53:02

标签: scala parser-combinators

我正在尝试使用Scala了解解析器组合器,并编写了以下内容:

import scala.util.parsing.combinator._

class SimpleParser extends RegexParsers {

  def operand: Parser[String] = "[A-Za-z]+".r ^^ {_.toString}

  def operator: Parser[String] = "OR|AND".r ^^ {_.toString}

  def term: Parser[String] = (("(" ~> (operand ~ operator ~ operand) <~ ")")) ^^ {
    case o1 ~ operator ~ o2 => o1 + " " + operator + " " + o2
    case _ => " "
  }


  def expression: Parser[String] = (operand | term | (operand ~ operator ~ term))^^ {
    case str:String => str
    case operand ~ operator ~ term => operand + " " + operator + " " + term
  }
}

object ParserTest extends SimpleParser{
  def main(args: Array[String]): Unit = {
     println(parseAll(expression, "A").get)
     println(parseAll(expression, "(A OR C)").get)
     println(parseAll(expression, "A AND (A OR C)").get)
  }
}

前两个印刷品可以找到,而最后一个印刷品可以找到:

Exception in thread "main" java.lang.RuntimeException: No result when parsing failed at scala.sys.package$.error(package.scala:27)
at scala.util.parsing.combinator.Parsers$NoSuccess.get(Parsers.scala:181)
at scala.util.parsing.combinator.Parsers$NoSuccess.get(Parsers.scala:167)
at ParserTest$.main(ParserTest.scala:31)
at ParserTest.main(ParserTest.scala)

我认为最后一句话与“表达式”中的(操作数〜运算符〜术语)模式相匹配。有人可以解释我为什么我的模式是错误的,也许可以显示写一个匹配最后一个打印语句?

1 个答案:

答案 0 :(得分:3)

首先,您没有正确处理Failure的结果。如果你是,你会在最后一个例子中看到它返回[1.3] failure: end of input expected A AND (B OR C) ^ 并带有消息

expression

这里的问题是你的解析器在|内的顺序错误。

当创建解析器的分离(uisng operand)时,你总是必须从“最贪婪”的解析器开始。换句话说,这里发生的是parseAll本身正在成功解析“A”并解析结束。但是,def expression: Parser[String] = ((operand ~ operator ~ term) | term | operand)^^ 看到解析已成功但仍有输入,因此它返回上述错误。

如果颠倒3个解析器的顺序,它看起来像:

public float getValue(int id, float num1, float num2){
    float result = 0.0;
    switch (id) {
    case R.id.btnAdd:
        oper = "+";
        result = num2 + num2;
        break;
    case R.id.btnSub:
        oper = "-";
        result = num1 - num2;
        break;
    case R.id.btnMult:
        oper = "*";
        result = num1 * num2;
        break;
    case R.id.btnDiv:
        oper = "/";
        result = num1 / num2;
        break;
    default:
        break;
}
return result;
}

现在它们已正确订购,所有3个示例都有效。