Scala Parser, почему не работает "pat <~ pat ~> pat"? - PullRequest
3 голосов
/ 23 апреля 2011

Испытывая простой комбинатор синтаксического анализа, я сталкиваюсь с ошибками компиляции.

Я бы хотел разобрать - "Smith, Joe" в его объект Name, такой как Name (Joe, Smith).Я думаю, достаточно просто.

Вот код, связанный с этим:

    import util.parsing.combinator._

    class NameParser extends JavaTokenParsers {
      lazy val name: Parser[Name] = 
        lastName <~ "," ~> firstName ^^ {case (l ~ f) => Name(f, l)}
      lazy val lastName = stringLiteral
      lazy val firstName = stringLiteral
    }

    case class Name(firstName:String, lastName: String)

И я тестирую его через

object NameParserTest {
  def main(args: Array[String]) {
    val parser = new NameParser()
    println(parser.parseAll(parser.name, "Schmo, Joe"))
  }
}

Получение ошибки компиляции:

error: constructor cannot be instantiated to expected type;
found   : NameParser.this.~[a,b]
required: java.lang.String
lazy val name: Parser[Name] = lastName <~ "," ~> firstName ^^ {case (l ~ f) => Name(f, l)}

Что мне здесь не хватает?

Ответы [ 3 ]

8 голосов
/ 23 апреля 2011

В этой строке здесь:

  lazy val name: Parser[Name] = 
    lastName <~ "," ~> firstName ^^ {case (l ~ f) => Name(f, l)}

вы не хотите использовать <~ и ~>. Вы создаете парсер, который соответствует "," и firstName и сохраняет только ",", а затем вы создаете парсер, который соответствует lastName и предыдущему парсеру и сохраняет только lastName.

Вы можете заменить его следующим:

(lastName <~ ",") ~ firstName ^^ {case (l ~ f) => Name(f, l)}

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

[1.1] failure: string matching regex `"([^"\p{Cntrl}\\]|\\[\\/bfnrt]|\\u[a-fA-F0-9]{4})*"' expected but `S' found

Schmo, Joe
^

stringLiteral ожидает что-то похожее на строковый литерал в коде (что-то в кавычках). (JavaTokenParsers предназначен для разбора содержимого, похожего на Java.) Это работает:

scala> val x = new NameParser
x: NameParser = NameParser@1ea8dbd

scala> x.parseAll(x.name, "\"Schmo\", \"Joe\"")
res0: x.ParseResult[Name] = [1.15] parsed: Name("Joe","Schmo")

Вам, вероятно, следует заменить его регулярным выражением, которое указывает, какие строки вы будете принимать для имен. Если вы посмотрите документацию здесь , вы увидите:

implicit def regex (r: Regex) : Parser[String]

A parser that matches a regex string

Таким образом, вы можете просто поместить туда объект Regex, и он будет преобразован в синтаксический анализатор, соответствующий ему.

7 голосов
/ 23 апреля 2011

комбинатор ~> игнорирует левую сторону, а комбинатор <~ игнорирует правую сторону. Таким образом, результат lastName <~ "," ~> firstName никогда не может включать результаты как firstName, так и lastName. На самом деле это только результат разбора lastName, потому что "," ~> firstName игнорируется. Вам необходимо использовать последовательную композицию здесь:

lazy val name: Parser[Name] =         
  lastName ~ "," ~ firstName ^^ {case (l ~_~ f) => Name(f, l)}

Или, если вы хотите более красивое совпадение с шаблоном:

lazy val name: Parser[Name] =         
  lastName ~ ("," ~> firstName) ^^ {case (l ~ f) => Name(f, l)}
4 голосов
/ 23 апреля 2011

Код

lastName <~ "," ~> firstName

в конечном итоге отбрасывает результат анализа firstName.Из-за правил приоритета операторов в Scala оператор анализируется так, как если бы он был заключен в скобки, например:

lastName <~ ("," ~> firstName)

, но даже если он был сгруппирован по-другому, вы все равно работаете только с тремя анализаторами и выбрасываете результатиз двух из них.

Таким образом, в результате вы получаете String, который передается в вашу функцию отображения, которая написана так, чтобы ожидать ~[String, String].Вот почему вы получаете ошибку компилятора, которую вы делаете.

Один полезный метод для устранения неполадок такого рода состоит в добавлении атрибутов к подвыражениям:

lazy val name: Parser[Name] =
  ((lastName <~ "," ~> firstName): Parser[String ~ String]) ^^ { case l ~ f => Name(f, l) }

, которые могут помочь вам определить, где именно реальностьи ваши ожидания расходятся.

...