Du befindest dich hier: FSI Informatik » Prüfungsfragen und Altklausuren » Hauptstudiumsprüfungen » Lehrstuhl 2 » Allgemeines, Stimmung   (Übersicht)

Inhaltsverzeichnis

Allgemeines, Stimmung

Pruefer: Phillipsen
Beisitzer: Kamp
Zeit: 30 Minuten (voll ausgenutzt)

Atmosphaere sehr freundlich und entspannt, obwohl ich „leicht“ nervoes war. Der Beisitzer stellt fragen. Phillipsen fragt mitten rein mit teilweise detail/leicht fiesen Fragen.

Code

Ungefaehr so:

public class A extends B {

    class FunctionInt extends Function<Integer>{
        
            public Integer apply(Integer p){
                return zeugs...;
            }
    } 

   public boolean foo(int a){
       return zeugs...;
   }

   public int bar(){
        FunctionInt f = new FunctionInt(); [2]
        f.apply(2);
        
        ...
        
        boolean f = foo(2); [1]
        
        ...
        
        return check(f); [3]
    }

}

Fragen

B: Beisitzer P: Pruefer S: Ich

B: Wir haben hier Code. Was passiert da?

S: Also wir haben hier eine generische Klasse, da macht der Compiler…

B: Nein, ganz von vorne, oben bei class.

S: Achso, Lexer erklärt, dass er einzelne Zeichen einliest und in bedeutungstragende Elemente aufspaltet. Gut automatisch generierbar, als DEA realisiert weil schnell.

B: Was ist diese Namenstabelle?

S: Öhm, da werden so Token reingespeichert, wo die sind oder so.

P: Moment, das erklären Sie mir nocheinmal, warum braucht man die?

S: [Irgendwas versucht zu erklären, aber nicht gewusst] Weiß ich nicht.

B: Na gut, wie sieht das bei Anweisung [1] aus?

S: TK_Bool, ID, TK_ASSIGN, ID, '(',

B: Okay das reicht, danke. Was jetzt?

S: Parser macht aus Token Syntaxbaum / AST. Wird auch automatisch generiert, aber als Kellerautomat.

P: Was bekommt er als Eingabe?

S: Die Token natürlich, die Grammatikregeln, und Code, der ausgeführt wird, wenn eine Reduktion durchgeführt wurde.

B: Okay, führen sie das doch mal bei [2] durch.

S: *Baum hingemalt so gut es geht* (die Prüfer wollten wohl hauptsächlich die linke Seite, und das hinmalen mit den Generics sehen. Das hab ich nicht so gut hinbekommen, da wurde auch nachgefragt bzw erwähnt, dass das so nicht so toll ist. Man will wohl die Klasse generisch hinschreiben, und den Typ spezialisieren.)

P: Und wo steht jetzt dieses f?

S: Ah, das steht in der Namenstabelle… (P grinst)

B: Gut, danke soweit. Was kommt jetzt?

S: Semantische Analyse, Deklarationseigenschafts- und Typprüfung.

B: Wofür braucht man die Typprüfung?

S: Um festzustellen, ob die benutzten Operanten auf die Typen definiert sind, und welche Operanten man bei Überladung nutzen muss.

B: Gut, was als nächstes?

S: Abbildungsphase

B: Gut, was machen wir hier konkret?

S: Also zuerst haben wir hier eine generische Klasse.

B: Wie transformiert der Compiler die?

S: Da wird in Java alles ausradiert und durch Objekt ersetzt, und hier konkret braucht man noch eine Brückenmethode

B: Warum?

S: Weil hier in apply das Integer nicht ersetzt wird, weil es konkretisiert wurde. Die Überladung jedoch erfordert, dass es vom gleichen Typ sein muss.

B: Wie sieht die aus?

S: Object apply (Object a){

      return (Integer) apply((Integer) a);
  }
  

B: Das Integer da muss weg, es wird eh ein Objekt gemacht. Egal. Was nun?

S: Das ist auch noch eine innere Klasse, die müssen wir auch transformieren.

B: Wie?

S: Klasse rausziehen, Namen nach Format Outer$Inner umbenennen, also A$FunctionInt, Referenz auf die äußere Klasse mitspeichern, Konstruktor erstellen der Äußere Referenz bekommt.

P: Da fehlt noch was.

S: Ähm, ähm…, die Namen der Klasse überall austauschen

P: Auch, aber ich meine etwas anderes, ist in diesem Beispiel nicht mit dabei.

B: Wenn sie so an Modifikatoren denken…

S: Achja, Access-Methoden für den Zugriff auf die Variablen der äußeren Klassen in der äußeren Klasse hinzufügen.

P: Das wars, danke

B: Gut, was jetzt?

S: Zwischencode erzeugen.

B: Gut, da haben wir verschiedene Verfahren kennengelernt. Hier ist eines davon, welches ist das *legt mir Zettel mit nem Baum und Transformationsmustern hin*

S: Codeerzeugung durch Baumtransformation.

B: Wie funktioniert das?

S: Man erzeugt Regeln aus den Maschineninstruktionen und ersetzt Bottom-Up Muster so gut wie es geht, bis man den ganzen Baum transformiert hat, pro Reduktion wird der Maschinenbefehl ausgegeben. Am Ende ist fertiger Code da.

B: Kann man alle Maschineninstruktionen abbilden?

S: *kurz überlegt, dachte es wäre eine Fangfrage* Mir fällt gerade kein Gegenbeispiel ein, ich denke schon.

P: Wirklich alle?

S: Also die Adressierungsarten wenns der Maschinensatz hergibt, ja…

P: Sicher, alle Adressierungsarten?

S: Schon…

P: Was ist denn mit so speziellen Arrayzugriffen, in Schleifen…

S: Ah, ja, natürlich, Maschinenbefehle mit Seiteneffekten wie Inkrementierungen lassen sich da nicht abbilden. Die werden normalerweise ignoriert.

P: Genau.

B: So, sind wir fertig?

S: Nein, Wir haben hier unbegrenzt viele Register angenommen, wir brauchen jetzt noch Registerzuteilung

B: Das macht man mit Graphfärben, wie funktioniert das?

S: Interferenzgraphen aufstellen, dann versuchen den Graphen zu färben.

B: Und wie färbt man den?

S: Naja, also ab 3 Farben ist es NP-Schwer, da braucht man eine Heuristik, wir haben in der Vorlesung die Grad<R-Regel kennengelernt (kurz erklärt)

B: Was sind da Knoten, was Kanten im Graphen

S: Knoten sind Lebensspannen der symbolischen Registern, Kanten sind Kollisionen zwischen den Lebensspannen. Kollision heißt hier, das ein Wert des symbolischen Registers innerhalb der Lebensspanne des anderen gesetzt wird.

P: Kann man so Lebensspannen auch teilen?

S: Ja, kann man, wenn mehrere verschiedene Werte in einem Register untergebracht werden

B: Was kann man da noch so machen, in diesem Intereferenzgraphen

S: Registerverschmelzung und Spilling

P: Erklären sie mal, wann man diese Registerverschmelzung macht

S: Wenn man von einem symbolischen Register ein mov in ein anderes macht, und man es schafft, beide symbolischen Register in das gleiche Hardwareregister abzubilden, kann man sich diese mov-Instruktion sparen.

P: Okay, und dieses Spiling?

S: Wenn der Graph nicht färbbar ist, sichert man sich das symbolische Register im Speicher und lädt das am Ende wieder.

P: Am Ende?

S: Ja… [P merkte, dass ich hier wohl nicht ganz genau Bescheid weiß]

P: Was ist, wenn sie das Zwischendurch brauchen?

S: Dann lade ich das jedesmal

P: Jedesmal?

S: Man kann es im Register lassen, das wäre eine Optimierung.

P: Und was machen sie, wenn Sie das im Speicher haben?

S: Neu färben, komplett.

P: Okay… [In der Besprechung erklärt man mir, dass man es nicht am Ende wieder lädt, sondern sobald man es wieder braucht, und so die Lebensspanne aufspaltet. Damit hat man auch Graphen mit weniger Kollisionen, und kann den damit wieder färben]

B: Gut, soweit zum Graphfärben. Wir haben da noch ein anderes Verfahren kennengelernt, das nicht ganz so gut ist.

S: Wir haben da noch DP und Graham&Glanville kennengelenrt

B: Ah, beim Registerverteilen

S: *leicht zögernd* Es gibt da noch Getreg

B: Okay, warum ist das nicht ganz so gut?

S: *Erstmal erklärt, weil ich nicht ganz wusste, was sie hören wollen* und das erzeugt nicht so optimale Verteilung

P: Ah, das ist aber keine gute Antwort, es ist nicht so gut, weil es nicht so gut ist.

S: Richtig, *nachdenk*

P: Sie kommen drauf, wenn sie denken, welche Sicht dieses Verfahren hat

S: Ah, hat nur lokale Sicht auf die aktuelle Instruktion, nicht auf den gesamten Quelltext, kann somit nicht so gut optimieren.

P: Genau das.

B: So, sind wir fertig?

S: Nein, wir können noch Instruktionen vertauschen

B: Warum sollte man das tun?

S: Fließband erklärt, dann was von Ressourcen und Datenabhängigkeit erklärt, genauer auf die Datenabhängigkeit mit Beispiel eingegangen (Multiplikation braucht noch nicht zurückgeschriebenes Ergebnis…)

B: Ah, alles klar. Gut. Danke. Dann sind wir hier fertig.

Nach kurzer Zeit wurde ich wieder hereingeholt und nach meinem Eindruck gefragt. Ich hatte halt Spilling und Getreg nicht so ganz gewusst/verstanden, was man in meinen Ausführungen auch gemerkt hat. Insgesamt hatte ich aber alle gefragten Themen gut verstanden und darlegen können, habe teilweise auch spezifischere Fragen (Parser führt Code aus) beantworten können, was insgesamt zu einem sehr guten Ergebnis führte.