Dagens tema: Syntaksanalyse Hva annet gjør en kompilator? Sjekking av navnebruk Testutskrifter Dag Langmyhr,Ifi,UiO: Forelesning 4. oktober 2005 Ark 1 av 20
Syntaksanalyse På skolen hadde vi grammatikkanalyse: Fanger krabber så lenge de orker Syntaksanalyse er på samme måte å finne hvilke språkelementer vi har og bygge syntakstreet. Heldigvis Analyse av programmeringsspråk er enklere enn naturlige språk: Programmeringsspråk har en klarere definisjon. Programmeringsspråk er laget for å kunne analyseres rimelig enkelt. Dag Langmyhr,Ifi,UiO: Forelesning 4. oktober 2005 Ark 2 av 20
Program DeclSeqv SentSeqv Decl Sent Sent Sent Sent Sent prog var n; begprog outtext "Skriv et tall: "; n := inint; outtext "Det dobbelte er "; outint(1) 2*n; outline; endprog VarDecl OutTextSent AssignSent Expression ExprPart InIntPart OutTextSent OutIntSent OutLineSent Expression ExprPart ExprPart ConstPart VarPart Dag Langmyhr,Ifi,UiO: Forelesning 4. oktober 2005 Ark 3 av 20
Språkdiagrammene Jernbanediagrammene er et ypperlig utgangspunkt for å analysere et program: Program prog ; Deklarasjon begprog ; Setning endprog Utifra dette vet vi: Først kommer symbolet prog. Hvis neste symbol ikke er begprog, kommer det en Deklarasjon etterfulgt av et semikolon. Før eller siden kommer symbolet begprog. Hvis neste symbol ikke er endprog, kommer en Setning etterfulgt av et semikolon. Før eller siden kommer symbolet endprog. Dag Langmyhr,Ifi,UiO: Forelesning 4. oktober 2005 Ark 4 av 20
Utifra dette kan vi lage en skisse for en metode som analyserer et Minila program: void analyserprogram () { Sjekk at vi har lest prog while ( neste symbol ikke er begprog ) Analysér Deklarasjon og ; Sjekk at vi har lest begprog while ( neste symbol ikke er endprog ) Analysér Setning og ; Sjekk at vi har lest endprog } Stort sett gjør vi to ting: Symboler (i rundinger) sjekkes. Meta symboler (i firkanter) overlates til sine egne metoder for analysering. Dag Langmyhr,Ifi,UiO: Forelesning 4. oktober 2005 Ark 5 av 20
Er det så enkelt? Mange programmeringsspråk er designet slik at denne teknikken kalt «recursive descent» alltid fungerer. Et analyseprogram er aldri i tvil om hvilken vei gjennom programmet som er den rette. Setning Tekst Variabel := Uttrykk intext Navn outchar Uttrykk outint ( Tall ) Uttrykk outline outtext Navn Tekst If-setning While-setning call Navn with Uttrykk into Variabel Dette omfatter Minila og Pascal men ikke Java, C og C++. I fagterminologien er de LL(1) språk. Dag Langmyhr,Ifi,UiO: Forelesning 4. oktober 2005 Ark 6 av 20
Plassering av metodene Husk at målet med analysen er tofoldig: Vi skal sjekke at programmet er riktig. Vi skal bygge opp syntakstreet. Da er det naturlig å koble analysemetoden til den klassen som skal inngå i syntakstreet. Hvert meta symbol i diagrammet implementeres av en Java klasse. Hver av disse klassene får en metode void analyze () {... } som kan analysere «seg selv». Dag Langmyhr,Ifi,UiO: Forelesning 4. oktober 2005 Ark 7 av 20
Samarbeid med SymbolGenerator Hvordan sikrer vi at symbolstrømmen fra SymbolGenerator er i fase med vår analyse? Det beste er å vedta noen regler som alle analyze metodene må følge: ❶ Når man kaller analyze, skal første symbol være lest inn! ❷ Når man returnerer fra en analyze, skal første symbol etter konstruksjonen være lest. Dag Langmyhr,Ifi,UiO: Forelesning 4. oktober 2005 Ark 8 av 20
Modifikasjoner av diagrammene Selv om diagrammene kan fungere bra som de er, kan de noen ganger forbedres: Noen ganger forekommer samme gruppe flere ganger, for eksempel ; Deklarasjon Da kan det være lurt å definere dette som et nytt meta symbol. Dag Langmyhr,Ifi,UiO: Forelesning 4. oktober 2005 Ark 9 av 20
Noen ganger trenger man å lagre data om konstruksjonen, for deklarasjoner av variable og prosedyrer: Deklarasjon var Navn [ Tall ], proc Navn in Navn [ ] out Navn Deklarasjon ; begproc ; Setning endproc Da bør man ha egne meta symboler (som blir egne objekter) for alternativene. Hvis meta symbolet er komplisert, kan det også være nyttig å innføre nye meta symboler (men dette gjelder ikke Minila). Dag Langmyhr,Ifi,UiO: Forelesning 4. oktober 2005 Ark 10 av 20
Feilsjekking Sjekken på syntaksfeil er svært enkel: Hvis neste symbol ikke gir noen lovlig vei i diagrammet, er det en feil. Utfordringen er å gi en feilmelding brukeren har nytte av: Linjenummeret er en selvfølge. Det er lurt å fortelle hva analyze forventet og hva som er neste symbol. Eksempel Jeg synes dette er en god melding: if (! symbgen.curis("then")) mainresp.error("forventet then etter betingelse men fant " +symbgen.cursymbol()); Dag Langmyhr,Ifi,UiO: Forelesning 4. oktober 2005 Ark 11 av 20
Et eksempel Her er en skisse av IfSent og dens analyze: class IfSent { Condition cond; SentSeqv ss1, ss2; void analyze () { if (! symbgen.curis("if")) gi feilmelding ; symbgen.readsymbol(); cond = new Condition(); cond.analyze(); if (! symbgen.curis("then")) gi feilmelding ; symbgen.readsymbol(); ss1 = new SentSeqv(); ss1.analyze(); } } if (symbgen.curis("else")) { symbgen.readsymbol(); ss2 = new SentSeqv(); ss2.analyze(); } else { ss2 = null; } if (! symbgen.curis("endif")) gi feilmelding ; symbgen.readsymbol(); Dag Langmyhr,Ifi,UiO: Forelesning 4. oktober 2005 Ark 12 av 20
Sjekking av navn En kompilator må også sjekke riktig navnebruk. Dette omfatter: Det må ikke forekomme dobbeltdeklarasjoner. Alle navn må være deklarert. Navnet må brukes riktig (enkel variabel kontra array kontra prosedyre). Dag Langmyhr,Ifi,UiO: Forelesning 4. oktober 2005 Ark 13 av 20
Lagring av navn Det enkleste er å lagre navnene i deklarasjonsobjektet: class DeclSeqv { private Decl firstdecl, lastdecl;. } class Decl { private Decl next; protected String name; }. class VarDecl extends Decl { private boolean isarray, isparam; private int arraylength;. } class ProcDecl extends Decl { private VarDecl inpar, outpar; private DeclSeqv ds; private SentSeqv ss;. } Dag Langmyhr,Ifi,UiO: Forelesning 4. oktober 2005 Ark 14 av 20
Hvordan finner man et navn? I Minila programmet kan vi ha følgende setning: x := a[4] + 1; Hvilken x er det snakk om, og hvilken a? 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) {. } Dag Langmyhr,Ifi,UiO: Forelesning 4. oktober 2005 Ark 15 av 20
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 man dem? Det enkleste er å la hvert DeclSeqv objekt ha en peker til sin nærmeste omliggende deklarasjonsliste. Dag Langmyhr,Ifi,UiO: Forelesning 4. oktober 2005 Ark 16 av 20
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. Er SymbolGenerator synkronisert? Til dette bruker man S utskriftene fra Del 0. A utskrifter Gjør man riktig valg i diagrammene. Det beste er å la hver analyze gi lyd fra seg. P utskrifter Ble analysetreet riktig? Det beste da er å skrive det ut etterpå. Dag Langmyhr,Ifi,UiO: Forelesning 4. oktober 2005 Ark 17 av 20
Testprogram Vi skal se på dette programmet: 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 Dag Langmyhr,Ifi,UiO: Forelesning 4. oktober 2005 Ark 18 av 20
A utskrift A utskriften begynner slik: 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; Dag Langmyhr,Ifi,UiO: Forelesning 4. oktober 2005 Ark 19 av 20
P utskrift Slik ser P utskriften ut: P testutskrift: Skriver innholdet av treet. 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 Dag Langmyhr,Ifi,UiO: Forelesning 4. oktober 2005 Ark 20 av 20