/* * unger.c: Desarrolla tablas de Unger en formato HTML tomando datos * interactivamente desde la consola. * * Copyright (C) 2008 Gonzalo J. Carracedo * http://batchdrake.wordpress.org * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #include #include #include #include #define OUTPUT_FILENAME "unger.html" #define A_MEALY 0 #define A_MOORE 1 #define BINARYCOMB(inputs) (1 << (inputs)) FILE *htmlfp; typedef struct { int *vt_states; /* Contiene: mt_states elementos */ } unger_transition_vector_t; typedef struct { int *vt_values; /* Contiene: mt_states elementos */ } unger_output_vector_t; typedef struct { int np_phase; int np_prev; int np_next; } unger_nonequiv_pair_t; typedef struct { int ec_code; int ec_counter; int *ec_states; } unger_equiv_class_t; typedef struct { int mt_inputs; int mt_states; unger_transition_vector_t *mt_transitions; /* Contiene: mt_inputs elementos */ unger_output_vector_t *mt_outputs; /* Contiene mt_inputs elementos */ unger_nonequiv_pair_t *mt_noneq_pairs; int mt_noneq_count; unger_equiv_class_t *mt_classes; int mt_class_count; int mt_type; int mt_index_offset; } unger_transition_table_t; inline void *xmalloc (size_t siz) { register void *result; if ((result = malloc (siz)) == NULL) { fprintf (stderr, "malloc: ¡Memoria insuficiente!\n"); exit (1); } return result; } inline void *xrealloc (void *p, size_t siz) { register void *result; if ((result = realloc (p, siz)) == NULL) { fprintf (stderr, "realloc: ¡Memoria insuficiente!\n"); exit (1); } return result; } int pair_is_noneq (unger_transition_table_t *table, int prev, int next) { int i; for (i = 0; i < table->mt_noneq_count; i++) if ((table->mt_noneq_pairs[i].np_prev == prev && table->mt_noneq_pairs[i].np_next == next) || (table->mt_noneq_pairs[i].np_next == prev && table->mt_noneq_pairs[i].np_prev == next)) return table->mt_noneq_pairs[i].np_phase + 1; return 0; } void transition_set_noneq_pair (unger_transition_table_t *table, int phase, int prev, int next) { if (pair_is_noneq (table, prev, next)) return; table->mt_noneq_pairs = xrealloc (table->mt_noneq_pairs, sizeof (unger_nonequiv_pair_t) * (table->mt_noneq_count + 1)); table->mt_noneq_pairs[table->mt_noneq_count].np_phase = phase; table->mt_noneq_pairs[table->mt_noneq_count].np_prev = prev; table->mt_noneq_pairs[table->mt_noneq_count].np_next = next; table->mt_noneq_count++; } unger_transition_table_t *unger_transition_table_new (int type, int inputs, int states) { unger_transition_table_t *result; int i; result = xmalloc (sizeof (unger_transition_table_t)); result->mt_inputs = inputs; result->mt_states = states; result->mt_transitions = xmalloc (sizeof (unger_transition_vector_t) * states); result->mt_outputs = xmalloc (sizeof (unger_output_vector_t) * states); result->mt_noneq_count = 0; result->mt_noneq_pairs = NULL; result->mt_type = type; result->mt_index_offset = 0; for (i = 0; i < inputs; i++) { result->mt_transitions[i].vt_states = xmalloc (sizeof (int) * states); memset (result->mt_transitions[i].vt_states, 0, sizeof (int) * states); } for (i = 0; i < inputs; i++) { result->mt_outputs[i].vt_values = xmalloc (sizeof (int) * states); memset (result->mt_outputs[i].vt_values, 0, sizeof (int) * states); } return result; } void unger_transition_table_set_vector (unger_transition_table_t *table, int input, int *vec) { int i; for (i = 0; i < table->mt_states; i++) table->mt_transitions[input].vt_states[i] = vec[i]; } void unger_transition_table_set_output (unger_transition_table_t *table, int input, int *vec) { int i; for (i = 0; i < table->mt_states; i++) table->mt_outputs[input].vt_values[i] = vec[i]; } char *get_color (int col) { char *colors[] = {"#FF5454", "#54FF54", "#FFFF54", "#5454FF", "#FF54FF", "#54FFFF", "#686868", "red", "green", "yellow", "blue", "purple", "cyan", "gray" }; if (!col) return "white"; return colors [(col - 1) % 14]; } void print_implication_table (unger_transition_table_t *table) { int i, j, n, m; int noneq; fprintf (htmlfp, ""); for (j = 1; j < table->mt_states; j++) { fprintf (htmlfp, "", j + table->mt_index_offset); for (i = 0; i < j; i++) { noneq = 0; for (m = 0; m < table->mt_inputs; m++) if ((noneq = pair_is_noneq (table, i, j)) != 0) break; fprintf (htmlfp, ""); } fprintf (htmlfp, "\n"); } fprintf (htmlfp, ""); for (i = 0; i < table->mt_states - 1; i++) fprintf (htmlfp, "", i + table->mt_index_offset); fprintf (htmlfp, "\n
q%d", get_color (noneq)); for (n = 0; n < table->mt_inputs; n++) /* Ahora, por cada entrada... */ fprintf (htmlfp, "%02d - %02d
", table->mt_transitions[n].vt_states[i] + table->mt_index_offset, table->mt_transitions[n].vt_states[j] + table->mt_index_offset); fprintf (htmlfp, "
q%d
\n
\n"); } int retrieve_output (unger_transition_table_t *table, int input, int state) { return table->mt_outputs[input].vt_values[state]; } void mark_1_noneq (unger_transition_table_t *table) { int i, j, n; for (n = 0; n < table->mt_inputs; n++) for (i = 0; i < table->mt_states; i++) for (j = 0; j < table->mt_states; j++) { if (retrieve_output (table, n, i) != retrieve_output (table, n, j)) transition_set_noneq_pair (table, 0, i, j); } } int mark_n_noneq (unger_transition_table_t *table, int phase) { int i, j, n; int discard_count; int state; discard_count = 0; for (j = 1; j < table->mt_states; j++) { for (i = 0; i < table->mt_states - 1; i++) { if (pair_is_noneq (table, i, j)) continue; for (n = 0; n < table->mt_inputs; n++) { /* pair_is_noneq me devuelve la fase en la que se tachó + 1 */ /* Esta pareja ya está tachada ANTERIORMENTE. Fuera... */ if ((state = pair_is_noneq (table, table->mt_transitions[n].vt_states[i], table->mt_transitions[n].vt_states[j])) && state < (phase + 1)) { transition_set_noneq_pair (table, phase, i, j); /* Lo marcamos */ discard_count++; } } } } return discard_count; } void class_insert_state (unger_transition_table_t *table, int class_index, int state) { table->mt_classes[class_index].ec_states = (int *) xrealloc (table->mt_classes[class_index].ec_states, (table->mt_classes[class_index].ec_counter + 1) * sizeof (int)); table->mt_classes[class_index].ec_states[table->mt_classes[class_index].ec_counter++] = state; } void print_equiv_classes (unger_transition_table_t *table) { int i, j; if (table->mt_class_count == 0) { fprintf (htmlfp, "-"); return; } for (i = 0; i < table->mt_class_count; i++) { if (i) fprintf (htmlfp, ", "); fprintf (htmlfp, "{"); for (j = 0; j < table->mt_classes[i].ec_counter; j++) { if (j) fprintf (htmlfp, ", "); fprintf (htmlfp, "q%d", table->mt_classes[i].ec_states[j] + table->mt_index_offset); } fprintf (htmlfp, "}"); } } int get_equiv_class (unger_transition_table_t *table, int state) { int i, j; for (i = 0; i < table->mt_class_count; i++) for (j = 0; j < table->mt_classes[i].ec_counter; j++) if (table->mt_classes[i].ec_states[j] == state) return i; return -1; } unger_equiv_class_t* get_equiv_class_ptr (unger_transition_table_t *table, int state) { int idx; if ((idx = get_equiv_class (table, state)) == -1) return NULL; else return &table->mt_classes[idx]; } void register_pair (unger_transition_table_t *table, int prev, int next) { int i, j; for (i = 0; i < table->mt_class_count; i++) /* i cuenta los índices de las clases de equivalencia */ { for (j = 0; j < table->mt_classes[i].ec_counter; j++) /* j cuenta los estados de la clase */ { /* Lo siguiente tiene que ver con la propiedad transitiva */ /* ya que si tengo q1, q2 y q3 en la clase, y un par q2, q4, tengo que meter el q4, ya que el q2 ya está */ if (table->mt_classes[i].ec_states[j] == prev) /* Si encontramos el previo, metemos el siguiente */ { if (get_equiv_class (table, next) == -1) /* No nos repitamos */ class_insert_state (table, i, next); return; } else if (table->mt_classes[i].ec_states[j] == next) /* Si encontramos el siguiente, metemos el previo */ { if (get_equiv_class (table, prev) == -1) class_insert_state (table, i, prev); return; } } } /* Ahora bien, si no hemos encontrado donde meter los estados, es que hace falta una clase nueva */ table->mt_classes = (unger_equiv_class_t *) xrealloc (table->mt_classes, (table->mt_class_count + 1) * sizeof (unger_equiv_class_t)); table->mt_classes[table->mt_class_count].ec_states = NULL; table->mt_classes[table->mt_class_count].ec_counter = 0; class_insert_state (table, table->mt_class_count, prev); class_insert_state (table, table->mt_class_count, next); table->mt_class_count++; } void register_unary_class (unger_transition_table_t *table, int state) { int class_index; class_index = get_equiv_class (table, state); if (class_index != -1) return; table->mt_classes = (unger_equiv_class_t *) xrealloc (table->mt_classes, (table->mt_class_count + 1) * sizeof (unger_equiv_class_t)); table->mt_classes[table->mt_class_count].ec_states = NULL; table->mt_classes[table->mt_class_count].ec_counter = 0; class_insert_state (table, table->mt_class_count, state); /* Registramos el estado */ table->mt_class_count++; } /* TODO: Detectar si un estado pertenece a una clase de equivalencia */ void solve_equiv_table (unger_transition_table_t *table) { int i, n, j, count; fprintf (htmlfp, "Tabla de estados equivalentes:
\n"); fprintf (htmlfp, "\n"); fprintf (htmlfp, "\n"); for (i = table->mt_states - 1; i >= 0; i--) { fprintf (htmlfp, ""); } fprintf (htmlfp, "
EstadoClases
q%d", i + table->mt_index_offset); count = 0; for (n = 0; n < table->mt_states - i - 1; n++) { // fprintf (htmlfp, "Recorro: %d\n", n); j = table->mt_states - 1 - n; if (!pair_is_noneq (table, i, j) && i != j) { count++; register_pair (table, i, j); } } /* Si no hemos añadido nada, es que la clase es unaria */ if (!count) register_unary_class (table, i); print_equiv_classes (table); fprintf (htmlfp, "

\n"); } void binary_print (int b, int width) { int n; for (n = width - 1; n >= 0; n--) fprintf (htmlfp, "%d", (b & (1 << n)) ? 1 : 0); } void indif_print (int width) { int n; for (n = 0; n < width; n++) fprintf (htmlfp, "-"); } int need_bits (int states) { int count; int mod; count = 0; mod = 0; while (states > 1) { mod += states % 2; states /= 2; count++; } return count + (mod ? 1 : 0); } /* Los mapas de Karnaugh en general se pueden escribir como celdas del 0..n contando en código Gray. Según Wikipedia: Para pasar un número binario al código binario Gray, hay una regla fácil de implementar en un lenguaje de programación: 1. Un número en binario siempre empieza en 1 --Los ceros a la izquierda no cuentan--; Pues en Gray también. Ej: 1000011110000 en binario se escribe 1xxxxXXXXxxxx. 2. Ahora nos fijamos en el segundo dígito. Si es igual al dígito anterior se pone un 0 (no cambia); Si es diferente --como es el caso, pues el dígito anterior era un 1 y el que observamos un 0-- se pondrá un 1 (cambia). Ej: El número del ejemplo anterior será: 11xxxXXXXxxxx. 3. En los casos sucesivos se repite el paso anterior, observando en el número binario 'natural' el dígito anterior al que se evalúa. Ej: El número del ejemplo anterior, pasado a código Gray será: 1100010001000. */ #define THISBIT(word, b) (((word) & (1 << (b))) != 0) int binary_to_gray (int number) { int n; int ant; int result; n = sizeof (int) * 8 - 1; for (ant = result = 0; n >= 0; n--) { result |= !(ant == THISBIT (number, n)) << n; ant = THISBIT (number, n); } return result; } #undef THISBIT inline void repeat (char c, int n) { register int i; for (i = 0; i < n; i++) fprintf (htmlfp, "%c", c); } inline void spaces (int n) { repeat (' ', n); } int state_is_marked (int *states, int state) { return states[state]; } void mark_equiv_states (unger_transition_table_t *table, int *states, int state) { unger_equiv_class_t *class; int n; class = get_equiv_class_ptr (table, state); if (class == NULL) /* Esto pasa cuando no hemos minimizado el autómata */ return; for (n = 0; n < class->ec_counter; n++) states[class->ec_states[n]] = 1; /* Marcados todos */ } int class_representant (unger_transition_table_t *table, int state) { unger_equiv_class_t *class; int n; int min; class = get_equiv_class_ptr (table, state); if (class == NULL) /* Esto pasa cuando no hemos minimizado el autómata */ return state; /* Puesto que la tabla va de menor a mayor, el más pequeño es el representante */ min = class->ec_states[0]; for (n = 0; n < class->ec_counter; n++) if (class->ec_states[n] < min) min = class->ec_states[n]; return min; } void print_transition_table (unger_transition_table_t *table) { int i, x; int width, swidth; int conv; int diff; int *states_marked; /* Usaré esto para saber qué estados son redundantes y no mostrarlos */ width = need_bits (table->mt_inputs); swidth = 3; /*need_bits (table->mt_states); */ states_marked = xmalloc (table->mt_states * sizeof (int)); memset (states_marked, 0, table->mt_states * sizeof (int)); /* Dejo todos los estados a cero */ fprintf (htmlfp, "Tabla de transición %sasociada al autómata.\n
", table->mt_class_count ? "simplificada " : ""); fprintf (htmlfp, ""); diff = swidth - width; fprintf (htmlfp, "\n", BINARYCOMB (width), table->mt_type == A_MOORE ? 2 : 1, table->mt_type == A_MOORE ? 1 : BINARYCOMB (width)); fprintf (htmlfp, ""); for (x = 0; x < BINARYCOMB (width); x++) { fprintf (htmlfp, ""); } if (table->mt_type == A_MEALY) for (x = 0; x < BINARYCOMB (width); x++) { fprintf (htmlfp, ""); } for (i = 0; i < table->mt_states; i++) { if (state_is_marked (states_marked, i)) continue; fprintf (htmlfp, "", i + table->mt_index_offset); for (x = 0; x < BINARYCOMB (width); x++) { fprintf (htmlfp, ""); } if (table->mt_type == A_MOORE) /* En los autómatas de Moore, sólo hay una serie de salidas */ fprintf (htmlfp, "", table->mt_outputs[0].vt_values[i]); else { for (x = 0; x < BINARYCOMB (width); x++) { conv = binary_to_gray (x); if (conv >= table->mt_inputs) fprintf (htmlfp, ""); else fprintf (htmlfp, "", table->mt_outputs[conv].vt_values[i]); } fprintf (htmlfp, ""); } mark_equiv_states (table, states_marked, i); } fprintf (htmlfp, "
SnSn+1y
"); conv = binary_to_gray (x); binary_print (conv, width); fprintf (htmlfp, ""); conv = binary_to_gray (x); binary_print (conv, width); fprintf (htmlfp, "
q%d"); conv = binary_to_gray (x); if (conv >= table->mt_inputs) indif_print (swidth); else fprintf (htmlfp, "q%d", class_representant (table, table->mt_transitions[conv].vt_states[i]) + table->mt_index_offset); fprintf (htmlfp, "%d-%d

"); free (states_marked); } char flipflop_j_get_transition (int a, int b) { if (a == 0 && b == 0) return '0'; if (a == 0 && b == 1) return '1'; return '-'; } char flipflop_k_get_transition (int a, int b) { if (a == 1 && b == 1) return '0'; if (a == 1 && b == 0) return '1'; return '-'; } void sort_classes (unger_transition_table_t *table) { int i; int j; int max; unger_equiv_class_t temp; for (i = table->mt_class_count - 1; i >= 0; i--) { max = i; for (j = i; j >= 0; j--) if (class_representant (table, table->mt_classes[max].ec_states[0]) < class_representant (table, table->mt_classes[j].ec_states[0])) max = j; temp = table->mt_classes[i]; table->mt_classes[i] = table->mt_classes[max]; table->mt_classes[max] = temp; } } void print_jk_flipflop (unger_transition_table_t *table) { int x, i, n; int conv, iconv; int width, swidth; int state; int prev, next; width = need_bits (table->mt_inputs); swidth = need_bits (table->mt_class_count); /* Lo primero será codificar los estados */ for (i = 0; i < table->mt_class_count; i++) table->mt_classes[i].ec_code = binary_to_gray (i); fprintf (htmlfp, "Valores de entrada de los biestables:
"); fprintf (htmlfp, ""); for (n = swidth - 1; n >= 0; n--) fprintf (htmlfp, "", BINARYCOMB (width), n, BINARYCOMB (width), n); fprintf (htmlfp, "\n"); fprintf (htmlfp, ""); /* Con esto pintamos todas las posibles combinaciones de entrada */ for (n = 0; n < swidth * 2 + 1; n++) for (i = 0; i < BINARYCOMB (width); i++) { conv = binary_to_gray (i); fprintf (htmlfp, ""); } fprintf (htmlfp, "\n"); for (i = 0; i < table->mt_class_count; i++) { state = class_representant (table, table->mt_classes[i].ec_states[0]); /* Obtenemos el representante */ conv = table->mt_classes[i].ec_code; fprintf (htmlfp, ""); fprintf (htmlfp, "", state + table->mt_index_offset); fprintf (htmlfp, ""); for (x = 0; x < BINARYCOMB (width); x++) { /* Ahora por todas las posibles combinaciones de entrada */ /* En state: Tengo el estado que estoy mirando */ fprintf (htmlfp, ""); } /* Ahora, vamos con los valores de entrada de los biestables */ /* Tenemos exactamente swidth biestables */ for (n = swidth - 1; n >= 0; n--) { /* Estamos en el biestable n */ /* Primero, vamos con las J's */ /* Este estado es codificado como... conv */ conv = binary_to_gray (i); /* Ahora, recorremos todas las entradas posibles */ for (x = 0; x < BINARYCOMB (width); x++) { /* Esta entrada la pasamos a código Gray para poder simplificar a ojo */ iconv = binary_to_gray (x); if (iconv >= table->mt_inputs) { fprintf (htmlfp, ""); continue; } /* El estado previo depende de los estados de los biestables */ prev = conv & (1 << n) ? 1 : 0; next = binary_to_gray (get_equiv_class (table, table->mt_transitions[iconv].vt_states[state])) & (1 << n) ? 1 : 0; fprintf (htmlfp, "", flipflop_j_get_transition (prev, next)); } for (x = 0; x < BINARYCOMB (width); x++) { /* Esta entrada la pasamos a código Gray para poder simplificar a ojo */ iconv = binary_to_gray (x); if (iconv >= table->mt_inputs) { fprintf (htmlfp, ""); continue; } /* El estado previo depende de los estados de los biestables */ prev = conv & (1 << n) ? 1 : 0; next = binary_to_gray (get_equiv_class (table, table->mt_transitions[iconv].vt_states[state])) & (1 << n) ? 1 : 0; fprintf (htmlfp, "", flipflop_k_get_transition (prev, next)); } } fprintf (htmlfp, "\n"); } fprintf (htmlfp, "
Sn"); for (i = swidth - 1; i >= 0; i--) fprintf (htmlfp, "Q%dn", i); fprintf (htmlfp, "", BINARYCOMB (width)); for (i = swidth - 1; i >= 0; i--) fprintf (htmlfp, "Q%dn+1", i); fprintf (htmlfp, "J%dK%d
x = "); binary_print (conv, width); fprintf (htmlfp, "
q%d"); binary_print (conv, swidth); fprintf (htmlfp, ""); conv = binary_to_gray (x); /* Transformo la entrada a código Gray */ if (conv >= table->mt_inputs) indif_print (swidth); else binary_print (binary_to_gray (get_equiv_class (table, table->mt_transitions[conv].vt_states[state])), swidth); fprintf (htmlfp, "X%cX%c

\n"); } void header (unger_transition_table_t *table) { fprintf (htmlfp, "\n"); fprintf (htmlfp, "Tablas de Unger\n"); fprintf (htmlfp, "\n"); fprintf (htmlfp, "\n"); fprintf (htmlfp, ""); fprintf (htmlfp, "

Minimización de autómatas - tablas de Unger

\n"); fprintf (htmlfp, "
\n"); fprintf (htmlfp, "A continuación se describen los pasos realizados para minimizar un autómata tipo %s de %d entradas y %d estados. Los estados se numeran a partir del %d
\n", table->mt_type == A_MOORE ? "Moore" : "Mealy", table->mt_inputs, table->mt_states, table->mt_index_offset); fprintf (htmlfp, "

\n"); } void footer () { fprintf (htmlfp, "\n\n"); } void html_solve (unger_transition_table_t *table) { int n; header (table); print_transition_table (table); mark_1_noneq (table); fprintf (htmlfp, "Tachados los 1-no equivalentes:\n
"); print_implication_table (table); n = 1; while (mark_n_noneq (table, n++)) { fprintf (htmlfp, "Tachados los %d-no equivalentes:\n
", n); print_implication_table (table); } solve_equiv_table (table); fprintf (htmlfp, "\nLas anteriores clases de equivalencia nos permiten deducir la siguiente tabla simplificada:
\n"); sort_classes (table); print_transition_table (table); print_jk_flipflop (table); footer (table); } int input_num () { int r; char buf [256]; do { if (fgets (buf, 256, stdin) == NULL) exit (0); } while (!sscanf (buf, "%i", &r)); return r; } void print_moore () { printf ("AUTÓMATA DE MOORE\n\n"); printf (" .----.\n"); printf ("X ---->| F1 |\n"); printf (" A '----'\n"); printf (" | |\n"); printf (" | |\n"); printf (" | V\n"); printf (" | .---.\n"); printf (" '---| S |\n"); printf (" '---'\n"); printf (" |\n"); printf (" |\n"); printf (" V\n"); printf (" .----.\n"); printf (" | F2 |--> Y\n"); printf (" '----'\n"); } void print_mealy () { printf ("AUTÓMATA DE MEALY\n\n"); printf (" .----.\n"); printf ("X +---->| F1 |\n"); printf (" | A '----'\n"); printf (" | | |\n"); printf (" | | |\n"); printf (" | | V\n"); printf (" | | .---.\n"); printf (" | '---| S |\n"); printf (" | '---'\n"); printf (" | |\n"); printf (" | |\n"); printf (" | V\n"); printf (" | .----.\n"); printf (" '---->| F2 |--> Y\n"); printf (" '----'\n"); } int main () { int type; int states; int inputs; int i, j; int error; int *vect; char spit; unger_transition_table_t *table; htmlfp = stdout; printf ("Programa de simplificación de autómatas tipo Mealy/Moore.\n"); printf ("----------------------------------------------------------------\n"); printf ("Este programa generará el resultado en formato HTML (página web)\n"); printf ("por lo que precisará de un navegador web para poder visualizarlo\n"); printf ("correctamente, como Mozilla Firefox, Opera o Internet Explorer.\n\n"); printf ("NOTA: el programa supondrá que las entradas van de 0 a n-1 en codificación binaria y que todas las entradas son posibles.\n"); printf ("¿Qué tipo de autómata quiere minimizar? (introduzca 0 o 1)\n"); printf (" 0: Mealy\n"); printf (" 1: Moore\n"); do { printf ("Tipo: "); type = input_num (); if (type != 0 && type != 1) { printf ("Tipo incorrecto. Debe elegir entre 0 o 1.\n"); continue; } } while (0); if (type == 0) print_mealy (); else print_moore (); do { printf ("\nNúmero de entradas que acepta este autómata: "); inputs = input_num (); if (inputs < 1) { printf ("Valor incorrecto. Debe haber al menos una entrada.\n"); continue; } } while (0); do { printf ("\nNúmero de estados internos del autómata: "); states = input_num (); if (inputs < 2) { printf ("Valor incorrecto. Debe haber al menos dos estados para que el sistema sea secuencial.\n"); continue; } } while (0); table = unger_transition_table_new (type, inputs, states); do { printf ("\n¿A partir de qué estado empiezo a numerar? (lo normal es 0): "); table->mt_index_offset = input_num (); } while (0); printf ("\nA continuación se procede a introducir las transiciones en función de las entradas.\n"); printf ("Por cada entrada debe introducir las transiciones de estados en el orden natural.\n"); printf ("Es decir, el primer número es la transición de q%d, el segundo a la de q%d, etc...\n", table->mt_index_offset, table->mt_index_offset + 1); printf ("En cada línea se deben introducir un total de %d números.\n", states); vect = xmalloc (sizeof (int) * inputs); for (i = 0; i < inputs; i++) { do { printf ("Transición para entrada %d (x = ", i); binary_print (i, need_bits (inputs)); printf ("): "); error = 0; for (j = 0; j < states; j++) { if (!scanf ("%i", &vect[j])) { printf ("Transición de q%d incorrecta.\n", j + table->mt_index_offset); error++; } vect[j] -= table->mt_index_offset; if (vect[j] < 0 || vect[j] >= states) { printf ("La transición de q%d apunta a un estado fuera de rango.\n", j); error++; } } if (error) { printf ("Parece que hubo un error en la lectura. Por favor, vuelva a intentarlo.\n"); continue; } unger_transition_table_set_vector (table, i, vect); } while (0); } printf ("\nA continuación se procede a introducir los valores binarios de las salidas.\n"); printf ("El orden y cantidad de salidas es en el mismo que en el caso anterior.\n\n"); vect = xmalloc (sizeof (int) * inputs); for (i = 0; i < inputs; i++) { do { printf ("Salida"); if (type == A_MOORE) /* Una única salida, asociada a los estados */ printf (": "); else { printf (" asociada a la entrada %d (x = ", i); binary_print (i, need_bits (inputs)); printf ("): "); } error = 0; for (j = 0; j < states; j++) { if (!scanf ("%i", &vect[j])) { printf ("Salida q%d incorrecta.\n", j + table->mt_index_offset); error++; } } if (error) { printf ("Parece que hubo un error en la lectura. Por favor, vuelva a intentarlo.\n"); continue; } unger_transition_table_set_output (table, i, vect); } while (0); if (type == A_MOORE) /* Si es Moore, ya hemos acabado */ break; } printf ("Datos recogidos correctamente. Ahora se generará un fichero \"" OUTPUT_FILENAME "\" con los resultados de la salida en el mismo directorio que ejecutó el programa.\n"); htmlfp = fopen (OUTPUT_FILENAME, "w"); if (htmlfp == NULL) { perror ("Se produjo un error abriendo el fichero.\n"); printf ("¿Desea volcar el código HTML directamente a la consola? [s/N]: "); spit = getchar (); if (spit != 's' && spit != 'S') { fprintf (stderr, " *** Minimización abortada a petición del usuario.\n"); exit (1); } htmlfp = stdout; printf ("\n\n"); } html_solve (table); printf ("\n\nHecho.\n"); return 0; }