Ohjelmointikielten periaatteet Syksy 2004. Antti-Juhani Kaijanaho



Samankaltaiset tiedostot
Konekielinen ohjelmointi

Johdanto Meta Kielten jaotteluja Historia. Aloitusluento. TIES542 Ohjelmointikielten periaatteet, kevät Antti-Juhani Kaijanaho

Ohjelmointikielten periaatteet Syksy Antti-Juhani Kaijanaho

4. Lausekielinen ohjelmointi 4.1

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

Koodi. Antti-Juhani Kaijanaho. 11. marraskuuta Sisältö

1. Olio-ohjelmointi 1.1

Ohjelmointikielten periaatteet Syksy Antti-Juhani Kaijanaho

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

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

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

11/20: Konepelti auki

Tietotekniikan valintakoe

815338A Ohjelmointikielten periaatteet

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

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

2 Konekieli, aliohjelmat, keskeytykset

Luento 1 Tietokonejärjestelmän rakenne

Luento 1 Tietokonejärjestelmän rakenne. Järjestelmän eri tasot Laitteiston nopeus

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

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

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

LOAD R1, =2 Sijoitetaan rekisteriin R1 arvo 2. LOAD R1, 100

ELM GROUP 04. Teemu Laakso Henrik Talarmo

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

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset

4. Lausekielinen ohjelmointi 4.1

Java-kielen perusteet

Ohjelmointi 1 / syksy /20: IDE

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

Luento 1 Tietokonejärjestelmän rakenne

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

Tiedon esitysmuodot. Luento 6 (verkkoluento 6) Lukujärjestelmät Kokonaisluvut, liukuluvut Merkit, merkkijonot Äänet, kuvat, muu tieto

Prolog kielenä Periaatteet Yhteenveto. Prolog. Toni ja Laura Fadjukoff. 9. joulukuuta 2010

Luento 1 Tietokonejärjestelmän rakenne. Järjestelmän eri tasot Laitteiston nopeus

13. Loogiset operaatiot 13.1

Python-ohjelmointi Harjoitus 2

Algoritmit 1. Luento 3 Ti Timo Männikkö

Java-kielen perusteet

815338A Ohjelmointikielten periaatteet Harjoitus 5 Vastaukset

Imperatiivisten ohjelmien organisointiparadigmojen. historia

Imperatiivisten ohjelmien organisointiparadigmojen historia

Ohjelmoijan binaarialgebra ja heksaluvut

TIEP114 Tietokoneen rakenne ja arkkitehtuuri, 3 op. FT Ari Viinikainen

Tähtitieteen käytännön menetelmiä Kevät 2009 Luento 4: Ohjelmointi, skriptaus ja Python

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

Ohjelmoinnin perusteet Y Python

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

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

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

Ohjelmistojen mallintaminen, mallintaminen ja UML

TT00AA Ohjelmoinnin jatko (TT10S1ECD)

ITKP102 Ohjelmointi 1 (6 op)

.NET ajoympäristö. Juha Järvensivu 2007

Algoritmit. Ohjelman tekemisen hahmottamisessa käytetään

Kertausluento luennoista 1-3 1

11.4. Context-free kielet 1 / 17

Tietokoneen toiminta, Kevät Copyright Teemu Kerola Järjestelmän eri tasot Laitteiston nopeus

Laitteistonläheinen ohjelmointi

TIE PRINCIPLES OF PROGRAMMING LANGUAGES Eiffel-ohjelmointikieli

Yhtälönratkaisusta. Johanna Rämö, Helsingin yliopisto. 22. syyskuuta 2014

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

Luento 1 (verkkoluento 1) Ohjelman sijainti Ohjelman esitysmuoto Laitteiston nopeus

TAMPEREEN TEKNILLINEN YLIOPISTO Digitaali- ja tietokonetekniikan laitos. Harjoitustyö 4: Cache, osa 2

kertaa samat järjestykseen lukkarissa.

Kertausluento 1 (lu01, lu02, lu03) Tietokonejärjestelmän rakenne ttk-91 ja sillä ohjelmointi

Pedacode Pikaopas. Java-kehitysympäristön pystyttäminen

Lisää pysähtymisaiheisia ongelmia

Ohjelmoinnin perusteet Y Python

Tutoriaaliläsnäoloista

Ohjelmointikielten periaatteiden taustaa


etunimi, sukunimi ja opiskelijanumero ja näillä

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

Paavo Räisänen. Ohjelmoijan binaarialgebra ja heksaluvut.

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

Chapel. TIE Ryhmä 91. Joonas Eloranta Lari Valtonen

811120P Diskreetit rakenteet

17/20: Keittokirja IV

Se mistä tilasta aloitetaan, merkitään tyhjästä tulevalla nuolella. Yllä olevassa esimerkissä aloitustila on A.

Luento 1 (verkkoluento 1) Tietokonejärjestelmä

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 8. syyskuuta 2016

Arkkitehtuurikuvaus. Ratkaisu ohjelmistotuotelinjan monikielisyyden hallintaan Innofactor Oy. Ryhmä 14

TIES325 Tietokonejärjestelmä. Jani Kurhinen Jyväskylän yliopisto Tietotekniikan laitos

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

Matematiikan peruskurssi 2

PRINCIPLES OF PROGRAMMING LANGUAGES - DEBUGGER

5. HelloWorld-ohjelma 5.1

Matematiikan tukikurssi

ITKP102 Ohjelmointi 1 (6 op)

Ohjelmointi 1. Kumppanit

Ohjelmoinnin perusteet, syksy 2006

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

Luento 3 (verkkoluento 3) Ttk-91 konekielinen ohjelmointi. Ohjelman esitysmuoto Konekielinen ohjelmointi ttk-91:llä (Titokone, TitoTrainer)

Java-kielen perusteita

13. Loogiset operaatiot 13.1

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

Osoitin ja viittaus C++:ssa

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

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

Transkriptio:

Ohjelmointikielten periaatteet Syksy 2004 Antti-Juhani Kaijanaho

Copyright c 2002, 2004 Antti-Juhani Kaijanaho Tästä teoksesta saa valmistaa kappaleita ja sen saa saattaa yleisön saataviin, muuttamattomana tai muutettuna, käännöksenä tai muunnelmana, toisessa kirjallisuus- tai taidelajissa taikka toista tekotapaa käyttäen, mikäli kaikki seuraavat ehdot tulevat täytetyksi: (1) Kun teoksesta valmistetaan muutettu kappale tai muutettu teos kokonaan tai osittain saatetaan yleisön saataviin, on teoksen muuttajan nimi, salanimi tai nimimerkki ilmoitettava tekijän nimen rinnalla. (2) Kun teoksesta valmistetaan muutettu kappale tai muutettu teos kokonaan tai osittain saatetaan yleisön saataviin, on pidettävä huoli, ettei muutettua teosta voi hyvällä tahdolla sekoittaa alkuperäiseen. (3) Teoksen tekijän nimeä ei saa ilman hänen eri lupaansa käyttää teoksen markkinoinnissa. Erikseen korostettakoon, että teoksen tekijä ei vaadi maksua teoskappaleiden valmistamisesta tai teoksen saattamisesta yleisön saataviin. Teoskappaleen valmistaja tai teoksen yleisön saataviin saattaja saa periä tästä haluamansa maksun. Tekijänoikeuslaki(404/1961) 3 1 mom: Kun teoksesta valmistetaan kappale tai teos kokonaan tai osittain saatetaan yleisön saataviin, on tekijä ilmoitettava sillä tavoin kuin hyvä tapa vaatii.

Sisältö Esipuhe v Luku1. Johdanto 1 1. Kieltenjaotteluja 1 2. Kielenvalinta 6 3. Ohjelmointikieltensuunnitteluperiaatteita 7 4. Kielenmäärittely 8 5. Toteutustekniikoista 10 Osa 1. Imperatiivinen ohjelmointi 11 Luku 2. Konekielinen ohjelmointi 13 1. Konekielet 13 2. Symbolisetkonekielet 15 3. Abstraktitkoneet 16 4. Neloskielenidea 18 5. Systeemikutsut 23 6. Konekielelläohjelmoinnista 24 Luku3. Suoraviivaohjelmat 27 1. Suoraviivaohjelmanelementit 27 2. Abstraktisyntaksi 35 3. Denotationaalinensemantiikka 38 4. Tyyppijärjestelmä 46 5. Konkreettikielioppi 51 6. Toteutuksesta 57 Luku 4. Kontrollivuon ohjaus 61 Luku 5. Epädeterministinen ohjelmointi 63 Luku6. Samanaikaisuus 65 1. Jaettumuisti 65 2. Erilliset kommunikoivat prosessit 65 Luku7. Aliohjelma-abstraktio 67 Osa 2. Applikatiivinen ohjelmointi 69 Luku8. Funktioabstraktio 71 iii

iv SISÄLTÖ Luku9. Tyypitys 73 Luku 10. Rakenteiset arvot 75 Luku11. Synteesi 77 Osa 3. Laajuuden hallinta 79 Luku 12. Abstraktit tietorakenteet ja modulit 81 Luku13. Olioabstraktio 83 Luku14. Polymorfismi 85 Kirjallisuutta 87 Liite A. Neloskoneen systeemikutsut 89 Liite B. Ohjelmointikielten historia 95 1. Kaksi ensimmäistä sukupolvea: ennen vuotta 1955 95 2. Automaattinen ohjelmointi ja ohjelmointikielten synty: 1955 1960 95 3. Baabelin torni: 1960-luku 97 4. Modernismi:1970-luku 98 5. Postmodernismi:1980-luku 99 6. Internetin nousu: 1990-luku 100 7. Sukupolvista 100 Liite C. Semanttiset alueet 101 1. Tuloalueet 103 2. Summa-alueet 104 3. Funktioalueet 106 Liite D. ALKEIS-suoran kääntäjä 109 1. Pääohjelma 109 2. Selain 113 3. Apuluokat 119 4. Lauseet 122 5. Tyypit 128 6. Lausekkeenjäsennin 135 7. Primäärilausekkeet 138 8. Operaattorilausekkeet 142 9. Muunnoslausekkeet 147

Esipuhe Tämä moniste on toinen yritykseni hahmottaa ohjelmointikielten alaa syventävän yliopistokurssin kokoiseksi suupalaksi. Ensimmäiseni kirjoitin syksyllä 2002 opettaessani Jyväskylän yliopiston ohjelmistotekniikan opiskelijoille Ohjelmointikielten periaatteita. Jotain tuosta monisteesta on jäljellä tässä monisteessa, mutta suurin osa on kokonaan uusiksi kirjoitettu, pääosin siksi, että olen tämän kahden vuoden kuluessa oppinut niin paljon uutta alasta. Toisaalta tuo moniste oli aina tarkoitukseni kirjoittaa uusiksi, tosin kuvittelin pääseväni tästä hommasta helpolla, toimittamalla vanhan tekstini luettavammaksi. Tämä moniste on kirjoitettu Ohjelmointikielten periaatteet-opintojakson tarpeisiin, kun luennoin sen toisen kerran syksyllä 2004. Kirjoitan tätä kolmenlaisten opiskelijoiden tarpeisiin: (1) Ohjelmistotekniikan tai yleisemmin tietotekniikan syventäviä opintoja tekevä opiskelija etsinee tästä monisteesta (2) Jokunen opiskelija on varmaankin kiinnostunut oman ohjelmointikielen suunnittelusta. Jokaiselta monisteen lukijalta oletan muutamia taitoja ja tietoja: (1) Ohjelmointitaito ja-kokemus on välttämätön. Tämä moniste ei opeta ohjelmointia! (2) Oletan, että lukijoille on tämän ajan valtaohjelmointikielistä ainakin Java tuttu. Jonkin verran käytän esimerkkeinä myös muita C-sukuisia kieliä(c, C++, C#, Cyclone). (3) Yliopistomatematiikan peruskäsitteitä käytän vapaasti olettaen, että ne eivät tuota lukijoille ongelmia. Tällaisia käsitteitä ovat joukko ja funktio sekä niiden perusoperaatiot. Lisäksi oletan, että lause- ja predikaattilogiikan alkeet ovat lukijoille tuttuja. XXX Christopher Strachey on kirjoittanut(lainaus Hoaren[11]): Ithaslongbeenmypersonalviewthattheseparationof practical and theoretical work is artificial and injurious. Muchofthepracticalworkdoneincomputing,bothin software and in hardware design, is unsound and clumsybecausethepeoplewhodoithavenotanyclearunderstanding of the fundamental design principles of their v

vi ESIPUHE work. Most of the abstract mathematical and theoretical workissterilebecauseithasnopointofcontactwithreal computing. Kuten Hoare, myös minä jaan tämän näkemyksen, ja senpä vuoksi tämä moniste käsittelee aihettaan sekä teorian että käytännön näkökulmasta. Pääosa luentomonisteesta jakaantuu lukuihin, joista jokaisessa tarkastellaan yhtä tätä monistetta varten kehitettyä ohjelmointikieltä. Kukin ohjelmointikieli määritellään formaalisti, ja kullekin niistä rakennetaan yksinkertainen kääntäjä. Nämä kielet muodostavat ALKEIS-kielten perheen. Esiversioita ovat lukeneet: Hilkka Heikkilä Markus Inkeroinen Tommi Kärkkäinen Ville Tirronen Antti Vuorenmaa Kiitokset myös kaikille vuoden 2002 kurssin opiskelijoille, erityisesti Joni Töyrylälle, joka antoi kurssin aikana tekemänsä muistiinpanot käyttööni.

LUKU 1 Johdanto HowmanytimesdoIhavetotellyou? Therighttoolfortherightjob! Scotty elokuvassa Star Trek V Ohjelmointi on ongelmien ratkaisemista. Asiaa voi katsoa kahdelta kannalta: voi keskittyä ymmärtämään ongelmaa tai ratkaisumalleja. Voidaan ajatella, että maailma jakautuu kahteen osaan, ongelma-avaruuteen ja ratkaisuavaruuteen. Ongelma-avaruus koostuu kaikista mahdollisista ongelmista, ja ratkaisuavaruus koostuu kaikista mahdollisista ratkaisuista. Ohjelmoijan tehtävänä on siirtää ongelma(joka elää ongelma-avaruudessa) ratkaisuavaruuteen, jolloin siitä tulee ratkaisu. Ohjelmointikieli on ohjelmoijan pääasiallisin työkalu, ja kielen toteutus(kääntäjä tai tulkki) auttaa ohjelmoijaa ratkaisun luomisessa: kielen ominaisuudet ratkaisevat, kuinka syvälle ratkaisuavaruuteen ohjelmoijan tulee ongelmaansa viedä suunnitteluvaiheessa ja mistä lähtien kielen toteutus tekee sen ohjelmoijan puolesta. 1. Kielten jaotteluja Ohjelmointikieliä on mielettömän paljon. Jonkinlaista järjestystä tähän suureen joukkoon saadaan erilaisilla jaotteluilla. 1.1. Sukupolvet. Eräs tunnettu mutta nykyisin vähämerkityksinen jaottelu jakaa kielet eri sukupolviin: Ensimmäinen sukupolvi: koostuu konekielistä. Konekielellä tarkoitan tässä nyt ohjelman sitä muotoa, jonka kone pystyy sellaisemaan lukemaan. Seuraavassa on Hello Worldohjelma erään tietokoneen konekiellä(esitettynä 16-lukujärjestelmässä tavujonona): 1

2 1. JOHDANTO Käytännössä konekieliset ohjelmat suunniteltiin kirjoittamalla ohjelmat ensin paperilla symbolisesti, käyttämällä konekäskyistä muistikasnimiä. Myös vuokaavioita saatettiin harrastaa monimutkaisten ohjelmien kirjoittamisessa. Konetta varten ohjelma käännettiin käsin konekielelle. Ensimmäinen sukupolvi oli vallalla 1940-luvun lopulta 1950-luvun alkupuolelle. Toinen sukupolvi: syntyi, kun keksittiin, että voidaan kirjoittaa ohjelma suorittamaan yllämainittu käännöstyö muistikkaista konekielelle. Toinen sukupolvi koostuu siis symbolisista konekielistä. Edellä esitetty Hello World-ohjelma käännettiin seuraavasta symbolisella konekielellä kirjoitetusta ohjelmasta:! Toinen sukupolvi oli vallalla 1950-luvun puoleenväliin asti. Kolmas sukupolvi: syntyi vuonna 1955, kun FORTRAN kehitettiin. Lähes kaikki nykyisin ohjelmointikieliksi kutsumamme kielet ovat kolmannen sukupolven kieliä. Neljäs ja viides sukupolvi: esiintyvät puheissa toisinaan, mutta niiden sisältö riippuu täysin puhujasta. Tavallisimmin neljännen tai viidennen sukupolven kielellä tarkoitetaan joko sovelluskehittimiä(delphi ym.) tai ohjelmoitavia sovellusohjelmia(excel ym.). 1.2. Paradigmat. Edward Sapir ja Benjamin Whorf esittivät viime vuosisadan alkupuolella kielitieteellisen hypoteesin, joka tunnetaan nykyisin nimellä Sapirin Whorfin hypoteesi. Sen heikompi muoto, johon nykyisetkin kielitieteilijät enemmän tai vähemmän uskovat, kuuluu: Kieli vaikuttaa ajatteluun. Myös ohjelmoinnin yhteydessä tämä heikompi muoto on totta: se, mitä ohjelmointikieltä osaa, vaikuttaa siihen, miten ohjelmointiongelmia ryhtyy ratkaisemaan. Kaikki kielet eivät ole tässä suhteessa samanarvoisia: esimerkiksi Pascalin ja C:n tukema ajattelutapa on niin samanlainen, että kummastakin kielestä voi varsin vähällä vaivalla siirtyä toiseen. Vastaavanlainen samankaltaisuus pätee, tosin vähemmässä määrin, myös C++:aan ja Javaan. Jotkin kielet puolestaan suosivat niin erilaisia

1. KIELTEN JAOTTELUJA 3 ajattelutapoja, että ne tuntuvat aluksi aivan eri maailmoilta, eikä toisen osaamisesta ole kovin suurta apua toisen osaamisessa. Ajatustavoiltaan läheisten kielten katsotaan yleensä kuuluvan samaan kieliparadigmaan, mutta niiden väliset rajapyykit eivät ole useinkaan kovin selvät. Kieliparadigmoille sukua ovat ohjelmointiparadigmat, tosin aika usein näiden välistä eroa ei nähdä(myös tämän kirjoittaja on ne monesti sekoittanut!). Kukin ohjelmointiparadigma on oikeastaan idealisoitu versio niistä ajattelutavoista, joita vastaava kieliparadigma suosii. Alan Perlis[25] kirjoitti kaksi vuosikymmentä sitten: A language that doesn t affect the way you think about programming, is not worth knowing. Minä kääntäisin tämän väitteen toisin päin: A language that affects the way you think about programming is worth knowing. Itse asiassa väittäisin, että jokaisen ohjelmointiin vakavissaan suhtautuvan tulisi tuntea ainakin pari-kolme eri kieliparadigmoihin kuuluvaa kieltä eli oikeastaan pari-kolme eri ohjelmointiparadigmaa. Ohjelmointiparadigmoiksi lasketaan tavallisimmin ainakin seuraavat(huomaa, että nämä paradigmat eivät ole toisistaan erillisiä, vaan ne menevät osittain päällekkäin): Imperatiivisen ohjelmoinnin:(käskyohjelmoinnin) juuret ovat syvällä ratkaisuavaruudessa, von Neumannin arkkitehtuurin perusrakenteissa. Imperatiivinen ohjelmoija näkee maailman joukkona muistipaikkoja, joita muutellaan yksitellen von Neumannin pullonkaulaa pitkin. Imperatiiviselle ohjelmoinnille tyypillistä on tiedon muuttaminen in place(sitä kopioimatta), silmukoiden runsas käyttö, ohjelmakoodin korostuminen sekä käskymetafora. Deklaratiivisen ohjelmoinnin:(kuvausohjelmoinnin) juuret ovat ongelma-avaruudessa, ongelmien täsmällisessä kuvaamisessa yleensä matematiikan keinoin. Sen taustalla on yleensä vahva matemaattinen teoria, joka on sovitettu ohjelmoinnin tarpeisiin. Deklaratiiviselle ohjelmoinnille tyypillistä on tiedon muuttumattomuus(muutos tehdään tekemällä uusi, erilainen kopio), rekursion runsas käyttö, tietorakenteiden korostuminen sekä laskentametafora. Proseduraalisen ohjelmoinnin:(toiminto-ohjelmoinnin) perusabstraktio on aliohjelma. Proseduraalinen ohjelmoija keskittyy etsimään koodistaan tai suunnitelmastaan toimintoja, jotka toistuvat, ja tekee niistä aliohjelmia. Proseduraalinen ohjelmointi esiintyy yleensä imperatiivisen ohjelmoinnin kanssa yhdessä.

4 1. JOHDANTO Olio-ohjelmointi: näkee kaiken olioina ja niiden välisenä kommunikaationa. Olio-ohjelmoija keskittyy hahmottamaan olioita ja niiden välisiä suhteita. Myös olio-ohjelmointi on yleensä imperatiivista ohjelmointia, vaikka deklaratiivinen olioohjelmointi ei olekaan käsitteenä mahdoton ajatus. Funktio-ohjelmointi:(funktionaalinen ohjelmointi) on eräässä mielessä proseduraalisen ohjelmoinnin yleistys. Funktioohjelmoija näkee ohjelman(matemaattisena) funktiona. Funktioohjelmalle tyypillisiä ilmaisukeinoja ovat funktionaalit(funktiot, jotka ottavat toisia funktioita parametrikseen). Funktioohjelmointi lasketaan perinteisesti deklaratiiviseksi ohjelmoinniksi, vaikka oikeastaan deklaratiivinen funktio-ohjelmointi onkin harvinaisempaa kuin imperatiivinen funktio-ohjelmointi, jossa funktiot ovat oikeastaan vain yleistettyjä aliohjelmia. Logiikkaohjelmointi: perustuu ajatukseen, että looginen päättely voidaan mekanisoida(joka pitää paikkansa vain rajoitetusti). Logiikkaohjelmoija näkee ohjelman loogisena väitteenä, joka pitää todistaa. Logiikkaohjelma koostuu kyseisen väitteen muotoilusta sekä niiden oletusten muotoilusta, joita päättelyssä voidaan käyttää. Puhtaimmillaan logiikkaohjelmointi on täysin deklaratiivista, mutta käytännössä logiikkaohjelmointia harrastetaan myös imperatiivisesti, jossa päättelysäännöt vastaavat aliohjelmia. Olio-ohjelmoinnista ja funktio-ohjelmoinnista on kummastakin tiedekunnassamme laudaturkurssi(tjtl33 ja TIE328). Ohjelmointikielet jaotellaan usein myös yllämainitttuihin paradigmalokeroihin. Tämä on kuitenkin varsin ongelmallista. Jokaisella ohjelmointikielellä on omin paradigmansa, jota se tukee parhaiten, mutta hyvin monet kielet ovat aidosti moniparadigmakieliä siinä mielessä, että niitä voidaan käyttää mainiosti useammassakin ohjelmointiparadigmassa. Seuraavassa olen luetellut tyypillisiä ohjelmointikieliparadigmojen tunnusmerkkejä ja tyyppiesimerkkejä; kannattaa kuitenkin muistaa, että minkään paradigman tyyppiesimerkit eivät rajoitu pelkästään sen paradigman sisälle. Imperatiivisen kielen:(käskykielen) merkittävimmät tunnusmerkit ovat sijoituslause(tai-lauseke) ja peräkkäistäminen. Useimmissa kielissä peräkkäistäminen on implisiittistä: peräkkäin kirjoitetut lauseet suoritetaan peräkkäin. Niissäkin kielissä yleensä puolipiste on peräkkäistyksen merkkinä. Lähes kaikki kielet ovat imperatiivisia. Tyyppiesimerkkejä ovat Algol-suvun kielet(pascal, C, C++, Java).

1. KIELTEN JAOTTELUJA 5 Deklaratiivisen kielen:(kuvailukielen) tunnusmerkki on se, että siitä puuttuu sijoituslause ja peräkkäistäminen. Deklaratiivisen kielen pääetu on, että siinä pätee viittausläpinäkyvyys(referential transparency), mikä helpottaa huomattavasti ohjelmien formaalia pyörittelyä käsin tai koneellisesti. Aidosti deklaratiiviset kielet ovat harvinaisia, ja niihin pätee Alan Perlisin[25] lausahdus: Purely applicative languages are poorly applicable.(perlis käytti deklaratiivisista kielistä nimeä applikatiivinen kieli.) Esimerkkejä lienevät λ-laskenta ja John Backusin FP-kieli[6]. Viime vuosikymmenellä kehitettiin muutamia tekniikoita, joilla kielestä saatettiin tehdä eräässä mielessä sekä deklaratiivinen että imperatiivinen. Näitä tekniikoita käyttäviä kieliä ovat Clean ja Haskell. Proseduraaliset kielet:(toimintokielen) tukevat aliohjelmarakennetta. Tyyppiesimerkkejä ovat C ja Pascal. Myös C++ ja Java kuuluvat tähän luokkaan, vaikka ne ovatkin ensisijaisesti oliokieliä. Oliokielet: tukevat olioita, joilla on identiteetti ja toiminta(metodit) sekä toimintojen periminen oliolta toiselle(tai luokkapohjaisissa kielissä luokalta toiselle). Tyyppiesimerkkejä ovat Smalltalk, Python, Java ja C++. Funktiokielten:(funktionaalisten kielten) tärkein tunnusmerkki on tuki täysivaltaisille funktioille(funktioille, joita voi palauttaa funktiosta, antaa funktiolle parametriksi ja tallettaa tietorakenteisiin). Muita tyypillisiä mutta ei universaaleja ominaisuuksia ovat tuki halvalle tiedon kopioinnille, algebralliset tietotyypit ja niiden hahmonsovitus ja tehokas rekursio. Tyyppiesimerkkejä ovat Lisp, SML, Haskell ja Clean. Myös useimmat oliokielet voidaan sijoittaa tähän kategoriaan, sillä olioilla ja täysivaltaisilla funktioilla on paljon yhteistä ainakin pellin alla. 1.3. Ousterhoutin jaottelu. John Ousterhout[24] määrittelee järjestelmäohjelmointikielen ja juontokielen eron seuraavasti: järjestelmäohjelmointikieli: Nämä kielet on tarkoitettu tietorakenteiden ja yksittäisten komponenttien toteuttamiseen siirrettävästi ja korkeammalla tasolla kuin symbolisella konekielellä kirjoitettaessa. Ne käyttävät vahvaa staattista tyypitystä. Järjestelmäohjelmointikieliä ovat esimerkiksi PL/I, Pascal,C,C++jaJava.

6 1. JOHDANTO juontokieli: Juontokielet olettavat, että on jo olemassa joukko hyödyllisiä komponentteja, jotka on kirjoitettu järjestelmäohjelmointikielillä. Juontokieliä käytetään komponenttien yhdistelemiseen, eräänlaisina liimoina(usein puhutaankin englanniksi glue languageistä). Juontokielet käyttävät tyypillisesti dynaamista tyypitystä- tyypityksen vahvuus vaihtelee.(ousterhout puhui tyypittömyydestä mutta hän tarkoitti dynaamista tyypitystä.) Juontokieliä ovat esimerkiksi Perl, Python, Rexx, Tcl, Visual Basic ja Unixin kuoret. Ousterhoutin jaottelua on kovasti kritisoitu. 2. Kielen valinta Tyypilliset tavat valita toteutuskieli ovat me ollaan aina käytetty tätä kieltä tuo kieli on kaikkien huulilla; käyttäkäämme sitä Kumpaakin tapaa voidaan kenties perustella liiketoiminnallisilla syillä, mutta teknisesti molemmat tavat ovat huonoja. Varsinkin ison projektin suunnittelijoiden kannattaa pohtia kielen valintaa tosissaan, sillä sillä voi olla iso vaikutus projektin tuottavuuteen. Projektiorhanisaatiolle uuden ja oudon kielen valintaa pidetään merkittävänä riskitekijänäprojektinonnistumiselle 1 Kannattaa huomata, että kielen valintaa ei voi tarkastella irrallaan kielen tukityökalujen(kääntäjä, tulkki, debuggeri yms.) tarkastelusta, mutta niitä ei silti pidä sekoittaa toisiinsa. Useimmissa kielisodissa, mitä esimerkiksi netissä käydään, kielet ja niiden tukityökalut sekoitetaan toisiinsa niin autuaasti, että vertailun mielekkyys katoaa kokonaan. Lawlis[19] on esittänyt prosessin, jolla toteutuskielen voi valita(näennäisen?) täsmällisesti vaatimusten mukaan. Burgess[7] on esittänyt kriteereitä, jota hänen mukaansa on syytä tarkastella valittaessa toteutuskieltä korkealaatuisen tuotteen tekemistä varten. Raymond[29] on käsitellyt kielen valintaa Unix-ympäristöön ohjelmaa rakentavan vapaaohjelmaprojektin näkökulmasta, mutta hänen havaintonsa ovat yleisemminkin sovellettavissa. Seuraavassa olen koonnut Lawlisin, Burgessin ja Raymondin pohjalta muutaman kysymyksen, joita voidaan käyttää kielten arvioinnissa(ei missään erityisessä järjestyksessä): (1) Tukeeko kieli hyvää ohjelmointityyliä ja tekeekö se huonon tyylin hankalaksi? 1 Eikösittenolisikinparempi,ettäkaikkiopettelisivatuseitakieliäjokoulussa tai yliopistolla?

3. OHJELMOINTIKIELTEN SUUNNITTELUPERIAATTEITA 7 (2) Onko kielestä olemassa standardi? Miten tarkasti ja selkeästi se määrittelee kielen? Tukevatko kielen toteutukset standardia ja tekevätkö ne epästandardin koodin kirjoittamisen hankalaksi? (3) Onko kielestä olemassa laadukkaita toteutuksia? (4) Onko kieli riippumaton yksittäisistä käyttöjärjestelmistä ja laitteistoista? Toisin sanoen, onko se siirrettävä myös käytännössä? (5) Tukeeko kieli sovellusalueita, joilla projekti tai organisaatio toimii? (6) Auttaako vai haittaako se turvallisuuden(safety) ja luotettavuuden tavoittelua? (7) Ovatko sen toteutukset ajanmukaisia? (8) Onko sille olemassa tarvittavat prosessia tukevat työkalut? 3. Ohjelmointikielten suunnitteluperiaatteita Tony Hoare kirjoitti 1970-luvun alussa poleemisen artikkelin[10], jossa hän antoi mielestään objektiiviset kriteerit ohjelmointikielen hyvyydelle. Ne ovat seuraavat. Kielen tulisi auttaa ohjelman suunnittelussa. Kielen tulisi auttaa ohjelman dokumentoinnissa. Kielen tulisi auttaa virheiden jäljittämisessä. Näiden pohjalta Hoare nimeää viisi avainlausahdusta, jotka kuvaavat hyvää ohjelmointikieltä: yksinkertaisuus: Yksinkertaisuus on välttämätöntä, sillä muuten edes kielen kehittäjä ei voi arvioida tekemiensä valintojen seurauksia eikä kielen toteuttaja voi saavuttaa edes luotettavuutta saati sitten tehokkuutta ja nopeutta. Yksinkertaisuudesta hyötyy kuitenkin ensisijaisesti kielen käyttäjä. turvallisuus: Turvallisuudella Hoare tarkoittaa sitä, että kielellä kirjoitettu ohjelma ei saa missään tilanteessa edes ohjelmoijan virheen seurauksena käyttäytyä hallitsemattomasti(esimerkiksi sekoittaa käyttöjärjestelmän tai muistinhallinnan tietorakenteita) tai eri järjestelmissä eri tavoilla. Lisäksi kielen syntaksin tulee olla sellainen, ettei yksinkertainen kirjoitusvirhe muuta ohjelman merkitystä merkittävästi. Nykyisinä Internet-ohjelmoinnin aikoina turvallisuus on entistä merkittävämpi, sillä juuri ohjelmointikielten turvallisuuden puute on ollut merkittävä tietomurtoja edistävä tekijä. lyhyt kääntymisaika: Käännösajan(se aika, joka kestää koodin muuttamisen päättymisestä siihen, kun muutettua ohjelmaa voi ajaa) tulee olla mahdollisimman lyhyt, jotta virheenjäljitys ja-korjaus onnistuisi mahdollisimman hyvin. Tämä

8 1. JOHDANTO vaikuttaa myös kielensuunnittelijan työhön, sillä eri ominaisuudet vaativat eri määrän työtä käännösaikana. ajonaikainen tehokkuus: Ohjelmointikieli on työkalu ja siksi sen tulee olla tehokas. Tässä pätee sama kuin edellisessäkin kohdassa: kielensuunnittelija voi vaikuttaa paljon siihen, että onko hänen kielensä toteutettavissa tehokkaasti. Tämä ja edellinen vaatimus ovat osittain keskenään ristiriitaisia, sillä pääsääntöisesti ajonaikainen tehokkuus paranee, kun käännösaikaa kasvatetaan lisäämällä kääntäjään optimointeja. Kuitenkin kielen suunnittelija voi vaikuttaa paljon siihen, että kuinka paljon näitä optimointeja välttämättä tarvitaan. luettavuus: Ohjelman luettavuuden tärkeyden pitäisi olla kaikille selvä. Hoare antaa myös artikkelissaan monia ohjeita siitä, miten hänen mielestään näihin tavoitteisiin voitaisiin päästä, mutta monet niistä ovat jo varsin kyseenalaisia. Silti kielensuunnittelusta kiinnostuneen kannattaa tutustua Hoaren artikkeliin kokonaisuudessaan. Hoaren listaan voimme lisätä vielä yhden avainlausahduksen: stabiilius. Tuotantokäytössä olevan kielen tulee olla saavuttanut tietynasteinen kypsyys. Kielen käyttäjien tulee voida luottaa siihen, ettäjuurisekielenversioonvalidivieläkahden,viidenjaaikausein vielä kymmenenkin vuoden kuluttua sekä ei pelkästään Windowsissa vaan myös Unixissa, Macissa ja vaikkapa GNU:ssa. Tässä auttaa voimakkaasti kielen standardointi, sillä standardi antaa stabiiliutta ja antaa yhteisen pohjan kielen eri toteutuksille. TEHTÄVÄ 1.1. Ovatko nämä kriteerit tarkoituksenmukaisia? Ovatko ne kattavia? Mitä sinä pidät tärkeänä ohjelmointikielessä? TEHTÄVÄ 1.2. Löydätkö vastaavuuksia ohjelmointikielen ja ohjelman hyvyyden arviointiin käytettävien kriteereiden väliltä? 4. Kielen määrittely Kielestä on aina syytä kirjoittaa määrittelydokumentti(specification) samaan aikaan kun sitä ensimmäistä kertaa toteutetaan tai heti sen jälkeen. Määrittelydokumentti kertoo ohjelmoijalle, mitä kieli tarjoaa, ja toteuttajalle, mitä hänen ohjelmansa tulee tehdä. Tämän dokumentin lisäksi on toki hyvä olla ohjelmoijan opas erikseen, koska määrittelydokumentti on ollessaan hyödyllinen tavallisesti suhteellisen vaikealukuinen. Määrittelydokumentissa kuvataan kaikki oleellinen kielestä riittävällä tarkkuudella. Tässä on valittavissa monta tarkkuustasoa: voidaan esittää asia epämuodollisesti tai sitten hieman muodollisemmin. Kielioppi esitetään nykyisin lähes aina täysin muodollisesti käyttäen tiettyjä formalismeja(tavallisimmin Backus-Naur Form(BNF)

4. KIELEN MÄÄRITTELY 9 tai sen muunnokset EBNF ja ABNF). Merkitysoppi on tapana ilmaista sanallisesti, koska olemassaolevat merkitysopin muodolliset kuvausmenetelmät(aksiomaattinen, denotationaalinen ja operationaalinen) ovat varsin vaikeita kirjoittaa ja lukea. Myös mahdollinen tyyppijärjestelmä voidaan kuvata muodollisesti esittelemällä se päättelysääntöjoukkona. Palaamme näihin kaikkiin formalismeihin myöhemmin. Uuden ohjelmointikielen määrittelydokumenttia levitetään tavallisimmin kielen alkuperäisen toteutuksen mukana. Toisinaan erityisesti yliopistoissa ja tutkimuslaitoksissa luotujen kielten määrittelydokumentti julkaistaan laitosraporttina tai jopa kansainvälisenä tutkimusartikkelina, ja monien määrittelyjen nimi onkin muotoa Report onthexlanguagey,missäxonjokinkieltäykuvaavalausahdus.tavallista on myös julkaista kielten paranneltuja versioita, jolloin saattaa tulla kyseeseen julkaista myös Revised Report on the X Language Y. Scheme on tästä mainio esimerkki: Scheme-raportista on nyt voimassa viides revisio[15]. Kun kieli on saavuttanut tietyn kypsyystason ja käyttäjäjoukon, aletaan tavallisesti puuhata sen standardointia. Standardointia harrastavat monet järjestöt, tärkeimpinä ISO(kansainvälinen standardointijärjestö, ), usein yhteistyössä IEC:n(kansainvälinensähköteknillinenstandardointijärjestö, )kanssa, ECMA(informaatio- ja kommunikaatojärjestelmiä standardoiva eurooppalainenjärjestö, )sekäieee(instituteof ElectricalandElectronicsEngineers, ).Takavuosina merkittävässä asemassa olivat myös Yhdysvaltain kansallisen standardointijärjestön ANSI:n standardit, mutta nykyisin lähes kaikki ohjelmointikieliin liittyvät ANSI-standardit ovat myös kansainvälisiä ISO/IEC-standardeja. Usein tosin kielten standardointi tehdään näiden virallisten tahojen ulkopuolella(esimerkiksi Haskell-kielen standardointi tehtiin käyttäjä- ja toteuttajayhteisön sisällä, ja kielen määrittely julkaistiin kirjana[26] ja lehtiartikkelina[27]). Seuraavassa on listattu joidenkin tunnettujen kielten standardit: C-kielestä on kolme standardia: ANSI X3.159-1989, ISO/IEC 9899:1990 ja ISO/IEC 9899:1999. Kaksi ensimmäistä ovat oleellisesti sama standardi ja käsittelevät sitä C:n versiota, jota on tapana kutsua ANSI C:ksi, C89:ksi tai C90:ksi. Kolmas standardi käsittelee C:n uutta versiota C99:ää. C++-kielen standardi on ISO/IEC 14882:1998. Scheme-kielen standardi on IEEE Std 1178-1990. C#-kielen standardi on ECMA-334. BASIC-kielestä on neljä standardia: ANSI X3.60-1978, ECMA- 116, ANSI X3.113-1987(R1998) ja ISO/IEC 10279:1991(E). Ne kaikki käsittelevät hieman eri versiota kielestä. Java-kielestä ei ole standardia.

10 1. JOHDANTO 5. Toteutustekniikoista Ohjelmointikielten toteutukset jaetaan kahteen pääluokkaan: on tulkkeja(interpreter) ja kääntäjiä(compiler). Rajanveto näiden luokkien välillä on hankalaa. Räikeimmissä tapauksissa se on suhteellisen helppoa: tulkki lukee ohjelmatekstiä ja suorittaa sitä lukiessaan, kääntäjä tuottaa ohjelmatekstistä konekielisen version, joka ajetaan erikseen. Käytännössä kuitenkaan puhtaita tulkkejaeiole. Varsin suosittu tapa toteuttaa tulkki on rakentaa se kaksivaiheiseksi. Tulkkiin sisältyy eräänlainen esikääntäjä, joka kääntää ohjelman jonkin kuvitteellisen koneen konekielelle. Tämä kuvitteellinen eli virtuaalinen kone on suunniteltu siten, että sille on kyseinen kieli helppo kääntää ja toisaalta sitä on helppo simuloida ohjelmallisesti. Tulkin toinen osa on sitten tämän virtuaalisen koneen simulaattori, jota usein sanotaan virtuaalikoneeksi, joka sitten tosiasiassa tulkkaa tuon käännetyn tuloksen. Tämän virtuaalisen koneen konekieli on eräänlainen välikieli, jota tulkki käyttää apunaan. Sitä kutsutaan toisinaan tavukoodiksi(bytecode). Ohjelmointikielten kääntäjän(ja virtuaalikoneratkaisua käyttävän tulkin esikääntäjäosan) perusrakenne on kaksijakoinen: sillä on lähdekielestä riippuva etupää ja kohdekielestä(kohdekoneen konekieli) riippuva takapää. Etupää koostuu neljästä vaiheesta: leksikaalinen analyysi, syntaktinen analyysi, semanttinen analyysi ja välikoodin(intermediate code) tuottaminen. Takapää koostuu optimoimesta ja tuloskoodin(object code) tuottimesta. Tavallisesti osa näistä vaiheista tapahtuu limittäin, ei erillisinä vaiheina välituloksineen. Kääntäjätekniikan(jota myös tulkeissa käytetään) perusteos on ns. lohikäärmekirja[4], mutta se on suhteellisen vanha ja keskittyy lähinnä käskykielten kääntämiseen. Uudempi, ihan kohtuullinen kirja on Andrew Appelin Modern compiler implementation in Java[5], josta on olemassa versiot myös C- ja ML-kielille. Funktiokielten toteutusta käsittelee Peyton Jones[28].

Osa1 Imperatiivinen ohjelmointi

LUKU 2 Konekielinen ohjelmointi Tässä luvussa käsitellään konekielistä ohjelmointia ja esitellään kuvitteellinen kone, jonka avulla monisteessa myöhemmin esitellään eri kieliominaisuuksien toiminta. 1. Konekielet Konekielellä tarkoitetaan sitä kieltä, jota tietokone ymmärtää suoraan. Koska kaikki nykytietokoneet perustuvat samaan ideaan siitä, miten tietokone toimii(ns. von Neumannin kone), ovat myös eri koneiden konekielet suurpiirteisesti katsoen samanlaisia. Yhteistä kaikille konekielille on se, että ne eivät ole tekstuaalisia vaan asiat ilmaistaan konekielellä koodaamalla ne jollakin annetulla tavallatavujonoksi 1,jotasittenkoneenprosessoritulkitsee. Yhteistä myös kaikille konekielille on se, että ohjelmat voidaan jäsentää dataksi ja koodiksi, ja koodi voidaan edelleen jäsentää jonoksi käskyjä(engl. instructions), jotka viittaavat dataan ja muualle koodiin. Käskyt puolestaan voidaan luokitella karkeasti seuraavasti: (1) datan siirto (2) kokonaislukuaritmetiikka (3) vertailu (4) ehdolliset hypyt (5) ehdottomat hypyt (6) järjestelmäkutsut (7) sovellusaluekohtaiset käskyt (8) järjestelmäkäskyt Näistä viisi ensimmäistä käskyluokkaa ovat jatkuvassa käytössä kaikissa ohjelmissa. Järjestelmäkutsujakin käytetään kaikissa ohjelmissa, mutta niiden käyttötaajuus vaihtelee. Järjestelmäkäskyjä eivät tavalliset ohjelmat kykene käyttämään, ne ovat olemassa käyttöjärjestelmien tarpeita varten. Useimmat tietokoneet tarjoavat lisäksi koko joukon erilaisia sovellusaluekohtaisia käskyjä; näistä lähes yleiskäyttöisen aseman on saanut liukulukukäskyt, pöytäkoneissa tavallisia 1 Tavu(engl.byte)eivälttämättäolekahdeksanbittinen,vaikkanykykoneissa näin onkin. Huolitellussa kielenkäytössä tavu tarkoittaa koneen pienintä osoitettavissa olevaa tietoyksikköä; jos halutaan puhua nimenomaan kahdeksanbittisestä tietoyksiköstä, korrekti termi on oktetti. 13

14 2. KONEKIELINEN OHJELMOINTI ovat erilaiset reaaliaikagrafiikan piirtämisessä tarvittavat laskentamenetelmät(esimerkiksi SIMD ja MMX). Yleensä konekielissä on jokin varsin yksinkertainen mekanismi, jollaerikäskytvoidaanerottaatoisistaan.vanhoissa,ns.cisc-malleissa 2 käskyn aloitti yleensä ns. operaatiokoodi(engl. opcode), joka yleensä vei yhden tavun. Operaatiokoodi ilmaisi, mistä käskystä oli kyse sekä mistä löytynyttä dataa käsky käsitteli. Operaatiokoodia seurasi vaihteleva määrä operandeja, jotka tarkensivat datan sijaintia(antaen esimerkiksi kiinteän osoitteen, mistä data löytyy). UudemmissaRISC-maleissa 3 käskytovatyleensäkiinteämittaisia(esimerkiksi neljän tavun mittaisia riippumatta käskystä) sekä sisältävät operaatiokoodin ja yhden tai useamman operandin. Vaikka konekielet ovatkin suurpiirteisesti katsoen samanlaisia, niiden välillä on huomattavia eroja yksityiskohdissa. Pääsääntöisesti vain samanlaiselle koneelle tarkoitettu konekielinen ohjelma toimii toisessa koneessa. Eri prosessorit jaotellaan sen mukaan, toimivatko toiselle kirjoitetut ohjelmat toisessa prosessorissa. Keskeinen käsite on käskykanta-arkkitehtuuri(engl. instruction set architecture), joka määrää, mitä käskyjä prosessori tukee. Tällä hetkellä merkittävät käskykanta-arkkitehtuurit ovat IA-32: Ehkäpä kaikkien aikojen menestynein käskykanta-arkkitehtuuri: Lähes kaikki nykyiset pöytäkoneet ja kannettavat perustuvat IA-32:lle. Myös monet vähäistä tai keskinkertaista tehoa vaativat palvelimet käyttävät IA-32:a. Ensimmäinen prosessori, joka tuki tätä käskykantaa, oli Intelin 80-386 vuodelta 1985. Myöhemmät prosessorit ovat laajentaneet käskykantaa, mutta sen ydin on edelleen sama, jota 80-386 tuki. IA-32:ta tukevia prosessoreita valmistavat lähinnä Intel ja AMD, mutta on muitakin valmistajia. Kuten tietokonealalla yleensäkin on tapana, markkinajohtaja IA-32 ei ole teknisesti paras markkinoilla olevista vaihtoehdoista. AMD64: AMD:n suunnittelema uusi(2003) käskykanta-arkkitehtuuri, joka on IA-32:n laajennus samassa mielessä kuin IA-32 itse oli aiempien Intel 8086- ja 80286-arkkitehtuurien laajennus. Vaikka AMD64 on varsin nuori, sen odotetaan seuraavien vuosien korvaavan IA-32:n. Kuten IA-32:ta, AMD- 64:ää tukevia prosessoreita valmistavat sekä AMD(Athlon64 ja Opteron) että Intel(EM64T). 2 ComplexInstructionSetComputer;valtaossassapöytäkoneitakäytettäväIntelin 32-bittinen prosessoriarkkitehtuuri IA-32(80386, Pentium ym.) kuuluu tähän luokkaan historiansa vuoksi. 3 Reduced/RegularInstructionSetComputer;näitäovatkäytännössäkaikki 1980-luvun loppupuolella tai sitä myöhemmin puhtaalta pöydältä suunnitellut prosessoriarkkitehtuurit; esimerkiksi Sparc, Alpha ja mobiililaitteista usein löytyvä ARM.

2. SYMBOLISET KONEKIELET 15 PowerPC: Applen, IBM:n ja Motorolan yhteishankkeena 1990- luvun alussa lanseeraama käskykanta-arkkitehtuuri, jota käyttävät nykyisin lähinnä uudehkot Macintosh-koneet. ARM: ARM on suhteellisen suurta laskentatehoa tarvitsevien sulautettujen järjestelmien(esimerkiksi mobiilipäätelaitteet) ja kämmenmikrojen prosessorien käskykanta-arkkitehtuuri. ARM-yhteensopivia prosessoreita valmistaa moni mikroprosessorivalmistaja. MIPS: Merkittävä suurta laskentatehoa vaativien sulautettujen ja mobiilien järjestelmien prosessorien käskykanta-arkkitehtuuri; käytössä myös SGI:n työasemien prosessoreissa. Sparc: Suosittu käskykanta-arkkitehtuuri palvelinkäytössä. Alkuperäinen Sparc on 32-bittinen; sen 64-bittinen laajennus on nimeltään UltraSparc. 2. Symboliset konekielet Konekieltä ei juuri koskaan kirjoiteta käsin. Konekieliset ohjelmat syntyvät yleensä varsinaisten ohjelmointikielten kääntäjien vasteena. Toisinaan kuitenkin ohjelmoija haluaa kirjoittaa samalla abstraktiotasolla, jonka konekieli tarjoaa. Tällaisia tilanteita varten jokaiseen konekieleen liittyy symbolinen konekieli(engl. assembly). Se on konekielisen ohjelman tekstuaalinen esitysmuoto, jossa kukin käsky on omalla rivillään, osoitteiden sijasta käytetään symbolisia nimiä ja jossa käskyn toimittama operaatio ja sen operandit on selvästi erotettu toisistaan. Symbolisella konekielellä kirjoitetun ohjelman kääntämiseen varsinaiselle konekielelle tarvitaan oma ohjelmansa(tosin onnistuusekylläkäsinkin),ns.assembler 4. Lähes kaikilla symbolisilla konekielillä on sama perusrakenne. Kuten edellä jo todettiin, kukin käsky on omalla rivillään. Pystysuunnassa symbolisellä konekielellä kirjoitettu ohjelma jakautuu sarakkeisiin, joiden avulla käskyn eri osat jäsentyvät. Tavallisesti käskyn osoitetta edustava symbolinen nimi, ns. label, on ensimmäisessä sarakkeessa. Jos sellaista ei ole, ensimmäinen sarake on tyhjä. Toinen sarake on varattu käskyn muistikkaalle(engl. mnemonic) yleensä kolmikirjaiminen, joskus kaksi- tai nelikirjaiminen tunnus, joka nimeää käskyn. Kolmas, neljäs ja joskus viideskin sarake on käskyn operandien käytössä. Tämän tarkemmin ei symbolisia konekieliä voi kuvata yleisesti, sillä jokaisella symbolisella konekielellä on omat merkintätapansa. Tavallisesti kullakin käskykanta-arkkitehtuurilla on täsmälleen yksi symbolinen konekieli; IA-32 on tästä poikkeus, sillä on nimittäin niitä kaksi: AT&T:n ja Intelin symbolinen konekieli. 4 Huomaa:assemblyonkieli,assemblerohjelma.

16 2. KONEKIELINEN OHJELMOINTI KUVA 1. Yksinkertainen aliohjelma C-kielellä! " ##$ % &! # ' (! ) %! ) # ) * )! # ) %! * + ) %!# ) *,% ) # ) % ) # ) -. +! " ##$./ ( * % ) #) ) ) #) #"# ) "+ ) #) # # ) *,% ) # ) % ) # ) -./. + (!! ) %! * ) # ) KUVA 2. Yksinkertainen aliohjelma IA32-arkkitehtuurin symbolisella konekielellä(at&t) Kuvissa 2, 3 ja 4 on kuvattu yksinkertainen aliohjelma kolmella eri symbolisella konekielellä. Vastaava C-kielinen aliohjelma on kuvassa 1. 3. Abstraktit koneet Abstrakti kone on käskykanta-arkkitehtuuri, jota ei ole tarkoitettu toteutettavaksi suoraan laitteistossa. Jos abstaktilla koneella on ohjelmistototeutus, se on virtuaalikone.

3. ABSTRAKTIT KONEET 17 " % &! #! / (.. % ) # ) " ) " # " # ) *! ) # %.. + * # ) * ) # ) "../ ( ) # # ) % ) # ) ) " # " # ) $ ) # " # ) ) # # ) " ) # # ) ) # ) # ) ) # ) # ) ) # ) $ # ) %../ ) # "+ # ).. + ( * ) # ) KUVA 3. Yksinkertainen aliohjelma UltraSparc-arkkitehtuurin symbolisella konekielellä Ohjelmoijan näkemä tietokone on harvoin täsmälleen se, jonka tietokoneen laitteisto toteuttaa. Yleensä ohjelmoija voi luottaa käyttöjärjestelmän palveluihin. Käyttöjärjestelmä siis rakentaa fyysisen tietokoneen päälle eräänlaisen virtuaalisen tietokoneen, siis virtuaalikoneen. Joskus ohjelmoijan kirjoittamaa ohjelmaa suorittaa simulaattori, joka imitoi jotain abstraktia konetta; tällöin ohjelmoijan näkemä kone on tyystin toinen kuin mitä laitteistosta voisi päätellä. Tällainen tilanne on esimerkiksi silloin, kun Java-ohjelmaa ajetaan Java-virtuaalikoneessa. Tämän luvun loppuosa esittelee erään abstraktin koneen, joka on eräänlainen todellisten koneiden idealisaatio, ja se tarjoaa jonkin verran myös käyttöjärjestelmältä odotettavia palveluita. Ideana on, että myöhemmin tässä monisteessa voidaan sitten pohtia kehittyneempien ohjelmointikielten toteutusta tämän abstraktin koneen tarjoamassa viitekehyksessä ilman, että tarvitsee miettiä sellaisia kääntäjätekniikan inhottavuuksia kuten rekisterien valintaa.

18 2. KONEKIELINEN OHJELMOINTI % &! #' ( * # %, # # *! # # % #./ ( # # # # # # # #"+ # # %, # *! # # % " # #./ % KUVA 4. Yksinkertainen aliohjelma PowerPC-arkkitehtuurin symbolisella konekielellä 4. Neloskielen idea Neloskieli on erään abstraktin koneen symbolinen konekieli. Ennen kuin voidaan puhua itse kielestä, pitää hahmotella kyseinen abstrakti kone. Olkoon se nimeltään Neloskone. Neloskoneen rakenne on kaksijakoinen: sillä on muisti ja prosessointiyksikkö.neloskoneenmuistion2 32 tavuntaulukko;tavunkoko on tavanomaiset kahdeksan bittiä. Jokaisella muistin tavulla on yksikäsitteinen osoite, joka on 32-bittinen etumerkitön kokonaisluku. Muisti jakautuu neljään osaan: tekstimuistiin, datamuistiin, nollamuistiin, käyttämättömän muistin alueeseen sekä pinomuistiin. Kukin muistin osa on yhtenäinen osa muistia. Tekstimuisti alkaa aina osoitteesta 0, datamuisti heti tekstimuistin jälkeen ja nollamuisti heti datamuistin jälkeen. Nollamuistin jälkeen alkaa käyttämättömänmuistinalue,jotaeisaalukeajajohoneisaakirjoittaa.muistinlopussaonpinomuisti,jokapäättyyosoitteeseen2 32 1.Kunkin

4. NELOSKIELEN IDEA 19 muistialueen eli segmentin koko voi vaihdella käynnistyskerrasta toiseen; nollamuistin ja pinomuistin koko voi vaihdella myös suorituksen aikana. Tekstimuistiin kirjoittaminen on kiellettyä; muistipaikan, jonkaosoiteon0,lukeminenonmyöskiellettyä. 5 Vaikka muisti onkin tavutaulukko, sitä tavallisesti käsitellään neljäntavunelisanan(engl.word)yksiköissä 6.Sanavoidaantilanteesta riippuen tulkita etumerkittömäksi 32-bittiseksi kokonaisluvuksi, etumerkilliseksi 32-bittiseksi kokonaisluvuksi tai yksinkertaisen tarkkuudenliukuluvuksi.jossanantavutovatx 0,...,x 3,missäx 0 onse tavu,jonkaosoiteonpienin,jax 3 onsetavu,jonkaosoiteonsuurin, sana tulkitaan seuraavasti etumerkittömäksi kokonaisluvuksi: Sanan lukuarvo etumerkittömänä kokonaislukuna on 3 i=0 256 i x i, toisin sanoen vähiten merkitsevä tavu on sanassa ensimmäisenä. Neloskone on siis little-endian; jos vähiten merkitsevä tavu olisi ensimmäisenä, se olisi big-endian. etumerkilliseksi kokonaisluvuksi: Kun sana tulkitaan etumerkilliseksi kokonaisluvuksi, on sen etumerkki negatiivinen, jos sanan eniten merkitsevä bitti on 1 ja positiivinen, jos sanan eniten merkitsevä bitti on 0. Jos sanan etumerkki on negatiivinen, sanan itseisarvo saadaan, kun siihen sovelletaan ensin biteittäistä negaatiota, minkä jälkeen se tulkitaan yllä esitetysti etumerkittömäksi kokonaisluvuksi ja tulokseen lisätään 1. Positiivisen luvun arvon saamiseksi riittää soveltaa sanaan suoraan yllä esitettyä etumerkittömän luvun menetelmää. Toisin sanoen Neloskone käyttää kahden komplementti-esitystä(engl. two s complement). yksinkertaisen tarkkuuden liukuluvuksi: IEEE 754-standardin[1] mukaisesti. Sanasta voidaan käsitellä myös vähemmän merkitsevää puolikasta, siis sitä 16-bittistä kokonaisuutta, joka koostuu sanan kahdesta ensimmäisestä tavusta. Tällainen puolisana(engl. half-word) voidaan tulkita etumerkittömäksi kokonaisluvuksi tai etumerkilliseksi 5 TämämuistinjakosegmentteihinonitseasiassamatkittuUNIX-käyttöjärjestelmien käyttämästä kullekin ohjelmalle erikseen annetun muistiavaruuden rakenteesta. Unixissa nollamuistin nimi on bss. 6 Sananpituusvaihteleekäskykanta-arkkitehtuuristariippuen;yleensäseon kaksi, neljä tai kahdeksan tavua pitkä. Sitä sanotaan myös konesanaksi(engl. machine word).

20 2. KONEKIELINEN OHJELMOINTI kokonaisluvuksi yllä esitettyä vastaavalla tavalla. Tietyissä tilanteissa kaksi peräkkäistä sanaa muodostavat kaksoissanan(engl. doubleword), joka tulkitaan kaksinkertaisen tarkkuuden liukuluvuksi IEEE 754 -standardin mukaisesti. Kaksoissana, sana tai puolisana voidaan lukea vain alkaen neljällä jaollisista osoitteista. Ajatus on, että tekstimuisti sisältää suoritettavan ohjelman konekielisen koodin. Kukin käsky vie 16 tavua; käskyjen koodaus jätetään tarkoituksella määrittelemättä. Datamuisti sisältää kaiken ohjelman alussa varattavan ja alustettavan datan, nollamuisti sisältää kaiken ohjelman alussa varattavan ja nollaksi alustettavan datan. Koneessa pyörivä ohjelma voi lisäksi kasvattaa nollamuistin kokoa ja näin mahdollistaa dynaamisen muistinvarauksen(tosin ohjelma joutuu itse pitämään kirjaa yksittäisten dynaamisten muuttujien varauksista ja vapauttamisista). Pinomuistia ohjelma voi käyttää esimerkiksi aliohjelmien hallintaan. Koneessa on viisi 32-bittistä rekisteriä: SP:(Stack Pointer) Suurin osoite, joka ei kuulu pinomuistiin. FP:(Frame Pointer) On aina suurempi tai yhtäsuuri kuin SP. IP:(Instruction Pointer) Sisältää sen tekstimuistin tavun osoitteen, josta seuraavaksi suoritettava käsky alkaa. ZL:(Zero Limit) Pienin osoite, joka ei kuulu tekstimuistiin, datamuistiin eikä nollamuistiin. AR:(Address Register) Käytetään epäsuorien osoitusten osoitelähteenä. Kun Nelikone käynnistyy, se lataa ajettavan ohjelman jostakin tarkemmin määrittelemättömästä lähteestä. Ohjelma määrää tekstija datamuistin koon sekä nollamuistin ja pinomuistin lähtökoon sekä sen, mitä tekstimuistiin sisältyy ja mitkä ovat datamuistin tavujen alkuarvot. Ennen suorituksen alkamista se nollaa kaikki nollamuistin tavut. Nelikoneen käskyt on lueteltu taulukossa 1. Kukin operandi(opr1, opr2taiopr3)voiolla [nimi], jolloin operandin sisältö luetaan alkaen muistipaikasta, jonka osoite on vakion nimi arvo; [R + n], jolloin operandin sisältö luetaan alkaen muistipaikasta, joka saadaan, kun R-rekisterin(FP tai AR) sisältämään osoitteeseenlisätäänvakion(0 n<2 3 2);sekä [R n], jolloin operandin sisältö luetaan alkaen muistipaikasta, joka saadaan, kun R-rekisterin(FP tai AR) sisältämästäosoitteestavähennetäänvakion(0 n<2 3 2). Operandi voi myös olla jotain seuraavista, jos se ei esiinny nuolen ( ) vasemmalla puolella: n,jolloinoperandinsisältöonkyseinenvakion(0 n<2 3 2); tai

4. NELOSKIELEN IDEA 21 Käsky Kuvaus opr1 opr2 Kopioi opr2:n sisältö opr1:een. opr1 opr2 + opr3 Laita opr2:n ja opr3:n summa opr1:een. opr1 opr2 opr3 Laita opr2:n ja opr3:n erotus opr1:een. opr1 opr2 opr3 Laita opr2:n ja opr3:n tulo opr1:een. opr1 opr2 / opr3 Jaa opr2 opr3:lla ja laita osamäärä opr1:een. opr1 opr2 mod opr3 Jaa opr2 opr3:lla ja laita jakojäännös opr1:een. opr1 opr2 and opr3 Suorita biteittäinen ja-operaatio opr2:n ja opr3:n välillä ja tallenna tulos opr1:een. opr1 opr2 or opr3 Suorita biteittäinen tai-operaatio opr2:n ja opr3:n välillä ja tallenna tulos opr1:een. opr1 opr2 xor opr3 Suorita biteittäinen poissulkeva tai -operaatio opr2:n ja opr3:n välillä ja tallenna tulos opr1:een. opr1 not opr2 Suorita biteittäinen negaatio opr2:lle ja tallenna tulos opr1:een. opr1 reg Kopioi rekisterin reg (AR, SP, FP tai ZL) sisältö opr1:een. reg opr1 Kopioi rekisterin opr1:n sisältö reg:iin(ar, SP, FP taizl). reg1 reg2 Kopioi rekisterin reg:n(ar, SP, FP tai ZL) sisältö reg2:een(ar,sp,fptaizl). SP SP +n LisääSP:henvakion. SP SP n Vähennä SP:stä vakio n. ifopr1 =opr2gotoopr3 Josopr1:njaopr2:nsisällötovatsamat,laitaopr3:n sisältö IP:hen. if opr1 < opr2 goto opr3 Jos opr1:n sisältö on pienempi kuin opr2:n sisältö, laita opr3:n sisältö IP:hen. if opr1 opr2 goto opr3 Jos opr1:n sisältö on pienempi tai yhtäsuuri kuin opr2:n sisältö, laita opr3:n sisältö IP:hen. if opr1 > opr2 goto opr3 Jos opr1:n sisältö on pienempi kuin opr2:n sisältö, laita opr3:n sisältö IP:hen. if opr1 opr2 goto opr3 Jos opr1:n sisältö on suurempi tai yhtäsuuri kuin opr2:n sisältö, laita opr3:n sisältö IP:hen. if opr1 opr2 goto opr3 Jos opr1:n ja opr2:n sisällöt ovat erisuuret, laita opr3:n sisältö IP:hen. goto opr1 Laita opr1:n sisältö IP:hen. syscall n Tee systeemikutsu, jonka tunnus on vakio n(ks. liitea). TAULUKKO 1. Nelikoneen käskykanta nimi,jolloinoperandinsisältöonseluku,jotako.nimiedustaa. Operandi, joka on muotoa[jotain+0] tai[jotain-0] voidaan lyhentää [jotain]. Operandien koko ja tulkinta määräytyy käskyn mukaan. Pääsääntöisesti operandien on neljä tavua ja ne tulkitaan etumerkittömiksi kokonaisluvuiksi. Tämä voidaan muuttaa kirjoittamalla käskyrivin loppuun jokin seuraavista merkinnöistä:

22 2. KONEKIELINEN OHJELMOINTI (FS): Operandit ovat nelitavuisia sanoja, jotka tulkitaan yksinkertaisen tarkkuuden liukuluvuiksi. (FD): Kukin operandi koostuu kahdesta perättäisestä nelitavuisesta sanasta, joka tulkitaan kaksinkertaisen tarkkuuden liukuluvuiksi. (S): Operandit ovat nelitavuisia sanoja, jotka tulkitaan etumerkillisiksi kokonaisluvuiksi. (H): Operandit ovat kaksitavuisia puolisanoja, jotka tulkitaan etumerkittömiksi kokonaisluvuiksi. (HS): Operandit ovat kaksitavuisia puolisanoja, jotka tulkitaan etumerkillisiksi kokonaisluvuiksi. (B): Operandit ovat tavuja, jotka tulkitaan etumerkittömiksi kokonaisluvuiksi. (BS): Operandit ovat tavuja, jotka tulkitaan etumerkittömiksi kokonaisluvuiksi. Kertolaskun tulosoperandi ja jakolaskun jaettavan sisältävä operandi on kokonaislukulaskennassa aina kaksi kertaa niin pitkä kuin muut operandit. Vertailukäskyjen kolmas operandi sekä goton ainoa operandi on kuitenkin tällaisista merkinnöistä huolimatta aina nelitavuinen sana, joka tulkitaan etumerkittömäksi kokonaisluvuksi, joka on tekstimuistiin kuuluva osoite. Bitittäisten operaatioiden(and, or, xor, not) kanssa merkinnät(fs) ja(fd) ovat kiellettyjä, sillä liukuluvun bitittäinen käsittely ei ole mielekästä. Esimerkiksi käsky [tmp] [rv] 10(B) kertoo rv:n edustaman muistipaikan sisällön kymmenellä ja sijoittaa tuloksen puolisanaan, joka alkaa tmp:n sisältämästä osoitteesta. Symbolisessa konekielessä tulee olla myös tapa määritellä symbolisia nimiä osoitteille ja vakioille. Sovitaan niin, että rivin alussa oleva sana, jonka perässä on kaksoispiste, määrittelee kyseisen sanan symboliseksi vakioksi, jonka arvona on seuraavan käskyn osoite. Sovitaan myös, että pseudokäsky data, jonka perään kirjoitetaan yksi luku, lisää datamuistiin uuden nelitavuisen muuttujan, jonka alkuarvo on kyseinen luku. Lisäksi sovitaan, että pseudokäsky zero lisää nollamuistin kokoa neljällä tavulla(varaten näin tilaa yhdelle nolla-alusteiselle muuttujalle). Sovittakoon vielä, että pseudokäsky string, jonka perään kirjoitetaan C-tyylinen merkkijono, lisää datamuistiin tavujonon, jonka sisältö on tuo merkkijono. Pseudokäskyn osoite olkoon sen määrittelemän uuden muuttujan osoite(zeron tapauksessa nollamuistin ylärajan vanha arvo). Kuvassa5onesitettykuvien1,2,3ja4aliohjelmanelikielellä.

str2ulong:sp SP 4 [SP] FP FP SP [s] [FP +8] [rv] 0 loop: AR [s] [tmp] 0 [tmp] [AR](B) if[tmp] =0gotofinish [tmp] [tmp] 48 [rv] [rv] 10 [rv] [rv] +[tmp] [s] [s] +1 goto loop finish: [FP +8] [rv] FP [FP] AR [SP +4] SP SP +8 goto AR tmp: zero s: zero rv: zero 5. SYSTEEMIKUTSUT 23 KUVA 5. Yksinkertainen aliohjelma Nelikielellä 5. Systeemikutsut Ollakseen hyödyllinen ohjelman tulee voida vaikuttaa ympäristöönsä sekä ottaa ympäristöstään vaikutteita. Tämä tapahtuu ohjaamalla erilaisia oheislaitteita kuten näyttöä, printteriä ja hiirtä. Yleensä tavallisen ohjelman ei anneta kuitenkaan vapaasti keskustella oheislaitteiden avulla; syyt lienevät kaikille tutut. Sen sijaan käyttöjärjestelmä keskustelee laitteiden kanssa ja välittää ohjelmien pyynnöt eteenpäin huolehtien siitä, että samaan aikaan käynnissä olevat ohjelmat eivät tallo toisiaan varpaille. Käytännössä ohjelman tulee voidakseen keskustella ympäristönsä kanssa siis keskustella käyttöjärjestelmän kanssa. Tavallisesti tämä tapahtuu systeemikutsujen(engl. system calls) avulla: kun ohjelma haluaa käyttää käyttöjärjestelmän palveluita, se käyttää jotain erityistämekanismiakutsuakseenkäyttöjärjestelmää 7 Neloskoneen tapauksessa koneeseen on sisäänrakennettu jokunen systeemikutsu. Systeemikutsu etenee siten, että ohjelma laittaa 7 Toinenvaihtoehtoolisiantaakäyttöjärjestelmänkutsuaohjelmaatarvittaessa. Tätä sanottaisiin tapahtumapohjaiseksi(engl. event-based) systeemiksi. Tavallisesti todellisissa järjestelmissä käytetään tarpeen mukaan molempia järjestelyitä.

24 2. KONEKIELINEN OHJELMOINTI 0 Avaa olemassaoleva tiedosto 1 Luouusitiedostojaavaase 2 Sulje avattu tiedosto 3 Luetiedostosta 4 Kirjoitatiedostoon 5 Muuta luku/kirjoituskohdan sijaintia(seek) 6 Kerro luku/kirjoituskohdan sijainti(tell) 7 Jakaudu(fork) 8 Kloonaudu(clone) 9 Lähetä viesti toiselle rinnalla suoritettavalle koneelle 10 Vastaanotaviesti 11 Sammutakone 12 Odota rinnakkaisen koneen sammumista 13 Aika TAULUKKO 2. Neloskoneen systeemikutsut systeemikutsun argumentit pinoon ja käyttää sitten syscall n-käskyä, missä n on halutun systeemikutsun tunnus. Neloskoneen käyttöjärjestelmä poistaa argumentit pinosta ja laittaa tilalle paluutiedon, sekä suorittaa halutun toiminnon, mikäli se on mahdollista. Neloskoneen tapauksessa kolme parametria ottava ja yhden paluutiedon antava systeemikutsu etenee siis suunnilleen näin: SP SP 12 [SP + 8] parametri3 [SP + 4] parametri2 [SP + 0] parametri1 syscall n [paluutiedon paikka] [SP + 0] SP SP +4 Tässä n on halutun systeemikutsun tunnusnumero. Taulukossa 2 on lyhyesti esitetty Neloskoneen systeemikutsut. Tarkemmin ne esitellään liitteessä A. Tässä vaiheessa systeemikutsujen tarkka toiminta ei ole oleellista; niihin palataan myöhemmin. 6. Konekielellä ohjelmoinnista Symbolisella konekielellä ohjelmointi voi olla tottumattomalle outoa, joten sanotaan sananen siitä. Symbolisella konekielellä ohjelmoinnin kaksi tärkeintä eroa korkean tason kielillä ohjelmointiin nähden on, että konekielellä joudutaan kaikki kontrollirakenteet kirjoittaa gotoa tai muuta vastaavaa menetelmää käyttäen ja että lausekkeet joudutaan käsin purkamaan osaoperaatioihinsa(päättäen samalla, minne välitulokset tallennetaan). Näinpä konekieliohjelmointi on hyvinkin matalan tason näperöintiä ja se kannattaa pääosin jättää kääntäjän huoleksi.