Staattinen metaohjelmointi

Samankaltaiset tiedostot
ELM GROUP 04. Teemu Laakso Henrik Talarmo

Metaohjelmointia ja muuta hauskaa

Haskell ohjelmointikielen tyyppijärjestelmä

TIE PRINCIPLES OF PROGRAMMING LANGUAGES Eiffel-ohjelmointikieli

Chapel. TIE Ryhmä 91. Joonas Eloranta Lari Valtonen

Tyyppiluokat II konstruktoriluokat, funktionaaliset riippuvuudet. TIES341 Funktio-ohjelmointi 2 Kevät 2006

11/20: Konepelti auki

Algoritmit 1. Luento 3 Ti Timo Männikkö

Concurrency - Rinnakkaisuus. Group: 9 Joni Laine Juho Vähätalo

C-ohjelmoinnin peruskurssi. Pasi Sarolahti

Operaattoreiden ylikuormitus. Operaattoreiden kuormitus. Operaattoreiden kuormitus. Operaattoreista. Kuormituksesta

Ohjelmistojen mallintaminen

TIE Principles of Programming Languages CEYLON

58131 Tietorakenteet ja algoritmit (syksy 2015)

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

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset

15. Ohjelmoinnin tekniikkaa 15.1

4. Luokan testaus ja käyttö olion kautta 4.1

TIES542 kevät 2009 Tyyppijärjestelmän laajennoksia

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen

Groovy. Niko Jäntti Jesper Haapalinna Group 31

Tietorakenteet ja algoritmit

Imperatiivisen ohjelmoinnin peruskäsitteet. Meidän käyttämän pseudokielen lauseiden syntaksi

Tietorakenteet ja algoritmit - syksy

Dart. Ryhmä 38. Ville Tahvanainen. Juha Häkli

Common Lisp Object System

ITKP102 Ohjelmointi 1 (6 op)

Ohjelmoinnin peruskurssien laaja oppimäärä

15. Ohjelmoinnin tekniikkaa 15.1

lausekkeiden tapauksessa. Jotkin ohjelmointikielet on määritelty sellaisiksi,

Algoritmit 2. Luento 8 To Timo Männikkö

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

Koka. Ryhmä 11. Juuso Tapaninen, Akseli Karvinen. 1. Taustoja 2. Kielen filosofia ja paradigmat 3. Kielen syntaksia ja vertailua JavaScriptiin Lähteet

815338A Ohjelmointikielten periaatteet Harjoitus 7 Vastaukset

Ohjelmoinnin peruskurssien laaja oppimäärä

D-OHJELMOINTIKIELI. AA-kerho, 33. Antti Uusimäki. Arto Savolainen

Tietorakenteet (syksy 2013)

TIE Principles of Programming Languages. Seminaariesityksen essee. Ryhmä 18: Heidi Vulli, Joni Heikkilä

7. Näytölle tulostaminen 7.1

Osoitin ja viittaus C++:ssa

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

Ohjelmoinnin peruskurssien laaja oppimäärä

Rajoittamattomat kieliopit (Unrestricted Grammars)

Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005

TIEA255 Tietotekniikan teemaseminaari ohjelmointikielet ja kehitysalustat. Antti-Juhani Kaijanaho. 16. helmikuuta 2011

13. Loogiset operaatiot 13.1

Tutoriaaliläsnäoloista

ITKP102 Ohjelmointi 1 (6 op)

Geneeriset luokat. C++ - perusteet Java-osaajille luento 6/7: Template, tyyppi-informaatio, nimiavaruudet. Geneerisen luokan käyttö.

Solidity älysopimus ohjelmointi. Sopimus suuntautunut ohjelmointi

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

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

Ohjelmointikieli TIE Principles of Programming Languages Syksy 2017 Ryhmä 19

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

Ohjelmoinnin perusteet Y Python

Ohjelmointi 1 / syksy /20: IDE

Vertailulauseet. Ehtolausekkeet. Vertailulauseet. Vertailulauseet. if-lauseke. if-lauseke. Javan perusteet 2004

Käännös, linkitys ja lataus

Koottu lause; { ja } -merkkien väliin kirjoitetut lauseet muodostavat lohkon, jonka sisällä lauseet suoritetaan peräkkäin.

12 Mallit (Templates)

ITKP102 Ohjelmointi 1 (6 op)

Alkuarvot ja tyyppimuunnokset (1/5) Alkuarvot ja tyyppimuunnokset (2/5) Alkuarvot ja tyyppimuunnokset (3/5)

TIEA241 Automaatit ja kieliopit, kesä Antti-Juhani Kaijanaho. 29. toukokuuta 2013

Ohjelmoinnin peruskurssien laaja oppimäärä

Lisää pysähtymisaiheisia ongelmia

1. Olio-ohjelmointi 1.1

Satunnaisalgoritmit. Topi Paavilainen. Laskennan teorian opintopiiri HELSINGIN YLIOPISTO Tietojenkäsittelytieteen laitos

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. X Poikkeusten käsittelystä

System.out.printf("%d / %d = %.2f%n", ekaluku, tokaluku, osamaara);

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

Ohjelmoinnin perusteet Y Python

Malliperustainen ohjelmistokehitys - MDE Pasi Lehtimäki

Rekursiolause. Laskennan teorian opintopiiri. Sebastian Björkqvist. 23. helmikuuta Tiivistelmä

Sisällys. 12. Näppäimistöltä lukeminen. Yleistä. Yleistä

Apuja ohjelmointiin» Yleisiä virheitä

Tietorakenteet ja algoritmit

Tietorakenteet ja algoritmit syksy Laskuharjoitus 1

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

Common Language Runtime

5. HelloWorld-ohjelma 5.1

Ruby. Tampere University of Technology Department of Pervasive Computing TIE Principles of Programming Languages

ITKP102 Ohjelmointi 1 (6 op), arvosteluraportti

A TIETORAKENTEET JA ALGORITMIT

Perinteiset tietokoneohjelmat alkavat pääohjelmasta, c:ssä main(), jossa edetään rivi riviltä ja käsky käskyltä.

ITKP102 Ohjelmointi 1 (6 op), arvosteluraportti

ITKP102 Ohjelmointi 1 (6 op), arvosteluraportti

Pythonin alkeet Syksy 2010 Pythonin perusteet: Ohjelmointi, skriptaus ja Python

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Ongelma(t): Miten mikro-ohjelmoitavaa tietokonetta voisi ohjelmoida kirjoittamatta binääristä (mikro)koodia? Voisiko samalla algoritmin esitystavalla

Ohjelmoinnin peruskurssien laaja oppimäärä

4.2. ALIOHJELMAT 71. Tulosvälitteisyys (call by result) Tulosvälitteinen parametri kopioidaan lopuksi

7/20: Paketti kasassa ensimmäistä kertaa

JAVA-PERUSTEET. JAVA-OHJELMOINTI 3op A JAVAN PERUSTEET LYHYT KERTAUS JAVAN OMINAISUUKSISTA JAVAN OMINAISUUKSIA. Java vs. C++?

12. Näppäimistöltä lukeminen 12.1

Ohjelmoinnin perusteet Y Python

Java-kielen perusteita

Visual Basic -sovelluskehitin Juha Vitikka

Luku 6. Dynaaminen ohjelmointi. 6.1 Funktion muisti

Harjoitus 3 (viikko 39)

C++11 lambdat: [](){} Matti Rintala

Transkriptio:

Staattinen metaohjelmointi Karri Kulmala karriku@iki.fi Markus Silván mape@st.jyu.fi Juho Yli-Honkola juylihon@cc.jyu.fi 1 Johdanto Sanakirjassa sana metakieli (metalanguage) määritellään seuraavasti[]: kieli, jonka avulla voidaan määritellä kieliä Esiliite meta merkitsee tässä yhteydessä korkeampaa abstraktiotasoa. Joten ylläoleva määritelmä kuvaa hyvin metaohjelmoinnin olemusta sellaisten ohjelmien tekemistä, joilla kuvataan tai muokataan toisia ohjelmia tai ohjelmaa itseään. (Jälkimmäisessä tapauksessa on kyse refleksiivisyydestä (reflection)). Metaohjelmia voidaan ajaa useissa eri yhteyksissä ja eri aikoina, mutta tämä artikkeli keskittyy ainoastaan staattiseen metaohjelmointiin (static metaprogramming). Staattiset metaohjelmat ovat käännöksen aikana suoritettavia ohjelmia, joilla vaikutetaan varsinaiseen ohjelmaan. Tiivistelmä Tämä artikkeli käsittelee staattisen metaohjelmoinnin historiaa, perusteita ja sovelluksia. Tarkemmin perehdytään aihiometaohjelmointiin C++-kielessä, sekä tutustutaan pintapuolisesti Haskell-kielen staattista metaohjelmointia tukevaan laajennukseen. Kuten johdannossa jo mainittiin, ohjelmat jotka suoritetaan käännöksen aikana ovat staattisia metaohjelmia. Staattista metaohjelmointia ovat esimerkiksi Backus-Naur Form sekä ohjelmointi C/C++-esikääntäjämakroilla. Ohjelmointikielen kääntäjä voidaan ajatella metaohjelmaksi, joka muuttaa syötteenä saamansa ohjelmakoodin esitystavan abstraktiksi syntaksipuuksi, ja sen edelleen johonkin toiseen muotoon, esimerkiksi tavukoodiksi. Staattinen metaohjelmointi mahdollistaa ohjelman mukauttamisen käännösaikana. Esimerkiksi ohjelman kääntäminen eri alustoille voidaan tehdä helpommaksi[2]. Kääntäjästä riippumaton optimointi on staattisen metaohjelmoinnin sovellusala, joka on myös taloudellisesti merkittävä[5]. Staattinen metaohjelmointi ei ole täysin mutkatonta, sillä virheenjäljitys on vaikeaa, koska staattisella metatasolla toimivia virheenjäljitystyökaluja ei ole. Tämä asettaa vaatimuksia staattisten metaohjelmien testaamiselle. Luvussa tutustutaan staattiseen metaohjelmointiin yleisellä tasolla. Tarkennamme edelleen fokusta luvussa 3, jossa paneudutaan C++:n aihiometaohjelmointiin (template metaprogramming). Siellä tulevat tutuiksi C++aihimetaohjelmoinnin historia (3.1) ja C++:n kaksitasoisena ohjelmointikielenä (3.2). Aihiometaohjelmoinnin perusteet tulevat tutuksi luvussa 3.3. Haskell-kielen metaohjelmointilaajennuksesta kertoo luku. 2 Staattinen metaohjelmointi 3 Staattinen metaohjelmointi C++:ssa 3.1 Historiaa Ensimmäiset aihiometaohjelmointi esimerkit kirjoitti Erwin Unruh. Hän toi esimerkit myös ANSI/ISO C++ standardointikomitean tietoon [7]. Ohjelmat tuottivat käännöksen aikana varoituksia, joista ohjelman tuloste oli luettavissa. Esimerkiksi, yksi ohjelmista tuotti käännösaikana varoituksia, jotka sisälsivät alkulukuja. Kaiken tämän teki mahdolliseksi ISO C++ komitean tekemät vaatimukset C++:n aihioille. Kun ISO C++ komitea lisäsi aihiot C++-kieleen, asetettiin niille seuraavat vaatimukset[5]:!!" # %$'& ( $'& $))$*,+.-/!0-1- 2!'' 3!.& 1

Jäsentyyppien ja kokonaislukutyyppisten jäsenvakioiden instantiointi tehdään vain tarvittaessa. Aihioita voidaan kuormittaa parametrien suhteen. Aihiot voivat olla rekursiivisia. Funktionaalisia kieliä tuntevalle ylläolevan listan seuraukset ovat ilmeiset ja Todd Veldhuizen kirjoitti aiheesta vuonna 1995 [8]: Aihiot ovat käännösaikana suoritettava funktionaalinen kieli. 3.2 C++ kaksitasoisena kielenä Turingin täydellisen kielen vaatimuksina voidaan pitää vähintään ehto- ja silmukkarakenteita[1], joten aihiot muiden C++ ominaisuuksien kanssa muodostavat Turingin-täydellisen, käännöksen aikaisen C++:n alikielen. Tämä seikka tekee C++:sta kaksitasoisen kielen: C++ ohjelmassa voi olla sekä staattista koodia, joka suoritetaan käännöksen aikana, että dynaamista koodia, joka suoritetaan myöhemmin ajon aikana. Koska C++:n staattinen taso on Turingin täydellinen, ei ole olemassa teoreettisia rajoja sille, mitä sillä voisi toteuttaa. Kuitenkin on olemassa teknisiä rajoituksia, kuten käännösajat, kääntäjien rajoitukset ja virheenjäljitys- sekä ylläpitoongelmat. 3.3 Aihiometaohjelmoinnin perusrakenteet Aihiometaohjelmat (template metaprogram) koostuvat numeroita tai tyyppejä datanaan käyttävistä luokka-aihiosta (template class). C++-kielen perusrakenteita, kuten -silmukkaa ja -lausetta, vastaavat aihiometaohjelmointi rakenteet voidaan toteuttaa aihioiden määrittelyn suoraa tai epäsuoraa rekursiota silmukkarakenteena hyödyntäen, joissa luokka-aihion erikoistapaus (template specialization) toimii ehtolausekkeena. Ilman ehtolauseketta, joka toimii rekursion pysäyttävänä mekamismina, kääntäjä jäisi loputtomaan rekursioon. Kääntäjän pitää myös yksiselitteisesti pystyä valitsemaan käytettävä erikoistapaus aihion parametrien perusteella [3]. Yleisesti aihetta käsittelevissä artikkeleissa esiintyvä yksinkertainen aliohjelma kokonaisluvun kertoman laskemiseksi on hyvä esimerkki aihioiden käyttöstä silmukkarakenteena. Kertoman laskeminen perinteisessä ohjelmoinnissa silmukkarakenteella on esitetty esimerkissä 1 ja aihiometaohjelmointia hyödyntäen esimerkissä 2. Voimme ajatella esimerkin 2 luokka-aihion funktiona, joka suoritetaan käännösaikana. Se on siis metafunktio (metafunction) [8].!" #$%'&)( * + %+,(-!.%*(/ 0"0 "#$!1%2 3( $#" 5"#$( Esimerkki 1: Kokonaisluvun kertoman laskeminen silmukalla. $ 6"7"$". 8 ""9"9;: < " $ "#"6'"#$%'1?: ".<@"&8*>">A #$ ""9"9;: < "".&8 $ "#"6'"#$%+& BB?C #9 # D+%: "."E"8*>>A" #<$( Esimerkki 2: Kokonaisluvun kertoman laskeminen aihioilla. Esimerkin 2 luokka-aihiota käytettäessä kertoma lasketaan ohjelman käännösaikana, jolloin varsinaiseen ohjelmakoodin liitetään vain laskennan tulos. Siksi staattisia metafunktioita ei voida käyttää käyttäjän syötteitä tarvitsevaan laskentaan[8]. 3. Optimointi aihiometaohjelmoinnin avulla Esimerkiksi operaattoreiden ylikuormitusta hyödyntävät abstraktit säiliötietorakenteet olivat alunperin huomattavasti vastaavaa matalan tason toteutusta tehottomampia. Tälläisiä suorituskykyongelmia kutsutaan yleisesti abstraktiosakoksi (abstraction penalty)[9]. Kääntäjän optimoija ei voi kuitenkaan poistaa abstraktiosakkoa, sillä optimoijalta puut- 2!"!" 1 %$'& ( $'& $))$*,+- /!- 1-2!'' 3!.&

tuu abstraktioista tarvittava semanttinen tieto. Yritykset kuvailla luokan semantiikkaa kääntäjille ovat epäonnistuneet, eikä yleistä ratkaisua luultavasti ole olemassa. Aihiot saattavat tulevaisuudessa tarjota käyttökelpoisempaa ratkaisua optimointiin [9]. Suorituskyky yleensä kasvaa, kun algoritmin silmukat avataan (inlining) tällöin funktiokutsujen ja pinon käytön viemät resurssit säästyvät[8]. Aihiometaohjelmoinnin avulla silmukoiden avaaminen voidaan tehdä automaattisesti[9]. Kuitenkin tällaisen ohjelmakoodin kääntäminen vie kauemmin, ohjelman koko kasvaa ja ylläpito sekä virheiden etsintä hankaloituu [8]. 3.5 Aihiometaohjelmoinnin ohjausrakenteet Vaikka rakenteiden luominen luokka-aihioilla onkin melko hankalaa, on se kuitenkin mahdollista. Aihioilla on mahdollista toteuttaa kaikki C++-kielen ohjausrakenteet - lausetta lukuunottamatta. Esimerkissä 3, toisin kuin tavallinen - lause, luokka-aihioilla toteutettu versio generoi ohjelmaan toisen lausekkeista tai riippuen siitä toteutuiko ehto. Koska on kyse staattisesta metaohjelmoinnista, on ehto tunnettava jo käännösaikana[8]. B"B "9"9$" <9 $ 6"7$". =<"" 8 "9"9 6$! "9"9 6$."#$8 7"#"= 9 " < $? *? BB "#<$!9$ 9 $ 6$ <&)( "9"9 6$."9"$"8 7"#"= 9 " < $? *? BB "9$!9"$ 9 $ 6$,( B"B $ 7<"$ 6<$ B $"9$/9 $6$ > 6$. <8*>">A* )( Esimerkki 3: Ehtolause luokka-aihioilla toteutettuna.! " -lause voidaan toteuttaa luokkaaihioilla, jos parametrina käytetään kokonaislukua. Kuten -lauseen tapauksessa, myös tässä ohjelmaan generoituu vain toteutunut tapaus riippuen # :n arvosta. BB "9"9$""< <9 $ 6"7"$". %$8 $ #<@"9 $6$ *( $ 6"7"$". #$&8 9 $ 6$ <&)( $ 6"7"$". #$","8 9 $ 6$,( BB $ 7<"$ 6<$ 29'& '( 9$ 6<$ 6$".)$8*>">A )( Esimerkki : Switch-lause luokka-aihioilla toteutettuna. Esimerkissä 5 on toteutettu silmukkarakenne luokka-aihioilla. Samaan tapaan on mahdollista toteuttaa myös - ja! " * -silmukat Vain generoituu käännettyyn ohjelmaan. Huomaa, että statement voi muuttua I:n arvon mukaan [8]. BB "9"9$""< <9 $ 6"7"$". %$8 7 $*> $ "#"62D% +$"@"&-, %/. 9 $ 6$ *( 6$".D10 +$"@&" >2.8*>">A* )( ".3.8 BB65 # ""$!"" 7'7$ 6$".8*>">A )( Esimerkki 5: Silmukka luokka-aihioilla toteutettuna. Aihiometaohjelmoinnin ohjausrakenteita voidaan käyttää myös käytettävien tyyppien valitsemiseen käännösaikana. Esimerkissä 6 on!!" # %$'& ( $'& $))$*,+.-/!0-1- 2!'' 3!.& 3

8 esitetty * -rakennetta vastaava metafunktio, joka palauttaa tyypin. Tämäntyyppiset metafunktiot ovat erittäin käyttökelpoisia, sillä niiden avulla voidaan esimerkiksi tarkistaa kokonaislukutyypin koko käännösaikana. $ 6"7$". =<"" ) "99 7($ 7$ /"9"9 9 "#< $:5 7$3$ 7(<$ 7<$ 3 *( $ 6"7$".""9"9 7(<$ 7<$ "99 9$ 7$"8 9 "#< $:."9$ 3($ 7$ 9$ 7<$"8 7$3$ 9$ 7<$ 3 *( B"B?C "" B"B > + 7 9" #<"$"$5 $:. &0,8< /9 (<" - 8*>"> 3 5 3( 9$ 7$"8 Esimerkki 6: # -aihio ja sen käyttö tyypin valintaan. Staattinen metaohjelmointi Haskelissa Staattinen metaohjelmointi ei ole ainoastaan C++:n ominaisuus. Standardi-Haskell ei tue metaohjelmointia, mutta siihen on kehitetty laajennos nimeltään Template Haskell, joka tukee staattista metaohjelmointia[6]. Laajennoksen ovat kehittäneet Tim Sheard ja Simon Peyton Jones. Laajennuksen tarkoitus käy ilmi seuraavasta lainauksesta[6]: Laajennuksen tarkoituksena on antaa ohjelmoijalle mahdollisuus laskea joitain ohjelman osia sen sijaan, että ne olisi kirjoitettava ja tehdä tämä saumattoman mutkattomasti. Laajennus mahdollistaa ehdollinen kääntämisen ohjelma voidaan kääntään eri tavalla eri alustoilla. Template Haskelilla voidaan tehdä myös suorituskykyoptimointia..1 Esimerkki Template Haskelissa templaten eli aihion käyttöä merkitään $-merkillä. Alla esimerkki C-tyyppisen -funtion tekemisestä Template Haskelliin 7. [6] BB $ 6"7<"$ "7 7 " >">"< D+@8 7 7 "29%D$ 79$!9! "$# D$ >">A:6< #+@8 7 @8 7 D$ %&# % D$ &' > 9 %( )@8) D$ 9*) 0"09 (7&? +$#,$# D$ - > 9 %(9@8) D$ 9*) 0"09 $#<$# D$ = /.29 > 9 %5D$ 9) 0"0) "29*$# BB ) 7 "00 " >219 ' $316 3 6<9D! $ -funktion to- Esimerkki 7: C-tyylisen teutus Template Haskelilla 5 Yhteenveto Staattinen metaohjelmointi antaa ohjelmoijalle voimakkaan työkalun jolla vaikuttaa ohjelman suoritukseen. Voidaan ajatalla, että staattisen metaohjelmoinnin avulla ohjelmoija pääsee vaikuttamaan käännöksen lopputulokseen tasolla, johon aiemmin vain kääntäjäohjelmien tekijät pystyivät. Optimointi- ja mukauttamismahdollisuudet ovat tästä mainio esimerkki. Viitteet [1] Corrado Böhm ja Giuseppe Jacopini: Flow diagrams, turing machines and languages with only two formation rules, Communications of the ACM, 9(5), ss. 366 371, 1966, ISSN 0001-0782. [2] Krzysztof Czarnecki ja Ulrich W. Eisenecker: Generative Programming - Methods, Tools and Applications, Addison Wesley Professional, 2000, ISBN 0-201-30977-7. [3] J. Järvi: Compile time recursive objects in C++, teoksessa Technology of Object- Oriented Languages and Systems, (ss. 66 77), IEEE Computer Society Press, 1998. [] Professor George A. Miller et al.: Wordnet, An Electronic Lexical Database, Priceton University, 2002. 7!!! 8 8 URL " 65 :9; <! = [5] Arch D. Robison: Impact of economics on compiler optimization, teoksessa ISCO- PE Conference on ACM 2001 Java Grande, (ss. 1 10), ACM Press, 2001, ISBN 1-58113-359-6.!"!" 1 %$'& ( $'& $))$*,+- /!- 1-2!'' 3!.&

[6] Tim Sheard ja Simon Peyton Jones: Template meta-programming for haskell, teoksessa Proceedings of the workshop on Haskell workshop, (ss. 1 16), ACM Press, 2002, ISBN 1-58113- 605-6. [7] Erwin Unruh: Prime Number Computation, 199, ANSI X3J16-9-0075/ISO WG21 62. [8] Todd L. Veldhuizen: Using C++ template metaprograms, C++ Report, 7(), ss. 36 3, toukokuu 1995, ISSN 100-602, reprinted in C++ Gems, ed. Stanley Lippman. [9] Todd L. Veldhuizen: C++ templates as partial evaluation, teoksessa ACM SIGPLAN Workshop on Partial Evaluation and Semantics-Bases Program Manipulation, 1999.!!" # %$'& ( $'& $))$*,+.-/!0-1- 2!'' 3!.& 5