-
Notifications
You must be signed in to change notification settings - Fork 2
/
cilisp.c
executable file
·203 lines (167 loc) · 4.98 KB
/
cilisp.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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#include "cilisp.h"
#define RED "\033[31m"
#define RESET_COLOR "\033[0m"
// yyerror:
// Something went so wrong that the whole program should crash.
// You should basically never call this unless an allocation fails.
// (see the "yyerror("Memory allocation failed!")" calls and do the same.
// This is basically printf, but red, with "\nERROR: " prepended, "\n" appended,
// and an "exit(1);" at the end to crash the program.
// It's called "yyerror" instead of "error" so the parser will use it for errors too.
void yyerror(char *format, ...)
{
char buffer[256];
va_list args;
va_start (args, format);
vsnprintf (buffer, 255, format, args);
printf(RED "\nERROR: %s\nExiting...\n" RESET_COLOR, buffer);
fflush(stdout);
va_end (args);
exit(1);
}
// warning:
// Something went mildly wrong (on the user-input level, probably)
// Let the user know what happened and what you're doing about it.
// Then, move on. No big deal, they can enter more inputs. ¯\_(ツ)_/¯
// You should use this pretty often:
// too many arguments, let them know and ignore the extra
// too few arguments, let them know and return NAN
// invalid arguments, let them know and return NAN
// many more uses to be added as we progress...
// This is basically printf, but red, and with "\nWARNING: " prepended and "\n" appended.
void warning(char *format, ...)
{
char buffer[256];
va_list args;
va_start (args, format);
vsnprintf (buffer, 255, format, args);
printf(RED "WARNING: %s\n" RESET_COLOR, buffer);
fflush(stdout);
va_end (args);
}
FUNC_TYPE resolveFunc(char *funcName)
{
// Array of string values for function names.
// Must be in sync with members of the FUNC_TYPE enum in order for resolveFunc to work.
// For example, funcNames[NEG_FUNC] should be "neg"
char *funcNames[] = {
"neg",
"abs",
"add",
// TODO complete the array
// the empty string below must remain the last element
""
};
int i = 0;
while (funcNames[i][0] != '\0')
{
if (strcmp(funcNames[i], funcName) == 0)
{
return i;
}
i++;
}
return CUSTOM_FUNC;
}
AST_NODE *createNumberNode(double value, NUM_TYPE type)
{
AST_NODE *node;
size_t nodeSize;
nodeSize = sizeof(AST_NODE);
if ((node = calloc(nodeSize, 1)) == NULL)
{
yyerror("Memory allocation failed!");
exit(1);
}
// TODO complete the function
// Populate "node", the AST_NODE * created above with the argument data.
// node is a generic AST_NODE, don't forget to specify it is of type NUMBER_NODE
return node;
}
AST_NODE *createFunctionNode(FUNC_TYPE func, AST_NODE *opList)
{
AST_NODE *node;
size_t nodeSize;
nodeSize = sizeof(AST_NODE);
if ((node = calloc(nodeSize, 1)) == NULL)
{
yyerror("Memory allocation failed!");
exit(1);
}
// TODO complete the function
// Populate the allocated AST_NODE *node's data
return node;
}
AST_NODE *addExpressionToList(AST_NODE *newExpr, AST_NODE *exprList)
{
// TODO complete the function
// at newExpr to the exprList as the head. return the resulting list's head.
return NULL; // stub
}
RET_VAL evalFuncNode(AST_NODE *node)
{
if (!node)
{
yyerror("NULL ast node passed into evalFuncNode!");
return NAN_RET_VAL; // unreachable but kills a clang-tidy warning
}
// TODO complete the function
// HINT:
// the helper functions that it calls will need to be defined above it
// because they are not declared in the .h file (and should not be)
return NAN_RET_VAL;
}
RET_VAL evalNumNode(AST_NODE *node)
{
if (!node)
{
yyerror("NULL ast node passed into evalNumNode!");
return NAN_RET_VAL;
}
// TODO complete the function
return NAN_RET_VAL;
}
RET_VAL eval(AST_NODE *node)
{
if (!node)
{
yyerror("NULL ast node passed into eval!");
return NAN_RET_VAL;
}
// TODO complete the function
return NAN_RET_VAL;
}
// prints the type and value of a RET_VAL
void printRetVal(RET_VAL val)
{
switch (val.type)
{
case INT_TYPE:
printf("Integer : %.lf\n", val.value);
break;
case DOUBLE_TYPE:
printf("Double : %lf\n", val.value);
break;
default:
printf("No Type : %lf\n", val.value);
break;
}
}
void freeNode(AST_NODE *node)
{
if (!node)
{
return;
}
// TODO complete the function
// look through the AST_NODE struct, decide what
// referenced data should have freeNode called on it
// (hint: it might be part of an s_expr_list, with more
// nodes following it in the list)
// if this node is FUNC_TYPE, it might have some operands
// to free as well (but this should probably be done in
// a call to another function, named something like
// freeFunctionNode)
// and, finally,
free(node);
}