/* 2015/10 functions to support printGV() */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "ast.h"
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
const char *AST_TYPE_string[] = {"PROGRAM", "GLOBAL_DECL_LIST", "GLOBAL_DECL", "DECL_LIST", "FUNCTION_DECL", "PARAM_LIST", "PARAM", "DIM_FN", "DIMFN1", "EXPR_NULL", "BLOCK", "DECL", "TYPE_DECL", "VAR_DECL",
"TYPE", "STRUCT_TYPE", "DEF_LIST", "DEF", "OPT_TAG", "TAG", "ID_LIST", "DIM_DECL", "CEXPR", "MCEXPR", "CFACTOR", "INIT_ID_LIST", "INIT_ID", "STMT_LIST", "STMT", "ASSIGN_EXPR_LIST",
"NONEMPTY_ASSIGN_EXPR_LIST", "TEST", "ASSIGN_EXPR", "RELOP_EXPR", "RELOP_TERM", "RELOP_FACTOR", "REL_OP", "RELOP_EXPR_LIST", "NONEMPTY_RELOP_EXPR_LIST", "EXPR", "ADD_OP", "TERM",
"MUL_OP", "FACTOR", "VAR_REF", "DIM", "STRUCT_TAIL", "NUL","ID_value", "CONST_value"};
static void printLabelString(FILE *fp, AST_NODE *astNode)
{
const char *binaryOpString[] = {
"+",
"-",
"*",
"/",
"==",
">=",
"<=",
"!=",
">",
"<",
"&&",
"||"
};
const char *unaryOpString[] = {
"+",
"-",
"!"
};
// fprintf(fp, "%d ", astNode->linenumber);
switch (astNode->nodeType) {
case PROGRAM_NODE:
fprintf(fp, "PROGRAM_NODE");
break;
case DECLARATION_NODE:
fprintf(fp, "DECLARATION_NODE ");
switch (astNode->semantic_value.declSemanticValue.kind) {
case VARIABLE_DECL:
fprintf(fp, "VARIABLE_DECL");
break;
case TYPE_DECL:
fprintf(fp, "TYPE_DECL");
break;
case FUNCTION_DECL:
fprintf(fp, "FUNCTION_DECL");
break;
case FUNCTION_PARAMETER_DECL:
fprintf(fp, "FUNCTION_PARAMETER_DECL");
break;
default:
assert(false);
}
break;
case IDENTIFIER_NODE:
fprintf(fp, "IDENTIFIER_NODE ");
fprintf(fp, "%s ", astNode->semantic_value.identifierSemanticValue.identifierName);
switch (astNode->semantic_value.identifierSemanticValue.kind) {
case NORMAL_ID:
fprintf(fp, "NORMAL_ID");
break;
case ARRAY_ID:
fprintf(fp, "ARRAY_ID");
break;
case WITH_INIT_ID:
fprintf(fp, "WITH_INIT_ID");
break;
default:
assert(false);
}
break;
case PARAM_LIST_NODE:
fprintf(fp, "PARAM_LIST_NODE");
break;
case NUL_NODE:
fprintf(fp, "NUL_NODE");
break;
case BLOCK_NODE:
fprintf(fp, "BLOCK_NODE");
break;
case VARIABLE_DECL_LIST_NODE:
fprintf(fp, "VARIABLE_DECL_LIST_NODE");
break;
case STMT_LIST_NODE:
fprintf(fp, "STMT_LIST_NODE");
break;
case STMT_NODE:
fprintf(fp, "STMT_NODE ");
switch (astNode->semantic_value.stmtSemanticValue.kind) {
case WHILE_STMT:
fprintf(fp, "WHILE_STMT");
break;
case FOR_STMT:
fprintf(fp, "FOR_STMT");
break;
case ASSIGN_STMT:
fprintf(fp, "ASSIGN_STMT");
break;
case IF_STMT:
fprintf(fp, "IF_STMT");
break;
case FUNCTION_CALL_STMT:
fprintf(fp, "FUNCTION_CALL_STMT");
break;
case RETURN_STMT:
fprintf(fp, "RETURN_STMT");
break;
default:
assert(false);
}
break;
case EXPR_NODE:
fprintf(fp, "EXPR_NODE ");
switch (astNode->semantic_value.exprSemanticValue.kind) {
case BINARY_OPERATION:
fprintf(fp, "%s", binaryOpString[astNode->semantic_value.exprSemanticValue.op.binaryOp]);
break;
case UNARY_OPERATION:
fprintf(fp, "%s", unaryOpString[astNode->semantic_value.exprSemanticValue.op.unaryOp]);
break;
default:
assert(false);
}
break;
case CONST_VALUE_NODE:
fprintf(fp, "CONST_VALUE_NODE ");
switch (astNode->semantic_value.const1->const_type) {
case INTEGERC:
fprintf(fp, "%d", astNode->semantic_value.const1->const_u.intval);
break;
case FLOATC:
fprintf(fp, "%f", astNode->semantic_value.const1->const_u.fval);
break;
case STRINGC:
astNode->semantic_value.const1->const_u.sc[strlen(astNode->semantic_value.const1->const_u.sc) - 1] = 0;
fprintf(fp, "\\\"%s\\\"", astNode->semantic_value.const1->const_u.sc + 1);
astNode->semantic_value.const1->const_u.sc[strlen(astNode->semantic_value.const1->const_u.sc)] = '"';
astNode->semantic_value.const1->const_u.sc[strlen(astNode->semantic_value.const1->const_u.sc) + 1] = 0;
break;
default:
assert(false);
}
break;
case NONEMPTY_ASSIGN_EXPR_LIST_NODE:
fprintf(fp, "NONEMPTY_ASSIGN_EXPR_LIST_NODE");
break;
case NONEMPTY_RELOP_EXPR_LIST_NODE:
fprintf(fp, "NONEMPTY_RELOP_EXPR_LIST_NODE");
break;
default:
fprintf(fp, "default case in char *getLabelString(AST_TYPE astType)");
break;
}
}
// count: the (unused) id number to be used
// return: then next unused id number
static int printGVNode(FILE *fp, AST_NODE* node, int count)
{
if (node == NULL) {
return count;
}
int currentNodeCount = count;
fprintf(fp, "node%d [label =\"", count);
printLabelString(fp, node);
fprintf(fp, "\"]\n");
++count;
int countAfterCheckChildren = count;
if (node->child) {
countAfterCheckChildren = printGVNode(fp, node->child, count);
fprintf(fp, "node%d -> node%d [style = bold]\n", currentNodeCount, count);
}
int countAfterCheckSibling = countAfterCheckChildren;
if (node->rightSibling) {
countAfterCheckSibling = printGVNode(fp, node->rightSibling, countAfterCheckChildren);
fprintf(fp, "node%d -> node%d [style = dashed]\n", currentNodeCount, countAfterCheckChildren);
}
return countAfterCheckSibling;
}
void printGV(AST_NODE *root, const char* fileName)
{
if (fileName == NULL) {
fileName = "AST_Graph.gv";
}
FILE *fp;
fp = fopen(fileName, "w");
if (!fp) {
printf("Cannot open file \"%s\"\n", fileName);
return;
}
fprintf(fp , "Digraph AST\n");
fprintf(fp , "{\n");
fprintf(fp , "label = \"%s\"\n", fileName);
int nodeCount = 0;
printGVNode(fp, root, nodeCount);
fprintf(fp , "}\n");
fclose(fp);
}
// vim: set sw=4 ts=4 sts=4 et: