Одна вещь, которая может повлиять на ваш выбор, заключается в том, можно ли найти комментарии в действительных синтаксических анализаторах. Например, скажем, у вас есть что-то вроде:
val p = "(" ~> "[a-z]*".r <~ ")"
, который будет анализировать что-то вроде (abc)
, но из-за комментариев, которые могли бы на самом деле сталкиваются с что-то вроде:
(; comment goes here
abc
)
Тогда я бы рекомендовал использовать TokenParser или один из его подкласс. Это больше работает, потому что вы должны предоставить лексический парсер, который сделает первый проход, чтобы отменить комментарии. Но это также более гибким, если у вас есть вложенные комментарии или если ;
можно избежать или, если ;
может быть внутри строкового литерала, как:
abc = "; don't ignore this" ; ignore this
С другой стороны, вы можете также попытаться переопределить значение из whitespace быть что-то вроде
override protected val whiteSpace = """(\s|;.*)+""".r
Или что-то вдоль этих линий. Например, используя пример из scaladoc RegexParsers:
import scala.util.parsing.combinator.RegexParsers
object so1 {
Calculator("""(1 + ; foo
(1 + 2))
; bar""")
}
object Calculator extends RegexParsers {
override protected val whiteSpace = """(\s|;.*)+""".r
def number: Parser[Double] = """\d+(\.\d*)?""".r ^^ { _.toDouble }
def factor: Parser[Double] = number | "(" ~> expr <~ ")"
def term: Parser[Double] = factor ~ rep("*" ~ factor | "/" ~ factor) ^^ {
case number ~ list => (number /: list) {
case (x, "*" ~ y) => x * y
case (x, "/" ~ y) => x/y
}
}
def expr: Parser[Double] = term ~ rep("+" ~ log(term)("Plus term") | "-" ~ log(term)("Minus term")) ^^ {
case number ~ list => list.foldLeft(number) { // same as before, using alternate name for /:
case (x, "+" ~ y) => x + y
case (x, "-" ~ y) => x - y
}
}
def apply(input: String): Double = parseAll(expr, input) match {
case Success(result, _) => result
case failure: NoSuccess => scala.sys.error(failure.msg)
}
}
Это печатает:
Plus term --> [2.9] parsed: 2.0
Plus term --> [2.10] parsed: 3.0
res0: Double = 4.0
Я немного играл с библиотекой комбинаторов синтаксиса в Scala, и я бы рекомендовал использовать «TokenParser» для чего угодно, кроме самых тривиальных парсеров. Во-первых, токенизация сначала делает парсер более быстрым и простым. Во-вторых, без второй фазы токенизации очень трудно получить парсер правильно. У меня были всевозможные проблемы с попытками отличить ключевые слова и идентификаторы. Например, я обнаружил, что мой синтаксический анализатор будет обрабатывать 'if x then y else z' и' ifxthenyelsez' одинаково, если я не добавлю кучу негативных результатов в мои регулярные выражения. – DaoWen
Спасибо за ваши комментарии. Перекрытие белого пространства кажется интересным. Теперь, когда я закончил свой парсер с помощью 'RegexParsers', я больше не хочу менять все, чтобы использовать« ToeknParser », хотя я еще не знаю разницы. – jbx
@ DaoWen Причина, по которой вы получаете 'ifxthenyelsez', вероятно, объясняется тем, как структурируются ваши регулярные выражения. У меня была аналогичная проблема, вы можете проверить это: http://stackoverflow.com/questions/20793058/how-to-skip-whitespace-but-use-it-as-a-token-delimeter-in-a -parser-combinator/20794142? noredirect = 1 # comment31174010_20794142 – jbx