Как работают обратные вызовы ассемблера ParseKit? Где я должен хранить работу, которую я делаю в них?
Как я должен использовать функции обратного вызова в parsekit? предположим, у меня есть следующее правило:
expr_s = expr_p '+' expr_s | expr_p ;
я должен вытолкнуть 3 символа из полученной сборки PKA и добавить первые и последние числа, а затем отправить ответ обратно в стек?
И для вышеупомянутого правила, как я должен знать, что это первое или второе правило, которое вызвало совпадение?
Я не понимаю порядок, в котором 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
Почему мой отдых 0?
1 ответ
Разработчик ParseKit здесь.
Во-первых, лучший способ понять это - книга Стивена Метскера, на которой основан ParseKit.
Во-вторых, зацените мой ответ на другой вопрос о PKAssembly
"s stack
а также target
,
В-третьих, вот мой ответ на другой вопрос PaseKit о неожиданных обратных вызовах.
В-четвертых, оформить заказ TDArithmeticParser.m
файл в цели тестирования ParseKit (входит в проект 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 об автоматическом сбросе этого токена. Это делает вещи немного более удобными для вас при написании ваших обратных вызовов.
Обратите внимание, что если вы хотите, чтобы ваша грамматика имела приоритет оператора слева направо (например, калькулятор), эта грамматика не будет работать. Если вам это нужно, задайте отдельный вопрос с тегом #ParseKit здесь, в Stackru, и я отвечу на него быстро.
Я бы определил эти обратные вызовы:
- (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]]];
}
Два важных момента
- Не беспокойтесь о том, сколько раз вызывались эти обратные вызовы. Они могут быть вызваны чаще, чем вы ожидаете, или в странном порядке.
- Не храните результаты работы, выполненной в этих обратных вызовах, в иваре. Всегда храните свою работу на
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
Надеюсь это поможет.