6

parsekitでコールバック関数をどのように使用する必要がありますか?次のルールがあるとします。

expr_s = expr_p '+' expr_s | expr_p ; 

結果のPKAssemblyから3つのシンボルをポップし、最初と最後の数字を追加してから、答えをスタックにプッシュする必要がありますか?
そして、上記のルールの場合、一致を引き起こしたのは最初または2番目のルールであることをどのように知る必要がありますか?
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

なぜ私の解像度は0ですか?

4

1 に答える 1

8

ここでParseKitの開発者。

まず、このことを理解するための最良の方法は、 ParseKitのベースとなっているStevenMetskerの本です。


次に、とについて別の質問に対する私の答えを確認してください。PKAssemblystacktarget


第三に、予期しないコールバックに関する別の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つの重要なポイント

  1. これらのコールバックが何回呼び出されるかについて心配する必要はありません。予想よりも何度も呼び出されたり、奇妙に見える順序で呼び出されたりする場合があります。
  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

お役に立てれば。

于 2012-04-06T16:30:40.293 に答える