INF 2100 20. okt. 2004 Dette er siste forelesning. Dagens tema: Diverse om kode-generering: Litt om uttrykk, betingelser og while-setninger Prosedyrer og kall Gruppene ukene fremover: Ukene fra 25. okt. og fra 1. nov.: Lite eksplisitte oppgaver, men mye egenarbeid og gjennomgang etter gruppas ønske Ukene fra 8. nov. og fra 15. nov.: Gruppelærerne er til stede ved starten av gruppetiden, for spørsmål, inn- og utlevering De er til stede minst et kvarter, men vil ellers gå når det ikke er mer spørsmål etc. Pass på å komme i gang med Del-2. Mye hjelp på gruppene! Frist mandag 8. november. Den vil bli håndhevet strengt. Ekstra til levering av Del-2: Skrive en liten rapport ut fra noen spørsmål/punkter som blir lagt ut i god tid. Intervju for å sjekke at det er egenhendig arbeid Utplukk for intervju bekjentgjøres senest: Fredag 12. november, kl 12.00, på kurssiden Alle må da sjekke på kurssiden Og eventuelt bekrefte at forslått tid er OK (eller søke om annen tid) Vi setter opp forslag til tid, fortrinnsvis 15., 16 og 17. nov. (ca 1/2 time) Gruppelærer og kursleder er til stede Alle på laget skal kunne angi en rimelig del som de har vært med å lage Vi stiller spørsmål etc. som skal være helt greie om dere har gjort arbeidet selv Ingen godkjenning er endelig før alle intervjuene er foretatt! 2 Hoved-ansv. Kodegenerator Tregenerator void lagkode() innk utk Oversiktsbilde Listing-ansv. lagsti( A, C) lagcic( A, C) nesteinstadr() nesteinst resvar(ant, navn) Flink-repr. Instr-lager nesteledig Kodegenerator Hva tilbyr Flink-representanten utad? void lagkode() innk utk lagsti( A, C) nesteinstadr() resvar(ant, navn) reskonst(verdi) Flink-repr.? fyllgammeladr(instnr, nyadr) startopp() avslutt() skrivflok() reskonst(verdi) fyllgammeladr(instnr, nyadr) Kodegeneratoren skal være distribuert til tre-nodene To typer testutskrift: - K (start/slutt kodegen-metodene) - I (genererte instruksjoner m.m.) skrivflok() Flokfil Et antall metoder som gjør at Kode-generatoren ikke behøver å tenke på detaljer under veis (skal være en god sekretær for kodegenereringen) Kan tenke på en radio: Hvilke knotter og visere er de rette? Må tenke gjennom hvilke behov Kode-generatoren får Disse må dekkes på en effektiv og naturlig måte Og slik at de passer sammen, også stilmessig og navnemessig Vi gjerne naturlig bli delt opp i grupper Skal kunne beskrives i begreper som kodegeneratoren tenker i. Flokfil
Sentrale metoder i Flink-representanten void lagldi(int A, int C) int F = 1; < Øk IL_ledig", og sjekk at det er plass til en instr. til >; // Sett instruksjonen ned i lageret: func[il_ledig] = F; adr[il_ledig] = A; corr[il_ledig] = C; < Kall passelig metode i Listing-ansv. for I-testutskrift >; Osv. for alle de andre instruksjonene int nesteinstadr() leverer verdien av IL_ledig" int resvar(int ant, String navn) // Denne reserverer "ant" celler i heltallslageret (ved å // Øke HL_ledig". Sjekke at det er plass nok. // Leverer adr. til (første) cellen. // Parameteren "navn" er bare med for I-testutskriften // Skal gi I-testutskr. med: HL_ledig", "ant" og "navn" int reskonst(int verdi) // Denne reserverer en celle i heltallslageret, fyller den med // den angitte verdien, og lever adr. til cellen. // Skal sjekke at det er plass nok. // Skal gi I-testutskr. med: HL_ledig" og "verdi" void fyllgammeladr(int instnr, int nyadr) // Skal fylle instruksjon nr "instnr" med adressedel "nyadr" // Skal gi I-testutskr. med: "instnr" og "nyadr" Gjøres i en felles metode i Flink-repr.? Merk forskjellen i eventuell plassering Kan også godt lage egne hjelpe-metoder: Disse kan mest natulig være felles for alle nodene i treet Altså, de deklareres static i ytterste trenodeklasse Et eksempel kan være: static void lagaropinst(string arop, int adr, int corr) Dekl: Rep: Behandling av variabel-deklarasjoner navn: U Enkel/ array? fdekl navn: Q DS SS DeklSekv VarDekl Enkel/ array? VarDekl-klassen må utvides med variabel (for eksempel celleno ) Angir hvilken celle den har fått tildelt i heltalls-lageret (første tildelte celle, om det er array) Inne i VarDekl: Instr-lager void lagkode( ) <K-test-inn>; if (<det er array>) celleno = flinkrepr.resvar(<antall celler til arrayen>, navn); else celleno = flinkrepr.resvar(1, navn); <K-test-ut>; Forandringer i gamle deler av kompilatoren Forandringer i Hoved-ansvarlig: Ved innlesning av parameterne: Full parameter-sekvens til kompilatoren: <prog-fil> <flok-fil> <listing-fil> <hvilke testutskr.> <maxinst> <maxint> De to første parameterene må oppgis maxinst er lengden av inst-lageret og maxint er lengden av heltallslageret Om ikke oppgitt skal disse ha verdien 1000 Parametere man ikke vil oppgi angis ved - (eller blank, om de er på slutten) Ved oppsetting av modul-objektene: Også Kode-generator og Flink-representant må skapes Flink-representanten skal ved oppstart også få maxinst og maxint. Igangsetting: Også kodegenereringen må settes i gang: tregen.lesprogr(); // Var der i Del 1 kodegen.oversett(); // Ny i Del 2 Oversettelsen skal bare startes dersom Minila-program OK Dette går automatisk dersom man har vanlig struktur (og ikke bruker softerror ) Merk: Det kan også komme feilmeldinger fra Del 2 (f.eks. for liten plass ) Forandringer i gamle deler av kompilatoren (forts.) Ekstra variabel i deklarasjons-nodene: For dekl. av variable/arrayer/parametere: En variabel (f.eks. cellenr ) som inneholder adresse til reservert(e) celle(r) For proseyre-deklarasjoner: En variabel (f.eks. startadr ) som inneholder adresse til første instruksjon Utvide Listing-ansvarlig Med apparat for å ta seg av K- og I-testutskrift Ny metode i Tre-generatoren Som Kode-generatoren kan kalle for å få (peker til roten av) treet Utvide mengden av statiske felles-variable (og metoder?) for treet: Den eneste nye er antakeligvis peker til Flink-representanten Må også legges til i oppstart-metoden for treet (som setter disse variablene) Mange av de som er der fra Del 1 er også viktige i Del 2 Kanskje skal også xbet og xin være slike variable (se nederst side 106)
Oversettelse av uttrykk (mye på gruppene) SETI 7 0 ADDI x 0 MULI 5 0 7 + x * 5 - inint * z[5] / z[x] et 0 1 2 3 4 Res. for x Res. for z 5 + Y[3] * inint / X Til de tilsvarende deklarasjoner (Variabel). Se tabell 5.2 og 5.3 arop: null Konstant verdi: 5 arop: + Variabel navn: Y indeks: 3 arop: * Inint arop: / Variabel indeks: - CIC - - INI - - STI xin 0 CCI - - SUBI xin 0 SETC 5 0 MULI z 1 LDC x 0 DIVI z 1 5 maxint-1 I klassen: class Variabel extends Ledd void // NB: K-testutskrift ikke antydet her if (<det er enkel variabel>) if (arop == null ) FlinkRepr.lagLDI (deklarasjon.celleno, 0); else if ( arop.equals ( + ) ) lagaddi else if ( arop.equals ( / ) ) lagdivi else <det er noe inkonsistent i trestrukturen>; else < Behandling av indekserte variable >; Betingelser og while-setning lagkode i betingelse while a + 2 <= b / c do x:= a * b ; if x > 8 then x:= x + a; endif; endwhile; Betingelse Relop: <= U1 U2 nestesetn While-setning BET SS Setekv fs IfSetn Instruksjons-lager STI xbet SUBI xbet JLTI? JMP void lagkode() <K-testutskrift-inn>; <LAG kode for U1>; // Altså f.eks.: U1.lagKode() <LAG: (STI, xbet, 0) >; // Altså f.eks.: flinkrepr.lagsti(xbet, 0) <LAG kode for U2>; <LAG: (SUBI, xbet, 0) >; if (relop.equals( = )) flinkrepr.lagjnei( -1, 0 ); else if (relop.equals( =/= )) flinkrepr.lagjeqi( -1, 0 ); else if (relop.equals( <> ) ) flinkrepr.lagjeqi( -1, 0 ); else if (relop.equals( )) flinkrepr.lagj??i ( -1, 0 ); else if (relop.equals( >= )) flinkrepr.lagjgti( -1, 0 ); else <Intern-feil: noe feil med verdiene>; Se Tabell 5.7, side 44 Kunne eventuelt lage en hjelpe-metode av dette, men den ville bare bli kalt herfra. // Angående flinkrepr.lagjxxi ( -1, 0) : Foreløpig ukjent adresse-del, fylles inn siden. // Beskjed fra betingelse til kalleren: // - Hoppinstruksjonen uten adressedel er siste instruksjon jeg laget a + 2 b / c <K-testutskrift-ut>;
void lagkode() <K-testutskrift-inn>; int startadr = flinkrepr.nesteinstadr(); lagkode i while-setningen <LAG: kode for betingelsen BET>; int jmpsted = flinkrepr.nesteinstadr() - 1; // Instruksjonen som mangler adresse <LAG: kode for setningssekvensen SS>; <LAG: (JMP, startadr, 0)>; // Nå kjenner vi riktig adresse for uthoppet i betingelsen: flinkrepr.fyllgammeladr(jmpsted, flinkrepr.nesteinstadr() ); <K-testutskrift-ut>; DeklSekv fdekl VarDekl navn: navn: Y Prosedyredeklarasjon og call-setning navn: U proc P in x out y; var u; proc Q; endproc; begproc u:= x+1; call Q; endproc; call P with a+b into c; navn: P startadr: DS inpar outpar SS navn: Q ProcDekl P CallSetn with into a +b navn: Setekv fs c CallSetn Svært likt venstresiden i tilordning, bruk samme klasse. Instruksjons-lager STC P.retAdr STI X LDI Y LDC P.retAdr JMP 0 1 JRC STI c P.retAdr X Y U 14 void lagkode( ) lagkode i ProcDecl // Variabel som husker adresse til lokasjonen for returadressen (ret<p> i Tab. 5.10): int retlok = flinkrepr.resvar(1, <prosedyrens navn> ); // Reservering av slik lokasjon <Lag kode for deklsekvensen DS>; // NB: Behandler også eventuelle parametere (samt lager kode for indre prosedyrer). startadr = flinkrepr.nextinstadr(); // x<p>. NB: startadr er lokal i ProcDekl-klassen <LAG: (STC, retlok, 0)>; if (inpar!= null) <LAG: (STI, inpar.celleno, 0)>; <Lag kode for setningssekvensen SS>; if (outpar!= null) <LAG: (LDI, outpar.celleno, 0)>; <LAG: (LDC, retlok, 0)>; // Vil hente returadressen <LAG: (JMP, 0, 1)>; // Vil hoppe tilbake til returadressen 15 lagkode i CallSetn class CallSetn extends Setning with; Variabel into; // Klassen Variabel : Som for venstre-side i tilordning. void if (with!= null) with.; // Beregner uttrykket til I-reg. < LAG: (JRC, deklarasjon.startadr, 0) >; // Denne gjør selve kallet if (into!= null) into.; // For enkel variabel a, lag: (STI a 0) 16
Litt om uttesting av Del-2 Burde ikke være verre å teste ut enn Del 1, men litt annerledes Veldig indirekte, ved at det er den produserte koden som skal utføres riktig Dermed kan det være vanskelig å tenke fra utførelsesfeil i Flink tilbake til virkelig feil I-testutskrift er spesielt nyttig Ta gjerne også I-testutskrift av testprogrammet med den ferdige kompilatoren Slike kan generelt være fine å studere, til ettertanke angående alt som skal gjøres (Merk dog at i denne gjøres reservasjon av xbet og xin på et merkelig tidlig tidspunkt) Ta én og én setningstype, og få dem til å fungere riktig F.eks.: Først må de enkleste deklarasjoner bli behandlet riktig Deretter: ning med enkle uttrykk og variable Helt til slutt: Alt med prosedyrer og kall Om feil er vanskelig å finne, husk: Alt kan være galt (også test-utskriftene) Ta f.eks. ut P-testutskrift og sjekk at tidligere deler er OK Sammenlikn med I-testutskrift fra den ferdige kompilatoren Sjekk også at det som kommer inn i Flink-maskinen (xflink) er det fra I-testutskriften 17