complete workshopoverzicht januari - juni 2015

Examenvragen CC 2014-2015
Misschien krijg je van sommige vragen slechts een deel op het examen, of een combinatie van
stukken uit verschillende vragen.
Lexical analysis
De eerste fase van de compiler is de lexicale analyse. Hier zet de compiler de invoerstroom
van karakters om naar een outputstroom van tokens m.b.v. eindige automaten. Hoe kan men
dit implementeren? Wanneer noem je iets een token in deze context?
Longest match en rule priority lossen ambigu¨ıteit in deze fase op. Leg beide concepten uit en
geef telkens een voorbeeld.
Hoe gaat men om met lexicale fouten?
Hoe werken lexicale analysegeneratoren?
Hoe communiceert de lexicale analyse met de syntactische analyse?
Parsing
Leg predictive (of recursive-descent) parsing uit. Waarom hebben we FIRST, FOLLOW en
NULLABLE nodig en hoe worden ze gebruikt bij het opstellen van de predictive parsing
table? Hoe worden die verzamelingen berekend? Hoe gebruik je de parsing table? Hoe komt
het tot uiting dat je een programma in een taal met een zekere grammatica niet kan parsen?
Ligt dit aan de grammatica of de taal en in welke gevallen kan je er iets aan doen? Leg uit.
(LR-parsing) Wat is LR-parsing, hoe stel je een parse table op voor een LR(1) grammatica,
hoe gebruik je die?
Leg verschillende manieren uit om om te gaan met ambigu¨ıteiten in de grammatica, op het
niveau van de grammatica, het gebruik van parse-tables, en een parsergenerator.
Error recovery: In het boek staan 2 mechanismen:
• Local error repair: Error symbol
• Global error repair: Burke-Fisher methode
Omschrijf en vergelijk beide mechanismen:
• Wat is het?
• Hoe werkt het?
• Voor- en nadelen?
• Kan je ze beide gebruiken voor LL en LR parsing?
1
Abstract Syntax - Semantic Analysis
1. Welke voordelen zijn er aan het omzetting van de parse tree naar een abstract syntax
tree in deze fase?
2. Wat zijn symbooltabellen, hoe werken ze en waarom zijn ze nodig? Waarom zou je
symbolen gebruiken en leg uit hoe deze kunnen worden ge¨ımplementeerd. Leg het
gebruik van de symbooltabel uit voor type-checking van (algemeen) recursieve functies.
3. Bij het type checken worden de types van de variabelen vastgelegd. Waarvoor en in welke
fase(s) wordt deze type-informatie nog gebruikt? In hoeverre iss Semantic Analysis nog
machine-onafhankelijk?
4. Bij weak typing gebeuren er impliciete conversies tussen types. Wat/waar moet er
aangepast worden aan een compiler om weak typing te implementeren?
5. Typchecking is in het boek behandeld onder het hoofdstuk Semantische Analyse. Andere semantische acties (vb liveness analyse) gebeuren echter tijdens een andere fase.
Beargumenteer waarom dit zo gebeurt.
Activation Records, Intermediate Code
1. Beschrijf de stack frame layout en welke informatie daarover nodig is tijdens de IRtranslatiefase, op een manier die zo machineonafhankelijk mogelijk is.
2. Toegang tot variabelen moet op verschillende manieren mogelijk gemaakt worden: bespreek toegang tot globale variabelen, lokale variabelen, variabelen in een lexicaal omsluitende procedure, een dynamisch omsluitende procedure, een parameter, een returnwaarde.
3. Kan het FP register niet eenvoudig vervangen worden door en/of gebaseerd worden op
het SP register? Bespreek aan de hand van het principe van activatierecords en een
stack.
4. Bespreek caller-save en callee-save registers. Op welke fase(s) van de compiler heeft het
onderscheid tussen die twee effect? Welk?
5. Leg uit hoe Intermediaire Code wordt opgebouwd en waarom. In hoeverre is IC machineonafhankelijk?
2
Basic Blocks, Traces, Instruction Selection
1. Bespreek de algoritmes Maximal Munch en Dynamic Programming in de context van
instructieselectie. Vermeld daarbij zeker de begrippen “optimum tiling” en “optimal
tiling”. Resulteert een optimum tiling sowieso in de meest efficinte opeenvolgende instructies? Waarom wel/niet? Het effect van RISC/CISC is hierbij wellicht belangrijk.
2. Wat is het grote voordeel van canonical trees t.o.v. trees gegenereerd door de semantische analyse? Leg ook uit hoe men deze transformatie realiseert. Leg het nut uit van
basic blocks en traces! Waarom gebruiken we basic blocks om traces te genereren?
3. Wat zijn basic blocks? Waaruit bestaan ze? Hoe maak je ze en waarom zijn ze nuttig?
Zijn basic blocks optimaal?
4. In het boek staat een tile voor ´e´en machine-instructie. Bespreek mogelijk nuttige varianten daarvan.
Liveness Analysis
1. Wat is liveness analyse, wanneer wordt het uitgevoerd in de compiler en waarvoor dient
het? Hoe wordt liveness berekend door een compiler, in het bijzonder wat zijn de in- en
outsets? Welke optimalisaties voor het berekenen van liveness zijn er en leg uit.
2. Wat wordt bedoeld met een conservative approximation in de liveness analyse en leg uit
a.d.h.v statische en dynamische liveness. Op welke plaatsen in de compiler wordt verder
nog conservative benaderingen gemaakt en van welke eigenschappen of constructies?
3. Toon het verband en de verschillen aan tussen control flow analysis en data flow analysis.
Register Allocation
1. Leg het basis algoritme voor register allocatie uit. Vermeld zeker:
(a) wat de overeenkomst is met het kleuren van graaf;
(b) waarom een standaard algoritme voor een K-kleuring van een graaf te vinden toch
niet gebruikt kan worden;
(c) de vijf stappen van het algoritme en hoe deze samenwerken
2. Waarom willen we knopen samennemen en welke impact heeft dit op het kleuren door
vereenvoudiging? Leg ook uit waarom.
3. Bij het kleuren door vereenvoudiging gaan we ´e´en voor ´e´en de knopen terug van de
stack halen en kleuren. Maakt het uit welke kleur gekozen wordt voor:
(a) de correctheid van het algoritme?
(b) een optimale uitkomst?
Motiveer de keuze.
3
4. Bij het samennemen van knopen zijn er 2 veilige strategien: Briggs en George.
(a) Geven deze beide strategi¨en altijd dezelfde oplossing?
(b) Mag je beide strategi¨en naast elkaar gebruiken?
Motiveer de keuze, dit mag uiteraard ook met een voorbeeld.
5. Soms moeten sommige tijdelijke variabelen op een bepaald moment in een gegeven
machineregister zitten.
(a) Hoe gaat de registerallocator daar mee om?
(b) Waarop moet de compiler letten om geen performantieproblemen te krijgen?
6. Leg het Sethi-Ullman labeling algoritme uit, eerst zonder spilling, dan met spilling. Hoe
pas je het in in de algemene register allocatie?
Garbage Collection
1. Welke fases van de compiler cycle moeten aangepast worden om een GC algoritme te
ondersteunen? Maak het nodige onderscheid tussen mark-and-sweep/copy/reference
counting/generational/incremental ...
2. Welke eigenschap(pen) heeft een functionele taal (e.g. Haskell/Scheme) die GC kan
uitbuiten?
3. Leg het basic tri-color algoritme uit. Geef de 2 invarianten van dit algoritme. Hoe
kunnen deze invarianten bewaard worden?
4. Om de root-set at runtime te berekenen worden pointer maps gebruikt. Schets kort
hoe pointer maps worden opgesteld en hoe ze gebruikt worden. In welke fase van het
compilatieproces kunnen ze (reeds) opgesteld worden? Zijn die pointer maps getypeerd?
5. Leg uit: mark-and-sweep, copy collection, reference counting, Baker’s algoritme. Geef
karakteristieken (tijd/ruimte gebruik) en voor- of nadelen t.o.v. elkaar.
JITcompilatie
1. Leg uit wat JITcompilatie is, wanneer het gebruikt kan worden, wanneer het absoluut
nodig is, wat de voordelen en nadelen zijn.
2. Leg het linear scan register allocatie algoritme uit. Vergeet daarbij niet uit te leggen
hoe liveness bepaald wordt (niet enkel de definitie!). Bespreek ook enkele verbeteringen
aan het basis algoritme. Waarom voldoet het Chaitin-Briggs algoritme niet?
3. Welke andere fasen van een klassieke compiler moeten ook een JITversie hebben om aan
JITcompilatie te kunnen doen? Op welk ogenblik wordt daarvoor informatie verzameld,
bijvoorbeeld in de context van Java?
4
Functionele talen
1. Leg de basisprincipes van de implementatie van luie uitvoering uit. Je moet daarbij
o.a. spreken over closures. Bespreek mogelijke nadelen en hoe die door bepaalde optimalisaties kunnen verholpen worden - denk daarbij zowel aan tijd als ruimte. Wat
is het verschil met een thunk die gebruikt wordt om call-by-name of call-by-need te
implementeren?
2. Implementaties van functionele talen moeten staartrecursie (of meer algemeen de laatste
call in een body) optimiseren. Waarom? Hoe kan dat gebeuren? Kan je die principes
ook gebruiken in niet-functionele talen?
3. Indien je bv. Haskell naar C zou vertalen, dan moet je oplossingen vinden voor staartrecursie, voor closures, voor functies als first-class objects (die gedeeltelijk at runtime
kunnen gemaakt worden) en voor garbage collection. Beschrijf hoe je elk ervan zou
aanpakken of wat de mogelijkheden zijn. Zijn die problemen verschillend als je Haskell
vertaalt naar een machinearchitectuur en waar in een klassiek compilatieschema zou je
elke ervan aanpakken?
5