k&r 04-04: added stack manipulation commands

master
Tibor Bizjak 2023-07-08 17:46:02 +02:00
parent 4d95f4515b
commit b655221b5b
1 changed files with 65 additions and 21 deletions

View File

@ -4,31 +4,55 @@
#define printerr(format, ...) printf("error: " format "\n", ##__VA_ARGS__) #define printerr(format, ...) printf("error: " format "\n", ##__VA_ARGS__)
int stack_len(void);
void push(double x); void push(double x);
double pop(void); double pop(void);
int stack_len(void); double peek(void);
void clear(void);
/* --------- PROMPT FORMATS */
#define PROMPT_F ">> "
#define POP_PRINT_F "pop -> %.8g\n"
#define PEEK_PRINT_F "peek -> %.8g\n"
#define EMPTY_F "empty\n"
/* --------- ERROR MESSAGES */ /* --------- ERROR MESSAGES */
#define ZERODIV_ERR "zero divisor" #define ZERODIV_ERR "zero divisor"
#define FULL_STACK_ERR "stack full, can't push %g"
#define EMPTY_STACK_ERR "stack empty"
/* --------- CALCULATOR FUNCTIONS TYPES */
/* command application */
#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)
/* nonzero second operand */
#define NONZ_SND_OP if (!op2) printerr(ZERODIV_ERR); else
/* --------- CALCULATOR FUNCTIONS */ /* --------- 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 \ #define FUNCTIONS \
X(+, COMM_OP) \ X(+, COMM_OP) \
X(*, COMM_OP) \ X(*, COMM_OP) \
X(-, NONC_OP, double) \ X(-, NONC_OP, double) \
X(/, NONZ_OP, double) \ X(/, NONC_OP, double, NONZ_SND_OP) \
X(%, NONZ_OP, int) X(%, NONC_OP, int, NONZ_SND_OP) \
X(print, COMMAND) \
X(dup, COMMAND) \
X(swap, COMMAND) \
X(clear, COMMAND)
/* --------- 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 #define MAXTOKEN 100
@ -40,11 +64,16 @@ int main()
char token[MAXTOKEN + 1]; char token[MAXTOKEN + 1];
double op2; double op2;
int t_len; int t_len;
printf(PROMPT_F);
while (t_len = gettoken(token, MAXTOKEN)) { while (t_len = gettoken(token, MAXTOKEN)) {
if (t_len < 0) if (t_len < 0) { /* newline token */
printf("\t%g\n", pop()); if (stack_len())
else printf(POP_PRINT_F, pop());
else
printf(EMPTY_F);
printf(PROMPT_F);
} else
#define X(F, APPLY, ...) \ #define X(F, APPLY, ...) \
if (!strcmp(#F, token)) \ if (!strcmp(#F, token)) \
APPLY(F, ##__VA_ARGS__); \ APPLY(F, ##__VA_ARGS__); \
@ -53,7 +82,10 @@ int main()
#undef X #undef X
push(atof(token)); push(atof(token));
} }
printf("%g\n", pop()); if (!stack_len())
putchar('\n');
while (stack_len())
printf(POP_PRINT_F, pop());
return 0; return 0;
} }
@ -98,14 +130,14 @@ int stack_len()
return sp; return sp;
} }
/* push: push f onto value stack */ /* push: push f onto value stack */
void push(double f) void push(double f)
{ {
if (sp < MAXVAL) if (sp < MAXVAL)
val[sp++] = f; val[sp++] = f;
else else
printf("error: stack full, can't push %g\n", f); printerr(FULL_STACK_ERR, f);
} }
/* pop: pop and return top value from stack */ /* pop: pop and return top value from stack */
@ -113,8 +145,20 @@ double pop(void)
{ {
if (sp) if (sp)
return val[--sp]; return val[--sp];
printf("error: stack empty\n"); 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; return 0.0;
} }
void clear(void)
{
sp = 0;
}