Københavns Universitet Naturvidenskabelig Embedseksamen Oversættere Skriftlig eksamen onsdag d. 19. april 2006 Eksamenstiden er to timer. Opgavernes vægt i procent er angivet ved hver opgave. Den skriftlige eksamen i Oversættere er bestået, hvis minimum 50% af opgaven er besvaret tilfredsstillende, eller en proportionalt større del er løst delvist tilfredsstillende. Hver opgaves vægt i procent er angivet ved opgavens start. Ligeledes er de enkelte spørgsmåls andel i denne vægt angivet. Alle de sædvanlige hjælpemidler må benyttes, herunder også lydløse elektroniske lommeregnere og PDA ere (f.eks. Palm Pilot), dog ikke hvis disse har trådløs netadgang eller telefoni. En almindelig bærbar PC vil ikke være tilstrækkelig lydløs p.g.a. blæser, harddisk og støjende tastatur. I tvivlstilfælde gælder eksamensvagtens afgørelse. Det er tilladt at bruge blyant til besvarelsen, såfremt denne er tydeligt læselig.
Skriftlig eksamen onsdag d. 19. april 2006 i Oversættere side 1 af 4 Opgave 1: Grammatikker (15%) Betragt følgende kontekstfri grammatik: Spørgsmål 1.1 (6%) A aaa A aa Vis at grammatikken er tvetydig ved at vise to forskellige syntakstræer for samme tegnfølge. Spørgsmål 1.2 (9%) Lav en entydig grammatik for det samme sprog som ovenstående grammatik. Vink: Argumenter for, at produktionen A aaa kan erstattes med A AaA, og eliminer derefter tvetydighed som for regneudtryk. Opgave 2: Automater og regulære udtryk (20%) Betragt følgende sprog: Følger af cifrene 0 og 1, hvor det sidste ciffer forekommer mindst en gang tidligere i følgen, som f.eks. 010, 1101 og 1010 (men ikke f.eks. 1 eller 1110). Spørgsmål 2.1 (6%) Lav et regulært udtryk for sproget. Spørgsmål 2.2 (14%) Lav et DFA for sproget. Hvis DFA en laves direkte (uden at konvertere det regulære udtryk), så forklar kort logikken i konstruktionen. Vink: Tænk over den information, hver tilstand skal holde styr på.
Skriftlig eksamen onsdag d. 19. april 2006 i Oversættere side 2 af 4 Opgave 3: Syntaksanalyse (17%) Funktionerne Nullable og FIRST beskriver hhv. hvorvidt en følge af grammatiske symboler kan afledede den tomme tegnfølge og hvilke tegn eventuelle afledte tegnfølger kan starte med. Vi kan på lignende måde definere to nye funktioner Oneable og SECOND, hvor Oneable(α) er sand hvis og kun hvis α kan aflede en tegnfølge af længde 1, og SECOND(α) er mængden af tegn, der kan forekomme som nummer to tegn i tegnfølger, som α kan aflede. Spørgsmål 3.1 (7%) Lav ligninger for Oneable på samme måde som ligningerne for Nullable i algoritme 3.4 i Basics of Compiler Design. Du kan bruge Nullable i din definition. Spørgsmål 3.2 (10%) Lav ligninger for SECOND på samme måde som ligningerne for FIRST i algoritme 3.5 i Basics of Compiler Design. Du kan bruge Nullable, Oneable og FIRST i din definition. Opgave 4: Kodegenerering (16%) Kapitel 6 i Basics of Compiler Design bruger en mellemkode, hvor alle operationer sker på navngivne mellemkodevariabler. Et ofte brugt alternativ er stakbaseret mellemkode, hvor operationer sker på de øverste elementer af en stak. En sådan mellemkode kan have (bl.a.) følgende instruktioner: Instruction Const num Instruction Push id Instruction unop Instruction binop Instruction Call functionid Betydningen af instruktionerne er som følger:
Skriftlig eksamen onsdag d. 19. april 2006 i Oversættere side 3 af 4 Const n Push x unop binop Læg værdien n ovenpå stakken. Læg indholdet af variablen x ovenpå stakken. Erstat staktoppen med resultatet af unop anvendt på staktoppen. Fjern de to øverste elementer fra stakken, anvend binop på dem (med øverste element som andet argument) og læg resultatet tilbage på stakken. Call f Kald funktionen f. f tager sine argumenter fra de øverste elementer af stakken (sidste argument øverst) og lægger sit resultat i stedet. Bemærk, at en instruktion fjerner alle sine argumenter fra stakken og lægger sit resultat oven på den reducerede stak. Et kald til en funktion med tre argumenter vil f.eks. fjerne de tre øverste elementer fra stakken og vil ved retur lægge sit resultat oven på denne mindre stak. Vi vil bruge denne stakbaserede mellemkode i denne og de to følgende opgaver. Spørgsmål 4.1 (16%) Vis oversættelsesskemaer i stil med figur 6.3 i Basics of Compiler Design for udtrykssproget fra figur 6.2 i samme. Nettoeffekten af beregningen af et udtryk skal være at lægge dets resultat på toppen af stakken. Vink: Du har ikke brug for place atttributten, men ftable og vtable skal bevares. Opgave 5: Registerallokering (19%) Når man skal generere maskinkode fra den stakbaserede mellemkode fra opgave 4, skal man gemme stakelementerne i registre. Spørgsmål 5.1 (9%) Skitser, hvordan stakelementer tildeles registre, og hvordan en stakinstruktion oversættes til en maskinkodeinstruktion, der bruger registre. Du skal ikke beskrive oversættelsen af hver enkelt instruktion, men blot forholde dig til invarianten om, at en instruktion tager sine argumenter fra de n øverste stakelementer og bagefter lægger sit resultat ovenpå den reducerede stak. Du kan antage, at stakken er tom ved starten af udtrykket, at der er registre nok, samt at koden er ren udtryksberegning uden hop eller funktionskald. Du kan
Skriftlig eksamen onsdag d. 19. april 2006 i Oversættere side 4 af 4 bruge registre fra nummer 0 og op uden øvre grænse (og register 0 er ikke konstant lig 0). Spørgsmål 5.2 (10%) Hvis der ikke er registre nok til alle stakelementer, skal man spill e nogle af stakelementerne. Skitser, hvordan dette kan gøres. Opgave 6: Funktionskald (13%) Vi tilføjer til stakmaskinen fra opgave 4 instruktionen Pop x, som fjerner staktoppen og lægger værdien i variablen x. Når der er funktionskald, vil stakken indeholde både funktionens parametre og (under disse) evt. også mellemresultater fra det udtryk, hvori funktionskaldet indgår. Funktionens krop antager, at argumenterne ligger i navngivne variabler (som hentes med Push instruktioner), så argumenterne flyttes først fra stakken til variablerne med hjælp af Pop instruktioner. Derefter beregnes kroppen af funktionen, så dennes resultat lægges på stakken (som generelt ved beregning af udtryk). Dermed overholdes invarianten om, at nettoeffekten af et funktionskald er at fjerne argumenterne fra stakken og lægge resultatet på den reducerede stak. Men det giver et problem for registerallokeringen fra spørgsmål 6.2: Antagelsen om, at evaluering af udtryk starter fra en tom stak gælder ikke. Desuden kan en funktion ikke vide i hvilke registre, dens parametre ligger, da det afhænger af hvor mange elementer, der ligger på stakken under parametrene. Spørgsmål 6.1 (13%) Skitser, hvordan man kan lave en kaldsekvens/prolog/epilog, der sørger for, at hver funktion kan registerallokere sine parametre og sin stak startende fra register 0. Du behøver ikke tage højde for returadressen eller allokering af de navngivne variabler, kun beregningsstakken og parametrene. Vink: Det er nemmest med en ren caller-saves strategi.