如何忽略解析器组合器中的单行注释

时间:2014-01-04 19:07:17

标签: scala parser-combinators

我有一个有效的解析器,但我刚刚意识到我不满足于评论。在我正在解析的DSL中,注释以;字符开头。如果遇到;,则会忽略该行的 rest (但不是全部,除非第一个字符为;)。

我正在为我的解析器扩展RegexParsers并忽略空格(默认方式),所以无论如何我都会丢失新的行字符。我不希望修改我必须满足注释可能性的每个解析器,因为语句可以跨越多行(因此每个语句的每个部分可能以注释结束)。是否有任何干净的方法来实现这一目标?

2 个答案:

答案 0 :(得分:6)

可能影响您选择的一件事是您是否可以在有效的解析器中找到评论。例如,假设你有类似的东西:

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

或者那些东西。 例如,使用RegexParsers scaladoc中的示例:

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

答案 1 :(得分:0)

在将代码传递给解析器之前,只需使用正则表达式过滤掉所有注释。

def removeComments(input: String): String = {
  """(?ms)\".*?\"|;.*?$|.+?""".r.findAllIn(input).map(str => if(str.startsWith(";")) "" else str).mkString
}

val code =
"""abc "def; ghij"
abc ;this is a comment
def"""

println(removeComments(code))