-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlab7.c
More file actions
270 lines (237 loc) · 7.52 KB
/
Copy pathlab7.c
File metadata and controls
270 lines (237 loc) · 7.52 KB
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
/**
* Implementation for an infix integer algebraic expression evaluator.
* Converts in-fix expression to postfix notation, evaluates expression.
* Infix expression is provided as a single, quoted command-line argument.
*
* COMP220: Lab 7 Starter Project - Stacks & Queues
* Author: Joseph Fall
* Co-Author: Bryan Ho, Keyann Al-Kheder
* Date: Mar. 6, 2018
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>
#include "stack.h"
#include "queue.h"
#include "istack.h"
// Helper Functions
Queue_t tokenize(char* expression);
bool isOperand(char* t);
int operandValue(char* t);
bool isOperator(char* token);
bool isOpenBracket(char* token);
bool isCloseBracket(char* token);
bool isBracket(char* token);
int precedence(char* token);
// Experession Evaluator Functions
Queue_t toPostfix(Queue_t infix_tokens);
int evalExpr(Queue_t postfix_tokens);
//**********************
// MAIN
//**********************
int main(int argc, char* argv[]) {
if (argc != 2) {
printf("Usage: eval \"4 + 5 * ( x - a ) / 3\" \n\n");
exit(-1);
}
Queue_t infix_expression;
Queue_t postfix_expression;
infix_expression = tokenize(argv[1]);
printf("Infix Expression: ");
qPrint(infix_expression);
postfix_expression = toPostfix(infix_expression);
printf("Postfix Expression: ");
qPrint(postfix_expression);
printf("Answer: %d\n", evalExpr(postfix_expression));
qDestroy(&infix_expression);
qDestroy(&postfix_expression);
return 0;
}
//**********************
// Helpers
//**********************
// POST: returns the single character symbol at the start of t, or NULL
char symbol(char* t)
{
return strlen(t) > 0 ? t[0] : '\0';
}
// POST: returns true if c is a valid operand symbol, false otherwise
bool isOperand(char* t)
{
int i;
for (i=0; i<strlen(t); i++) {
if (! (isdigit(t[i]) || isalpha(t[i])))
return false; // valid operands must be alpha-numeric
}
return strlen(t) > 0;
}
// PRE: IsOperand(t)
// POST: returns numeric value of operand t
int operandValue(char* t)
{
assert(isOperand(t));
char c = symbol(t);
// if c is a digit, return its numeric value
if (isdigit(c)) {
return atoi(t);
}
else
{ // c is an identifier, do a lookup to find its value
// TODO: implement proper identifier lookup table. For now, return 0 for a, 1 for b, etc..
return (tolower(c) - 'a');
}
}
// POST: returns true if t represents a valid operator symbol, false otherwise
bool isOperator(char* t)
{
char c = symbol(t);
return strlen(t) == 1 && (c=='+' || c=='-' || c=='*' || c=='/' );
}
// POST: returns true if t is the open bracket symbol, false otherwise
bool isOpenBracket(char* t)
{
char c = symbol(t);
return strlen(t) == 1 && c=='(';
}
// POST: returns true if t is the close bracket symbol, false otherwise
bool isCloseBracket(char* t)
{
char c = symbol(t);
return strlen(t) == 1 && c==')';
}
// POST: returns true if t is a bracket symbol, false otherwise
bool isBracket(char* t)
{
return isOpenBracket(t) || isCloseBracket(t);
}
// PRE: isOperator(t) || isBracket(t)
// POST: returns relative precedence of the operator, op, as follows:
// lowest to highest : ( ) + - * /
int precedence(char* t)
{
assert( isOperator(t) || isBracket(t) );
char op = t[0];
if (op == '(' || op == ')' )
return 0;
else if (op == '+' || op == '-')
return 1;
else if (op == '*' || op == '/' )
return 2;
assert (false); // should never happen
return 0;
}
// PRE: expression is a set of space-separated tokens
// POST: Side-effect - spaces replaced by '\0' in original expression
// RETURN: pointers to each token in original expression returned in sequence
// Caller is responsible for calling qDestroy on returned Queue object.
Queue_t tokenize(char* expression)
{
const char* sep = " "; // each token separaterd by single space!
char* t;
Queue_t tokens = qCreate();
t = strtok(expression, sep); // initialize strtok with expression.
/* parse rest of tokens */
while( t != NULL ) {
qEnqueue(&tokens, t);
t = strtok(NULL, sep); // next token
}
return tokens;
}
//********************************************
// In-fix experession --> Post-fix expression
//
// NOTE: a valid expression for this module may only contain:
// -- integer or symbolic operands
// -- the operators * + - / (no unary operators)
// -- matching brackets in pairs ( and )
//*********************************************
// PRE: infix_tokens contains a valid in-fix algebraic expression, as defined above.
// POST: returns a Queue containing the expression tokens in post-fix sequence.
// Caller is responsible for calling qDestroy on returned Queue object.
Queue_t toPostfix(Queue_t infix_tokens)
{
int i;
char* token;
Queue_t expression = qCreate();
Stack_t operators = stackCreate();
while (!qIsEmpty(infix_tokens)) {
token = qDequeue(&infix_tokens);
if (isOperator(token) ) { // Math Operator
// any operators of equal or higher precedence on stack need be evaluated first...
while ((! stackIsEmpty(operators)) &&
precedence(token) <= precedence(stackTop(operators)) )
qEnqueue(&expression, stackPop(&operators));
// then push the new operator onto the stack for evaluation once we have all operands
stackPush(&operators, token);
}
else if (isOpenBracket(token)) { // Open Bracket
// push open brackets on stack so sub-expression is evaluated as a group
stackPush(&operators, token);
}
else if (isCloseBracket(token)) { // Close Bracket
// pop operators for sub-expression and place them in queue for evaluation
while (!stackIsEmpty(operators) && ! isOpenBracket(stackTop(operators))) {
qEnqueue(&expression, stackPop(&operators));
}
// TODO: add some better error handling here
assert(! stackIsEmpty(operators) ); // there MUST be a matching Open bracket
stackPop(&operators); // remove the matching open bracket.
}
else { // Operand
// TODO: add some better error handling here
assert( isOperand(token) ); // token MUST otherwise be a valid operand
// Simply queue up the operand for evaluation
qEnqueue(&expression, token);
}
}
// Finally, add any remaining (usually high precedence) operators to expression.
while (! stackIsEmpty(operators)) {
// TODO: add some better error handling here
assert( ! isOpenBracket(stackTop(operators) ));
qEnqueue(&expression, stackPop(&operators));
}
assert( stackIsEmpty(operators) );
stackDestroy(&operators);
return expression;
}
//*********************************************
// Evaluate Post-fix Expression
//*********************************************
// PRE: postfix contains a valid post-fix algebraic expression, as defined above
// Variable substitutions still need to be performed.
// POST: returns the result of evaluating the post-fix expression.
int evalExpr(Queue_t expression)
{
intStack_t stack = istackCreate();
int final = 0;
while(! qIsEmpty(expression)){ //Taken from Bryan
char* c = qDequeue(&expression);
if (isOperand(c)){
}
else if(isOperator(c)){
int secondOperand = istackPop(&stack);
int firstOperand = istackPop(&stack);
final = applyOperator(c, firstOperand, secondOperand);
istackPush(&stack, final);
}
}
return istackTop(stack);
}
int applyOperator(char* c, int firstOperand, int secondOperand) //Taken from Bryan
{
if (c[0] == '+'){
return firstOperand + secondOperand;
}
else if(c[0]=='/'){
return firstOperand/secondOperand;
}
else if(c[0]=='-'){
return firstOperand - secondOperand;
}
else if(c[0]=='*'){
return firstOperand * secondOperand;
}
}