Code owners
Assign users and groups as approvers for specific file changes. Learn more.
tac_print.c 11.97 KiB
#include <stdio.h>
#include<assert.h>
#include "mcc/dynamic_array.h"
#include "mcc/symbol_table.h"
#include "mcc/symbol_table_print.h"
#include "mcc/tac.h"
#define LABEL_SIZE 64
static const char *tac_type(enum mcc_tac_operation type)
{
switch (type) {
case MCC_TAC_BOOL:
case MCC_TAC_BOOL_LITERAL:
case MCC_TAC_NOT:
case MCC_TAC_AND:
case MCC_TAC_OR:
case MCC_TAC_LOAD_BOOL:
case MCC_TAC_STORE_BOOL:
case MCC_TAC_EQ_BOOL:
case MCC_TAC_IDENTIFIER_BOOL:
case MCC_TAC_PARAM_BOOL:
case MCC_TAC_PARAM_POP_BOOL:
case MCC_TAC_NEQ_BOOL: return "bool";
case MCC_TAC_INT:
case MCC_TAC_INT_LITERAL:
case MCC_TAC_MINUS_INT_BIN:
case MCC_TAC_PLUS_INT:
case MCC_TAC_MUL_INT:
case MCC_TAC_DIV_INT:
case MCC_TAC_LOAD_INT:
case MCC_TAC_EQ:
case MCC_TAC_NEQ:
case MCC_TAC_GT:
case MCC_TAC_LT:
case MCC_TAC_LTEQ:
case MCC_TAC_IDENTIFIER_INT:
case MCC_TAC_PARAM_INT:
case MCC_TAC_PARAM_POP_INT:
case MCC_TAC_GTEQ: return "int";
case MCC_TAC_FLOAT:
case MCC_TAC_IDENTIFIER_FLOAT:
case MCC_TAC_FLOAT_LITERAL:
case MCC_TAC_MINUS_FLOAT_UN:
case MCC_TAC_PLUS_FLOAT:
case MCC_TAC_MINUS_FLOAT_BIN:
case MCC_TAC_MUL_FLOAT:
case MCC_TAC_DIV_FLOAT:
case MCC_TAC_PARAM_FLOAT:
case MCC_TAC_PARAM_POP_FLOAT:
case MCC_TAC_LOAD_FLOAT:
case MCC_TAC_STORE_FLOAT:
case MCC_TAC_LT_FLOAT:
case MCC_TAC_LTEQ_FLOAT:
case MCC_TAC_GT_FLOAT:
case MCC_TAC_GTEQ_FLOAT:
case MCC_TAC_EQ_FLOAT:
case MCC_TAC_NEQ_FLOAT: return "float";
case MCC_TAC_STRING:
case MCC_TAC_IDENTIFIER_STRING:
case MCC_TAC_STRING_LITERAL:
case MCC_TAC_PARAM_STRING:
case MCC_TAC_PARAM_POP_STRING:
case MCC_TAC_LOAD_STRING:
case MCC_TAC_STORE_STRING: return "string";
case MCC_TAC_JMP:
case MCC_TAC_JMP_FALSE:
case MCC_TAC_LABEL:
case MCC_TAC_CALL:
case MCC_TAC_RETURN:
case MCC_TAC_FUNCTION_END:
case MCC_TAC_UNKNOWN: return "untyped";
case MCC_TAC_PARAM_POP_BOOL_ARR:
case MCC_TAC_PARAM_BOOL_ARR: return "bool_array";
case MCC_TAC_PARAM_POP_INT_ARR:
case MCC_TAC_PARAM_INT_ARR: return "int_array";
case MCC_TAC_PARAM_POP_STRING_ARR:
case MCC_TAC_PARAM_STRING_ARR: return "string_array";
case MCC_TAC_PARAM_POP_FLOAT_ARR:
case MCC_TAC_PARAM_FLOAT_ARR: return "float_arr";
}
return "ERROR";
}
void mcc_tac_print(struct mcc_tac *tac, FILE *out)
{
fprintf(out,"------------------------------\n");
fprintf(out,"- TAC -\n");
fprintf(out,"------------------------------\n");
for (int i = 0; i < tac->tac_entries->size ; i++) {
struct mcc_tac_entry *entry = tac->tac_entries->arr[i];
const char *op_type = tac_type(entry->tac_op);
switch (entry->tac_op) {
// Assignment
case MCC_TAC_BOOL:
case MCC_TAC_IDENTIFIER_BOOL:
case MCC_TAC_BOOL_LITERAL:
case MCC_TAC_INT:
case MCC_TAC_IDENTIFIER_INT:
case MCC_TAC_INT_LITERAL:
case MCC_TAC_FLOAT:
case MCC_TAC_IDENTIFIER_FLOAT:
case MCC_TAC_FLOAT_LITERAL:
case MCC_TAC_STRING:
case MCC_TAC_IDENTIFIER_STRING:
case MCC_TAC_STRING_LITERAL:
fprintf(out,"%s = %s (%s)\n", entry->result, entry->arg1, op_type);
break;
// Unary
case MCC_TAC_MINUS_INT_UN:
case MCC_TAC_MINUS_FLOAT_UN:
fprintf(out,"%s = -%s (%s)\n", entry->result, entry->arg1, op_type);
break;
case MCC_TAC_NOT:
fprintf(out,"%s = !%s (%s)\n", entry->result, entry->arg1, op_type);
break;
// Binary
case MCC_TAC_PLUS_INT:
case MCC_TAC_PLUS_FLOAT:
fprintf(out,"%s = %s + %s (%s)\n", entry->result, entry->arg1,
entry->arg2, op_type);
break;
case MCC_TAC_MINUS_INT_BIN:
case MCC_TAC_MINUS_FLOAT_BIN:
fprintf(out,"%s = %s - %s (%s)\n", entry->result, entry->arg1,
entry->arg2, op_type);
break;
case MCC_TAC_MUL_INT:
case MCC_TAC_MUL_FLOAT:
fprintf(out,"%s = %s * %s (%s)\n", entry->result, entry->arg1,
entry->arg2, op_type);
break;
case MCC_TAC_DIV_INT:
case MCC_TAC_DIV_FLOAT:
fprintf(out,"%s = %s / %s (%s)\n", entry->result, entry->arg1,
entry->arg2, op_type);
break;
case MCC_TAC_LT:
case MCC_TAC_LT_FLOAT:
fprintf(out,"%s = %s < %s (%s)\n", entry->result, entry->arg1,
entry->arg2, op_type);
break;
case MCC_TAC_GT:
case MCC_TAC_GT_FLOAT:
fprintf(out,"%s = %s > %s (%s)\n", entry->result, entry->arg1,
entry->arg2, op_type);
break;
case MCC_TAC_LTEQ:
case MCC_TAC_LTEQ_FLOAT:
fprintf(out,"%s = %s <= %s (%s)\n", entry->result, entry->arg1,
entry->arg2, op_type);
break;
case MCC_TAC_GTEQ:
case MCC_TAC_GTEQ_FLOAT:
fprintf(out,"%s = %s >= %s (%s)\n", entry->result, entry->arg1,
entry->arg2, op_type);
break;
case MCC_TAC_AND:
fprintf(out,"%s = %s && %s (%s)\n", entry->result, entry->arg1,
entry->arg2, op_type);
break;
case MCC_TAC_OR:
fprintf(out,"%s = %s || %s (%s)\n", entry->result, entry->arg1,
entry->arg2, op_type);
break;
case MCC_TAC_EQ:
case MCC_TAC_EQ_FLOAT:
case MCC_TAC_EQ_BOOL:
fprintf(out,"%s = %s == %s (%s)\n", entry->result, entry->arg1,
entry->arg2, op_type);
break;
case MCC_TAC_NEQ:
case MCC_TAC_NEQ_FLOAT:
case MCC_TAC_NEQ_BOOL:
fprintf(out,"%s = %s != %s (%s)\n", entry->result, entry->arg1,
entry->arg2, op_type);
break;
// params
case MCC_TAC_PARAM_BOOL:
case MCC_TAC_PARAM_INT:
case MCC_TAC_PARAM_FLOAT:
case MCC_TAC_PARAM_STRING:
fprintf(out,"param_push %s (%s)\n", entry->arg1, op_type);
break;
case MCC_TAC_PARAM_POP_BOOL:
case MCC_TAC_PARAM_POP_INT:
case MCC_TAC_PARAM_POP_FLOAT:
case MCC_TAC_PARAM_POP_STRING:
fprintf(out,"param_pop %s (%s)\n", entry->arg1, op_type);
break;
// load
case MCC_TAC_LOAD_BOOL:
case MCC_TAC_LOAD_INT:
case MCC_TAC_LOAD_FLOAT:
case MCC_TAC_LOAD_STRING:
fprintf(out,"load %s[%s] %s (%s)\n", entry->arg1, entry->arg2,
entry->result, op_type);
break;
// store
case MCC_TAC_STORE_BOOL:
case MCC_TAC_STORE_INT:
case MCC_TAC_STORE_FLOAT:
case MCC_TAC_STORE_STRING:
fprintf(out,"store %s[%s] %s (%s)\n", entry->result, entry->arg2,
entry->arg1, op_type);
break;
// IR operations
case MCC_TAC_JMP:
fprintf(out,"jump %s (%s)\n", entry->result, op_type);
break;
case MCC_TAC_JMP_FALSE:
fprintf(out,"jumpfalse %s %s (%s)\n", entry->arg1, entry->result,
op_type);
break;
case MCC_TAC_LABEL:
fprintf(out,"\n");
fprintf(out,"label %s (%s)\n", entry->result, op_type);
break;
case MCC_TAC_VARIABLE_DECLARATION:
fprintf(out,"declaration %s\n", entry->arg1);
break;
case MCC_TAC_CALL:
fprintf(out,"call %s %s (%s)\n", entry->result, entry->arg1, op_type);
break;
case MCC_TAC_RETURN:
case MCC_TAC_FUNCTION_END:
fprintf(out,"return (%s)\n", op_type);
break;
case MCC_TAC_FUNCTION_START:
fprintf(out, "\n\nfunction %s start \n", entry -> arg1);
break;
default:
fprintf(out,"ERROR\n");
}
}
}
static void print_dot_begin(FILE *out)
{
assert(out);
fprintf(out, "digraph \"AST\" {\n"
"\tnodesep=0.6\n");
}
static void print_dot_end(FILE *out)
{
assert(out);
fprintf(out, "}\n");
}
static void print_dot_node(FILE *out, const void *node, const char *label)
{
assert(out);
assert(node);
assert(label);
fprintf(out, "\t\"%p\" [shape=box, label=\"%s\"];\n", node, label);
}
static void print_dot_edge(FILE *out, const void *src_node, const void *dst_node, const char *label)
{
assert(out);
assert(src_node);
assert(dst_node);
assert(label);
fprintf(out, "\t\"%p\" -> \"%p\" [label=\"%s\"];\n", src_node, dst_node, label);
}
static void print_dot_node_diamond(FILE *out, const void *node, const char *label)
{
assert(out);
assert(node);
assert(label);
fprintf(out, "\t\"%p\" [shape=diamond, label=\"%s\"];\n", node, label);
}
static void print_dot_node_label(FILE *out, int label)
{
assert(out);
assert(label);
fprintf(out, "\t\"Label%d\" [shape=box, label=\"Label%d\"];\n", label,label);
}
static void print_dot_edge_from_label(FILE *out,
const void *dst_node, int label)
{
assert(out);
assert(dst_node);
assert(label);
fprintf(out, "\t\"Label%d\" -> \"%p\" [label=\"%s\"];\n", label, dst_node,
"");
}
static void print_dot_edge_label(FILE *out, const void *src_node,
int label, bool if_else)
{
assert(out);
assert(src_node);
assert(label);
if(if_else==true){
fprintf(out, "\t\"%p\" -> \"Label%d\" [label=\"%s\"];\n", src_node, label,"YES");
}else{
fprintf(out, "\t\"%p\" -> \"Label%d\" [label=\"%s\"];\n", src_node, label,"");
}
}
void mcc_print_cfg_dot(struct mcc_tac *tac, FILE *out)
{
fprintf(out,"------------------------------\n");
fprintf(out,"- CFG DOT -\n");
fprintf(out,"------------------------------\n");
for(int i = 0; i < tac-> tac_entries->size; i++)
{
struct mcc_tac_entry *entry = tac->tac_entries->arr[i];
struct mcc_tac_entry *next_entry = tac->tac_entries->arr[i+1];
const char *op_type = tac_type(entry->tac_op);
switch (entry->tac_op)
{
case MCC_TAC_BOOL:
case MCC_TAC_IDENTIFIER_BOOL:
case MCC_TAC_BOOL_LITERAL:
case MCC_TAC_INT:
case MCC_TAC_IDENTIFIER_INT:
case MCC_TAC_INT_LITERAL:
case MCC_TAC_FLOAT:
case MCC_TAC_IDENTIFIER_FLOAT:
case MCC_TAC_FLOAT_LITERAL:
case MCC_TAC_STRING:
case MCC_TAC_IDENTIFIER_STRING:
case MCC_TAC_STRING_LITERAL:
/*
* have to do this otherwise 'label can only be part of
* a statement and a declaration is not a statement' error
*/
assert(entry->result);
char label[LABEL_SIZE] = { 0 };
snprintf(label, sizeof(label),"%s = %s (%s)\n", entry->result, entry->arg1, op_type);
print_dot_node(out,entry,label);
if(next_entry->tac_op == MCC_TAC_LABEL){
print_dot_edge_label(out,entry,next_entry->result,false);
}
break;
default: fprintf(out, "error %d\n", op_type);
break;
}
}
}