Konečný automat je rozpoznávací funkcí, která určí, zda-li zadaný vstup patří do daného regulárního jazyka (výstup: true, false). Občas je ale zapotřebí navíc získat určitý komplexní výstup, který není binární (např. překlad vstupního řetězce nebo výpočet na jeho základě). Proto je zapotřebí konečný automat obohatit na přechodových hranách o funkce, které se při průchodu automatem provedou. Tímto způsobem vznikne konečný překladový automat.
Příklad
Vytvořte konečný překladový automat přijímající řetězce reprezentující decimální (19875), hexadecimální (0x1FA570) a oktalová (01764) čísla, vracející jejich decimální hodnotu.
Popis
Začínáme v uzlu S (start), pokud nám přijde číslo 1-9, pak se jedná o desítkové číslo a přejdeme do stavu D, při přechodu provedeme akci, která nám dané číslo uloží do paměti (A1). V uzlu D zpracováváme přicházející číslo (A1), dokud nám přichází vstup. Uzel D je koncový.
Pokud nám ovšem v uzlu S přijde nula, tak nevíme, jestli se jedná o hexadecimální nebo oktalové číslo, to se dozvíme až podle dalšího vstupu. Každopádně 0 je korektní číslo, proto je uzel H/O koncový.
Když přijde za nulou nějaké číslo, tak je zřejmé, že se jedná o oktalové číslo, které budeme převádět akcí A2, pokud přijde x, tak se jedná o hexadecimální číslo, zpracovávané akcí A3. U hexadecimálního čísla musíme ještě projít právě přes uzel x, který není koncový, protože číslo 0x není v korektním formátu.
Kód
/** * konecny prekladovy automat * @author Pavel Micka */ public class TranslationFiniteStateMachine { /** * index, na kterem se pri prekladu nachazime */ private int index = 0; /** * prekladany retezec */ private String s; /** * hodnota, kterou to vrati */ private int hodnota = 0; public TranslationFiniteStateMachine(String s) { this.s = s; } /** * prelozi vstup automatu ve tvaru * 124689 - decimalni cislo * 02345 - oktalove cislo * 0x56AF5 - hexadecimalni cislo * na decimalni cislo * @return decimalni reprezentace */ public int translate() { final String ERROR = "spatny vstup"; final String EMPTY = "spatny vstup / retezec je prazdny"; char in = readNext(); if (in >= '1' && in <= '9') { //cislice, nezacina nulou, pujde o dekadicke cislo do { hodnota = hodnota * 10 + (in - 48); //48 == znak 0 v ascii, akce A1 } while ((in = readNext()) != 0 && in - 48 >= 0 && in - 48 <= 9); //dokud nejsme na konci vstupu //nebo neprisel nesmysl if (in == 0) { return hodnota; } else { throw new IllegalArgumentException(ERROR + " " + in); } } else if (in == '0') {//oct or hexa in = readNext(); if (in == 'x') { //hexa boolean readed = false; //jesli byl uz precten alespon jeden //znak samotneho cisla - 0x nebereme while (((in = readNext()) != 0) && (in >= '0' && in <= '9') || (in >= 'A' && in <= 'F')) { readed = true; if (in >= '0' && in <= '9') { //cislo hodnota = hodnota * 16 + (in - 48); //48 == znak 0 v ascii, akce A3 } else { //cislo nad 9...cili A - F hodnota = hodnota * 16 + (in - 65 + 10); //65 == znak A v ascii, +10 protoze A == 10 v hexa } } //dokud nejsme na konci vstupu //nebo neprisla blbost if (in == 0 && readed) { return hodnota; } else { throw new IllegalArgumentException(ERROR + " " + in); } } else if (in >= '0' && in <= '7') {//octa do { hodnota = hodnota * 8 + (in - 48); //48 == znak 0 v ascii, akce A2 } while ((in = readNext()) != 0 && in >= '0' && in <= '7'); //dokud nejsme na konci vstupu //nebo neprisel nesmysl if (in == 0) { return hodnota; } else { throw new IllegalArgumentException(ERROR + " " + in); } } else if(in == 0){ //na vstupu byla jenom nula, ted uz tam nic neni return 0; } } else if (in == 0) { throw new IllegalArgumentException(EMPTY); } throw new IllegalArgumentException(ERROR + " " + in); } /** * vrati dalsi znak na vstupu * @return znak na vstupu nebo 0 v pripade konce retezce */ private char readNext() { if (index >= s.length()) { return 0; } char ret = s.charAt(index); index++; return ret; } }