4

Parser Combinators を使用して 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)

このコードは機能しますが、FIRST ステートメントにエラーがある場合にのみ意味のあるメッセージを出力します。それが後のステートメントにある場合、パーサーは誤ったステートメント全体が「終了」トークンに置き換えられることを確認したいため、メッセージは非常に使用できなくなります。

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

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

 ^ 

私の質問: reprepsepを意味のあるエラー メッセージと組み合わせて動作させ、繰り返しフラグメントの先頭ではなく適切な場所にキャレットを配置する方法はありますか?

4

2 に答える 2

1

「自家製」の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
                  ^
于 2010-12-11T23:40:20.837 に答える
1

ああ、解決策を見つけた!メインのパーサーで関数句を使用して、後戻りしにくい新しいパーサーを返す必要があることがわかりました。(正確には何を意味するのだろうか、おそらく改行を見つけた場合は追跡しないのでしょうか?)障害が発生した最後の位置を追跡します。

かわった:

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] ...
于 2010-12-11T23:01:36.177 に答える