MÄLARDALENS HÖGSKOLA CD5560 Formella språk, automater och beräkningsteori Användarmanual för simulatorn JFLAP
Innehållsförteckning Att komma igång med JFLAP... 3 Att köra en sträng... 5 Att köra flera strängar... 7 Att skapa en ny automat... 8 Att återkomma till Editorn... 8 Att skapa en deterministiskt finit automat... 8 Att skapa och köra en ickedeterministiskt finit automat...8 Att jämföra två finita automater... 11 Att omvandla NFA till DFA... 11 Att omvandla NFA till grammatik... 13 Att omvandla NFA till RE... 13 Att omvandla RE till NFA... 15 Att skapa och köra en pushdown-automat... 16 Att skapa en ickedeterministisk pushdown-automat... 17 Att omvandla en grammatik till FA och PDA...19 Att skapa och köra en turingmaskin... 21 Att göra ett L-system... 23 2
Att komma igång med JFLAP Då man startar simulatorn JFLAP får man följande alternativ att välja emellan. Väljer man att göra en Finit Automat (FA), en Pushdown-automat (PDA), en Turingmaskin (TM) eller en multi-tape Turingmaskin får man upp följande editor. Om man däremot väljer att göra en grammatik får man upp en annan editor (se figur nedan). Detta medför också att innehållet i Input-, Test- och Convert-menyerna förändras beroende på vilka funktioner som för tillfället finns tillgängliga. 3
Editorn avsedd för att göra automater är försedd med fyra operationer (se nästa figur): Attribute Editor används för att flytta på olika tillstånd och för att ange start- och sluttillstånd. Snabbkommandot är a. State Creator används för att skapa nya tillstånd. Snabbkommandot är s. Transition Creator används för att skapa tillståndsövergångar. Snabbkommandot är t. Deleter används för att ta bort saker. Snabbkommandot är d. a s t d Genom att markera State Creator eller att trycka på s (snabbkommandot för State Creator) kan man placera ut ett antal tillstånd i arbetsytan som visas i nästa figur. Tillstånden namnges automatiskt, men det går att namnge dem på annat sätt genom att högerklicka och välja Label. För att kunna skapa övergångar mellan de olika tillstånden markerar man Transition Creator eller trycker på t och drar sedan muspekaren mellan de två aktuella tillstånden. Därefter får man möjlighet att fylla i vilken symbol man ska läsa av. Operationen avslutas med att antingen trycka enter eller trycka utanför automaten med musknappen. Väljer man inte någon symbol blir övergångssymbolen automatiskt λ, dvs den tomma strängen. I figuren ovan skapar vi en tillståndsövergång med tecknet b mellan q0 och q1. Utöver detta vill ha en loop i tillstånd q0. Detta görs genom att först klicka i det aktuella 4
tillståndet och därefter fylla i ett a. Operationen avslutas antingen med att vi trycker enter eller genom att trycka utanför automaten med musknappen. Genom att trycka på a och högerklicka på ett tillstånd kan man ställa in om det ska vara starttillstånd eller sluttillstånd. Vill man ha flera övergångar mellan två tillstånd får man dra flera övergångspilar där emellan, en för varje symbol. Du har nu lärt dig hur man använder JFLAP för att bygga upp en finit automat. Skapandet av pushdown-automater och turingmaskiner skiljer sig inte markant från detta. Den enda skillnaden är vad som ska anges i tillståndsövergångarna för respektive automat. Att köra en sträng Vi fortsätter med att jobba med samma automat som vi skapade i föregående stycke. Under input-menyn (se nästa figur) finns fyra funktioner att välja. Till exempel kan vi testa att steppa genom tillstånden genom att välja Step by State. 5
Om man väljer ett av de tre första alternativen får man fylla i en inputsträng. (Vi kommer att titta närmare på Multiple Run under stycket med Att köra med flera strängar.) Efter det att man tryckt på OK dyker följande fönster upp. I nederdelen av fönstret ser man i konfigurationsrutan vilket tillstånd man befinner sig i och hur många tecken som har konsumerats (se bild nedan). Konfigurationsruta 6
Stega vidare i strängen genom att trycka på Step. Här nedan har hela strängen konsumerats, vilket man kan se genom att de svarta tecknen i strängen nu har blivit grå. Om strängen dessutom godkänns blir konfigurationsrutan grön. Om man markerar konfigurationsrutan i nedre delen av fönstret (genom att klicka på den) kan man välja Trace och få då fram följande fönster där man kan se vilka tillstånd som har besökts. Vi kommer också att behandla de övriga funktionerna under stycket med Att skapa och köra en ickedeterministiskt finit automat. Att köra flera strängar Om man under inputmenyn väljer Multiple Run får man möjlighet att testa flera strängar samtidigt. För att se om strängarna är accepterade eller inte, klickar man på Run Inputs. Man kan även välja View Trace för att få se hur en viss sträng konsumerats och varför resultatet blev som det blev. 7
Att skapa en ny automat Antingen startar man JFLAP och väljer den typ av automat man vill skapa eller om man redan har JFLAP igång och vill skapa en annan automat ska man då välja File > New. Följande fönster dyker då upp på nytt. Att återkomma till Editorn Så fort man kör någon funktion ur Input-, Test- eller Convert-menyn blir Editorn släckt. För att komma tillbaka till den gör man följande: File>Dismiss Tab, vilket också innebär att man förlorar alla körningar man har framme. Att skapa en deterministiskt finit automat Under stycket med Att komma igång med JFLAP visar vi ett exempel på skapandet av en deterministiskt finit automat. Att skapa och köra en ickedeterministiskt finit automat Om du har glömt hur man skapar en finit automat kan du läsa under stycket Att komma igång med JFLAP. Här visas en körning av en ickedeterministisk sådan. 8
Automaten har ritats upp (enligt bild ovan) och vi börjar steppa igenom tillstånden med inputsträngen a. Eftersom första övergången är en λ-övergång finns det två vägar att gå (automaten är ickedeterministisk). Vid första inmatningen kontrolleras både tillstånd q1 och q3. När vi sedan stegar oss vidare, visar det sig att vi inte kommer vidare i tillstånd q3. I tillstånd q2 blir den inmatade strängen däremot godkänd och därför grön. 9
Vi testar även att skicka in strängen bbb i samma automat. Som vi nämnde ovan får vi två vägar att välja mellan. Vi markerar rutan med q1 och trycker Freeze för att enbart stega vidare i q3. För att ta bort frysningen markerar vi konfigurationsrutan och trycker Thaw. 10
Att jämföra två finita automater Under Test-menyn kan man välja att jämföra två automater för att se om de är lika. Man får jämföra den aktuella automaten med någon av de övriga automaterna som är öppna. I Test-menyn finns även funktioner för att markera λ-övergångar samt tillstånd där ickedeterminism råder. Att omvandla NFA till DFA Vi återvänder här till vår ickedeterministiskt finita automat (NFA). Under Convert-menyn finns olika alternativ på vad man kan omvandla sin automat till. Här försöker vi göra vår NFA deterministisk genom att välja Convert> Convert to DFA. Följande fönster dyker då upp. 11
Här har vi omvandlat vår NFA (till vänster) till motsvarande DFA (till höger) genom att klicka Complete. Vi har även snyggat till automaten genom att klicka på Attribute (a) och flyttat om tillstånden på ett mer överskådligt sätt. Om man sedan klickar på Done får man fram den fullständiga automaten i ett nytt fönster. 12
Att omvandla NFA till grammatik Vi fortsätter här med vår NFA och testar att få fram en grammatik som motsvarar denna. Man kan antingen välja Hint för att se varje regel för sig eller att visa hela grammatiken på en gång (Show all). Då man klickar på Export får man fram den färdiga grammatiken i ett nytt fönster (se bild nedan). Härifrån går det att omvandla grammatiken till en PDA eller FA. Att omvandla NFA till RE Här testar vi att göra om vår NFA till motsvarande reguljära uttryck. Simulatorn berättar för oss att vi inte kan ha flera sluttillstånd och ber oss att göra ett nytt. 13
Nedan har vi gjort samma automat fast med ett enda sluttillstånd. Här ritas alla tomma övergångar ut på vägen mot ett reguljärt uttryck. (Du kan be programmet göra detta åt dig genom att trycka Do It). Här får vi fram uttrycket för vår NFA (Genom att trycka Do It). Plustecknet står för (union). 14
Att omvandla RE till NFA Här omvandlar vi ett reguljärt uttryck till en NFA genom att först välja File > New > Regular Expression och skapa ett reguljärt uttryck genom att skriva in aa*+bb*. Därefter väljer vi Convert > Convert to NFA för att få fram följande utseende. Vi delar upp den i mindre delar genom att markera det tredje alternativet enligt nedan och sedan trycka på tillståndsövergången. 15
Använd Do Step för att komplettera övergångar. Denna NFA motsvarar vår ursprungliga. Att skapa och köra en pushdown-automat Här skapas en pushdownautomat (PDA) för språket L = {(,)}. Observera att Z-tecknet motsvarar $-tecknet. I övrigt påminner editorn och funktioner om de för finita automater, förutom att man måste ange tre parametrar, först vilken symbol som ska läsas från inputsträngen, sedan vilket tecken som ska läsas från stacken och till sist vilket tecken som ska läggas på stacken. 16
Genom att välja att testa strängen ((()) (Input Test by State) får man fram nästa bild där man kan se vilka tecken som har konsumerats på input-tapen och vilket tecken som, för ögonblicket, läggs upp på stacken. Att skapa en ickedeterministisk pushdown-automat Här skapas en NPDA. 17
Eftersom det här är en ickedeterministisk automat kommer flera konfigurationer/vägar att öppnas upp samtidigt när en sträng körs genom automaten. Därför blir det lite rörigt om man inte tar frysfunktionen (denna finns beskriven under Att skapa och köra en ickedeterministisk finit automat) till hjälp. När man stegar sig fram (vi har valt Input Step by State med input aa) dyker två möjliga vägar upp. Vi väljer att frysa den första konfigurationen för att kunna koncentrera oss på den andra. Med det alternativet visar det sig att inputsträngen inte accepteras av automaten. Detta gör att vi väljer att låsa upp den första konfigurationen igen för att kontrollera om någon annan väg accepteras (se bild nedan). När vi fortsätter får vi återigen två nya vägar att välja mellan (se bild nedan). Som tidigare låser vi den ena av dem för att lättare kunna följa den andra. Det visar sig då att den andra strängen har tagit en accepterande väg och det räcker med att en väg leder till acceptans för att strängen ska godkännas av automaten. Vi kan också låsa upp den frysta vägen för att se vart den leder, även om detta inte är nödvändigt då vi redan fått fram ett accepterande svar. 18
Att omvandla en grammatik till FA och PDA Starta simulatorn JFLAP om den inte redan är igång. Tryck sedan på Grammar. Vi testar att göra en grammatik som omvandlas till en finit automat och en annan som omvandlas till en pushdown-automat. Vi skriver in följande reguljära grammatik. Här omvandlar vi grammatiken till motsvarande FA genom att välja Convert>Convert Right Linear Grammar to FA och sedan Show All för att få fram den fullständiga automaten (se nästa bild). 19
För att omvandla till en PDA skriver vi in följande sammanhangsfria grammatik. Här omvandlar vi grammatiken till en motsvarande PDA genom att välja Convert>Convert CFG to PDA (LL) och sedan Show All för att få fram den fullständiga automaten. 20
Istället för att välja Show All kan man markera varje regel och välja Create Selected för att göra det steg för steg. Som vi tidigare nämnde kan man välja Export för att öppna ett nytt fönster med den automaten i när man är klar. Att omvandla en grammatik till en parse-tabell Då man har definierat en ny grammatik (i vårt fall E E+T;E T;T 1) kan man göra om denna till en parse-tabell, antingen den långa vägen (Build LL Parse Table eller Build SLR Parse Table) eller den korta (Brute Force Parse). Då man valt Brute Force Parse får man fram följande fönster (se bild nedan). Vi har matat in 1+1+1 som input och stegar oss fram med Start och sedan Step. I bilden ovan visas trädstrukturen för grammatiken, men kan även välja att studera tabellen över samma grammatik. Att skapa och köra en turingmaskin Här skapas en turingmaskin (TM). Observera att -tecknet motsvarar #-tecknet. I övrigt påminner editor och funktioner om dem som fanns för FA och PDA. 21
Om man tidigare har testat köra strängar med FA och/eller PDA är det nu lätt att hänga med. Här testar vi att köra strängen aaa med vår turingmaskin för att se om strängen accepteras av denna (Input Step aaa). Efter det att vi har steppat igenom TM visar det sig att strängen tillhör språket och konfigurationsrutan blir därför grön (se nästa figur). 22
Att göra ett L-system Då man skapar ett L-system får man se till att göra blanksteg mellan de enskilda tecknen för att det ska fungera. Nedan har ett system skapats. Parametrarna i det nedre fältet är extrafunktioner som används bland annat då man vill byta färg från den förvalda svarta. För att köra väljer man Input Rendersystem. Därefter får man öka värdet i högra övre hörnet tills man får ut något vackert. 23