Dagens tema: 12 gode råd for en kompilatorskriver Hvordan sjekke navn? Testutskrifter 12 gode råd
Hva skal gjøres med navn? Sjekking av navn En kompilator må også sjekke riktig navnebruk: Det må ikke forekomme dobbeltdeklarasjoner. Alle navn må være deklarert. Navnet må brukes riktig (enkel variabel kontra array kontra prosedyre).
Lagring av navn Lagring av navn Det enkleste er å lagre navnene i deklarasjonsobjektet: class DeclSeqv { private Decl firstdecl, lastdecl;. } class VarDecl extends Decl { private boolean isarray, isparam; private int arraylength;. } class Decl { private Decl next; protected String name;. } class ProcDecl extends Decl { private VarDecl inpar, outpar; private DeclSeqv ds; private SentSeqv ss;. }
Hvordan finne navn? Hvordan finne et navn? I Minila programmet kan vi ha følgende setning: x := a[4] + 1; Hvilken x er det snakk om, og hvilken a?
Hvordan finne navn? Lokale variable Det enkleste er å sjekke om variabelen er en lokal variabel proc p in a[]; var x; begproc. x := a[4] + 1;. endproc; La analyze få med en parameter som peker til den lokale deklarasjonslisten: void analyze (DeclSeqv localdeclseqv) {. }
Hvordan finne navn? Global navn Navn kan imidlertid være deklarert «lenger ute»: prog var a; proc p1; var b; proc p2; var c; begproc... a... b... c... endproc; : Hvordan finner globale navn? Det enkleste er å la hvert DeclSeqv objekt ha en peker til sin nærmeste omliggende deklarasjonsliste.
Hvordan finne navn? Skjuling av navn Som i de fleste språk vil en indre deklarasjon skjule en ytre. prog var a; proc p1; var a; begproc... a... endproc :
Hvordan finne navn? Deklarasjonsrekkefølgen Husk at navn i Minila først er kjent etter at de er deklarert. prog var a; proc p1; proc p2; begproc... a... endproc; var a; proc p3; begproc... a... endproc :
Oversikt Testutskrifter Det er lett å gjøre feil når man programmerer noe såpass komplisert som en kompilator. Det lureste er å godta dette og heller finne teknikker for å oppdage feilen. S utskriftene fra del 0 forteller om analysen er synkronisert med SymbolGenerator, A utskrifter avslører om man gjør riktige valg i jernbanediagrammene. Det beste er å la hver analyze gi lyd fra seg. P utskrifter sjekker om analysetreet ble riktig ved å skrive det ut etterpå.
A utskrifter Et veldig enkelt Minila program. prog var x, z; proc read out a; begproc a := inint; endproc; proc write in a; begproc outint(4) a; outline; endproc; begprog call read into x; z := x; call write with z; endprog
A utskrifter 1: Et veldig enkelt Minila program. 2: 3: prog A: INN Program 4: var x, z; A: INN DeclSeqv A: INN VarDecl A: UT VarDecl A: INN VarDecl 5: A: UT VarDecl 6: proc read out a; A: INN ProcDecl A: INN VarDecl A: UT VarDecl 7: begproc A: INN DeclSeqv A: UT DeclSeqv 8: a := inint; A: INN SentSeqv A: INN AssignSent A: INN AssignVar A: UT AssignVar A: INN Expression A: INN InIntPart A: UT InIntPart A: UT Expression A: UT AssignSent 9: endproc; A: UT SentSeqv 10: A: UT ProcDecl 11: proc write in a; A: INN ProcDecl A: INN VarDecl A: UT VarDecl 12: begproc 13: outint(4) a; outline; A: INN DeclSeqv A: UT DeclSeqv A: INN SentSeqv A: INN OutIntSent A: INN Expression A: INN VarPart A: UT VarPart A: UT Expression A: UT OutIntSent A: INN OutLineSent A: UT OutLineSent 14: endproc; A: UT SentSeqv 15: begprog A: UT ProcDecl A: UT DeclSeqv 16: call read into x; A: INN SentSeqv A: INN CallSent A: INN AssignVar A: UT AssignVar A: UT CallSent 17: z := x; A: INN AssignSent A: INN AssignVar A: UT AssignVar
P utskrifter prog var x ; var z ; proc read out a ; begproc a := inint ; endproc ; proc write in a ; begproc outint( 4 ) a ; outline ; endproc ; begprog call read into x ; z := x ; call write with z ; endprog
Start nå! Råd nr 1: Start nå! Det tar typisk 10 50 timer å programmere Del 1 om man ikke har gjort slikt før. Påtrengende spørsmål Det er 21 dager til 7. november. Hvor mange timer per dag blir det?
Forstå hva du skal gjøre! Råd nr 2: Forstå problemet! Forstå hva du skal gjøre før du begynner å programmere. NB! Skriv noen korte kodesnutter i Minila. Tegn syntakstrærne deres. Studér eksemplet med kalkulatoren i øvelsesoppgavene. På dette stadium kan man samarbeide så mye man ønsker!
Forstå hva du skal gjøre! Program DeclSeqv SentSeqv prog var n; begprog outtext "Skriv et tall: "; n := inint; outtext "Det dobbelte er "; outint(1) 2*n; outline; endprog Decl VarDecl Sent OutTextSent Sent AssignSent Expression ExprPart InIntPart Sent Sent Sent OutTextSent OutIntSent OutLineSent Expression ExprPart ExprPart ConstPart VarPart
Start enkelt! Råd nr 3: Start med noe enkelt! Ingen bør forvente at de kan skrive all koden og så bare virker den. Start med et enkelt programmeringsspråk Program : prog begprog endprog og få det til å virke først. Utvid etter hvert. Sjekk hver utvidelse før du går videre.
Start enkelt! class Program { public void analyze (DeclSeqv localdeclseqv) { listresp.testaout("inn", "Program"); if(! symbgen.curis("prog")) mainresp.error("programmet startet ikke med prog"); symbgen.readsymbol(); if(! symbgen.curis("begprog")) mainresp.error("forventet begprog"); symbgen.readsymbol(); if(! symbgen.curis("endprog")) mainresp.error("forventet endprog"); symbgen.readsymbol(); } } listresp.testaout("ut","program");
Bruk aktiv feilsøking! Råd nr 4: Ikke sitt og stirr på koden! Når programmet ikke virker: 1. Se på siste versjon av programkoden. 2. Siden du arbeider i små steg er feilen sannsynligvis i de siste linjene du endret. 3. Hvis du ikke har funnet feilen i løpet av fem minutter, gå over til aktiv feilsøking.
Husk testutskriftene! Råd nr 5: Les testutskriftene! A utskriftene forteller hvilke analyze metoder som kalles. Anta at vi har programmet prog var i; begprog i := 3; endprog Programmet gir en feilmelding i linje 2: ***Feil: Forventet begprog Hva er galt?
Husk testutskriftene! Svaret kan vi finne i A utskriften: 1: prog 2: var i; A: INN Program A: INN SentSeqv ***Feil: Forventet begprog Utskriften skulle ha startet 1: prog 2: var i; A: INN Program A: INN DeclSeqv A: INN VarDecl 3: begprog A: UT VarDecl 4: i := 3; A: UT DeclSeqv A: INN SentSeqv A: INN AssignSent A: INN AssignVar
Husk testutskriftene! P utskriften viser en utskrift av det genererte treet. Anta at vi har det samme testprogrammet prog var i; begprog i := 3; endprog Hvis P utskriften er prog var i ; begprog endprog så vet vi at setninglisten ikke settes opp riktig (eller at det er feil i P utskriften).
Lag egne testutskrifter Råd nr 6: Lag egne testutskrifter Her er litt (muligens feilaktig) kode fra SentSeqv.analyze: public void analyze (DeclSeqv localdeclseqv) { listresp.testaout("inn", "SentSeqv"); Sent newsent = null; while (moresentences()) { if (symbgen.curisname()) newsent = new AssignSent(); else if (symbgen.curis("call")) newsent = new CallSent(); else if (symbgen.curis("if")) newsent = new IfSent(); else if (symbgen.curis("intext")) newsent = new InTextSent(); else if (symbgen.curis("outchar")) newsent = new OutCharSent(); else if (symbgen.curis("outint")) newsent = new OutIntSent(); else if (symbgen.curis("outline")) newsent = new OutLineSent(); else if (symbgen.curis("outtext")) newsent = new OutTextSent(); else if (symbgen.curis("while")) newsent = new WhileSent(); newsent.analyze(localdeclseqv); addsent(newsent); } if (! symbgen.curis(";")) mainresp.error("forventet ; etter setning"); symbgen.readsymbol(); } listresp.testaout("ut", "SentSeqv");
Lag egne testutskrifter Anta at vi får melding om null peker i linjen med newsent.analyze. Slikt skal ikke skje. Mitt råd er å legge inn noe à la while (moresentences()) { System.out.println("SentSeqv.analyze: " + "symbgen.curis er " + symbgen.curis());
Behold testutskriftene! Råd nr 7: Behold testutskriftene! Når feilen er funnet, bør man la testutskriften forbli i koden. Man kan få bruk for den igjen. Derimot bør man kunne slå den av eller på: Det mest avanserte er å bruke opsjoner på kommandolinjen: java MinMinila debugss.a testprog.min
Behold testutskriftene! Det fungerer også godt å benytte statusvariable: static boolean debugss_a = true;. if (debugss_a) { System.out.println("SentSeqv.analyze: " + "symbgen.curis er " + symbgen.curis()); }
Stol ikke på det du har skrevet! Råd nr 8: Mistro din egen kode! Det er altfor lett å stole på at ens egen kode andre steder er korrekt. Løsningen er å legge inn assertions som bare sjekker at alt er som det skal være (som vist her i IfSent.analyze): public void analyze (DeclSeqv localdeclseqv) { listresp.testaout("inn", "IfSent"); assert symbgen.curis("if"): "If setning starter ikke med if."; }.
Stol ikke på det du har skrevet! NB! Husk å kjøre med java ea Minila for å slå på mekanismen.
Synkronisér med symbolgeneratoren! Råd nr 9: Sjekk spesielt på readsymbol! Det er lett å kallereadsymbol for ofte eller for sjelden. Her er et forsøk på å skrive IfSent.analyze: public void analyze (DeclSeqv localdeclseqv) { listresp.testaout("inn", "IfSent"); } cond = new Condition(); cond.analyze(localdeclseqv); if (! symbgen.curis("then")) mainresp.error("forventet then etter betingelse"); SS = new SentSeqv(); SS.analyze(localDeclSeqv); if (symbgen.curis("else")) { elsess = new SentSeqv(); elsess.analyze(localdeclseqv); } if (! symbgen.curis("endif")) mainresp.error("forventet endif til slutt i If setn"); listresp.testaout("ut", "IfSent"); Hvor skal det kall på readsymbol?
Synkronisér med symbolgeneratoren! Husk kontrakten med SymbolGenerator Her er reglene som analyze metodene må følge: 1. Når man kaller analyze, skal første symbol være lest inn. 2. Når man returnerer fra en analyze, skal første symbol etter konstruksjonen være lest. Vær spesielt oppmerksom på if tester og løkker.
Synkronisér med symbolgeneratoren! public void analyze (DeclSeqv localdeclseqv) { listresp.testaout("inn", "IfSent"); symbgen.readsymbol(); cond = new Condition(); cond.analyze(localdeclseqv); if (! symbgen.curis("then")) mainresp.error("forventet then etter betingelse"); symbgen.readsymbol(); SS = new SentSeqv(); SS.analyze(localDeclSeqv); if (symbgen.curis("else")) { symbgen.readsymbol(); elsess = new SentSeqv(); elsess.analyze(localdeclseqv); } if (! symbgen.curis("endif")) mainresp.error("forventet endif til slutt i If setn"); } symbgen.readsymbol(); listresp.testaout("ut", "IfSent");
Ta sikkerhetskopier! Råd nr 10: Ta kopier daglig eller oftere! Programmering er mye prøving og feiling. Noen ganger må man bare glemme alt man gjorde den siste timen. Det finnes systemer for versjonskontroll som man bør lære seg før eller siden. I mellomtiden kan man ha nytte av 1. Ta en kopi av Java filen hver gang du starter med å legge inn ny kode. 2. Ta uansett en kopi hver dag (om noe som helst er endret).
Hele folket i arbeid! Råd nr 11: Fordel arbeidet! Dere er to om jobben. Selv om begge må kjenne til hovedstrukturen, kan man fordele programmeringen. Forslag 1. Én tar det som har med deklarasjoner. 2. Én tar det som har med setninger. Men... Snakk ofte sammen. Planlegg hvordan dere bruker filene så ikke den ene ødelegger det den andre har gjort.
Søk profesjonell hjelp! Råd nr 12: Bruk hjelpemidlene Spør gruppelærerne! De er tilgjengelige under gruppetimene og svarer på e post til andre tider. Orakel Siste uken før oblig fristene vil de sitte på terminalstuen i Abel for å svare på spørsmål. Les kompendiet Stoffet er forklart med flere detaljer enn det er mulig på forelesningene.
Hva har vi vært innom? Vi har snakket om Navn lagres i deklarasjonsobjektet. analyze får med peker til lokale deklarasjonsliste. Hver deklarasjonsliste peker på listen utenfor. Testutskriftene er svært nyttige. 12 gode råd.