【问题标题】:How do ParseKit's Assembler Callbacks work? Where should I store the work I do in them?ParseKit 的汇编程序回调如何工作?我应该在哪里存储我在其中所做的工作?
【发布时间】:2012-04-06 15:24:37
【问题描述】:

我应该如何在 parsekit 中使用回调函数?假设我有以下规则:

expr_s = expr_p '+' expr_s | expr_p ; 

我应该从生成的 PKAssembly 中弹出 3 个符号并添加第一个和最后一个数字,然后将答案推回堆栈吗?
对于上述规则,我怎么知道是第一条规则还是第二条规则导致了匹配?
我不明白 ParseKit 调用回调函数的顺序。我真的需要一些帮助。

感谢 Todd 的回复,谨记您的指示 我为一个包含加法和乘法的简单数学表达式编写了以下语法和回调函数:

- (IBAction)press_equals:(id)sender {
NSString *g = @"@start = expr_s; expr_s = expr_p ('+'! expr_p)+ ; expr_p = Number ('*'!     Number)+  ;";
PKParser *p = [[PKParserFactory factory] parserFromGrammar:g assembler:self];
NSString *s = @"3*4+4*8";

[p parse:s];

PKAssembly *res = [p parse:s];
NSLog(@"res %@", res);

}



- (void)parser:(PKParser *)p didMatchExpr_s:(PKAssembly *)a {
NSLog(@"%s %@", __PRETTY_FUNCTION__, a);

NSArray *toks = [a objectsAbove:nil];


double total = 0.0;
for (PKToken *tok in toks) {
    total += tok.floatValue;
}


a.target = [NSNumber numberWithDouble:total];
}
- (void)parser:(PKParser *)p didMatchExpr_p:(PKAssembly *)a {
NSLog(@"%s %@", __PRETTY_FUNCTION__, a);

NSArray *toks = [a objectsAbove:nil];


double total = 1.0;
for (PKToken *tok in toks) {
    total *= tok.floatValue;
}
a.target = [NSNumber numberWithDouble:total];
}

这是我得到的输出:

2012-04-06 22:54:31.975 Calculator[1070:207] -[CalculatorViewController    parser:didMatchExpr_p:] [3, 4]3/*/4^+/4/*/8
2012-04-06 22:54:31.976 Calculator[1070:207] -[CalculatorViewController parser:didMatchExpr_p:] [4, 8]3/*/4/+/4/*/8^
2012-04-06 22:54:31.977 Calculator[1070:207] -[CalculatorViewController parser:didMatchExpr_s:] []3/*/4/+/4/*/8^
2012-04-06 22:54:31.977 Calculator[1070:207] -[CalculatorViewController parser:didMatchExpr_p:] [3, 4]3/*/4^+/4/*/8
2012-04-06 22:54:31.978 Calculator[1070:207] -[CalculatorViewController parser:didMatchExpr_p:] [4, 8]3/*/4/+/4/*/8^
2012-04-06 22:54:31.978 Calculator[1070:207] -[CalculatorViewController parser:didMatchExpr_s:] []3/*/4/+/4/*/8^
2012-04-06 22:54:31.979 Calculator[1070:207] res 0

为什么我的 res 为 0?

【问题讨论】:

  • Sadegh,我已经更新了下面的答案以匹配您修改后的问题。以后,如果您所问内容的细节发生重大变化,请考虑提出一个新问题。

标签: objective-c parsekit


【解决方案1】:

ParseKit 的开发者在这里。

首先,理解这些东西的最好方法是 Steven Metsker's book,ParseKit 就是基于它。


二、结账my answer to another question about PKAssembly's stack and target.


第三,这里是my answer to another PaseKit question about unexpected callbacks


第四,检查 ParseKit Tests Target 中的TDArithmeticParser.m file(包含在 ParseKit Xcode 项目中。此类具有实现您似乎正在寻找的相同类型的算术逻辑的回调。

还检查arithmetic.grammar file(也在 ParseKit 测试目标中)。这是一个如何在 ParseKit 语法中设计算术语法的示例。


最后,对于上面的示例,这里有一些更具体的想法。

让我们稍微澄清一下您的语法,因为您提出的问题非常基本,我认为它不需要非常复杂的语法来解决。这是一个基本的算术语法,它使乘法和除法运算符优先于加法和减法:

@start         = expr;
expr           = term (plusTerm | minusTerm)*;
term           = factor (timesFactor | divFactor)*;
plusTerm       = '+'! term;
minusTerm      = '-'! term;
timesFactor    = '*'! factor;
divFactor      = '/'! factor;
factor         = Number;

'+' 之后的 ! 告诉 ParseKit 自动丢弃此令牌。这使您在编写回调时更加方便。

注意,如果您希望语法只有从左到右的运算符优先级(如计算器),则此语法将不起作用。如果您需要,请在 StackOverflow 上提出一个标记为 #ParseKit 的单独问题,我会及时回答。

我会定义这些回调:

- (void)parser:(PKParser *)p didMatchExpr:(PKAssembly *)a {
    NSLog(@"%s %@", __PRETTY_FUNCTION__, a);

    NSNumber *n = [a pop];

    // the expr is complete, and its value is on the stack.
    // important! wrap things up by 
    // storing your work in `a.target`. not in an ivar.
    a.target = n;
}

- (void)parser:(PKParser *)p didMatchFactor:(PKAssembly *)a {
    NSLog(@"%s %@", __PRETTY_FUNCTION__, a);

    // a number token was found. store its number value on the stack
    PKToken *tok = [a pop];
    [a push:[NSNumber numberWithDouble:tok.floatValue]];
}

- (void)parser:(PKParser *)p didMatchPlusTerm:(PKAssembly *)a {
    NSLog(@"%s %@", __PRETTY_FUNCTION__, a);

    // a '+' expr was found. pop off the two operands and add them
    // store the result on the stack temporarily
    NSNumber *n2 = [a pop];
    NSNumber *n1 = [a pop];
    [a push:[NSNumber numberWithDouble:[n1 doubleValue] + [n2 doubleValue]]];
}

- (void)parser:(PKParser *)p didMatchMinusTerm:(PKAssembly *)a {
    NSLog(@"%s %@", __PRETTY_FUNCTION__, a);

    // a '-' expr was found. pop off the two operands and subtract them
    // store the result on the stack temporarily
    NSNumber *n2 = [a pop];
    NSNumber *n1 = [a pop];
    [a push:[NSNumber numberWithDouble:[n1 doubleValue] - [n2 doubleValue]]];
}

- (void)parser:(PKParser *)p didMatchTimesFactor:(PKAssembly *)a {
    NSLog(@"%s %@", __PRETTY_FUNCTION__, a);

    // a '*' expr was found. pop off the two operands and multiply them
    // store the result on the stack temporarily
    NSNumber *n2 = [a pop];
    NSNumber *n1 = [a pop];
    [a push:[NSNumber numberWithDouble:[n1 doubleValue] * [n2 doubleValue]]];
}

- (void)parser:(PKParser *)p didMatchDivideFactor:(PKAssembly *)a {
    NSLog(@"%s %@", __PRETTY_FUNCTION__, a);

    // a '/' expr was found. pop off the two operands and divide them
    // store the result on the stack temporarily
    NSNumber *n2 = [a pop];
    NSNumber *n1 = [a pop];
    [a push:[NSNumber numberWithDouble:[n1 doubleValue] / [n2 doubleValue]]];
}

两个重点

  1. 不用担心这些回调被调用了多少次。它们的调用次数可能比您预期的要多,或者调用顺序看起来很奇怪。
  2. 不要将这些回调中完成的工作结果存储在 ivar 中。始终将您的工作存储在 a 参数的 targetstack 上。我通常将临时值存储在stack 上,并将最终结果存储在target 上,因为我觉得这样最方便。但是你有灵活性。

我会写这个驱动代码:

NSString *g = .. // fetch grammar above
PKParser *p = [[PKParserFactory factory] parserFromGrammar:g assembler:self];
NSString *s = @"3*4+4*8";

PKAssembly *res = [p parse:s];
NSLog(@"res %@", res);

我看到了这个日志输出:

-[DebugAppDelegate parser:didMatchFactor:] [3]3^*/4/+/4/*/8
-[DebugAppDelegate parser:didMatchFactor:] [3, 4]3/*/4^+/4/*/8
-[DebugAppDelegate parser:didMatchTimesFactor:] [3, 4]3/*/4^+/4/*/8
-[DebugAppDelegate parser:didMatchFactor:] [12, 4]3/*/4/+/4^*/8
-[DebugAppDelegate parser:didMatchFactor:] [12, 4, 8]3/*/4/+/4/*/8^
-[DebugAppDelegate parser:didMatchTimesFactor:] [12, 4, 8]3/*/4/+/4/*/8^
-[DebugAppDelegate parser:didMatchPlusTerm:] [12, 4]3/*/4/+/4^*/8
-[DebugAppDelegate parser:didMatchPlusTerm:] [12, 32]3/*/4/+/4/*/8^
-[DebugAppDelegate parser:didMatchExpr:] [3]3^*/4/+/4/*/8
-[DebugAppDelegate parser:didMatchExpr:] [12]3/*/4^+/4/*/8
-[DebugAppDelegate parser:didMatchExpr:] [16]3/*/4/+/4^*/8
-[DebugAppDelegate parser:didMatchExpr:] [44]3/*/4/+/4/*/8^
res 44

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-16
    • 1970-01-01
    • 2011-02-15
    • 1970-01-01
    • 2017-05-30
    • 2012-03-09
    相关资源
    最近更新 更多