Как улучшить сообщения об ошибках в парсерах на основе парсера-комбинатора Scala?

Я написал парсер на основе комбинаторов парсеров Scala:

class SxmlParser extends RegexParsers with ImplicitConversions with PackratParsers {
    [...]
    lazy val document: PackratParser[AstNodeDocument] =
        ((procinst | element | comment | cdata | whitespace | text)*) ^^ {
            AstNodeDocument(_)
        }
    [...]
}
object SxmlParser {
    def parse(text: String): AstNodeDocument = {
        var ast = AstNodeDocument()
        val parser = new SxmlParser()
        val result = parser.parseAll(parser.document, new CharArrayReader(text.toArray))
        result match {
            case parser.Success(x, _) => ast = x
            case parser.NoSuccess(err, next) => {
                tool.die("failed to parse SXML input " +
                    "(line " + next.pos.line + ", column " + next.pos.column + "):\n" +
                    err + "\n" +
                    next.pos.longString)
            }
        }
        ast
    }
}

Обычно результирующие сообщения об ошибках синтаксического анализа довольно приятны. Но иногда становится просто

sxml: ERROR: failed to parse SXML input (line 32, column 1):
`"' expected but `' found
^

Это происходит, если символы кавычек не закрываются и парсер достигает EOT. Что я хотел бы здесь увидеть, так это (1) в какой продукции находился синтаксический анализатор, когда он ожидал """ (у меня их несколько) и (2) где на входе эта продукция начала синтаксический анализ (что является индикатором, где вводная цитата находится на входе).Кто-нибудь знает, как я могу улучшить сообщения об ошибках и включить дополнительную информацию о фактическом состоянии внутреннего синтаксического анализа, когда происходит ошибка (возможно, что-то вроде трассировки стека производственного правила или что-то еще, что можно разумно дать здесь, чтобы лучше идентифицировать место ошибки). Кстати, приведенная выше «строка 32, столбец 1» на самом деле является позицией EOT и, следовательно, здесь, конечно, бесполезна.


person Ralf S. Engelschall    schedule 25.05.2010    source источник


Ответы (2)


Я еще не знаю, как быть с (1), но я также искал (2), когда нашел эту веб-страницу:

https://wiki.scala-lang.org/plugins/viewsource/viewpagesrc.action?pageId=917624

Я просто копирую информацию:

Полезным усовершенствованием является запись входной позиции (номер строки и номер столбца) значимых токенов. Для этого необходимо сделать три вещи:

  • Сделайте так, чтобы каждый тип вывода расширял scala.util.parsing.input.Positional
  • вызвать комбинатор Parsers.positioned()
  • Используйте источник текста, который записывает позиции строк и столбцов

и

Наконец, убедитесь, что источник отслеживает позиции. Для потоков вы можете просто использовать scala.util.parsing.input.StreamReader; для строк используйте scala.util.parsing.input.CharArrayReader.

В настоящее время я играю с ним, поэтому я попытаюсь добавить простой пример позже.

person Vinz    schedule 25.06.2010
comment
Теперь я могу подтвердить, что этот способ сделать это правильно (и действительно легко!). Он отлично работает для меня - person Vinz; 29.06.2010
comment
Предоставленная ссылка кажется мертвой. - person jbx; 27.11.2013
comment
Спасибо за сообщение о мертвой ссылке, я нашел другой источник для того же объяснения. - person Vinz; 09.12.2013

В таких случаях вы можете использовать err, failure и ~! с производственными правилами, разработанными специально для устранения ошибки.

person Daniel C. Sobral    schedule 25.05.2010