Scala Parser Combinatorsで書かれたパーサーから意味のあるエラーメッセージを返す
-
08-10-2019 - |
質問
パーサーの組み合わせを使用して、Scalaでパーサーを書き込もうとしています。私が再帰的に一致した場合、
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 })
それから、声明に障害があるたびに、私は良いエラーを得ることができます。ただし、これは醜い長いコードです。だから私はこれを書きたいです:
def body: Parser[Body] =
("begin" ~> statementList <~ "end" ) ^^ {
case s => { new Body(s); }
}
def statementList : Parser[List[Statement]] =
rep(statement)
このコードは機能しますが、最初のステートメントにエラーがある場合に意味のあるメッセージのみを印刷します。それが後の声明にある場合、メッセージは痛みを伴って使用できなくなります。なぜなら、パーサーは「エンド」トークンに置き換えられた誤った声明全体を見たいと思っているからです。
Exception in thread "main" java.lang.RuntimeException: [4.2] error: "end" expected but "let" found
let b : string = x(3,b,"WHAT???",!ERRORHERE!,7 )
^
私の質問:得る方法はありますか 担当者 と repsep 意味のあるエラーメッセージと組み合わせて作業して、繰り返しのフラグメントの開始ではなく、正しい場所にケアを置きますか?
解決 2
ああ、解決策を見つけました!メインパーサーの関数フレーズを使用して、新しいパーサーを返す必要があることがわかります。 後ろに追跡する傾向が少ない。 (それが正確に何を意味するのだろうか、おそらくそれがラインブレイクを見つけた場合、それは後ろに追跡されないだろうか?) 障害が発生した場合の最後の位置を追跡します。
かわった:
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] ...
の中へ:
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] ...
他のヒント
「自家製」を組み合わせることで、それを行うことができます rep
ステートメント内の非バックトラッキングを備えた方法。例えば:
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
^
所属していません StackOverflow