Question

J'essaie d'écrire un analyseur en utilisant scala Parser Combinators. Si je correspond récursive,

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

je reçois de bons errormessages chaque fois qu'il ya une faute dans un communiqué. Cependant, ce code est laid à long. Je voudrais donc écrire ceci:

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

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

Ce code fonctionne, mais seulement imprime des messages significatifs s'il y a une erreur dans la première déclaration. Si elle est dans un communiqué plus tard, le message devient douloureusement inutilisable, car l'analyseur veut voir toute déclaration erronée remplacée par le jeton « fin »:

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

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

 ^ 

Ma question: est-il un moyen d'obtenir représentant et repsep travailler en combinaison avec des messages d'erreur significatifs, cet endroit le caret au bon endroit au lieu de le commencer du fragment de répétition?

Était-ce utile?

La solution 2

Ah, a trouvé la solution! Il se avère que vous devez utiliser l'expression de fonction sur votre analyseur principal pour renvoyer un nouvel analyseur que est moins enclin à suivre en arrière. (Je me demande ce exactement signifie, peut-être que si elle trouve une coupure de ligne, il ne sera pas suivi de retour?) suit la dernière position sur Wich une défaillance est survenue.

changé:

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

dans:

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

Autres conseils

Vous pouvez le faire en combinant une « maison » méthode rep avec les non-retours en arrière dans les déclarations. Par exemple:

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
                  ^
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top