#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 в этом конкретном примере.