/ / Cómo ignorar los comentarios de una sola línea en un analizador-combinador - scala, analizadores-combinador

Cómo ignorar comentarios de una sola línea en un analizador-analizador - scala, parser-combinators

Tengo un analizador funcional, pero me acabo de dar cuenta de que no atiendo comentarios. En el DSL que estoy analizando, los comentarios comienzan con un ; personaje. Si un ; se encuentra, el descanso de la línea se ignora (no todo, sin embargo, a menos que el primer carácter sea ;)

Estoy extendiendo RegexParsers para mi analizador e ignorando espacios en blanco (elforma predeterminada), así que estoy perdiendo los nuevos caracteres de línea de todos modos. No deseo modificar todos y cada uno de los analizadores que tengo para atender la posibilidad de comentarios tampoco, porque las declaraciones pueden abarcar varias líneas (por lo tanto, cada parte de cada declaración puede terminar con un comentario). ¿Hay alguna manera limpia de lograrlo? ¿esta?

Respuestas

4 para la respuesta № 1

Una cosa que puede influir en su elección es si se pueden encontrar comentarios dentro de sus analizadores válidos. Por ejemplo, supongamos que tiene algo como:

val p = "(" ~> "[a-z]*".r <~ ")"

que analizaría algo como ( abc ) pero debido a los comentarios, podrías encontrar algo como:

( ; comment goes here
abc
)

Entonces recomendaría usar un TokenParser o una de sus subclases. Es más trabajo porque tiene que proporcionar un analizador léxico que haga un primer pase para descartar los comentarios. Pero también es más flexible si tiene comentarios anidados o si el ; se puede escapar o si el ; puede estar dentro de una cadena literal como:

abc = "; don"t ignore this" ; ignore this

Por otro lado, también podría intentar anular el valor de espacio en blanco ser algo como

override protected val whiteSpace = """(s|;.*)+""".r

O algo por el estilo. Por ejemplo, utilizando el ejemplo de 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)
}
}

Esto imprime:

Plus term --> [2.9] parsed: 2.0
Plus term --> [2.10] parsed: 3.0
res0: Double = 4.0

0 para la respuesta № 2

Simplemente filtre todos los comentarios con una expresión regular antes de pasar el código a su analizador.

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))