Aliohjelmat. 1 Kutsusekvenssit. Antti-Juhani Kaijanaho 5. helmikuuta 2007

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

kontrollivuon analyysejä optimointiensa tueksi ja myös tiettyjen merkitysopillisten

samalla seuraavaan puoliavaruuteen (sukupolveen), jota siivotaan harvemmin.

TIE448 Kääntäjätekniikka, syksy Antti-Juhani Kaijanaho. 13. lokakuuta 2009

11/20: Konepelti auki

Luku 7. Aliohjelmat. 7.1 Kutsusekvenssit. Aliohjelma (subroutine) on useimpien kielten tärkein kontrollivuon ohjausja abstrahointikeino.

TIES542 kevät 2009 Kontrollivuon ohjaus

Luento 4 Aliohjelmien toteutus

Luento 4 (verkkoluento 4) Aliohjelmien toteutus

Jatkeet. TIES341 Funktio ohjelmointi 2 Kevät 2006

Jakso 4 Aliohjelmien toteutus

Aliohjelmatyypit (2) Jakso 4 Aliohjelmien toteutus

Jakso 4 Aliohjelmien toteutus

Aliohjelmatyypit (2) Jakso 4 Aliohjelmien toteutus

Luento 4 (verkkoluento 4) Aliohjelmien toteutus

Jakso 4 Aliohjelmien toteutus

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

Jakso 4 Aliohjelmien toteutus. Tyypit Parametrit Aktivointitietue (AT) AT-pino Rekursio

Algoritmit 1. Luento 3 Ti Timo Männikkö

Ohjelmoinnin peruskurssien laaja oppimäärä

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

Luento 4 Aliohjelmien toteutus

Luento 4 Aliohjelmien toteutus

Tutoriaaliläsnäoloista

Luento 4 Aliohjelmien toteutus. Tyypit Parametrit Aktivointitietue (AT) AT-pino Rekursio

Ohjelmoinnin peruskurssien laaja oppimäärä

IDL - proseduurit. ATK tähtitieteessä. IDL - proseduurit

ATK tähtitieteessä. Osa 3 - IDL proseduurit ja rakenteet. 18. syyskuuta 2014

Sisällys. 1. Omat operaatiot. Yleistä operaatioista. Yleistä operaatioista

1. Omat operaatiot 1.1

Osoitin ja viittaus C++:ssa

Tietorakenteet ja algoritmit

ITKP102 Ohjelmointi 1 (6 op)

Ohjelmoinnin peruskurssien laaja oppimäärä

Scheme-kesäkurssi luento 5

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

TIEA341 Funktio-ohjelmointi 1, kevät 2008

815338A Ohjelmointikielten periaatteet Harjoitus 5 Vastaukset

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

Groovy. Niko Jäntti Jesper Haapalinna Group 31

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

Ohjelmoinnin peruskurssien laaja oppimäärä

TIE448 Kääntäjätekniikka, syksy Antti-Juhani Kaijanaho. 27. lokakuuta 2009

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

Scheme-kesäkurssi luento 3

Ohjelmoinnin peruskurssien laaja oppimäärä

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

TIES542 kevät 2009 Tyyppijärjestelmän laajennoksia

Harjoitustyö: virtuaalikone

Monipuolinen esimerkki

Olion elinikä. Olion luominen. Olion tuhoutuminen. Olion tuhoutuminen. Kissa rontti = null; rontti = new Kissa();

ITKP102 Ohjelmointi 1 (6 op)

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Sisällys. Yleistä attribuuteista. Näkyvyys luokan sisällä. Tiedonkätkentä. Aksessorit. 4.2

TIE448 Kääntäjätekniikka, syksy Antti-Juhani Kaijanaho. 26. lokakuuta 2009

TIEP114 Tietokoneen rakenne ja arkkitehtuuri, 3 op. Assembly ja konekieli

TIE PRINCIPLES OF PROGRAMMING LANGUAGES Eiffel-ohjelmointikieli

TAMPEREEN TEKNILLINEN YLIOPISTO

ITKP102 Ohjelmointi 1 (6 op)

semantiikasta TIE448 Kääntäjätekniikka, syksy 2009 Antti-Juhani Kaijanaho 5. lokakuuta 2009 TIETOTEKNIIKAN LAITOS Ohjelmointikielten staattisesta

Sisällys. 7. Oliot ja viitteet. Olion luominen. Olio Java-kielessä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin peruskurssien laaja oppimäärä

TIE448 Kääntäjätekniikka, syksy Antti-Juhani Kaijanaho. 7. joulukuuta 2009

Algoritmit 1. Luento 4 Ke Timo Männikkö

Ohjelmoinnin perusteet Y Python

TAMPEREEN TEKNILLINEN YLIOPISTO

Ohjelmoinnin peruskurssien laaja oppimäärä

Java-kielen perusteet

Ohjelmoinnin peruskurssien laaja oppimäärä

TIEP114 Tietokoneen rakenne ja arkkitehtuuri, 3 op. Assembly ja konekieli

815338A Ohjelmointikielten periaatteet Harjoitus 7 Vastaukset

Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Rinnakkaistietokoneet luento S

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmointikieli TIE Principles of Programming Languages Syksy 2017 Ryhmä 19

TIEA341 Funktio-ohjelmointi 1, kevät 2008

3. Muuttujat ja operaatiot 3.1

Apuja ohjelmointiin» Yleisiä virheitä

Metodit. Metodien määrittely. Metodin parametrit ja paluuarvo. Metodien suorittaminen eli kutsuminen. Metodien kuormittaminen

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

Sisällys. Yleistä attribuuteista. Näkyvyys luokan sisällä ja ulkopuolelta. Attribuuttien arvojen käsittely aksessoreilla. 4.2

Algoritmit 2. Luento 13 Ti Timo Männikkö

7. Oliot ja viitteet 7.1

ELM GROUP 04. Teemu Laakso Henrik Talarmo

815338A Ohjelmointikielten periaatteet

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

Tieto- ja tallennusrakenteet

C-kielessä taulukko on joukko peräkkäisiä muistipaikkoja, jotka kaikki pystyvät tallettamaan samaa tyyppiä olevaa tietoa.

815338A Ohjelmointikielten periaatteet

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

Tietotekniikan valintakoe

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

Lisää pysähtymisaiheisia ongelmia

Kehittää ohjelmointitehtävien ratkaisemisessa tarvittavia metakognitioita!

A TIETORAKENTEET JA ALGORITMIT

Tietorakenteet ja algoritmit - syksy

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

Transkriptio:

Aliohjelmat Antti-Juhani Kaijanaho 5. helmikuuta 2007 1 Kutsusekvenssit Aliohjelmaan kontrolli siirtyy sen kutsun (engl. call) kautta. Kun aliohjelman suoritus päättyy, kontrolli siirtyy takaisin sinne, missä kutsu tehtiin. Tämä johtaa siihen, että aliohjelmien kutsurakenne on lifo-tyyppinen (engl. last in, first out), ja toteutustekniikaksi sopii mainiosti pino. Nelikoneessa kutsujan omat rekisterit tallennetaan pinoon SLIDE-käskyn avulla, ja näin rekisteristö vapautuu kutsuttavan käyttöön. Oikeastaan voidaan ajatella, että rekisteristö on yksinkertaisesti pinon päälimmäinen elementti, ja loppuosa pinosta on muistissa. Tätä hieman abstraktimpaa pinokäsitettä kutsutaan aliohjelmakäsitteen yhteydessä aktivaatiopinoksi (engl. activation stack). Näin samaa käsitteistöä voidaan käyttää muidenkin koneiden kohdalla. Joissakin koneissa aktivaatiopino on muistissa kokonaisuutenaan, ja rekisteristö on aktivaatiopinon välimuisti! Aliohjelman perusidea on, että kutsuja laittaa aktivaatiopinoon (Nelikoneessa rekisteriin $0) itseään seuraavan käskyn osoitteen ja sitten siirtää kontrollin aliohjelmalle (eli hyppää aliohjelman alkuun, suorittaa go to -lauseen, jonka kohteena on aliohjelman alku). Viimeisenä toimenaan aliohjelma ottaa pinosta (Nelikoneessa $0-rekisteristä) osoitteen ja hyppää tuohon osoitteeseen. Kun aliohjelmista muodostetaan pino, tulee samalla sallituksi aliohjelmien rekursiivinen kutsuminen. Tällöin aliohjelmalla on aktivaatiopinossa useita aktivaatioita. Varsinkin erittäin vanhoissa ohjelmointikielissä rekursion salliminen ei ollut mitenkään itsestään selvää, sillä niiden toteutukset varasivat jokaiselle aliohjelmalle oman pätkän muistia; ja tällöin aliohjelmalla saattoi olla vain yksi aktivaatio. Nykykielistä kaikki kuitenkin sallivat rekursion. Tavallisesti aliohjelmat ovat parametrisoituja. Parametrisoidun aliohjelman kutsu välittää aliohjelmalle dataa, jota aliohjelman odotetaan käyttävän hyväksi. Tätä dataa kutsutaan aliohjelman argumenteiksi (engl. argument) kielitasolla tarkastellen kyse on lausekkeista, joiden arvo annetaan aliohjelmalle. Tärkeää on nyt huomata, että paluuosoite voidaan ajatella aliohjelmalle annettuna ylimääräisenä, viimeisen argumentin jälkeen (tai ennen ensimmäistä argumenttia) tulevana argumenttina. Näin aliohjelmakutsu on tulkittavissa argumentteja välittävänä go to -lauseena [3]! Tämä havainto on tärkeä, sillä kutsun tulkitseminen hypyksi mahdollistaa monia merkittäviä optimointeja. Esimerkiksi jos jokin aliohjelma kutsuu toista aliohjelmaa viimeisenä tekonaan, voidaan tätä yksinkertaistaa reilusti: kutsuja poistaa aktivaatiopinosta omat tietonsa ja latoo niiden paikalle kutsuttavan aliohjelman kaipaamat tiedot. Erityisesti se asettaa paluuosoitteeksi sen osoitteen, jonka se itse oli omalta kutsujaltaan saanut! Kun kutsuttava sitten aikoinaan palaa, se hyppää suoraan kutsujan kutsujaan kulkematta kutsujansa kautta lainkaan. Kutsuvasta aliohjelmasta ei jäänyt merkkiäkään aktivaatiopinoon, jolloin tällaisia häntäkutsuja (engl. tail call) voidaan tehdä loputtomasti ilman, että pinon koko kasvaisi sen seurauksena rajattomasti. Tätä optimisaatiota sanotaan häntäkutsun poistoksi (engl. tail call elimination). Sillä on myös merkitysopillista merkitystä. Kun häntäkutsu (eli aliohjelman lopuksi tehtävä kutsu) ei kasvata pinon kokoa, sitä voidaan käyttää iteraation ilmaisemiseen. Tunnetuin esimerkki kielestä, jossa iteraatio ilmaistaan häntärekursiona (engl. tail recursion), on Scheme, jonka määrittelydokumentti vaatii jokaiselta Scheme-toteutukselta luotettavan häntäkutsun poiston. Schemessä olisi esimerkiksi kertoman laskeminen luonnollisinta ilmaista näin: 1

(define (! n) (define (loop i accu) (if (eq? i 1) accu (loop (- i 1) (* accu i)))) (loop n 1)) Jotkut aliohjelmat palauttavat (engl. return) tietoa kutsujalle päätyttyään. Aliohjelmaa, joka palauttaa tietoa kutsujalle, sanotaan funktioksi (engl. function). Muut aliohjelmat ovat proseduureja (engl. procedure). Joissakin kielissä kaikkii aliohjelmat ovat funktioita, ja paluuarvoton tilanne hoidetaan palauttamalla arvo, jolla ei ole väliä. Joissakin kielissä on erityinen tyyppi tällaista paluuarvoa varten. Funktion määrittelyssä on kieliopillinen pulma. Onko funktion runko lauseke vai lause? Jos se on lauseke, funktion paluuarvo on luonnollisesti tuon lausekkeen arvo, mutta jotta tällainen funktio olisi hyödyllinen, tulee lausekkeisiin sisältyä kaikki tarvittavat kontrollia ohjaavat rakenteet. Jos se on lause (yleensä lohko), niin on ratkaistava, miten paluuarvo ilmaistaan. Joissakin kielissä (esimerkiksi Pascal) funktion nimeen sijoittaminen ilmaisee paluuarvon. Toisissa kielissä (kuten C- sukuiset) on erityinen return-lause, jolla funktiosta poistutaan paluuarvo ilmaisten. Funktioihin liittyy toinenkin, vakavampi pulma. Jos funktiolla saa olla sivuvaikutuksia (yleensä näin on, jos funktion runko on lause tai lohko), ei ole ollenkaan samantekevää enää, missä järjestyksessä lausekkeet lasketaan: esimerkiksi jos suoritettavana on lauseke f (5) + f (5), ei ole sallittua optimoida tätä muotoon 2 f (5), jos f :llä on sivuvaikutuksia. Yleisemminkin lausekkeiden sivuvaikutukset ovat pulmallisia. Tämä pulma voidaan ratkaista seuraavilla tavoilla: 1. Sallitaan sivuvaikutukset ja määritellään lausekkeiden laskujärjestys tarkasti. Tällöin sivuvaikutusten suoritusjärjestys on täysin määrätty. 2. Sallitaan sivuvaikutukset ja määritellään, että lausekkeiden laskujärjestys on vapaa tietyin poikkeuksin (esimerkiksi -operaattori laskee aina vasemman operandinsa ennen oikeaa, ja oikea saattaa jäädä kokonaan laskematta). Tällöin sivuvaikutusten suoritusjärjestys on osoittain määrätty. 3. Sallitaan sivuvaikutukset mutta pakotetaan ohjelmoija määräämään suoritusjärjestys eksplisiittisesti tyyppi- tai efektijärjestelmän avulla. 4. Kielletään sivuvaikutukset kokonaan. Osittainen laskujärjestyksen määrääminen ja sivuvaikutusten salliminen lienee yleisin ratkaisu. Ehkä siistein on kuitenkin tyyppi- tai efektijärjestelmään perustuva valjastaminen, jota AL- KEIS 2007 -kielessä jo käytetään. 2 Parametrinvälitysmekanismit Olemme puhuneet edellä aliohjelman argumenteista. Kuten edellä sanottiin, ne ovat ne datat, jotka aliohjelmalle annetaan ne ovat lausekkeita, jotka ovat osa aliohjelmakutsua. Asian toinen puoli on se, että aliohjelman sisällä nämä näkyvät paikallisina muuttujina. Näitä muuttujia sanotaan aliohjelman parametreiksi (engl. parameter). Toisin sanoen siinä missä kutsuja näkee argumentteja, kutsuttava näkee parametreja. Toisinaan argumentista käytetään nimeä todellinen parametri (engl. actual parameter), jolloin parametria sanotaan muodolliseksi parametriksi (engl. formal parameter). Sitä mekanismia, jolla argumentti ja parametri kytketään toisiinsa, sanotaan parametrinvälitysmekanismiksi (parameter passing mechanism). Seuraavat neljä mekanismia ovat tavallisimmat: Arvovälitteisyys (engl. call by value) Arvovälitteinen parametri on kopio argumentista: parametrin arvo on aliohjelman alussa argumentin arvo, ja parametriin tehdyt muutokset eivät näy argumentissa. Tulosvälitteisyys (engl. call by result) Tulosvälitteinen parametri kopioidaan lopuksi argumentiksi: parametrin arvo on aliohjelman alussa määräämätön, mutta siihen tehdyt muutokset välitetään argumenttiin kopioimalla parametri argumenttiin aliohjelman palatessa. Arvo-tulosvälitteisyys (engl. call by value-result) Arvo-tulosvälitteinen parametri on kopio argumentista, ja se kopioidaan lopuksi argumentiksi: parametrin arvo on aliohjelman 2

alussa argumentin arvo, ja parametriin tehdyt muutokset välitetään argumenttiin kopioimalla parametri argumenttiin aliohjelman palatessa. Viitevälitteisyys (engl. call by reference) Argumentti ja parametri ovat sama olio, joten kaikki parametriin tehdyt muutokset näkyvät välittömästi argumentissa. Nykyaikana näistä tavallisimmat ovat arvovälitteisyys ja viitevälitteisyys. Harvinaisempi ja nykyisin huonoksi todettu mekanismi on nimivälitteisyys (engl. call by name). Idea on se, että argumenttilauseketta ei lasketa kutsuhetkellä, vaan ohjeet sen laskemiseksi annetaan aliohjelmalle. Kun aliohjelma käyttää parametria, se laskee argumenttilausekkeen arvon. Tämä tehdään uudestaan joka kerta, kun parametria käytetään. Sivuvaikutusten kanssa tällainen voi aiheuttaa kaikenlaista vinkeää (etsipä jostain käsiisi tietoa vekottimesta nimeltä Jensen s device) ja myös ikävää (koetapa kirjoittaa toimiva swap-aliohjelma). Toimivampi mutta varsin harvinainen versio nimivälitteisyydestä on nimeltään tarvevälitteisyys (engl. call by need). Idea on sama kuin nimivälitteisyydessä, mutta tarvevälitteisyydessä huolehditaan siitä, että jokainen tarvevälitteinen parametri lasketaan samalla aktivaatiokerralla korkeintaan kerran seuraavilla käyttökerroilla käytetään aiemman laskennan tulosta. Tarvevälitteisyys on erityistapaus laiskasta laskennasta (engl. lazy evaluation). On myös esitetty mekanismia, jonka voisi nimetä lohkonvälitykseksi [1, 2]; siinä argumenttina on kutsuvan aliohjelman lohko, jonka kutsuttu aliohjelma sitten aktivoi kerran tai useamminkin. 3 Staattinen ja dynaaminen vaikutusalue Useimmat nykykielet ovat lohkorakenteisia. Tällaisten kielten ohjelmateksti on hahmotettavissa hierarkkisena kokonaisuutena: koko teksti jakautuu eri moduleihin (tai paketteihin), jotka puolestaan saattavat jakautua luokkiin, sitten tulevat aliohjelmat, aliohjelmat puolestaan saattavat sisältää uusia aliohjelmia tai luokkia sekä sisäkkäisiä lohkoja. Lohkorakenteiset kielet voidaan jakaa kahteen luokkaan vaikutusalueiden käyttäytymisen perusteella: kielet, joissa on käytössä staattiset vaikutusalueet (engl. static scoping, lexical scoping), sekä kielet, joissa on käytössä dynaamiset vaikutusalueet (dynamic scoping). Joissakin harvoissa kielissä (lähinnä Common Lisp) ohjelmoija voi valita nimen esittelyn yhteydessä, käytetäänkö tuon esittelyn tapauksessa staattista vai dynaamista vaikutusaluetta. Staattinen vaikutusalue alkaa esittelystä ja jatkuu tekstuaalisesti sen lohkon loppuun, joka oli sisin esittelyn kohdalla. Mikään muu osa ohjelmatekstistä ei kuulu vaikutusalueeseen. Mikäli saman nimen jonkin toisen esittelyn vaikutusalue on voimassa esittelyn kohdalla, peittää tämä esittely koko vaikutusalueensa ajan tuon toisen esittelyn. Staattinen vaikutusalue on täysin määrätty jo ennen ohjelman suorituksen alkamista. Dynaaminen vaikutusalue eroaa staattisesta siten, että esittelyn vaikutusalue ulottuu niihin aliohjelmiin, joita kutsutaan vaikutusalueen ollessa voimassa ja peittämätön. Vaikutusalue riippuu siis siitä, mitä suoritusaikana tapahtuu. Dynaaminen vaikutusalue on tapa antaa aliohjelmille näkymättömiä parametreja: dynaamisen vaikutusalueen ollessa käytäntönä voidaan esimerkisi kirjoittaa seuraavasti my print_base := 16 print(42); end Tämä ohjelma siis tulostaisi 2A; aliohjelma print toimii eri tavoin sen mukaan, mikä on muuttujan print_base arvo. Tämä voi näyttää hyödylliseltä, mutta käytännössä dynaamisen vaikutusalueen periaate aiheuttaa ongelmia, kun kutsujan muuttujamäärittelyt yllättäen vaikuttavatkin kutsutun aliohjelman toimintaan. Vaara on jopa suurempi kuin globaalien muuttujien tapauksessa. Dynaaminen vaikutusalue tuli käyttöön Lispin mukana. Kielen kehittäjä John McCarthy piti sitä bugina, mutta silti tuo ominaisuus jäi eloon. Vasta tuoreet Lisp-murteet, kuten Scheme ja Common Lisp, käyttävät oletuksena staattisen vaikutusalueen periaatetta. Juuri muut kielet kuin Lisp ja sen murteet eivät käytä dynaamisen vaikutusalueen periaatetta. 3

4 Aktivaatiotietue Aliohjelman aktivaation tiedot (paikalliset muuttujat, parametrit, paluuosoite) muodostavat aktivaatiotietueen (engl. activation record)) tai kehys (engl. frame). Jokainen kerta, kun aliohjelmaa kutsutaan, syntyy aliohjelman uusi aktivaatio (engl. activation), ja sen aktivaatiotietue sisältää kaiken sen tiedon, mitä tuosta nimenomaisesta aktivaatiotiedosta on pidettävä yllä ja erillään muista aktivaatioista. Joissakin tilanteissa aktivaatiotietue on staattinen olio; tällöin kyseinen aliohjelma ei voi olla rekursiivinen eikä vapaakäyntinen (engl. reentrant). Joissakin kielten toteutuksissa aktivaatiotietue on kekodynaaminen olio joskus tämä on jopa välttämätöntä. Aktivaatiotietueen paikka ei ole tavallisesti tiedossa ennen suorituksen alkua (se on tiedossa vain, jos aktivaatiotietue on staattinen olio). Sen sijaan sen osien sijainti suhteessa tietueen alkuun on hyvinkin tiedossa ennen suorituksen alkua. Senpä takia pääsy aktivaatiotietueessa oleviin tietoihin järjestetään käyttäen lähes jokaisesta prosessorista löytyvää rekisteri-ja-siirtymä-osoitusta. Kielen toteutus varaa yhden rekisterin osoittamaan sen aliohjelman aktivaatiotietuetta, jolla kontrolli on. Tätä rekisteriä sanotaan kehysosoitinrekisteriksi (engl. frame (pointer) register) tai kantaosoitinrekisteriksi (engl. base pointer register). Kun jotain toista aliohjelmaa kutsutaan, tulee tuon rekisterin sisältö tallentaa jonnekin. Joissakin laitteissa se tallennetaan aliohjelman alkaessa kutsutun aliohjelman omaan aktivaatiotietueeseen, ja se palauttaa rekisterin arvon ennen paluutaan; Nelikoneen kaltaisessa järjestelmässä se tallentuu muiden rekisterien mukana SLIDE-käskyä käytettäessä. Tallennettua kehysosoitinrekisterin arvoa sanotaan dynaamiseksi linkiksi (engl. dynamic link) sitä voitaisiin käyttää myös esimerkiksi dynaamisen vaikutusalueen toteuttamiseen. Kaikki ne aktivaatiotietueet, joihin pääsee dynaamisten linkkien kautta siitä tietueesta, jonka osoite on kehysosoitinrekisterissä, muodostavat kutsupinon (engl. call stack) eli aktivaatiopinon (engl. activation stack) eli dynaamisen ketjun (engl. dynamic chain). Joissakin kielissä aliohjelmia voidaan kirjoittaa toisten aliohjelmien sisään. Mikäli tällaisessa kielessä on käytössä staattinen vaikutusalue, tulee jotenkin aliohjelmasta olla pääsy sitä staattisesti ympäröivien aliohjelmien sopivan aktivaation paikallisiin muuttujiin (eli aktivaatiotietueisiin). Yksinkertaisessa tapauksessa tällaista aliohjelmaa voidaan kutsua vain itsestään, siitä aliohjelmasta, jossa se on määritelty, sekä niistä aliohjelmista, jotka on määritelty sen itsensä sisällä (staattisessa mielessä). Tällaisessa tilanteessa luonteva valinta staattisesti ympäröivän aliohjelman aktivaatioksi, johon pitää päästä käsiksi, on se, jossa kutsu tapahtuu. Kun kutsu tapahtuu, annetaan aliohjelmalle piiloargumenttina osoitin tähän aktivaatiotietueeseen. Tällöin tuo osoite jää osaksi kutsutun aliohjelman aktivaatiotietuetta; tuota osoitetta sanotaan staattiseksi linkiksi (engl. static link). Aktivaatiotietueet, joihin pääsee staattisten linkkien kautta siitä tietueesta, jonka osoite on kehysosoitinrekisterissä, muodostavat staattisen ketjun (engl. static chain). Staattisen vaikutusalueen ollessa voimassa mihin tahansa näkyvään paikalliseen muuttujaan pääsee käsiksi hakemalla sitä staattisen ketjun kautta. Kussakin tilanteessa tiedetään ennen suorituksen alkua, kuinka syvällä staattisessa ketjussa kukin muuttuja on, ja tämän perusteella voidaan muuttujanhakukoodi generoida suoraviivaisesti: ladataan johonkin rekisteriin ensin kehysosoitinrekisterin arvo, sitten ladataan tuon osoittimen kautta staattinen linkki tuohon rekisteriin ja iteroidaan tätä tarpeeksi monta kertaa. Lopuksi tuota rekisteriä voidaan käyttää kuin kehysosoitinrekisteriä ikään hakemaan löydetyn aktivaatiotietueen sisältämä muuttuja. Erityisesti 1970- ja 1980-luvun kääntäjät yrittivät optimoida tätä näyteikkunatekniikalla (engl. display technique). Tässä pidetään yllä erityistä taulukkoa, johon on koottu kaikki staattiseen ketjuun kuuluvat staattiset linkit. Tällöin muuttujan haku vaatii tämän näyteikkunataulukon (engl. display) indeksoinnin ja sitten tuloksena saadun osoitteen käyttämisen kuten edellä muuttujan hakemiseen. Iterointi jää kokonaan pois. Käytännössä tästä ei kuitenkaan ole ollut hyötyä, koska näyteikkunan ylläpito vaatii yleensä enemmän työtä kuin mitä muuttujanhaussa säästyy: yleensä muuttujanhakuja muualta kuin omasta aktivaatiotietueesta on harvoin, ja silloinkin kun niitä on usein, ne voidaan optimoida tehokkaammin yleisemmillä tekniikoilla, esimerkiksi yhteisen alilausekkeen optimoinnilla. Silti näyteikkunatekniikka voi olla harkinnan arvoinen prosessoreilla, joissa on vähän rekistereitä. 4

Mikäli aliohjelma voidaan antaa argumenttina toiselle aliohjelmalle, monimutkaistuu staattisen linkin hakeminen. Tällöin käytännössä argumenttina antajan (joka on siinä asemassa, kuin edellä oli aliohjelman kutsuja) tulee antaa argumenttina (piilossa) myös staattinen linkki, jotta sen saaja voisi kutsua aliohjelmaa antaen sille tuo staattinen linkki (omaansa se ei yleisessä tapauksessa voi antaa). Joissakin kielissä aliohjelmat ovat täysivaltaisia (engl. first class), eli niitä voidaan tallentaa muuttujiin, viedä parametrina ja palauttaa paluuarvona vapaasti. Tällöin aliohjelmalla tulee olla olio, joka edustaa sitä muuttujissa, aliohjelman paluuarvona ja argumenttina. Mikäli kielessä aliohjelmat eivät voi olla sisäkkäisiä, pelkkä aliohjelman koodin alun osoite riittää olion sisällöksi. Näin toimitaan esimerkiksi C:ssä (funktio-osoitin). Muussa tapauksessa oliossa pitää tuon osoittimen lisäksi olla myös staattinen linkki, joka annetaan kutsuttaessa aliohjelmalle piiloargumenttina. Tällaista oliota sanotaan toisinaan sulkeumaksi (engl. closure). call implementations considered harmful or, LAMBDA: The ultimate GOTO. Kirjassa James K. Ketchel et al., toim., Proceedings of the 1977 annual conference, ss. 153 162. ACM Press, 1977. 5 Vuorottaisrutiinit Sukua aliohjelmakäsitteelle on sellainen käsite kuin vuorottaisrutiini (engl. coroutine). Vuorottaisrutiinia kutsutaan kuten aliohjelmaa, ja siinä syntyy vastaavalla tavalla aktivaatiotietue. Ero on siinä, että vuorottaisrutiini voi palauttaa kontrollin väliaikaisesti kutsujalleen; tällöin kutsuja voi toimia, kunnes se antaa kontrollin takaisin vuorottaisrutiinille, jolloin sen suoritus jatkuu siitä mihin se jäi. Tällainen pallottelu voi jatkua pitkäänkin, kunnes vuorottaisrutiini palaa aliohjelman tavoin lopullisesti. Viitteet [1] Heiko Kießling ja Uwe Krüger. Blocks and procedures. SIGPLAN Notices, 28(11), 1993. [2] Hanspeter Mössenböck. Treating statement sequences as block objects. SIGPLAN Notices, 27(8), 1992. [3] Guy Lewis Steele, Jr. Debunking the expensive procedure call myth or procedure 5