-
Notifications
You must be signed in to change notification settings - Fork 0
/
eval.c
94 lines (86 loc) · 2.46 KB
/
eval.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
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <sys/errno.h>
#include "eval.h"
#include "op.h"
/* Perform the operation with the given symbol on the stack by popping the
* necessary items off the top, then pushing the result back onto the stack.
* Returns 0 if the operation is valid, or -1 otherwise.
*/
static int exec_operation(struct stack *stack, const char *symbol)
{
if (!stack) {
fprintf(stderr, "exec_operation: stack is a NULL pointer\n");
exit(EFAULT);
}
const struct operation *op = find_operation(symbol);
if (!op) {
fprintf(stderr, "Invalid operator '%s'\n", symbol);
return -1;
} else if (op->num_args > stack->size) {
fprintf(stderr, "Operation takes %d arguments, but there %s %d on the stack.\n",
op->num_args, stack->size == 1 ? "is" : "are",
stack->size);
return -1;
}
stack_push(stack, (op->function)(stack));
return 0;
}
/* Return whether the string is a valid floating-point number, by strtof.
*/
static bool is_number(const char *str)
{
char *endptr;
int len = strlen(str);
strtof(str, &endptr);
return len > 0 && endptr == str + len;
}
/* Evaluate the expression. If stack points to a stack, use the context of that
* stack. If the stack is a NULL pointer, use a temporary empty stack.
* If the expression is valid, return its result and modify the stack.
* If the expression is invalid, return NaN without modifying the stack.
*/
double eval_expression(const char *expr, struct stack *context_stack)
{
double ret;
bool error = false;
struct stack *stack, *backup_stack = NULL;
if (context_stack) { //Use the supplied stack, keeping a backup
stack = context_stack;
backup_stack = malloc(sizeof(*backup_stack));
stack_dup(backup_stack, stack);
} else { //Use a temporary stack
stack = malloc(sizeof(*backup_stack));
stack_init(stack);
}
char *exprdup, *tofree, *token;
tofree = exprdup = strdup(expr);
while ((token = strsep(&exprdup, " ")) != NULL) {
if (is_number(token)) {
stack_push(stack, strtof(token, NULL));
ret = nan("");
} else if (!strcmp(token, "p") || !strcmp(token, "print")) {
stack_print(stack);
ret = nan("");
} else if (exec_operation(stack, token) == 0) {
ret = stack_peek(stack);
} else {
ret = nan("");
error = true;
break;
}
}
if (context_stack) {
if (error)
stack_dup(stack, backup_stack); //restore stack
free(backup_stack);
} else {
free(stack);
}
free(tofree);
return ret;
}