我想知道是否有办法在返回PKParser遇到语法错误之前解析的程序集中有多远。
我使用的语法基本上描述了前缀表示法语言。
例如:
给出标准前缀表示法语法和字符串“(+ a - b c))” 我想检索匹配的[(,+,a),所以我可以让用户知道在哪里修复它们的错误,但是completeMatchFor和bestMatchFor不会返回任何我可以用来查找它的内容资讯
理想情况下,我想说'('是预期的,但对于语法来说,没有必要像我正在使用的那样简单。
从作为用户手册提到的书中,似乎我需要为此创建一个自定义解析器,但我希望我可能只是错过了框架中的某些内容。
思想?
答案 0 :(得分:3)
ParseKit的开发人员。
ParseKit中有两个功能,可用于帮助提供描述输入中遇到的解析错误的用户可读提示。
-[PKParser bestMatchFor:]
PKTrack
类听起来你知道-bestMatchFor:
方法,即使它在这种情况下没有达到预期效果。
我认为PKTrack
课程在这里会更有帮助。正如Metsker's book中所述,PKTrack
与PKSequence
完全相同,只是它的子分析符是必需的,并且当所有子分析符不匹配时会抛出错误(带有有用的错误消息)。
所以这是你的示例输入的语法:
@start = '(' expr ')' | expr;
expr = ('+' | '-') term term;
term = '(' expr ')' | Word;
任何连续列出的作品都是一个序列 - 但可能是一个轨道。
将这些序列更改为轨道的好处是,如果输入不匹配,将引发NSException
,并带有人类可读的解析错误消息。缺点是您现在必须将工厂生成的解析器的所有用法包装在try / catch块中以捕获这些跟踪异常。
目前(或者至少在此之前)问题是PKParserFactory
从未使用Tracks生成解析器。相反,它总是使用Sequences。
所以我只是在Google Code的行李箱头添加了一个新选项(你需要udpate)。
#define USE_TRACK 0
在
PKParserFactory.m
默认情况下为0
。如果将此定义更改为1
,将使用轨道而不是序列。所以考虑到上面的语法和无效输入,如下所示:
(+ a - b c))
和此客户端代码:
NSString *g = // fetch grammar above
PKParser *p = [[PKParserFactory factory] parserFromGrammar:g assembler:self];
NSString *s = @"(+ a - b c))";
@try {
PKAssembly *res = [p parse:s];
NSLog(@"res %@", res);
}
@catch (NSException *exception) {
NSLog(@"Parse Error:%@", exception);
}
你会得到一个很好的人类可读错误:
Parse Error:
After : ( + a
Expected : Alternation (term)
Found : -
希望有所帮助。
答案 1 :(得分:3)
我也在努力解决这个问题。为了使-bestMatchFor:
在识别错误条件方面有用,PKAssembly
的公共接口中应该有方法指示是否有更多的令牌/字符需要解析。 -completeMatchFor:
能够确定错误状态,因为它可以访问私有-hasMore
方法。也许PKAssembly
的{{1}}方法应该是公开的。
我查看了-hasMore
,但由于我想以编程方式处理错误,因此对我没用。
我的结论是我要么编写自己的自定义Track解析器,要么改变框架并公开PKTrack
。还有其他方法来处理错误吗?
在我找到更好的方法来检测错误之前,我已将以下内容添加到包含自定义解析器实现的文件中:
-hasMore
在我的解析方法中:
@interface PKAssembly ()
- (BOOL)hasMore;
- (id)peek;
@end
@implementation PMParser
...
@end
如果发生错误,PKAssembly* a = [PKTokenAssembly assemblyWithString:s];
PKAssembly* best = [self bestMatchFor:a];
PMParseNode* node = nil;
BOOL error = NO;
NSUInteger errorOffset = 0;
if (best == nil) // Anything recognized?
{
error = YES;
}
else
{
if ([best hasMore]) // Partial recognition?
{
PKToken* t = [best peek];
error = YES;
errorOffset = t.offset;
}
node = [best pop];
}
将包含无法识别的令牌的位置。