ここでParseKitの開発者。
まず、このことを理解するための最良の方法は、 ParseKitのベースとなっているStevenMetskerの本です。
次に、とについての別の質問に対する私の答えを確認してください。PKAssembly
stack
target
第三に、予期しないコールバックに関する別のPaseKitの質問に対する私の答えです。
第4に、ParseKit Tests Target(ParseKit Xcodeプロジェクトに含まれています。このクラスには、探しているのと同じ種類の算術論理を実装するコールバックがあります)でTDArithmeticParser.m
ファイルをチェックアウトします。
また、arithmetic.grammar
ファイルをチェックアウトします(ParseKit Tests Targetでも)。これは、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]]];
}
2つの重要なポイントは
- これらのコールバックが何回呼び出されるかについて心配する必要はありません。予想よりも何度も呼び出されたり、奇妙に見える順序で呼び出されたりする場合があります。
- これらのコールバックで行われた作業の結果を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
お役に立てれば。