Ohjelmointikielten syntaksista ja semantiikasta

Samankaltaiset tiedostot
815338A Ohjelmointikielten periaatteet

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset

FORMAALI SYSTEEMI (in Nutshell): aakkosto: alkeismerkkien joukko kieliopin määräämä syntaksi: sallittujen merkkijonojen rakenne, formaali kuvaus

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 3. joulukuuta 2015

11.4. Context-free kielet 1 / 17

Ongelma(t): Miten jollakin korkeamman tason ohjelmointikielellä esitetty algoritmi saadaan suoritettua mikro-ohjelmoitavalla tietokoneella ja siinä

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 9. lokakuuta 2016

8. Kieliopit ja kielet

Yhteydettömät kieliopit [Sipser luku 2.1]

TIEA241 Automaatit ja kieliopit, kevät Antti-Juhani Kaijanaho. 2. helmikuuta 2012

Jäsennys. TIEA341 Funktio ohjelmointi 1 Syksy 2005

ICS-C2000 Tietojenkäsittelyteoria Kevät 2016

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 30. marraskuuta 2015

Attribuuttikieliopit

uv n, v 1, ja uv i w A kaikilla

Luku 3. Syntaktisia kysymyksiä. 3.1 Lausekkeet

5.5 Jäsenninkombinaattoreista

TIES542 kevät 2009 Denotaatio

Vasen johto S AB ab ab esittää jäsennyspuun kasvattamista vasemmalta alkaen:

TIEA241 Automaatit ja kieliopit, kevät 2011 (IV) Antti-Juhani Kaijanaho. 19. tammikuuta 2012

Säännöllisten kielten sulkeumaominaisuudet

8. Kieliopit ja kielet 1 / 22

TIEA241 Automaatit ja kieliopit, kevät Antti-Juhani Kaijanaho. 12. kesäkuuta 2013

2. Yhteydettömät kielet

Aloitus. TIEA241 Automaatit ja kieliopit, kevät 2011 (IV) Antti-Juhani Kaijanaho. 14. maaliskuuta 2011 TIETOTEKNIIKAN LAITOS. Aloitus.

TIEA241 Automaatit ja kieliopit, kevät Antti-Juhani Kaijanaho. 16. helmikuuta 2012

tään painetussa ja käsin kirjoitetussa materiaalissa usein pienillä kreikkalaisilla

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 3. lokakuuta 2016

jäsentäminen TIEA241 Automaatit ja kieliopit, syksy 2015 Antti-Juhani Kaijanaho 26. marraskuuta 2015 TIETOTEKNIIKAN LAITOS

MS-A0402 Diskreetin matematiikan perusteet

Lisää pysähtymisaiheisia ongelmia

Yhteydettömän kieliopin jäsennysongelma

Kontekstittomat jäsennysmenetelmät

811120P Diskreetit rakenteet

ITKP102 Ohjelmointi 1 (6 op)

T Syksy 2002 Tietojenkäsittelyteorian perusteet Harjoitus 8 Demonstraatiotehtävien ratkaisut

Algoritmit 1. Luento 3 Ti Timo Männikkö

S BAB ABA A aas bba B bbs c

Säännölliset kielet. Sisällys. Säännölliset kielet. Säännölliset operaattorit. Säännölliset kielet

Rekursiiviset palautukset [HMU 9.3.1]

Muodolliset kieliopit

Chomskyn hierarkia ja yhteysherkät kieliopit

Ei-yhteydettömät kielet [Sipser luku 2.3]

Laskennan mallit (syksy 2010) Harjoitus 8, ratkaisuja

Rajoittamattomat kieliopit (Unrestricted Grammars)

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

jäsentämisestä TIEA241 Automaatit ja kieliopit, syksy 2015 Antti-Juhani Kaijanaho 27. marraskuuta 2015 TIETOTEKNIIKAN LAITOS

ALKEIS-kielen semantiikan aksiomaattinen määrittely

TIEA241 Automaatit ja kieliopit, kevät 2011 (IV) Antti-Juhani Kaijanaho. 29. huhtikuuta 2011

Syntaksi. TIE448 Kääntäjätekniikka, syksy Antti-Juhani Kaijanaho. 22. syyskuuta 2009 TIETOTEKNIIKAN LAITOS. Syntaksi. Aluksi.

811120P Diskreetit rakenteet

815338A Ohjelmointikielten periaatteet Harjoitus 7 Vastaukset

TIEA241 Automaatit ja kieliopit, kevät 2011 (IV) Antti-Juhani Kaijanaho. 31. maaliskuuta 2011

Täydentäviä muistiinpanoja kontekstittomien kielioppien jäsentämisestä

TIEA241 Automaatit ja kieliopit, kevät 2011 (IV) Antti-Juhani Kaijanaho. 31. maaliskuuta 2011

jäsennyksestä TIEA241 Automaatit ja kieliopit, syksy 2016 Antti-Juhani Kaijanaho 29. syyskuuta 2016 TIETOTEKNIIKAN LAITOS Kontekstittomien kielioppien

PERL. TIE Principles of Programming Languages. Ryhmä 4: Joonas Lång & Jasmin Laitamäki

ELM GROUP 04. Teemu Laakso Henrik Talarmo

Todistus: Aiemmin esitetyn mukaan jos A ja A ovat rekursiivisesti lueteltavia, niin A on rekursiivinen.

Sisällys. 3. Muuttujat ja operaatiot. Muuttujat ja operaatiot. Muuttujat. Operaatiot. Imperatiivinen laskenta. Muuttujat. Esimerkkejä: Operaattorit.

TIEA241 Automaatit ja kieliopit, kesä Antti-Juhani Kaijanaho. 10. kesäkuuta 2013

3. Muuttujat ja operaatiot 3.1


Jäsennysalgoritmeja. TIE448 Kääntäjätekniikka, syksy Antti-Juhani Kaijanaho. 29. syyskuuta 2009 TIETOTEKNIIKAN LAITOS. Jäsennysalgoritmeja

T Syksy 2004 Logiikka tietotekniikassa: perusteet Laskuharjoitus 7 (opetusmoniste, kappaleet )

4. Lausekielinen ohjelmointi 4.1

811120P Diskreetit rakenteet

811120P Diskreetit rakenteet

etunimi, sukunimi ja opiskelijanumero ja näillä

A ja B pelaavat sarjan pelejä. Sarjan voittaja on se, joka ensin voittaa n peliä.

Automaatit. Muodolliset kielet

Hahmon etsiminen syotteesta (johdatteleva esimerkki)

TIEA241 Automaatit ja kieliopit, kesä Antti-Juhani Kaijanaho. 26. kesäkuuta 2013

arvostelija JavaCC Petri Kärki Helsinki 15. huhtikuuta 2005 Seminaarityö HELSINGIN YLIOPISTO Tietojenkäsittelytieteen laitos

Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005

ICS-C2000 Tietojenkäsittelyteoria. Tähän mennessä: säännölliset kielet. Säännöllisten kielten pumppauslemma M :=

Täydentäviä muistiinpanoja jäsennysalgoritmeista

Palautetta viime luennosta

Jos sekaannuksen vaaraa ei ole, samastamme säännöllisen lausekkeen ja sen esittämän kielen (eli kirjoitamme R vaikka tarkoitammekin L(R)).

Äärellisten automaattien ja säännöllisten kielten ekvivalenssi

Ohjelmoinnin peruskurssien laaja oppimäärä

on rekursiivisesti numeroituva, mutta ei rekursiivinen.

2) Aliohjelma, jonka toiminta perustuu sivuvaikutuksiin: aliohjelma muuttaa parametrejaan tai globaaleja muuttujia, tulostaa jotakin jne.

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

Vaihtoehtoinen tapa määritellä funktioita f : N R on

811312A Tietorakenteet ja algoritmit Kertausta kurssin alkuosasta

Rekursio. Funktio f : N R määritellään yleensä antamalla lauseke funktion arvolle f (n). Vaihtoehtoinen tapa määritellä funktioita f : N R on

ICS-C2000 Tietojenkäsittelyteoria

JOHDATUS TEKOÄLYYN TEEMU ROOS

Matematiikan tukikurssi

14.1 Rekursio tyypitetyssä lambda-kielessä

4. Lausekielinen ohjelmointi 4.1

4 Matemaattinen induktio

AS C-ohjelmoinnin peruskurssi 2013: C-kieli käytännössä ja erot Pythoniin

(0 1) 010(0 1) Koska kieli on yksinkertainen, muodostetaan sen tunnistava epädeterministinen q 0 q 1 q 2 q3

Ehto- ja toistolauseet

ITKP102 Ohjelmointi 1 (6 op)

ITKP102 Ohjelmointi 1 (6 op)

Tehtävä 2: Säännölliset lausekkeet

Rekursiiviset tyypit

Transkriptio:

Ohjelmointikielten syntaksista ja semantiikasta Tässä osassa esitellään käsitteet syntaksi ja semantiikka sekä tutustutaan ohjelmointikielen syntaksin kuvaamismenetelmiin. Esimerkiksi Sebestan ([Seb]) luvuissa 3 ja 4 ja Harsun kirjan [Har] luvussa 2 käsitellään seuraavassa esitettäviä asioita. 1. Kielen syntaksi ja semantiikka käsitteinä Ohjelmointikieltä määriteltäessä tarvitaan täsmällinen ja helposti ymmärrettävä kuvaus kielestä. Tämä on tärkeää sekä kieltä toteutettaessa että käytettäessä kieltä ohjelmointiin. On kuvattava kielen rakenne ja kielen konstruktioiden merkitys. Ensin mainittu koskee kielen syntaksia ja jälkimmäinen sen semantiikkaa. Kielen syntaksi (syntax) on sen rakenne. Syntaksi määrittelee ne säännöt, joiden perusteella kielen lailliset ilmaukset voidaan muodostaa. Semantiikka (semantics) määrittelee puolestaan näiden ilmauksien merkityksen. Esimerkiksi C-kielen if-lauseen syntaksi (ilman else -osaa) on if(<expression>) <statement> Tämän lauseen semantiikka on puolestaan seuraava: Jos lausekkeen <expression> arvo ei ole nolla, niin lause <statement> suoritetaan. Jos lausekkeen arvo on nolla, lausetta ei suoriteta. Ohjelmointikielen syntaksin formaalia määritelmää kutsutaan (analogisesti luonnollisen kielen kanssa) kieliopiksi (grammar). Kielten syntaksin formaaliin esittämiseen käytetään yleisesti kontekstista riippumattomia (context-free, kontekstivapaita, yhteysriippumattomia jne) kielioppeja. Sen sijaan semantiikan formaaliin kuvaamiseen ei ole olemassa yhtä yleisesti hyväksyttyä tapaa. Tässä käsitellään pääasiassa syntaksin esittämistä mainittujen kielioppien avulla.

2. BNF -kieliopit Tunnetuin formaali kielioppi kehitettiin vuonna 1960 kuvaamaan ALGOL -kielen syntaksia; kielioppi nimettiin kehittäjiensä mukaan BNF:ksi (Backus-Naur Form). Hieman aiemmin (vuonna 1959) kieliteoreetikko Noam Chomsky oli kehittänyt kontekstista riippumattoman kieliopin. Voidaan osoittaa, että itse asiassa molemmat kieliopit ovat ekvivalentit, ts. ne määrittelevät täsmälleen saman asian, ainoa ero on merkintätapa. Tästä syystä termejä "kontekstista riippumaton kielioppi" ja "BNF - kielioppi" käytetään synonyymeina. Tässä käytetään enimmäkseen termiä "BNF - kielioppi", koska kielen syntaksi kuvataan BNF:n avulla. Nimitystä "kontekstista riippumaton kielioppi" käytetään, koska tällaisella kieliopilla kuvataan kieli, jonka määrittelyt eivät saa riippua siitä yhteydestä, missä ne esitetään. BNF -kielioppi muodostetaan äärellisestä joukosta kielioppisääntöjä, jotka yhdessä määrittelevät (formaalin) kielen. Tässä pyritään luonnollisesti kuvaamaan ohjelmointikieliä. Huomaa, että syntaktisesti kuvataan ainoastaan muodollisesti oikein muodostettuja ohjelmia, semanttisesti tällaiset voivat olla täysin mielettömiä. Aluksi tarvitaan määrittely kielelle: Määritelmä. Kieli on joukko äärellisen pituisia jonkin aakkoston sanoja (merkkijonoja). Tämä määrittely pitää siis sisällään sen, että aakkosto on kiinnitettävä etukäteen ja saadaan muodostaa ainoastaan äärellisen mittaisia sanoja. Määrittelyn perusteella mikä tahansa ohjelmointikieli (esimerkiksi FORTRAN, C tai Java) on kieli, aakkostona on yleensä ASCII- tai UNICODE-merkistö. Kielen pienimmät perusosaset eli lekseemit (tekstialkiot, leksikaaliset sanat, lexemes) jätetään usein pois kielen formaalista kuvauksesta yksinkertaisuuden vuoksi; nämä voidaan luetella sanakirjamaisesti erillään syntaktisesta kuvauksesta. Ohjelmointikielen lekseemeihin kuuluvat tunnisteet (identifiers), literaalit (literals), operaattorit (operators),

erikoissanat (special words, key words) ja erikoissymbolit (special symbols). Literaalit ovat erityyppisten vakioiden arvoja. Ne voivat olla siis esimerkiksi kokonaislukuvakioita, merkkijonovakioita jne. Lekseemien kategorioita kutsutaan alkionimiksi (sanaset, tokens). Lekseemit ovat siis alkionimien ilmentymiä. Varatut sanat ovat erikoissanojen erikoistapaus. Kielen leksikaalinen rakenne on kuitenkin läheisesti sidoksissa syntaktisen rakenteeseen. Syntaksin tarkistus tapahtuu yleensä niin, että kielen selausvaiheessa (scanning phase) kerätään lekseemit ja jäsentelyvaiheessa (parsing) tarkistetaan varsinainen syntaktinen rakenne. Esimerkiksi C-kielen lauseessa if( luku < 0) luku++; lekseemi alkionimi if erikoissana ( erikoissymboli luku tunniste < erikoissymboli 0 literaali ) erikoissymboli + operaattori ; erikoissymboli Kielen kuvauksessa tarvitaan jonkinlainen metakieli, jonka avulla kuvataan kohdekieltä. Näin ollen on tärkeää erottaa metakielen ja kuvattavan kielen symbolit toisistaan. Kontekstista riippumaton kielioppi koostuu joukosta kielioppisääntöjä, joiden vasemmalla puolella esiintyy ainoastaan määriteltävään rakenteen nimi, vasemman ja oikean puolen erotinmerkkinä toimii symboli ::= ja oikealla puolella voi esiintyä symboleita ja rakenteen nimiä. Rakenteiden nimiä, jotka yleensä esitetään kulmasulkeiden sisällä (<rakenne>), nimitetään välisymboleiksi eli nonterminaaleiksi, koska ne hajaantuvat edelleen pienempiin osiin. Kielen lekseemejä kutsutaan loppusymboleiksi eli terminaaleiksi, sillä ne eivät enää hajaannu pienempiin osiin.

Kielioppisääntöjä sanotaan myös produktioiksi, koska ne tuottavat kieleen kuuluvat merkkijonot johtamalla ne säännöistä. Puhtaassa BNF:ssä käytetään ainoastaan seuraavia metasymboleja: < > ::= Kolmen ylimmän symbolin merkitys on kerrottu yllä ja symboli ilmaisee vaihtoehtoa: Tällä symbolilla erotettuja termejä voidaan jompaakumpaa käyttää johdossa. Rakenteiden määrittely voi olla rekursiivista, ts. sama rakenteen nimi voi esiintyä säännössä sekä oikealla että vasemmalla puolella. Esimerkiksi kymmenjärjestelmän etumerkittömät luvut voitaisiin määritellä syntaktisesti seuraavasti: <luku> ::= <luku><numero> <numero> <numero> ::= 0 1 2 3 4 5 6 7 8 9 Huomaa kuitenkin, että esimerkiksi 000131 on laillisesti johdettu luku (ohjelmointikielet myös yleensä sallivat lukujen esittämisen näin). Tällä yksinkertaisella merkintätavalla voidaan kuvata ohjelmointikielten syntakseja. Mukavuuden vuoksi usein käytetään laajennettua BNF:ää (extended BNF, EBNF), johon on lisätty metasymbolit [ ] { } Näiden merkitys on seuraava: [] tarkoittaa sulkujen sisällä olevan lausekkeen vapaaehtoista valintaa, ts. määrittelyssä

<sana> ::= x[y] sana voi olla x tai xy. Edelleen {} tarkoittaa sulkujen sisällä olevan lausekkeen esiintymistä 0 tai useampi kertaa, ts. nyt määrittelyssä <sana> ::= x{y} sana voi olla x, xy, xyy, xyyy, jne. Laajennetussa BNF:ssä voidaan myös käyttää sulkuja ryhmittelyyn. Muitakin helpottavia merkintöjä saatetaan käyttää EBNF:ksi nimitettävissä esityksissä. Esimerkki. C-kielen if -lause voidaan kuvata seuraavasti: <if_stmt> ::= if(<expr>) <stmt>[else <stmt>]; Tässä määrittelyssä pitää luonnollisesti antaa myöhemmin säännöt välisymboleille <expr> ja <stmt>. Valintatilanteessa voidaan käyttää myös metakielessä sulkuja; esimerkkinä Pascal - kielen for-lause <for_stmt> ::= for <var> := <expr> (to downto) <expr> do <stmt>; Kielen kaikki syntaktisesti oikeat lauseet voidaan johtaa kielioppisäännöistä; johtaminen tapahtuu lähtien liikkeelle jostakin kieliopin säännöstä ja korvaamalla välisymboleita joillakin määrittelyillään. Kontekstista riippumattoman kieliopin tapauksessa kaikki vaihtoehtoiset määrittelyt sallitaan kaikissa yhteyksissä.

Esimerkiksi jossakin ohjelmointikielessä sijoituslause yhteen- ja kertolaskua sisältäville aritmeettisille operaatioille voitaisiin määritellä seuraavasti: <assign> ::= <id> = <expr> <id> ::= X Y Z <expr> ::= <id> + <expr> <id> * <expr> (<expr>) <id> Tällöin lause X = X*(Y+Z) voitaisiin johtaa seuraavasti: <assign> -> <id> = <expr> -> X = <expr> -> X = X*<expr> -> X = X*(<expr>) -> X = X*(<id> + <expr>) -> X = X*(Y + <expr>) -> X = X*(Y + <id>) -> X = X*(Y + Z) Lauseen johtaminen voidaan myös esittää graafisesti johtopuuna (parse tree). Tällöin nähdään lauseiden hierarkkinen rakenne selvemmin. Esimerkiksi yllä olevan sijoituslauseen johtopuu olisi

Kielioppia sanotaan monikäsitteiseksi (ambiguous), mikäli samalla lauseella on useita erilaisia johtopuita. Jos sijoituslauseen kielioppia muutettaisiin hieman, esimerkiksi muotoon <assign> ::= <id> = <expr> <id> ::= X Y Z <expr> ::= <id> + <expr> <expr> * <expr> (<expr>) <id> seurauksena olisi monikäsitteinen kielioppi, nimittäin esimerkiksi lauseella X = X + Y*Z on kaksi erilaista johtopuuta (muodosta ne!). Tämä on ongelmallista, sillä kääntäjät pohjaavat usein semanttisen tulkinnan syntaktiseen muotoon. Esimerkiksi tässä tapauksessa kielioppi ei kerro, suoritetaanko laskutoimitus muodossa (X+Y)*Z vai (kuten aritmeettisten sääntöjen nojalla on oikein) X+(Y*Z). Vaikka kielioppi ei

olisikaan monikäsitteinen, sama lause voidaan yleensä johtaa eri tavoin; tällöin kuitenkin näitä kaikkia vastaa sama jäsennyspuu. 3. Syntaksikaaviot BNF:n ja EBNF:n säännöt voidaan esittää myös graafisessa muodossa ns. syntaksikaaviona (syntax graph, syntax diagram) avulla. Tällöin käytetään suunnattua polkua, jossa kieliopin loppusymbolit ja välisymbolit merkitään solmuiksi. Loppusymbolien nimet kirjoitetaan ovaaleihin ja välisymbolit suorakaiteisiin seuraavasti Muotonsa vuoksi syntaksikaavioita kutsutaan myös ratapihakaavioiksi. Vaihtoehtoinen toiminto esitetään kirjoittamalla vaihtoehdot rinnakkain, esimerkiksi säännöt X1 X2 ja {YN} kirjoitetaan Näin saadaan esimerkiksi Pascal-kielen case-lause

<case_stmt> ::= CASE <expression> OF <case_list> [;] END <case_list> ::= {<const_list>: <stmt>;}<const_list>: <stmt> <const_list> ::= <const> {, <const>} muunnettua syntaksikaavioksi Huomaa, että kielioppisääntö sisältää vielä kolme välisymbolia (expression, stmt, const), joille tulisi myös antaa säännöt. Seuraavassa listauksessa on esimerkki syntaktisesti oikeasta Pascal-kielisestä case-lauseesta Case SELECTION of 1 : Begin Writeln('Selection one'); End; 2 : Begin Writeln('Selection two'); End; 3,4 : Begin Writeln('Selection three'); End; End; Edellä SELECTION tunnistetaan lausekkeeksi ja jäsennetään välisymbolilla expression. Vakiot 1, 2, 3 ja 4 tunnistetaan ensin ensin välisymboliin const_list kuuluviksi ja lopuksi ne jäsennetään välisymbolilla const. Erikoissana Begin aloittaa ja End lopettaa lauseen, joten näiden muodostamat kokonaisuudet jäsennetään välisymbolilla stmt.

Edellä kuvatun graafisen esityksen etuja on mm. se, että syntaksidiagrammia voidaan käyttää varsin suoraviivaisesti kirjoitettaessa jäsentäjä (parser, syntax analyzer) kieliopille. 4. Jäsentäjät Seuraavaksi käsitellään lyhyesti erilaisia tapoja konstruoida jäsentäjä. Ohjelmointikieli voi olla käännettävä, tulkattava tai hybridi. Käännettävästä kielestä muodostetaan erityisen ohjelman, kääntäjän (compiler) avulla konekielinen ohjelma, joka sitten suoritetaan. Tulkattavalla kielellä kirjoitetun ohjelman ajaa erillinen tulkki (interpreter) suoraan ohjelmointikielellä kirjoitetusta koodista. Hybridisysteemissä kääntäjä muodostaa ohjelmasta välimuodon, joka tulkataan. Esimerkiksi Java on hybridikieli: alkuperäinen ohjelma käännetään tavukoodiksi, jonka Javan virtuaalikone suorittaa. Kaikki käännettävät kielet tarvitsevat jäsentäjän osana kääntäjää. Lähes poikkeuksetta kääntäjät jakavat syntaksianalyysin leksikaaliseen analyysiin ja varsinaiseen jäsentämiseen. Leksikaalinen analyysi toimii jäsentämisen esioperaationa ja on oikeastaan osa jäsentämistä. Leksikaalinen analysoija on pääasiassa hahmontunnistaja: se poimii ohjelmasta lekseemit ja tunnistaa niiden tyypin, ts. mistä alkionimestä on kysymys. Yleensä alkionimille käytetään (nimettyjä) kokonaislukutunnistetta jäsentäjän sisällä. Esimerkkinä ohjelmointikielen sijoituslause luku = toinen_luku + 25; lekseemi alkionimi luku IDENT (tunniste) = ASSIGN_OP (operaattori) toinen_luku IDENT (tunniste) + PLUS_OP (operaattori) 25 INT_LIT (literaali) ; SEMICOLON (erikoissymboli)

Tässä ei puututa lähemmin leksikaalisen analyysin toteutukseen; periaatteessa kysymys on kuitenkin varsin suoraviivaisesta hahmontunnistusongelmasta. Seuraavassa oletetaan, että käytössä on funktio, joka hakee jäsennettävästä merkkijonosta seuraavan lekseemin ja sijoittaa sen globaaliin muuttujaan sekä paluuarvonaan (kokonaisluku) antaa alkionimen tyyppikoodin. Jäsentäjän tehtävä on konstruoida syötteenä saamalleen ohjelmalle jäsennyspuu; yksinkertaisimmillaan jäsentäjä toimii vain syntaksin tarkastajana, ts. se tutkii ainoastaan, onko ohjelma syntaktisesti oikein muodostettu. Virhetilanteessa jäsentäjän on luonnollisesti raportoitava asianmukaisesti havaitusta virheestä. Jäsentäjät jaetaan kahteen pääluokkaan sen mukaan, miten jäsennyspuu rakennetaan. Osittavat (ylätasolta lähtevät) jäsentäjät (top-down parsers) etenevät puun juuresta lehtiin päin, kun taas kokoavat (alatasolta lähtevät) jäsentäjät (bottom-up parsers) rakentavat puun päinvastaisessa järjestyksessä. Kaikki yleisesti käytettävät jäsentäjät toimivat kuitenkin siinä suhteessa samalla periaatteella, että ne tutkivat ainoastaan yhden lekseemin eteenpäin kerrallaan. Kokoavien jäsentäjien ideana on sovittaa käsiteltävän merkkijonon loppuosa (oikea puoli) jonkin kielioppisäännön oikeaan puoleen ja tämä redusoidaan sitten kyseisen säännön vasemmaksi puoleksi, minkä vuoksi jäsennystä kutsutaan myös LRjäsennykseksi. Sebestan kirjan [Seb] luvussa 4.5 on käsitelty tarkemmin tällaisia jäsentäjiä. Osittavat jäsentäjät toimivat päinvastoin: ne päättelevät merkkijonon vasemmasta päästä lähtien, onko tutkittava lauseke loppu- vai välisymboli ja redusoivat välisymbolit sovittaen ne sopivan kielioppisäännön vasemmaksi puoleksi. Tällöin jäsennystä sanotaan LL-jäsennykseksi. (Ks myös [Har], 2.4) (E)BNF:n tai vastaavan syntaksikaavion avulla esitetylle kieliopille luonnollisimmin rakentuu jäsentäjä, joka noudattaa osittavaa ns. rekursiivisesti etenevää (rekursiivisesti laskeutuvaa, recursive descent) algoritmia. EBNF sopii erityisen hyvin rekursiivisesti etenevän jäsentäjän konstruoimiseen. Tällaisessa jäsentäjässä on kokoelma (yleensä rekursiivisia) funktioita, jotka tuottavat jäsennyspuun ylhäältä lähtien. Tarvitaan leksikaalinen analysoija (aiemmin mainittu funktio ) ja jokaista kieliopin välisymbolia kohti oma funktio, joka käsittelee kyseisen välisymbolin. Esimerkki valaisee asiaa. Rakennetaan aiemmin esitetylle Pascal -kielen case -lauseelle rekursiivisesti etenevä jäsentäjä. Oletetaan, että ohjelmassa on funktio,

joka hakee jäsennettävästä merkkijonosta seuraavan lekseemin ja sijoittaa sen globaaliin muuttujaan sym. Oletetaan lisäksi, että välisymboleille "expression", "const" ja "stmt" on kullekin oma funktio, joka huolehtii kyseisen kielioppisäännön tarkastamisesta. Oletetaan vielä, että virhetilanteessa kutsutaan metodia error(). Tällöin pseudokoodi yllä olevan case -lauseen jäsentämiseksi voisi olla PROGRAM CASE_STATEMENT String sym if( sym!= "CASE") error() else expression() ; if( sym!= "OF") error() else case_list() if(sym!= "END") error() function case_list() const_list() if(sym!= ":") error() else stmt() if(sym == ";") if(sym!= "END") case_list() else if(sym!= "END") error()

function const_list() const() if(sym ==",") const_list() else if(sym!= ":") error() function expression() // Parse expression according to rule const() // Parse const according to rule stmt () // Parse statement according to rule END PROGRAM CASE_STATEMENT Rekursiivisesti etenevä menetelmä on varsin tehokas, mutta sisältää erään rajoituksen: kielioppisäännöt eivät saa sisältää vasemmanpuoleista rekursiota. Esimerkiksi säännön <expr> ::= <expr> + <term> <term> ::= muuntaminen jäsentäjäksi johtaisi seuraavan kaltaiseen ohjelmaan:

PROGRAM EXPR String sym expr(); function expr() expr() ; if( sym == "+") term() else error() function term() // Parse term END PROGRAM EXPR Nyt huomataan välittömästi, että funktion expr() kutsuminen johtaa päättymättömään rekursioon. Ahon, Sethin ja Ullmanin kirjassa ([Aho]) kääntäjiä ja niiden toteutusalgoritmeja käsitellään laajasti. Tässä on ainoastaan pyritty antamaan pintapuolinen kuva kielen syntaksin ja jäsennysprosessin välisestä yhteydestä. 4. Semantiikka Palataan vielä lopuksi lyhyesti ohjelmointikielten semantiikkaan. Usein puhutaan staattisesta ja dynaamisesta semantiikasta. Näistä oikeastaan ainoastaan dynaaminen semantiikka on varsinaista semantiikkaa, ts. ohjelmointikielen merkitysoppia. Staattisen semantiikan ongelmat eivät liity merkitykseen vaan koskevat paremminkin ohjelmien sallittua muotoa (ts. lähestyvät syntaktisia kysymyksiä). Staattisen semantiikan kysymykset ovat sellaisia muotoseikkoja, joita on vaikea tai mahdoton kuvata BNF:n avulla. Esimerkiksi vaatimus siitä, että muuttuja on määriteltävä ennen arvon sijoittamista siihen, on tällainen ominaisuus. Staattisen semantiikan nimitys johtuu siitä, että sen vaatimukset voidaan tarkistaa jo käännösaikana. Varsinainen eli dynaaminen semantiikka on varsin hankala aihe. Ei nimittäin ole yleisesti hyväksyttyä formaalia järjestelmää kuvaamaan ohjelmien merkitysoppia.

Luonnollisesti ohjelmointikielen määrittelyn yhteydessä sen konstruktioiden merkitys olisi tarkasti kuvattava. Yleensä tämä kuitenkin tapahtuu luonnollista kieltä käyttämällä eikä formaalisti. Usein semantiikka jaetaan tarkastelunäkökulman perusteella operationaaliseen, denotationaaliseen ja aksiomaattiseen semantiikkaan. Tässä ei paneuduta ohjelmointikielten merkitysoppiin syvällisemmin vaan tyydytään kuvaamaan kyseiset käsitteet. Operationaalinen semantiikka pyrkii kuvaamaan annetun ohjelman merkityksen suorittamalla ohjelman joko reaalisessa tai virtuaalisessa tietokoneessa; koneen tilat ohjelman suorituksen aikana määrittelevät tällöin ohjelman merkityksen. Formaalia operationaalista semantiikkaa käytettiin ohjelmointikielen PL/I merkitysopin kuvaamiseen jo 1960-luvulla. Tämä semantiikan laji pohjautuu algoritmeihin eikä niinkään matemaattiseen esitykseen; operationaalinen semantiikka voi olla hyödyllinen tapa kuvata merkitysoppi kielen käyttäjille ja toteuttajille, kunhan esitystapa pidetään riittävän selkeänä ja yksinkertaisena. Aksiomaattinen semantiikka kehitettiin, kun pyrittiin konstruoimaan menetelmä todistaa ohjelmien korrektisuutta. Nimensä mukaisesti aksiomaattinen semantiikka pohjautuu matemaattiseen logiikkaan. Aksiomaattisen semantiikan tuntemus voi olla hyödyksi ohjelmoijalle, jonka on todistettava aukottomasti ohjelmansa korrektius. Myös denotationaalinen semantiikka perustuu matematiikkaan, nimittäin rekursiivisten funktioiden teoriaan. Yleisesti katsotaan, että tämä semantiikan muoto kuvaa käytettävistä menetelmistä tarkimmin ohjelmien merkitysopin. Denotationaalisen semantiikan avulla lähes mikä tahansa ohjelmointikielen piirre voidaan kuvata matemaattisen funktion avulla. Denotationaalista semantiikkaa voidaan käyttää hyödyksi ohjelmointikielten suunnittelussa; ohjelmoijan kannalta sitä ei voitane pitää erityisen käyttökelpoisena. Sebesta ([Seb]) käsittelee hieman perusteellisemmin semantiikan kysymyksiä kirjansa luvussa 3.5. (Ks. myös [Har], 2.5 ja 2.6)

Lähteet [Aho] Aho, A.V., Sethi, R. & Ullman, J.D. Compilers: Principles, Techniques and Tools. Addison-Wesley 1986. [Har] Harsu, Maarit. Ohjelmointikielet, Periaatteet, käsitteet, valintaperusteet, Talentum 2005. [Seb] Sebesta, Robert W. Concepts of Programming Languages 10th edition, Pearson 2013.