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() */
12 #define MAXOP 100 /* max size of operand or operator */
13 #define NUMBER '0' /* signal that a number was found */
14 #define IDENTIFIER '1' /* signal that an identifier was found */
15 #define VARIABLE '2' /* signal that a variable was found */
16 #define ASSIGNMENT '3' /* signal that a variable was found */
17 #define LETTERS 26 /* number of letters in alphabet */
19 int getop(char []);
20 void push(double);
21 double pop(void);
22 double printtop(void);
23 int duplicate(void);
24 int swap(void);
25 void clear(void);
26 int assign(char, double);
27 double interpolate(char);
29 /* reverse Polish calculator */
30 int main() {
31 int type;
32 double op2, val;
33 char s[MAXOP];
34 int index;
35 while ((type = getop(s)) != EOF) {
36 switch (type) {
37 case NUMBER:
38 push(atof(s));
39 break;
40 case IDENTIFIER:
41 if (strcmp(s, "sin") == 0)
42 push(sin(pop()));
43 else if (strcmp(s, "cos") == 0)
44 push(cos(pop()));
45 else if (strcmp(s, "exp") == 0)
46 push(exp(pop()));
47 break;
48 case VARIABLE:
49 push(interpolate(s[0]));
50 break;
51 case ASSIGNMENT:
52 assign(s[0], atof(s+2));
53 break;
54 case '+':
55 push(pop() + pop());
56 break;
57 case '*':
58 push(pop() * pop());
59 break;
60 case '-':
61 op2 = pop();
62 push(pop() - op2);
63 break;
64 case '/':
65 op2 = pop();
66 if (op2 != 0.0)
67 push(pop() / op2);
68 else
69 printf("error: zero divisor\n");
70 break;
71 case '%':
72 op2 = pop();
73 if (op2 != 0.0)
74 push((int) pop() % (int) op2);
75 else
76 printf("error: zero divisor\n");
77 break;
78 case '?':
79 printf("\t%.8g\n", printtop());
80 break;
81 case '#':
82 if (duplicate() == 0)
83 printf("error: can't duplicate\n");
84 break;
85 case '~':
86 if (swap() == 0)
87 printf("error: swap failed, stack needs two numbers\n");
88 break;
89 case '!':
90 clear();
91 break;
92 case '\n':
93 printf("\t%.8g\n", pop());
94 break;
95 default:
96 printf("error: unknown command %s\n", s);
97 break;
98 }
99 }
102 #include <ctype.h> /* for tolower() */
103 #define MAXVAL 100 /* maximum depth of val stack */
105 int sp = 0; /* next free stack position */
106 double val[MAXVAL]; /* value stack */
107 double var[LETTERS]; /* variable stack */
109 /* push: push f onto value stack */
110 void push (double f) {
111 if (sp < MAXVAL)
112 val[sp++] = f;
113 else
114 printf ("error: stack full, can't push %g\n", f);
117 /* pop: pop and return top value from stack */
118 double pop(void) {
119 if (sp > 0)
120 return val[--sp];
121 else {
122 printf("error: stack empty\n");
123 return 0.0;
127 /* printtop: print the top value of the stack without popping it */
128 double printtop(void) {
129 if (sp > 0)
130 return val[sp-1];
131 else {
132 printf("error: stack empty\n");
133 return 0.0;
137 /* duplicate: duplicate the top value of the stack
138 * return 1 if successful, 0 on failure */
139 int duplicate(void) {
140 if (sp <= 0) {
141 return 0;
142 } else if (sp >= MAXVAL) {
143 return 0;
144 } else {
145 val[sp] = val[sp-1];
146 sp++;
147 return 1;
151 /* swap: swap the top two values of the stack
152 * return 1 if successful, 0 on failure */
153 int swap(void) {
154 if (sp > 1) {
155 int temp = val[sp-1];
156 val[sp-1] = val[sp-2];
157 val[sp-2] = temp;
158 return 1;
160 return 0;
163 /* clear: clear the stack */
164 void clear(void) {
165 sp = 0;
168 /* assign: assign a double to a variable
169 * return 1 on success, 0 on failure */
170 int assign(char variable, double value) {
171 int index = tolower(variable) - 'a';
172 if (0 <= index && index < LETTERS) {
173 var[index] = value;
174 return 1;
176 printf("error: assignment failed, variable needs to be single letter\n");
177 return 0;
180 /* interpolate: interpolate variable */
181 double interpolate(char variable) {
182 int index = tolower(variable) - 'a';
183 if (0 <= index && index < LETTERS) {
184 return var[index];
186 printf("error: variable must be single letter\n");
187 return 0.0;
190 #include <ctype.h>
192 int getch(void);
193 void ungetch(int);
195 /* getop: get next operator or numeric operand */
196 int getop(char s[]) {
197 int i, c;
198 while ((s[0] = c = getch()) == ' ' || c == '\t')
200 s[1] = '\0';
201 i = 0;
202 if (isalpha(c)) {
203 while ((s[++i] = c = getch()) != ' ' && c != '\t' && c != '\n')
205 s[i] = '\0';
206 if (c != EOF)
207 ungetch(c);
208 if (s[1] == '=') {
209 return ASSIGNMENT;
210 } else if (s[1] == '\0') {
211 return VARIABLE;
212 } else {
213 return IDENTIFIER;
216 /* negative number or minus */
217 if (c == '-') {
218 s[++i] = c = getch();
219 if (!isdigit(c) && c != '.') {
220 ungetch(c);
221 return '-';
224 if (!isdigit(c) && c != '.')
225 return c; /* not a number */
226 if (isdigit(c)) /* collect integer part */
227 while (isdigit(s[++i] = c = getch()))
229 if (c == '.') /* collect fraction part */
230 while (isdigit(s[++i] = c = getch()))
232 s[i] = '\0';
233 if (c != EOF)
234 ungetch(c);
235 return NUMBER;
238 #define BUFSIZE 100
240 char buf[BUFSIZE]; /* buffer for ungetch */
241 int bufp = 0;
243 /* get a (possibly pushed back) character */
244 int getch(void) {
245 return (bufp > 0) ? buf[--bufp] : getchar();
248 /* push character back on input */
249 void ungetch(int c) {
250 if (bufp >= BUFSIZE)
251 printf("ungetch: too many characters\n");
252 else
253 buf[bufp++] = c;