From 1f31d9e372ab28e799064083cde9a78576491483 Mon Sep 17 00:00:00 2001 From: Tibor Bizjak Date: Sun, 9 Jul 2023 14:06:16 +0200 Subject: [PATCH] k&r 04-05: added math.h bindings --- k&r/04-funcs-and-prog-struct/04-calc.c | 78 ++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 10 deletions(-) diff --git a/k&r/04-funcs-and-prog-struct/04-calc.c b/k&r/04-funcs-and-prog-struct/04-calc.c index 895bb98..e3f37dd 100644 --- a/k&r/04-funcs-and-prog-struct/04-calc.c +++ b/k&r/04-funcs-and-prog-struct/04-calc.c @@ -1,6 +1,7 @@ #include #include #include +#include #define printerr(format, ...) printf("error: " format "\n", ##__VA_ARGS__) @@ -18,34 +19,91 @@ void clear(void); /* --------- ERROR MESSAGES */ #define ZERODIV_ERR "zero divisor" +#define DOMAIN_ERR "operand not in domain [%d, %d]" +#define NEG_ERR "negative operand %g" #define FULL_STACK_ERR "stack full, can't push %g" #define EMPTY_STACK_ERR "stack empty" -/* --------- CALCULATOR FUNCTIONS TYPES */ -/* command application */ +/* --------- CALCULATOR FUNCTION TYPES */ +/* renaming macro */ +#define CALL(TOKEN, F, APPLY, ...) APPLY(F, ##__VA_ARGS__) + +/* value */ +#define VALUE(ID) push(ID) + +/* command */ #define COMMAND(CMD) CMD() /* commutative operator */ #define COMM_OP(OP) push(pop() OP pop()) /* non-commutative operator */ #define NONC_OP(OP, T, ...) \ - do { T op2 = pop(); __VA_ARGS__ push(((T) pop()) OP op2); } while (0) + do { T op = pop(); __VA_ARGS__ push(((T) pop()) OP op); } while (0) /* nonzero second operand */ -#define NONZ_SND_OP if (!op2) printerr(ZERODIV_ERR); else +#define NONZ_SND_OP if (!op) printerr(ZERODIV_ERR); else + +/* unary function */ +#define UNARY_FUN(F) push(F(pop())) +/* unary function with tests */ +#define UNARY_T_FUN(F, T, ...) do { double op = pop(); __VA_ARGS__ push(F(op)); } while (0) +/* operator in range */ +#define IN_RANGE(A, B) if (op < A || op > B) printerr(DOMAIN_ERR, A, B); else +/* operator > 0 */ +#define NON_NEG if (op < 0) printerr(NEG_ERR, op); else + +/* commutative function */ +#define COMM_FUN(F) push(F(pop(), pop())) +/* non-commutative function */ +#define NONC_FUN(F, T, ...) \ + do { T op = pop(); __VA_ARGS__ push(F(pop(), op)); } while (0) /* --------- CALCULATOR FUNCTIONS */ -#define FUNCTIONS \ + +#define COMMANDS \ + X(print, COMMAND) \ + X(dup, COMMAND) \ + X(swap, COMMAND) \ + X(clear, COMMAND) + +#define OPERATORS \ X(+, COMM_OP) \ X(*, COMM_OP) \ X(-, NONC_OP, double) \ X(/, NONC_OP, double, NONZ_SND_OP) \ X(%, NONC_OP, int, NONZ_SND_OP) \ - X(print, COMMAND) \ - X(dup, COMMAND) \ - X(swap, COMMAND) \ - X(clear, COMMAND) + X(>, NONC_OP, double) \ + X(<, NONC_OP, double) \ + X(<=, NONC_OP, double) \ + X(>=, NONC_OP, double) + +#define MATH_H_BINDINGS \ + X(sin, UNARY_FUN) \ + X(cos, UNARY_FUN) \ + X(tan, UNARY_FUN) \ + X(acos, UNARY_T_FUN, double, IN_RANGE(-1, 1)) \ + X(asin, UNARY_T_FUN, double, IN_RANGE(-1, 1)) \ + X(atan, UNARY_FUN) \ + X(exp, UNARY_FUN) \ + X(log, UNARY_T_FUN, double, NON_NEG) \ + X(log10, UNARY_T_FUN, double, NON_NEG) \ + X(log2, UNARY_T_FUN, double, NON_NEG) \ + X(pow, NONC_FUN, double) \ + X(sqrt, UNARY_T_FUN, double, NON_NEG) \ + X(ceil, UNARY_FUN) \ + X(floor, UNARY_FUN) \ + X(round, UNARY_FUN) \ + X(abs, CALL, fabs, UNARY_FUN) \ + X(max, CALL, fmax, COMM_FUN) \ + X(min, CALL, fmin, COMM_FUN) \ + X(pi, CALL, M_PI, VALUE) + + +#define TOKENS \ + COMMANDS \ + OPERATORS \ + MATH_H_BINDINGS /* --------- COMMAND DEFINITIONS */ @@ -78,7 +136,7 @@ int main() if (!strcmp(#F, token)) \ APPLY(F, ##__VA_ARGS__); \ else - FUNCTIONS + TOKENS #undef X push(atof(token)); }