1

編集:解決済み、以下の「FIX」を参照

数値の複雑さに応じて浮動小数点数または整数を解析するようにスカラ パーサー コンビネーターをセットアップしようとしています。これが私が現在持っているものです:

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))
  }

}

IntegerLiteralFloatLiteralテストの両方が完全に機能します。IntegerLiteralご覧のとおり、数値をint または float として解析できるかどうかに応じて、数値を an または FloatLiteral として解析したいと考えています。テストの最初の行はNumberLiteral機能しますが、2 行目に次のエラーが表示されますjava.lang.RuntimeException: no result when parsing failed。float パーサーは parse できるため、パーサーがこのエラーをスローする理由がわかりません32.3。を使用して数値パーサーで何か間違ったことをしていinteger | floatますか?

4

1 に答える 1

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
于 2015-06-28T07:52:53.470 に答える