From ee2d8d1e9d35235697d3066469d91c09f0477283 Mon Sep 17 00:00:00 2001 From: Bruno BELANYI Date: Sun, 8 Nov 2020 18:42:16 +0100 Subject: [PATCH] pratt: eval: add exponentiation operator This showcases right-associative operators --- src/eval.c | 19 +++++++++++++++++++ src/operators.inc | 14 ++++++++------ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/eval.c b/src/eval.c index 21a43aa..89afc7a 100644 --- a/src/eval.c +++ b/src/eval.c @@ -38,6 +38,8 @@ struct token { LeftFunc(Name) #define INFIX(Name) \ LeftFunc(Name) +#define POWER(Name) \ + LeftFunc(Name) #define TERN(Name) \ LeftFunc(Name) #define PAREN(Name) \ @@ -72,6 +74,8 @@ static const struct { [Name] = {OP_STRING(__VA_ARGS__), OP_SIZE(__VA_ARGS__), NulPrio, LeftPrio, NulFunc(Name), LeftFunc(Name), }, #define INFIX(Name, NulPrio, LeftPrio, ...) \ [Name] = {OP_STRING(__VA_ARGS__), OP_SIZE(__VA_ARGS__), NulPrio, LeftPrio, NULL, LeftFunc(Name), }, +#define POWER(Name, NulPrio, LeftPrio, ...) \ + [Name] = {OP_STRING(__VA_ARGS__), OP_SIZE(__VA_ARGS__), NulPrio, LeftPrio, NULL, LeftFunc(Name), }, #define TERN(Name, NulPrio, LeftPrio, ...) \ [Name] = {OP_STRING(__VA_ARGS__), OP_SIZE(__VA_ARGS__), NulPrio, LeftPrio, NULL, LeftFunc(Name), }, #define PAREN(Name, NulPrio, LeftPrio, ...) \ @@ -244,6 +248,21 @@ bool eval_string(const char *input, int *res) { *res = lhs Operator *res; \ return true; \ } +static int my_pow(int lhs, int rhs) { + if (!rhs) + return 1; + int rec = my_pow(lhs * lhs, rhs / 2); + if (rhs & 1) + rec *= lhs; + return rec; +} +#define POWER(Name, NulPrio, LeftPrio, Operator) \ + LeftFunc(Name) { \ + if (!parse_until(input, res, LeftPrio - 1)) \ + return false; \ + *res = my_pow(lhs, *res); \ + return true; \ + } #define TERN(Name, NulPrio, LeftPrio, Operator) \ LeftFunc(Name) { \ int true_val; \ diff --git a/src/operators.inc b/src/operators.inc index 08b217e..6efed95 100644 --- a/src/operators.inc +++ b/src/operators.inc @@ -8,12 +8,13 @@ #endif // Simple operators -OP( PLUS_PLUS, 120, 110, PREFIX_POSTFIX, ++, '+', '+', 0) -OP(MINUS_MINUS, 120, 110, PREFIX_POSTFIX, --, '-', '-', 0) -OP( NOT, 120, -1, PREFIX, !, '!', 0) -OP( BIT_NOT, 120, -1, PREFIX, ~, '~', 0) -OP( PLUS, 110, 90, PREFIX_INFIX, +, '+', 0) -OP( MINUS, 110, 90, PREFIX_INFIX, -, '-', 0) +OP( PLUS_PLUS, 130, 120, PREFIX_POSTFIX, ++, '+', '+', 0) +OP(MINUS_MINUS, 130, 120, PREFIX_POSTFIX, --, '-', '-', 0) +OP( NOT, 130, -1, PREFIX, !, '!', 0) +OP( BIT_NOT, 130, -1, PREFIX, ~, '~', 0) +OP( PLUS, 120, 90, PREFIX_INFIX, +, '+', 0) +OP( MINUS, 120, 90, PREFIX_INFIX, -, '-', 0) +OP( POWER, -1, 110, POWER, PLACEHOLDER, '*', '*', 0) OP( TIMES, -1, 100, INFIX, *, '*', 0) OP( DIVIDES, -1, 100, INFIX, /, '/', 0) OP( MODULO, -1, 100, INFIX, %, '%', 0) @@ -40,6 +41,7 @@ OP( NUMBER, 0, -1, NOT_OP, PLACEHOLDER, 0) #undef PREFIX #undef PREFIX_INFIX #undef INFIX +#undef POWER #undef TERN #undef PAREN #undef NOT_OP