Scala解析器构建的简单计算器示例



我们有以下代码。可在https://scastie.scala-lang.org/JIJ230HAQZ2pqD5qdXSRRw获取

当输入为1+1,但由于某些原因不能匹配1-1时,它会产生语法错误。

你能帮帮我吗?

import scala.util.parsing.combinator._
class  OurParsers extends RegexParsers {
def expression: Parser[Expression] = addSub

def addSub = (add | sub)
def add: Parser[Expression] = productDivision ~ rep("+" ~> productDivision) ^^ {
case p ~ Nil => p
case p ~ prods => Sum(p, prods)
}
def sub: Parser[Expression] = productDivision ~ rep("-" ~> productDivision) ^^ {
case p ~ Nil => p
case p ~ prods => Subtract(p, prods)
}
def productDivision: Parser[Expression] = term ~ rep("*" ~> term) ^^ {
case t ~ Nil => t
case t ~ terms => Product(t, terms)
}
def term: Parser[Expression] = number | "(" ~> expression <~ ")"
def number: Parser[Number] = """(+|-)?[0-9]+(.[0-9]+)?""".r ^^ {
case num => Number(num.toDouble)
}
}
trait Expression {
def execute: Double
}
case class Sum(val operand1: Expression, val operands: List[Expression]) extends Expression {
def execute =
operand1.execute + operands.map(_.execute).reduce(_+_)
}
case class Subtract(val operand1: Expression, val operands: List[Expression]) extends Expression {
def execute =
operand1.execute - operands.map(_.execute).reduce(_-_)
}
case class Product(val operand1: Expression, val operands: List[Expression]) extends Expression {
def execute =
operand1.execute * operands.map(_.execute).reduce(_*_)
}
case class Division(val operand1: Expression, val operands: List[Expression]) extends Expression {
def execute =
operand1.execute / operands.map(_.execute).reduce(_/_)
}
case class Number(val value: Double) extends Expression {
def execute = value
}
val parsers = new OurParsers
val result = parsers.parseAll(parsers.expression, "1-1")
result match {
case result: parsers.Failure => throw new Exception("syntax error")
case _ => {
val exp = result.get  // get the expression from the tree
println("tree: " + exp.toString)
val value = exp.execute  // execute the expression
println(value.toString)  // return string representation of result
}
}

原因是-既可以是数字的一部分,也可以是二进制运算。在到达sub之前,将-绑定为number的一部分。因此,当您想要term-term时,您得到了termterm序列。

你必须改变你的语法来避免这个问题,或者继续写像1-(1)这样的东西,因为-(1)不会被解析为数字(尽管它建议你不会将-解析为一元操作,所以语法改变可能会更好)。

最新更新