Blame


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