Hvordan skrive Flok og Flass kode? I mange tilfelle er det svært enkelt: inchar INC inint INI Tegnet eller tallverdien kommer i I registeret. outchar OUTC outint (n) OUTI n outline OLIN I Flink maskinen blir dette: Func Adrs Corr 0 1 0 ISTORE 1 7 1 0 0 A 2 21 5 1 0 B 3 2 0 Tegnet eller tallet må først ligge i I registeret. Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 2 av 22 Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 4 av 22 Dagens tema: Hvordan skrive Flass og Flok kode? «én til én oversettelse» uttrykk løkker array er prosedyrer Prosjektet struktur del 0 feilhåndtering Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 1 av 22 Uttrykk Uttrykk er også ganske lette å oversette (siden det skal skje fra venstre mot høyre og vi ikke har parenteser): A := A * B + 5 blir til LDI A MULI B INCI 5 STI A A INTG 0 B INTG 0 Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 3 av 22
I Flink maskinen blir dette: Func Adrs Corr 0 1 0 1 7 2 2 5 1 3 2 0 ISTORE 0 0 A 1 0 B 2 7 Syv Forenkling Koden på forrige lysark kunne vært skrevet med færre instruksjoner. Det skal vi ikke gjøre i dette kurset! Det aller viktigste er at koden er riktig. Optimalisering i en kompilator er altfor komplisert for dette kurset. Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 6 av 22 Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 8 av 22 Men hva med A := A * 7 + B når vi bare kan multiplisere med verdier i minnet? Da må vi lagre 7 i minnet: LDI A MULI Syv ADDI B STI A A INTG 0 B INTG 0 Syv INTG 7 Løkker I løkker må vi hoppe utifra en test: repeat A := A + 1; until A >= 10; Hvordan beregner vi betingelsen? Vi bør i stedet beregne A 10 og sjekke om resultatet er 0. Vi skal hoppe når testen er usann. L LDI A INCI 1 STI A LDI A INCI 10 JLTI L Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 5 av 22 Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 7 av 22
Løsningen I Flink brukes følgende løsning: #! /store/bin/flass Data 0: 4 arr INTG 4 Data 1: IARZ 4 Code 0: 22 2 0 start SETC 2 Code 1: 1 0 1 LDI arr * Code 2: 21 1 0 INCI 1 Code 3: 2 0 1 STI arr * Code 4: 0 0 0 STOP For å kalle en prosedyre, hopper man til den med instruksjonen JRC som legger PC registeret i C registeret før den hopper. Ved return hopper man tilbake JMP 0 * (Nesten alltid må man gjemme unna verdien i C registeret mens man utfører innmaten i prosedyren.) Parameter og returverdi overføres i I registeret. Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 10 av 22 Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 12 av 22 Array er Hvordan kan vi bruke array er? C registeret Til hjelp for dette har vi C registeret som brukes slik: ❶ Plassér indeksen i C registeret. ❷ Bruk så LDI arr * Stjernen indikerer at den virkelige adressen får man ved å legge sammen C registeret og adressen til arr. Prosedyrer Hvordan programmerer man prosedyrer? Man trenger: ❶ En måte å hoppe til prosedyren ❷ En måte å komme tilbake ❸ Mulighet for å overføre parameter og returverdi Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 9 av 22 Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 11 av 22
Den tilsvarende koden i Flass kan se slik ut: start OUTT Skriv # outtext "Skriv et tall: "; INI # a := inint; JRC p # call p with a into a; OUTT Svaret # outtext "Svaret er "; OUTI 1 # outint(1) a; OLIN # outine; STOP # proc p: p JGEI px # if a < 0 then STI pa # SETI 0 # a := 0 a; SUBI pa # endif; px JMP 0 * # «Hopp tilbake» pa INTG 0 Skriv ITXT "Skriv et tall: " Svaret ITXT "Svaret er " (men denne koden er optimalisert og en god del kortere enn den koden vår kompilator skal lage!) Vår struktur Minila Tegngenerator Linjegenerator Symbolgenerator Flinkrepresentant Listing Del 0 Del 1 Del 2 Flok Hovedansvarlig Tregenerator Kodegenerator Listeansvarlig Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 14 av 22 Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 16 av 22 Eksempel Her er et enkelt program med en prosedyre som beregner absoluttverdien av et tall: prog proc p in a out b; begproc if a < 0 then b := 0 a; else b := a; endif; endproc; var a; begprog outtext "Skriv et tall: "; a := inint; call p with a into a; outtext "Svaret er "; outint(1) a; outline; endprog Prosjektet Hvordan skriver man et større program som en kompilator? Struktur En fornuftig måte å dele opp problemet på er å se på hvor data flyter. Da er det enklere å kapsle inn deler av programmet. Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 13 av 22 Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 15 av 22
Linjegenerator leser programmet linje for linje og fjerner kommentarer. Tegngenerator deler linjen opp i enkelt tegn. Symbolgenerator setter tegnene sammen til symboler: prog begprog outtext "Hei på deg!" ; outline ; endprog Feil Hva gjør man med feil? Før prøvde man å finne så mange feil som mulig. Vi skal stoppe med melding ved første feil. Målet er å gi en så god melding at feilen er lett å lokalisere. Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 18 av 22 Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 20 av 22 Del 0 En kompilator kan lese og tolke en program tegn for tegn, men det er mye lettere om det kan gjøres symbol for symbol. Dette ordner en scanner. Anta at programmet er prog begprog Skriv en hilsen: outtext "Hei på deg!"; outline; Det var det. endprog Kommunikasjonen Følgende prinsipper brukes: Hvert objekt har en peker til de andre objekter den trenger. Hvert objekt har sin «nåværende informasjon» i lokale variable som stort sett er usynlige utenfra. Hvert objekt kaller «forgjengeren i kjeden» for å få det til å hente frem neste dataelement. Det blir tilgjengelig enten i returverdien eller i en variabel i objektet. Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 17 av 22 Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 19 av 22
I vår kompilator bruker vi denne metoden: // <<<<<<<<<<<<<<<<<<<<<<< MinilaException >>>>>>>>>>>>>>>>>>>>>>> // Dette brukes for å føre kontrollen fra mainresp.error(...) og ut // av programmet (til shutdown kallene lenger ned). class MinilaException extends RuntimeException {} // ********* Metode for standard behandling av feil ****** // public void error (String message) { //## Få tak i line og linjenummer fra CharacterGenerator, og skriv ut //## til skjerm (ved f.eks. "System.err.println(...)") //## Skriv ut på skjermen: " ***FEIL: message " //## Be også ListingResponsible å skrive ut feilmeldingen throw new MinilaException(); // Fanges i metoden "compile" over. } Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 22 av 22 Unntak Vår hovedmekanisme for feilhåndtering er unntak («exceptions»). Deklarasjon Unntak er vanlige klasseobjecter: new Exception() Å gjøre unntak Unntak «kastes»: throw new exception() Mottak Unntak kan tas imot: try {... } catch (Exception e) {... } Unntak kan følge metodekall bakover inntil de blir fanget opp. Dag Langmyhr,Ifi,UiO: Forelesning 5. september 2006 Ark 21 av 22