From 4d95f4515b958aeb13dc11b2e9304184849273fd Mon Sep 17 00:00:00 2001 From: Tibor Bizjak Date: Sat, 8 Jul 2023 16:37:54 +0200 Subject: [PATCH] k&r 04-03: rewrote calculator, added modulo and negative numbers --- k&r/04-funcs-and-prog-struct/04-calc.c | 120 +++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 k&r/04-funcs-and-prog-struct/04-calc.c diff --git a/k&r/04-funcs-and-prog-struct/04-calc.c b/k&r/04-funcs-and-prog-struct/04-calc.c new file mode 100644 index 0000000..b564b2f --- /dev/null +++ b/k&r/04-funcs-and-prog-struct/04-calc.c @@ -0,0 +1,120 @@ +#include +#include +#include + + +#define printerr(format, ...) printf("error: " format "\n", ##__VA_ARGS__) +void push(double x); +double pop(void); +int stack_len(void); + +/* --------- ERROR MESSAGES */ +#define ZERODIV_ERR "zero divisor" + + +/* --------- CALCULATOR FUNCTIONS */ +/* commutative operator application */ +#define COMM_OP(OP) push(pop() OP pop()) +/* non-commutative operator application */ +#define NONC_OP(OP, T, ...) \ + do { T op2 = pop(); __VA_ARGS__ push(((T) pop()) OP op2); } while (0) +/* nonzero second operand operator application */ +#define NONZ_OP(OP, T) \ + NONC_OP(OP, T, if (!op2) printerr(ZERODIV_ERR); else) + +#define FUNCTIONS \ + X(+, COMM_OP) \ + X(*, COMM_OP) \ + X(-, NONC_OP, double) \ + X(/, NONZ_OP, double) \ + X(%, NONZ_OP, int) + + + +#define MAXTOKEN 100 +int gettoken(char *token, int max_t); + +/* reverse Polish calculator */ +int main() +{ + char token[MAXTOKEN + 1]; + double op2; + int t_len; + + while (t_len = gettoken(token, MAXTOKEN)) { + if (t_len < 0) + printf("\t%g\n", pop()); + else + #define X(F, APPLY, ...) \ + if (!strcmp(#F, token)) \ + APPLY(F, ##__VA_ARGS__); \ + else + FUNCTIONS + #undef X + push(atof(token)); + } + printf("%g\n", pop()); + + return 0; +} + +/* -------- PARSING FUNCTIONS */ +#include + +#define BLANK ' ' + +/* gettoken: get next space delimited token from input + * return token length, -1 on newline and 0 on EOF */ +int gettoken(char *token, int t_max) +{ + + static int c = BLANK; + + while (isspace(c) && c != '\n') /* remove leading whitespace */ + c = getchar(); + + if (c == '\n') { /* newline is a token */ + c = BLANK; + return -1; + } + + /* fetch token */ + int i; + for (i = 0; i < t_max && c != EOF && !isspace(c); c = getchar(), i++) + token[i] = c; + + token[i] = '\0'; + return i; +} + +/* ------ GLOBAL STACK */ +#define MAXVAL 100 /* maximum depth of val stack */ + +int sp = 0; +double val[MAXVAL]; + +int stack_len() +{ + return sp; +} + +/* push: push f onto value stack */ +void push(double f) +{ + if (sp < MAXVAL) + val[sp++] = f; + else + printf("error: stack full, can't push %g\n", f); + +} + +/* pop: pop and return top value from stack */ +double pop(void) +{ + if (sp) + return val[--sp]; + printf("error: stack empty\n"); + return 0.0; +} + +