Как улучшить обмен сообщениями об ошибках анализатора 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
немедленно сдастся и сообщит о неудаче.