Возвращая значимых сообщений об ошибках из парсера, написанного сочетаторами Scala Parser

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

Вопрос

Я пытаюсь написать парсер в 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)

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

 ^ 

Мой вопрос: есть ли способ получить способ получить реп а также 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
                  ^
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top