Преобразование синтаксического анализатора[Any] в более строгий тип

#scala #parsing

#скала #синтаксический анализ

Вопрос:

Программирование в главе 33 Scala объясняет комбинаторный синтаксический анализ:

В нем приводится такой пример:

   import scala.util.parsing.combinator._

  class Arith extends JavaTokenParsers {   
    def expr: Parser[Any] = term~rep(" "~term | "-"~term)
    def term: Parser[Any] = factor~rep("*"~factor | "/"~factor)
    def factor: Parser[Any] = floatingPointNumber | "("~expr~")"
  }
 

Как я могу сопоставить expr его с более узким типом, чем Parser[Any] ? Другими словами,

Я бы хотел взять def expr: Parser[Any] и сопоставить этот подход с ^^ более строгим типом.

Примечание — я задал этот вопрос в группах Scala Google — https://groups.google.com/forum /#!forum/scala-пользователь, но не получил полного ответа, который мне помог.

Комментарии:

1. Обычно вы используете синтаксический анализатор для сопоставления a String с экземпляром структуры данных. Какова ваша структура данных здесь? Затем Any может быть заменен типами этой структуры.

2. Да, разве вы не можете просто заменить любой на другой тип и сделать так, чтобы вы возвращали что-то такого типа …?

3. @Kigyo, я надеялся на это в ответе 🙂

Ответ №1:

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

Вот полный пример со структурой данных из вашего данного кода.

 object Arith extends JavaTokenParsers {

  trait Expression //The data structure
  case class FNumber(value: Float) extends Expression
  case class Plus(e1: Expression, e2: Expression) extends Expression
  case class Minus(e1: Expression, e2: Expression) extends Expression
  case class Mult(e1: Expression, e2: Expression) extends Expression
  case class Div(e1: Expression, e2: Expression) extends Expression

  def expr: Parser[Expression] = term ~ rep(" " ~ term | "-" ~ term) ^^ {
    case term ~ rest => rest.foldLeft(term)((result, elem) => elem match {
      case " " ~ e => Plus(result, e)
      case "-" ~ e => Minus(result, e)
    })
  }

  def term: Parser[Expression] = factor ~ rep("*" ~ factor | "/" ~ factor) ^^ {
    case factor ~ rest => rest.foldLeft(factor)((result, elem) => elem match {
      case "*" ~ e => Mult(result, e)
      case "/" ~ e => Div(result, e)
    })
  }

  def factor: Parser[Expression] = floatingPointNumber ^^ (f => FNumber(f.toFloat)) | "(" ~> expr <~ ")"

  def parseInput(input: String): Expression = parse(expr, input) match {
    case Success(ex, _) => ex
    case _ => throw new IllegalArgumentException //or change the result to Try[Expression]
  }
}
 

Теперь мы можем начать что-то анализировать.

 Arith.parseInput("(1.3   2.0) * 2")
//yields: Mult(Plus(FNumber(1.3),FNumber(2.0)),FNumber(2.0))
 

Конечно, у вас также может быть a Parser[String] или a Parser[Float] , где вы непосредственно преобразуете или оцениваете входную строку. Это, как я уже сказал, зависит от вас.

Комментарии:

1. Большое вам спасибо! Я думаю, что этот пост улучшит качество документов Scala в этом конкретном примере.