Blob


1 /*
2 * Exercise 4-6. Add commands for handling variables. (It's easy to provide
3 * twenty-six variables with single-letter names.) Add a variable for the most
4 * recently printed value.
5 */
7 #include <stdio.h>
8 #include <stdlib.h> /* for atof() */
9 #include <math.h> /* for math functions */
10 #include <string.h> /* for strcmp() */
11 #include <ctype.h> /* for tolower() */
13 #define MAXOP 100 /* max size of operand or operator */
14 #define NUMBER '0' /* signal that a number was found */
15 #define IDENTIFIER '1' /* signal that an identifier was found */
16 #define VARIABLE '2' /* signal that a variable was found */
17 #define ASSIGNMENT '3' /* signal that a variable was found */
18 #define LETTERS 26 /* number of letters in alphabet */
20 int getop(char []);
21 void push(double);
22 double pop(void);
23 double printtop(void);
24 int duplicate(void);
25 int swap(void);
26 void clear(void);
27 int assign(int, double);
28 double eval(int index);
30 /* reverse Polish calculator */
31 int main() {
32 int type;
33 double op2, val;
34 char s[MAXOP];
35 int index;
36 while ((type = getop(s)) != EOF) {
37 switch (type) {
38 case NUMBER:
39 push(atof(s));
40 break;
41 case IDENTIFIER:
42 if (strcmp(s, "sin") == 0)
43 push(sin(pop()));
44 else if (strcmp(s, "cos") == 0)
45 push(cos(pop()));
46 else if (strcmp(s, "exp") == 0)
47 push(exp(pop()));
48 break;
49 case VARIABLE:
50 index = tolower(s[0]) - 'a';
51 if (0 <= index && index < LETTERS) {
52 push(eval(index));
53 } else {
54 printf("error: variable must be single letter\n");
55 }
56 break;
57 case ASSIGNMENT:
58 index = tolower(s[0]) - 'a';
59 val = atof(s+2);
60 if (!assign(index, val)) {
61 printf("error: assignment failed, variable needs to be single letter\n");
62 }
63 break;
64 case '+':
65 push(pop() + pop());
66 break;
67 case '*':
68 push(pop() * pop());
69 break;
70 case '-':
71 op2 = pop();
72 push(pop() - op2);
73 break;
74 case '/':
75 op2 = pop();
76 if (op2 != 0.0)
77 push(pop() / op2);
78 else
79 printf("error: zero divisor\n");
80 break;
81 case '%':
82 op2 = pop();
83 if (op2 != 0.0)
84 push((int) pop() % (int) op2);
85 else
86 printf("error: zero divisor\n");
87 break;
88 case '?':
89 printf("\t%.8g\n", printtop());
90 break;
91 case '#':
92 if (duplicate() == 0)
93 printf("error: can't duplicate\n");
94 break;
95 case '~':
96 if (swap() == 0)
97 printf("error: swap failed, stack needs two numbers\n");
98 break;
99 case '!':
100 clear();
101 break;
102 case '\n':
103 printf("\t%.8g\n", pop());
104 break;
105 default:
106 printf("error: unknown command %s\n", s);
107 break;
112 #define MAXVAL 100 /* maximum depth of val stack */
114 int sp = 0; /* next free stack position */
115 double val[MAXVAL]; /* value stack */
116 double var[LETTERS]; /* variable stack */
118 /* push: push f onto value stack */
119 void push (double f) {
120 if (sp < MAXVAL)
121 val[sp++] = f;
122 else
123 printf ("error: stack full, can't push %g\n", f);
126 /* pop: pop and return top value from stack */
127 double pop(void) {
128 if (sp > 0)
129 return val[--sp];
130 else {
131 printf("error: stack empty\n");
132 return 0.0;
136 /* printtop: print the top value of the stack without popping it */
137 double printtop(void) {
138 if (sp > 0)
139 return val[sp-1];
140 else {
141 printf("error: stack empty\n");
142 return 0.0;
146 /* duplicate: duplicate the top value of the stack
147 * return 1 if successful, 0 on failure */
148 int duplicate(void) {
149 if (sp <= 0) {
150 return 0;
151 } else if (sp >= MAXVAL) {
152 return 0;
153 } else {
154 val[sp] = val[sp-1];
155 sp++;
156 return 1;
160 /* swap: swap the top two values of the stack
161 * return 1 if successful, 0 on failure */
162 int swap(void) {
163 if (sp > 1) {
164 int temp = val[sp-1];
165 val[sp-1] = val[sp-2];
166 val[sp-2] = temp;
167 return 1;
169 return 0;
172 /* clear: clear the stack */
173 void clear(void) {
174 sp = 0;
177 /* assign: assign a double to a variable, letters represented by int from 0-25
178 * return 1 on success, 0 on failure */
179 int assign(int index, double value) {
180 if (0 <= index && index < LETTERS) {
181 var[index] = value;
182 return 1;
184 return 0;
187 /* eval: evaluate variable, letters represented by int from 0-25 */
188 double eval(int index) {
189 if (0 <= index && index < LETTERS) {
190 return var[index];
192 return 0.0;
195 #include <ctype.h>
197 int getch(void);
198 void ungetch(int);
200 /* getop: get next operator or numeric operand */
201 int getop(char s[]) {
202 int i, c;
203 while ((s[0] = c = getch()) == ' ' || c == '\t')
205 s[1] = '\0';
206 i = 0;
207 if (isalpha(c)) {
208 /*
209 while (isalpha(s[++i] = c = getch()))
211 */
212 while ((s[++i] = c = getch()) != ' ' && c != '\t' && c != '\n')
214 s[i] = '\0';
215 if (c != EOF)
216 ungetch(c);
217 if (s[1] == '=') {
218 return ASSIGNMENT;
219 } else if (s[1] == '\0') {
220 return VARIABLE;
221 } else {
222 return IDENTIFIER;
225 /* negative number or minus */
226 if (c == '-') {
227 s[++i] = c = getch();
228 if (!isdigit(c) && c != '.') {
229 ungetch(c);
230 return '-';
233 if (!isdigit(c) && c != '.')
234 return c; /* not a number */
235 if (isdigit(c)) /* collect integer part */
236 while (isdigit(s[++i] = c = getch()))
238 if (c == '.') /* collect fraction part */
239 while (isdigit(s[++i] = c = getch()))
241 s[i] = '\0';
242 if (c != EOF)
243 ungetch(c);
244 return NUMBER;
247 #define BUFSIZE 100
249 char buf[BUFSIZE]; /* buffer for ungetch */
250 int bufp = 0;
252 /* get a (possibly pushed back) character */
253 int getch(void) {
254 return (bufp > 0) ? buf[--bufp] : getchar();
257 /* push character back on input */
258 void ungetch(int c) {
259 if (bufp >= BUFSIZE)
260 printf("ungetch: too many characters\n");
261 else
262 buf[bufp++] = c;