From cf145e880be6e1ca7003b0082098678bd29f204c Mon Sep 17 00:00:00 2001 From: Tibor Bizjak Date: Mon, 10 Jul 2023 17:48:07 +0200 Subject: [PATCH] moved stack to 04-glob-stack.h moved token definitons to 04-token.h --- k&r/04-funcs-and-prog-struct/04-calc.c | 131 +------------------ k&r/04-funcs-and-prog-struct/04-glob-stack.h | 47 +++++++ k&r/04-funcs-and-prog-struct/04-tokens.h | 92 +++++++++++++ 3 files changed, 145 insertions(+), 125 deletions(-) create mode 100644 k&r/04-funcs-and-prog-struct/04-glob-stack.h create mode 100644 k&r/04-funcs-and-prog-struct/04-tokens.h 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 48dac3f..e2c3d51 100644 --- a/k&r/04-funcs-and-prog-struct/04-calc.c +++ b/k&r/04-funcs-and-prog-struct/04-calc.c @@ -1,10 +1,12 @@ #include #include #include -#include #include #include +#define MAX_STACK 100 +#include "04-glob-stack.h" +#include "04-tokens.h" /* --------- ERROR MESSAGES */ #define printerr(format, ...) printf("error: " format "\n", ##__VA_ARGS__) @@ -12,53 +14,19 @@ #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" -#define SHORT_STACK_ERR "not enough elements on stack" #define UNKNOWN_TOKEN_ERR "unknown token %s" #define VAR_NOT_SET_ERR "variable %c has no value" /* --------- PROMPT FORMATS */ -#define PROMPT_F ">> " -#define POP_PRINT_F "pop -> %.8g\n" -#define PEEK_PRINT_F "peek -> %.8g\n" +#define PROMPT_F ">>> " +#define POP_PRINT_F "%.8g\n" +#define PEEK_PRINT_F "-> %.8g\n" #define INITIAL_PROMPT_F \ "A simple polish notation calculator.\n" \ "Type 'help' for a list of available commands\n" \ PROMPT_F - -/* ------ GLOBAL VALUE STACK */ -#define MAXVAL 100 /* maximum depth of val stack */ - -int sp = 0; -double val[MAXVAL]; - -/* length: current length of stack */ -#define length() sp -/* push: push f onto value stack */ -#define push(x) \ - ((sp < MAXVAL) ? val[sp++] = x : printerr(FULL_STACK_ERR, (double) (x))) -/* pop: pop and return top value from stack */ -double pop(void) -{ - return sp ? val[--sp] : (printerr(EMPTY_STACK_ERR), 0); -} -/* peek: return top value from stack, leave stack unchanged */ -#define peek() (sp ? val[sp-1] : (printerr(EMPTY_STACK_ERR), 0)) -/* clear: clear stack */ -#define clear() (sp = 0) -/* dup: duplicate top element */ -#define dup() do { double tmp = peek(); push(tmp); } while (0) -/* swap: swap top two elements */ -#define swap() \ - do { if (sp < 2) printerr(SHORT_STACK_ERR); else { \ - double tmp = peek(); \ - val[sp-1] = val[sp-2], val[sp-2] = tmp; \ - } \ - } while (0) - - /* -------- STACK PRINTING FUNCTIONS */ double lst_print; /* print_peek: print top element, leave stack unchanged */ @@ -103,93 +71,6 @@ void print_vars(void) printf("%c = %.8g\n", i+'a', var_vals[i]); } -/* --------- CALCULATOR FUNCTION TYPES */ -/* the following macros allow us to call native c constructs - * in a declarative style */ - -/* 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, ...) \ - do { double op = pop(); __VA_ARGS__ push(pop() OP op); } while (0) -/* 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) -/* commutative function */ -#define COMM_FUN(F) push(F(pop(), pop())) -/* non-commutative function */ -#define NONC_FUN(F, ...) \ - do { double op = pop(); __VA_ARGS__ push(F(pop(), op)); } while (0) - -/* OPERAND TESTS */ -/* nonzero operand */ -#define NONZ_SND_OP if (!op) printerr(ZERODIV_ERR); else -/* operator in range */ -#define IN_RANGE(A, B) if (op < A || op > B) printerr(DOMAIN_ERR, A, B); else -/* non-negative operand */ -#define NON_NEG if (op < 0) printerr(NEG_ERR, op); else - - -/* --------- CALCULATOR FUNCTIONS */ -/* renaming macro */ -#define CALL(TOKEN, F, APPLY, ...) APPLY(F, ##__VA_ARGS__) - -#define COMMANDS \ - X(_, "last printed value", CALL, lst_print, VALUE) \ - X(ENTER, "pop top of stack and print it", CALL, print_pop, COMMAND) \ - X(print, "print top of stack", CALL, print_peek, COMMAND) \ - X(dup, "duplicate top of stack", COMMAND) \ - X(swap, "swap top two elements of stack", COMMAND) \ - X(clear, "clear stack", COMMAND) \ - X(help, "print all available commands", COMMAND) \ - X(vars, "print defined variables and their values", CALL, print_vars, COMMAND) - -#define MOD(x, y) ((int) (x) % (int) (y)) - -#define OPERATORS \ - X(+, "add operands", COMM_OP) \ - X(*, "multiply operands", COMM_OP) \ - X(-, "substact operands", NONC_OP) \ - X(/, "divide operands", NONC_OP, NONZ_SND_OP) \ - X(%, "apply modulo to operands", CALL, MOD, NONC_FUN, NONZ_SND_OP) \ - X(>, "greater than", NONC_OP) \ - X(<, "less than", NONC_OP) \ - X(<=, "less than or equal", NONC_OP) \ - X(>=, "greater than or equal", NONC_OP) \ - X(==, "test equality", COMM_OP) - -#define MATH_H_BINDINGS \ - X(sin, "sine", UNARY_FUN) \ - X(cos, "cosine", UNARY_FUN) \ - X(tan, "tangent", UNARY_FUN) \ - X(acos, "arc cosine", UNARY_T_FUN, IN_RANGE(-1, 1)) \ - X(asin, "arc sine", UNARY_T_FUN, IN_RANGE(-1, 1)) \ - X(atan, "arc tangent", UNARY_FUN) \ - X(exp, "exponentional function", UNARY_FUN) \ - X(log, "natural logarithm", UNARY_T_FUN, NON_NEG) \ - X(log10, "logarithm of base 10", UNARY_T_FUN, NON_NEG) \ - X(log2, "logarithm of base 2", UNARY_T_FUN, NON_NEG) \ - X(pow, "power function", NONC_FUN) \ - X(sqrt, "square root", UNARY_T_FUN, NON_NEG) \ - X(ceil, "round up value", UNARY_FUN) \ - X(floor, "round down value", UNARY_FUN) \ - X(round, "round to nearest", UNARY_FUN) \ - X(abs, "absolute value", CALL, fabs, UNARY_FUN) \ - X(max, "maximum value", CALL, fmax, COMM_FUN) \ - X(min, "minimum value", CALL, fmin, COMM_FUN) \ - X(pi, "value of pi", CALL, M_PI, VALUE) - -#define TOKENS \ - COMMANDS \ - OPERATORS \ - MATH_H_BINDINGS - /* variable manipulation tokens */ #define VAR_TOKENS \ X('=', "pop value top from stack and set %s to value", set_var) \ diff --git a/k&r/04-funcs-and-prog-struct/04-glob-stack.h b/k&r/04-funcs-and-prog-struct/04-glob-stack.h new file mode 100644 index 0000000..e7c2be8 --- /dev/null +++ b/k&r/04-funcs-and-prog-struct/04-glob-stack.h @@ -0,0 +1,47 @@ +#ifndef STACK_H + +#define STACK_H +#define printerr(format, ...) printf("error: " format, ##__VA_ARGS__) + +#define EMPTY_STACK_ERR "stack empty" +#define SHORT_STACK_ERR "not enough elements on stack" + +#ifndef MAX_STACK +#define MAX_STACK 100 +#endif // MAX_STACK + +static int sp = 0; +static double val[MAX_STACK]; + +/* length: current length of stack */ +#define length() sp + +/* push: push f onto value stack */ +#define push(x) \ + ((sp < MAX_STACK) ? val[sp++] = x : printerr(FULL_STACK_ERR, (double) (x))) + +/* pop: pop and return top value from stack */ +double pop(void) +{ + return sp ? val[--sp] : (printerr(EMPTY_STACK_ERR), 0); +} + +/* peek: return top value from stack, leave stack unchanged */ +#define peek() (sp ? val[sp-1] : (printerr(EMPTY_STACK_ERR), 0)) + +/* clear: clear stack */ +#define clear() (sp = 0) + +/* dup: duplicate top element */ +#define dup() do { double tmp = peek(); push(tmp); } while (0) + +/* swap: swap top two elements */ +#define swap() \ + do { if (sp < 2) printerr(SHORT_STACK_ERR); else { \ + double tmp = peek(); \ + val[sp-1] = val[sp-2], val[sp-2] = tmp; \ + } \ + } while (0) + +#undef printerr +#endif // STACK_H diff --git a/k&r/04-funcs-and-prog-struct/04-tokens.h b/k&r/04-funcs-and-prog-struct/04-tokens.h new file mode 100644 index 0000000..697a089 --- /dev/null +++ b/k&r/04-funcs-and-prog-struct/04-tokens.h @@ -0,0 +1,92 @@ +#ifndef TOKENS_H + +#define TOKENS_H +#include +/* --------- CALCULATOR FUNCTION TYPES */ +/* the following macros allow us to call native c constructs + * in a declarative style */ + +/* 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, ...) \ + do { double op = pop(); __VA_ARGS__ push(pop() OP op); } while (0) +/* 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) +/* commutative function */ +#define COMM_FUN(F) push(F(pop(), pop())) +/* non-commutative function */ +#define NONC_FUN(F, ...) \ + do { double op = pop(); __VA_ARGS__ push(F(pop(), op)); } while (0) + +/* OPERAND TESTS */ +/* nonzero operand */ +#define NONZ_SND_OP if (!op) printerr(ZERODIV_ERR); else +/* operator in range */ +#define IN_RANGE(A, B) if (op < A || op > B) printerr(DOMAIN_ERR, A, B); else +/* non-negative operand */ +#define NON_NEG if (op < 0) printerr(NEG_ERR, op); else + + +/* --------- CALCULATOR FUNCTIONS */ +/* renaming macro */ +#define CALL(TOKEN, F, APPLY, ...) APPLY(F, ##__VA_ARGS__) + +#define COMMANDS \ + X(_, "last printed value", CALL, lst_print, VALUE) \ + X(ENTER, "pop top of stack and print it", CALL, print_pop, COMMAND) \ + X(print, "print top of stack", CALL, print_peek, COMMAND) \ + X(dup, "duplicate top of stack", COMMAND) \ + X(swap, "swap top two elements of stack", COMMAND) \ + X(clear, "clear stack", COMMAND) \ + X(help, "print all available commands", COMMAND) \ + X(vars, "print defined variables and their values", CALL, print_vars, COMMAND) + +#define MOD(x, y) ((int) (x) % (int) (y)) + +#define OPERATORS \ + X(+, "add operands", COMM_OP) \ + X(*, "multiply operands", COMM_OP) \ + X(-, "substact operands", NONC_OP) \ + X(/, "divide operands", NONC_OP, NONZ_SND_OP) \ + X(%, "apply modulo to operands", CALL, MOD, NONC_FUN, NONZ_SND_OP) \ + X(>, "greater than", NONC_OP) \ + X(<, "less than", NONC_OP) \ + X(<=, "less than or equal", NONC_OP) \ + X(>=, "greater than or equal", NONC_OP) \ + X(==, "test equality", COMM_OP) + +#define MATH_H_BINDINGS \ + X(sin, "sine", UNARY_FUN) \ + X(cos, "cosine", UNARY_FUN) \ + X(tan, "tangent", UNARY_FUN) \ + X(acos, "arc cosine", UNARY_T_FUN, IN_RANGE(-1, 1)) \ + X(asin, "arc sine", UNARY_T_FUN, IN_RANGE(-1, 1)) \ + X(atan, "arc tangent", UNARY_FUN) \ + X(exp, "exponentional function", UNARY_FUN) \ + X(log, "natural logarithm", UNARY_T_FUN, NON_NEG) \ + X(log10, "logarithm of base 10", UNARY_T_FUN, NON_NEG) \ + X(log2, "logarithm of base 2", UNARY_T_FUN, NON_NEG) \ + X(pow, "power function", NONC_FUN) \ + X(sqrt, "square root", UNARY_T_FUN, NON_NEG) \ + X(ceil, "round up value", UNARY_FUN) \ + X(floor, "round down value", UNARY_FUN) \ + X(round, "round to nearest", UNARY_FUN) \ + X(abs, "absolute value", CALL, fabs, UNARY_FUN) \ + X(max, "maximum value", CALL, fmax, COMM_FUN) \ + X(min, "minimum value", CALL, fmin, COMM_FUN) \ + X(pi, "value of pi", CALL, M_PI, VALUE) + +#define TOKENS \ + COMMANDS \ + OPERATORS \ + MATH_H_BINDINGS + +#endif // TOKENS_H