Branch data Line data Source code
1 : : #include <stdlib.h>
2 : : #include <stdio.h>
3 : : #include <string.h>
4 : : #include <stdarg.h>
5 : : #include "dictionary.h"
6 : : #include "expression.h"
7 : : #include "compile.h"
8 : :
9 : : int current_scope;
10 : :
11 : : dictionary *local_variables[MAX_SCOPE];
12 : : dictionary global_variables;
13 : : unsigned int num_labels = 0;
14 : : unsigned int current_string = 0;
15 : : static unsigned int order_of_operations[] = {0, 9, 9, 10, 10, 1, 7, 7, 7, 7, 6, 6, 5, 4, 9, 3, 2, 8, 8};
16 : :
17 : : unsigned char do_print;
18 : :
19 : : //Wrapper to fprintf to control whether we actually write to a file
20 : 0 : void fileprint(FILE *fp, const char *format, ...){
21 : 0 : va_list ap;
22 : :
23 [ # # ]: 0 : if(do_print){
24 : 0 : va_start(ap, format);
25 : 0 : vfprintf(fp, format, ap);
26 : 0 : va_end(ap);
27 : : }
28 : 0 : }
29 : :
30 : 0 : void operation_none_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){
31 : 0 : snprintf(error_message, sizeof(error_message), "Unrecognized operation");
32 : 0 : do_error(1);
33 : 0 : }
34 : :
35 : 0 : void operation_add_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){
36 : 0 : value *pointer_value;
37 : 0 : char *integer_reg;
38 : 0 : unsigned int pointer_size;
39 : :
40 [ # # # # ]: 0 : if(peek_type(&(value_a->data_type)) == type_function || peek_type(&(value_b->data_type)) == type_function){
41 : 0 : snprintf(error_message, sizeof(error_message), "Addition of function type is undefined");
42 : 0 : do_error(1);
43 : : }
44 [ # # ]: 0 : if(peek_type(&(value_a->data_type)) == type_pointer){
45 [ # # ]: 0 : if(peek_type(&(value_b->data_type)) == type_pointer){
46 : 0 : snprintf(warning_message, sizeof(warning_message), "Adding two pointers together. Treating them as integers instead");
47 : 0 : do_warning();
48 : 0 : fileprint(output_file, "add %s, %s, %s\n", reg_a, reg_a, reg_b);
49 : 0 : *output_type = value_a->data_type;
50 : 0 : return;
51 : : }
52 : 0 : pointer_value = value_a;
53 : 0 : integer_reg = reg_b;
54 : : } else {
55 [ # # ]: 0 : if(peek_type(&(value_b->data_type)) == type_pointer){
56 : 0 : pointer_value = value_b;
57 : 0 : integer_reg = reg_a;
58 : : } else {
59 : 0 : fileprint(output_file, "add %s, %s, %s\n", reg_a, reg_a, reg_b);
60 : 0 : *output_type = INT_TYPE;
61 : 0 : return;
62 : : }
63 : : }
64 : 0 : pointer_size = type_size(&(pointer_value->data_type), 1);
65 [ # # ]: 0 : if(pointer_size == 4){
66 : 0 : fileprint(output_file, "sll %s, %s, 2\n", integer_reg, integer_reg);
67 [ # # ]: 0 : } else if(pointer_size != 1){
68 : 0 : fileprint(output_file, "li $t2, %d\n", pointer_size);
69 : 0 : fileprint(output_file, "mult %s, $t2\n", integer_reg);
70 : 0 : fileprint(output_file, "mflo %s\n", integer_reg);
71 : : }
72 : 0 : fileprint(output_file, "add %s, %s, %s\n", reg_a, reg_a, reg_b);
73 : :
74 : 0 : *output_type = pointer_value->data_type;
75 : : }
76 : :
77 : 0 : void operation_subtract_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){
78 : 0 : type *pointer_type;
79 : 0 : type *pointer_type2;
80 : 0 : value *pointer_value;
81 : 0 : char *integer_reg;
82 : 0 : unsigned int pointer_size;
83 : :
84 [ # # # # ]: 0 : if(peek_type(&(value_a->data_type)) == type_function || peek_type(&(value_b->data_type)) == type_function){
85 : 0 : snprintf(error_message, sizeof(error_message), "Subtraction of function type is undefined");
86 : 0 : do_error(1);
87 : : }
88 [ # # ]: 0 : if(peek_type(&(value_a->data_type)) == type_pointer){
89 [ # # ]: 0 : if(peek_type(&(value_b->data_type)) == type_pointer){
90 : 0 : pointer_type = &(value_a->data_type);
91 : 0 : pointer_type2 = &(value_b->data_type);
92 [ # # ]: 0 : if(!types_equal(pointer_type, pointer_type2)){
93 : 0 : snprintf(error_message, sizeof(error_message), "Cannot subtract pointers to different types");
94 : 0 : do_error(1);
95 : : }
96 : 0 : fileprint(output_file, "sub %s, %s, %s\n", reg_a, reg_a, reg_b);
97 [ # # ]: 0 : if(type_size(pointer_type, 1) == 4){
98 : 0 : fileprint(output_file, "sra %s, %s, 2\n", reg_a, reg_a);
99 [ # # ]: 0 : } else if(type_size(pointer_type, 1) != 1){
100 : 0 : fileprint(output_file, "li $t2, %d\n", type_size(pointer_type, 1));
101 : 0 : fileprint(output_file, "div %s, $t2\n", reg_a);
102 : 0 : fileprint(output_file, "mflo %s\n", reg_a);
103 : : }
104 : 0 : *output_type = INT_TYPE;
105 : 0 : return;
106 : : }
107 : 0 : pointer_value = value_a;
108 : 0 : integer_reg = reg_b;
109 : : } else {
110 [ # # ]: 0 : if(peek_type(&(value_b->data_type)) == type_pointer){
111 : 0 : pointer_value = value_b;
112 : 0 : integer_reg = reg_a;
113 : : } else {
114 : 0 : fileprint(output_file, "sub %s, %s, %s\n", reg_a, reg_a, reg_b);
115 : 0 : *output_type = INT_TYPE;
116 : 0 : return;
117 : : }
118 : : }
119 : 0 : pointer_size = type_size(&(pointer_value->data_type), 1);
120 [ # # ]: 0 : if(pointer_size == 4){
121 : 0 : fileprint(output_file, "sll %s, %s, 2\n", integer_reg, integer_reg);
122 [ # # ]: 0 : } else if(pointer_size != 1){
123 : 0 : fileprint(output_file, "li $t2, %d\n", pointer_size);
124 : 0 : fileprint(output_file, "mult %s, $t2\n", integer_reg);
125 : 0 : fileprint(output_file, "mflo %s\n", integer_reg);
126 : : }
127 : 0 : fileprint(output_file, "sub %s, %s, %s\n", reg_a, reg_a, reg_b);
128 : :
129 : 0 : *output_type = pointer_value->data_type;
130 : : }
131 : :
132 : 0 : void operation_multiply_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){
133 [ # # # # : 0 : if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){
# # # # ]
134 : 0 : snprintf(error_message, sizeof(error_message), "Cannot multiply non-int types");
135 : 0 : do_error(1);
136 : : }
137 : 0 : fileprint(output_file, "mult %s, %s\n", reg_a, reg_b);
138 : 0 : fileprint(output_file, "mflo %s\n", reg_a);
139 : 0 : *output_type = INT_TYPE;
140 : 0 : }
141 : :
142 : 0 : void operation_divide_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){
143 [ # # # # : 0 : if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){
# # # # ]
144 : 0 : snprintf(error_message, sizeof(error_message), "Cannot divide non-int types");
145 : 0 : do_error(1);
146 : : }
147 : 0 : fileprint(output_file, "div %s, %s\n", reg_a, reg_b);
148 : 0 : fileprint(output_file, "mflo %s\n", reg_a);
149 : 0 : *output_type = INT_TYPE;
150 : 0 : }
151 : :
152 : 0 : void operation_modulo_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){
153 [ # # # # : 0 : if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){
# # # # ]
154 : 0 : snprintf(error_message, sizeof(error_message), "Cannot modulo non-int types");
155 : 0 : do_error(1);
156 : : }
157 : 0 : fileprint(output_file, "div %s, %s\n", reg_a, reg_b);
158 : 0 : fileprint(output_file, "mfhi %s\n", reg_a);
159 : 0 : *output_type = INT_TYPE;
160 : 0 : }
161 : :
162 : 0 : void operation_assign_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){
163 [ # # ]: 0 : if(!value_a->is_reference){
164 : 0 : snprintf(error_message, sizeof(error_message), "Cannot assign to r-value");
165 : 0 : do_error(1);
166 : : }
167 : 0 : pop_type(&(value_a->data_type));
168 [ # # ]: 0 : if(peek_type(&(value_a->data_type)) == type_function){
169 : 0 : snprintf(error_message, sizeof(error_message), "Cannot assign to function");
170 : 0 : do_error(1);
171 : : }
172 [ # # ]: 0 : if(type_size(&(value_a->data_type), 0) == 4){
173 : 0 : fileprint(output_file, "sw %s, 0(%s)\n", reg_b, reg_a);
174 [ # # ]: 0 : } else if(type_size(&(value_a->data_type), 0) == 1){
175 : 0 : fileprint(output_file, "sb %s, 0(%s)\n", reg_b, reg_a);
176 : : }
177 : 0 : fileprint(output_file, "move %s, %s\n", reg_a, reg_b);
178 : 0 : *output_type = value_b->data_type;
179 : 0 : }
180 : :
181 : 0 : void operation_less_than_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){
182 [ # # # # : 0 : if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){
# # # # ]
183 : 0 : snprintf(error_message, sizeof(error_message), "Cannot compare non-int types with '<'");
184 : 0 : do_error(1);
185 : : }
186 : 0 : fileprint(output_file, "slt %s, %s, %s\n", reg_a, reg_a, reg_b);
187 : 0 : *output_type = INT_TYPE;
188 : 0 : }
189 : :
190 : 0 : void operation_greater_than_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){
191 [ # # # # : 0 : if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){
# # # # ]
192 : 0 : snprintf(error_message, sizeof(error_message), "Cannot compare non-int types with '>'");
193 : 0 : do_error(1);
194 : : }
195 : 0 : fileprint(output_file, "sgt %s, %s, %s\n", reg_a, reg_a, reg_b);
196 : 0 : *output_type = INT_TYPE;
197 : 0 : }
198 : :
199 : 0 : void operation_less_than_or_equal_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){
200 [ # # # # : 0 : if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){
# # # # ]
201 : 0 : snprintf(error_message, sizeof(error_message), "Cannot compare non-int types with '<='");
202 : 0 : do_error(1);
203 : : }
204 : 0 : fileprint(output_file, "sgt %s, %s, %s\n", reg_a, reg_a, reg_b);
205 : 0 : fileprint(output_file, "seq %s, %s, $zero\n", reg_a, reg_a);
206 : 0 : *output_type = INT_TYPE;
207 : 0 : }
208 : :
209 : 0 : void operation_greater_than_or_equal_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){
210 [ # # # # : 0 : if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){
# # # # ]
211 : 0 : snprintf(error_message, sizeof(error_message), "Cannot compare non-int types with '>='");
212 : 0 : do_error(1);
213 : : }
214 : 0 : fileprint(output_file, "slt %s, %s, %s\n", reg_a, reg_a, reg_b);
215 : 0 : fileprint(output_file, "seq %s, %s, $zero\n", reg_a, reg_a);
216 : 0 : *output_type = INT_TYPE;
217 : 0 : }
218 : :
219 : 0 : void operation_equals_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){
220 [ # # # # ]: 0 : if(peek_type(&(value_a->data_type)) == type_function || peek_type(&(value_b->data_type)) == type_function){
221 : 0 : snprintf(error_message, sizeof(error_message), "Cannot compare function types");
222 : 0 : do_error(1);
223 : : }
224 [ # # ]: 0 : if(peek_type(&(value_a->data_type)) == type_pointer){
225 [ # # ]: 0 : if(peek_type(&(value_b->data_type)) == type_pointer){
226 : 0 : pop_type(&(value_a->data_type));
227 : 0 : pop_type(&(value_b->data_type));
228 [ # # ]: 0 : if(!types_equal(&(value_a->data_type), &(value_b->data_type))){
229 : 0 : snprintf(warning_message, sizeof(warning_message), "Comparing incompatible data types");
230 : 0 : do_warning();
231 : : }
232 : 0 : fileprint(output_file, "seq %s, %s, %s\n", reg_a, reg_a, reg_b);
233 : 0 : *output_type = INT_TYPE;
234 : : } else {
235 : 0 : snprintf(warning_message, sizeof(warning_message), "Comparing pointer and non-pointer types");
236 : 0 : do_warning();
237 : 0 : fileprint(output_file, "seq %s, %s, %s\n", reg_a, reg_a, reg_b);
238 : 0 : *output_type = INT_TYPE;
239 : : }
240 : : } else {
241 [ # # ]: 0 : if(peek_type(&(value_b->data_type)) == type_pointer){
242 : 0 : snprintf(warning_message, sizeof(warning_message), "Comparing pointer and non-pointer types");
243 : 0 : do_warning();
244 : : }
245 : 0 : fileprint(output_file, "seq %s, %s, %s\n", reg_a, reg_a, reg_b);
246 : 0 : *output_type = INT_TYPE;
247 : : }
248 : 0 : }
249 : :
250 : 0 : void operation_not_equals_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){
251 [ # # # # ]: 0 : if(peek_type(&(value_a->data_type)) == type_function || peek_type(&(value_b->data_type)) == type_function){
252 : 0 : snprintf(error_message, sizeof(error_message), "Cannot compare function types");
253 : 0 : do_error(1);
254 : : }
255 [ # # ]: 0 : if(peek_type(&(value_a->data_type)) == type_pointer){
256 [ # # ]: 0 : if(peek_type(&(value_b->data_type)) == type_pointer){
257 : 0 : pop_type(&(value_a->data_type));
258 : 0 : pop_type(&(value_b->data_type));
259 [ # # ]: 0 : if(!types_equal(&(value_a->data_type), &(value_b->data_type))){
260 : 0 : snprintf(warning_message, sizeof(warning_message), "Comparing incompatible data types");
261 : 0 : do_warning();
262 : : }
263 : 0 : fileprint(output_file, "sne %s, %s, %s\n", reg_a, reg_a, reg_b);
264 : 0 : *output_type = INT_TYPE;
265 : : } else {
266 : 0 : snprintf(warning_message, sizeof(warning_message), "Comparing pointer and non-pointer types");
267 : 0 : do_warning();
268 : 0 : fileprint(output_file, "sne %s, %s, %s\n", reg_a, reg_a, reg_b);
269 : 0 : *output_type = INT_TYPE;
270 : : }
271 : : } else {
272 [ # # ]: 0 : if(peek_type(&(value_b->data_type)) == type_pointer){
273 : 0 : snprintf(warning_message, sizeof(warning_message), "Comparing pointer and non-pointer types");
274 : 0 : do_warning();
275 : : }
276 : 0 : fileprint(output_file, "sne %s, %s, %s\n", reg_a, reg_a, reg_b);
277 : 0 : *output_type = INT_TYPE;
278 : : }
279 : 0 : }
280 : :
281 : 0 : void operation_and_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){
282 [ # # # # : 0 : if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){
# # # # ]
283 : 0 : snprintf(error_message, sizeof(error_message), "Cannot '&' non-int types");
284 : 0 : do_error(1);
285 : : }
286 : 0 : fileprint(output_file, "and %s, %s, %s\n", reg_a, reg_a, reg_b);
287 : 0 : *output_type = INT_TYPE;
288 : 0 : }
289 : :
290 : 0 : void operation_or_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){
291 [ # # # # : 0 : if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){
# # # # ]
292 : 0 : snprintf(error_message, sizeof(error_message), "Cannot '|' non-int types");
293 : 0 : do_error(1);
294 : : }
295 : 0 : fileprint(output_file, "or %s, %s, %s\n", reg_a, reg_a, reg_b);
296 : 0 : *output_type = INT_TYPE;
297 : 0 : }
298 : :
299 : 0 : void operation_shift_left_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){
300 [ # # # # : 0 : if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){
# # # # ]
301 : 0 : snprintf(error_message, sizeof(error_message), "Cannot '<<' non-arithmetic types");
302 : 0 : do_error(1);
303 : : }
304 : 0 : fileprint(output_file, "sllv %s, %s, %s\n", reg_a, reg_a, reg_b);
305 : 0 : *output_type = INT_TYPE;
306 : 0 : }
307 : :
308 : 0 : void operation_shift_right_func(char *reg_a, char *reg_b, value *value_a, value *value_b, FILE *output_file, type *output_type){
309 [ # # # # : 0 : if((!types_equal(&(value_a->data_type), &INT_TYPE) && !types_equal(&(value_a->data_type), &CHAR_TYPE)) || (!types_equal(&(value_b->data_type), &INT_TYPE) && !types_equal(&(value_b->data_type), &CHAR_TYPE))){
# # # # ]
310 : 0 : snprintf(error_message, sizeof(error_message), "Cannot '>>' non-arithmetic types");
311 : 0 : do_error(1);
312 : : }
313 : 0 : fileprint(output_file, "srav %s, %s, %s\n", reg_a, reg_a, reg_b);
314 : 0 : *output_type = INT_TYPE;
315 : 0 : }
316 : :
317 : : void (*operation_functions[])(char *, char *, value *, value *, FILE *, type *) = {operation_none_func, operation_add_func, operation_subtract_func, operation_multiply_func, operation_divide_func, operation_assign_func, operation_less_than_func, operation_greater_than_func, operation_less_than_or_equal_func, operation_greater_than_or_equal_func, operation_equals_func, operation_not_equals_func, operation_and_func, operation_or_func, operation_modulo_func, operation_none_func, operation_none_func, operation_shift_left_func, operation_shift_right_func};
318 : :
319 : 0 : int type_size(type *t, unsigned int start_entry){
320 : 0 : uint64_t d0;
321 : 0 : uint64_t d1;
322 : 0 : uint64_t d2;
323 : 0 : unsigned int index;
324 : 0 : unsigned int current_entry = 0;
325 : 0 : int entry;
326 : 0 : int output = 1;
327 : :
328 : 0 : d0 = t->d0;
329 : 0 : d1 = t->d1;
330 : 0 : d2 = t->d2;
331 : 0 : index = t->current_index;
332 : 0 : while(1){
333 : 0 : entry = 0;
334 [ # # ]: 0 : if(d0&1){
335 : 0 : entry |= 1;
336 : : }
337 [ # # ]: 0 : if(d1&1){
338 : 0 : entry |= 2;
339 : : }
340 [ # # ]: 0 : if(d2&1){
341 : 0 : entry |= 4;
342 : : }
343 [ # # ]: 0 : if(current_entry >= start_entry){
344 [ # # # # : 0 : switch(entry){
# # # ]
345 : 0 : case type_void:
346 : 0 : return output*VOID_SIZE;
347 : 0 : case type_int:
348 : 0 : return output*INT_SIZE;
349 : 0 : case type_char:
350 : 0 : return output*CHAR_SIZE;
351 : 0 : case type_pointer:
352 : 0 : return output*POINTER_SIZE;
353 : 0 : case type_function:
354 : 0 : return output*POINTER_SIZE;
355 : 0 : case type_list:
356 : 0 : index--;
357 : 0 : output *= t->list_indicies[index];
358 : 0 : break;
359 : 0 : default:
360 : 0 : return 0;
361 : : }
362 [ # # ]: 0 : } else if(entry == type_list){
363 : 0 : index--;
364 : : }
365 : 0 : d0 >>= 1;
366 : 0 : d1 >>= 1;
367 : 0 : d2 >>= 1;
368 : 0 : current_entry++;
369 : : }
370 : : }
371 : :
372 : 0 : static void free_var(void *v){
373 : 0 : variable *var;
374 : :
375 : 0 : var = (variable *) v;
376 : 0 : free(var->varname);
377 : 0 : free(var);
378 : 0 : }
379 : :
380 : 0 : void free_global_variables(){
381 : 0 : free_dictionary(global_variables, free_var);
382 : 0 : }
383 : :
384 : 0 : void free_local_variables(){
385 : 0 : int i;
386 : :
387 [ # # ]: 0 : for(i = current_scope; i >= 0; i--){
388 [ # # ]: 0 : if(local_variables[i]){
389 : 0 : free_dictionary(*local_variables[i], free_var);
390 : 0 : free(local_variables[i]);
391 : 0 : local_variables[i] = NULL;
392 : : }
393 : : }
394 : :
395 : 0 : variables_size = 0;
396 : 0 : }
397 : :
398 : 0 : static int var_stack_position(variable *var){
399 : 0 : return saved_stack_size + variables_size - var->stack_pos - 4;
400 : : }
401 : :
402 : 0 : unsigned int align4(unsigned int size){
403 : 0 : unsigned int remainder;
404 : :
405 : 0 : remainder = size%4;
406 [ # # ]: 0 : if(remainder){
407 : 0 : size += 4 - remainder;
408 : : }
409 : :
410 : 0 : return size;
411 : : }
412 : :
413 : 0 : void compile_variable_initializer(char **c){
414 : 0 : variable *var;
415 : 0 : char varname_buf[32];
416 : 0 : type vartype;
417 : :
418 : 0 : vartype = EMPTY_TYPE;
419 : 0 : parse_type(&vartype, c, varname_buf, NULL, 32, 0);
420 : 0 : var = malloc(sizeof(variable));
421 : 0 : var->varname = malloc(sizeof(char)*32);
422 : 0 : var->var_type = vartype;
423 : 0 : strcpy(var->varname, varname_buf);
424 [ # # ]: 0 : variables_size += align4(type_size(&(var->var_type), 0));
425 : 0 : var->stack_pos = variables_size - 4;
426 [ # # ]: 0 : if(read_dictionary(*local_variables[current_scope], var->varname, 0)){
427 : 0 : free(var->varname);
428 : 0 : free(var);
429 : 0 : snprintf(error_message, sizeof(error_message), "Duplicate local variable definition");
430 : 0 : do_error(1);
431 : : }
432 : 0 : write_dictionary(local_variables[current_scope], var->varname, var, 0);
433 : 0 : skip_whitespace(c);
434 [ # # ]: 0 : if(**c != ';'){
435 : 0 : snprintf(error_message, sizeof(error_message), "Expected ';'");
436 : 0 : do_error(1);
437 : : }
438 : 0 : ++*c;
439 : 0 : }
440 : :
441 : 0 : void compile_integer(value *output, char **c, unsigned char dereference, unsigned char force_stack, FILE *output_file){
442 : 0 : int int_value;
443 : :
444 : 0 : output->data = allocate(force_stack);
445 : 0 : int_value = strtol(*c, c, 0);
446 [ # # ]: 0 : if(output->data.type == data_register){
447 : 0 : fileprint(output_file, "li $s%d, %d\n", output->data.reg, int_value);
448 [ # # ]: 0 : } else if(output->data.type == data_stack){
449 : 0 : fileprint(output_file, "li $t0, %d\nsw $t0, %d($sp)\n", int_value, get_stack_pos(output->data));
450 : : }
451 : 0 : output->data_type = INT_TYPE;
452 : 0 : output->is_reference = 0;
453 : 0 : }
454 : :
455 : 0 : static void compile_local_variable(value *output, variable *var, unsigned char dereference, unsigned char force_stack, FILE *output_file){
456 : 0 : data_entry data;
457 : 0 : type data_type;
458 : :
459 : 0 : data_type = var->var_type;
460 : 0 : data = allocate(force_stack);
461 : 0 : output->data_type = data_type;
462 : 0 : output->data = data;
463 [ # # ]: 0 : if(dereference){
464 [ # # ]: 0 : if(peek_type(&(var->var_type)) == type_list){
465 [ # # ]: 0 : if(data.type == data_register){
466 : 0 : fileprint(output_file, "addi $s%d, $sp, %d\n", data.reg, var_stack_position(var));
467 [ # # ]: 0 : } else if(data.type == data_stack){
468 : 0 : fileprint(output_file, "addi $t0, $sp, %d\n", var_stack_position(var));
469 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(data));
470 : : }
471 : 0 : pop_type(&(output->data_type));
472 : 0 : output->data_type.current_index--;
473 : 0 : add_type_entry(&(output->data_type), type_pointer);
474 : : } else {
475 [ # # ]: 0 : if(data.type == data_register){
476 [ # # # ]: 0 : switch(type_size(&data_type, 0)){
477 : 0 : case 1:
478 : 0 : fileprint(output_file, "lb $s%d, %d($sp)\n", data.reg, var_stack_position(var));
479 : 0 : break;
480 : 0 : case 4:
481 : 0 : fileprint(output_file, "lw $s%d, %d($sp)\n", data.reg, var_stack_position(var));
482 : 0 : break;
483 : :
484 : : }
485 [ # # ]: 0 : } else if(data.type == data_stack){
486 [ # # # ]: 0 : switch(type_size(&data_type, 0)){
487 : 0 : case 1:
488 : 0 : fileprint(output_file, "lb $t0, %d($sp)\n", var_stack_position(var));
489 : 0 : fileprint(output_file, "sb $t0, %d($sp)\n", get_stack_pos(data));
490 : 0 : break;
491 : 0 : case 4:
492 : 0 : fileprint(output_file, "lw $t0, %d($sp)\n", var_stack_position(var));
493 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(data));
494 : 0 : break;
495 : : }
496 : 0 : }
497 : : }
498 : : } else {
499 [ # # ]: 0 : if(peek_type(&(var->var_type)) == type_list){
500 [ # # ]: 0 : if(data.type == data_register){
501 : 0 : fileprint(output_file, "addi $s%d, $sp, %d\n", data.reg, var_stack_position(var));
502 [ # # ]: 0 : } else if(data.type == data_stack){
503 : 0 : fileprint(output_file, "addi $t0, $sp, %d\n", var_stack_position(var));
504 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(data));
505 : : }
506 : : } else {
507 [ # # ]: 0 : if(data.type == data_register){
508 : 0 : fileprint(output_file, "addi $s%d, $sp, %d\n", data.reg, var_stack_position(var));
509 [ # # ]: 0 : } else if(data.type == data_stack){
510 : 0 : fileprint(output_file, "addi $t0, $sp, %d\n", var_stack_position(var));
511 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(data));
512 : : }
513 : : }
514 : 0 : add_type_entry(&(output->data_type), type_pointer);
515 : : }
516 : :
517 : 0 : output->is_reference = !dereference;
518 : 0 : }
519 : :
520 : 0 : static void compile_global_variable(value *output, variable *var, unsigned char dereference, unsigned char force_stack, FILE *output_file){
521 : 0 : data_entry data;
522 : 0 : type data_type;
523 : :
524 : 0 : data_type = var->var_type;
525 : 0 : data = allocate(force_stack);
526 [ # # ]: 0 : if(data.type == data_register){
527 : 0 : fileprint(output_file, "la $s%d, %s\n", data.reg, var->varname);
528 : : } else {
529 : 0 : fileprint(output_file, "la $t0, %s\n", var->varname);
530 : : }
531 : 0 : output->data = data;
532 : 0 : output->is_reference = !dereference;
533 [ # # # # ]: 0 : if(dereference && !var->leave_as_address){
534 [ # # ]: 0 : if(peek_type(&data_type) == type_list){
535 : 0 : pop_type(&data_type);
536 : 0 : data_type.current_index--;
537 : 0 : add_type_entry(&data_type, type_pointer);
538 [ # # ]: 0 : if(data.type == data_stack){
539 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(data));
540 : : }
541 : : } else {
542 [ # # ]: 0 : if(data.type == data_register){
543 : 0 : fileprint(output_file, "lw $s%d, 0($s%d)\n", data.reg, data.reg);
544 [ # # ]: 0 : } else if(data.type == data_stack){
545 : 0 : fileprint(output_file, "lw $t0, 0($t0)\n");
546 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(data));
547 : : }
548 : : }
549 : : } else {
550 : 0 : add_type_entry(&data_type, type_pointer);
551 [ # # ]: 0 : if(data.type == data_stack){
552 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(data));
553 : : }
554 : : }
555 : 0 : output->data_type = data_type;
556 : 0 : }
557 : :
558 : 0 : void compile_variable(value *output, char **c, unsigned char dereference, unsigned char force_stack, FILE *output_file){
559 : 0 : char *start;
560 : 0 : char varname[32] = {0};
561 : 0 : unsigned int varname_length = 0;
562 : 0 : variable *var;
563 : 0 : int i;
564 : :
565 : 0 : skip_whitespace(c);
566 : 0 : start = *c;
567 [ # # # # ]: 0 : while(alphanumeric(**c) && varname_length < 31){
568 : 0 : ++*c;
569 : 0 : varname_length++;
570 : : }
571 : 0 : memcpy(varname, start, varname_length);
572 : 0 : varname[31] = '\0';
573 : :
574 [ # # ]: 0 : for(i = current_scope; i >= 0; i--){
575 : 0 : var = read_dictionary(*local_variables[i], varname, 0);
576 [ # # ]: 0 : if(var){
577 : 0 : break;
578 : : }
579 : : }
580 : :
581 [ # # ]: 0 : if(!var){
582 : 0 : var = read_dictionary(global_variables, varname, 0);
583 [ # # ]: 0 : if(!var){
584 : 0 : snprintf(error_message, sizeof(error_message), "Unrecognized variable '%s'", varname);
585 : 0 : do_error(1);
586 : : }
587 : 0 : compile_global_variable(output, var, dereference, force_stack, output_file);
588 : : } else {
589 : 0 : compile_local_variable(output, var, dereference, force_stack, output_file);
590 : : }
591 : 0 : }
592 : :
593 : : void compile_expression(value *output, char **c, unsigned char dereference, unsigned char force_stack, FILE *output_file);
594 : :
595 : 0 : void cast(value *v, type t, unsigned char do_warn, FILE *output_file){
596 : 0 : type t_copy;
597 : 0 : type_entry entry1;
598 : 0 : type_entry entry2;
599 : :
600 [ # # # # ]: 0 : if(types_equal(&(v->data_type), &VOID_TYPE) && !types_equal(&t, &VOID_TYPE)){
601 : 0 : snprintf(error_message, sizeof(error_message), "Can't cast void type to non-void type");
602 : 0 : do_error(1);
603 : : }
604 : :
605 [ # # ]: 0 : if(peek_type(&t) == type_list){
606 : 0 : snprintf(error_message, sizeof(error_message), "Can't cast to an array");
607 : 0 : do_error(1);
608 : : }
609 : :
610 [ # # # # ]: 0 : if(type_size(&(v->data_type), 0) == 4 && type_size(&t, 0) == 1){
611 [ # # ]: 0 : if(v->data.type == data_register){
612 : 0 : fileprint(output_file, "sll $s%d, $s%d, 24\n", v->data.reg, v->data.reg);
613 : 0 : fileprint(output_file, "sra $s%d, $s%d, 24\n", v->data.reg, v->data.reg);
614 [ # # ]: 0 : } else if(v->data.type == data_stack){
615 : 0 : fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(v->data));
616 : 0 : fileprint(output_file, "sll $t0, $t0, 24\n");
617 : 0 : fileprint(output_file, "sra $t0, $t0, 24\n");
618 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(v->data));
619 : : }
620 [ # # # # ]: 0 : } else if(type_size(&(v->data_type), 0) == 1 && type_size(&t, 0) == 4){
621 [ # # ]: 0 : if(v->data.type == data_stack){
622 : 0 : fileprint(output_file, "lb $t0, %d($sp)\n", get_stack_pos(v->data));
623 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(v->data));
624 : : }
625 : : }
626 : :
627 : 0 : t_copy = t;
628 : 0 : entry1 = pop_type(&t_copy);
629 : 0 : entry2 = pop_type(&(v->data_type));
630 [ # # # # ]: 0 : if((entry1 == type_pointer) != (entry2 == type_pointer) && do_warn){
631 : 0 : snprintf(warning_message, sizeof(warning_message), "Casting between pointer and non-pointer types");
632 : 0 : do_warning();
633 [ # # # # : 0 : } else if(entry1 == type_pointer && !types_equal(&t_copy, &(v->data_type)) && !types_equal(&t_copy, &VOID_TYPE) && !types_equal(&(v->data_type), &VOID_TYPE) && do_warn){
# # # # #
# ]
634 : 0 : snprintf(warning_message, sizeof(warning_message), "Casting between incompatible pointer types");
635 : 0 : do_warning();
636 : : }
637 : :
638 : 0 : v->data_type = t;
639 : 0 : }
640 : :
641 : 0 : void compile_dereference(value *v, FILE *output_file){
642 : 0 : type data_type;
643 : :
644 : 0 : data_type = v->data_type;
645 [ # # ]: 0 : if(pop_type(&data_type) != type_pointer){
646 : 0 : snprintf(error_message, sizeof(error_message), "Cannot dereference non-pointer type");
647 : 0 : do_error(1);
648 : : }
649 [ # # ]: 0 : if(peek_type(&data_type) == type_void){
650 : 0 : snprintf(error_message, sizeof(error_message), "Cannot dereference void pointer");
651 : 0 : do_error(1);
652 : : }
653 [ # # ]: 0 : if(peek_type(&data_type) == type_list){
654 : 0 : pop_type(&data_type);
655 : 0 : data_type.current_index--;
656 : 0 : add_type_entry(&data_type, type_pointer);
657 [ # # ]: 0 : } else if(peek_type(&data_type) != type_function){
658 [ # # ]: 0 : if(v->data.type == data_register){
659 [ # # ]: 0 : if(type_size(&data_type, 0) == 1){
660 : 0 : fileprint(output_file, "lb $s%d, 0($s%d)\n", v->data.reg, v->data.reg);
661 [ # # ]: 0 : } else if(type_size(&data_type, 0) == 4){
662 : 0 : fileprint(output_file, "lw $s%d, 0($s%d)\n", v->data.reg, v->data.reg);
663 : : }
664 [ # # ]: 0 : } else if(v->data.type == data_stack){
665 : 0 : fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(v->data));
666 [ # # ]: 0 : if(type_size(&data_type, 0) == 1){
667 : 0 : fileprint(output_file, "lb $t0, 0($t0)\n");
668 : 0 : fileprint(output_file, "sb $t0, %d($sp)\n", get_stack_pos(v->data));
669 [ # # ]: 0 : } else if(type_size(&data_type, 0) == 4){
670 : 0 : fileprint(output_file, "lw $t0, 0($t0)\n");
671 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(v->data));
672 : : }
673 : : }
674 : : }
675 : :
676 : 0 : v->data_type = data_type;
677 : 0 : v->is_reference = 0;
678 : 0 : }
679 : :
680 : 0 : void compile_function_call(char **c, value *func, FILE *output_file){
681 : 0 : reg_list reg_state;
682 : 0 : data_entry return_data;
683 : 0 : data_entry return_address_data;
684 : 0 : type current_argument_type;
685 : 0 : value current_argument_value;
686 : 0 : unsigned int label_num;
687 : 0 : int func_stack_pos = 0;
688 : 0 : int any_args = 0;
689 : :
690 [ # # ]: 0 : if(peek_type(&(func->data_type)) == type_pointer){
691 : 0 : pop_type(&(func->data_type));
692 : : }
693 [ # # ]: 0 : if(pop_type(&(func->data_type)) != type_function){
694 : 0 : snprintf(error_message, sizeof(error_message), "Can't call non-function type");
695 : 0 : do_error(1);
696 : : }
697 : :
698 : 0 : label_num = num_labels;
699 : 0 : num_labels++;
700 : 0 : reg_state = push_registers(output_file);
701 : :
702 [ # # ]: 0 : if(func->data.type == data_register){
703 : 0 : func_stack_pos = get_reg_stack_pos(reg_state, func->data.reg);
704 : : }
705 : 0 : return_address_data = allocate(1);
706 : 0 : return_data = allocate(1);
707 : 0 : fileprint(output_file, "la $t0, __L%d\n", label_num);
708 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(return_address_data));
709 [ # # ]: 0 : if(peek_type(&(func->data_type)) == type_returns){
710 : 0 : skip_whitespace(c);
711 [ # # ]: 0 : if(**c != ')'){
712 : 0 : snprintf(error_message, sizeof(error_message), "Expected ')'");
713 : 0 : do_error(1);
714 : : }
715 : 0 : ++*c;
716 : : }
717 [ # # ]: 0 : while(peek_type(&(func->data_type)) != type_returns){
718 : 0 : any_args = 1;
719 : 0 : current_argument_type = get_argument_type(&(func->data_type));
720 : 0 : compile_expression(¤t_argument_value, c, 1, 1, output_file);
721 [ # # # # ]: 0 : if(**c != ',' && peek_type(&(func->data_type)) != type_returns){
722 : 0 : snprintf(error_message, sizeof(error_message), "Expected ','");
723 : 0 : do_error(1);
724 [ # # # # ]: 0 : } else if(**c != ')' && peek_type(&(func->data_type)) == type_returns){
725 : 0 : snprintf(error_message, sizeof(error_message), "Expected ')'");
726 : 0 : do_error(1);
727 : : }
728 : 0 : ++*c;
729 : 0 : cast(¤t_argument_value, current_argument_type, 1, output_file);
730 : : }
731 : :
732 : 0 : pop_type(&(func->data_type));
733 [ # # ]: 0 : if(func->data.type == data_register){
734 : 0 : fileprint(output_file, "lw $t0, %d($sp)\n", func_stack_pos);
735 [ # # ]: 0 : if(any_args)
736 : 0 : fileprint(output_file, "addi $sp, $sp, %d\n", get_stack_pos(current_argument_value.data));
737 : : else
738 : 0 : fileprint(output_file, "addi $sp, $sp, %d\n", get_stack_pos(return_data));
739 : 0 : fileprint(output_file, "jr $t0\n\n");
740 [ # # ]: 0 : } else if(func->data.type == data_stack){
741 : 0 : fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(func->data));
742 [ # # ]: 0 : if(any_args)
743 : 0 : fileprint(output_file, "addi $sp, $sp, %d\n", get_stack_pos(current_argument_value.data));
744 : : else
745 : 0 : fileprint(output_file, "addi $sp, $sp, %d\n", get_stack_pos(return_data));
746 : 0 : fileprint(output_file, "jr $t0\n\n");
747 : : }
748 : 0 : fileprint(output_file, "__L%d:\n", label_num);
749 [ # # ]: 0 : if(any_args)
750 : 0 : fileprint(output_file, "addi $sp, $sp, %d\n", -get_stack_pos(current_argument_value.data));
751 : : else
752 : 0 : fileprint(output_file, "addi $sp, $sp, %d\n", -get_stack_pos(return_data));
753 : 0 : fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(return_data));
754 : 0 : deallocate(return_data);
755 : 0 : deallocate(return_address_data);
756 : 0 : pull_registers(reg_state, output_file);
757 [ # # ]: 0 : if(func->data.type == data_register){
758 : 0 : fileprint(output_file, "move $s%d, $t0\n", func->data.reg);
759 [ # # ]: 0 : } else if(func->data.type == data_stack){
760 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(func->data));
761 : : }
762 : 0 : }
763 : :
764 : 0 : void compile_list_index(char **c, value *address, unsigned char dereference, FILE *output_file){
765 : 0 : value index;
766 : 0 : type address_type;
767 : :
768 : 0 : address_type = address->data_type;
769 [ # # ]: 0 : if(pop_type(&address_type) != type_pointer){
770 : 0 : snprintf(error_message, sizeof(error_message), "Cannot address non-pointer type");
771 : 0 : do_error(1);
772 : : }
773 : 0 : ++*c;
774 : 0 : compile_expression(&index, c, 1, 0, output_file);
775 [ # # ]: 0 : if(**c != ']'){
776 : 0 : snprintf(error_message, sizeof(error_message), "Expected closing ']'");
777 : 0 : do_error(1);
778 : : }
779 : 0 : ++*c;
780 : 0 : cast(&index, INT_TYPE, 1, output_file);
781 [ # # ]: 0 : if(index.data.type == data_register){
782 [ # # ]: 0 : if(type_size(&address_type, 0) == 4){
783 : 0 : fileprint(output_file, "sll $s%d, $s%d, 2\n", index.data.reg, index.data.reg);
784 [ # # ]: 0 : } else if(type_size(&address_type, 0) != 1){
785 : 0 : fileprint(output_file, "li $t0, %d\n", (int) type_size(&address_type, 0));
786 : 0 : fileprint(output_file, "mult $s%d, $t0\n", index.data.reg);
787 : 0 : fileprint(output_file, "mflo $s%d\n", index.data.reg);
788 : : }
789 [ # # ]: 0 : if(address->data.type == data_register){
790 : 0 : fileprint(output_file, "add $s%d, $s%d, $s%d\n", address->data.reg, address->data.reg, index.data.reg);
791 [ # # # # ]: 0 : if(dereference && peek_type(&address_type) != type_list){
792 [ # # ]: 0 : if(type_size(&address_type, 0) == 4){
793 : 0 : fileprint(output_file, "lw $s%d, 0($s%d)\n", address->data.reg, address->data.reg);
794 [ # # ]: 0 : } else if(type_size(&address_type, 0) == 1){
795 : 0 : fileprint(output_file, "lb $s%d, 0($s%d)\n", address->data.reg, address->data.reg);
796 : : } else {
797 : 0 : snprintf(error_message, sizeof(error_message), "[INTERNAL] Unusable type size");
798 : 0 : do_error(1);
799 : : }
800 : : }
801 [ # # ]: 0 : } else if(address->data.type == data_stack){
802 : 0 : fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(address->data));
803 : 0 : fileprint(output_file, "add $t0, $t0, $s%d\n", index.data.reg);
804 [ # # # # ]: 0 : if(dereference && peek_type(&address_type) != type_list){
805 [ # # ]: 0 : if(type_size(&address_type, 0) == 4){
806 : 0 : fileprint(output_file, "lw $t0, 0($t0)\n");
807 [ # # ]: 0 : } else if(type_size(&address_type, 0) == 1){
808 : 0 : fileprint(output_file, "lb $t0, 0($t0)\n");
809 : : } else {
810 : 0 : snprintf(error_message, sizeof(error_message), "[INTERNAL] Unusable type size");
811 : 0 : do_error(1);
812 : : }
813 : : }
814 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(address->data));
815 : : }
816 [ # # ]: 0 : } else if(index.data.type == data_stack){
817 : 0 : fileprint(output_file, "lw $t1, %d($sp)\n", get_stack_pos(index.data));
818 [ # # ]: 0 : if(type_size(&address_type, 0) == 4){
819 : 0 : fileprint(output_file, "sll $t1, $t1, 2\n");
820 [ # # ]: 0 : } else if(type_size(&address_type, 0) != 1){
821 : 0 : fileprint(output_file, "li $t0, %d\n", (int) type_size(&address_type, 0));
822 : 0 : fileprint(output_file, "mult $t1, $t0\n");
823 : 0 : fileprint(output_file, "mflo $t1\n");
824 : : }
825 [ # # ]: 0 : if(address->data.type == data_register){
826 : 0 : fileprint(output_file, "add $s%d, $s%d, $t1\n", address->data.reg, address->data.reg);
827 [ # # # # ]: 0 : if(dereference && peek_type(&address_type) != type_list){
828 [ # # ]: 0 : if(type_size(&address_type, 0) == 4){
829 : 0 : fileprint(output_file, "lw $s%d, 0($s%d)\n", address->data.reg, address->data.reg);
830 [ # # ]: 0 : } else if(type_size(&address_type, 0) == 1){
831 : 0 : fileprint(output_file, "lb $s%d, 0($s%d)\n", address->data.reg, address->data.reg);
832 : : }
833 : : }
834 [ # # ]: 0 : } else if(address->data.type == data_stack){
835 : 0 : fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(address->data));
836 : 0 : fileprint(output_file, "add $t0, $t0, $t1\n");
837 [ # # # # ]: 0 : if(dereference && peek_type(&address_type) != type_list){
838 [ # # ]: 0 : if(type_size(&address_type, 0) == 4){
839 : 0 : fileprint(output_file, "lw $t0, 0($t0)\n");
840 [ # # ]: 0 : } else if(type_size(&address_type, 0) == 1){
841 : 0 : fileprint(output_file, "lb $t0, 0($t0)\n");
842 : : }
843 : : }
844 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(address->data));
845 : : }
846 : : }
847 : 0 : deallocate(index.data);
848 [ # # ]: 0 : if(dereference){
849 : 0 : pop_type(&(address->data_type));
850 [ # # ]: 0 : if(peek_type(&(address->data_type)) == type_list){
851 : 0 : pop_type(&(address->data_type));
852 : 0 : address->data_type.current_index--;
853 : 0 : add_type_entry(&(address->data_type), type_pointer);
854 : : }
855 : : }
856 : 0 : address->is_reference = !dereference;
857 : 0 : }
858 : :
859 : : void match_brackets(char **c);
860 : :
861 : 0 : void skip_string(char **c){
862 [ # # # # : 0 : while(**c && **c != '\"'){
# # # # #
# ]
863 [ # # # # : 0 : if(**c == '\\'){
# # # # #
# ]
864 : 0 : *c += 2;
865 : : } else {
866 : 0 : ++*c;
867 : : }
868 : : }
869 [ # # # # : 0 : if(**c){
# # # # #
# ]
870 : 0 : ++*c;
871 : : }
872 : 0 : }
873 : :
874 : 0 : void match_parentheses(char **c){
875 [ # # # # : 0 : while(**c && **c != ')' && **c != ']'){
# # ]
876 [ # # ]: 0 : if(**c == '"'){
877 : 0 : ++*c;
878 : 0 : skip_string(c);
879 : 0 : skip_whitespace(c);
880 : 0 : continue;
881 : : }
882 [ # # ]: 0 : if(**c == '('){
883 : 0 : ++*c;
884 : 0 : match_parentheses(c);
885 [ # # ]: 0 : } else if(**c == '['){
886 : 0 : ++*c;
887 : 0 : match_brackets(c);
888 : : } else {
889 : 0 : ++*c;
890 : : }
891 : 0 : skip_whitespace(c);
892 : : }
893 [ # # # # ]: 0 : if(!**c || **c == ']'){
894 : 0 : snprintf(error_message, sizeof(error_message), "Expected ')'");
895 : 0 : do_error(1);
896 : : }
897 : 0 : ++*c;
898 : 0 : }
899 : :
900 : 0 : void match_brackets(char **c){
901 [ # # # # : 0 : while(**c && **c != ']' && **c != ')'){
# # ]
902 [ # # ]: 0 : if(**c == '"'){
903 : 0 : ++*c;
904 : 0 : skip_string(c);
905 : 0 : skip_whitespace(c);
906 : 0 : continue;
907 : : }
908 [ # # ]: 0 : if(**c == '('){
909 : 0 : ++*c;
910 : 0 : match_parentheses(c);
911 [ # # ]: 0 : } else if(**c == '['){
912 : 0 : ++*c;
913 : 0 : match_brackets(c);
914 : : } else {
915 : 0 : ++*c;
916 : : }
917 : 0 : skip_whitespace(c);
918 : : }
919 [ # # # # ]: 0 : if(!**c || **c == ')'){
920 : 0 : snprintf(error_message, sizeof(error_message), "Expected ']'");
921 : 0 : do_error(1);
922 : : }
923 : 0 : ++*c;
924 : 0 : }
925 : :
926 : 0 : void skip_comment(char **c){
927 : 0 : ++*c;
928 [ # # ]: 0 : if(**c == '/'){
929 [ # # # # ]: 0 : while(**c && **c != '\n'){
930 : 0 : ++*c;
931 : : }
932 [ # # ]: 0 : if(**c){
933 : 0 : ++*c;
934 : : }
935 : : } else {
936 : 0 : ++*c;
937 [ # # # # : 0 : while(**c && (**c != '*' || (*c)[1] != '/')){
# # ]
938 : 0 : ++*c;
939 : : }
940 [ # # ]: 0 : if(**c){
941 : 0 : *c += 2;
942 : : }
943 : : }
944 : 0 : }
945 : :
946 : 0 : unsigned char is_cast(char *c){
947 [ # # # # ]: 0 : if(*c != '('){
948 : 0 : return 0;
949 : : }
950 : :
951 : 0 : c++;
952 : 0 : return parse_datatype(NULL, &c);
953 : : }
954 : :
955 : 0 : void skip_value(char **c){
956 : 0 : skip_whitespace(c);
957 [ # # # # : 0 : while(**c == '*' || **c == '&' || **c == '!' || **c == '~' || **c == '-' || is_cast(*c) || is_whitespace(*c)){
# # # # #
# # # #
# ]
958 [ # # ]: 0 : if(**c == '('){//ie if we are casting
959 : 0 : ++*c;
960 : 0 : match_parentheses(c);
961 [ # # ]: 0 : } else if(**c == '/'){
962 : 0 : skip_comment(c);
963 : : } else {
964 : 0 : ++*c;
965 : : }
966 : : }
967 [ # # ]: 0 : while(**c == '('){
968 : 0 : ++*c;
969 : 0 : match_parentheses(c);
970 : 0 : skip_whitespace(c);
971 : : }
972 [ # # ]: 0 : if(digit(**c)){
973 [ # # ]: 0 : while(digit(**c)){
974 : 0 : ++*c;
975 : : }
976 [ # # ]: 0 : } else if(alpha(**c)){
977 [ # # ]: 0 : while(alphanumeric(**c)){
978 : 0 : ++*c;
979 : : }
980 [ # # ]: 0 : } else if(**c == '\"'){
981 : 0 : ++*c;
982 : 0 : skip_string(c);
983 [ # # ]: 0 : } else if(**c == '\''){
984 : 0 : ++*c;
985 [ # # ]: 0 : if(**c == '\\'){
986 : 0 : ++*c;
987 : : }
988 [ # # # # ]: 0 : while(**c && **c != '\''){
989 : 0 : ++*c;
990 : : }
991 [ # # ]: 0 : if(**c){
992 : 0 : ++*c;
993 : : }
994 : : }
995 : 0 : skip_whitespace(c);
996 [ # # # # ]: 0 : while(**c == '[' || **c == '('){
997 [ # # ]: 0 : if(**c == '('){
998 : 0 : ++*c;
999 : 0 : match_parentheses(c);
1000 [ # # ]: 0 : } else if(**c == '['){
1001 : 0 : ++*c;
1002 : 0 : match_brackets(c);
1003 : : }
1004 : 0 : skip_whitespace(c);
1005 : 0 : skip_whitespace(c);
1006 : : }
1007 : 0 : }
1008 : :
1009 : 0 : void compile_string(value *output, char **c, unsigned char dereference, unsigned char force_stack, FILE *output_file){
1010 : 0 : ++*c;
1011 : 0 : skip_string(c);
1012 : :
1013 : 0 : output->data = allocate(force_stack);
1014 [ # # ]: 0 : if(output->data.type == data_register){
1015 : 0 : fileprint(output_file, "la $s%d, __str%d\n", output->data.reg, current_string);
1016 [ # # ]: 0 : } else if(output->data.type == data_stack){
1017 : 0 : fileprint(output_file, "la $t0, __str%d\n", current_string);
1018 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(output->data));
1019 : : }
1020 [ # # ]: 0 : if(do_print)
1021 : 0 : current_string++;
1022 : 0 : output->data_type = CHAR_TYPE;
1023 : 0 : add_type_entry(&(output->data_type), type_pointer);
1024 : 0 : output->is_reference = 0;
1025 : 0 : }
1026 : :
1027 : 0 : void compile_character(value *output, char **c, unsigned char dereference, unsigned char force_stack, FILE *output_file){
1028 : 0 : int char_constant = 0;
1029 : 0 : char escape_sequences[] = {'a', 'b', 'e', 'f', 'n', 'r', 't', 'v', '\\', '\'', '\"', '\?'};
1030 : 0 : int escape_values[] = {0x07, 0x08, 0x1B, 0x0C, 0x0A, 0x0D, 0x09, 0x0B, 0x5C, 0x27, 0x22, 0x3F};
1031 : 0 : unsigned char i;
1032 : :
1033 : 0 : ++*c;
1034 : :
1035 [ # # ]: 0 : if(**c == '\\'){
1036 : 0 : ++*c;
1037 [ # # ]: 0 : for(i = 0; i < sizeof(escape_sequences)/sizeof(char); i++){
1038 [ # # ]: 0 : if(**c == escape_sequences[i]){
1039 : 0 : char_constant = escape_values[i];
1040 : : }
1041 : : }
1042 [ # # ]: 0 : if(!char_constant){
1043 : 0 : snprintf(error_message, sizeof(error_message), "Unrecognized escape sequence\n");
1044 : 0 : do_error(1);
1045 : : }
1046 : : } else {
1047 : 0 : char_constant = **c;
1048 : : }
1049 : 0 : ++*c;
1050 [ # # ]: 0 : if(**c != '\''){
1051 : 0 : snprintf(error_message, sizeof(error_message), "Expected closing '\n");
1052 : 0 : do_error(1);
1053 : : }
1054 : 0 : ++*c;
1055 : :
1056 : 0 : output->data = allocate(force_stack);
1057 [ # # ]: 0 : if(output->data.type == data_register){
1058 : 0 : fileprint(output_file, "li $s%d, %d\n", output->data.reg, char_constant);
1059 [ # # ]: 0 : } else if(output->data.type == data_stack){
1060 : 0 : fileprint(output_file, "li $t0, %d\n", char_constant);
1061 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(output->data));
1062 : : }
1063 : 0 : output->data_type = INT_TYPE;
1064 : 0 : output->is_reference = 0;
1065 : 0 : }
1066 : :
1067 : 0 : void compile_logical_not(value *v, FILE *output_file){
1068 : 0 : int size;
1069 : :
1070 [ # # ]: 0 : if(v->data.type == data_register){
1071 : 0 : fileprint(output_file, "seq $s%d, $s%d, $zero\n", v->data.reg, v->data.reg);
1072 [ # # ]: 0 : } else if(v->data.type == data_stack){
1073 : 0 : size = type_size(&(v->data_type), 0);
1074 [ # # ]: 0 : if(size == 4){
1075 : 0 : fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(v->data));
1076 [ # # ]: 0 : } else if(size == 1){
1077 : 0 : fileprint(output_file, "lb $t0, %d($sp)\n", get_stack_pos(v->data));
1078 : : }
1079 : 0 : fileprint(output_file, "seq $t0, $t0, $zero\n");
1080 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(v->data));
1081 : : }
1082 : :
1083 : 0 : v->data_type = INT_TYPE;
1084 : 0 : }
1085 : :
1086 : 0 : void compile_not(value *v, FILE *output_file){
1087 : 0 : int size;
1088 : :
1089 [ # # # # ]: 0 : if(!types_equal(&(v->data_type), &INT_TYPE) && !types_equal(&(v->data_type), &CHAR_TYPE)){
1090 : 0 : snprintf(error_message, sizeof(error_message), "Can't perform bitwise not of non-numerical type");
1091 : 0 : do_error(1);
1092 : : }
1093 [ # # ]: 0 : if(v->data.type == data_register){
1094 : 0 : fileprint(output_file, "nor $s%d, $s%d, $s%d\n", v->data.reg, v->data.reg, v->data.reg);
1095 [ # # ]: 0 : } else if(v->data.type == data_stack){
1096 : 0 : size = type_size(&(v->data_type), 0);
1097 [ # # ]: 0 : if(size == 4){
1098 : 0 : fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(v->data));
1099 [ # # ]: 0 : } else if(size == 1){
1100 : 0 : fileprint(output_file, "lb $t0, %d($sp)\n", get_stack_pos(v->data));
1101 : : }
1102 : 0 : fileprint(output_file, "nor $t0, $t0, $t0\n");
1103 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(v->data));
1104 : : }
1105 : :
1106 : 0 : v->data_type = INT_TYPE;
1107 : 0 : }
1108 : :
1109 : 0 : void compile_negate(value *v, FILE *output_file){
1110 : 0 : int size;
1111 : :
1112 [ # # # # ]: 0 : if(!types_equal(&(v->data_type), &INT_TYPE) && !types_equal(&(v->data_type), &CHAR_TYPE)){
1113 : 0 : snprintf(error_message, sizeof(error_message), "Can't negate non-numerical type");
1114 : 0 : do_error(1);
1115 : : }
1116 [ # # ]: 0 : if(v->data.type == data_register){
1117 : 0 : fileprint(output_file, "sub $s%d, $zero, $s%d\n", v->data.reg, v->data.reg);
1118 [ # # ]: 0 : } else if(v->data.type == data_stack){
1119 : 0 : size = type_size(&(v->data_type), 0);
1120 [ # # ]: 0 : if(size == 4){
1121 : 0 : fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(v->data));
1122 [ # # ]: 0 : } else if(size == 1){
1123 : 0 : fileprint(output_file, "lb $t0, %d($sp)\n", get_stack_pos(v->data));
1124 : : }
1125 : 0 : fileprint(output_file, "sub $t0, $zero, $t0\n");
1126 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(v->data));
1127 : : }
1128 : :
1129 : 0 : v->data_type = INT_TYPE;
1130 : 0 : }
1131 : :
1132 : 0 : void compile_value(value *output, char **c, unsigned char dereference, unsigned char force_stack, FILE *output_file){
1133 : 0 : char *temp_c;
1134 : 0 : type cast_type;
1135 : :
1136 : 0 : skip_whitespace(c);
1137 : :
1138 [ # # ]: 0 : if(**c == '*'){
1139 : 0 : ++*c;
1140 : 0 : compile_value(output, c, 1, force_stack, output_file);
1141 [ # # ]: 0 : if(dereference){
1142 : 0 : compile_dereference(output, output_file);
1143 : : }
1144 : 0 : output->is_reference = !dereference;
1145 : 0 : return;
1146 [ # # ]: 0 : } else if(**c == '&'){
1147 : 0 : ++*c;
1148 [ # # ]: 0 : if(dereference){
1149 : 0 : compile_value(output, c, 0, force_stack, output_file);
1150 : : } else {
1151 : 0 : snprintf(error_message, sizeof(error_message), "Can't get address of r-value");
1152 : 0 : do_error(1);
1153 : : }
1154 : 0 : output->is_reference = 0;
1155 : 0 : return;
1156 [ # # ]: 0 : } else if(**c == '!'){
1157 : 0 : ++*c;
1158 [ # # ]: 0 : if(dereference){
1159 : 0 : compile_value(output, c, 1, force_stack, output_file);
1160 : 0 : compile_logical_not(output, output_file);
1161 : : } else {
1162 : 0 : snprintf(error_message, sizeof(error_message), "Can't get address of r-value");
1163 : 0 : do_error(1);
1164 : : }
1165 : 0 : output->is_reference = 0;
1166 : 0 : return;
1167 [ # # ]: 0 : } else if(**c == '~'){
1168 : 0 : ++*c;
1169 [ # # ]: 0 : if(dereference){
1170 : 0 : compile_value(output, c, 1, force_stack, output_file);
1171 : 0 : compile_not(output, output_file);
1172 : : } else {
1173 : 0 : snprintf(error_message, sizeof(error_message), "Can't get address of r-value");
1174 : 0 : do_error(1);
1175 : : }
1176 : 0 : output->is_reference = 0;
1177 : 0 : return;
1178 [ # # # # ]: 0 : } else if(**c == '-' && !digit((*c)[1])){
1179 : 0 : ++*c;
1180 [ # # ]: 0 : if(dereference){
1181 : 0 : compile_value(output, c, 1, force_stack, output_file);
1182 : 0 : compile_negate(output, output_file);
1183 : : } else {
1184 : 0 : snprintf(error_message, sizeof(error_message), "Can't get address of r-value");
1185 : 0 : do_error(1);
1186 : : }
1187 : 0 : output->is_reference = 0;
1188 : 0 : return;
1189 : : }
1190 : :
1191 [ # # ]: 0 : if(**c == '('){
1192 : 0 : ++*c;
1193 : 0 : skip_whitespace(c);
1194 : 0 : temp_c = *c;
1195 : : //Type casting
1196 [ # # ]: 0 : if(parse_datatype(NULL, &temp_c)){
1197 : 0 : cast_type = EMPTY_TYPE;
1198 : 0 : parse_type(&cast_type, c, NULL, NULL, 0, 0);
1199 [ # # ]: 0 : if(**c != ')'){
1200 : 0 : snprintf(error_message, sizeof(error_message), "Expected ')'");
1201 : 0 : do_error(1);
1202 : : }
1203 : 0 : ++*c;
1204 : 0 : compile_value(output, c, 1, force_stack, output_file);
1205 : 0 : cast(output, cast_type, 0, output_file);
1206 : : //Associative parentheses
1207 : : } else {
1208 : 0 : compile_expression(output, c, dereference, force_stack, output_file);
1209 [ # # ]: 0 : if(**c == ')'){
1210 : 0 : ++*c;
1211 : : } else {
1212 : 0 : snprintf(error_message, sizeof(error_message), "Expected closing ')'");
1213 : 0 : do_error(1);
1214 : : }
1215 : : }
1216 [ # # # # ]: 0 : } else if(**c == '-' || digit(**c)){
1217 : 0 : compile_integer(output, c, dereference, force_stack, output_file);
1218 [ # # ]: 0 : } else if(alpha(**c)){
1219 : 0 : compile_variable(output, c, dereference, force_stack, output_file);
1220 [ # # ]: 0 : } else if(**c == '\"'){
1221 : 0 : compile_string(output, c, dereference, force_stack, output_file);
1222 [ # # ]: 0 : } else if(**c == '\''){
1223 : 0 : compile_character(output, c, dereference, force_stack, output_file);
1224 : : } else {
1225 : 0 : snprintf(error_message, sizeof(error_message), "Unrecognized expression value");
1226 : 0 : do_error(1);
1227 : : }
1228 : :
1229 : 0 : skip_whitespace(c);
1230 [ # # # # ]: 0 : while(**c == '[' || **c == '('){
1231 [ # # ]: 0 : if(**c == '['){
1232 [ # # ]: 0 : if(output->is_reference){
1233 : 0 : compile_dereference(output, output_file);
1234 : : }
1235 : 0 : compile_list_index(c, output, dereference, output_file);
1236 [ # # ]: 0 : } else if(**c == '('){
1237 : 0 : ++*c;
1238 [ # # ]: 0 : if(output->is_reference){
1239 : 0 : compile_dereference(output, output_file);
1240 : : }
1241 : 0 : compile_function_call(c, output, output_file);
1242 : : }
1243 : :
1244 : 0 : skip_whitespace(c);
1245 : : }
1246 : : }
1247 : :
1248 : 0 : operation peek_operation(char *c){
1249 [ # # # # : 0 : switch(*c){
# # # # #
# # # ]
1250 : 0 : case '+':
1251 : 0 : return operation_add;
1252 : 0 : case '-':
1253 : 0 : return operation_subtract;
1254 : 0 : case '*':
1255 : 0 : return operation_multiply;
1256 : 0 : case '/':
1257 : 0 : return operation_divide;
1258 : 0 : case '%':
1259 : 0 : return operation_modulo;
1260 : 0 : case '=':
1261 [ # # ]: 0 : if(c[1] == '='){
1262 : 0 : return operation_equals;
1263 : : } else {
1264 : 0 : return operation_assign;
1265 : : }
1266 : 0 : case '!':
1267 [ # # ]: 0 : if(c[1] == '='){
1268 : 0 : return operation_not_equals;
1269 : : } else {
1270 : 0 : return operation_none;
1271 : : }
1272 : 0 : case '>':
1273 [ # # ]: 0 : if(c[1] == '>'){
1274 : 0 : return operation_shift_right;
1275 [ # # ]: 0 : } else if(c[1] == '='){
1276 : 0 : return operation_greater_than_or_equal;
1277 : : } else {
1278 : 0 : return operation_greater_than;
1279 : : }
1280 : 0 : case '<':
1281 [ # # ]: 0 : if(c[1] == '<'){
1282 : 0 : return operation_shift_left;
1283 [ # # ]: 0 : } else if(c[1] == '='){
1284 : 0 : return operation_less_than_or_equal;
1285 : : } else {
1286 : 0 : return operation_less_than;
1287 : : }
1288 : 0 : case '&':
1289 [ # # ]: 0 : if(c[1] == '&'){
1290 : 0 : return operation_logical_and;
1291 : : } else {
1292 : 0 : return operation_and;
1293 : : }
1294 : 0 : case '|':
1295 [ # # ]: 0 : if(c[1] == '|'){
1296 : 0 : return operation_logical_or;
1297 : : } else {
1298 : 0 : return operation_or;
1299 : : }
1300 : : }
1301 : :
1302 : 0 : return operation_none;
1303 : : }
1304 : :
1305 : 0 : operation get_operation(char **c){
1306 : 0 : operation output;
1307 : :
1308 : 0 : skip_whitespace(c);
1309 [ # # # # : 0 : switch(**c){
# # # # #
# # # ]
1310 : 0 : case '+':
1311 : 0 : output = operation_add;
1312 : 0 : break;
1313 : 0 : case '-':
1314 : 0 : output = operation_subtract;
1315 : 0 : break;
1316 : 0 : case '*':
1317 : 0 : output = operation_multiply;
1318 : 0 : break;
1319 : 0 : case '/':
1320 : 0 : output = operation_divide;
1321 : 0 : break;
1322 : 0 : case '%':
1323 : 0 : output = operation_modulo;
1324 : 0 : break;
1325 : 0 : case '=':
1326 [ # # ]: 0 : if((*c)[1] == '='){
1327 : 0 : output = operation_equals;
1328 : 0 : ++*c;
1329 : : } else {
1330 : 0 : output = operation_assign;
1331 : : }
1332 : 0 : break;
1333 : 0 : case '!':
1334 [ # # ]: 0 : if((*c)[1] == '='){
1335 : 0 : output = operation_not_equals;
1336 : 0 : ++*c;
1337 : : } else {
1338 : 0 : output = operation_none;
1339 : : }
1340 : 0 : break;
1341 : 0 : case '>':
1342 [ # # ]: 0 : if((*c)[1] == '>'){
1343 : 0 : output = operation_shift_right;
1344 : 0 : ++*c;
1345 [ # # ]: 0 : } else if((*c)[1] == '='){
1346 : 0 : output = operation_greater_than_or_equal;
1347 : 0 : ++*c;
1348 : : } else {
1349 : 0 : output = operation_greater_than;
1350 : : }
1351 : 0 : break;
1352 : 0 : case '<':
1353 [ # # ]: 0 : if((*c)[1] == '<'){
1354 : 0 : output = operation_shift_left;
1355 : 0 : ++*c;
1356 [ # # ]: 0 : } else if((*c)[1] == '='){
1357 : 0 : output = operation_less_than_or_equal;
1358 : 0 : ++*c;
1359 : : } else {
1360 : 0 : output = operation_less_than;
1361 : : }
1362 : 0 : break;
1363 : 0 : case '&':
1364 [ # # ]: 0 : if((*c)[1] == '&'){
1365 : 0 : output = operation_logical_and;
1366 : 0 : ++*c;
1367 : : } else {
1368 : 0 : output = operation_and;
1369 : : }
1370 : 0 : break;
1371 : 0 : case '|':
1372 [ # # ]: 0 : if((*c)[1] == '|'){
1373 : 0 : output = operation_logical_or;
1374 : 0 : ++*c;
1375 : : } else {
1376 : 0 : output = operation_or;
1377 : : }
1378 : 0 : break;
1379 : 0 : default:
1380 : 0 : output = operation_none;
1381 : 0 : break;
1382 : : }
1383 : 0 : ++*c;
1384 : 0 : return output;
1385 : : }
1386 : :
1387 : 0 : void compile_operation(value *first_value, value *next_value, operation op, FILE *output_file){
1388 : 0 : char reg0_str_buffer[5] = {0, 0, 0, 0, 0};
1389 : 0 : char reg1_str_buffer[5] = {0, 0, 0, 0, 0};
1390 : 0 : char *reg0_str = "";
1391 : 0 : char *reg1_str = "";
1392 : 0 : type output_type;
1393 : :
1394 [ # # # # ]: 0 : if(types_equal(&(first_value->data_type), &VOID_TYPE) || types_equal(&(next_value->data_type), &VOID_TYPE)){
1395 : 0 : snprintf(error_message, sizeof(error_message), "Can't operate on void value");
1396 : 0 : do_error(1);
1397 : : }
1398 : :
1399 [ # # ]: 0 : if(first_value->data.type == data_register){
1400 : 0 : snprintf(reg0_str_buffer, sizeof(reg0_str_buffer)/sizeof(char), "$s%d", first_value->data.reg);
1401 : 0 : reg0_str = reg0_str_buffer;
1402 [ # # ]: 0 : } else if(first_value->data.type == data_stack){
1403 : 0 : reg0_str = "$t0";
1404 [ # # ]: 0 : if(type_size(&(first_value->data_type), 0) == 4){
1405 : 0 : fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(first_value->data));
1406 [ # # ]: 0 : } else if(type_size(&(first_value->data_type), 0) == 1){
1407 : 0 : fileprint(output_file, "lb $t0, %d($sp)\n", get_stack_pos(first_value->data));
1408 : : } else {
1409 : 0 : snprintf(error_message, sizeof(error_message), "[INTERNAL] Unusable type size %d", type_size(&(first_value->data_type), 0));
1410 : 0 : do_error(1);
1411 : : }
1412 : : }
1413 [ # # ]: 0 : if(next_value->data.type == data_register){
1414 : 0 : snprintf(reg1_str_buffer, sizeof(reg1_str_buffer)/sizeof(char), "$s%d", next_value->data.reg);
1415 : 0 : reg1_str = reg1_str_buffer;
1416 [ # # ]: 0 : } else if(next_value->data.type == data_stack){
1417 : 0 : reg1_str = "$t1";
1418 [ # # ]: 0 : if(type_size(&(next_value->data_type), 0) == 4){
1419 : 0 : fileprint(output_file, "lw $t1, %d($sp)\n", get_stack_pos(next_value->data));
1420 [ # # ]: 0 : } else if(type_size(&(next_value->data_type), 0) == 1){
1421 : 0 : fileprint(output_file, "lb $t1, %d($sp)\n", get_stack_pos(next_value->data));
1422 : : } else {
1423 : 0 : snprintf(error_message, sizeof(error_message), "[INTERNAL] Unusable type size %d", type_size(&(next_value->data_type), 0));
1424 : 0 : do_error(1);
1425 : : }
1426 : : }
1427 : 0 : operation_functions[op](reg0_str, reg1_str, first_value, next_value, output_file, &output_type);
1428 : 0 : deallocate(next_value->data);
1429 [ # # ]: 0 : if(first_value->data.type == data_stack){
1430 [ # # ]: 0 : if(type_size(&output_type, 0) == 4){
1431 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(first_value->data));
1432 [ # # ]: 0 : } else if(type_size(&output_type, 0) == 1){
1433 : 0 : fileprint(output_file, "sb $t0, %d($sp)\n", get_stack_pos(first_value->data));
1434 : : } else {
1435 : 0 : snprintf(error_message, sizeof(error_message), "[INTERNAL] Unusable type size %d", type_size(&output_type, 0));
1436 : 0 : do_error(1);
1437 : : }
1438 : : }
1439 : 0 : first_value->data_type = output_type;
1440 : 0 : first_value->is_reference = 0;
1441 : 0 : }
1442 : :
1443 : 0 : static void compile_expression_recursive(value *first_value, char **c, FILE *output_file){
1444 : 0 : operation current_operation;
1445 : 0 : operation next_operation;
1446 : 0 : unsigned int label_num = 0;
1447 : 0 : value next_value;
1448 : 0 : char *temp_c;
1449 : 0 : type cast_to;
1450 : 0 : int current_line_temp;
1451 : :
1452 : 0 : skip_whitespace(c);
1453 : 0 : current_operation = get_operation(c);
1454 [ # # ]: 0 : if(current_operation == operation_none){
1455 : 0 : snprintf(error_message, sizeof(error_message), "Unrecognized operation");
1456 : 0 : do_error(1);
1457 [ # # ]: 0 : } else if(current_operation == operation_logical_or){
1458 : 0 : label_num = num_labels;
1459 : 0 : num_labels++;
1460 : 0 : cast(first_value, INT_TYPE, 0, output_file);
1461 [ # # ]: 0 : if(first_value->data.type == data_register){
1462 : 0 : fileprint(output_file, "sne $s%d, $s%d, $zero\n", first_value->data.reg, first_value->data.reg);
1463 : 0 : fileprint(output_file, "bne $s%d, $zero, __L%d\n", first_value->data.reg, label_num);
1464 [ # # ]: 0 : } else if(first_value->data.type == data_stack){
1465 : 0 : fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(first_value->data));
1466 : 0 : fileprint(output_file, "sne $t0, $t0, $zero\n");
1467 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(first_value->data));
1468 : 0 : fileprint(output_file, "bne $t0, $zero, __L%d\n", label_num);
1469 : : }
1470 [ # # ]: 0 : } else if(current_operation == operation_logical_and){
1471 : 0 : label_num = num_labels;
1472 : 0 : num_labels++;
1473 : 0 : cast(first_value, INT_TYPE, 0, output_file);
1474 [ # # ]: 0 : if(first_value->data.type == data_register){
1475 : 0 : fileprint(output_file, "beq $s%d, $zero, __L%d\n", first_value->data.reg, label_num);
1476 [ # # ]: 0 : } else if(first_value->data.type == data_stack){
1477 : 0 : fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(first_value->data));
1478 : 0 : fileprint(output_file, "beq $t0, $zero, __L%d\n", label_num);
1479 : : }
1480 : : }
1481 : :
1482 : 0 : temp_c = *c;
1483 : 0 : current_line_temp = current_line;
1484 : 0 : skip_value(&temp_c);
1485 : 0 : current_line = current_line_temp;
1486 : 0 : next_operation = peek_operation(temp_c);
1487 [ # # # # ]: 0 : if(next_operation == operation_assign && order_of_operations[operation_assign] > order_of_operations[current_operation]){
1488 : 0 : compile_value(&next_value, c, 0, 0, output_file);
1489 : : } else {
1490 : 0 : compile_value(&next_value, c, 1, 0, output_file);
1491 : : }
1492 : 0 : skip_whitespace(c);
1493 [ # # ]: 0 : while(order_of_operations[next_operation] > order_of_operations[current_operation]){
1494 : 0 : compile_expression_recursive(&next_value, c, output_file);
1495 : 0 : skip_whitespace(c);
1496 : 0 : next_operation = peek_operation(*c);
1497 : : }
1498 [ # # ]: 0 : if(current_operation == operation_assign){
1499 : 0 : cast_to = first_value->data_type;
1500 : 0 : pop_type(&cast_to);
1501 : 0 : cast(&next_value, cast_to, 1, output_file);
1502 : 0 : compile_operation(first_value, &next_value, current_operation, output_file);
1503 [ # # # # ]: 0 : } else if(current_operation == operation_logical_or || current_operation == operation_logical_and){
1504 : 0 : cast(&next_value, INT_TYPE, 0, output_file);
1505 [ # # ]: 0 : if(next_value.data.type == data_register){
1506 : 0 : fileprint(output_file, "sne $s%d, $s%d, $zero\n", next_value.data.reg, next_value.data.reg);
1507 [ # # ]: 0 : if(first_value->data.type == data_register){
1508 : 0 : fileprint(output_file, "move $s%d, $s%d\n", first_value->data.reg, next_value.data.reg);
1509 [ # # ]: 0 : } else if(first_value->data.type == data_stack){
1510 : 0 : fileprint(output_file, "sw $s%d, %d($sp)\n", next_value.data.reg, get_stack_pos(first_value->data));
1511 : : }
1512 [ # # ]: 0 : } else if(next_value.data.type == data_stack){
1513 [ # # ]: 0 : if(first_value->data.type == data_register){
1514 : 0 : fileprint(output_file, "lw $s%d, %d($sp)\n", first_value->data.reg, get_stack_pos(next_value.data));
1515 : 0 : fileprint(output_file, "sne $s%d, $s%d, $zero\n", first_value->data.reg, first_value->data.reg);
1516 [ # # ]: 0 : } else if(first_value->data.type == data_stack){
1517 : 0 : fileprint(output_file, "lw $t0, %d($sp)\n", get_stack_pos(next_value.data));
1518 : 0 : fileprint(output_file, "sne $t0, $t0, $zero\n");
1519 : 0 : fileprint(output_file, "sw $t0, %d($sp)\n", get_stack_pos(first_value->data));
1520 : : }
1521 : : }
1522 : 0 : deallocate(next_value.data);
1523 : 0 : fileprint(output_file, "\n__L%d:\n", label_num);
1524 : : } else {
1525 : 0 : compile_operation(first_value, &next_value, current_operation, output_file);
1526 : : }
1527 : 0 : skip_whitespace(c);
1528 : 0 : }
1529 : :
1530 : 0 : void compile_expression(value *first_value, char **c, unsigned char dereference, unsigned char force_stack, FILE *output_file){
1531 : 0 : char *temp_c;
1532 : 0 : int current_line_temp;
1533 : 0 : operation next_operation;
1534 : :
1535 : 0 : temp_c = *c;
1536 : 0 : current_line_temp = current_line;
1537 : 0 : skip_value(&temp_c);
1538 : 0 : current_line = current_line_temp;
1539 : :
1540 : 0 : next_operation = peek_operation(temp_c);
1541 [ # # ]: 0 : if(peek_operation(temp_c) == operation_assign){
1542 : 0 : compile_value(first_value, c, 0, force_stack, output_file);
1543 : : } else {
1544 [ # # # # ]: 0 : compile_value(first_value, c, dereference || next_operation != operation_none, force_stack, output_file);
1545 : : }
1546 [ # # # # : 0 : while(**c && **c != ';' && **c != ',' && **c != ')' && **c != ']'){
# # # # #
# ]
1547 : 0 : compile_expression_recursive(first_value, c, output_file);
1548 : : }
1549 : 0 : }
1550 : :
1551 : 0 : void determine_stack_size(value *first_value, char **c, unsigned char dereference, unsigned char force_stack){
1552 : 0 : char *temp_c;
1553 : :
1554 : 0 : do_print = 0;
1555 : 0 : saved_stack_size = 0;
1556 : 0 : temp_c = *c;
1557 : 0 : compile_expression(first_value, c, dereference, force_stack, NULL);
1558 : 0 : *c = temp_c;
1559 : 0 : do_print = 1;
1560 : 0 : }
1561 : :
1562 : 0 : void compile_root_expression(value *first_value, char **c, unsigned char dereference, unsigned char force_stack, FILE *output_file){
1563 : 0 : determine_stack_size(first_value, c, dereference, force_stack);
1564 : 0 : deallocate(first_value->data);
1565 [ # # ]: 0 : if(saved_stack_size != 0){
1566 : 0 : fprintf(output_file, "addi $sp, $sp, %d\n", -saved_stack_size);
1567 : : }
1568 : 0 : compile_expression(first_value, c, dereference, force_stack, output_file);
1569 : 0 : }
1570 : :
1571 : : //THIS MUST ALWAYS BE CALLED AFTER COMPILE_ROOT_EXPRESSION IS RUN AGAIN!
1572 : : //It is not included in compile_root_expression just in case the caller wants to first cast the return value of compile_root_expression
1573 : : //If compile_root_expression did do that, then such a cast either would not work or would be past the bounds of the stack
1574 : 0 : void reset_stack_pos(value *first_value, FILE *output_file){
1575 [ # # ]: 0 : if(first_value->data.type == data_stack){
1576 : 0 : fprintf(output_file, "lw $t0, %d($sp)\n", get_stack_pos(first_value->data));
1577 : : }
1578 [ # # ]: 0 : if(saved_stack_size != 0){
1579 : 0 : fprintf(output_file, "addi $sp, $sp, %d\n", saved_stack_size);
1580 : : }
1581 : 0 : }
|