Как улучшить обмен сообщениями об ошибках анализатора Sprache с отсутствующей закрывающей скобкой?

Я строю простую грамматику в командном стиле, используя Sprache. Я пытаюсь выяснить, есть ли способ улучшить отчетность об ошибках при отсутствии закрывающего символа (например,],), }).

Если закрывающий символ отсутствует, моя грамматика правильно сообщает об ошибке. Однако обмен сообщениями приводит к трудностям в понимании реальной проблемы. Учитывая следующую строку для анализа:

sum 10 [multiply 5 4

Sprache сообщает о следующей ошибке:

Sprache.ParseException : Parsing failure: unexpected '['; expected newline or end of input (Line 1, Column 8); recently consumed: sum 10

Похоже, происходит то, что парсер пытается сопоставить на моем CommandSubstitution и не может найти закрытие ']', Это приводит к тому, что синтаксический анализатор отступает и пытается заменить его. Как это не может больше соответствовать Things для команды, он пытается сопоставить на CommandTerminator, Как это не может соответствовать '[' он сообщает об ошибке с жалобой на ожидаемое newline или же end of input вместо того, чтобы сказать: "Эй, приятель, ты не соответствовал своей скобке!"

Существуют ли какие-либо обходные пути или рекомендации, как можно улучшить грамматику, чтобы улучшить отчетность, используя библиотеку синтаксического анализа, такую ​​как Sprache?

public static readonly Parser<Word> Word = Parse.Char(IsWordChar, "word character").AtLeastOnce().Text()
                                                .Select(str => new Word(str));

public static readonly Parser<CommandSubstitution> CommandSubstitution = from open in Parse.Char('[').Once()
                                                                            from body in Parse.Ref(() => Things)
                                                                            from close in Parse.Char(']').Once()
                                                                            select new CommandSubstitution(body.ToList());


public static readonly Parser<Thing> Thing = CommandSubstitution.Or<Thing>(Word);

public static readonly Parser<IEnumerable<Thing>> Things = (from ignoreBefore in WordSeparator.Optional()
                                                            from thing in Thing
                                                            from ignoreAfter in WordSeparator.Optional()
                                                            select thing).Many();

public static readonly Parser<IEnumerable<Thing>> Command = from things in Things
                                                            from terminator in CommandTerminator
                                                            select things;

1 ответ

Похоже, что общая проблема заключается в том, что Sprache терпит неудачу, пробует альтернативы и снова терпит неудачу, когда вместо этого он должен просто сдаться после первой неудачи.

Вы определяете Things парсер, использующий Parse.Many метод расширения. Вещь о Parse.Many синтаксический анализатор - то, что это всегда успешно независимо от того, успешен ли его внутренний анализатор или терпит неудачу. Если внутренний парсер не работает, Parse.Many просто предполагает, что больше нет входных данных, которые ему нужно потреблять.

Это то, что, кажется, происходит здесь. Первый, Parse.Many потребляет фрагмент "sum 10 ", Затем он пытается проанализировать больше ввода, но не удается. Поскольку он не смог проанализировать больше входных данных, он предполагает, что больше нет входных данных, которые он должен использовать. Но тогда возникает ошибка, потому что фрагмент [multiply 5 4 не был потреблен.

Чтобы это исправить, используйте Parse.XMany вместо Parse.Many, Если внутренний парсер для Parse.XMany дает сбой после использования хотя бы одного символа, затем Parse.XMany немедленно сдастся и сообщит о неудаче.

Другие вопросы по тегам