如何使用ParseKit框架找到解析错误

时间:2012-04-03 23:24:04

标签: objective-c parsekit

我想知道是否有办法在返回PKParser遇到语法错误之前解析的程序集中有多远。

参考:http://parsekit.com/

我使用的语法基本上描述了前缀表示法语言。

例如:

给出标准前缀表示法语法和字符串“(+ a - b c))” 我想检索匹配的[(,+,a),所以我可以让用户知道在哪里修复它们的错误,但是completeMatchFor和bestMatchFor不会返回任何我可以用来查找它的内容资讯

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

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

思想?

2 个答案:

答案 0 :(得分:3)

ParseKit的开发人员。

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

  1. -[PKParser bestMatchFor:]
  2. PKTrack
  3. 听起来你知道-bestMatchFor:方法,即使它在这种情况下没有达到预期效果。

    我认为PKTrack课程在这里会更有帮助。正如Metsker's book中所述,PKTrackPKSequence完全相同,只是它的子分析符是必需的,并且当所有子分析符不匹配时会抛出错误(带有有用的错误消息)。

    所以这是你的示例输入的语法:

    @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]; } 将包含无法识别的令牌的位置。