Opiskelumateriaali - Syntaksi ja semantiikka
Transcription
Opiskelumateriaali - Syntaksi ja semantiikka
Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Syntaksi ja semantiikka 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. 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. Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Syntaksi ja semantiikka 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), Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Syntaksi ja semantiikka 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. Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Syntaksi ja semantiikka 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ä Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Syntaksi ja semantiikka <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ä. Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Syntaksi ja semantiikka 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 Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Syntaksi ja semantiikka 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 Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Syntaksi ja semantiikka 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 Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Syntaksi ja semantiikka <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. Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Syntaksi ja semantiikka 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 luku = toinen_luku + 25 ; alkionimi IDENT (tunniste) ASSIGN_OP (operaattori) IDENT (tunniste) PLUS_OP (operaattori) INT_LIT (literaali) SEMICOLON (erikoissymboli) Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Syntaksi ja semantiikka Tässä ei puututa lähemmin leksikaalisen analyysin toteutukseen; periaatteessa kysymys on kuitenkin varsin suoraviivaisesta hahmontunnistusongelmasta. Seuraavassa oletetaan, että käytössä on funktio GetToken(), 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 laskeutuvaa (recursive descent) algoritmia. EBNF sopii erityisen hyvin rekursiivisesti laskeutuvan 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 GetToken()) 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 laskeutuva jäsentäjä. Oletetaan, että ohjelmassa on funktio GetToken(), Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Syntaksi ja semantiikka 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 GetToken() if( sym != "CASE") error() else GetToken() expression() GetToken(); if( sym != "OF") error() else GetToken() case_list() if(sym != "END") error() return function case_list() const_list() if(sym != ":") error() else GetToken() stmt() GetToken() if(sym == ";") GetToken() if(sym != "END") case_list() else if(sym != "END") error() return Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Syntaksi ja semantiikka function const_list() const() GetToken() if(sym ==",") GetToken() const_list() else if(sym != ":") error() return function expression() // Parse expression according to rule return const() // Parse const according to rule return stmt () // Parse statement according to rule return END PROGRAM CASE_STATEMENT Rekursiivisesti laskeutuva 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: Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Syntaksi ja semantiikka PROGRAM EXPR String sym GetToken() expr(); return function expr() expr() GetToken(); if( sym == "+") GetToken() term() else error() return function term() // Parse term return 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. Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Syntaksi ja semantiikka 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) Ari Vesanen, Tietojenkäsittelytieteiden laitos, Oulun yliopisto 815338A Ohjelmointikielten periaatteet: Syntaksi ja semantiikka 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.