2012-04-03 38 views
4

我想知道是否有方法可以找回PKParser在遇到语法错误之前解析了多少程序集。如何使用ParseKit框架查找解析错误

参考:http://parsekit.com/

我使用的基本描述前缀符号表达语言的语法。

例如:

给你的标准前缀表示法表达语法和字符串 “(+ A - BC))” 我想检索[(+,一],其中匹配,所以我可以给用户一些想法以修正他们的错误,但是完整匹配和bestMatchFor不会返回任何我可以用来找到该信息的东西。

理想情况下,我想说'('是预期的,但它没有必要像我使用的那样简单的语法。

从作为用户手册提到的书,它似乎如果我需要为此创建一个自定义分析器,但是我希望可能我错过了框架中的某些东西。

想法?

回答

3

开发商ParseKit这里。

ParseKit中有两个功能可用于帮助提供描述输入中遇到的分析错误的用户可读提示。

  1. -[PKParser bestMatchFor:]
  2. PKTrack

这听起来像你知道的-bestMatchFor:方法,即使它没有做,你在这种情况下会发生什么。

我认为PKTrack这个班在这里会更有帮助。如Metsker's book中所述,PKTrackPKSequence完全相同,区别仅在于其子分析器是必需的,并且在其所有子分析器不匹配时都会引发错误(并附带有用的错误消息)。

因此,这里是为您的示例输入语法:

@start   = '(' expr ')' | expr; 
expr   = ('+' | '-') term term; 
term   = '(' expr ')' | Word; 

连续列出的任何产品有一个序列 - 而是可以曲目。

将这些序列更改为曲目的好处是,如果输入不匹配,将会抛出一个NSException带有人类可读的分析错误消息。缺点是你现在必须将工厂生成的解析器的所有用法都包含在try/catch块中以捕获这些跟踪异常。

目前(或现在,至少)的问题是PKParserFactory从来没有使用轨道生成分析器。相反,它总是使用序列。

所以我只是增加了一个新的选项在主干头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 : - 

希望这有助于。

3

我也在与这个问题搏斗。为了使-bestMatchFor:在识别错误​​条件中有用,应该有PKAssembly的公共接口中的方法指示是否有更多的标记/字符要被解析。 -completeMatchFor:能够确定错误状态,因为它可以访问专用-hasMore方法。也许PKAssembly-hasMore方法应该是公开的。

我看着PKTrack但由于我想以编程方式处理错误,所以对我没有用。

我的结论是我要么写自己的自定义Track解析器,要么改变框架并公开-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]; 
} 

如果发生错误,errorOffset将包含无法识别的令牌的位置。