Rückkehr aussagekräftige Fehlermeldungen von einem Parser mit Scala Parser Kombinatoren geschrieben

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

Frage

Ich versuche, einen Parser in scala mit Parser Kombinatoren zu schreiben. Wenn ich passen rekursiv,

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

dann bekomme ich gute Störmeldungen, wenn ein Fehler in einer Erklärung ist. Dies ist jedoch hässlich langer Code. Also ich möchte, dies schreiben:

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

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

Dieser Code funktioniert, druckt aber nur sinnvoll, Meldungen, wenn ein Fehler in der ersten Anweisung ist. Wenn es in einer späteren Aussage ist, wird die Nachricht schmerzlich unbrauchbar, weil der Parser die gesamte fehlerhafte Anweisung ersetzt durch das „Ende“ Token sehen will:

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

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

 ^ 

Meine Frage: Gibt es eine Möglichkeit zu bekommen rep und repsep arbeitet in Kombination mit aussagekräftigen Fehlermeldungen dieser Stelle der Einfügemarke an der richtigen Stelle statt auf dem Beginn des wiederholten Fragment?

War es hilfreich?

Lösung 2

Ah, fand die Lösung! Es stellt sich heraus, dass Sie die Funktion Phrase auf Ihrem Haupt-Parser verwenden müssen einen neuen Parser zurück, dass weniger zu verfolgen zurück geneigt ist. (Ich frage mich, was es genau bedeutet, vielleicht, dass, wenn es einen Zeilenumbruch findet, wird es nicht zurückverfolgen?) verfolgt die letzte Position auf Weichen ein Ausfall aufgetreten ist.

geändert:

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] ...

in:

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] ...

Andere Tipps

Sie können es durch eine Kombination von „hausgemachten“ rep Verfahren mit nicht-Rückzieher innerhalb Aussagen. Zum Beispiel:

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
                  ^
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top