1 abba angry birds bombing apparatus LKTT 2012 (periodit II-III) 17. SYYSKUUTA 2012, VERSIO 1.0 Kielen määrittely annetaan laajennetulla BNF-notaatiolla, joka on seuraava. <nimi> ::= määrittely määrittelee välisymbolin nimi a1 a2 a1 jota välittömästi seuraa a2 a1 a2 a1 tai a2 [ a ] a tai ei mitään { a } nolla tai useampia kertoja a ( a1 a2 ) a3 kaarisulut määräävät vaikutusalueen (esimerkissä a1 tai a2 ja heti perään a3) Kun <nimi> esiintyy operaattorin ::= oikealla puolella, on sen merkitys täsmälleen sama kuin määrittely. 1. Perusrakenteita 1.1. Kommentti on merkkijono, joka a) alkaa -- ja päättyy rivin loppuun, tai b) alkaa merkeillä {* ja loppuu merkkeihin *} (voi siis olla useampirivinen). 1.2. Alkioiden (non-terminaalit) välissä saa olla tyhjiä merkkejä: välilyönti, rivinvaihto tai tabulaattori. 1.3. digit ::= 0 1... 9 1.4. integer ::= digit { digit } 1.5. scale_factor ::= ( E e ) [ + - ] integer 1.6. float ::= integer. integer [ scale_factor ] 1.7. number ::= integer float 1.8. letter ::= a... z A... Z ö Ö ä Ä 1.9. ident ::= letter { letter digit _ } 1.10. ident_list ::= ident {, ident } 1.11. full_ident ::= ident [ [ expression_list ] ] 1.12. qualident ::= { full_ident. } full_ident 1
2 1.13. designator ::= qualident 1.14. single_character ::= ascii merkki 32-255 1.15. character ::= single_character \ single_character 1.16. char_constant ::= character 1.17. string_constant ::= { character } 1.18. Kielen varatut sanat (tunnistetaan pienellä kirjoitettuna): and begin const div do else elsif end eval exit extern for foreach function if import in initially internal is loop mod module not of or out pointer procedure record return returns then type uses while with Näiden lisäksi varattuja sanoja ovat myös kaikki kielen tietotyyppien nimet: bool, char, float, int, string, vector, map, stack, osoittimiin liittyvät nimet val, null, kaikkien sisäisten funktioiden ja proseduurien nimet sekä vakiot TRUE, FALSE. 2. Kielen syntaksi 2.1. Käännösyksikkö 2.1.1. compilation ::= module { module } 2.1.2. module ::= module ident is [ import_part ] declaration_part procedure_part [ begin statement_sequence ] end ident. 2.2. Moduulin pääosat 2.2.1. import_part ::= import ident_list ; 2.2.2. declaration_part ::= { type_declaration ; variable_declaration ; } 2.2.3. procedure_part ::= { procedure_declaration ; function_declaration ; } 2
3 2.3. Peruslauseita 2.3.1. boolean_exp ::= expression 2.3.2. statement ::= assignment procedure_call if_statement loop_statement while_statement iterate_statement eval expression exit [ boolean_exp ] return [ expression ] 2.3.3. statement_sequence ::= [ with declaration_part do ] statement ; { statement ; } 2.3.4. assignment ::= designator - <expression 2.3.5. procedure_call ::= qualident [ actual_parameters ] 2.3.6. if_statement ::= if boolean_exp then statement_sequence { elsif boolean_exp then statement_sequence } [ else statement_sequence ] end if 2.3.7. loop_statement ::= loop statement_sequence end loop 2.3.8. while_statement ::= while boolean_exp do loop_statement 2.3.9. iterate_statement ::= for ident in range loop_statement foreach ident in expression loop_statement 2.3.10. range ::= expression... expression 2.4. Funktiot ja proseduurit 2.4.1. fp_section ::= [ in ] [ out ] ident_list : type 2.4.2. formal_parameters ::= ( fp_section { ; fp_section } ) 2.4.3. procedure_heading ::= procedure ident [ formal_parameters ] 2.4.4. procedure_body ::= statement_sequence end [ ident ] 2.4.5. procedure_declaration ::= procedure_heading := procedure_body 2.4.6. function_heading ::= function ident [ formal_parameters ] returns type 2.4.7. function_declaration ::= function_heading := procedure_body 2.4.8. actual_parameters ::= ( [ expression_list ] ) 2.4.9. function_call ::= qualident actual_parameters 3
4 2.5. Tyypit ja muuttujat 2.5.1. type ::= qualident [ pointer ] 2.5.2. record_type ::= record ident : type { ; ident : type } end 2.5.3. vector_type ::= vector [ range {, range } ] of type 2.5.4. map_type ::= map of type, type 2.5.5. stack_type ::= stack of type 2.5.6. type_declaration ::= type ident is ( type record_type vector_type map_type stack_type ) 2.5.7. map_val ::= factor : expression 2.5.8. map_init ::= { map_val {, map_val } } 2.5.9. vector_init ::= [ expression_list ] 2.5.10. initialization ::= expression vector_init map_init 2.5.11. variable_declaration ::= ident_list : type [ initially initialization ] const ident is initialization 2.6. Lausekkeet 2.6.1. primary ::= number char_constant string_constant qualident function_call ( expression ) 2.6.2. prefix_op ::= + - not & 2.6.3. factor ::= [ prefix_op ] primary 2.6.4. mult_op ::= * / div mod 2.6.5. term ::= factor { mult_op factor } 2.6.6. add_op ::= + - ++ 2.6.7. simple_expression ::= term { add_op term } 2.6.8. relation_op ::= = # = = 2.6.9. relation ::= simple_expression [ relation_op simple_expression ] 4
5 2.6.10. expression ::= relation { and relation } relation { or relation } 2.6.11. expression_list ::= expression {, expression } 2.7. Import-moduulin rakenne 2.7.1. import_module ::= extern [ C ] module ident [ requires_part ] import_declaration_part import_procedure_part end. 2.7.2. requires_part ::= uses ident_list ; 2.7.3. import_type_declaration ::= type_declaration 2.7.4. import_variable_declaration ::= ident : [ const ] type internal string_constant 2.7.5. import_declaration_part ::= { import_variable_declaration ; import_type_declaration ; } 2.7.6. import_procedure_part ::= { procedure_heading internal string_constant ; function_heading internal string_constant ; } 5
6 3. Tietotyypit 3.1. bool : totuusarvot TRUE ja FALSE. 3.2. char : ascii-merkki (8 bittinen). 3.3. int : etumerkillinen kokonaisluku, joka on yhteensopiva saman ympäristön C-kielisen int -tietotyypin kanssa (esim. 32 bittinen). 3.4. float : liukuluku, joka on yhteensopiva saman ympäristön C-kielisen double -tietotyypin kanssa (esim. 64 bittinen). 3.5. string : merkkijono (kuten C-kielessä eli ascii-merkit ja viimeisenä tavuna nolla). Merkkijonoa voi indeksoida, jolloin saatu yksittäinen merkki on tyyppiä char. 3.6. vector : Samaa tietotyyppiä sisältävä 1 N ulotteinen taulukko. 3.7. map : Assosiatiivinen taulukko. 3.8. stack : Pino, jota käsitellään aliohjelmilla push, pop ja isempty. 4. Semantiikkaa (tämä ei ole täydellinen luettelo, tarkista WWW-sivulta) 4.1. Leksikaalit 4.1.1. Merkkiliteraalien ja merkkijonojen yhteydessä voidaan käyttää merkintää \x, joka tarkoittaa merkkiä x itse tai erikoismerkintää jostain ohjauskoodista. Tällä tavoin saadaan kirjattua esim. merkkijonon sisään lainausmerkki. Ainakin seuraavien symbolien on toimittava: \n rivinvaihto (kuten C-kielessä) \t tabulaattori \0 nolla (merkkijonon lopetusmerkki) \ merkki itse (heittomerkki) \" merkki itse (lainausmerkki) \\ merkki itse (takakenoviiva) 4.1.2. Merkkijonon sisällä esiintyvät kommenttimerkit eivät aloita tai lopeta kommenttia. 4.1.3. Kielen varattu sana ei saa esiintyä muussa kuin syntaksin määräämässä merkityksessä. Varattu sana ei siis voi olla esim. moduulin, muuttujan tai tietotyypin nimenä. 4.1.4. qualident tarkoittaa pisteillä toisistaan eroteltuja nimiä (esim. moduuli.funktionimi tai moduuli.recordnimi.muuttujanimi ). 4.1.5. Nimien peittyminen on sallittua (eli jos esim. funktion parametrina on muuttuja i ja funktion rungossa silmukan silmukkamuuttuja on i, niin silmukan sisällä i-tarkoittaa silmukkamuuttujaa ja edellisen tason muuttujaan ei pystytä viittaamaan). 6
7 4.2. Moduulit 4.2.1. Määrittelyn lopussa oleva ident on sama kuin moduulin nimi. 4.2.2. Import-moduuli ei esiinny yksinään käännösyksikkönä, vaan se luetaan erillisestä tiedostosta import -lauseen seurauksena. 4.2.3. Import-moduulin uses -osassa luetellut moduulit otetaan automaattisesti mukaan käännökseen ( moduulinimi.o ) ja niiden alustuskoodi suoritetaan - paitsi jos kyseessä on C-moduuli (kts. 4(4.2)4.2.8). 4.2.4. Ohjelmakoodi lähtee suoritukseen Main-nimisen moduulin alustuskoodista. Kaikki muut moduulit ovat käännösyksiköitä, joista tuotetaan esittelytiedosto ja objektitiedosto. 4.2.5. Esittelytiedosto tuotetaan nimelle moduulinimi.abbadef 4.2.6. Kaikkien import-moduulina käyttöön otettujen moduulien alustuskoodit on suoritettava ennen Main:n käynnistymistä. 4.2.7. Jokaisen abba-kielisen moduulin ohjelmakoodissa on globaali rutiini assembler-nimellä moduulinimi$init, joka suorittaa moduulin alustuksen. 4.2.8. Jos import-moduuli on esitelty C -moduuliksi, niin se ei sisällä alustuskoodia vaan kaikki esitellyt rutiinit ovat ulkopuolisia C- funktioita. 4.2.9. Import-moduulien internal -määreet (merkkijono) kertovat rakenteista käytettävän nimen assembler-tasolla. 4.3. Lauseet 4.3.1. for ja foreach -silmukan silmukkamuuttuja on näkyvissä ainoastaan silmukan sisällä. 4.3.2. Silmukkamuuttujaan ei saa sijoittaa. 4.3.3. Pinolle suoritettu foreach käy läpi pinon kaikki alkiot (suunnassa pinon päältä pohjalle ). 4.3.4. Map-taulukolle suoritettu foreach käy läpi taulukon kaikki avaimet type T is map of string, int; puhelinluettelo : T initially { "jyke": 12345, "bitti": 45612 }; -- tulosta kaikki numerot for nimi in puhelinluettelo loop println( nimi, ":", puhelinluettelo[nimi] ); end loop; 7
8 4.3.5. Taulukolle suoritettu foreach on määritelty vain yksiulotteisille taulukoille. 4.3.6. exit boolean_exp poistuu sisimmästä silmukasta jos ehtolauseen arvo on TRUE. 4.3.7. exit -lause voi esiintyä ainoastaan silmukkarakenteen sisällä. 4.3.8. eval suorittaa lausekkeen ja hukkaa sen arvon (käytetään lähinnä silloin, jos halutaan kutsua funktiota ilman, että sen paluuarvolla on merkitystä). 4.3.9. with... do luo uuden näkyvyysalueen, jossa määritellyt tyypit ja muuttujat ovat voimassa seuraavaan lohkon sulkevaan rakenteeseen. 4.4. Tietotyypit 4.4.1. Tietotyypeillä on rakenne-ekvivalenssi. 4.4.2. Automaattisia tyyppimuunnoksia tietotyyppien välillä ei ole olemassa. 4.4.3. Osoittimilla on erityinen tyhjä arvo null, joka on tyyppiyhteensopiva kaikkien osoitintietotyyppien kanssa. 4.4.4. record -tyyppi saa sisältää osoittimen samaa tietotyyppiä oleviin alkioihin. type IntList is record x : int; next : IntList pointer end; 4.4.5. Jos osoitinta käytettäessä on yksikäsitteistä, että tarkoitetaan osoittimen päässä olevaa arvoa, toiminta tehdään automaattisesti. Jos käyttötilanne ei ole selkeä, kerrotaan varatulla sanalla val tilanteet joissa halutaan käyttää osoittimen päässä olevaa arvoa. nimi osoitin osoitin.val osoitin.nimi merkitys osoittimen arvo osoittimen osoittama arvo osoittimen päässä olevan record:n kenttä (jolle tehdään tulkinta uudelleen) a, b : IntList; p, q : IntList pointer; 8
9 p <- null; -- sijoitetaan osoitinmuuttujaan tyhjä arvo p <- &a; q <- &b; q.next <- null; q.x <- 42; -- tiedetään kohteen olevan muuttuja p.val <- q.val; -- q:n osoittama record kopioidaan -- p:n osoittamaan paikkaan p.next <- q; p.next.x <- 1; -- muuttujan b kenttä x p.next.next <- null; p.next.next.val <- b; -- semanttisesti oikein, -- viittaus null:n läpi p <- q; -- osoitin q muuttujaan p 4.4.6. Eri tietotyyppien oletusalkuarvot ovat: FALSE, a, 0, 0.0, "abba", null. 4.5. Lausekkeet 4.5.1. # on erisuuruusoperaattori. 4.5.2. boolean_exp on lauseke, jonka laskettu lopputulos on tietotyyppiä bool. 4.5.3. Peruslaskutoimitukset toimivat totutulla tavalla tietotyypeillä int ja float. 4.5.4. Perustietotyyppien välillä ei ole automaattisia tyyppimuunnoksia. (Erityisesti int ja float eivät ole yhteensopivia.) 4.5.5. mod ja div toimivat vain kokonaisluvuilla int ja toteuttavat ehdot x = (x div y) y + (x mod y) 0 (x mod y) < y tai y < (x mod y) 0 4.5.6. Merkkijonoilla string katenointi ( ++ ) tuottaa uuden merkkijonon, joka on yhdistelmä laskun termeistä. 4.5.7. Operaattori & antaa muuttujaan viittaavan osoittimen. 4.5.8. Osoittimien arvoilla toimivat yhtä- ja erisuuruusvertailut. 4.5.9. and ja or noudattavat oikosulkuevaluointia (ketjutetun lausekkeen laskeminen lopetetaan heti kun sen lopputulos on tiedossa). 4.6. Muuttujat 4.6.1. const -muuttujien tietotyyppi määräytyy määrittelyn alustuslausekkeen tietotyypin mukaan. 4.7. Funktiot ja proseduurit 9
10 4.7.1. Aliohjelmaa (procedure) saa kutsua vain lauseessa. 4.7.2. Funktiota saa kutsua vain lausekkeessa (erillisenä lauseena kutsu tehdään eval -lauseen avulla). 4.7.3. Funktioiden ja proseduurien nimet ovat kuorimettuja siten, että oikean aliohjelman valitsemiseen tarvitaan nimen lisäksi parametrien lukumäärä ja tietotyypit. Kielen sisäisten aliohjelmien nimiä ei saa kuormittaa. 4.7.4. Funktion ja proseduurin määrittelyn lopussa oleva ident on oltava sama kuin ko. aliohjelman nimi (koodin selkeyteen tähtäävä syntaksi). 4.7.5. Parametrimääreiden toiminta: Määre <tyhjä> in out in out Käyttö sijoituksessa Luku ja kirjoitus. Kuten paikallinen muuttuja (arvoparametri). Vain luku. Vakioparametrimuuttuja. Vain kirjoitus. Viitepaluuarvo. Luku ja kirjoitus. Viiteparametri. 4.7.6. Arvon palauttaminen return -lauseella proseduurista on virhe. 4.7.7. Tyhjä return -lause funktiossa on virhe. 10
11 4.7.8. Kielen sisäiset funktiot Nimi Argumentin Tulostyyppi Toiminta tyyppi len(x) string, int x:n pituus (alkioiden vector, stack lukumäärä, jossa merkkijonoilla ei ole mukana loppunollaa) ord(x) char int x:n järjestysnumero chr(x) 0 int char x:s ascii-merkki 255 pop(p) pino arvo Palauttaa pinon päällimmäisen alkion ja samalla poistaa ko. alkion pinosta. Jos pino on tyhjä, niin toiminta on määrittelemätön isempty(p) pino bool Palauttaa TRUE jos pino on tyhjä, muutoin FALSE convert(x,t) X T Palauttaa arvon joka on tietotyyppiä T ja jonka arvo on x 4.7.9. convert -funktion tulee ymmärtää vähintään muunnokset Muunnos convert(d, int) convert(i, float) Toiminta Palauttaa suurimman kokonaisluvun joka on d Palauttaa liukuluvun, jonka arvo on i 11
12 4.7.10. Kielen sisäiset proseduurit read(m,s) readln(m,s) muuttuja ja boolean status muuttuja ja boolean status Nimi Argumentin Toiminta tyyppi malloc(p) osoitinmuuttuja dynaaminen muistinvaraus, johon mahtuu osoittimen tietotyyppiä oleva alkio, osoitinmuuttuja osoittaa varattuun lohkoon free(p) osoitinmuuttuja poistaa osoittimen päässä olevan alkion käytöstä ja asettaa parametrina olevan osoittimen arvoksi null. print(a,b,...) luettelo dataa tulostaa parametrit println(a,b,...) luettelo dataa toimii kuten print, mutta tulostaa viimeisenä rivinvaihdon lukee käyttäjältä merkkejä, jotka muunnetaan parametrin m arvoksi. s on TRUE jos muunnos onnistui. (Toteutusvinkki: scanf()) lukee käyttäjältä rivin merkkejä, jotka muunnetaan parametrin m arvoksi. s on TRUE on muunnos onnistui. Myös rivinvaihtomerkki luetaan pois syötteestä. push(p,x) pino ja arvo laittaa pinon p päällimmäiseksi uuden arvon x (joka on pinon tyyppiä). 4.7.11. int, float ja string tietotyyppien parametrinvälityksen on oltava yhteensopiva C-kielestä tuotetun koodin kanssa (C:n vastaavat tietotyypit int, double ja char*). Tämä takaa sen, että abba-ohjelmat voivat käyttää C-kielellä tehtyjä kirjastoja. 12
13 4.7.12. Osoitintyypeille määritellyt malloc ja free varaavat ja vapauttavat dynaamista muistia. Molemmat ottavat yhden osoitintyyppisen argumentin. Lause malloc(p); varaa p:n osoittaman tyypin tarvitseman määrän dynaamista muistia, ja lause free(p); vapauttaa p:n osoittaman muistin. Lauseen malloc(p) suorittamisen jälkeen p sisältää varatun muistilohkon osoitteen (tai null jos muistinvaraus epäonnistui). 13
14 5. Käyttöliittymä 5.1. Kääntäjää ajetaan komennolla abbac 5.2. Kääntäjän on ymmärrettävä seuraavat komentoriviparametrit -h tulostaa käyttöohjeen. tiedosto(t) luettelo lähdekooditiedostoja. -o btiedosto valmis binääri tulee nimelle btiedosto (oletuksena abba.out). -S käännös tuottaa tiedostoon moduulinimi.s käännöksen LLVMassembler muodossa. -llib linkittää mukaan kirjaston lib. (esim. -lcurses). -Lpath hakemisto, josta kirjastoja, moduulikoodeja ja import-esittelyitä etsitään (jos tarvitaan useampia hakemistoja, niin valitsin annetaan useamman kerran). Työskentelyhakemisto on aina mukana etsinnässä. -Xstring asettaa päälle toteuttajien oman laajennuksen kääntäjässä. Esimerkkinä vaikkapa -Xgs ottaa käyttöön roskienkeruun tuotetussa binäärissä tai -Xjava tuottaa suoritettavan koodin javan tavukoodina. 5.3. Kääntäjä osaa ottaa itse automaattisesti mukaan kaikki tarvitsemansa apukirjastot ilman että käyttäjän tarvitsee niitä luetella -l ja -L vipusilla. Omat apukirjastot tulee sijoittaa hakemistoon, joka on kerrottu kääntäjän käännösvaiheessa Makefilen PREFIX-muuttujalla (katso tarkemmin työn palautusohjeista WWW-sivuilla). 5.4. Vinkki: tätä kaikkea ei ole tarvis nysvätä itse, vaan osan ominaisuuksista voi toteuttaa käyttämällä hyväksi valmiita työkaluja (clang ja llvm-sovelluskehyksen työkalut). Sopivilla parametreilla ja vipusilla kirjastojen linkitys mukaan yms. saa toteutettua helposti. 14