Tomta-tyylsstä ylestetystä LR-jäsentäjstä Jaakko Korpela Tampereen ylopsto Tetojenkästtelyteteden latos Tetojenkästtelyopp Pro gradu -tutkelma Marraskuu 2004
Tampereen ylopsto Tetojenkästtelyteteden latos Tetojenkästtelyopp Jaakko Korpela: Tomta-tyylsstä ylestetystä LR-jäsentäjstä Pro gradu -tutkelma, 92 svua Marraskuu 2004 Jäsentäjä on ohjelma, joka analyso syötteenä annetun merkkjonon kelopllsen rakenteen. Jäsentäjän tehtävänä on määrttää, kunka kelopsta vodaan johtaa annettu syöte. Jos syötemerkkjono kuuluu kelopn määräämään keleen, jäsentäjä tulostaa sen jäsennyksen, muussa tapauksessa jäsentäjä lmottaa vrheestä. LR-jäsentämnen on käytännössä suosttu jäsennysmenetelmä, jota on menestyksellsest käytetty ohjelmontkelten kääntäjssä jo yl kolmenkymmenen vuoden ajan. Menetelmänä se on lmasuvomanen, tehokas ja sop automaattslle jäsentäjägeneraattorelle. LR-kelopn määrttämnen halutulle kelelle vo kutenkn olla hankalaa. Ylestetyn LR-jäsentämsen tarkotuksena on laajentaa LR-jäsentäjä tommaan kaklla kontekstttomlla kelopella. Lang ratkas ensmmäsenä ylesen ylesen jäsennysongelman teoreettsest ja Tomta kehtt myöhemmn tehokkaan käytännöllsen ratkasun. Alkuperänen Tomtan algortm e kutenkaan pysähdy kästellessään keloppa, joka ssältää epäsuoran vasemman rekurson. Tässä tutkelmassa perehdytään ylesest Tomtan kehttämään ylestettyyn LR-jäsentämseen. Työssä estetään myös sekä Farshn että Scottn ja muden jäsennysalgortmt, jotka perustuvat Tomtan algortmehn, mutta tomvat oken kaklla kontekstttomlla kelopella. Tutkelmassa analysodaan myös alkuperäsessä Tomtan algortmssa oleva ongelma ja estetään algortmn korjauksa perusteluneen. Avansanat ja -sanonnat: ylestetty kontekstton jäsentämnen, Tomtajäsentäjät.
Ssällys. Johdanto... 2. Merkntöjä ja termejä...3 3. Ylestettyjen LR-jäsentäjen kehtys...5 4. LR-jäsentäjä...8 4.. Johdanto...8 4.2. LR()-jäsentäjän muodostamnen...9 4.3. Alkojoukkojen muodostamnen LR()-jäsentäjälle...0 4.4. LR()-jäsennystaulun muodostamnen... 5. GLR-jäsennysalgortmsta ylesest...4 5.. Graafrakentenen pno (GSS)...5 5.2. GSS:n rakentamnen syötteestä...7 5.3. Tyhjen sääntöjen kästtelemnen...22 6. Tomtan algortm e...25 6.. Esmerkk epäsuorasta vasemmasta rekursosta...29 6.2. Esmerkk epäsuorasta okeasta rekursosta...34 6.3. Tomtan algortm 2...37 7. Farshn algortm...39 8. RNGLR-algortm...43 8.. Epäsuora okea rekurso ja okeanpuolesest tyhjentyvät säännöt...43 8.2. GLR-jäsentämnen muunnellulla DFA:lla...45 8.3. Esmerkk RNGLR-algortmn tomnnasta...47 9. Tomtan algortm 2...5 9.. Tomtan algortm 2 tyhjä sääntöjä ssältävlle kelopelle...5 9.2. Tomtan algortm 2 ja epäsuora vasen rekurso...54 0. Muunneltu Tomtan algortm 2...62 0.. Muunneltu Tomtan algortm 2a...62 0.2. Muunneltu Tomtan algortm 2a ja epäsuora vasen rekurso...64 0.3. Muunneltu Tomtan algortm 2a ja syklnen kelopp...68 0.4. Muunneltu Tomtan algortm 2b...72 0.5. Esmerkk muunnellusta Tomtan algortmlla 2b...74 0.6. Muunneltu Tomtan algortm 2b ja epäsuora okea rekurso...75 0.7. Muunneltu Tomtan algortm 2c...77 0.8. Muunneltu Tomtan algortm 2c ja epäsuora okea rekurso...80. Muunnellun Tomtan algortmn 2 omnasuukssta...82.. Muunneltu Tomtan algortm 2c pysähtyy ana...82
.2. Muunneltu Tomtan algortm 2c on rajottamaton suuruusluokaltaan 88 2. Yhteenveto...92 Vteluettelo... 93
. Johdanto Huomattava tulos determnststen jäsentäjäalgortmen alalla neljäkymmentä vuotta stten ol se, että kelet, jotka ovat lähes determnstsä, votn tehokkaast jäsentää käyttäen senakasa, tehokkuudeltaan suhteellsen penn konesn mahtuva jäsentäjä [JSE04]. Automaattsen jäsentämsen käytäntö onkn muuttunut suhteellsen vähän 970-luvun alkupuolelta lähten, jollon julkastn useta LALR()- ja LL()-jäsentäjägeneraattoreta [MN04]. Suurn ongelma LALR()-jäsentäjägeneraattoreta käytettäessä on se, että sopvan kelopn muodostamnen annetulle keloplle on työlästä. LALR()- jäsentäjä on determnstnen, sllä jokasella tomnta-askeleella on päätettävä käyttäen pnon pnnalla olevaa tlaa ja seuraavaa syötemerkkä, srretäänkö syötteestä seuraava syötemerkk pnoon va valtaanko yks kelopn säännöstä sovellettavaks redusonnks pnossa [ASU86]. Jäsennyskonflkten ratkasemnen vaat algortmn syvällstä ymmärtämstä, ekä se sllonkaan ole helppoa [MN04]. Kaklla kontekstttomlla kelllä e ole LALR()-keloppa. Vakka kelopp votasnkn muuttaa LALR()-kelopks, prosess vo olla työläs, ja se vo tuhota kelopn kästteellsen rakenteen. Sen sjaan että kuvattasn kel, jota jäsennetään, päädytään kuvaamaan prosess, jolla jäsennys tehdään. Koska kelopp on tärken osa jäsennysmäärttelyä, tämä e ole tovottavaa. Lsäks on huomattava, että sllon, kun kelen rakenne e ole jäsentäjän krjottajan hallnnassa, e voda olettaa kelen omaavan determnststä keloppa. Luonnollsten kelten jäsentämsessä (natural language parsng, NLP) kelet ovat yleensä epädetermnstsä ja monselttesä. Nnpä luonnollsen kelen jäsentäjän on löydettävä jäsennys mahdollsest äärettömästä joukosta [JSE04]. Pääasallnen vahtoehto tastelussa srrä/redoso-konflkten kanssa on ollut hylätä automaattnen jäsennysteknologa kokonaan. Kokemus on kutenkn osottanut, että jäsentäjän krjottamnen käsn on työlästä ja lopputulosta on vakeata muuttaa ssältämään laajennuksa [MN04]. Tonen vahtoehto jäsennyskonflkten ratkasemseks LR-jäsentämsessä on smuloda epädetermnstsyyttä determnstsellä koneella, jollon jäsennysohjelma suorttaa kakk eteentulevat jäsennystomnnot. Tehokkaampen jäsentäjägeneraatoren kehtystä ja käyttöönottoa on osaltaan edstänyt valtava kehtys prosessoreden tehokkuudessa sekä, ehkä tärkeämpänä asana, käytettävän mustn määrässä [JSE04]. 970-luvun alussa kun LALR- ja LL-jäsentäjägeneraatoreta kehtettn, mustn koko ol
2 tyypllsest 0 4 tavun luokkaa, kun tyypllsessä käyttökoneessa mustn määrä on nykyään 0 9 tavun luokkaa. Tämän tutkelman ssältö on seuraava. Luvussa 2 estellään aheeseen lttyvä merkntöjä ja termejä. Luvussa 3 paneudutaan lyhyest ylestettyjen LR-jäsentäjen kehtykseen estellen sen merkttävmmät kehtysvaheet. Luvussa 4 kästellään normaala LR-jäsentäjää. Luvussa 5 kästellään ykstyskohtn paneutumatta ylestetyn LR-jäsentämsen peraatteet esmerkken kautta. Luvussa 6 annetaan formaal kuvaus luvun 5 menetelmstä ja todetaan, ette se kakssa tapauksssa pysty tunnstamaan syöttetä. Luvussa 6 estetään myös lyhyest esmerkn kautta Tomtan algortm kontekstttomlle kelopelle ja estään shen lttyvät ongelmat. Luvussa 7 estellään Farshn jäsennysalgortm ja luvussa 8 Scottn ja muden jäsennysalgortm. Luvussa 9 palataan Tomtan kontekstttomen keloppen jäsennysalgortmn ja annetaan sen formaal kuvaus. Samassa luvussa analysodaan myös tarkemmn algortmn lttyvä ongelma. Luvussa 0 tuodaan eslle korjauksa Tomtan algortmn ja luvussa estellään jotakn korjauksn lttyvä todstuksa. Vastaavanlasa korjauksa alkuperäseen Tomtan algortmn e krjallsuudessa ole akasemmn estetty. Kakk tutkelmassa estetyt tulokset ovat krjottajan omaa käsalaa.
3 2. Merkntöjä ja termejä Kontekstton kelopp koostuu joukosta T perusmerkkejä, joukosta N apumerkkejä, merkstä S N, jota sanotaan alkumerkks, ja joukosta kelopn sääntöjä. Säännöt ovat muotoa A ::= α, mssä A N ja α on (mahdollsest tyhjä) perus- ja apumerkestä koostuva merkkjono. Jäsennysaskel (dervaton step) on muotoa γa σ γασ oleva tomnta, mssä γ ja σ ovat perus- ja apumerkestä koostuva merkkjonoja ja A ::= α on kelopn sääntö. Merkkjonon τ jäsennys merkkjonosta σ on sarja jäsennysaskela σ β β 2... β n τ. Jos τ jäsentyy merkkjonosta σ käyttämällä n jäsennysaskelta, vodaan krjottaa myös σ τ ta σ n τ. Jos jäsennyksä tehtäessä korvataan ana vasemmanpuolesn apumerkk, puhutaan vasemmanpuolesmmasta jäsennyksestä (leftmost dervaton) ta vasemmasta johdosta. Vastaavast korvattaessa ana okeanpuolesn apumerkk puhutaan okeanpuolesmmasta jäsennyksestä (ta okeasta johdosta). Vasemmanpuolesnta jäsennystä merktään α β ja okeanpuolesnta jäsennystä merktään α β. op Tyhjästä merkkjonosta käytetään merkntää ε. Kelopn säännön vp A ::= αβ sanotaan olevan okealta tyhjentyvä (rght nullable), jos β ε, mutta β ε. Kelopn sanotaan omaavan epäsuoran vasemman (ta okean) rekurson (hdden left/rght recurson), jos snä on apumerkk A ja sellaset merkkjonot τ ja σ, että τ + ε ja A σaτ (ta A τaσ ). Kelopllnen muoto (sentental form) on sellanen merkkjono α, että S α ja lause on sellanen kelopllnen muoto, joka koostuu van perusmerkestä. Kelopn Γ muodostama kel määrtellään nstä lausesta koostuvaks joukoks L (Γ), jolla on jäsennys kelopn Γ alkumerkstä S. Lausetta, joka on generotu kelopsta käyttäen vasemmanpuolesnta jäsennystä, sanotaan vasemmanpuoleseks kelopllseks muodoks. Okeanpuolesen jäsennykseksen generomaa lausetta sanotaan vastaavast okeanpuoleseks kelopllseks muodoks. Alkuosan αβ okeanpuolesesta kelopllsesta muodosta αβω sanotaan olevan kelopn kelvollnen alkuosa (vable prefx). Kelopn symbollle x ja merkkjonolle γ määrtellään FIRST T (x) = {t T jollekn merkkjonolle β, x tβ, FIRST (ε ) = {ε T
FIRST( xγ ) = FIRST FIRST T T ( x) FIRST T ( x), muuten. 4 ( γ ), jos x ε Äärellnen tla-automaatt (fnte state automaton, FA) on suunnattu graaf, jonka solmuja sanotaan tloks. Yks tla automaatssa on alkutla ja jotkut tlat ovat hyväksymstloja ta lopputloja. Graafn kaara kutsutaan srtymks ja ntä merktään syötesymbolella ta tyhjällä merkkjonolla ε. Äärellsä automaatteja käytetään syötemerkkjonojen hyväksymseen ta hylkäämseen. Äärellnen automaatt hyväksyy syötteen, jos alkutlasta lähten kulkemalla syötemerkkjonon määräämen symboleden osottama srtymä päädytään lopputlaan, kun koko syötemerkkjono on luettu. Muussa tapauksessa automaatt hylkää syötteen. Äärellnen tla-automaatt on determnstnen (determnstc fnte automata, DFA), jos snä e ole tyhjä srtymä, el srtymä, jossa syötesymbola e lueta, ja jos jokaselle kelopn symbollle x jokasesta solmusta on korkentaan yks srtymä symbollla x.
5 3. Ylestettyjen LR-jäsentäjen kehtys Backus-Naurn notaaton (Backus-Naur Form, BNF) kehttämnen ohjelmontkel ALGOL-60 syntaksn kuvaamseks [BBG+63] ol ensmmänen merkttävä askel jäsennysmenetelmen formalsomseks. BNF:n avulla mukaan saatn ltettyä Chomskyn kehttämä kontekstttomen keloppen matemaattnen vtekehys [GR62]. Kuvassa 3. on hahmoteltu ylestetetyn LR-jäsentämsen kehtystä. Knuth [Knu65] formalso kokoavan LR-jäsennysmenetelmän ja osott, että LR-jäsentäjät tomvat lneaarsessa ajassa syötteen ptuuden suhteen. Knuthn työ ssäls suurmman osan teoreettssta tulokssta LRjäsentämsestä, mutta Knuth e tse ptänyt tuloksaan käytännössä sovellettavna. Vakka Knuthn kuvalemat LR-jäsentäjät tomvat lneaarsessa ajassa syötteeseen nähden, nden tlavaatmus on pahmmassa tapauksessa eksponentaalnen kelopn kokoon nähden. LR-jäsentäjän vaatma must käytännössä käytettävllä kelllä (puhumattakaan teoreettssta äärtapaukssta) yltt selväst senakasten koneden kapasteetn. Kuva 3.. Ylestetyn LR-jäsentämsen kehtys [JSE04]. Tlanne muuttu De Remern LALR- [DeR69] ja SLR-algortmen [DeR7] ansosta. Nämä algortmt lovat pohjan Knuthn tulosten käytännöllseen
6 soveltamseen. De Remern algortmt käyttävät samaa jäsennysmalla kun Knuthn algortm, mutta jäsennyksessä käytettäven jäsennystaulujen rakentamseen käytetty menetelmä tuottaa penempä jäsennystauluja, sälyttäen kutenkn suuren osan Knuthn malln lmasuvomasta. Unx-työkalu YACC [Joh75] käyttää LALR-jäsentämsalgortma ja jotakn menetelmä [AJU75] kelopn monselttesyyden purkamseks. YACC muodostu nopeast standard-työkaluks jäsentämsessä. Akateemsemmalla puolella Lang [Lan74] työskentel teoreettsten kysymysten parssa, tutken mahdollsuuksa smuloda epädetermnstsyyttä determnstsllä menetelmllä. Tomta [Tom86] kehtt ylestetyn LR-jäsentäjän (Generalzed LR, GLR) luonnollsten kelten tehokkaaseen jäsentämseen. Tomta huomo, että luonnollsten kelten kelopt ovat enmmäkseen LR-kelopppeja, jossa on jonkn verran monselttesyyttä. Samaa vodaan sanoa monsta ohjelmontkelstä (varsnkn esm. C++), joten Tomtan algortm soveltuu hyvn myös nden jäsentämseen. Vakka e ole varmaa, olko Tomta tetonen Langn tulokssta, Tomtan työtä vodaan ptää näden käytännöllsenä toteutuksena, jossa johdon tallentamseen käytetty tetorakenne on pääasallnen uus tulos. GLR käyttää syvyys-ensn etsntää ylläptäen lstaa kaksta mahdollssta (osttassta) jäsennyksstä nykyseen syötemerkkn ast. LR-jäsentäjässä konfguraato on tallennettuna tlanumeron pnoon. Nnpä tetyn syötteen kakken jäsennysvahtoehtojen läpkäymseks tarvtsee ylläptää useampaa pnoa, yks jokasta yksttästä jäsennystä koht. LR-jäsennysalgortma on muokattu nn, että aktvssta pnosta (epäaktvset pnot ovat sellasa, jossa on päädytty tlanteeseen, jossa jäsennystä e voda jatkaa) suortetaan kakk mahdollset redusonnt, ennen seuraavan syötemerkn srtämstä pnoon. Käytettäessä osotnpohjasta estystapaa pnossa päädytään puurakenteeseen. Tomta havats, että nden arvojen joukko, joka vo esntyä pnon pnnalla, on äärellnen joukko jäsennystloja. Pnon tomnnan kontekstton luonne johtaa shen, että puun oksa vodaan yhdstää, kun nllä on sama lehden arvo [JSE04]. Tomta kutsu tetorakennetta graafrakenteseks pnoks (Graph Structured Stack, GSS). Tomta kuvas vs algortma. Nästä ensmmänen kuvaa aheeseen lttyvä perusdeota ja soveltuu van LR()-kelopelle. Tonen algortm tom sälyttävllä kelopella ja lopussa algortmessa lsätään omnasuuksa tyhjen sääntöjen halltsemseks. Tomtan algortmesta löytyy kutenkn vrhe, sllä ne evät pysähdy kelopella, jotka ssältävät epäsuoran vasemman rekurson. Farshn [NF9] ratkasu ongelmaan ol suorttaa täydellnen etsntä kaklle aktvslle tlolle uusen tlojen etsmseks. Tämä etsntä vo kutenkn olla
7 epäkäytännöllsen paljon akaa vevä. Rekers [Rek92] kehtt Farshn algortma tuottamalla tvmmän jäsennysmetsän. Vsser [Vs97] taas muokkas Farshn algortma tommaan lman selaajaa. Molemmssa algortmessa redusonten etsntä tyhjn sääntöhn lttyen on kutenkn jäljellä. Scottn ja muden [SJH00] kehttämämä RNGLR-algortm ssältää henovarasemman korjauksen Tomtan algortmessa olevaan ongelmaan tyhjn sääntöhn lttyen ja BRNGLR [SJE03] käyttää redusonten suorttamseen bnärsöntä, jollon jäsentäjä tom kuutollsessa ajassa syötteeseen nähden mlle tahansa kontekstttomalle keloplle. Aycockn ja Horspooln [AHJ0] jäsentäjät evät suoranasest lty GLR-jäsentämseen vaan ovat lähnnä saaneet jotakn vakutteta tästä suunnasta.
8 4. LR-jäsentäjä 4.. Johdanto LR-jäsentäjä on kontekstttomen keloppen jäsentäjätyypp, jota ylesest käytetään ohjelmontkelten kääntäjssä. LR-jäsentäjä on kokoava (bottom-up) jäsentäjä, joka lukee syötettään vasemmalta okealle ja pyrk kääntestä okeaa johtoa muodostaen koht kelopn alkumerkkä. LR-jäsentämsellä on lukusa etuja ja se on pääasallnen jäsennysmenetelmä monlle ohjelmontkellle. Kaksta syötettä vasemmalta okealle lukevsta jäsentäjstä LR-jäsentäjä havatsee syntaktset vrheet akasmmassa mahdollsessa vaheessa. LR-jäsentäjä koostuu syötepuskursta, josta syötettä luetaan merkk kerrallaan, lukupäästä, joka lukee ana jotan kohtaa syötteestä, pnosta ja jäsennystaulusta. Jäsennystaulussa on tomnnot jokaselle perusmerklle jokasessa tlassa ja srry-tloja (goto states) apumerkelle. Edellstä osaa taulusta sanotaan tomntatauluks ja jälkmmästä srry-tauluks. Pno koostuu symbol/tla paresta ja aluks pnossa on van tla 0. LR-jäsentäjän tlat koostuvat LR-alkosta (LR-tems). LR-alko on par ([ A ::= α β ], ω ), mssä ω on perusmerkkjono, joka vo koostua perusmerkestä ja syötteen loppua kuvaavasta $-merkstä. LR-alkon osaa [ A ::= α β ] sanotaan ytmeks (core). Par ([ A ::= α β ], ω ) kuvaa jäsentäjän kontekstn. Tällön yrtetään löytää merkkjono, joka jäsentyy kelopssa apumerkstä A, ja jota seuraa merkkjono ω. Merkkjono α on jo pnon pnnalla ja tämän jälkeen jäljellä olevasta syötteestä on löydettävä osa, joka jäsentyy merkkjonosta βω. Jos ω on ana van yhden merkn mttanen, sanotaan stä kurkstusalkoks (lookahead tem). Tällön LR-jäsentäjää sanotaan LR()-jäsentäjäks. Kurkstusalkolla e ole merktystä muotoa [ A :: = α β, a ], mssä β ε, olevssa LR()-alkossa, mutta tlassa, jossa on muotoa [ A :: = α, a ] oleva LR()-alko, suortetaan redusont, jos seuraava syötemerkk on a. Tomntataulu vo ssältää neljä erlasta tomntoa jokaselle tlalle: Syötemerkn srto pnoon ja srtymnen tlaan s Redusont säännön p mukaan Vrhe Syötemerkkjonon hyväksymnen.
9 Algortm etenee lukemalla nykysen tlan pnon pnnalta ja seuraavan syötemerkn syötepuskursta. Näden perusteella on tomntataulussa määrätty tomnta. Syötemerkn srrossa pnoon työnnetään ensmmänen merkk syötepuskursta ja uus tla. Redusonnssa pnosta postetaan sopva määrä symboleta ja katsotaan pnon pnnalle jäävä tlasymbol t. Tämän jälkeen työnnetään pnoon säännön p vasemman puolen apumerkk A sekä se tla, joka on srry-taulun kohdassa (t, A). Vrhetomnnossa srrytään vrheestätopumustlaan ja hyväksymstomnnossa syöte hyväksytään. Redusonnssa pnosta postettaven symbolen määrä määräytyy redusonnssa käytettävän säännön mukaan. Jos säännön okeassa puolessa on m merkkä, postetaan pnosta 2m symbola (m tlaa ja m merkkä). 4.2. LR()-jäsentäjän muodostamnen LR()-alko [ A :: = α β, a ] on pätevä (vald) kelvollselle alkuosalle γ, jos kelopssa on jäsennys. γ = δα, ja S op δaw δαβ w, mssä op 2. joko a on merkkjonon w ensmmänen symbol, ta w = ε ja a = $ [ASU86]. Ylesest ottaen kelvollselle alkuosalle vo olla useta pätevä alkota. LR()-jäsentäjän muodostamsessa määrätään pätevät alkot jokaselle kelvollselle alkuosalle kelopssa (alkaen tyhjästä merkkjonosta). Päteven alkoden joukosta kelvollselle alkuosalle γ käytetään merkntää V(γ ). Jokanen V(γ ) vastaa yhtä jäsentäjän tlaa. Keskenen ajatus LR()-jäsentäjän rakentamsessa on ensn muodostaa kelopsta detarmnstnen äärellnen automaatt, joka tunnstaa kelvollset alkuosat. LR()-alkota ryhmtellään joukkohn I, jotka muodostavat yllä mantut LR()-jäsentäjän tlat. Tlojen muodostamseks määrtellään kaks funktota, sulkeuma ja srry. Sulkeuma-funktossa tlassa s, jossa on muotoa [ A :: = α Bβ, a ] oleva LR()- alkota, lsätään tlaan s myös alkot [ B :: = γ, b ], mssä B ::= γ on kelopn sääntö ja b = FIRST( β a ) ensmmänen perusmerkk lauseessa, joka on jäsennetty merkkjonosta β a. Perusteluna tälle on se, että LR()-alkon [ A :: = α Bβ, a ] mukaan oltaessa tlassa s, pnon pnnalla on merkkjono α ja seuraavaks odotetaan syötteestä löytyvän merkkjono, joka on jäsennettävssä merkkjonosta Bβ a. Koska B on säännön B ::= γ vasen puol, seuraa tästä, että
0 tlassa s odotetaan seuraavaks syötteestä löytyvän merkkjonon, joka on jäsennettävssä merkkjonosta γ b. Srry-funkto saa syötteenään parn (I, X), mssä I on LR()-alkojoukko ja X on kelopn symbol. Joukko srry(i, X) määrtellään muotoa [ A :: = α X β, a ] oleven alkoden sulkeumaks, kun joukossa I on alko [ A :: = α Xβ, a ]. Intutvsest, jos I on LR()-alkojoukko, joka on pätevä kelvollselle alkuosalle γ, nn srry(i, X) on LR()-alkojoukko, joka on pätevä kelvollselle alkuosalle γ X. 4.3. Alkojoukkojen muodostamnen LR()-jäsentäjälle Alkojoukkojen I muodostamseks laajennetaan aluks kelopp G kelopks G lsäämällä sääntö S ':: = S, mssä S on kelopn alkumerkk ja S ' on apumerkk, joka e esnny kelopssa G. Tämän apumerkn tarkotuksena on tunnstaa kohta, jossa syöte vodaan hyväksyä. LR()-alkojoukot muodostetaan algortmlla. Algortm. Algortm LR()-alkojoukkojen muodostumseen [ASU86]. Syöte. Laajennettu kelopp G. Tulos. LR()-alkojoukot, jotka ovat pätevä alkota yhdelle ta useammalle kelopn G kelvollselle alkuosalle. Menetelmä (pääfunkto alkot, sekä funktot sulkeuma ja srry): funkto sulkeuma(i) ; alota tosta jokaselle alkolle [ A :: = α Bβ, a ] joukossa I, jokaselle säännölle B ::= γ kelopssa G ja jokaselle perusmerklle b = FIRST( β a ) jolla [ B :: = γ, b ] e ole joukossa I suorta lsää [ B :: = γ, b ] joukoon I kunnes joukkoon I e voda enää lsätä alkota loppu; funkto srry(i, X); alota olkoon J sellanen joukko LR()-alkota [ [ A :: = α Xβ, a ] on joukossa I; palauta sulkeuma( J ) loppu; A :: = α X β, a ], että
funkto alkot(g ) alota C = {sulkeuma({[ S ':: = S,$ ]) tosta jokaselle sellaselle LR()-alkojoukolle I joukossa C ja jokaselle sellaselle kelopn ymbollle X, että srry(i, X) e ole tyhjä joukko, ekä se ole joukossa C suorta lsää srry(i, X) joukkoon C kunnes joukkoon C e voda enää lsätä uus alkojoukkoja I loppu; LR()-alkojoukot muodostavat determnstsen äärellsen automaatn, joka tunnstaa kelopn kelvollset alkuosat. Automaatssa LR()-alkojoukosta I on srtymä kelopn symbollla X LR()-alkojoukkoon J, jos J = srry(i, X). Jokanen alkojoukko I automaatssa on joukko pätevä LR()-alkota slle kelvollselle alkuosalle, joka muodostuu kuljetusta srtymstä kuljettaessa alkutlasta tlaan I. 4.4. LR()-jäsennystaulun muodostamnen LR()-jäsennystaulua käytetään jäsennyksessä jäsennystomnnasta päätettäessä. Jäsennystaulun rvt koostuvat automaatn tlosta ja sarakkeet (laajentamattoman) kelopn symbolesta. Jäsennystaulu rakennetaan algortma 2 käyttäen. Algortm 2. Algortm LR()-jäsennystaulun muodostamseen [ASU86]. Syöte. Laajennettu kelopp G. Tulos. LR()-jäsennystaulu. Menetelmä:. Muodosta C = { I 0, I,..., I n, kokoelma joukosta LR()-alkota keloplle G. 2. Jäsentäjän tla muodostetaan joukosta I. Jäsennystomnto tlassa määräytyy seuraavast: a) Jos LR()-alko [ A :: = α aβ, b ] on joukossa I j, aseta tomnta[, a] = srrä j. Tässä tapauksessa a on perusmerkk
2 b) Jos [ A :: = α, a ] on joukossa I ja aseta tomnta[, A] = reduso A S ', A ::= α c) Jos [ S ':: = S,$ ] on joukossa I, aseta tomnta[, $] = hyväksy Jos edellämantut säännöt tuottavat konflkteja, el useamman kun yhden tomnnon yhteen tomntataulun kohtaan, kelopp e ole LR()-kelopp ja algortmn suortus epäonnstuu. 3. Jos srry( I, A) = I j, nn jäsennystaulussa srry[, A] = j. 4. Kakk kohdat jäsennystaulussa, johon kohdat 2 ja 3 evät tuota merkntää, ovat vrhetloja. 5. Jäsentäjän alkutla on se tla, joka muodostetaan sulkeumalla LR()-alkosta [ S ':: = S,$ ]. Esmerkk. Tarkastellaan esmerkknä keloppa Γ, jonka säännöt ovat S :: = SS S :: = SSS S :: = b. Tästä muodostettu LR()-alkojoukkojen mukanen DFA on estetty kuvassa 4.. Kuva 4.. LR()-jäsennyksen mukanen DFA keloplle Γ.
3 Tla 3 ssältää LR()-alkon [ S ':: = S,$], joten tla 3 on lopputla. LR()- alkojoukosta muodostettu LR()-jäsennystaulu on estetty kuvassa 4.2. $ b S 0 s4 g3 r/s2 r/r2/s4 g 2 r r/s4 g 3 hyv. s4 g2 4 r3 r3 Kuva 4.2. LR()-jäsennystaulu keloplle Γ.
4 5. GLR-jäsennysalgortmsta ylesest Avan kuten LR-jäsentäjämsessä, GLR-jäsentämsessäkn käytetään jäsennyspnoa ja äärellstä ohjausta. Äärellnen ohjaus määrttelee, mkä jäsennystomnto (syötemerkn srto pnoon, redusont) suortetaan seuraavan syötemerkn ja pnon pnnalla olevan tlan perusteella. Mutta, kuten jo yllä manttn, pnon sjasta GLR-jäsentäjä käyttää graafrakentesta pnoa (GSS), joka ssältää kakk pnot, jotka LR-jäsentäjä mahdollstaa. Jokasta pnoa graafssa pdetään erllsenä LR-jäsentäjänä ja jokasta pnoa kästellään rnnakkan. Pnot synkronodaan srtämällä jokanen syötemerkk samanakasest. GLR-jäsentäjän graafrakentenen pno on yksnkertanen. Jotkn pnojen solmusta ovat pnojensa pnnalla ja algortm ptää nästä lukua. Jokasella solmulla on vähntään yks sellanen suunnattu kaar alempn solmuhn jossan pnossa, että jokanen äärellnen polku tetyn pnon pntasolmusta ykskästteseen pohjasolmuun muodostaa potentaalsen LR-jäsennyspnon. Kontekstttomssa kelopessa vo olla muotoa A ::= ε oleva sääntöjä, ns. tyhjä sääntöjä. Tyhjä sääntöjä ssältävän kelopn tapauksessa GSS vo ssältää sykln ja nän ollen äärettömän ptkän polun. Myöhemmn estetään algortmeja, jossa tämä on otettu huomoon. Nämä algortmt tomvat oken myös tyhjä sääntöjä ssältäven keloppen kanssa. GLR tom seuraavast: jokasen syötemerkn kohdalla jokasen pnon pnnalla olevalle tlalle suortetaan jokanen mahdollnen LR()-jäsennystomnto. Tomntoja vo olla useta mahdollsa vastaten jäsennyskonflkta tavallsessa LR-jäsentäjässä. Syötemerkn srto pnoon luo uuden solmun pnon pnnalle ja tästä luodaan suunnattu kaar alempaan solmuun. Redusonnssakn on mahdollsta luoda uus solmu, mutta tosn kun LRjäsentäjässä, jossa pnosta postetaan tloja ja latetaan uus tla pnoon, GLR:ssä kuljetaan GSS:ää kakken LR-jäsentäjässä postettaven tlojen oh. Tämän jälkeen luodaan uus solmu (elle vastaavaa ole jo olemassa) ja lsätään stä suunnattu kaar shen solmuun, joka LR-jäsentäjässä syötemerkn kanssa määrää uuden tlan. Jos kaks er pnoa srtävät saman tlan pnoon ta redusotuvat samaan tlaan, pnojen pnnat yhdstetään samaks solmuks.
5 5.. Graafrakentenen pno (GSS) GSS koostuu tlasolmusta, jotka vastaavat tloja DFA:ssa sekä suunnatusta kaarsta. GSS:ään vodaan ssällyttää myös kelopn symboleja, jos jäsennykset halutaan eksplsttsest tallentaa. Tässä estyksessä GSS ssältää myös kelopn symbolt. GSS on suunnattu graaf, joka ssältää tlasolmuja ja kelopn symboleja nn, että kelopn symboln ssältävät solmut ja tlan ssältävät solmut vuorottelevat. Tomtan algortm saa syötteenään syötemerkkjonon a a2... a ja tämän avulla se käy läp LR()-algortmn muodostamaa determnststä äärellstä automaatta (DFA) rakentaen GSS:ää edetessään. Tällön GSS ssältää kuvassa 5. estettyä muotoa olevan algraafn, n Kuva 5.. Algraaf GSS:ssä. jos DFA:ssa on kuvassa 5.2 estettyä muotoa oleva srtymä. Kuva 5.2. Kuvan 5. graafa vastaava DFA. Rakentamsta tehdään askelmssa nn, että alkuaskeleen jälkeen jokasta syötemerkkä koht suortetaan yks askel. GSS:n tlat kuuluvat joukkoon U. Tämä jaetaan askelen mukaan joukkohn U, 0 n. Kuvassa 5. tla k kuuluu sten joukkoon U ja tla h kuuluu joukkoon U. Tämä vastaa ss syötemerkn srtämstä pnoon tavallsessa LR-jäsentäjässä. Joukon U sanotaan olevan suljettu redusonten suhteen, jos joukon kaksta tlosta on suortettu kakk mahdollset redusonnt. U 0 on alkujoukko, joka ssältää DFA:n alkutlan ja on suljettu redusonten suhteen. Samon jokanen joukko U, n, on muodostettu joukosta U lsäämällä joukkoon U tlat, jotka saadaan suorttamalla salltut srrä-tomnnot joukon U tlosta ja stten sulkemalla U redusonten suhteen.
6 GSS ssältää kuvassa 5.3 estettyä muotoa olevan algraafn, Kuva 5.3. Algraaf GSS:ssä. mssä u U ja v U sllon, kun GSS ssältää myös kuvassa 5.4 estettyä j muotoa olevan algraafn, Kuva 5.4. Algraaf GSS:ssä. mssä u U j, U w, A :: = x... xm on kelopn sääntö ja DFA:ssa on srtymä tlasta k tlaan h symbollla A. Tämä vastaa ss redusonta tavallsessa LRjäsentäjässä. Kuvan 5.4 tlanteessa solmun v sanotaan olevan redusontrelaatossa (reducton related) solmuun w (2m+)-ptusen polun kautta. Kuvassa 5.5 asaa on velä havannollstettu esttämällä vastaava tlanne DFA:ssa. Kuva 5.5. Redusontrelaato solmujen v ja w välllä.
7 Tlasolmun sanotaan olevan tasolla, jos se kuuluu joukkoon U. Tlasolmulla v U sanotaan olevan pätevä redusont, jos sen ssältämä tla h ssältää DFA:ssa LR-alkon ( A :: = α, a+ ). (LR()-jäsennyksen mukasen DFA:n muodostamseen käytetty algortm varmstaa sen, että α on luettu merkkjono.) Vastaavast, kelopn säännön A ::= α sanotaan olevan pätevä tlasolmulle v, joka on tasolla ja jonka ssältämä tla on h, jos DFA:ssa tla h ssältää LR-alkon ( A :: = α, a+ ). Pätevät redusonnt suortetaan ss sllon, kun algortm on lukenut merkkjonon a...a ja seuraava syötemerkk on a +. Tlasolmusta koostuva joukko U on suljettu redusonten suhteen, kun sen jokanen taso on suljettu redusonten suhteen. Oletetaan, että solmu w on joukon U tasolla ja että se ssältää tlan l. Tarkastellaan nyt tlan l LR()- alkota ( A :: = x... x m, a+ ). Olkoon k sellasen solmun u ssältämä tla, joka on saavutettavssa GSS:ssä solmusta w sellasta polkua ptkn, jonka ptuus on 2m. Tällön DFA:n tlasta k on srtymä symbollla A tlaan h. GSS:n joukko U ssältää tällön solmun v tlalla h ja symbolsolmun A, jonka edeltäjä on v ja jälkelänen on u. Kakk joukot U GSS:ssä ovat suljettuja redusonten suhteen. 5.2. GSS:n rakentamnen syötteestä Ennen algortmn formaala kuvausta estetään seuraavaks GSS:n muodostamnen esmerkn avulla. Esmerkknä käytetään monselttestä keloppa Γ 2, jonka säännöt ovat S :: = E E :: = E :: = E + E E :: = E E. Ensn muodostetaan LR()-alkojoukkojen mukanen DFA (kuva 5.6).
8 Kuva 5.6. Kelopsta Γ 2 muodostettu LR()-jäsennyksen mukanen DFA. Muodostetaan GSS syötteestä +. Ensmmäsenä joukkoon U 0 lsätään alkutla 0. Tlassa 0 e ole pätevä redusonteja (kelopp e ssällä tyhjä sääntöjä), joten U 0 = { v 0. Tämän jälkeen luetaan merkk (suortetaan srrätomnto), luodaan symbolsolmu u symbollla (merktään [ u, ]) ja tlasolmu v tlalla 2 (merktään [ v, 2]). Solmusta v tehdään solmun u edeltäjä ja solmusta u tehdään solmun v 0 edeltäjä. Solmu v lsätään joukkoon U (kuva 5.7). Kuva 5.7. Syötemerkn lukemnen. Seuraavaks tlassa 2 tutktaan, löytyykö sellä pätevä redusonteja syötemerkn ollessa +. Koska tähän mennessä on luettu van yks syötemerkk, tälläsen LR()-alkon on oltava muotoa ( A :: = a, a2 ). Tla 2 ssältää LR()- alkon ( E :: =, + ). Tämän mukaan kuljetaan kahden askeleen mttasta polkua solmusta v solmuun v 0. DFA:ssa on srtymä merkllä E tlasta 0 tlaan. Nnpä GSS:ään luodaan tlasolmu [ v 2, ], joka lsätään joukkoon U. GSS:ään luodaan myös symbolsolmu symbollla E, josta tehdään solmun v 2 jälkelänen ja solmun v 0 edeltäjä (kuva 5.8).
9 Kuva 5.8. Redusont sääntöön E :: = perustuen. Tämän jälkeen tarkstetaan pätevät redusonnt juur lsätystä tlasolmusta ja jatketaan prosessa, kunnes U on suljettu redusonten suhteen. Tässä tapauksessa solmussa v 2 e ole pätevä redusonteja, joten U on kästelty. Ylesest askeleen alussa GSS:ssä on joukko U tlasolmuja ja syötteenä on a... an $. Jokasta joukon U tlasolmua v koht tarkstetaan, onko DFA:ssa srtymä merkllä a tlasta k tlaan l. Jokasta tällästä srtymää koht tarkstetaan, ssältääkö GSS:n joukko U jo tlasolmun tlalla l. Jos e, lsätään tällanen tlasolmu joukkoon U. (Jokanen joukko U ssältää ss van korkentaan yhden tlan l.) Jos tlalla l on jälkeläsenä symbolsolmu symbollla a, nn tästä symbolsolmusta lsätään kaar solmuun k joukossa U. Muussa tapauksessa luodaan symbolsolmu tlasolmun l jälkeläseks symbollla a ja tehdään tästä tlasolmun k edeltäjä. Kun kakk solmut joukosta U on kästelty, saadaan U = U a. Joukko U saadaan ss joukosta U lukemalla syötemerkk a. Esmerkssä askeleella 2 on vomassa U = {,2 ja U + = {5 (kuva 5.9). Kuva 5.9. Syötemerkn + lukemnen. Joukossa U 2 = {5 e ole redusonteja syötemerkllä, joten luetaan seuraava syötemerkk ja lsätään se GSS:ään. Saadaan ss U 2 = {2 (kuva 5.0).
20 Kuva 5.0. Syötemerkn lukemnen. Seuraavaks muodostetaan redusontsulkeuma joukolle U a. Jokaselle tlasolmulle v U, jokaselle tlalle k ja jokaselle muotoa ( A :: = x... x m, a+ ) olevalle LR()-alkolle tlassa k, etstään GSS:stä kakk tlasolmut [u, l ], jotka ovat 2m ptusen polun päässä tlasolmusta v. Olkoon DFA:ssa srtymä tlasta l tlaan g merkllä A. Jos joukossa U e velä ole tlasolmua tlalla g, nn luodaan solmu w ja lsätään se joukkoon U. Jos tlasolmusta w tlasolmuun u on jo olemassa kahden askeleen ptunen polku, e tehdä mtään. Muuten luodaan symbolsolmu A, joka on solmun w jälkelänen ja solmun u edeltäjä. Prosessa jatketaan, kunnes U on suljettu redusonten suhteen (kuva 5.). Kuva 5.. Redusont GSS:ssä ylesessä tapauksessa. Esmerkkn sovellettuna redusontsulkeuman laskemnen tlasta 2 syötemerkllä lsää joukkoon U 3 tlat 7 ja (kuva 5.2). Kuva 5.2. Redusonnt sääntöhn E :: = ja E :: = E + E perustuen.
2 Seuraavaks luetaan seuraava syötemerkk. DFA:ssa tlosta ja 7 on molemmsta srtymät tlaan 4 syötemerkllä (kuva 5.3). Kuva 5.3. Syötemerkn lukemnen. Tlasta 4 e ole redusonteja syötemerkllä, joten U 4 = {4. Luetaan merkk (kuva 5.4). Kuva 5.4. Syötemerkn lukemnen. Tlasta 2 redusonnn suorttamnen syötemerkllä $ lsää joukkoon U 5 tlan 6. Redusont tästä lsää joukkoon U 5 tlat ja 7. Redusont tlasta 7 ve DFA:ssa tlaan, mutta koska tämä tla on jo joukossa U 5, e stä enää lsätä. Syötemerkn $ lukemnen tlassa johtaa lopulta syötteen hyväksymseen (kuva 5.5).
22 Kuva 5.5. Täydellnen GSS syötteelle +. 5.3. Tyhjen sääntöjen kästtelemnen Kun kelopssa on tyhjä sääntöjä, stä muodostetun LR()-jäsennyksen mukasen DFA:n tlossa on muotoa [ A :: =, a ] oleva LR()-alkota. Jos alkutlassa on LR()-alko [ S :: =,$ ], kuuluu tyhjä lause kelopn määräämään keleen. Tällasten redusonten lttämnen yllä kuvattuun GLR-jäsennysmalln on yksnkertasta. Jos joukossa U on tlasolmu [v, h] mssä DFA:n tla h ssältää LR()-alkon [ A :: =, a+ ], etstään LR()-jäsennystaulusta rvltä h, sarakkeesta A kohta gk. Tämän jälkeen katsotaan, ssältääkö joukko U jo solmun tlalla k. Jos e, luodaan tlasolmu [w, k] ja symbolsolmu [u, A]. Solmusta u tehdään solmun w jälkelänen ja solmun v edeltäjä. Jos joukossa U on jo tlasolmu [w, k], mutta e kahden askeleen mttasta polkua solmuun v, luodaan symbolsolmu [u, A], ja tämän kautta kahden askeleen mttanen polku solmusta w solmuun v. Jos joukossa U on jo tlasolmu [w, k] ja solmusta w on kahden askeleen mttanen polku solmuun v, e tehdä mtään. GSS:ssä on nän polku kahden samaan joukkoon U kuuluvan solmun välllä. Tämän seurauksena GSS:ään vo muodostua sykl. Myöhemmn nähdään kutenkn, että tämä pystytään jäsennyksessä kästtelemään. Havannollstetaan seuraavaks tyhjen sääntöjen kästtelyä GSS:n rakentamsessa. Tarkastellaan keloppa Γ 3, jonka säännöt ovat S:: = Aa ε A :: = S ε. Tästä muodostettu LR()-jäsennyksen mukanen DFA on estetty kuvassa 5.6. Syötteenä on a.
23 Kuva 5.6. Kelopsta Γ 3 muodostettu LR()-jäsennyksen mukanen DFA. Aluks GSS:ään latetaan tlasolmu [ v 0, 0]. Solmu v 0 asetetaan joukkoon U 0. DFA:n tlassa 0 on kaks redusonta syötemerkn ollessa a. LR()-alko [ S :: =, a ] luo tlasolmun [ v, 2], sekä symbolsolmun symbollla S, josta tehdään solmun v jälkelänen ja solmun v 0 edeltäjä. LR()-alko [ A :: =, a ] luo tlasolmun [ v 3, 3], sekä symbolsolmun symbollla A, josta tehdään solmun v 2 jälkelänen ja solmun v 0 edeltäjä (kuva 5.7). Kuva 5.7. Redusonnt tyhjn sääntöhn perustuen. Solmua v kästeltäessä huomataan, että DFA:n tlassa 2 on redusont [ A :: = S, a ]. Tämä ve takasn solmuun v 0. Nyt algortmn mukaan on tarkotus lsätä GSS:ään ja joukkoon U 0 tlasolmu tlalla 3, sekä GSS:ään tlasolmun jälkeläseks symbolsolmu symbollla A. Mutta koska joukossa U 0 on jo tlasolmu tlalla 3 ja GSS:ssä tämän jälkeläsenä symbolsolmu symbollla A, e tehdä mtään. Solmussa v 2 suortetaan srto ja luodaan tlasolmu [ v 3, ], sekä symbolsolmu symbollla a, josta tehdään solmun v 2 jälkelänen ja solmun v edeltäjä. Solmu v 3 lsätään joukkoon U (kuva 5.8). Kuva 5.8. Syötemerkn a lukemnen.
24 Syötemerkknä on nyt $. Solmua v 3 kästeltäessä huomataan, että DFA:n tlassa on redusont [ S :: = Aa,$]. Tämä ve takasn solmuun v 0. GSS:ään ja joukkoon U lsätään tlasolmu [ v 4, 2], sekä GSS:ään tlasolmun jälkeläseks symbolsolmu symbollla S. Mtään muuta e enää tehdä. Tla 2 on lopputla, joten syöte hyväksytään (kuva 5.9). Kuva 5.9. Täydellnen GSS syötteelle a.
25 6. Tomtan algortm e Tomta [Tom86] kuvas vs algortma, algortmt 0,, 2, 3 ja 4, ylestettyyn LRjäsentämseen. Algortm ssältää suurmman osan tarvttavasta välnestöstä, mutta se soveltuu kutenkn van kelopelle, jotka evät ssällä tyhjä sääntöjä. Estetään seuraavaks formaalst menetelmä, jolla tähän mennessä on muodostettu GSS. Kyseessä on Scottn ja muden [SJH00] tekemä pen muunnelma Tomtan algortmsta. Se suorttaa tyhjn sääntöhn lttyvät redusonnt edellä kuvatulla tavalla, kun tlasolmua kästellään ensmmäsen kerran. Tämä algortm on pohjana Scottn ja muden RNGLR-algortmlle [SJH00], joka estellään myöhemmn. Lsäks sen tarkastelu auttaa ymmärtämään, mks alkuperäset Tomtan algortmt 2, 3 ja 4 evät tom tetyssä tapauksssa. Algortm ylläptää seuraava joukkoja: A : joukko tlasolmuja, jotka on kästeltävä GSS:ssä U : joukko askeleen tlasolmuja R : joukko suorttamattoma redusonteja Q : joukko suorttamattoma srtoja. Algortmssa on kolme funktota, jotka rakentavat GSS:ää: TOIMIJA: Kästtelee joukkoon A tallennetuttuja tlasolmuja. Lsää joukkoon R redusonteja ja joukkoon Q srtoja. REDUSOIJA: Kästtelee redusonteja joukosta R. Lsää tarvttavat tla- ja symbolsolmut GSS:ään. SIIRTÄJÄ: Kästtelee srrot joukosta Q. Lsää tarvttavat tla- ja symbolsolmut GSS:ään. Algortmn syöte on kontekstton kelopp, jonka säännöt on numerotu, tästä kelopsta muodostettu LR()-jäsennyksen mukanen DFA jäsennystaulun muodossa sekä syötemerkkjono a... an $. Algortm 3. Algortm e ylestettyyn LR-jäsentämseen [SJH00]. luo tlasolmu [ v 0, 0], mssä 0 on DFA:n alkutla aseta U 0 = { v 0, A = θ, R = θ, Q = θ
26 jokaselle, 0 n, suorta JÄSENNÄ_SYMBOLI() olkoon q DFA:n lopputla jos U n ssältää tlasolmun, jonka tla on q on DFA:n lopputla, lmota jäsennyksen onnstuneen muuten lmota jäsennyksen epäonnstuneen JÄSENNÄ_SYMBOLI() { A = U U + = θ nn kauan kun A θ ta R θ tee jos A θ suorta TOIMIJA() muuten suorta REDUSOIJA() suorta SIIRTÄJÄ() TOIMIJA() { posta v joukosta A ja olkoon h solmun v tla jos srrä k on tomnta LR()-jäsennystaulun kohdassa (h, a + ) lsää (v, k) joukkoon Q jokaselle reduso p tomnnalle DFA:n tomntataulun kohdassa (h, a + ) jos säännön p okean puolen ptuus on 0, lsää (v, p) joukkoon R muuten jokaselle solmun v jälkelässolmulle u, lsää (u, p) joukkoon R REDUSOI() { posta (u, j) joukosta R olkoon m säännön p okean puolen ptuus ja olkoon X säännön p vasemman puolen apumerkk jos m = 0 olkoon k solmun u tla ja olkoon gl tomnta LR()-jäsennystaulun kohdassa (k, X) jos joukossa U e ole tlaa l luo GSS:ään uus tlasolmu [v, l] ja lsää v joukkohn U ja A olkoon [v, l] joukon U solmu jos GSS:ssä on kahden askeleen mttanen polku solmusta v solmuun u, älä tee mtään muuten { luo GSS:ään symbolsolmu [u, X] ja tee tästä solmun v jälkelänen ja solmun u edeltäjä jos v e ole joukossa A { jokaselle sellaselle redusonnlle rk LR()-jäsennystaulun kohdassa (l, a + ), joka e perustu tyhjään sääntöön lsää (u, k) joukkoon R muuten jokaselle tlasolmulle w joka vodaan saavuttaa solmusta u 2m- mttasta polkua ptkn tee { olkoon k solmun w tla ja olkoon gl tomnta LR()-jäsennystaulun kohdassa
27 (k, X) jos joukossa U e ole tlaa l, luo GSS:ään uus tlasolmu [v, l] ja lsää v joukkohn U ja A olkoon [v, l] joukon U solmu jos GSS:ssä on kahden askeleen mttanen polku solmusta v solmuun u, älä tee mtään muuten { luo GSS:ään symbolsolmu [u, X] ja tee tästä tästä solmun v jälkelänen ja solmun w edeltäjä jos v e ole joukossa A { jokaselle redusonnlle rk DFA:n tomntataulun kohdassa (l, a + ) lsää (u, k) joukko on R SIIRTÄJÄ( { nn kauan kun Q θ suorta { posta (v, k) joukosta Q jos joukossa U + e ole tlasolmua [w, k], luo tällänen solmu jos solmulla w e ole jälkelässolmua [u, a + ], luo tällänen solmu jos solmu u e ole solmun v edeltäjä, tee solmusta u solmun v edeltäjä Funkto TOIMIJA postaa joukkoon A tallennetun tlasolmun v ja tutk LR()-jäsennystaulusta mahdollset tomnnot tlasolmun v tlan ja seuraavan syötemerkn a + perusteella. Srrä-tomnnon tapauksessa joukkoon Q lsätään tla v sekä se tla k, johon DFA:ssa srrytään tlasta v lukemalla a +. Redusonten osalta joukkoon R tallennetaan symbolsolmu ja reduonnssa käytettävän säännön numero. Jos sääntö on tyhjä sääntö, symbolsolmu on v. Muussa tapauksessa joukkoon R tallennetaan jokanen par (u, p), mssä u on solmun v jälkelänen (ss symbolsolmu) GSS:ssä. REDUSOI-funkto kästtelee ss para (u, p), mssä u on solmu GSS:ssä ja p on redusonnssa käytettävän säännön numero. Funktossa REDUSOIJA redusonten kästtely pokkeaa sen mukaan, onko redusonnnssa käytetty sääntö tyhjä sääntö va e (el onko säännön okean puolen ptuus 0). Jos säännön p okean puolen ptuus m = 0, nn joukon U tlasolmu [u, k ], ssältää muotoa ( X :: =, a+ ) olevan LR()-alkon. Tällön haetaan LR()- taulusta rvltä k, sarakkeesta X kohta gl. Tämän jälkeen tutktaan, ssältääko U tlasolmun [v, l]. Jos e, tällänen tlasolmu luodaan GSS:ään ja lsätään
28 joukkoon U. Tämän jälkeen tutktaan, onko GSS:ssä kahden askeleen ptusta polkua tlasolmusta v tlasolmuun u. Jos e, luodaan symbolsolmu [ u ', X], josta tehdään solmun v seuraaja ja solmun u edeltäjä (kuva 6.). Kuva 6.. Solmun v lsäämnen. Jos joukon U tlasolmu [v, h] ssältää muotoa ( X :: = x... x m, a+ ) olevan LRalkon, mssä m, on etsttävä kakk tlasolmut z, jotka ovat 2m-ptusen polun päässä tlasolmusta v. Ongelmana on kutenkn se, että myöhemmässä vaheessa saatetaan solmulle v lsätä uus jälkelänen ja luoda nän uus samanptunen polku solmusta v sekä uus mahdollnen redusont, jota e olla velä kästelty. Jos tlasolmussa joudutaan käymään uudestaan, koska stä on lsätty uus polku, nn kakken polkujen läpkäymnen teks jäsentäjästä hyvn tehottoman. (Tämä e aheuttas vrhettä, koska algortmssa tarkstetaan kahden askeleen ptusten polkujen olemassaolo. Nän jo tehtyjä redusonteja e tosteta.) Tämän taka funktossa TOIMIJA redusonnt tallennetaan ensmmäsen solmun mukaan, joka on tlasolmusta lähtevän polun varrella. Kun tlasolmu v lsätään GSS:ään, sllä on tla h ja jälkeläsenä symbolsolmu u (kuva 6.2). Kuva 6.2. Tlasolmu v ja symbolsolmu u. Jokasta tlan h muotoa ( X :: = x... x m, a+ ) olevaa LR()-alkota koht REDUSOI-funkton kästeltäväks tulee redusont (u, p), mssä p on säännön X :: = x... x m numero. Kun redusonta (u, p) kästellään, etstään kakk solmut, jotka ovat (2m-)-ptusen polun päässä solmusta u. Jos myöhemmässä vaheessa tlasolmusta v luodaan uus polku (kuva 6.3),
29 Kuva 6.3. Tlasolmu v ja symbolsolmut u ja u. nn kaklle tlan h redusonnelle suortettavks redusonneks määrtellään (u, p). Nän jo suortettuja redusonteja e enää käydä läp. SIIRTÄJÄ-funktossa yhdstetään perusmerkt nn, että kakk polut joukon U tetystä tlasta joukkoon U kulkevat saman symbolsolmun kautta (kuva 6.4). Kuva 6.4. Symbolsolmujen yhdstämnen. 6.. Esmerkk epäsuorasta vasemmasta rekursosta Seuraavaks edellä annettua Tomtan algortma havannollstetaan esmerkn avulla. Esmerkssä syötteenä on merkkjono xb ja keloppna Γ 4 jonka säännöt ovat S ':: = S S ::= AS b x A ::= ε. Kelopp ssältää epäsuoran vasemman rekurson (hdden left recurson), koska se ssältää johdon S ASb Sb. Määrtelmän mukaan kelopp ssältää epäsuoran vasemman rekurson, jos se ssältää sellasen apumerkn A ja sellaset merkkjonot τ ja σ sten, että σ + ε ja A σaτ. LR()-jäsennystaulu keloplle Γ 4 on estetty kuvassa 6.5.
30 $ a x A S 0 r3/s9 g8 g7 r 2 s 3 r 4 s3 5 r3/s6 g5 g2 6 g2 7 hyv. 8 r3/s6 g5 g4 9 r2 Kuva 6.5. LR()-jäsennystaulu keloplle Γ 4. GSS:n muodostamnen alotetaan lsäämällä tyhjään graafn tlasolmu [ v 0, 0]. Ss A = U 0 = { v 0, R = Q = θ ja syötemerkknä on a = x. Solmu v 0 postetaan joukosta A ja tutktaan LR()-taulusta tomnta tlan ollessa 0 ja syötemerkn ollessa x. Tomntoja on kaks: redusont säännön 3 ( A ::= ε ) mukaan ja syötemerkn srto. Srto ( v 0, 9) asetetaan joukkoon Q. Säännön A ::= ε okean puolen ptuus on 0, joten suortettavaks redusonnks joukkoon R tulee ( v 0, 8). Suortetaan seuraavaks tämä redusont. LR()-taulussa kohdassa (0, A) on tomnto g8, joten GSS:n lsätään tlasolmu [ v, 8] sekä symbolsolmu symbollla A, josta tehdään solmun v jälkelänen ja solmun v 0 edeltäjä. Asetetaan solmu v joukkohn A ja U 0 (kuva 6.6). Kuva 6.6. Redusont sääntöön A ::= ε perustuen. Solmu v postetaan joukosta A. LR()-jäsennystaulussa kohdassa (8, x) on kaks tomntoa: redusont säännön 3 mukaan ja syötemerkn srto. Srto ( v, 6) asetetaan joukkoon Q ja redusont säännön 3 mukaan asetetaan joukkoon R. Suortetaan redusont, jollon GSS:ään lsätään tlasolmu [ v 2, 5] sekä
3 symbolsolmu symbollla A, josta tehdään solmun v 2 jälkelänen ja solmun v edeltäjä. Solmu v 2 asetetaan joukkohn A ja U 0 (kuva 6.7). Kuva 6.7. Redusont sääntöön A ::= ε perustuen. Kästeltäessä joukon A solmua v 2 huomataan, että U 0 ssältää jo tlan 5, joten solmusta v 2 luodaan polku tseensä. Koska tlassa 5 e ole ptuudeltaan nollaa suurempa redusonteja, uusa redusonteja e enää lsätä. Joukkoon Q lsätään srto ( v 2, 6) (kuva 6.8). Kuva 6.8. Redusont sääntöön A ::= ε perustuen. Suortetaan seuraavaks srrot joukosta R. GSS:ään ja joukkoon U lsätään tlasolmut [ v 3, 9] ja [ v 4, 6]. Solmut v 3 ja v 4 lsätään joukkoon A (kuva 6.9).
32 Kuva 6.9. Syötemerkn x lukemnen. Postetaan joukosta A solmu v 3. LR()-jäsennystaulussa e ole tomntoja kohdassa (9, b), joten e tehdä mtään. Seuraavaks postetaan solmu v 4 joukosta A. Tomnto LR()-jäsennystaulun kohdassa (6, b) on redusoda säännön 2 mukaan. Solmusta v 4 kuljetaan takasn solmuun v. LR()-jäsennystaulun merkntä kohdassa (7, S) on g4, joten lsätään joukkoon U tlasolmu [ v 5, 4]. GSS:ään lsätään myös symbolsolmu symbollla S, josta tehdään solmun v 5 jälkelänen ja solmun v edeltäjä. Solmu v 5 asetetaan joukkoon A (kuva 6.0). Kuva 6.0. Redusont sääntöön S :: = x perustuen. Kästellään joukon A solmu v 5. Anoa tomnto LR()-jäsennystaulun kohdassa (4, b) on syötemerkn srto, joten joukkoon Q lsätään alko ( v 5, 3). Joukot A ja R ovat tyhjä, joten suortetaan joukosta Q snne juur lsätty srto. Lsätään ss GSS:ään tlasolmu [ v 6, 3], joka lsätään joukkoon U 2 ja A (kuva 6.).
33 Kuva 6.. Syötemerkn b lukemnen. Kästellään joukon A solmu v 6. LR()-jäsennystaulun kohdassa (3, $) on redusont sääntöön perustuen. Suortetaan tämä redusont, jollon kuljetaan takasn solmuun v 0 ja katsotaan tomnto LR()-jäsennystaulun kohdasta (0, S). Tomnnon g7 mukaan lsätään joukkoon U 2 tlasolmu [ v 7, 7]. Muta tomntoja e tämän jälkeen tehdä. Joukko U 2 ssältää nyt tlasolmun [ v 7, 7], joka on lopputla. Nän syöte xb hyväksytään (kuva 6.2). Kuva 6.2. Täydellnen GSS syötteelle xb.
34 6.2. Esmerkk epäsuorasta okeasta rekursosta Edellä annettu algortm pysähtyy kaklla syöttellä, koska joukko U on äärellnen. Se nmttän ssältää korkentaan nn monta tlaa kun LR()- jäsennystaulu ssältää ja mstä tahansa solmusta joukossa U on korkentaan yks kahden askeleen mttanen polku mhn tahansa solmuun joukossa U j, j. Mutta kuten seuraavaks huomataan, algortm vo hylätä syötteen, joka kuuluu kelopn määrttelemään keleen. Tarkastellaan keloppa Γ 5, jonka säännöt ovat S ':: = S S ::= a S A ε A ::= ε. Kelopp ssältää epäsuoran okean rekurson (hdden rght recurson), koska se ssältää säännön S asa as. Määrtelmän mukaan kelopp ssältää epäsuoran okean rekurson, jos se ssältää sellasen apumerkn A ja merkkjonot τ ja σ, että τ + ε ja A σaτ. LR()-jäsenystaulu keloplle Γ 5 on estetty kuvassa 6.3. $ a A S 0 r2 s4 g3 r 2 r3 g 3 hyv. 4 r2 s4 g2 Kuva 6.3. LR()-jäsennystaulu keloplle Γ 5. LR()-jäsennystaulusta huomataan, että Γ 5 on LR()-kelopp, koska LR()- jäsennystaulussa e ole konflkteja. Syötemerkkjonona on aaa. Syötemerkllä a e ole redusonteja, joten kakk merkt a lukemalla päästään kuvan 6.4 GSS:ään. Kuva 6.4. Merkkjonon aaa lukemnen.
35 Kuvan 6.4 tlanteessa on vomassa U 0 = { v 0, U = { v, U 2 = { v 2 ja v3 U 3. Seuraavaks muodostetaan redusontsulkeuma joukolle U 3 syötemerkllä $ el postetaan v 3 joukosta A ja kästellään se. Tomnta r2 luo uuden tlasolmun [ v 4, 2], sekä kahden askeleen mttasen polun solmusta v 4 solmuun v 3. Solmu v 4 lsätään joukkohn U 3 ja A. Solmu v 4 postetaan joukosta A ja kästellään, jollon tomnta r3 luo uuden tlasolmun [ v 5, ]. Solmu v 5 lsätään joukkohn U 3 ja A (kuva 6.5). Kuva 6.5. Redusonnt sääntöhn S ::= ε ja A ::= ε perustuen. Postetaan solmu v 5 joukosta A ja kästellään se. Redusont säännön mukaan ve tlasolmuun [ v 2, 4]. Kohta (4, S) LR()-jäsennystaulussa on g2. Joukko U 3 ssältää jo tlasolmun [ v 4, 2], joten solmusta v 4 luodaan kahden askeleen mttanen polku solmuun v 2 (kuva 6.6). Kuva 6.6. Redusont sääntöön S :: = asa perustuen. Algortmn mukaan seuraavaks solmusta v 2 kakk ptuudeltaan nollaa suuremmat redusonnt lsätään joukkoon R. Koska LR()-taulun kohdassa (2,
36 $) e tällasä redusonteja ole, joukkoon R e lsätä mtään. Joukot A ja R ovat tyhjä, joten algortm pysähtyy. Koska U 3 e ssällä lopputlaa, syöte aaa hylätään, vakka se kuuluu kelopn Γ 5 määrttelemään keleen. Ongelmana on nyt se, että uus polku luotn keskelle olemassaolevaa polkua, el uus kaar lsättn lähteväks solmusta, jolla ol jo edeltäjä. Nän tlasolmusta v 5 lähtevää uutta polkua e kästelty (, mkä lopulta ols johtanut merkkjonon aaa hyväksymseen). Tomtan ratkasu tähän ongelmaan ol jakaa joukko U aljoukkohn sllon, kun suortetaan redusont tyhjään sääntöön perustuen. Tällön esmerkssä, jossa solmut v 4 ja v 5 ovat luotu tyhjään sääntöön perustuvan redusonnn kautta, solmut v 3, v 4 ja v 5 kuuluvat er joukkohn. Nnpä suortettaessa redusonta solmusta v 5, GSS:ään lsätään solmu v 6, koska snä joukossa, jossa solmu v 5 on, e ole tlasolmua tlalla 2. Solmussa v 6 suortetaan taas redusont tyhjään sääntöön perustuen, joten luotava solmu v 7 kuuluu er joukkoon kun v 6. Suorttamalla redusont solmusta v 7, kuljetaan solmuun v, luodaan solmu v 8 ja kahden askeleen mttanen polku solmusta v 8 solmuun v. Solmu v 8 luo solmun v 9, josta suortettava redusont lopulta luo tlasolmun [ v 0, 3], joka on lopputla (kuva 6.7). Kuva 6.7. Tomtan algortmn 2 syötteestä aaa muodostama GSS. Aljoukkojen luomnen joukolle U johtaa kutenkn shen, että nän tomva algortm e pysähdy kästellessään keloppa, joka ssältää epäsuoran vasemman rekurson.
37 6.3. Tomtan algortm 2 Estetään seuraavaks esmerkk stä, kunka Tomtan algortm käyttäytyy epäsuoran vasemman rekurson ssältävällä keloplla. Aheeseen palataan tarkemmn luvussa 9. Perusdeana on ss toma samon kun yllä ε -algortmssa, mutta kaks tlasolmua a ja b samalla algortmn askeleella kuuluvat er aljoukkohn U, j ja U, j+, jos solmu b on luotu tekemällä tyhjään sääntöön perustuva redusont solmussa a. Tarkastellaan jälleen keloppa Γ 4 syötteellä aa. Suortettaessa pelkkä redusonteja alkutlan 0 ssältävästä tlasolmusta v 0 päädytään kuvan 6.8 tlanteeseen. Kuva 6.8. Redusonnt sääntöön A ::= ε perustuen. Solmu v 0 kuuluu joukkoon U 0, 0. Tästä suortettu redusont tyhjän säännön A ::= ε perusteella luo uuden tlasolmun [ v, 7], joka kuuluu joukkoon U 0,. Suorttamalla redusont solmusta v jälleen säännön A ::= ε mukaan, luodaan tlasolmu [ v 2, 5]. Solmu v 2 kuuluu joukkoon U 0, 2, koska jälleen on suortettu redusont tyhjään sääntöön perustuen. Tomnta LR()-jäsennystaulun kohdassa (5, a) on redusoda säännön A ::= ε mukaan. Tomnta LR()-jäsennystaulun kohdassa (5, A) on g5, joten luodaan uus tlasolmu [ v 3, 5], joka lsätään joukkoon U 0, 3, koska on suortettu redusont tyhjään sääntöön perustuen (kuva 6.9).
38 Kuva 6.9. Redusont sääntöön A ::= ε perustuen. Suorttamalla redusont solmusta v 3 joudutaan jälleen luomaan uus aljoukko U 0, 4, johon latetaan tlasolmu [ v 4, 5]. Koska aljoukot ssältävät tlan 5, josta redusomalla joudutaan luomaan uus aljoukko tlalla 5, e tämä prosess pääty koskaan (kuva 6.20). Kuva 6.8. Päättymätön slmukka Tomtan algortmssa 2.
39 7. Farshn algortm Nav ratkasu tlanteeseen, jossa uus polku luodaan keskelle olemassaolevaa polkua, on tutka uudestaan kakk solmut joukosta U, jotka evät ole enää joukossa A. Nästä etstään redusonnt, jotka vovat käyttää alpolkunaan uutta polkua. Farshn [NF9] muunnos Tomtan algortmsta käyttää tätä menetelmää. Algortm 4. Farshn ylestetty LR-jäsennysalgortm kontekstttomlle kelopelle [NF9]. JÄSENNÄ(G, a...an ) { Γ : = θ a n+ : = $ r : = EPÄTOSI luo solmu v 0 merkllä s 0 U 0 : = { v 0 jokaselle, 0 n, suorta JÄSENNÄ_SANA palauta r JÄSENNÄ_SANA { A : = U R := θ, Q := θ tosta jos A θ suorta TOIMIJA muuten jos R θ suorta VIIMEISTELIJÄ kunnes R = θ ja A = θ suorta SIIRTÄJÄ TOIMIJA { posta joukosta A elementt v jokaselle α LR()-jäsennystaulun kohdassa (TILA(v), a + ) { jos α = hyväksy r : = TOSI jos α = srrä s lsää (v, s) joukkoon Q jos α = reduso p { olkoon m säännön p okean puolen ptuus jokaselle sellaselle solmulle w, joka 2m ptusen polun päässä solmusta v /* tyhjlle säännölle w = v */ lsää (w, p) joukkoon R