ACSE 2.0.3
Advanced Compiler System for Education
Loading...
Searching...
No Matches
program.c
Go to the documentation of this file.
1
3
4#include <string.h>
5#include <stdlib.h>
6#include <ctype.h>
7#include "errors.h"
8#include "program.h"
9#include "scanner.h"
10#include "codegen.h"
11#include "target_info.h"
12#include "target_asm_print.h"
13
14
15static t_label *newLabel(unsigned int value)
16{
17 t_label *result = (t_label *)malloc(sizeof(t_label));
18 if (result == NULL)
19 fatalError("out of memory");
20 result->labelID = value;
21 result->name = NULL;
22 result->global = 0;
23 result->isAlias = 0;
24 return result;
25}
26
28{
29 free(lab->name);
30 free(lab);
31}
32
34{
35 t_listNode *curNode = labels;
36 while (curNode != NULL) {
37 t_label *curLabel = (t_label *)curNode->data;
38 deleteLabel(curLabel);
39 curNode = curNode->next;
40 }
41 deleteList(labels);
42}
43
44
46{
47 t_instrArg *result = (t_instrArg *)malloc(sizeof(t_instrArg));
48 if (result == NULL)
49 fatalError("out of memory");
50 result->ID = ID;
51 result->mcRegWhitelist = NULL;
52 return result;
53}
54
56{
57 t_instruction *result = (t_instruction *)malloc(sizeof(t_instruction));
58 if (result == NULL)
59 fatalError("out of memory");
60 result->opcode = opcode;
61 result->rDest = NULL;
62 result->rSrc1 = NULL;
63 result->rSrc2 = NULL;
64 result->immediate = 0;
65 result->label = NULL;
66 result->addressParam = NULL;
67 result->comment = NULL;
68 return result;
69}
70
72{
73 if (inst == NULL)
74 return;
75 if (inst->rDest != NULL) {
77 free(inst->rDest);
78 }
79 if (inst->rSrc1 != NULL) {
81 free(inst->rSrc1);
82 }
83 if (inst->rSrc2 != NULL) {
85 free(inst->rSrc2);
86 }
87 free(inst->comment);
88 free(inst);
89}
90
91void deleteInstructions(t_listNode *instructions)
92{
93 if (instructions == NULL)
94 return;
95
96 t_listNode *curNode = instructions;
97 while (curNode != NULL) {
98 t_instruction *curInstr = (t_instruction *)curNode->data;
99 deleteInstruction(curInstr);
100 curNode = curNode->next;
101 }
102
103 deleteList(instructions);
104}
105
106
107t_symbol *newSymbol(char *ID, t_symbolType type, int arraySize)
108{
109 t_symbol *result = (t_symbol *)malloc(sizeof(t_symbol));
110 if (result == NULL)
111 fatalError("out of memory");
112 result->type = type;
113 result->arraySize = arraySize;
114 result->ID = ID;
115 result->label = NULL;
116 return result;
117}
118
119static void deleteSymbol(t_symbol *s)
120{
121 free(s->ID);
122 free(s);
123}
124
125static void deleteSymbols(t_listNode *variables)
126{
127 if (variables == NULL)
128 return;
129
130 t_listNode *curNode = variables;
131 while (curNode != NULL) {
132 t_symbol *curSymbol = (t_symbol *)curNode->data;
133 deleteSymbol(curSymbol);
134 curNode = curNode->next;
135 }
136
137 deleteList(variables);
138}
139
140
142{
143 t_program *result = (t_program *)malloc(sizeof(t_program));
144 if (result == NULL)
145 fatalError("out of memory");
146 result->symbols = NULL;
147 result->instructions = NULL;
148 result->firstUnusedReg = 1; // We are excluding register R0.
149 result->labels = NULL;
150 result->firstUnusedLblID = 0;
151 result->pendingLabel = NULL;
152
153 // Create the start label.
154 t_label *lStart = createLabel(result);
155 lStart->global = 1;
156 setLabelName(result, lStart, "_start");
157 assignLabel(result, lStart);
158
159 return result;
160}
161
163{
164 if (program == NULL)
165 return;
166 deleteSymbols(program->symbols);
168 deleteLabels(program->labels);
169 free(program);
170}
171
172
174{
175 t_label *result = newLabel(program->firstUnusedLblID);
176 if (result == NULL)
177 fatalError("out of memory");
178 program->firstUnusedLblID++;
179 program->labels = listInsert(program->labels, result, -1);
180 return result;
181}
182
183/* Set a name to a label without resolving duplicates. */
184void setRawLabelName(t_program *program, t_label *label, const char *finalName)
185{
186 t_listNode *i;
187
188 // Check the entire list of labels because there might be two
189 // label objects with the same ID and they need to be kept in sync.
190 for (i = program->labels; i != NULL; i = i->next) {
191 t_label *thisLab = i->data;
192
193 if (thisLab->labelID == label->labelID) {
194 // Found! Remove old name.
195 free(thisLab->name);
196 // Change to new name.
197 if (finalName)
198 thisLab->name = strdup(finalName);
199 else
200 thisLab->name = NULL;
201 }
202 }
203}
204
205void setLabelName(t_program *program, t_label *label, const char *name)
206{
207 // Remove all non a-zA-Z0-9_ characters.
208 char *sanitizedName = calloc(strlen(name) + 1, sizeof(char));
209 if (!sanitizedName)
210 fatalError("out of memory");
211 const char *srcp = name;
212 for (char *dstp = sanitizedName; *srcp; srcp++) {
213 if (*srcp == '_' || isalnum(*srcp))
214 *dstp++ = *srcp;
215 }
216
217 // Append a sequential number to disambiguate labels with the same name.
218 size_t allocatedSpace = strlen(sanitizedName) + 24;
219 char *finalName = calloc(allocatedSpace, sizeof(char));
220 if (!finalName)
221 fatalError("out of memory");
222 snprintf(finalName, allocatedSpace, "%s", sanitizedName);
223 int serial = -1;
224 bool ok;
225 do {
226 t_listNode *i;
227 ok = true;
228 for (i = program->labels; i != NULL; i = i->next) {
229 t_label *thisLab = i->data;
230 char *thisLabName;
231 int difference;
232
233 if (thisLab->labelID == label->labelID)
234 continue;
235
236 thisLabName = getLabelName(thisLab);
237 difference = strcmp(finalName, thisLabName);
238 free(thisLabName);
239
240 if (difference == 0) {
241 ok = false;
242 snprintf(finalName, allocatedSpace, "%s_%d", sanitizedName, ++serial);
243 break;
244 }
245 }
246 } while (!ok);
247
248 free(sanitizedName);
249 setRawLabelName(program, label, finalName);
250 free(finalName);
251}
252
253void assignLabel(t_program *program, t_label *label)
254{
255 // Check if this label has already been assigned.
256 for (t_listNode *li = program->instructions; li != NULL; li = li->next) {
257 t_instruction *instr = li->data;
258 if (instr->label && instr->label->labelID == label->labelID)
259 fatalError("bug: label already assigned");
260 }
261
262 // Test if the next instruction already has a label.
263 if (program->pendingLabel != NULL) {
264 // It does: transform the label being assigned into an alias of the
265 // label of the next instruction's label.
266 // All label aliases have the same ID and name.
267
268 // Decide the name of the alias. If only one label has a name, that name
269 // wins. Otherwise the name of the label with the lowest ID wins.
270 char *name = program->pendingLabel->name;
271 if (!name ||
272 (label->labelID && label->labelID < program->pendingLabel->labelID))
273 name = label->name;
274 // Copy the name.
275 if (name)
276 name = strdup(name);
277
278 // Change ID and name.
279 label->labelID = (program->pendingLabel)->labelID;
280 setRawLabelName(program, label, name);
281
282 // Promote both labels to global if at least one is global.
283 if (label->global)
284 program->pendingLabel->global = 1;
285 else if (program->pendingLabel->global)
286 label->global = true;
287
288 // Mark the label as an alias.
289 label->isAlias = true;
290
291 free(name);
292 } else {
293 program->pendingLabel = label;
294 }
295}
296
298{
299 char *buf;
300
301 if (label->name) {
302 buf = strdup(label->name);
303 } else {
304 buf = calloc(24, sizeof(char));
305 snprintf(buf, 24, "l_%d", label->labelID);
306 }
307
308 return buf;
309}
310
311
313{
314 static t_fileLocation lastFileLoc = {NULL, -1};
315
316 // Assign the currently pending label if there is one.
317 instr->label = program->pendingLabel;
318 program->pendingLabel = NULL;
319
320 // Add a comment with the line number.
321 if (curFileLoc.row >= 0 &&
322 (curFileLoc.file != lastFileLoc.file ||
323 curFileLoc.row != lastFileLoc.row)) {
324 size_t fileNameLen = strlen(curFileLoc.file);
325 size_t strBufSz = fileNameLen + 10 + 1;
326 instr->comment = calloc(strBufSz, sizeof(char));
327 if (instr->comment) {
328 snprintf(instr->comment, strBufSz, "%s:%d", curFileLoc.file,
329 curFileLoc.row + 1);
330 }
331 }
332 lastFileLoc = curFileLoc;
333
334 // Update the list of instructions.
335 program->instructions = listInsert(program->instructions, instr, -1);
336}
337
339 t_regID rs1, t_regID rs2, t_label *label, int immediate)
340{
341 t_instruction *instr = newInstruction(opcode);
342 if (rd != REG_INVALID)
343 instr->rDest = newInstrArg(rd);
344 if (rs1 != REG_INVALID)
345 instr->rSrc1 = newInstrArg(rs1);
346 if (rs2 != REG_INVALID)
347 instr->rSrc2 = newInstrArg(rs2);
348 if (label)
349 instr->addressParam = label;
350 instr->immediate = immediate;
351
352 // Add the newly created instruction to the current program. This function
353 // may be called with program set to NULL to just create the instruction
354 // without inserting it, so we need to handle this case as well.
355 if (program != NULL)
356 addInstruction(program, instr);
357
358 return instr;
359}
360
362{
363 t_instruction *instrToRemove = (t_instruction *)instrLi->data;
364
365 // Move the label and/or the comment to the next instruction.
366 if (instrToRemove->label || instrToRemove->comment) {
367 // Find the next instruction, if it exists.
368 t_listNode *nextPos = instrLi->next;
369 t_instruction *nextInst = NULL;
370 if (nextPos)
371 nextInst = nextPos->data;
372
373 // Move the label.
374 if (instrToRemove->label) {
375 // Generate a nop if there was no next instruction or if the next
376 // instruction is already labeled.
377 if (!nextInst || (nextInst->label)) {
378 nextInst = genNOP(NULL);
379 program->instructions =
380 listInsertAfter(program->instructions, instrLi, nextInst);
381 }
382 nextInst->label = instrToRemove->label;
383 instrToRemove->label = NULL;
384 }
385
386 // Move the comment, if possible; otherwise it will be discarded.
387 if (nextInst && instrToRemove->comment && !nextInst->comment) {
388 nextInst->comment = instrToRemove->comment;
389 instrToRemove->comment = NULL;
390 }
391 }
392
393 // Remove the instruction.
394 program->instructions = listRemoveNode(program->instructions, instrLi);
395 deleteInstruction(instrToRemove);
396}
397
399{
400 t_regID result = program->firstUnusedReg;
401 program->firstUnusedReg++;
402 return result;
403}
404
405
407 t_program *program, char *ID, t_symbolType type, int arraySize)
408{
409 // Check validity of type.
410 if (type != TYPE_INT && type != TYPE_INT_ARRAY)
411 fatalError("bug: invalid type");
412 // Check array size validity.
413 if (type == TYPE_INT_ARRAY && arraySize <= 0) {
414 emitError(curFileLoc, "invalid size %d for array %s", arraySize, ID);
415 return NULL;
416 }
417
418 // Check if another symbol already exists with the same ID.
419 t_symbol *existingSym = getSymbol(program, ID);
420 if (existingSym != NULL) {
421 emitError(curFileLoc, "variable '%s' already declared", ID);
422 return NULL;
423 }
424
425 // Allocate and initialize a new symbol object.
426 t_symbol *res = newSymbol(ID, type, arraySize);
427
428 // Reserve a new label for the variable.
429 res->label = createLabel(program);
430
431 // Set the name of the label.
432 char *lblName = calloc(strlen(ID) + 8, sizeof(char));
433 if (!lblName)
434 fatalError("out of memory");
435 sprintf(lblName, "l_%s", ID);
436 setLabelName(program, res->label, lblName);
437 free(lblName);
438
439 // Now we can add the new variable to the program.
440 program->symbols = listInsert(program->symbols, res, -1);
441 return res;
442}
443
444
445bool isArray(t_symbol *symbol)
446{
447 // Just check if the type field corresponds to one of the known array types.
448 if (symbol->type == TYPE_INT_ARRAY)
449 return true;
450 return false;
451}
452
453
454static bool compareVariableWithIDString(void *a, void *b)
455{
456 t_symbol *var = (t_symbol *)a;
457 char *str = (char *)b;
458 return strcmp(var->ID, str) == 0;
459}
460
461t_symbol *getSymbol(t_program *program, char *ID)
462{
463 // Search inside the list of variables.
464 t_listNode *elementFound =
465 listFindWithCallback(program->symbols, ID, compareVariableWithIDString);
466
467 // If the element is found return it to the caller. Otherwise return NULL.
468 if (elementFound != NULL)
469 return (t_symbol *)elementFound->data;
470
471 return NULL;
472}
473
474
475void genEpilog(t_program *program)
476{
477 if (program->pendingLabel != NULL) {
478 genExit0Syscall(program);
479 return;
480 }
481
482 if (program->instructions != NULL) {
483 t_listNode *lastNode = listGetLastNode(program->instructions);
484 t_instruction *lastInstr = (t_instruction *)lastNode->data;
485 if (lastInstr->opcode == OPC_CALL_EXIT_0)
486 return;
487 }
488
489 genExit0Syscall(program);
490 return;
491}
492
493void programDump(t_program *program, FILE *fout)
494{
495 fprintf(fout, "# Program dump\n\n");
496
497 fprintf(fout, "## Variables\n\n");
498 t_listNode *curVarNode = program->symbols;
499 while (curVarNode) {
500 t_symbol *var = curVarNode->data;
501 fprintf(fout, "\"%s\":\n", var->ID);
502
503 if (var->type == TYPE_INT) {
504 fprintf(fout, " type = int\n");
505 } else if (var->type == TYPE_INT_ARRAY) {
506 fprintf(fout, " type = int[%d]\n", var->arraySize);
507 } else {
508 fprintf(fout, " type = invalid\n");
509 }
510 char *labelName = getLabelName(var->label);
511 fprintf(fout, " label = %s (ID=%d)\n", labelName, var->label->labelID);
512 free(labelName);
513
514 curVarNode = curVarNode->next;
515 }
516
517 fprintf(fout, "\n## Instructions\n\n");
518 t_listNode *curInstNode = program->instructions;
519 while (curInstNode) {
520 t_instruction *instr = curInstNode->data;
521 if (instr == NULL)
522 fprintf(fout, "(null)");
523 else
524 printInstruction(instr, fout, false);
525 fprintf(fout, "\n");
526 curInstNode = curInstNode->next;
527 }
528
529 fflush(fout);
530}
Code generation functions.
Error logging utilities.
bool printInstruction(t_instruction *instr, FILE *fp, bool machineRegIDs)
char * file
The name of the file.
Definition errors.h:20
int row
The zero-based index of a line in the file.
Definition errors.h:21
void emitError(t_fileLocation loc, const char *fmt,...)
Definition errors.c:23
void fatalError(const char *format,...)
Definition errors.c:32
Structure that represents a location in a file.
Definition errors.h:19
t_instruction * genExit0Syscall(t_program *program)
Definition codegen.c:414
t_instruction * genNOP(t_program *program)
Definition codegen.c:395
struct t_listNode * next
Definition list.h:40
void * data
Pointer to the data associated to this node.
Definition list.h:44
t_listNode * listInsertAfter(t_listNode *list, t_listNode *listPos, void *data)
Definition list.c:44
t_listNode * listInsert(t_listNode *list, void *data, int pos)
Definition list.c:86
t_listNode * deleteList(t_listNode *list)
Definition list.c:189
t_listNode * listFindWithCallback(t_listNode *list, void *data, bool(*compareFunc)(void *a, void *b))
Definition list.c:124
t_listNode * listRemoveNode(t_listNode *list, t_listNode *element)
Definition list.c:148
t_listNode * listGetLastNode(t_listNode *list)
Definition list.c:51
A node belonging a list.
Definition list.h:39
t_fileLocation curFileLoc
Definition scanner.l:11
unsigned int firstUnusedLblID
Next unused label ID.
Definition program.h:103
t_label * addressParam
Definition program.h:77
t_symbolType type
A valid data type.
Definition program.h:86
t_listNode * instructions
List of instructions.
Definition program.h:100
t_listNode * mcRegWhitelist
Definition program.h:66
char * comment
A comment string associated with the instruction, or NULL if none.
Definition program.h:79
int arraySize
For arrays only, the size of the array.
Definition program.h:93
t_listNode * labels
List of all labels.
Definition program.h:99
t_listNode * symbols
Symbol table.
Definition program.h:101
t_label * pendingLabel
Next pending label to assign.
Definition program.h:104
char * name
Definition program.h:52
unsigned int labelID
Unique numeric identifier for the label.
Definition program.h:49
char * ID
Symbol name (should never be a NULL pointer or an empty string "").
Definition program.h:88
bool global
True if the label will be defined as 'global'.
Definition program.h:54
t_instrArg * rSrc1
First source argument (or NULL if none).
Definition program.h:74
t_regID firstUnusedReg
Next unused register ID.
Definition program.h:102
t_instrArg * rSrc2
Second source argument (or NULL if none).
Definition program.h:75
int immediate
Immediate argument.
Definition program.h:76
t_regID ID
The register identifier.
Definition program.h:63
t_label * label
Label associated with the instruction, or NULL.
Definition program.h:71
t_instrArg * rDest
Destination argument (or NULL if none).
Definition program.h:73
bool isAlias
Definition program.h:57
int opcode
Instruction opcode.
Definition program.h:72
void setLabelName(t_program *program, t_label *label, const char *name)
Definition program.c:205
void assignLabel(t_program *program, t_label *label)
Definition program.c:253
t_regID getNewRegister(t_program *program)
Definition program.c:398
#define REG_INVALID
Constant used for invalid register identifiers.
Definition program.h:31
bool isArray(t_symbol *symbol)
Definition program.c:445
t_symbol * getSymbol(t_program *program, char *ID)
Definition program.c:461
void programDump(t_program *program, FILE *fout)
Definition program.c:493
void genEpilog(t_program *program)
Definition program.c:475
t_label * createLabel(t_program *program)
Definition program.c:173
void removeInstructionAt(t_program *program, t_listNode *instrLi)
Definition program.c:361
t_symbol * createSymbol(t_program *program, char *ID, t_symbolType type, int arraySize)
Definition program.c:406
char * getLabelName(t_label *label)
Definition program.c:297
t_instruction * genInstruction(t_program *program, int opcode, t_regID rd, t_regID rs1, t_regID rs2, t_label *label, int immediate)
Definition program.c:338
int t_regID
Type for register identifiers.
Definition program.h:28
t_program * newProgram(void)
Definition program.c:141
void deleteProgram(t_program *program)
Definition program.c:162
t_symbolType
Definition program.h:37
@ TYPE_INT_ARRAY
‘int’ array type.
Definition program.h:39
@ TYPE_INT
‘int’ scalar type.
Definition program.h:38
@ OPC_CALL_EXIT_0
void deleteInstruction(t_instruction *inst)
Definition program.c:71
t_instrArg * newInstrArg(t_regID ID)
Definition program.c:45
void setRawLabelName(t_program *program, t_label *label, const char *finalName)
Definition program.c:184
void deleteLabel(t_label *lab)
Definition program.c:27
void deleteInstructions(t_listNode *instructions)
Definition program.c:91
t_symbol * newSymbol(char *ID, t_symbolType type, int arraySize)
Definition program.c:107
void deleteLabels(t_listNode *labels)
Definition program.c:33
t_instruction * newInstruction(int opcode)
Definition program.c:55
void addInstruction(t_program *program, t_instruction *instr)
Definition program.c:312
Program object definition and management.
Header file associated to scanner.y.
Generation of the output assembly program.
Properties of the target machine.