Semantik =
 
 
Beispiele:
  
 
Hilfsmittel: Attributgrammatiken
 
operational, axiomatisch, denotational
 
 
 
 
A : Knotenmenge→Attributwerte
 
 
eine Menge (Relation) von erlaubten Attribut-Tupeln
      
(A(X0), A(X1),…, A(Xn))
 
für Knoten X0
 
 
 
 
 
ein Ableitungsbaum  mit Annotationen ist 
 
Plan:
 
Ursprung:
Donald Knuth: Semantics of Context-Free Languages,
(Math. Systems Theory 2, 1968)
 
technische Schwierigkeit: Attributwerte
effizient bestimmen. (beachte: (zirkuläre) Abhängigkeiten)
 
 
 
 
(Band 3: Sortieren und Suchen)
 
(Leslie Lamport: LATEX)
 
http://www-cs-faculty.stanford.edu/~uno/
 
 
 
 
hängt nur von Attributwerten in Kindknoten ab
 
hängt nur von Attributwerten in Elternknoten
  und (linken) Geschwisterknoten ab
 
Wenn Abhängigkeiten bekannt sind,
kann man Attributwerte durch Werkzeuge bestimmen lassen.
 
 
 
 
 
 
abstrakter Syntaxbaum kann als
synthetisiertes Attribut konstruiert werden.
 
 
 
 
 
...bei geschachtelten Funktionsaufrufen
 
 
Beispiel
 
 
 
(Curry-Howard-Isomorphie)
 
 
 
 
SableCC is a parser generator for building compilers, interpreters ...,
strictly-typed abstract syntax trees and tree walkers
 
 
 
Benutzung:  
(dafür muß  
 
 
Multiplikation,
 Subtraktion,
 Klammern,
 Potenzen
 
Kommentar: in Java fehlen: algebraische Datentypen,
Pattern Matching, Funktionen höherer Ordnung.
Deswegen muß SableCC das simulieren -- das sieht
nicht schön aus. Die „richtige`` Lösung
sehen Sie später im Compilerbau.
 
Abstrakter Syntaxbaum, Interpreter: 
http://www.imn.htwk-leipzig.de/~waldmann/edu/ws11/cb/folien/main/node12.html,
Kombinator-Parser:
http://www.imn.htwk-leipzig.de/~waldmann/edu/ws11/cb/folien/main/node70.html
 
 
 
 
 
beschreibt Wirkung von Anweisungen 
  durch Änderung des Programmzustandes
 
ordnet jedem (Teil-)Programm einen Wert zu,
  Bsp: eine Funktion (höherer Ordnung).
 
Beweis von Programmeigenschaften durch
  Term-Umformungen
 
enthält Schlußregeln, 
  um Aussagen über Programme zu beweisen
 
 
arithmetischer Ausdruck 
⇒
 
3*x + 1
 
 
 
Beispiele: Java-Bytecode (javac, javap), 
 
Bemerkung: soweit scheint alles trivial--interessant
wird es bei Teilausdrücken mit Nebenwirkungen,
Bsp.  
 
 
Schleife
 
wird übersetzt in Sprungbefehle
 
Aufgabe: übersetze  
 
 
 
Beispiele
  
Vorteile denotationaler Semantik:
  
Programmiersprache ist Beschreibungssprache
 
 
 
 
beschreibt eine Zahl
 
beschreibt eine Funktion (von Variablenbelegung nach Wahrheitswert)
 
beschreibt eine formale Sprache
 
beschreibt eine Funktion (?)
  
 
 
Unterprogramme definiert durch Gleichungssysteme.
 
Sind diese immer lösbar? (überhaupt? eindeutig?)
 
Geben Sie geschlossenen arithmetischen Ausdruck für:
 
 
 
Notation für Aussagen über Programmzustände:
 
 
Beispiel:
 
Gültigkeit solcher Aussagen kann man
 
 
 
Bertrand Meyer, http://www.eiffel.com/
 
 
 
 
Kalkül: für jede Anweisung ein Axiom,
das die schwächste Vorbedingung
(weakest precondition) beschreibt.
 
 
Beispiele
 
 
 
 
Beispiel:
 
 
 
Schreiben Sie eine Java-Methode, deren Kompilation
genau diesen Bytecode erzeugt:
a)
 
b)
 
 
 
Ergänze das Programm:
 
 
 
 
S→mSS
S→e
Terminale: 
A(e) = 1, A(m) = 0
korrekt bezüglich einer Attributgrammatik, 
wenn 
unwesentlich sind z. B. die Knoten, 
die zu Hilfsvariablen der Grammatik gehören.
E -> E + P  ;  E.abs = new Plus(E.abs, P.abs)
E -> P      ;  E.abs = P.abs
String x = "foo"; String y = "bar";
Boolean.toString (x.length() < y.length()));
linke-seite { -> attribut-typ } 
   = { zweig-name } rechte-seite { ->  attribut-wert }
git clone git://dfa.imn.htwk-leipzig.de/ws13-code/pps.git
cd pps/rechner ; make ; make test ; make clean
sablecc gefunden werden, also /usr/local/waldmann/bin im PATH sein)
rechner.grammar enthält Attributgrammatik, diese beschreibt die Konstruktion
    des abstrakten Syntaxbaumes (AST) aus dem Ableitungsbaum (konkreten Syntaxbaum)
Eval.java enthält Besucherobjekt, dieses beschreibt die Attributierung
    der AST-Knoten durch Zahlen
Interpreter.java
Makefile
rechner/*
  
Der erzeugte Code ist synthetisiertes Attribut!push c;
code(x); code(y); o;
x <- pop; y <- pop; push (x o y);
CIL (gmcs, monodis)
x++ - --x;
while (B) A
   if (B) ...
(vervollständige!)
for(A; B; C) D in while!
Vorteil deklarativer Programierung:
f (x) = if x > 52 
        then x - 11 
        else f (f (x + 12))
t (x, y, z) = 
  if x <= y then z + 1 
  else t ( t (x-1, y, z) 
         , t (y-1, z, x) 
         , t (z-1, x, y) )
{ V } A { N }
{ x >= 5 } y := x + 3 { y >= 7 }
class Stack [G]     feature 
    count : INTEGER
    item : G is require not empty do ... end
    empty : BOOLEAN is do .. end
    full  : BOOLEAN is do .. end
    put (x: G) is
       require not full do ...
       ensure not empty
              item = x
              count = old count + 1
Beispiel sinngemäß aus: B. Meyer: 
Object Oriented Software Construction,
Prentice Hall 1997
 { N[x/E] } x := E { N } 
    { V und     B } C { N }  
und { V und not B } D { N }
=>  { V } if (B) then C else D { N }
wenn  { I and B } A { I },
dann  { I } while (B) do A { I and not B }
Eingabe int p, q; 
// p = P und q = Q
int c = 0;
// inv: p * q + c = P * Q 
while (q > 0) { 
   ???
}
// c = P * Q
Moral: erst Schleifeninvariante (Spezifikation),
dann Implementierung.
  public static int h(int, int);
    Code:
       0: iconst_3      
       1: iload_0       
       2: iadd          
       3: iload_1       
       4: iconst_4      
       5: isub          
       6: imul          
       7: ireturn
  public static int g(int, int);
    Code:
       0: iload_0       
       1: istore_2      
       2: iload_1       
       3: ifle          17
       6: iload_2       
       7: iload_0       
       8: imul          
       9: istore_2      
      10: iload_1       
      11: iconst_1      
      12: isub          
      13: istore_1      
      14: goto          2
      17: iload_2       
      18: ireturn
Eingabe: natürliche Zahlen a, b;
// a = A und b = B
int p = 1; int c = ???;
// Invariante:  c^b * p = A^B
while (b > 0) {
    ???
    b = abrunden (b/2);
}
Ausgabe: p; // p = A^B