Как ParseKit по ассемблеру Постбэк? Где я должен хранить работу, которую я делаю в них?

как использовать функции обратного вызова в parsekit? предположим, у меня есть следующее правило:--4-->

expr_s = expr_p '+' expr_s | expr_p ; 

должен ли я всплывать 3 символа из результирующего PKAssembly и добавлять первые и последние числа, а затем возвращать ответ в стек?
И для вышеуказанного правила, как я должен знать, что это первое или второе правило, которое вызвало совпадение?
Я не понимаю порядок, в котором ParseKit вызывает функции обратного вызова. Мне действительно нужна помощь.

Спасибо Тодда для вашего ответа, имея в виду ваши инструкции, я написал следующие грамматические и обратные функции для простого математического выражения, которое включает сложение и умножение:

- (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?

1 ответов


разработчик ParseKit здесь.

во-первых, лучший способ понять это Стивен Metsker это!--18-->, на котором основан Парсекит.


во-вторых, в кассу мой ответ на другой вопрос о PKAssembly ' s stack и target.


в-третьих, вот мой ответ на другой вопрос PaseKit о неожиданных обратных вызовах.


четвертый, оформить заказ на в ParseKit Тестирует Target (входит в проект ParseKit Xcode. Этот класс имеет обратные вызовы, которые реализуют ту же арифметическую логику, которую вы, похоже, ищете.

также оформить (также в цели тестов ParseKit). Это пример того, как создать арифметическую грамматику в синтаксисе ParseKit.


наконец, вот некоторые мысли более конкретно к вашему примеру выше.

давайте немного проясним вашу грамматику, так как вопрос, который вы задаете, довольно прост, и я не думаю, что для его решения требуется очень сложная грамматика. Вот базовая арифметическая грамматика, которая дает операторам умножения и деления приоритет над сложением и вычитанием:

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

это ! после '+' говорит ParseKit к отбросьте этот токен автоматически. Это делает вещи немного более удобными для вас при написании отзывов.

Примечание если вы хотите, чтобы ваша грамматика имела только приоритет оператора слева направо (например, калькулятор), эта грамматика не будет работать. Если вам это нужно, задайте отдельный вопрос с тегом #ParseKit здесь, в StackOverflow, и я отвечу на него быстро.

я бы определил эти обратные вызовы:

- (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]]];
}

два важных момента are

  1. не волнуйся сколько раз эти обратные вызовы называются. Их можно вызывать чаще, чем вы ожидаете, или в странном порядке.
  2. не храните результаты работы, проделанной в этих обратных вызовах в ivar. Всегда храните свою работу на любом a аргумент target или stack. Обычно я храню временные значения на stack, и конечный результат на target, поскольку я нахожу это наиболее удобным. Но у вас есть возможность.

I напишет этот код драйвера:

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

надеюсь, что это помогает.