如何通过缺少右括号来改进Sprache解析器错误消息?

时间:2016-06-12 19:51:55

标签: c# parsing 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。因为它不能与'['匹配,所以它报告错误抱怨预期的newlineend 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 个答案:

答案 0 :(得分:3)

听起来整个问题是Sprache失败,尝试替代方案,并且在第一次失败后应该放弃时再次失败。

您正在使用Things扩展方法定义Parse.Many解析器。关于Parse.Many解析器的事情是它总是成功,无论其内部解析器是成功还是失败。如果内部解析器失败,Parse.Many只是假设没有更多需要消耗的输入。

这就是这里似乎发生的事情。首先,Parse.Many使用片段"sum 10 "。然后它尝试解析更多输入,但失败了。由于它无法解析任何更多输入,因此它假定不再需要消耗任何输入。但随后会出现错误,因为片段[multiply 5 4尚未消耗。

要解决此问题,请使用Parse.XMany代替Parse.Many。如果Parse.XMany的内部解析器在消耗了至少一个字符后失败,那么Parse.XMany将立即放弃并报告失败。