From 919eb0c413c4281eff8c3b439e443da45134b4ae Mon Sep 17 00:00:00 2001 From: Tibor Bizjak Date: Sun, 9 Jul 2023 14:14:40 +0200 Subject: [PATCH] redefined stack manipulation functions as macros --- k&r/04-funcs-and-prog-struct/04-calc.c | 129 ++++++++++--------------- 1 file changed, 50 insertions(+), 79 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 e3f37dd..f40fe9f 100644 --- a/k&r/04-funcs-and-prog-struct/04-calc.c +++ b/k&r/04-funcs-and-prog-struct/04-calc.c @@ -3,13 +3,14 @@ #include #include - +/* --------- ERROR MESSAGES */ #define printerr(format, ...) printf("error: " format "\n", ##__VA_ARGS__) -int stack_len(void); -void push(double x); -double pop(void); -double peek(void); -void clear(void); +#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" +#define SHORT_STACK_ERR "not enough elements on stack" /* --------- PROMPT FORMATS */ #define PROMPT_F ">> " @@ -17,52 +18,72 @@ void clear(void); #define PEEK_PRINT_F "peek -> %.8g\n" #define EMPTY_F "empty\n" -/* --------- 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" +/* ------ GLOBAL VALUE STACK */ +#define MAXVAL 100 /* maximum depth of val stack */ + +int sp = 0; +double val[MAXVAL]; + +#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 */ +#define pop() (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) +/* print_peek: print top element, leave stack unchanged */ +#define print_peek() printf(PEEK_PRINT_F, peek()) +/* dup: duplicate top element */ +#define dup() push(peek()) +/* 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) /* --------- CALCULATOR FUNCTION TYPES */ -/* renaming macro */ -#define CALL(TOKEN, F, APPLY, ...) APPLY(F, ##__VA_ARGS__) +/* 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, T, ...) \ do { T op = pop(); __VA_ARGS__ push(((T) pop()) OP op); } while (0) -/* nonzero second operand */ -#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 - +#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, T, ...) \ do { T op = pop(); __VA_ARGS__ push(F(pop(), op)); } while (0) +/* 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(print, COMMAND) \ + X(print, CALL, print_peek, COMMAND) \ X(dup, COMMAND) \ X(swap, COMMAND) \ X(clear, COMMAND) @@ -107,12 +128,6 @@ void clear(void); /* --------- COMMAND DEFINITIONS */ -#define print() printf(PEEK_PRINT_F, peek()) -#define dup() push(peek()) -#define swap() \ - do { double fst, snd; snd = pop(), fst = pop(); push(snd), push(fst); } while (0) - - #define MAXTOKEN 100 int gettoken(char *token, int max_t); @@ -126,7 +141,7 @@ int main() printf(PROMPT_F); while (t_len = gettoken(token, MAXTOKEN)) { if (t_len < 0) { /* newline token */ - if (stack_len()) + if (length()) printf(POP_PRINT_F, pop()); else printf(EMPTY_F); @@ -140,9 +155,9 @@ int main() #undef X push(atof(token)); } - if (!stack_len()) + if (!length()) putchar('\n'); - while (stack_len()) + while (length()) printf(POP_PRINT_F, pop()); return 0; @@ -176,47 +191,3 @@ int gettoken(char *token, int t_max) 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 - printerr(FULL_STACK_ERR, f); -} - -/* pop: pop and return top value from stack */ -double pop(void) -{ - if (sp) - return val[--sp]; - printerr(EMPTY_STACK_ERR); - return 0; -} - -/* peek: return top value from stack, leave stack unchanged */ -double peek(void) -{ - if (sp) - return val[sp-1]; - printerr(EMPTY_STACK_ERR); - return 0.0; -} - -void clear(void) -{ - sp = 0; -}