devolver mensajes de error significativos de un programa de análisis escrito con Scala Analizador combinadores

StackOverflow https://stackoverflow.com/questions/4418975

Pregunta

Trato de escribir un analizador de Scala utilizando Analizador combinadores. Si Emparejo de forma recursiva,

def body: Parser[Body] =
("begin" ~> statementList  )  ^^ {
     case s => {   new Body(s); }
}

def statementList : Parser[List[Statement]] = 
  ("end" ^^ { _ => List() } )|
  (statement ~ statementList ^^ { case statement ~ statementList => statement :: statementList  })

Entonces consigo buenas ErrorMessages cada vez que hay un fallo en un comunicado. Sin embargo, se trata de código largo feo. Así que me gustaría que escribir esto:

def body: Parser[Body] =
("begin" ~> statementList <~ "end"  )  ^^ {
   case s => {   new Body(s); }
}

def statementList : Parser[List[Statement]] = 
    rep(statement)

Este código funciona, pero sólo imprime mensajes significativos si hay un error en el primer estado de cuenta. Si se trata de una declaración posterior, el mensaje se vuelve dolorosamente inservible, porque el analizador quiere ver toda la declaración errónea reemplazado por el "fin" token:

Exception in thread "main" java.lang.RuntimeException: [4.2] error: "end" expected but "let" found

 let b : string = x(3,b,"WHAT???",!ERRORHERE!,7 ) 

 ^ 

Mi pregunta: ¿hay una manera de conseguir rep y repsep que trabaja en combinación con los mensajes de error significativos, ese lugar el cursor en el lugar correcto en lugar de en el inicio del fragmento repitiendo?

¿Fue útil?

Solución 2

Ah, encontró la solución! Resulta que es necesario utilizar la frase de la función en el analizador principal de devolver un nuevo analizador que está menos inclinado a realizar un seguimiento posterior. (Me pregunto qué significa exactamente, tal vez que si encuentra un salto de línea no va a rastrear?) seguimiento de la última posición en wich se produjo un fallo.

cambiado:

def parseCode(code: String): Program = {
 program(new lexical.Scanner(code)) match {
      case Success(program, _) => program
      case x: Failure => throw new RuntimeException(x.toString())
      case x: Error => throw new RuntimeException(x.toString())
  }

}

def program : Parser[Program] ...

en

def parseCode(code: String): Program = {
 phrase(program)(new lexical.Scanner(code)) match {
      case Success(program, _) => program
      case x: Failure => throw new RuntimeException(x.toString())
      case x: Error => throw new RuntimeException(x.toString())
  }

}


def program : Parser[Program] ...

Otros consejos

Puede hacerlo mediante la combinación de un "hecho en casa" método rep con no dar marcha atrás dentro de sentencias. Por ejemplo:

scala> object X extends RegexParsers {
     |   def myrep[T](p: => Parser[T]): Parser[List[T]] = p ~! myrep(p) ^^ { case x ~ xs => x :: xs } | success(List())
     |   def t1 = "this" ~ "is" ~ "war"
     |   def t2 = "this" ~! "is" ~ "war"
     |   def t3 = "begin" ~ rep(t1) ~ "end"
     |   def t4 = "begin" ~ myrep(t2) ~ "end"
     | }
defined module X

scala> X.parse(X.t4, "begin this is war this is hell end")
res13: X.ParseResult[X.~[X.~[String,List[X.~[X.~[String,String],String]]],String]] =
[1.27] error: `war' expected but ` ' found

begin this is war this is hell end
                          ^

scala> X.parse(X.t3, "begin this is war this is hell end")
res14: X.ParseResult[X.~[X.~[String,List[X.~[X.~[String,String],String]]],String]] =
[1.19] failure: `end' expected but ` ' found

begin this is war this is hell end
                  ^
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top