ParseKit的开发者在这里。
首先,理解这些东西的最好方法是Steven Metsker 的书,ParseKit 就是基于该书。
其次,查看我对另一个关于PKAssembly
'sstack
和target
.
第三,这是我对另一个关于意外回调的 PaseKit 问题的回答。
第四,检查ParseKit测试目标中的TDArithmeticParser.m
文件(包含在 ParseKit Xcode 项目中。此类具有实现您似乎正在寻找的相同类型的算术逻辑的回调。
同时签出arithmetic.grammar
文件(也在 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]]];
}
两个重要的点是
- 不用担心这些回调被调用了多少次。它们的调用次数可能比您预期的要多,或者调用的顺序看起来很奇怪。
- 不要将这些回调中完成的工作结果存储在 ivar 中。始终将您的工作存储在
a
参数的target
或stack
. 我通常将临时值存储在 上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
希望这可以帮助。