-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontext.cpp
More file actions
126 lines (107 loc) · 3.47 KB
/
context.cpp
File metadata and controls
126 lines (107 loc) · 3.47 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
#include "context.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
// Set of operations for evaluating expressions:
int iadd(int x, int y) {
return x + y;
}
int isub(int x, int y) {
return x - y;
}
int idiv(int x, int y) {
return x / y;
}
int imul(int x, int y) {
return x * y;
}
float fadd(float x, float y) {
return x + y;
}
float fsub(float x, float y) {
return x - y;
}
float fdiv(float x, float y) {
return x / y;
}
float fmul(float x, float y) {
return x * y;
}
// Create and initialize EvalOps table
EvalOps *createEvalOps() {
EvalOps *eval_ops = (EvalOps*)malloc(sizeof(EvalOps));
eval_ops->iops['+'] = iadd;
eval_ops->iops['-'] = isub;
eval_ops->iops['/'] = idiv;
eval_ops->iops['*'] = imul;
eval_ops->flops['+'] = fadd;
eval_ops->flops['-'] = fsub;
eval_ops->flops['/'] = fdiv;
eval_ops->flops['*'] = fmul;
return eval_ops;
}
// Given a context, two expression values and an opcode (one of '+', '-', '*', '/'),
// first determine the type of the result (float or int) and then use the context's
// ops table to find the correct flop or iop to evaluate a result.
ExprValue doEval(Context *ctx, ExprValue l, ExprValue r, char opcode) {
ExprValue result;
if (l.type == T_FLT_CONST || r.type == T_FLT_CONST) {
result.type = T_FLT_CONST;
if (l.type == T_INT_CONST) {
l.value.float_value = l.value.int_value;
}
if (r.type == T_INT_CONST) {
r.value.float_value = r.value.int_value;
}
flop fop = ctx->eval_ops->flops[opcode];
result.value.float_value = fop(l.value.float_value, r.value.float_value);
} else {
result.type = T_INT_CONST;
iop op = ctx->eval_ops->iops[opcode];
result.value.int_value = op(l.value.int_value, r.value.int_value);
}
return result;
}
// A context should be created for each interaction:
Context *createContext() {
Context *new_context = (Context*)malloc(sizeof(Context));
new_context->symbol_table = createHash(DEFAULT_NUM_BUCKETS);
new_context->errors = createList();
new_context->eval_ops = createEvalOps();
return new_context;
}
#define zero_errors(ctx) (list_size(ctx->errors) == 0)
#define is_assign_stmt(ctx) ((list_size(ctx->parse_tree) == 1) && \
((Node*)getElement(ctx->parse_tree, 0))->type == T_ASSIGN)
// cleanUpContext should be called after a line has been processed to free memory:
void cleanUpContext(Context* ctx) {
// Delete parse_tree's memory. Don't delete assign nodes because they are in symbol table
deleter del_fn = ((zero_errors(ctx) && is_assign_stmt(ctx)) ? NULL : genericDeleteNode);
deleteList(&ctx->parse_tree, del_fn);
// Delete error messages
while(list_size(ctx->errors) > 0) {
ErrorMessage *em = (ErrorMessage*)removeElement(ctx->errors, 0);
free(em);
}
}
// deleteContext should be called when an interaction/session is ended:
void deleteContext(Context **ctx_ptr) {
if ((ctx_ptr != NULL) && (*ctx_ptr != NULL)) {
Context *ctx = *ctx_ptr;
deleteList(&ctx->parse_tree, genericDeleteNode);
deleteHash(&ctx->symbol_table, genericDeleteNode);
free(ctx->eval_ops);
deleteList(&ctx->errors, NULL);
free(ctx);
*ctx_ptr = NULL;
}
}
// Error message table and function - fairly limited
static const char *error_message_table[] = { "No such variable", "Incorrect syntax" };
// Create a message of the appropriate type:
ErrorMessage *makeError(ErrorTag error_tag, char* data) {
ErrorMessage *em = (ErrorMessage*)malloc(sizeof(ErrorMessage));
em->error_tag = error_tag;
snprintf(em->message, MAX_ERROR_MSG_LEN, "%s: %s", error_message_table[error_tag], data);
return em;
}