возвращение значимых сообщений об ошибках от анализатора, написанного с помощью Scala Parser Combinators - PullRequest
4 голосов
/ 12 декабря 2010

Я пытаюсь написать парсер в Scala, используя Parser Combinators.Если я сопоставлю рекурсивно,

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.Если это в более позднем утверждении, сообщение становится болезненно непригодным для использования, потому что синтаксический анализатор хочет, чтобы весь ошибочный оператор был заменен маркером «end»:

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

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

 ^ 

Мой вопрос: есть ли способ получить rep и repsep , работающие в сочетании со значимыми сообщениями об ошибках, которые помещают курсор в нужном месте, а не в начале повторяющегося фрагмента?

Ответы [ 2 ]

1 голос
/ 12 декабря 2010

Вы можете сделать это, комбинируя метод "home made" 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
                  ^
1 голос
/ 12 декабря 2010

Ах, нашел решение!Оказывается, вам нужно использовать функциональную фразу в вашем главном парсере, чтобы вернуть новый парсер, который менее склонен отслеживать.(Интересно, что именно это означает, возможно, что, если он обнаружит разрыв строки, он не будет отслеживать назад?) отслеживает последнюю позицию в случае сбоя.

в:

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