Парсер комбинатора скала не отступает, как я бы подумал… - PullRequest
4 голосов
/ 08 февраля 2012

Я слепо смотрю на эту проблему, и, наверное, это будет очень глупый вопрос.Но я должен проглотить свою гордость.

У меня есть этот синтаксический анализатор комбинатора, который не возвращается, как я ожидал.Я сократил это до небольшого примера без полного удаления контекста.По ощущениям «foobar» - примеры просто сложнее читать.Вот и я:

@RunWith(classOf[JUnitRunner])
class ParserBacktrackTest extends RegexParsers with Spec with ShouldMatchers {
  override def skipWhitespace = false

  lazy val optSpace = opt(whiteSpace)
  lazy val number = """\d+([\.]\d+)?""".r
  lazy val numWithOptSpace = number <~ optSpace

  private def litre = numWithOptSpace <~ ("litre" | "l")
  def volume = litre ^^ { case _ => "volume" }

  private def namedPieces = numWithOptSpace <~ ("pcs") ^^ { case _ => "explPcs" }
  private def implicitPieces = number ^^ { case _ => "implPcs" }
  protected def unitAmount = namedPieces | implicitPieces

  def nameOfIngredient = ".*".r

  def amount = volume | unitAmount
//  def amount = unitAmount
  protected def ingredient = (amount <~ whiteSpace) ~ nameOfIngredient

  describe("IngredientParser") {
    it("should parse volume") {
      shouldParse("1 litre lime")
    }
    it("should parse explicit pieces") {
      shouldParse("1 pcs lime")
    }
    it("should parse implicit pieces") {
      shouldParse("1 lime")
    }
  }

  def shouldParse(row: String) = {
    val result = parseAll(ingredient, row)
    result match {
      case Success(value, _) => println(value)
      case x => println(x)
    }
    result.successful should be(true)
  }
}

Итак, что происходит, если третий тест не пройден:

(volume~lime)
(explPcs~lime)
[1.4] failure: string matching regex `\s+' expected but `i' found

1 lime
   ^

Так что, похоже, litre-parser потребляет l, а затем не удается, когда не может 'не могу найти никакого места.Но я бы подумал, что тогда он вернется и попробует следующее правило производства.Очевидно, синтаксический анализатор implicitPieces анализирует эту строку, потому что, если я удаляю предыдущий анализатор томов (удаляем комментарий), он успешно завершается

(implPcs~litre lime)
(explPcs~lime)
(implPcs~lime)

Почему бы amount не возвращаться назад?Что я недопонимаю?

Ответы [ 2 ]

4 голосов
/ 08 февраля 2012

Я просто хочу опубликовать минимальный пример, иллюстрирующий мое недоразумение.Я думал, что это удастся:

  def foo = "foo" | "fo"
  def obar = "obar"

  def foobar = foo ~ obar

  describe("foobar-parser") {
    it("should parse it") {
      shouldParseWith(foobar, "foobar")
    }
  }

, но откат по | не работает таким образом.Дизъюнктивный синтаксический анализатор будет использовать «foo» и никогда не вернет его.

Он должен быть нормализован, чтобы дизъюнкция была перемещена на верхний уровень:

def workingFooBar = ("foo" ~ obar) | ("fo" ~ obar)
2 голосов
/ 08 февраля 2012

Не возвращается, потому что для 1 lime

  • ingredient начинается с amount
  • amount начинается с volume
  • volume начинается с litre и
  • litre успешно потребляет 1 l из 1 lime

Итак, litre, volume и amount были успешными! Вот почему тогда все продолжается со второй части ingredient, а именно whiteSpace.

НТН!

...