#ifdef HAVE_CONFIG_H # include "config.h" #endif #include "draw.h" #include #include #include #include #include static void print_ast_value(FILE *fp, CcmmcAstValueType type) { putc(' ', fp); switch (type) { case CCMMC_AST_VALUE_INT: fprintf(fp, ""); break; case CCMMC_AST_VALUE_FLOAT: fprintf(fp, ""); break; case CCMMC_AST_VALUE_VOID: fprintf(fp, ""); break; case CCMMC_AST_VALUE_INT_PTR: fprintf(fp, ""); break; case CCMMC_AST_VALUE_FLOAT_PTR: fprintf(fp, ""); break; case CCMMC_AST_VALUE_CONST_STRING: fprintf(fp, ""); break; case CCMMC_AST_VALUE_NONE: fprintf(fp, ""); break; case CCMMC_AST_VALUE_ERROR: fprintf(fp, ""); break; default: assert(false); } } static void printLabelString(FILE *fp, CcmmcAst *astNode) { const char *binaryOpString[] = { "+", "-", "*", "/", "==", ">=", "<=", "!=", ">", "<", "&&", "||" }; const char *unaryOpString[] = { "+", "-", "!" }; switch (astNode->type_node) { case CCMMC_AST_NODE_PROGRAM: fprintf(fp, "PROGRAM_NODE"); break; case CCMMC_AST_NODE_DECL: fprintf(fp, "DECLARATION_NODE "); switch (astNode->value_decl.kind) { case CCMMC_KIND_DECL_VARIABLE: fprintf(fp, "VARIABLE_DECL"); break; case CCMMC_KIND_DECL_TYPE: fprintf(fp, "TYPE_DECL"); break; case CCMMC_KIND_DECL_FUNCTION: fprintf(fp, "FUNCTION_DECL"); break; case CCMMC_KIND_DECL_FUNCTION_PARAMETER: fprintf(fp, "FUNCTION_PARAMETER_DECL"); break; default: assert(false); } break; case CCMMC_AST_NODE_ID: fprintf(fp, "IDENTIFIER_NODE "); fprintf(fp, "%s ", astNode->value_id.name); switch (astNode->value_id.kind) { case CCMMC_KIND_ID_NORMAL: fprintf(fp, "NORMAL_ID"); break; case CCMMC_KIND_ID_ARRAY: fprintf(fp, "ARRAY_ID"); break; case CCMMC_KIND_ID_WITH_INIT: fprintf(fp, "WITH_INIT_ID"); break; default: assert(false); } print_ast_value(fp, astNode->type_value); break; case CCMMC_AST_NODE_PARAM_LIST: fprintf(fp, "PARAM_LIST_NODE"); break; case CCMMC_AST_NODE_NUL: fprintf(fp, "NUL_NODE"); break; case CCMMC_AST_NODE_BLOCK: fprintf(fp, "BLOCK_NODE"); break; case CCMMC_AST_NODE_VARIABLE_DECL_LIST: fprintf(fp, "VARIABLE_DECL_LIST_NODE"); break; case CCMMC_AST_NODE_STMT_LIST: fprintf(fp, "STMT_LIST_NODE"); break; case CCMMC_AST_NODE_STMT: fprintf(fp, "STMT_NODE "); switch (astNode->value_stmt.kind) { case CCMMC_KIND_STMT_WHILE: fprintf(fp, "WHILE_STMT"); break; case CCMMC_KIND_STMT_FOR: fprintf(fp, "FOR_STMT"); break; case CCMMC_KIND_STMT_ASSIGN: fprintf(fp, "ASSIGN_STMT"); break; case CCMMC_KIND_STMT_IF: fprintf(fp, "IF_STMT"); break; case CCMMC_KIND_STMT_FUNCTION_CALL: fprintf(fp, "FUNCTION_CALL_STMT"); print_ast_value(fp, astNode->type_value); break; case CCMMC_KIND_STMT_RETURN: fprintf(fp, "RETURN_STMT"); break; default: assert(false); } break; case CCMMC_AST_NODE_EXPR: fprintf(fp, "EXPR_NODE "); switch (astNode->value_expr.kind) { case CCMMC_KIND_EXPR_BINARY_OP: fprintf(fp, "%s", binaryOpString[astNode->value_expr.op_binary]); break; case CCMMC_KIND_EXPR_UNARY_OP: fprintf(fp, "%s", unaryOpString[astNode->value_expr.op_unary]); break; default: assert(false); } print_ast_value(fp, astNode->type_value); break; case CCMMC_AST_NODE_CONST_VALUE: fprintf(fp, "CONST_VALUE_NODE "); switch (astNode->value_const.kind) { case CCMMC_KIND_CONST_INT: fprintf(fp, "%d", astNode->value_const.const_int); break; case CCMMC_KIND_CONST_FLOAT: fprintf(fp, "%f", astNode->value_const.const_float); break; case CCMMC_KIND_CONST_STRING: fprintf(fp, "\\\"%s\\\"", astNode->value_const.const_string); break; case CCMMC_KIND_CONST_ERROR: default: assert(false); } print_ast_value(fp, astNode->type_value); break; case CCMMC_AST_NODE_NONEMPTY_ASSIGN_EXPR_LIST: fprintf(fp, "NONEMPTY_ASSIGN_EXPR_LIST_NODE"); break; case CCMMC_AST_NODE_NONEMPTY_RELOP_EXPR_LIST: 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, CcmmcAst *node, int count) { if (node == NULL) return count; int currentNodeCount = count; fprintf(fp, "node%d [shape=box] [label =\"", count); printLabelString(fp, node); fprintf(fp, "\"]\n"); for (CcmmcAst *child = node->child; child != NULL; child = child->right_sibling) { int this_count = count + 1; count = printGVNode(fp, child, this_count); fprintf(fp, "node%d -> node%d [style = bold]\n", currentNodeCount, this_count); } return count; } void ccmmc_draw_ast(FILE *fp, const char *name, CcmmcAst *root) { fprintf(fp , "Digraph AST\n"); fprintf(fp , "{\n"); fprintf(fp , "label = \"%s\"\n", name); printGVNode(fp, root, 0); fprintf(fp , "}\n"); } static void print_symbol_type(FILE *fp, CcmmcSymbolType type) { switch (type.type_base) { case CCMMC_AST_VALUE_INT: fputs("int", fp); break; case CCMMC_AST_VALUE_FLOAT: fputs("float", fp); break; case CCMMC_AST_VALUE_VOID: fputs("void", fp); break; case CCMMC_AST_VALUE_INT_PTR: case CCMMC_AST_VALUE_FLOAT_PTR: case CCMMC_AST_VALUE_CONST_STRING: case CCMMC_AST_VALUE_NONE: case CCMMC_AST_VALUE_ERROR: default: assert(false); } if (ccmmc_symbol_type_is_array(type)) { if (type.array_size != NULL) for (size_t i = 0; i < type.array_dimension; i++) fprintf(fp, "[%zu]", type.array_size[i]); else fprintf(fp, "*"); } if (ccmmc_symbol_type_is_function(type)) { fputs(" (*)(", fp); if (type.param_count == 0) fputs("void)", fp); for (size_t i = 0; i < type.param_count; i++) { print_symbol_type(fp, type.param_list[i]); if (i == type.param_count - 1) fputs(")", fp); else fputs(", ", fp); } } } void ccmmc_draw_symbol_scope(FILE *fp, CcmmcSymbolScope *scope) { for (int i = 0; i < CCMMC_SYMBOL_SCOPE_HASH_TABLE_SIZE; i++) { for (CcmmcSymbol *symbol = scope->hash_table[i]; symbol != NULL; symbol = symbol->next) { fprintf(fp, "Bucket %d: %s, ", i, symbol->name); switch (symbol->kind) { case CCMMC_SYMBOL_KIND_TYPE: fputs("TYPE, ", fp); print_symbol_type(fp, symbol->type); break; case CCMMC_SYMBOL_KIND_VARIABLE: fputs("VARIABLE, ", fp); print_symbol_type(fp, symbol->type); break; case CCMMC_SYMBOL_KIND_FUNCTION: fputs("FUNCTION, ", fp); print_symbol_type(fp, symbol->type); break; default: assert(false); } putc('\n', fp); } } } // vim: set sw=4 ts=4 sts=4 et: