Il problema di verificare se un linguaggio regolare e' un codice, e' un caso speciale di una ben nota questione della teoria degli automi, ovvero il problema di testare se una data espressione regolare e' non ambigua. Sul concetto di non ambiguita' e' basato un algoritmo che decide l'univoca decifrabilita' dei linguaggi regolari, quando questi sono rappresentati da automi non ambigui. Si tratta di automi in cui non esistono due cammini distinti, che iniziano e finiscono negli stessi stati e che definiscono la stessa parola. Parliamo dell'algoritmo di Berstel e Perrin, che definisce un automa universale, l'automa flower, dal quale e' possibile decidere se il linguaggio definito dall'automa iniziale e' un codice. Head e Weber (1993) e McCloskey (1996) mettono in evidenza il fatto che l'algoritmo basato sull'automa flower esclude dagli input gli automi ambigui, i quali definiscono, anch'essi, linguaggi regolari e quindi andrebbero considerati. In particolare, se si volesse trasformare un automa ambiguo in non ambiguo questo comporterebbe un incremento esponenziale nel numero degli stati. Per tale motivo Head e Weber hanno disegnato un algoritmo efficiente che decide l'univoca decifrabilita' dei regolari verificando la single-valuedness dei transducers.
L'algoritmo di McCloskey, oggetto del nostro lavoro, si concentra sullo stesso obiettivo, ossia di eliminare l'inefficienza dovuta al passaggio da ambiguo a non ambiguo, e si basa sul test di Sardinas e Patterson, ma fornendo una generalizzazione del test ai linguaggi regolari.
L'algoritmo riceve in input un automa a stati finiti non deterministico con epsilon-transizioni (eventualmente ambiguo) e si compone fondamentalmente di quattro passi. Il primo passo consiste nel verificare se la parola vuota (epsilon), appartiene al linguaggio definito dall'automa in input. Questo viene realizzato attraverso una visita in profondita' del grafo che rappresenta l'automa, visitando solo gli archi etichettati con epsilon. Il secondo passo, consiste nella costruzione di un automa ristretto, ovvero un automa con un solo stato iniziale, un solo stato finale e tale che lo stato finale non ha trasizioni in entrata etichettata con epsilon, e nessuna transizione in uscita di qualsiasi tipo. L'algoritmo e' incentrato sul concetto di automa ristretto, ma l'autore non ha fornito un metodo sulla sua costruzione. Per tale motivo, il nostro lavoro e' consistito, anche, nel fornire un procedimento per la costruzione dell'automa e nel dimostrare l'equivalenza tra epsilon-NFA e automa ristretto. Il terzo passo prevede la costruzione di una variante della definizione del prodotto di un automa, sull'automa ristretto costruito al passo precedente. Infine l'ultimo passo consiste nell'individuazione di un cammino, nell'automa costruito al passo precedente, che dallo stato iniziale [q0, q0] porti allo stato finale [f, f] passando per almeno uno stato semi-finale, ovvero uno stato [s, f] o [f, s] con s diverso da f. L'esistenza di questo cammino permette di stabilire che il linguaggio definito dall'automa iniziale non e' univocamente decifrabile. L'ultimo passo viene realizzato effettuando due visite in profondita'. La prima realizzata sull'automa del passo precedente, consiste nel creare un insieme di stati semi-finali raggiungibili dallo stato iniziale. La seconda effettuata sull'automa con le transizioni invertite per creare un insieme di stati semi-finali raggiungibili dallo stato finale. Se l'intersezione tra i due insiemi e' vuota, il linguaggio e' un codice altrimenti non lo e'.
Si dimostra che l'algoritmo e' efficiente e richiede tempo O(n^2), anche in questa versione corretta. Per verificare, dal punto di vista pratico, la realizzabilita' di tale algoritmo nella sua complessita' computazionale e' stato realizzato un progetto in Java 6 che ha seguito le linee guida di tale algoritmo. A completamento del progetto si e' prodotto un'interfaccia grafica che consente all'utente di disegnare un automa o inserire un'espressione regolare attraverso l'ausilio delle interfacce grafiche di JFlap, e di visualizzare l'esito dell'esecuzione dell'algoritmo sull'input definito dall'utente stesso.