-
Notifications
You must be signed in to change notification settings - Fork 0
/
calc.c
executable file
·181 lines (166 loc) · 5.76 KB
/
calc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#include <assert.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <seq.h>
typedef uint32_t Um_word;
/* make Seq_T into a stack of integers */
static void push(Seq_T values, Um_word word)
{
assert(sizeof(Um_word) <= sizeof(uintptr_t));
Seq_addhi(values, (void *)(uintptr_t) word);
}
static Um_word pop(Seq_T values)
{
return (Um_word)(uintptr_t) Seq_remhi(values);
}
static Um_word get(Seq_T values, int i)
{
return (Um_word)(uintptr_t) Seq_get(values, i);
}
/*
* return true iff sequence has at least n elements
* when returning false, writes an error message about stack underflow
*/
static bool has(Seq_T sequence, int n);
/*
* implement binary operator. Macro needed because OPERATOR is not a C value
*/
#define BINARY(OPERATOR) \
do { \
if (has(values, 2)) { \
Um_word y = pop(values); \
Um_word x = pop(values); \
push(values, x OPERATOR y); \
} \
} while (false)
/*
* and similarly for unary operator
*/
#define UNARY(OPERATOR) \
do { \
if (has(values, 1)) { \
Um_word x = pop(values); \
push(values, OPERATOR x); \
} \
} while (false)
static void run(Seq_T values)
{
int c; /* character from standard input */
waiting:
/*
* if we are not entering a number, we are here,
* awaiting instructions
*/
c = getchar();
waiting_with_character:
switch (c) {
case EOF: return;
/* push a number */
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
push(values, c - '0');
goto entering;
/* unary and binary operators */
case '+': BINARY(+); goto waiting;
case '-': BINARY(-); goto waiting;
case '*': BINARY(*); goto waiting;
case '&': BINARY(&); goto waiting;
case '|': BINARY(|); goto waiting;
case '~' : UNARY(~); goto waiting;
case 'c' : UNARY(-); goto waiting; /* "change sign" */
case '/':
if (has(values, 2)) {
Um_word y = pop(values);
Um_word x = pop(values);
if (y == 0) {
printf("Division by zero\n");
push(values, x);
push(values, y);
} else if ((int32_t) x < 0) {
if ((int32_t) y < 0) {
x = -(int32_t)x;
y = -(int32_t)y;
push(values, x / y);
} else {
x = -(int32_t)x;
Um_word q = x / y;
push(values, -(int32_t)q);
}
} else if ((int32_t) y < 0) {
y = -(int32_t) y;
Um_word q = x / y;
push(values, -(int32_t)q);
} else {
push(values, x / y);
}
}
goto waiting;
case 's': /* swap top two values */
if (has(values, 2)) {
Um_word y = pop(values);
Um_word x = pop(values);
push(values, y);
push(values, x);
}
goto waiting;
case 'd': /* duplicate top value */
if (has(values, 1)) {
Um_word x = pop(values);
push(values, x);
push(values, x);
}
goto waiting;
case 'p': /* pop the value stack */
if (has(values, 1))
pop(values);
goto waiting;
case '\n': /* print the value stack */
for (int i = Seq_length(values); i > 0; i--)
printf(">>> %d\n", get(values, i - 1));
goto waiting;
case 'z': /* clear (zero out) the value stack by popping all elements */
while (Seq_length(values) > 0)
Seq_remlo(values);
goto waiting;
default:
if (!isspace(c))
printf("Unknown character '%c'\n", c);
goto waiting;
}
entering:
/* we are in the middle of entering a number */
c = getchar();
switch (c) {
/* if we see a digit, add it to number on top of the stack */
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
assert(has(values, 1));
Um_word w = pop(values);
push(values, 10 * w + c - '0');
goto entering;
// if we see anything else, behave as if waiting
default:
goto waiting_with_character;
}
}
int main()
{
Seq_T values = Seq_new(10);
run(values);
Seq_free(&values);
return EXIT_SUCCESS;
}
static bool has(Seq_T sequence, int n)
{
if (Seq_length(sequence) >= n)
return true;
else {
printf("Stack underflow---expected at least %d element%s\n",
n,
n == 1 ? "" : "s");
return false;
}
}