Dagens tema: INF 2100 8. september 2004 Mer om strukturen i treet og hvordan bygge det Testing av at navn er deklarert og brukt riktig Arbeid i gruppene neste uke: Oppgaver relevant for dette stadiet i Del-1 Forelesning neste uke: Del-1: Antakeligvis avslutning om Del-1 Kanskje noe om uttesting av programmer m.m. Eventuelle ekstrakrav til Del-1 legges ut senest fredag 10. sept. 1 Repetisjon: Hvordan bygge treet og analysere? Ha en klasse til hvert syntaksdiagram La hver klasse ha sin metode `analyse La den virke som en vanlig syntaksanalyse-metode class Setn SS; void analyse( ) < sjekk at while kommer >; B = new Betingelse( ); B.analyse ( ); < sjekk at do kommer >; SS = new ( ); SS.analyse( ); < sjekk at endwhile kommer >; De problematiske syntaks-diagrammene Typisk situasjon SETNSEKV: SETN: ; SETN TILORDNING. WHILESETN. class / / Logisk: Setn[ ] setninger = new Setn[??]; / / Praktisk: Vi lager en liste: Setn forstesetn; ning callsetn Ifsetn class Setn... bl.a. nestesetn... class ning extends Setn iabel V; Uttrykk U; class Setn extends Setn SS; fd Proc fs B SS abstract class Setn / / Skal ikke lage objekter av denne Setn nestesetn; abstract void analyse( ) ; / / Angir at denne vil være (konkret) definert i alle subklasser / / Kan like greit legges til en felles ytterste klasse: MinilaTreNode class Setn extends Setn SS; void analyse( ) som skissert tidligere / / Konkret utgave for Setn
Klassen Testutskrifter i Del-1: A- og P-testutskrift class Setn forstesetn; void analyse( ) Setn sistesetn, S; ning callsetn Ifsetn Dekl Prosedyre If while (< cursymb er et navn, while, if, call, outint eller outline > ) if ( curisnavn( ) ) S = new ning( ); else if ( curis( while ) ) S = new Setn( ); else if ( curis( if ) ) S = new IfSetn( ); else S.analyse( ); / / Riktig versjon blir valgt. / / Krever abstract -deklarasjonen i Setn (eller i MinilaTreNode) < Heng S inn bakerst i lista (bak sistesetn, eller først dersom tom) >; Bet A-testutskrift: Skriver ut en linje hver gang: Man starter en analyse-metode Man avslutter en analyse-metode Lages med passelige innrykk, for lett å kunne se kallstrukturen P-testutskrift: Etter at hele treet er generert, for å sjekke at treet er riktig: Skriver ut hele treet, som et Minila-program Gjerne i litt pent format, med innrykk etc. Startes ved å levere treet (ved roten) til Listing-ansvarlig, som selv gjør eventuell P-testutskrift ved hjelp av metoder i tre-nodene (tilsvarende analyse-metodene). Skisse til A-testutskrift Det store bildet: Modulene som skal bruke treet class Setn extends Setn Betingelse B SS; I Listing-ansvarlig, f.eks.: int innrykka; void analyse( ) < kall metode i Listing-ansv.: testain( while ) >; < sjekk at while kommer >; B:- new Betingelse( ); B.analyse ( ); < sjekk at do kommer >; SS:- new ( ): SS.analyse ( ); < sjekk at endwhile kommer >; < kall metode i Listing-ansv.: testaout( while ) >; void testain(string konstr) void testaout(string konstr) Hovedansv. Symbolgen. Listingansv. Dekl Kodegenerator var Prosedyre If Tregenerator Dødt tre?: Data som beskriver programmet, og kan leveres til interesserte Ikke helt dødt: Nodene har metoder til analyse og P-testutskrift (og kodegen) Disse kan sees som utplasserte fra hver sin modul. Greit fordi: De får grei tilgang til data i nodene, som de trenger Vi får automatisk riktig versjon av metodene, ut fra nodens type. Men ulempe: Metodene får ikke tilgang til dataene i moder-modulen Setn Dekl setn Bet Setn F.eks. pekere til andre moduler
Oppgradering av treet til en fullverdig modul med lokale variable, startopp-metode etc. abstract class MinilaTreNode / / Superklasse til alle tre-node-klassene static MainResponsible mainresp; static ListingResponsible listresp; static SymbolGenerator symbgen; Synlig fra alle noder i treet (siden de er objekter av subklasser av MinilaTreNode) iabel Uttrykk X := 5 + Y[3] * inint / X ning Uttrykk fledd static void startopp( mresp, lresp, sgen) mainresp = mresp;.. / / this.mainresp går ikke i statiske metoder / / Også en avslutnings-metode? op: null Konstant Verdi: 5 op: + iabel Navn: Y Indeks: 3 op: * Inint op: / iabel Navn: X Indeks: - abstract void analyse( ); abstract void testpout( ); < Senere også en til kodegenerering. >; Disse må få sin konkrete deklarasjon i alle subklasser av MinilaTreNode (som det skal lages objeketer av) / / Gjør at f.eks. følgende virker, og gir kall på analyse-metoden i IfSetn: / / MinilaTreNode N = new IfSetn(); N.analyse( ); Dette er helt spesielt for de svært enkle uttrykk i Minila. (Mer generelle uttrykk kan greiest sees som trær, men i Minila er de rene sekvenser av ledd) Vi kan lage listen etter samme mønster som f.eks. setnings-sekvens Hvert ledd inneholder operatoren foran seg (behagelig for kode-generering) Navn må bindes til tilsvarende deklarasjons-objekt (og bruken sjekkes) Uttrykks-klassene class Uttrykk // Skal også være subklasse av MinilaTreNode, direkte eller indirekte Ledd forsteledd; Et ferdig tre kan typisk se slik ut: void analyse( ) <konkret utgave, ikke ulik den for setning-sekvens> abstract class Ledd // Skal også være subklasse av MinilaTreNode, direkte eller indirekte Ledd nesteledd; String operator; // Kan passelig være null i første ledd? fd fs abstract void analyse( ); // Kan passelig flyttes ut til klassen MinilaTreNode Subklasser av Ledd, f.eks.: Konstant: Med plass til å holde selve verdien av konstanten DS Proc SS B SS. iabel: Med nok plass til å holde all informasjon om en enkel eller indeksert variabel. Og for hvert navn: Plass til peker til tilsvarende deklarasjon. Inint: Noe plass i det hele tatt? OG: Alle disse må ha egne konkrete utgaver av void analyse( ) (og av testpout, ikke markert over)
Deklarasjonene i treet For det første: var a, xx[5], z2; var u; Behandles som: var a; var xx[5]; var z2; var U; Men: Dette kompliserer analyse-metoden noe. Se kapittel 9.6 Representasjon etter samme prinsipp som for Uttrykk og : Dekl: navn: U navn: Q navn: P Dekl navn: Y ProcDekl navn: V Binding av navn i Minila Deklarasjons-forekomst og bruks-forekomst av navn: Typiske deklarasjons-forekomster var V; var A[20]; proc P in X out Y; Typiske bruks-forekomster: if V <= X + 1 then X:= V + 28 / Y; call P with A[B] + 2 into V; endif; Navnebindings-algoritmen for en bruks-forekomst av navn: Start der navnet er brukt Gå ett og ett hakk utover til omsluttende prosedyre/program Sjekk på hvert sted om navnet finnes i deklarasjonslisten der Stopp første gang navnet finnes deklarert: Da er dette den riktige betydningen (deklarasjonen) av navnet Om det aldri finnes deklarert på veien utover: Navnet er da udeklarert (gi feilmelding) Binding av navn i Minila prog var X, V[30]; proc P; var U, Y; proc Q; Holder på her var X, Z; begproc X := V[5] + 123 * Y; endproc; var V; Er ikke kommet i lista ennå begproc V := Y + 2; call Q; endproc; begprog X:= V[X]+1; call P; endprog Bruk av lokal-peker, m.m. navn: U navn: Y navn: V navn: Z null navn: Q navn: P IfSetn fsetn Setn void analyse( lokal) lokal : Angir -objektet til nærmeste prog/proc Brukes til å lete etter hvor et navn er deklarert Hvert -objekt må også ha en omsl, slik at vi eventuelt kan lete videre X Foreløpig ikke opprettet Foreløpig ikke opprettet V[5] fledd + 123 * Y
Behandling av parameteren lokal class X void analyse( lokal) // Hvilken parameter skal gies til nye kall på analyse( ) : y= new Y( ); y.analyse(??); class omsl; /* Peker til -objektet for omsluttende prosedyre/program. Er `null' i program-objektet sitt -objekt */ Dekl forstedekl; / / Første dekl-objekt i deklarasjons-lista Dekl finnlokaldekl(string navn) /* Hjelpe-metode som leter gjennom den lokale deklarasjons-lista (fra `forstedekl') etter en deklarasjon med dette navn. Returnerer peker til denne, eller `null' */ Det normale: Lever videre den du selv fikk som parameter! Spesielle tilfelle, som må tenkes over: I klassen X= eller ProcDecl, der man kaller analyse i Y= SetningsSekvens. I klassen X=DeklarasjonsSekvens, der man kaller analyse i en underliggende deklarasjon (spesielt viktig for Y=ProcDecl). 17 Dekl fin(string navn) /* Leter, med metoden `finnlokaldekl', først lokalt, så i `omsl', så i `omsl.omsl', osv. Stopper og leverer så fort den finnes, ellers levers `null' */ void analyse( lokal) / / Testutskrtift etc. omsl = lokal; < Osv., med vanlig analyse... >; d = new ProcDecl ( ); d.analyse(?? ); 18 Hva skal sjekkes i forbindelse med navn i Minila? Sjekk at det ikke i noen deklarasjons-liste er to deklarasjoner med samme navn I denne forbindelse regnes in/out-parametere med til prosedyrens deklarasjoner (Dette blir lett å gjøre med noen hjelpe-metoder i -klassen) Sjekk at alle bruksforekomster av navn faktisk er deklarert Og at de i så fall er brukt riktig (dette blir mye mer omfattende i reelle språk): Navn brukt som enkel variabel er deklarert som enkel variabel Navn brukt som array er deklarert som array Navn brukt etter call er deklarert som prosedyre I kall: At bruk av with og into stemmer med in og out i proc-deklarasjonen At en prosedyre ikke blir kalt rekursivt (bare ett kall i gang av gangen) Sjekk at man ikke er inni den prosedyren som kalles (i ett eller flere lag) Alternativt: Ikke sett prosedyrer inn i sin dekl.-liste før ved endproc (Dette ser vi på i en oppgave neste uke) 19