Parsing 递归下降分析器中的错误报告
我正在为配置文件编写递归下降解析器。这些文件大部分类似于ini文件。以下是某种类似EBNF的形式的语言:Parsing 递归下降分析器中的错误报告,parsing,language-agnostic,ebnf,recursive-descent,Parsing,Language Agnostic,Ebnf,Recursive Descent,我正在为配置文件编写递归下降解析器。这些文件大部分类似于ini文件。以下是某种类似EBNF的形式的语言: document ::= { category } category ::= title {entry} title ::= "[" <name> "]" entry ::= <key> ":" <value> 我可以在网上找到的所有示例都会解析输入,直到到达无效符号,然后在不打印有用错误消息的情况下退出。我有
document ::= { category }
category ::= title {entry}
title ::= "[" <name> "]"
entry ::= <key> ":" <value>
我可以在网上找到的所有示例都会解析输入,直到到达无效符号,然后在不打印有用错误消息的情况下退出。我有一个遵循这种行为的工作解析器,但我不确定如何实现有用的错误报告
例如,文档
由零个或多个类别组成。当前两个类别的解析没有错误,但第三个类别包含语法错误时,我该怎么办?如果输入在第二个类别之后结束,而我无法解析第三个类别,因为没有留下任何标记(这不应产生错误消息),该怎么办?我如何区分这些情况?无效行可以通过两种方式生效:成为条目或成为标题。这使我困惑
我希望我的程序在到达上述输入的最后一行时打印类似于
第9行:预期条目或标题的内容。人们通常是如何在递归下降解析器中实现错误消息的?我想你问了几个大的、不相关的问题,我将尝试回答它们:
当前两个类别的解析没有错误,但第三个类别包含语法错误时,我该怎么办
这当然取决于你的要求。从严格意义上讲,这将是验证失败,因为传入的文档实际上不符合您的语法规则,这是由于您提到的违反。它是否抛出错误、返回false、返回部分结果,都符合您的要求
如果输入在第二个类别之后结束,而我无法解析第三个类别,因为没有留下任何标记(这不应产生错误消息),该怎么办?我如何区分这些情况
正如您所说,这里没有问题,因为它符合文档
符号。如果您对实际实现感到困惑,那么这就是实现细节(您没有提供任何代码)
也许您应该尝试将EBNF可视化为更基本的BNF形式,而不使用{}
扩展,下面是一个示例:
document ::= category
category ::= title entries category | title entries
title ::= "[" <name> "]"
entries ::= entry | entries
entry ::= <key> ":" <value>
文档::=类别
类别::=标题条目类别|标题条目
标题::=“[”“]”
条目::=条目|条目
条目::=“:”
我个人认为,用这种方式表示语法可以为需要递归的地方提供更多的指导。例如,在本例中,您需要尝试在类别
符号解析中解析类别
。代码的结构或多或少会遵循这一点——即,如果它不能将下一个符号解析为一个类别,那么无论如何都会返回true(因为第二个定义标题条目紧随其后)
人们通常如何在递归下降解析器中实现错误消息
我自己也有同样的问题,但鉴于我找不到任何答案,我将按以下方式实施:
当我解析和吃令牌时,我将存储消耗的长度
当出现错误时,不要立即抛出它-将其与已解析的令牌数量一起存储
在解析结束时(包括回溯),如果没有可解析的解决方案,抛出消耗最多符号的错误
关键是#2。在实现带回溯的递归下降解析器时,可能会抛出多个误报。我认为就可用性而言,简单地抛出解析得最远的字符串通常是一种不错的启发式方法。我通常会这样做:“解析错误行42:找到“%”,预期“&.”使无效字符串有效是一项非常复杂的任务。首先做一个简单的错误报告,我同样找不到任何好的例子。好办法!
document ::= category
category ::= title entries category | title entries
title ::= "[" <name> "]"
entries ::= entry | entries
entry ::= <key> ":" <value>