编辑:已解决,请参阅" FIX"以下
我正在尝试设置一个scala解析器组合器来解析float或整数,具体取决于数字的复杂程度。这是我目前的情况:
import scala.util.parsing.combinator.JavaTokenParsers
trait NumberLiteral
case class IntegerLiteral(i:Int) extends NumberLiteral
case class FloatLiteral(f:Float) extends NumberLiteral
class Parser extends JavaTokenParsers {
def integer:Parser[IntegerLiteral] = wholeNumber ^^ {i => new IntegerLiteral(i.toInt)}
def float:Parser[FloatLiteral] = floatingPointNumber ^^ {f => new FloatLiteral(f.toFloat)}
//FIX: def float:Parser[FloatLiteral] = """[+-]?[0-9]*((\.[0-9]+([eE][+-]?[0-9]+)?[fF]?)|([fF])|([eE][+-]?[0-9]+))\b""".r ^^ {f => new FloatLiteral(f.toFloat)}
def number:Parser[NumberLiteral] = integer | float;
//FIX: def number:Parser[NumberLiteral] = float | integer;
}
我设置了scalatest来测试整数和浮点解析器,它们都可以工作。这是我的测试类的样子:
import org.scalatest._
class ParserSpec extends FlatSpec with Matchers {
val parser = new Parser()
"Parser" should "parse IntegerLiteral" in {
parser.parseAll(parser.integer, "0").get should equal (new IntegerLiteral(0))
parser.parseAll(parser.integer, "4").get should equal (new IntegerLiteral(4))
parser.parseAll(parser.integer, "4448338").get should equal (new IntegerLiteral(4448338))
parser.parseAll(parser.integer, "-33").get should equal (new IntegerLiteral(-33))
parser.parseAll(parser.integer, "-10101010").get should equal (new IntegerLiteral(-10101010))
parser.parseAll(parser.integer, "004").get should equal (new IntegerLiteral(4))
}
it should "parse FloatLiteral" in {
parser.parseAll(parser.float, "1.0").get should equal (new FloatLiteral(1.0f))
parser.parseAll(parser.float, "0").get should equal (new FloatLiteral(0))
parser.parseAll(parser.float, "32.3").get should equal (new FloatLiteral(32.3f))
parser.parseAll(parser.float, "3.4e3").get should equal (new FloatLiteral(3400))
parser.parseAll(parser.float, "-10").get should equal (new FloatLiteral(-10))
parser.parseAll(parser.float, "-4e-4").get should equal (new FloatLiteral(-0.0004f))
parser.parseAll(parser.float, "003.4").get should equal (new FloatLiteral(3.4f))
parser.parseAll(parser.float, "4f").get should equal (new FloatLiteral(4))
}
it should "parse NumberLiteral" in {
parser.parseAll(parser.number, "32").get should equal (new IntegerLiteral(32))
parser.parseAll(parser.number, "32.3").get should equal (new FloatLiteral(32.3f))
parser.parseAll(parser.number, "32f").get should equal (new FloatLiteral(32))
parser.parseAll(parser.number, "0.33").get should equal (new FloatLiteral(0.33f))
parser.parseAll(parser.number, "32e2").get should equal (new IntegerLiteral(3200))
parser.parseAll(parser.number, "0").get should equal (new IntegerLiteral(32))
parser.parseAll(parser.number, "32.3e1").get should equal (new IntegerLiteral(323))
}
}
IntegerLiteral
和FloatLiteral
测试都能完美运行。如您所见,我想将数字解析为IntegerLiteral
或FloatLiteral,具体取决于它是否可以解析为int或float。 NumberLiteral
测试中的第一行有效,但我在第二行收到以下错误:java.lang.RuntimeException: no result when parsing failed
。我无法弄清楚解析器抛出此错误的原因,因为浮点解析器可以解析32.3
。我在使用integer | float
?
答案 0 :(得分:4)
只需交换它们:
...
def number:Parser[NumberLiteral] = float | integer //float first
...
示例:
scala> parser.parseAll(parser.number, "32.3").get
res0: NumberLiteral = FloatLiteral(32.3)
它首先不起作用的原因是解析器确实解析了“32.3”中的“32”作为整数 - 而未解析的尾部“.3”确实导致错误。您可以使用parse
:
...
def number:Parser[NumberLiteral] = integer | float //integer first
...
scala> parser.parse(parser.number, "32.3")
res3: parser.ParseResult[NumberLiteral] = [1.3] parsed: IntegerLiteral(32)
//And here is how to get unparsed tail (".3"):
scala> val pointer = parser.parse(parser.number, "32.3").next
pointer: parser.Input = scala.util.parsing.input.CharSequenceReader@34a2d29d
scala> pointer.source.toString.drop(pointer.pos.column - 1)
res15: String = .3