äydentäviä muistiinpanoja jäsennysalgoritmeista Antti-Juhani Kaijanaho 7. helmikuuta 2012 1 simerkki arleyn algoritmin soveltamisesta arkastellaan kielioppia G : + () c ja sovelletaan arleyn algoritmia siihen sekä merkkijonoon c + c c. euraavassa esityksessä on yksi taulukko per i -joukko. aulukon otsikkorivillä kerrotaan, mistä joukosta on kyse, sekä mitä kohtaa merkkijonosta se tarkastelee (jolloin selaus tarkastelee pisteen jälkeistä merkkiä). Kukin taulukko luetteloi (ja numeroi) joukossa olevat asetelmat siinä järjestyksessä, jossa ne on siihen lisätty. Kunkin asetelman kohdalla on kerrottu, miksi se on joukkoon lisätty (sulkeissa olevat numerot viittaavat aiempiin riveihin). Jos sama asetelma tulee lisättäväksi samaan taulukkoon useampaan kertaan, käytetään ensimmäisen lisäyksen riviä merkitsemään myös myöhempien lisäysten syyt. 0 c + c c 1, 0 alustus 2 +, 0 ennustus (1, 2, 3) 3, 0 ennustus (1, 2, 3) 4 (), 0 ennustus (1, 2, 3) 5 c, 0 ennustus (1, 2, 3) IA241 Automaatit ja kieliopit, kevät 2012 1
1 c +c c 1 c, 0 selaus 0 (5) 2, 0 täydennys (1), 0 (1) 3 +, 0 täydennys (1, 2), 0 (2) 4, 0 täydennys (1, 2), 0 (3) 2 c + c c 1 +, 0 selaus 1 (3) 2 +, 2 ennustus (1, 2, 3) 3, 2 ennustus (1, 2, 3) 4 (), 2 ennustus (1, 2, 3) 5 c, 2 ennustus (1, 2, 3) 3 c + c c 1 c, 2 selaus 2 (5) 2 +, 0 täydennys (1), 2 (1) 3 +, 2 täydennys (1), 2 (2) 4, 2 täydennys (1), 2 (3) 5, 0 täydennys (2), 0 (1) 6 +, 0 täydennys (2, 5), 0 (2) 7, 0 täydennys (2, 5), 0 (3) 4 c + c c 1, 2 selaus 3 (4) 2, 0 selaus 3 (7) 3 +, 4 ennustus (1, 2) 4, 4 ennustus (1, 2) 5 (), 4 ennustus (1, 2) 6 c, 4 ennustus (1, 2) 5 c + c c 1 c, 4 selaus 4 (6) 2, 2 täydennys (1), 4 (1) 3, 0 täydennys (1), 4 (2) 4 +, 4 täydennys (1), 4 (3) 5, 4 täydennys (1), 4 (4) 6 +, 0 täydennys (2), 2 (1) 7 +, 2 täydennys (2), 2 (2) 8, 2 täydennys (2), 2 (3) 9, 0 täydennys (3, 6), 0 (1) 10 +, 0 täydennys (3, 6), 0 (2) 11, 0 täydennys (3, 6), 0 (3) 2
Koska (, 0) 5 pätee, julistetaan että c + c c L(G) myös pätee. dellä olevista taulukoista voidaan myös lukea jäsennyspuut. Piirretään ensiksi sellaiset puut, joissa solmuina ovat algoritmin taulukoista löytyvät asetelmat. Asetelmojen väliset suhteet luetaan taulukoista seuraavasti: Asetelma (, 0) on puun juuri. Asetelma A on jonkin toisen asetelman B oikeanpuolimmainen lapsi, jos asetelma B on merkitty johdetuksi täydennyksellä samassa taulukossa olevasta asetelmasta A. Jos asetelmalla on useita oikeanpuolimmaisia lapsia, on kyse tilanteesta, jossa on useita jäsennyspuita. Valitsemalla oikeanpuolimmaisista lapsista jonkin saadaan aikaan jokin jäsennyspuista. Asetelma, joka on johdettu toisesta selauksella taikka täydennyksellä jostakin edellisen taulukon asetelmasta, on sen oikeanpuoleinen sisarus. isarussuhdeketjussa tulee olla kaikilla asetelmilla sama produktio. Jos näin ei ole, algoritmia on sovellettu väärin. isarussuhdeketjun yhteisen produktion oikean puolen kutakin symbolia kohden pitää olla ketjussa asetelma, jossa piste on ko. symbolin kohdalla. Jos näin ei ole, puu on hylättävä epäonnistuneena jäsennysyrityksenä. euraavat ei-hylättävät puut saadaan aikaan. Merkitsen asetelman siten lyhentäen, että laitan varsinaiseksi merkiksi sen merkin, joka tulee asetelmassa ennen pistettä, ja varustan sen ylä- ja alaindekseillä i, j, joissa i kertoo sen taulukon ja j sen rivin, josta asetealma löydettiin puuhun. Yläindeksi viittaa oikeanpuolimmaisella (tai ainoalla) sisaruksella ylenevään polveen ja muilla sisaruuteen oikealle päin. Alaindeksi viittaa suhteeseen oikeanpuolimmaiseen (tai ainoaan) lapseen. iis esimerkiksi 5,6 3,2 kertoo, että kyseisessä asetelmassa pistettä edeltää, että sen vanhempi selviää tarkastelemalla taulukon 5 rivin 6 suhteita ja että sen lapsi selviää tarkastelemalla taulukon 3 rivin 2 suhteita. 3
1,3 1,3 5,9 3,7 5,14 4,2 + 2,1 5,6 3,2 5,3 5,3 c 5,1 3,5 1,3 1,3 + 2,1 3,2 5,6 c 1,1 3,4 3,4 4,1 5,2 5,2 c 1,1 c 3,1 c 3,1 c 5,1 2 nnustava jäsennys Olkoon G = (V, Σ, P, ) CFG. Olkoon lisäksi Σ. Määritelmä 1. Määritellään ominaisuus NULLABL (V Σ) seuraavasti: NULLABL = { ω (V Σ) ω G ε } Merkintä NULLABL(ω) tarkoittaa samaa kuin ω NULLABL. Määritelmä 2. Määritellään kuvaus FIR : (V Σ) Σ, FIR : ω { c Σ ω (V Σ) : ω G cω } Algoritmi 3. FIR ja NULLABL voidaan laskea jokaiselle välikesymbolille seuraavalla algoritmilla: 1. Alusta NULLABL =. 2. Alusta FIR(X) = kaikilla X V. 3. Kunnes NULLABL ja FIR eivät enää muutu, tee: (a) Jos kieliopissa on produktio X ε jollakin X V, tee NULLABL := NULLABL {X}. (b) Jos kieliopissa on produktio X α 1 α n joillakin X V, n Z + ja α 1,..., α n V Σ, tee: i. Aseta i := 1. ii. Jos α i Σ, tee FIR(X) := FIR(X) {α i }. iii. Jos α i V, tee FIR(X) := FIR(X) FIR(α i ). iv. Jos α i V ja α i NULLABL, tee: 4
A. i := i + 1 B. Jos i n, hyppää kohtaan 3(b)ii. C. NULLABL := NULLABL {X}. Algoritmin yleistys välike- ja päätemerkkien jonoille jää harjoitustehtäväksi. Määritelmä 4. Määritellään kuvaus FOLLOW : V (Σ { }), FOLLOW : X { c Σ ω, ω : G ωxcω } { ω : G ωx } Näin c FOLLOW(X) tarkoittaa, että X:n jälkeen voi tulla c. Vastaavasti FOLLOW(X) tarkoittaa sitä, että X voi esiintyä kieleen kuuluvan merkkijonon lopussa. Algoritmi 5. FOLLOW voidaan laskea seuraavalla algoritmilla: 1. Alusta FOLLOW(X) = kaikilla X V {}. 2. Alusta FOLLOW() = { }. 3. Kunnes FOLLOW ei enää muutu, tee: (a) Jos kieliopissa on produktio Y ωxω joillekin X, Y V ja ω, ω (V Σ), tee: i. FOLLOW(X) := FOLLOW(X) FIR(ω ). ii. Jos NULLABL(ω ), tee FOLLOW(X) := FOLLOW(X) FOLLOW(Y ). Algoritmi 6. Rekursiivisesti etenevän jäsennyksen jäsennystaulukko voidaan konstruoida muuttujaan M : V (Σ { }) P(P ) seuraavasti: 1. Alusta M(X, c) = kaikilla X V ja c Σ { }. 2. Kullekin kieliopin produktiolle A ω tee: (a) Kaikille c FIR(ω) tee M(A, c) := M(A, c) {A ω}. (b) Jos NULLABL(ω), niin jokaiselle c FOLLOW(ω) tee M(A, c) := M(A, c) {A ω}. Määritelmä 7. Jos rekursiivisesti etenevän jäsennyksen jäsennystaulukossa M pätee M(X, c) 1 kaikilla X V ja c Σ { }, kielioppi on LL(1) ja jäsennystaulukko on ennustava. arkastellaan nyt esimerkinomaisesti BNF-muotoista kielioppia 5
<statement> ::= if ( <expression> ) <statement> else <statement> return <expression> ; <expression> ::= <term> <expressionprime> <expressionprime ::= + <term> <expressionprime> - <term> <expressionprime> <term> ::= <constant> ( <expression> ) Kyse on lähes samasta kieliopista, johon luentoesimerkki Rdex.java perustuu. Kirjoitetaan se vielä varmuuden vuoksi tutummilla merkintätavoilla: if () else return ; + ε c () Lasketaan ensiksi NULLABL ja FIR algoritmia noudattaen. Alustus jättää taulukon tyhjäksi. NULLABL FIR Produktio if () else : NULLABL FIR if 6
Produktio return ; Produktio + : Produktio : Produktio c: Produktio (): Produktio ε: NULLABL FIR NULLABL FIR + NULLABL NULLABL FIR + FIR + c NULLABL FIR + NULLABL FIR + 7
Produktio : NULLABL FIR c ( + Mikään produktio ei tämän jälkeen aiheuta muutoksia taulukkoon, joten algoritmin suoritus päättyy. Lasketaan vielä FOLLOW. Alustus: NULLABL FIR FOLLOW c ( + Produktiot if () else välikesymbolin suhteen: NULLABL FIR FOLLOW c ( ) + Produktio return ; välikesymbolin suhteen: NULLABL FIR FOLLOW c ( ) ; + Produktio välikesymbolin suhteen: NULLABL FIR FOLLOW c ( ) ; + ) ; 8
Produktio välikesymbolin suhteen: NULLABL FIR FOLLOW c ( ) ; + ) ; + ) ; Produktio if () else välikesymbolin suhteen: NULLABL FIR FOLLOW else c ( ) ; + ) ; + ) ; Jäsennystaulukko on nyt yksinkertainen rakennettava: c + ( ) ; if else return if () else return ; + ε ε c () ämän pohjalta laadittu ennustava jäsennin (tai oikeammin tunnistin) on kurssin luentosivuilla saatavilla tiedostossa LL.java. 9