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