Nykyisten ohjelmointikielten esi-isä: Algol60 Antti Krats akrats@cc.jyu.fi Kai Lahti kail@cc.jyu.fi Sami Setämaa sapetase@cc.jyu.fi 1 Johdanto Tiivistelmä Artikkelissa kuvataan Algol60 ohjelmointikielen syntaksi sekä kaksi erilaista tapaa välittää parametreja aliohjelmille. Algolin kehittäminen aloitettiin 1950-luvun loppupuolella ja sen tuloksena saatiin ohjelmointikieliperhe, joka vaikutti suuresti nykyisiin ohjelmointikieliin. Tällöin kehitykseen käytetyt menetelmät ja ratkaisut olivat huomattavasti aikaansa edellä. Algol60 määrittelystä on julkaistu useita eri versioita, joista tunnetuimpia ovat "Revised report on the algorithm language ALGOL 60"[1] vuodelta 1963 ja "Modified Report on the Algorithmic Language ALGOL 60"[4] vuodelta 1976. Lisäksi Algol60:ssä on input/output funktioista kahdet erilaiset määritelmät, jotka on esitelty artikkeleissa "Report on Input-Output Procedures for ALGOL 60"[6] ja "A Proposal for Input-Output Conventions in ALGOL 60"[2]. Tämä artikkeli on koostettu siten, että toisessa luvussa käydään läpi Algol ohjelmointikieliperheen taustoja ja sen vaikutusta nykyisiin ohjelmointikieliin. Sen jälkeen tutustutaan Algol60 syntaksiin. Luvuissa neljä, viisi ja kuusi käydään läpi input/output funktiot, call-byvalue ja call-by-name. Lisäksi seitsemännessä luvussa esitellään muutamia esimerkkiohjelmia. 2 Yleistä Algol (Algorithmic Language) on ensimmäisiä lohkorakenteisia (eng. block-structured) ohjelmointikieliperheitä. Se kehitettiin yleiskäyttöiseksi ohjelmointikieleksi teolliseen ja tieteelliseen käyttöön. Algolin suunnitteli asiantuntijoista muodostettu komitea, jonka ehdotuksen pohjalta John Backus teki kielen ensimmäisen kääntäjän. Algolista kehittyi ajan kuluessa useita eri versioita, joista tärkeimpiä ovat Algol58 (IAL, International Algebraic Language), Algol60, Algol68, ABC Algol, Algol W ja S-Algol.[7] Algolin kehittäminen vuonna 1958 vaikutti paljolti sitä seuranneiden ohjelmointikielten kehittelyyn. Monet ohjelmointikielten ominaisuudet, joita nykyään pidetään itsestään selvinä esiteltiin ensi kertaa Algol60:ssä tai Algol68:ssa. Algol60 oli ensimmäisiä ohjelmointikieliä, jonka syntaksi oli formaalisti määritelty ennen kuin kielen kääntäjää oli tehty. Lisäksi Algol60:ssä ei ollut määritelty I/O-rutiineja. I/O-rutiinien puuttuminen ohjelmointikielestä oli 1950-luvun loppupuolella ennen kuulumatonta, mutta nykyään se on normaalia. Algol60:ssä on myöskin mielenkiintoinen ominaisuus, joka liittyy aliohjelmien parametrien välittämiseen. Algol60:ssä aliohjelmien parametreja pystyy välittämään kahdella eri menetelmällä, joita ovat call-by-value ja callby-name. Näistä jälkimmäisellä saatiin Algoliin eräänlainen dynaaminen vaikutusalue (eng. dynamic scoping). Tämän mahdollisti hidas, mutta joustava mekanismi nimeltään thunk. Algol60 tukee useita eri tietotyyppejä, joita ovat totuusarvo-, kokonaisluku- (useita eri kokoja), liukuluku- ja merkkijonotietotyypit. Merkkijonot olivat yksinkertaisia ja niiden käsittely oli rajoittunutta, tosin sitä parannettiin seuraavissa Algolin versioissa. Lisäksi Algolista puuttuu yleinen muistin hallinta ja dynaaminen muistinvaraus. [4] Algol60 vaatii, että kääntäjä tarkastaa aliohjelmien ja lauseiden parametrien tyypit. Kääntäjä ei myöskään hyväksy uusia tietotyyp- 1
pejä tai rakenteita. Ainoa ohjelmoijan määriteltävissä oleva tietotyyppi on taulukko. Algol60:ssä oli myöskin nykyään yleiset lohkorakenteet ja täydelliset kontrollirakenteet: ifthen-else, case ja while-silmukka. Algolin tärkeimpiä ominaisuuksia ovat kuitenkin sisäkkäiset lohkorakenteet sekä paikallisten ja lohkomuuttujien leksikaalinen tulkinta. [5] 3 Syntaksi Algol60 on uudelleen määritelty useita eri kertoja, jolloin määrittelyjen välillä on pieniä eroja. Seuraavassa käydään läpi "Revised report on the algorithm language AL- GOL 60"[1] vuodelta 1963. Raportti määrittelee Algol60:n referenssikielen (eng. reference language). Sen lisäksi on olemassa myös laitteistokieli (eng. hardware representation), jota käytetään Algol-ohjelmien syöttämiseen kääntäjälle. Erona referenssikieleen on vähemmän ilmaisuvoimaiset avainsanat ja symbolit, jotka johtuvat standardisyötevälineistön rajoittuneisuudesta. 3.1 Symbolit Algol60:n symbolit koostuvat merkistöstä, numeroista, totuusarvoista ja välimerkeistä. Merkistönä käytetään pieniä ja isoja kirjaimia a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Yksittäisillä kirjaimilla ei ole erityistä merkitystä vaan niitä käyttäen muodostetaan muuttujia ja merkkijonoja. Numeroina toimivat normaalit 10-järjestelmän numerot 0 1 2 3 4 5 6 7 8 9 joita voidaan käyttää numeroiden, muuttujien ja merkkijonojen muodostukseen. Numeroiden ja kirjaimien lisäksi on totuusarvot true f alse 3.2 Välimerkit Välimerkit koostuvat operaattoreista, erottimista, sulkeista, esittelyistä ja määrittelyistä. Operaattorit voidaan jakaa neljään eri ryhmään niiden merkityksen mukaan. Erilaisia ryhmiä ovat aritmeettiset-, relaatio-, loogisetja sekvenssioperaatiot. Aritmeettisia operaatioita ovat yhteen-, vähennys-, kerto-, jako- ja kokonaislukujen jakolasku sekä potenssi Relaatio-operaattoreita ovat pienempi, pienempi tai yhtä suuri, yhtä suuri, suurempi tai yhtä suuri, suurempi ja erisuuri Loogiset operaattorit ovat ekvivalenssi, implikaatio, disjunktio, konjunktio, negaatio!"#" $% Peräkkäistys-operaattorit ovat goto i f then else f or do Operaattoreille on määrätty laskujärjesteys, jonka mukaan lauseet käsitellään. Ensimmäisenä käsitellään aritmeettiset operaattorit seuraavassa järjestyksessä, &' ja. Aritmeettisten operaattoreiden jälkeen käsitellään relaatio-operaattorit ja niiden jälkeen loogiset operaattorit seuraavassa järjestyksessä $,#,!, ja. Erottimia ovat mm. pilkku, piste, exponentti, kaksoispiste, puolipiste, sijoitus ja välilyönti sekä avainsanat step, until, while ja comment ( ) * 10 : ; :+,- step until while comment Sulkeita ovat mm. kaari- ja hakasulut sekä begin ja ( ) [ ]./ begin Esittelyitä ovat own Boolean integer real array switch procedure ja määrittelyt ovat string label value 2!"! 1 %$'& ( $'& $))$*,+.-/!0- - 2!"''!.&
Seuraavassa on esimerkki edellä esitetyistä välimerkeistä. procedure esimerkki(a); value a; integer a; begin i f a 1 then goto pr1 else goto pr2 pr1 : print(. 1. ) goto loppu pr2 : print(. 2. ) loppu : 3.3 Rakenne Algol60-ohjelma koostuu sijoitusoperaattoreista, lohkoista, hyppykäskyistä, tyhjistä esittelyistä, ehtolauseista ja silmukoista. Seuraavassa käydään läpi tärkeimmät ominaisuudet. Sijoitusoperaattorin : avulla voidaan asettaa operaattorin vasemman puoleisen muuttujan arvoksi oikean puoleisen muuttujan, listan alkion tai funktion arvo. Lisäksi sijoitusoperaattoria voidaan käyttää aliohjelmissa tai funktioissa palautusarvon asettamiseksi. Lohkorakenteella voidaan erotella loogisia kokonaisuuksia toisistaan ja vähentää ohjelman käyttämän pinomuistin määrää. Algol60:ssä lohko on määritelty siten, että sen sisällä olevat esittelyt ovat voimassa ainoastaan lohkon sisällä. Lisäksi lohkossa B olevat esittelyt eivät ole voimassa lohkossa A, jos lohko A ei ole lohkon B alilohko. Jokainen aliohjelma, begin pari sekä label-lause muodostaa oman lohkonsa. Hyppykäskyllä goto voidaan lopettaa välittömästi nykyisen lohkon suoritus ja siirtyä eksplisiittisesti johonkin toiseen lohkoon, josta suoritusta jatketaan. Tyhjä lause (eng. dummy statement) ei suorita operaatiota, jolloin sitä voidaan käyttää label-lauseena. Tyhjää lausetta käytetään erityisesti goto:n yhteydessä, esimerkiksi begin ; loppu :. Ehtolauseet ovat yksinkertaisia i f then else - rakenteita, joissa i f - ja else-osioissa voi olla lohko. Ehtolauseen oikeellisuus aiheuttaa tiettyjen lohkon suorittamisen tai suorittamatta jättämisen. Moniosainen ehtolause tarkastetaan vasemmalta oikealle käyttäen operaattoreille määriteltyä laskujärjestystä. Silmukoita voidaan muodostaa f or-lauseen avulla. Tällöin f or- lauseen lohkoa suoritetaan kontrollimuuttujan ehdosta riippuen useita kertoja tai ei yhtään kertaa. Lisäksi f orlause tekee lisäyksen kontrollimuuttujaansa jokaisella lohkon suorituskerralla. Seuraava f or-silmukka tulostaa luvut 1 10. f or i : 1 step1 until 10 do print(i) 3.4 Aliohjelmat Algol 60:n aliohjelmia kutsutaan nimellä procedure. Niiden tarkoitus on sama kuin kirjastofunktioiden, eli tehdä Algol-ohjelmista yksinkertaisempia. Kuten myös useimmissa muissa ohjelmointikielissä, aliohjelmat voidaan erottaa kahdeksi osaksi: aliohjelman määrittelyksi ja kutsuksi. Aliohjelman määrittely koostuu otsikosta ja kommenttiosasta, joka antaa informaatiota parametreistä. Otsikon yleinen muoto on seuraava: procedure I(p1 p2 pn); value l; parametrien kuvaus ;. Tässä I on aliohjelman nimi ja p:t parametrejä. Parametreja voidaan kommentoida käyttäen seuraavanlaista notaatiota ) : (, missä voi olla mikä tahansa kirjain. Seuraavassa esimerkki aliohjelman muodostamisesta. ) procedure pistetulo(a b n )tulos : ( sigma); value n; array a b; integer n; real sigma; comment : a ja b ovat vektoreita joissa on n alkiolta Pistetulo on sigmassa Parameteri n välitetään call by value tyyppisesti; begin integer k; sigma : 0; f or k : 1 step 1 until n do sigma : sigma a[k] b[k] pistetulo : ( 3
Otsikossa olevassa value l; osassa kirjain l kuvaa listaa niistä parametreistä, jotka näkyvät aliohjelmalle paikallisena. Nämä parametrit eivät näy aliohjelman ulkopuolelle ja niinpä paluuarvoja ei voida laittaa listaan l. Value osa voi myös olla tyhjä. Otsikon parametrien kuvauksessa voidaan kommentoida parametrien tyyppiä ja tarkoitusta. Usein tämä osa voidaan jättää tyhjäksi aliohjelman yksinkertaisuuden vuoksi. Seuraavaksi on määriteltävä aliohjelman toiminta lausekkeella. Yleensä lauseke on yhdistetty lauseke tai blokki, jos lokaaleja muuttujia on määritelty. Aliohjelman voi muuttaa funktioksi siirtämällä palautusarvon tyypin procedure sanan eteen. Tällöin palautusarvoon voidaan viitata suoraan funktion sisällä. Yksinkertainen esimerkki aliohjelman muuttamisesta funktioksi on esimerkin 7.4 ohjelma. [1][7] Aliohjelmakutsun yleinen muoto on I(p1 p2 pn). Tässä I on aliohjelman nimi, joko on oltava aikaisemmin määritelty aliohjelmamäärittelynä. Sulkeiden sisällä olevat p:t ovat aliohjelmalle välitettäviä argumentteja. Niiden tyypit on oltava samoja kuin aliohjelman määrittelyssä. [7] 3.5 Funktiot Perus-Algol60:ssä ei ole I/O-funktioita, joten ne käsitellään erikseen luvussa 4. Taulukossa 1 esitellään standardifunktiot sekä muunnosfunktio entier. Muunnosfunktiolla voidaan muuntaa liukuluku kokonaisluvuksi, jolloin kokonaisluvun arvoksi asetetaan alaspäin pyöristetty liukuluku. Paluuarvo Funktio Parametrit integer/real abs(x) integer/real real sqrt(x) integer/real real sin(x) integer/real real cos(x) integer/real real arctan(x) integer/real real ln(x) integer/real real exp(x) integer/real integer sign(x) integer/real integer entier(x) real Taulukko 1: Algol60 standardifunktiot 4 Input/output funktiot Algol60:ssä ei ole varsinaisia syöttö- ja tulostusfunktioita, koska kielen määrittelyvaiheessa ne koettiin liian laitteistoriippuvaisiksi. Algol60:n kehittyessä kuitenkin huomattiin, että funktiot voitaisiin esitellä yleisellä tasolla. Tällöin International Federation for Information Processing:n (IFIP) työskentelyryhmä 2.1 (WG2.1) julkaisi ehdotuksen uusista funktioista. Julkaisussa Report on Input-Output Procedures for Algol 60 esiteltiin taulukon 2 mukaiset funktiot. [6] Funktio insymbol outsymbol length inreal outreal inarray outarray Parametrit channel, string, destination channel, string, source string channel, destination channel, source channel, destination channel, source Taulukko 2: IFIP:n input/output funktiot Hieman myöhemmin Association for Computing Machinery (ACM) julkaisi oman ehdotuksensa syöttö- ja tulostusfunktioiksi. Julkaisussa A Proposal For Input-Output Conventions In ALGOL 60 esiteltiin taulukon 3 mukaiset funktiot. [2] Funktio out list in list h skip v skip put get out control in control Parametrit unit, layout, list unit, layout, list position, overflow position, overflow n, list n, list unit, x1, x2, x3, x4 unit, x1, x2, x3, x4 Taulukko 3: ACM:n input/output funktiot Funktiolla out list(unit layout list) voidaan tulostaa unit parametrilla määritellylle laitteelle parametrina annettu lista list. Tulostuksen muotoilu tapahtuu layout-parametrilla. Lista ja muotoilu parametrit ovat aliohjelmia, joiden muodon Knuth on määritellyt artikke- 4!"! 1 %$'& ( $'& $))$*,+.-/!0- - 2!"''!.&
lissaan [2]. Funktio in list toimii samoin kuin out list, mutta unit-parametri määrää laitteen josta luetaan. Tulostuksessa voidaan hypätä eteenpäin funktioita h skip(position over f low) ja v skip(position over f low) käyttäen. Tällöin tulostusalueen ylittyessä kutsutaan over f low-parametrin määräämää aliohjelma. Funktiolla h skip hypätään vaakasuunnassa ja funktiolla v skip pystysuunnassa. Listan väliaikainen tallentaminen muistiin tapahtuu funktion put(n list) avulla. Listan tallennuspaikka identifioidaan parametrina annetulla tunnusluvulla n. Funktiolla get(n list) voidaan hakea lista tunnusluvun määräämästä tallennuspaikasta. Tulostuslaitteelle voidaan lähettää erityisiä ohjainkäskyjä funktioiden out control(unit x1 x2 x3 x4) ja in control(unit x1 x2 x3 x4) avulla. 5 Call-by-value Algolissa aliohjelmaan voidaan välittää parametrejä kahdella tavalla, call-by-name ja callby-value menetelmällä. Call-by-value menetelmässä kopioidaan argumenttien arvot aliohjelman parametrien paikalle. Huonona puolena on se, että informaatiota pystytään siirtämään ainoastaan aliohjelmaan päin (katso esimerkki 7.1). Call-by-value:ssa parametrit sijoitetaan aliohjelman määrittelyssä value-listaan. Tällöin aliohjelmaa kutsuttaessa asetetaan kutsussa olevat argumentit niitä vastaaviin valuelistassa määrättyihin muuttujiin. Asettaminen tapahtuu ennen aliohjelman lauseke osaan etenemistä. Nyt value-lista voidaan kuvitella omaksi blokiksi, joka luodaan aliohjelmaan siirryttäessä. Listassa olevat muuttujat ovat lokaaleja kuvitteellisen blokkiin nähden, mutta ei-lokaaleja aliohjelman runkoon nähden. 6 Call-by-name Call-by-name (ts. name replacement) on Algolin erikoisuus, jolla voidaan siirtää parametrejä sisään ja ulos aliohjelmasta. Kontrollin siirtyessä kutsusta aliohjelmaan kopioidaan argumentit nimineen aliohjelman parametrien paikalle. Call-by-name:a voidaankin ajatella makrona, joka korvaa parametrin nimen argumentin nimellä. Jos kutsu on muotoa f oo(a), sijoitetaan aliohjelmassa parametrin paikalle a-kirjain, vaikka aliohjelman määrittelyssä parametrin nimeksi olisi määrätty i. Kuulostaa siltä, että menetelmä toimii, mutta ajatellaanpa seuraavaa tilannetta: Aliohjelmalle välitetään kaksi argumenttia, joista toinen argumentti riippuu ensimmäisestä. Jos ensimmäistä parametria mennään muuttamaan, niin muuttuu myös toisen parametrin arvo. Nyt aliohjelma ei välttämättä käyttäydy halutulla tavalla (katso esimerkki 6.3). Revised Report:n [1] mukaan systemaattisella muuttujien nimien muuttamisella edellä esitetyn kaltaiset ongelmat voitaisiin kiertää. Tällöin esimerkin 7.3 aliohjelma olisi kuitenkin huomattavan hankala toteuttaa. Call-by-name:a suunniteltaessa ajateltiin rakentaa parametrinvälitysmekanismi, joka toimisi kuten call-by-reference. Kielensuunnittelukomitealle tuli kuitenkin erehdys ja vika huomattiin vasta sitten, kun oli liian myöhäistä muuttaa kielen määrittelyä [3]. Silti Algol 60:n call-by-name vei ratkaisevasti eteenpäin ohjelmointikielten kehitystä. 6.1 Thunkit Algol60:n call-by-name mahdollistaa parametrien laskemisen joka kerta uudelleen niitä käytettäessä. Tällöin parametrit ovat itseasiassa funktioita, jotka palauttavat jonkun arvon. Tällainen funktio suoritetaan uudelleen aina, kun parametria käytetään, jolloin sen palauttama arvokin voi muuttua. Näitä funktioita kutsutaan thunkeiksi ja ne ovat kääntäjän tekijän keino toteuttaa call-by-name. Thunkien käyttö on hidasta johtuen jatkuvista funktiokutsuista, mutta niiden avulla Algolin kehittäjät saivat kieleen tarvittavaa dynaamisuutta. 5
7 Esimerkkiohjelmia Seuraavassa esitellään yksinkertaisten esimerkkien avulla kuinka call-by-valueta, callby-namea, funktiota ja aliohjelmia voidaan käyttää Algol60:ssä. 7.1 Call-by-value Call-by-value-tyyppinen parametrien välitys tapahtuu käyttäen value-määrittelyä. Tällöin aliohjelmaan vietävät parametrit ovat yksisuuntaisia, jolloin parametreihin tehdyt muutokset eivät näy aliohjelman ulkopuolelle. procudure set(n m); value n m; real n m; n : m; 7.2 Call-by-name 1 Call-by-name tyyppisten parametrien välittäminen tapahtuu kuten call-by-valuessa, joskin value-määrittely puuttuu. Call-byvaluessa parametrit ovat kaksisuuntaisia ja niiden arvot voivat muuttua kesken aliohjelman suorituksen. begin integer i; array A[1 : 6]; procedure inc(n); integer n; n : n 1; comment : Toimii kuin alioh jelma olisi muotoa : i : i 1; ; inc(i) comment : Toimii kuin alioh jelma olisi muotoa : A[k] : A[k] 1; ; inc(a[k]) 7.3 Call-by-name 2 Seuraava esimerkki havainnollistaa call-byname tyyppisen parametrien välityksen ongelmakohdan. Aliohjelmassa vaihdetaan kahden annetun kokonaislukumuuttujan arvot, jolloin parametri x:n arvo muutetaan ennen y:n muuttumista. procedure swap(x y) integer x y; begin integer t; t : x; x : y; y : t; ; Mikäli y-parametri on riippuvainen x- parametrin arvosta huomataan, että ohjelma ei toimi oikein. Esimerkiksi aliohjelmakutsu Swap(i A[i]) ei toimisi koska, i:n arvo vaihtuu ennen A[i]:hin sijoitusta. Tällöin A[i]:n arvo ei vastaa enää alkuperäistä. 7.4 Aliohjelma ja funktio Aliohjelma ja funktio ovat toteutukseltaan lähes identtisiä, joskin funktioissa paluuarvoon voidaan viitata suoraan. begin integer arvo; procedure plus(t a b); value a b; real a b t; t : a b; comment : laske 1 2 ja aseta tulos arvo muuttu jaan jonka jälkeen tulosta se ; plus(arvo 1 2) print(arvo) Kuten edellä huomattiin aliohjelmassa oleva muuttuja n korvataan parametrina annettavalla muuttujalla. Edellinen aliohjelma voidaan helposti muuttaa funktioksi. Se tapahtuu siirtämällä palautusarvo funktion eteen. 6!"! 1 %$'& ( $'& $))$*,+.-/!0- - 2!"''!.&
begin real procedure plus(a b); value a b; real a b; plus : a b; comment : laske 1 2 ja tulosta vastaus ; print(plus(1 2)) 7.5 Jensen s Device Klassisin esimerkki call-by-name tyyppisestä parametrien välityksen tehokkuudesta on Jensen s Device. Se laskee annetun summalauseen arvon erittäin vähillä operaatioilla. begin integer i; real procedure sum(i lo hi term); value lo hi; integer i lo hi; real term; begin real temp; temp : 0; f or i : lo step 1 until hi do temp : temp term; sum : temp ; print( sum(i 1 100 1 i) 6 3 ) [2] D. E. Knuth: A proposal for input-output conventions in algol 60, Communications of the ACM, 7(5), ss. 273 283, 1964. [3] Donald E. Knuth: The remaining trouble spots in algol 60, Communications of the ACM, 10(10), ss. 611 618, 1967, ISSN 0001-0782. [4] R. M. De Morgan, I. D. Hill ja B. A. Wichmann: Modified report on the algorithmic language algol 60, The Computer Journal, 19(4), ss. 364 379, November 1976. [5] Peter Naur et al.: Report on the algorithmic language algol 60, Communications of the ACM, 3(5), ss. 299 314, 1960, ISSN 0001-0782. [6] International Federation of Information Processing: Report on input-output procedures for algol 60, Communications of the ACM, 7, s. 628, 1964. [7] H. R. Schwarz: An introduction to algol: a tutorial paper on algol with explanations and examples to make the use of the algol report more familiar, Communications of the ACM, 5(2), ss. 82 95, 1962, ISSN 0001-0782. 8 Yhteenveto Artikkelissa kuvattiin Algol60- ohjelmointikielen syntaksi sekä kaksi erilaista tapaa välittää parametreja aliohjelmille. Parametrien välitystavoista todettiin callby-value:n rajoittuneisuus. Se on kuitenkin turvallisempi kuin call-by-name, koska call-by-name:n dynaamisuus tekee siitä vaarallisen työkalun huolimattomissa käsissä. Viitteet [1] J. W. Backus et al.: Revised report on the algorithm language algol 60, Communications of the ACM, 6(1), ss. 1 17, 1963, ISSN 0001-0782. 7