#include "printing.h" #include #define LINUX_VIEW_COMMAND "| convert - -resize 70% sixel:- | cat" #define OSX_VIEW_COMMAND "| ./imgcat -W auto" static char *view_command(void) { struct utsname name; uname(&name); if (strcmp(name.sysname, "Darwin") == 0) { return OSX_VIEW_COMMAND; } else { return LINUX_VIEW_COMMAND; } } bool external_viewer = false; /**********************/ /* Printing functions */ /**********************/ // Print d'un sommet, version noms contenus dans un deq void list_print_state(void *p, FILE *out) { if (isempty_dequeue(p)) { fprintf(out, "E"); } else { for (uint j = 0; j < size_dequeue(p) - 1; j++) { fprintf(out, "%d,", lefread_dequeue(p, j)); } fprintf(out, "%d", lefread_dequeue(p, size_dequeue(p) - 1)); } } /********************************/ /* Print des arêtes d'un graphe */ /********************************/ void named_lgedges_print(stack *theedges, nfa *A, FILE *out) { for (uint i = 0; i < size_stack(theedges); i++) { // Boucle sur les états de départ fprintf(out, "%d -> %d [label = \"", ((multi_edge *)read_stack(theedges, i))->in, ((multi_edge *)read_stack(theedges, i))->out); if (!isempty_dequeue(((multi_edge *)read_stack(theedges, i))->lab)) { for (uint j = 0; j < size_dequeue(((multi_edge *)read_stack(theedges, i))->lab) - 1; j++) { uint letnum = lefread_dequeue(((multi_edge *)read_stack(theedges, i))->lab, j); if (A->alpha_names[letnum] == ' ') { fprintf(out, "%s,", "␣"); } else if (A->alpha_names[letnum] == '\"') { fprintf(out, "\\\","); } else { fprintf(out, "%c,", A->alpha_names[letnum]); } } uint letnum = lefread_dequeue( ((multi_edge *)read_stack(theedges, i))->lab, size_dequeue(((multi_edge *)read_stack(theedges, i))->lab) - 1); if (A->alpha_names[letnum] == ' ') { fprintf(out, "%s\"]\n", "␣"); } else if (A->alpha_names[letnum] == '\"') { fprintf(out, "\\\"\"]\n"); } else { fprintf(out, "%c\"]\n", A->alpha_names[letnum]); } } } } /******************/ /* Print d'un NFA */ /******************/ bool nfa_print(nfa *A, FILE *out) { fprintf(out, "digraph {\n"); fprintf(out, "gradientangle=90\n"); fprintf(out, "fontname=\"Helvetica,Arial,sans-serif\"\n"); fprintf(out, "resolution= \"200.0,0.0\"\n"); fprintf(out, "node [fontname=\"Helvetica,Arial,sans-serif\"]\n"); fprintf(out, "edge [fontname=\"Helvetica,Arial,sans-serif\"]\n"); fprintf(out, "rankdir=LR;\n\n"); uint i = 0; uint f = 0; for (uint k = 0; k < A->trans->size_graph; k++) { fprintf(out, "%d [style=solid", k); if (A->state_names) { fprintf(out, ",label=\"%s\"", A->state_names[k]); } if ((i < size_dequeue(A->initials) && lefread_dequeue(A->initials, i) == k) && (f < size_dequeue(A->finals) && lefread_dequeue(A->finals, f) == k)) { fprintf( out, ",fillcolor=\"blue:green\",style=filled,shape = doublecircle];\n"); i++; f++; continue; } if (i < size_dequeue(A->initials) && lefread_dequeue(A->initials, i) == k) { fprintf(out, ",fillcolor=\"blue:green\",style=filled,shape = circle];\n"); i++; continue; } if (f < size_dequeue(A->finals) && lefread_dequeue(A->finals, f) == k) { fprintf(out, ",shape = doublecircle];\n"); f++; continue; } fprintf(out, ",shape = circle];\n"); } stack *theedges; // Calcul de l'ensemble de transitions theedges = lgraph_to_multi_edges(A->trans); if (!theedges) { fprintf(stderr, "Error when printing: unable to convert graph to " "multi_edges.\nPlease implement lgraph_to_multi_edges()."); return false; } named_lgedges_print(theedges, A, out); while (!isempty_stack(theedges)) { multi_edge *new = pop(theedges); delete_dequeue(new->lab); free(new); } delete_stack(theedges); fprintf(out, "}\n"); return true; } /**************************/ /* Affichage sur le shell */ /**************************/ // Affichage d'un NFA void nfa_view(nfa *thenfa) { if (!thenfa) { CRITICAL("NFA is NULL, impossible to display it."); return; } char tmp_filename[] = "/tmp/nfa-XXXXXX.dot"; int d = mkostemps(tmp_filename, 4, O_APPEND); char png_filename[1 + strlen(tmp_filename)]; strcpy(png_filename, tmp_filename); strcpy(png_filename + strlen(tmp_filename) - 3, "png"); FILE *f_tmp = fdopen(d, "w"); if (!f_tmp) { CRITICAL("Unable to open temporary file"); } nfa_print(thenfa, f_tmp); fclose(f_tmp); char *command; if (!external_viewer) { command = multiple_strcat("dot -Tpng ", tmp_filename, view_command(), NULL); } else { command = multiple_strcat("dot -Tpng ", tmp_filename, " -o ", png_filename, "&& open ", png_filename, NULL); } TRACE("%s", command); system(command); free(command); } // Affichage de regexp, pour le débogage. // Ces fonctions vous sont fournies pour vous aider à déboguer votre code. static void reg_print_helper(regexp *r, regelem parent) { TRACE("reg_print_helper"); if (r == NULL) { return; } switch (r->op) { case CHAR: if (r->letter == ' ') { fprintf(stdout, "%s", "␣"); } else { fprintf(stdout, "%c", r->letter); } break; case EMPTY: print_color("∅", BLUE, stdout); break; case EPSILON: print_color("ε", YELLOW, stdout); break; case UNION: DEBUG("Union"); if (parent != UNION && parent != NONE) { print_color("(", CYAN, stdout); } reg_print_helper(r->left, UNION); print_color(" + ", RED, stdout); reg_print_helper(r->right, UNION); if (parent != UNION && parent != NONE) { print_color(")", CYAN, stdout); } break; case INTER: if (parent != INTER && parent != NONE) { print_color("(", CYAN, stdout); } reg_print_helper(r->left, INTER); printf(" ∩ "); reg_print_helper(r->right, INTER); if (parent != INTER && parent != NONE) { print_color(")", CYAN, stdout); } break; case CONCAT: DEBUG("Concat"); if (parent != CONCAT && parent != UNION && parent != NONE) { print_color("(", CYAN, stdout); } reg_print_helper(r->left, CONCAT); reg_print_helper(r->right, CONCAT); if (parent != CONCAT && parent != UNION && parent != NONE) { print_color(")", CYAN, stdout); } break; case STAR: DEBUG("Star"); if (r->left->op == CHAR || r->left->op == EPSILON || r->left->op == EMPTY) { reg_print_helper(r->left, STAR); print_color("*", CYAN, stdout); } else { // printf("("); reg_print_helper(r->left, STAR); // printf(")"); print_color("*", CYAN, stdout); } break; case COMPLEMENT: if (parent != NONE) { print_color("(", CYAN, stdout); } print_color("¬", RED, stdout); reg_print_helper(r->left, COMPLEMENT); if (parent != NONE) { print_color(")", CYAN, stdout); } break; default: CRITICAL("Unknown regexp operator (%d)", r->op); break; } } void reg_print(regexp *r) { TRACE("reg_print"); reg_print_helper(r, NONE); printf("\n"); }