Informatik III - Zusamenfassung

Werbung
Informatik III - Zusamenfassung
Patrick Pletscher
15. September 2004
1 Einführung in Haskell
Man kann das Ganze aber auch Infix schreiben:
1.1 Grundbegriffe der funktionalen
Programmierung
? 7 ’mod’ 2
• Funktionen und Werte
Eine Infix Binary-Funktion heisst ”Operator”.
– Funktionen berechnen Werte
Typ Bool
– Funktionen können selbst als Werte betrachtet werden
• Werte: True, False
• Keine Seiteneffekte: f(x) ergibt immer das gleiche
Ergebnis
• Operatoren (infix) &&, ||, not
Typ Tupel
1.2 Syntax
Beispiel : Student hat Name, Martikelnummer,
Anfangsjahr
ggT als funktionales Programm
ggt
|
|
|
x y
x == y
= x
y > x
= ggt y x
otherwise = ggt (x-y) y
Rekord-Typ:
mit Element:
(String, Int, Int)
("Fritz", 1234, 2002)
Muster und Funktionsdefinition
Anstatt anzugeben, wie etwas berechnet wird, gibt Funktionsdefinition mit Muster mi und Guards gi
kann kombiniert werden:
man an, was berechnet werden soll.
fun m1 m2 ... mn
| g1
= e1
:
| gm
= em
| otherwise = e
Das Programm besteht aus mehreren Fällen:
Name x1 ... xn
| guard1 = fall1
:
| guradm = fallm
---optional!
Lokale Reichweite mit let und where
Typen
• let
Entweder der User gibt Typen mit FunktionsDefinitionen an, z.B.
let x1 = e1
:
xn = en
in e
ggt :: Int -> Int -> Int
oder das System berechnet die Typen selbst.
Typ Int
let baut einen Ausdruck von anderen aus:
• Beschränkt auf 32bit
– xi kann sowohl Variable oder Funktionen
(lokal) binden
• Funktionen sind meist Präfixform, also:
– Eine Definition kann auch andere benutzen
? mod 7 2
Beispiel
1
Korrektheit - Richtiges Verhalten
f x = let sq y = y * y
in sq x + sq x
Basiert auf einfacher Idee: Funktionen sind Gleichungen, man kann also mathematische Methoden und
auch logische Kalküle benutzen, so z.Bsp.:
Wir können f auswerten, aber nicht sq.
• ”Excluded Middle”: für alle Aussagen P gilt immer:
P∨ 6 P
• Where
f p1 p2 .. pk
| g1 = e1
| g2 = e2
:
| gk = ek
where
v1 a1 ... an = r1
v2 = r2
:
• Fallunterscheidung: Gegeben sei Q ∨ R. Für P
müssen wir zeigen:
1. Aus der Annahme Q folgt P und
2. Aus der Annahme R folgt P
• Induktion.
2 Listen
– where wird direkt nach einer Funktionsdefinition gegeben
2.1 Listentypen
– Man kann Bindings über mehrere Guards
definieren
Listentyp, aufgebaut mit Listentyp-Konstruktor:
Wenn T ein Typ ist, dann ist [T ] ein Typ.
Beispiel
Elemente von [T ]:
maxThreeOccurs n m p = (maxVal, eqCount)
where maxVal = maxiThree n m p
eqCount = equalCount maxVal n m p
• Leere Liste [] :: [T ]
• Wenn a :: T und l :: [T ], dann (a : l) :: [T ]
maxiThree a b c = max a (max b c)
equalCount
where isN
isM
isP
val n m p
= if n ==
= if m ==
= if p ==
Abkürzung: 1 : (2 : (3 : [])) wird als [1, 2, 3] geschrieben.
= isN + isM + isP
val then 1 else 0
val then 1 else 0
val then 1 else 0
Weitere Abkürzungen:
? [3..6]
[3,4,5,6]::[Int]
1.3 Korrektheit
? [6..3]
[]::[Int]
Terminierung
Falls die Funktion f durch andere Funktionen
g1 , . . . , gk definiert wird und diese gi terminieren, [n,p..m] heisst Zahlen von n zu m in Schritten p−n:
dann terminiert f .
? [7,6..3]
[7,6,5,4,3]::[Int]
Das Problem sind Rekursionen:
Hinreichende Terminationsbedingung: Argumen? [0.0, 0.3 .. 1.0]
te werden entlang einer wohlfundierten Ordnung
[0.0, 0.3, 0.6, 0.9] :: [Double]
kleiner. Wobei eine Ordnung > wohlfundiert ist,
wenn es keine unendlich absteigende Ketten gibt
x1 > x2 > x3 > . . .. Beispiel: > N, Gegenbeispiele: 2.2 Standardfunktion über Listen
> Z, > R
length
Beispiel: Fakultät einer Zahl
length [] = 0
length (a:x) = 1 + length x
fac 0 = 1
fac n = n * fac (n-1)
Append (nicht nur für Strings)
fac n hat nur fac (n-1) als rekursiven Aufruf und
n > n−1, wobei > die Ordnung über den natürlichen
Zahlen ist.
[] ++ y = y
(a:x) ++ y = a:(x++y)
2
2.3 Muster
3 Abstraktion
Ein Muster wird wie folgt induktiv definiert:
3.1 Funktionen höherer Stufe
Konstante
Argumente dürfen selber Funktionen sein.
Variable
(Int -> Int) -> [Int] -> [Int]
Tupel : (p1 , . . . , pk ), wobei auch pi Muster sind
map
Liste : (p1 : p2 ) wobei auch pi Muster sind
-- higher order (function f is an argument)
map :: (a -> b) -> [a] -> [b]
’Wild cards’ :
map f [] = []
map f (a:x) = f a : map f x
Aber ein Muster muss linear sein: jede Variable darf
nur maximal ein Mal vorkommen.
Ähnlichkeit mit Listenkomprehension:
2.4 Musteranpassung
map f l = [f a | a <- l]
Argument a wird einem Muster p erfolgreich angefoldr
passt gdw p ist:
rechts-assoziatives Fold:
Konstante : a = p
f oldr(⊕) e [l1 , . . . , ln ] = l1 ⊕ (l2 , . . . ⊕ (ln ⊕ e))
Variable x: erfolgt immer mit Zuordnung x = a
foldr :: (a -> b -> b) -> b -> [a] -> b
Tupel (p1 , . . . , pk ): a = (a1 , . . . , ak ) und ai an pi anfoldr f e [] = e
gepasst wird.
foldr f e (x:xs) = f x (foldr f e xs)
Liste (p1 : p2 ): a ist eine nicht leere Liste und p1 wird Damit kann man z.Bsp. concat definieren:
dem Kopf von a angepasst und p2 wird dem Rest
von a angepasst.
concat xs = foldr (++) [] xs
? concat [[1,2,3],[4],[5,6]]
’Wild cards’ : immer, aber keine Bedingung (fun[1,2,3,4,5,6] :: [Int]
giert nur als Test)
foldl
zip (a:x) (b:y) = (a,b) : zip x y
zip _ _ = []
links-assoziatives Fold:
f oldl(⊕) e [l1 , . . . , ln ] = ((e ⊕ l1 ) ⊕ l2 ) . . . ⊕ ln
Insertion Sort
foldl :: (a -> b -> a) -> a -> [b] -> a
foldl f e [] = e
foldl f e (x:xs) = foldl f (f e x) xs
isort :: [Int] -> [Int]
isort [] = []
isort (a:x) = ins a (isort x)
ins :: Int -> [Int] -> [Int]
ins a [] = [a]
ins a (b:y)
| a <= b = a:(b:y)
| otherwise = b:(ins a y)
3.2 Typen und Polymorphismus
Polymorphe Typen enthalten Typvariablen:
length :: [t] -> Int
Definition: Ein Typ w für f ist ein allgemeiner (auch
prinzipaler ) Typ gdw. für alle Typen s für f , s eine
Instanz von w ist.
2.5 Listen-Komprehension
Notation für sequenzielle Verarbeitung der Listen,
welche mit Tests kombiniert werden kann.
3.3 Funktionen als Werte
[2*a | a <- l, b1(a), ..]
Funktionen können als Werte geliefert werden. So
z.Bsp. Funktionskomposition:
Quicksort
(f ◦ g)x = f (gx)
q [] = []
q (a:x) = q [y | y<-x, y <=a] ++
[a] ++ q[y |y<-x, y>a]
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(f . g) x = f (g x)
3
3.4 λ-Ausdrücke
Fold: Kombination von Elementen
Beispiel:
4.3 Map und Filter versus
Komprehension
? map (\x -> x * 2) [2,3,4]
[4,6,8] :: Int
Map und Filter können mit Komprehension implementiert werden
? foldr (\x y -> x * y) 1 [1,2,3,4]
24 :: Int
map f l = [f x | x <- l]
filter p l = [x | x <- l, p x]
3.5 Partielle Anwendung
Auch die Umkehrung gilt auch: [e | p <- s]
Jede Funktion nimmt genau ein Argument
multiply :: Int -> Int -> Int bedeutet
multiply :: Int -> (Int -> Int)
let fn p = e in map fn s
Guards erfordern Filter: [e | p <- s, g] übersetzt
als
(multiply 2) ist z.Bsp. eine Funktion, die ein Argument nimmt und als Resultat die Verdoppelung ist.
let fn p = e
pred p = g
in map fn (filter pred s)
3.6 Mehrere Argumente vs. Tupeln
4.4 zipWith
f :: (Int,Int) -> Int
f (x,y) = x * y + 17
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys
zipWith f _ _ = []
g :: Int -> Int -> Int
g x y = x * y +17
Tupel-Argumente: keine partielle Auswertung.
5 Typklassen und Polymorphismus
Aber äquivalent im folgenden Sinn:
5.1 Typklassen
curry :: ((a,b) -> c) -> a -> b -> c
uncurry :: a -> b -> c -> (a,b) -> c
allEqual :: Eq a => a -> a -> a -> Bool
allEqual x y z = (x == y) && (y == z)
Funktioniert für genau die Typen a, die zur Klasse
Eq gehören.
curry f
= f’ where f’ x1 x2 = f (x1,x2)
uncurry f’ = f where f(x1,x2) = f’ x1 x2
Beispiele
Eq ist die Gleichheitsklasse, eine Klasse definiert eine
Menge von Typen.
? f (3,4)
29 :: Int
Definition der Eq Klasse
? curry f 3 4
29 :: Int
class Eq a where
(==), (/=) :: a -> a -> Bool
x /= y
= not (x==y)
4 Programmierung höherer
Ordnung
Eine Definition beeinhaltet:
Klassenname: Eq
Signatur: Liste von Namen und Typen
4.1 Filter
(Optional Standard-) Definition: kann später überschrieben werden
filter :: (a -> Bool) -> [a] -> [a]
filter p [] = []
filter p (h:t)
| p h = h:rest
otherwise = rest
where rest = filter p t
Elemente von Klassen heissen Instanzen.
Instanzen
Durch eine Definition von Signaturfunktionen wird
ein Typ in einer Klasse instanziert.
4.2 Abstrahieren allgemeiner
Operationen
instance Eq Bool where
True == True = True
False == False = True
_ == _ = False
Map: Funktionale Anwendung auf jedes Element.
Filter: Selektion
4
Ageleitete Klassen
Regeln für Kern λ-Kalkül
• Symboltabelle Axiom: . . . , x : τ, . . . ` x :: τ
class Eq a => Ord a where
(<), (>), (<=), (>=) :: a -> a -> Bool
max, min :: a -> a -> a
• Abstraktion (x 6∈ A):
A, x : σ ` t :: τ
A ` λx.t :: σ → τ
x < y = (x <= y && x /= y)
x >= y = y <= x
x > y = y <= x && x/= y
max x y |
|
min x y |
|
x <= y
otherwise
x <= y
otherwise
=
=
=
=
• Applikation:
A ` t1 :: σ → τ
A ` t2 :: σ
A ` (t1 t2 ) :: τ
y
x
x
y
Die Applikation vereingt sich links. Bsp. xyz
steht für (xy)z
Wenn a zu Ord gehört, dann muss a auch zu Eq
gehören. Funktionen für Eq werden vererbt, einige
neue müssen gegeben werde:
Weitere Typregeln für mini-Haskell
• Basistypen
A ` n :: Int
Instance Ord Int where (<=) = primeLeInt
A ` true :: Bool
A ` f alse :: Bool
5.2 Typisierung
• Operationen (op ∈ {+, ×})
Ziel von Typisierung:
A ` t :: Int
A ` iszero(t) :: Bool
• schnell entscheidbare statische Analyse
A ` t1 :: Int
A ` t2 :: Int
A ` t1 op t2 :: Int
• erlaubt so viel Allgemeinheit und Wiederverwendbarkeit wie möglich.
A ` t0 :: Bool
A ` t1 :: τ
A ` t2 :: τ
A ` if t0 then t1 else t2 :: τ
• Keine Laufzeitfehler: Subjektreduktion
Sei e ,→ e0 und ` e :: τ . Dann gilt auch ` e0 :: τ
• Tupeln
A ` t1 :: τ1
A ` t2 :: τ2
A ` (t1 , t2 ) :: (τ1 , τ2 )
Mini-Haskell - Syntax
Programme sind Terme (Sie Variablen V und Zahlen
Z gegeben)
A ` t :: (τ1 , τ2 )
A ` fst(t) :: τ1
::= V | λx.t | (t1 t2 ) |
true | f alse | iszero(t) |
Z | t1 + t2 | t1 × t2 | if t0 then t1 else t2 |
(t1 , t2 ) | fst(t) | snd(t)
A ` t :: (τ1 , τ2 )
A ` snd(t) :: τ2
t
6 (Algebraische) Datentypen
6.1 Algebraische Datentypen
Typisierung
Anstatt gegebene Typen zu verwenden, kann ein Typ
Typen (VT ist die Menge von Typ Variablen, a, b, . . .) deklariert werden, der die Objekte ’direkt’ modelliert.
τ ::= VT | Bool | Int | (τ, τ ) | τ → τ
Aufzählungstypen (Verbunde)
data Season = Spring | Summer | Fall | Winter
Notation des Typsystems basiert auf Typurteilen A `
e :: τ
Syntax:
• fängt mit Keyword data an
• A ist ’Symboltabelle’: Abbildung von Identifikatoren auf Typen
• gibt verschiedene eindeutig genannte Konstruktoren
• e ist ein Ausdruck
• erster Buchstabe von Konstruktoren muss gross
sein
• τ ist ein Typ
5
6.4 Programmierung höherer Ordnung
mit Datentypen
Produkttypen
data People = Person Name Age
type Name = String
type Age = Int
Vorgehensweise vieler Funktionen höherer Ordnung
verallgemeinbar
mapTree :: (t -> u) -> Tree t -> Tree u
mapTree f Leaf = Leaf
mapTree f (Node x t1 t2) =
Node (f x) (mapTree f t1) (mapTree f t2)
Aufzählungs- und Produkttypen
Kombinationen möglich
data Shape = Circle Float |
Rectangle Float Float
6.5 treeFold
• Konstruktoren dienen als Funktionen
treeFold :: (a -> b -> b -> b) -> b -> Tree a -> b
? Rectangle
<<function>> :: Float -> Float -> Shape
treeFold f e Leaf = e
treeFold f e (Node x l r) =
f x (treeFold f e l) (treeFold f e r)
• Beispiele von Fuktionen:
area :: Shape -> Float
area (Circle r) = pi * r * r
area (Rectangle h w) = h * w
Von Bäumen zu Listen
preorder t = treeFold (\x y z -> [x] ++ y ++ z) [] t
inorder t = treeFold (\x y z -> y ++ [x] ++ z) [] t
Integration mit Klassen
postorder t = treeFold (\x y z -> y++ z ++ [x]) [] t
Klasseninstanz kann explizit kreiert werden:
data Foo = D1 | D2 | D3
7 Programmierung mit
verzögerter Auswertung
instance Eq Foo where
D1 == D1 = True
D2 == D2 = True
D3 == D3 = True
_ == _ = False
Haskell basiert auf verzögerter Auswertung: Ein Argument wird nur ausgeführt, wenn es gebraucht wird.
In einigen Fällen können Klasseninstanzen automatisch abgeleitet werden.
Mögliches Problem: Duplizierte Berechnung, z.B.
h x = x + x.
data Foo = D1 | D2 | D3
deriving (Eq, Ord, Enum, Show)
• Dieselben Ausdrücke würden hier zwei Mal ausgewertet.
6.2 Allgemeine Definition
data T
• Kann vermieden werden: Beide können gleichzeitig reduziert werden.
=
• Implementierungsidee: Ausdrücke werden als
Graphen anstatt als Bäume modelliert.
Con1 T11 . . . T1k1
|Con1 T21 . . . T2k2
..
.
Conn Tn1 . . . Tnkn
7.1 Auswertung - Diverses
Funktionen werden von aussen nach innen ausgeführt
und sonst von links nach rechts.
Tij sind andere Typen, möglicherweise auch T
(rekursiv).
8 Substitution
Rekursivtypen
f ree(x) = {x}
f ree(λx.M ) = f ree(M ) − {x}
f ree(M N ) = f ree(M ) ∪ f ree(N )
data Expr = Lit Int | Add Expr Expr |
Sub Expr Expr
6.3 Bäume
8.1 λ-Kalkül - Substitution
data Tree t = Leaf | Node t (Tree t) (Tree t)
deriving (Eq, Ord, Show)
M [x ← N ] bedeutet: x wird durch N in M ersetzt.
6
1. x[x ← N ] = N
Operationelle Semantik
2. y[x ← N ] = y, falls y 6= x
Varianten:
• Natürliche Semantik (Big-Step Semantics)
3. (P Q)[x ← N ] = (P [x ← N ]Q[x ← N ])
• SOS (Structural Operational Semantics)
4. (λx.P )[x ← N ] = λx.P
• ASMs (Gurevich Abstract State Machines)
5. (λy.P )[x ← N ] = λy.(P [x ← N ]), falls y 6= x
und y 6∈ F V (N )
9.3 Eine einfache imperative
Programmiersprache
6. (λy.P )[x ← N ] = λz.((P [y ← z])[x ← N ]) falls
y 6= x und y ∈ F V (N ), wobei z 6∈ F V (N P )
Nur zwei Typen: boolean, integer
Bedeutung der Anweisungen (informale Semantik)
9 Semantik von
Programmiersprachen Übersicht
skip
x:= e
s1 ; s2
9.1 Semantik (statisch vs. dynamisch)
if b then s1 else s2 end
Statische Semantik
while b do s end
Was muss zur Compilezeit überprüft werden?
var x := e in s end
• Typregeln, Typüberprüfung
p(~e, ~z)
• statische Analyse (z.B. Definite Assignment)
• Auflösung von Namen
Mache nichts (leere Anweisung)
Weise x den Wert von e zu.
Führe zuerst s1 aus, danach
s2
Falls b wahr ist, führe s1 aus,
sont s2 .
Solange b wahr ist, führe s
aus.
Erzeuge eine neue lokale Variable x mit dem Wert e und
führe s aus.
Rufe die Prozedur p mit den
Werten von ~e und den Variablen ~z auf.
Bedingung: Die Variablen in ~z müssen paarweise verschieden sein.
• Auflösung von Methoden (für überladene Methoden)
10 Natürliche Semantik von
Programmen
Dynamische Semantik
Was geschieht zur Laufzeit?
Idee: Zu einem Programm π definiert man induktiv
Tripel
σ −[s]→ σ 0
• Ausführung des Programms
• Was definiert den Zustand eines Programms?
mit der Bedeutung:
• Was ist der Effekt eines Programms auf den Zu- Die Ausführung der Anweisung s terminiert für π und
führt den Anfangszustand σ über in den Endzustand
stand?
σ0 .
9.2 Dynamische Semantik
10.1 Regeln der natürlichen Semantik
Denationelle Semantik
Die natürliche Semantik eines Programms wird durch
Regeln
ϕ1 . . . ϕ n
Condition
ψ
Programme = mathematische Objekte
• Ein Programm wird betrachtet als (partielle) Dabei sind ϕ1 , . . . , ϕn und ψ Tripel
Funktion in einem mathematischen Raum.
σ −[s]→ σ 0
• Gut für deklarative Sprachen (funktionale Programmierung).
wobei σ, σ 0 ∈ State und s ∈ Stm.
Bedeutung der Regel:
• Zu kompliziert für objekt-orientierte Sprachen
Falls Condition und ϕ1 , . . . , ϕn , dann ψ.
mit Vererbung, Exception Handling, Threads.
7
10.2 Natürliche Semantik
σ −[skip]→ σ
σ −[x:=e]→ σ[x 7→ A[e]σ]
σ −[s1 ]→ σ 0
σ 0 −[s2 ]→ σ 00
σ −[s1 ; s2 ]→ σ 00
σ −[s1 ]→ σ 0
falls B[b]σ = 1
σ −[if b then s1 else s2 end]→ σ 0
σ −[s2 ]→ σ 0
falls B[b]σ = 0
σ −[if b then s1 else s2 end]→ σ 0
σ −[s]→ σ 0
σ 0 −[while b do s end]→ σ 00
falls B[b]σ = 1
σ −[while b do s end]→ σ 00
σ −[while b do s end]→ σ
falls B[b]σ = 0
σ[x 7→ A[e]σ] −[s]→ σ 0
falls x ∈ dom(σ)
σ −[var x := e in s end]→ σ 0 [x 7→ σ(x)]
σ[x 7→ A[e]σ] −[s]→ σ 0
falls x 6∈ dom(σ)
σ −[var x := e in s end]→ σ 0 \{x 7→ σ 0 (x)}
{~x 7→ A[~e]σ, ~y 7→ σ(~z)} −[s]→ σ 0
σ −[p(~e; ~z)]→ σ[~z 7→ σ 0 (~y )]
für procedure p(~x; ~y ) begin s end
8
10.3 Die zugewiesenen Variablen
11.1 Transitionsregeln der
ASM-Semantik
AV(skip) = ∅
Leere Anweisung
AV(x := e) = {x}
H
AV(s1 ; s2 ) = AV(s1 ) ∪ AV(s2 )
AV(if b then s1 else s2 end) = AV(s1 ) ∪ AV(s2 )
skip →Nskip
Zuweisung
AV(while b do s end) = AV(s)
H
AV(var x := e in s end) = AV(s)\{x}
(x := e) → N (x := e)
store(env(x)) := A[e](store ◦ env)
AV(p(~e; ~z)) = {~z}
Die Menge AV(s) ist eine Obermenge der Variablen, Sequenzielle Komposition
die von der Anweisung s zur Laufzeit tatsächlich H (s ; s ) → H s
1
2
1
geändert werden.
(N s1 ; s2 ) → H s2
(s1 ;
N
s2 ) →
N
(s1 ; s2 )
10.4 Technische Details
If-Then-Else-Anweisung
Die natürliche Semantik erhält den Definitionsbereich
der Zustände.
Lemma 10.1. Falls σ −[s]→ σ 0 ,
dom(σ) = dom(σ 0 ).
H
dann ist
if b then s1 else s2 end →
if B[b](store ◦ env) = 1 then H s1 else H s2
if b then N s1 else s2 end → N if b then s1 else s2 end
Die natürliche Semantik von deterministischen Programmen ist deterministisch.
if b then s1 else N s2 end → N if b then s1 else s2 end
Lemma 10.2. Falls σ −[s]→ σ 0 und σ −[s]→ σ 00 ,dann
ist σ 0 = σ 00 .
While-Anweisung
H
Nur zugewiesene Variablen werden geändert.
Lemma 10.3. Falls σ −[s]→ σ 0 und
dom(σ)\AV(s), dann ist σ 0 (x) = σ(x).
while b do s end →
if B[b](store ◦ env) = 1 then H s else N while b do s end
x ∈ while b do N s end → H while b do s end
Lokale Variablendeklaration
10.5 Koinzidenz
H
Lemma 10.4. Falls σ und τ auf den Variablen von
e übereinstimmen, dann ist A[e]σ = A[e]τ .
Lemma 10.5. Falls σ und τ auf den Variablen von
b übereinstimmen, dann ist B[b]σ = B[b]τ .
var x := e in s end →Hs
let α = new(Adr) in
store(α) := A[e](store ◦ env)
env(x) := α
var x := e in N s end →Nvar x := e in s end
Lemma 10.6. Sei V eine Menge von Variablen, wel- Prozeduraufruf
che die freien Variablen von s umfasst. Falls σ und
H
p(~e; ~z) → procedure p(~
x; ~
y ) beginHs end
τ auf V übereinstimmen und σ −[s]→ σ 0 ,dann gibt es
let ~v = A[~e](store ◦ env) and α
~ = new(Adr) in
ein τ 0 so, dass τ −[s]→ τ 0
und τ und τ 0 auf V
frames := push(frames, hpos, envi)
übereinstimmen.
store(~
α) := ~v
env := {~
x 7→ α
~, ~
y 7→ env(~z)}
10.6 Semantische Äquivalenz von
Programmen
Rückkehr von einem Prozeduraufruf
Definition 10.1. Zwei Anweisungen s1 und s2 sind procedure p(~x; ~y ) beginN s end →
let holdpos, oldenvi = top(frames) in
semantsich äquivalent (geschrieben: s1 ≡ s2 ), falls
frames := pop(frames)
für alle Zustände σ und σ 0 gilt:
σ −[s1 ]→ σ 0
⇔
pos := oldpos
env := oldenv
mode := up
σ −[s2 ]→ σ 0
11 ASM Semantik von
Programmen
11.2 Natürliche Semantik ⇒
ASM-Semantik
Idee: Ein Cursor wandert in kleinen Schritten durch Theorem 11.1. Falls in der natürlichen Semantik
den abstrakten Syntaxbaum des Programms und σ −[s]→ σ 0 herleitbar ist und A ein ASM-Zustand ist
führt dabei Aktionen aus.
mit
9
• A(pos) =Hs
12.2 Instruktionen der VM
(ASM-Semantik)
• σ ⊆ A(store) ◦ A(env)
V M = case code(pc) of
const(i) →
dann erreicht die ASM-Semantik nach endlich vielen
opd:=opd· [i]
Schritten einen Zustand B so, dass
pc:=pc+1
• B(pos) =Ns
load(n) →
opd:=opd· [mem(loc(n))]
• σ 0 ⊆ B(store) ◦ B(env)
pc:=pc+1
loada(n) →
• A(env) ⊆ B(env)
opd:=opd· [loc(n))]
pc:=pc+1
• A(frames) = B(frames)
loadi→
let rest· [α] = opd in
und für alle Adressen α ∈ dom(A(store))\ran(A(env))
opd:= rest· [mem(α))]
gilt
pc:=pc+1
store(n) →
B(store)(α) = A(store)(α) und α 6∈ ran(B(env))
let rest· [v] = opd in
mem(loc(n)):=v
opd:= rest
12 Compilation auf virtuelle
pc:=pc+1
storei→
Maschine
let rest· [α, v] = opd in
mem(α):=v
12.1 Instruktionen der VM (informale
opd:= rest
Beschreibung)
pc:=pc+1
prim(op)
→
const(i)
Lege die Konstante i auf den
let
rest·
[v1 , v2 ] = opd in
Operandenstack.
opd:= rest· [v1 op v2 ]
load(n)
Lade den Wert der nten lokapc:=pc+1
len Variable auf den Operandenstack.
goto(i) → pc := i
loada(n)
Lade die Adresse der nten locond(op, i) →
kalen Variable auf den Opelet rest· [v] = opd in
randenstack.
opd:= rest
loadi
Nimm die Adresse zuoberst
if op(v) then pc := i
auf dem Operandenstack und
else pc:=pc+1
lade den Wert, der an der
invoke(p, n, k) →
Adresse gespeichert ist, auf
let rest· [v1 , . . . , vn ] = opd in
den Operandenstack.
stack:= push(stack,hpc,loci)
store(n)
Speichere den obersten Wert
pc:=
f irst(p)
des Operandenstacks als Wert
opd:= []
der nten lokalen Variablen.
loc:= {1 7→ α1 , . . . , n + k 7→ αn+k }
storei
Nimm den obersten Wert
des Operandenstacks und die
forall i ∈ [1, . . . , n] do mem(αi ) := vi
darunterliegende Adresse und
where α1 , . . . , αn+k = new(Adr, n + k)
speichere den Wert an der
return→
Adresse.
let hpc0 , loc0 i = top( stack) in
prim(op)
Nimm die obersten zwei Werstack:= pop(stack)
te des Operandenstacks und
pc:= pc0 + 1
ersetze sie durch das Resultat
loc:= loc0
der Operation op.
opd:= []
goto(i)
Springe zur iten Instruktion.
cond(op, i)
invoke(p, n, k)
return
Teste mittels op den obersten
Wert des Operandenstacks.
Falls der Test wahr ist, springe zu i.
Rufe die Prozedur p mit n Argumenten und k lokalen Variablen auf.
Kehre zurück zum Prozeduraufruf.
12.3 Compilation der arithmetischen
Ausdrücke
Funktion: CA : Aexp → List(Instr)
Gegeben sei die Anzahl von den lokalen Variablen
10
und eine Zuordnung von Nummern zu lokalen CB1 (b1 or b2 , lab) =
CB1 (b1 , lab)
Variablen und formalen Parametern einer Prozedur.
CB1 (b2 , lab)
Falls x ∈ Var, dann ist x̄ ∈ VarNr.
CB0 (b1 and b2 , lab) =
CB0 (b1 , lab)
CB0 (b2 , lab)
Für lokale Variablen und Werteparameter x
CB0 (b1 or b2 , lab) =
CB1 (b1 , end)
CB0 (b2 , lab)
end :
CA(x) =
load(x̄)
Für Variablenparameter x
CA(x) =
load(x̄)
loadi
12.5 Compilation der Anweisungen
Für Konstanten i
Für lokale Variablen und Werteparameter x
CA(i) =
const(i)
CS(x := e) =
CA(e)
store(x̄)
Funktion CS : Stm → List(Instr)
Für binäre Operatoren op
Für Variablenparameter x
CA(e1 op e2 ) =
CA(e1 )
CA(e2 )
prim(op)
CS(x := e) =
load(x̄)
CA(e)
storei
12.4 Compilation der Boolschen
Ausdrücke
Leere Anweisung
Funktionen CBi : Bexp × Pc → List(Instr)
CS (skip) = []
CB1 (b, lab): Falls b wahr ist, springe zu lab, sonst ans
Ende von b.
CB0 (b, lab): Falls b falsch ist, springe zu lab, sonst ans
Ende von b.
Sequentielle Komposition
CS(s1 ; s2 ) =
CS(s1 )
CS(s2 )
CB1 (e1 op e2 , lab) =
CA(e1 )
CA(e2 )
prim(op)
cond(ne,lab)
If-Anweisung
CS(if b then s1
CB0 (b, else)
CS(s1 )
goto(end)
else : CS(s2 )
end :
CB1 (not b, lab) =
CB0 (b, lab)
CB0 (e1 op e2 , lab) =
CA(e1 )
CA(e2 )
prim(op)
cond(eq,lab)
else
s2
Lokale Variablendeklaration
CS(var x := e
CA(e)
store(x̄)
CS(s)
CB0 (not b, lab) =
CB1 (b, lab)
in
s
end)=
While-Anweisung
CS(while b do s end)=
goto(test)
whl : CS(s)
test : CB1 (b, whl)
CB1 (b1 and b2 , lab) =
CB0 (b1 , end)
CB1 (b2 , lab)
end :
11
end)=
13.3 Natürliche Semantik ⇒ denationelle
Semantik
Prozeduraufruf (p mit k lokalen Variablen)
CS(p(e1 , . . . , em ; z1 , . . . , zn )) =
CA(e1 )
..
.
Theorem 13.1. Falls in der natürlichen Semantik
σ −[s]→ σ 0 herleitbar ist, dann gibt es ein n ∈ N, so
dass in der denationellen Semantik gilt σR[s n]σ 0 .
CA(em )
CV(z1 )
..
.
13.4 Denationelle Semantik ⇒ natürliche
Semantik
CV(zn )
invoke(p, m + n, k)
Theorem 13.2. Falls in der denationellen Semantik
σR[s n]σ 0 gilt, dann ist in der natürlichen Semantik
σ −[s]→ σ 0 herleitbar.
Für lokale Variablen und Werteparameter z
CV(z) =
loada(z̄)
13.5 Wiederholung: Relationen
Definition 13.2. Eine Relation R auf einer Menge
A ist eine Menge von Paaren R ⊆ A × A.
Für Variablenparameter z
CV(z) =
load(z̄)
Definition 13.3. Eine Relation R heisst funktional,
falls für alle x, y, z gilt: Falls hx, yi ∈ R und hx, zi ∈
R, dann ist y = z.
Prozedurdeklaration
Komposition und Identität
CS(procedure p(~x; ~y )
CS(s)
return
begin
s end)=
Zuerst S, dann R.
Definition 13.4. R ◦ S
S und hy, zi ∈ R}
{hx, zi|∃yhx, yi
∈
13 Denationelle Semantik
Definition 13.5 (Identität auf A). IdA
{hx, xi|x ∈ A}
=
13.1 Beschränkte Rekursion
Die Komposition ist assoziativ und IdA ist ein Neutralelement.
Neue Prozedurnamen p n für n ∈ N.
=
Lemma 13.2. Seien R1 , R2 , R3 und R Relationen
auf A. Dann gilt:
Mit p n wird die Prozedur p beschränkt auf die
maximale Rekursionstiefe n bezeichnet.
• R1 ◦ (R2 ◦ R3 ) = (R1 ◦ R2 ) ◦ R3
• IdA ◦ R = R = R ◦ IdA
• Falls die Ausführung des Prozeduraufrufs p n(~e; ~z) zu einer Rekursionstiefe grösser als n
Die Komposition von Relationen ist monoton
führt, terminiert der Aufruf nicht.
bezüglich der Mengeninklusion.
• Die Prozedur p (n + 1) ruft in ihrem Rumpf Lemma 13.3. Falls R1 ⊆ R2 und S1 ⊆ S2 , dann ist
nur Prozeduren q n auf.
R1 ◦ S1 ⊆ R 2 ◦ S2
Die Komposition von Relationen ist distributiv über
der Vereinigung von Relationen.
• Die Ausführung von p 0(~e; ~z) terminiert nie.
Definition 13.1. Für eine Anweisung s bezeichnet Lemma 13.4. Sei (R )
i i∈I eine Familie von Relatioman mit s n die Anweisung, die man aus s erhält, nen. Dann gilt:
indem man alle Prozeduraufrufe p(~e; ~z) durch be- [
[
[
[
schränkte Prozeduraufrufe p n(~e; ~z) ersetzt.
( Ri )◦S =
(Ri ◦S),
S ◦( Ri ) =
(S ◦Ri )
i∈I
13.2 Monotonie
i∈I
i∈I
i∈I
Reflexivität und Transitivität
Was mit kleiner Rekursionstiefe berechnet werden
Definition 13.6. Eine Relation R heisst reflexiv auf
kann, bekommt man auch mit grösserer RekursionsA, falls hx, xi ∈ R für alle x ∈ A.
tiefe.
Definition 13.7. Eine Relation R heisst transitiv
Lemma 13.1 (Monotonie). Falls m ≤ n und auf A, falls für alle x, y, z ∈ A gilt: Falls hx, yi ∈ R
σR[s m]σ 0 , dann gilt auch σR[s n]σ 0
und hy, zi ∈ R, dann ist hx, zi ∈ R.
12
13.7 Die While-Anweisung als kleinster
Fixpunkt
• R ist reflexiv auf A genau dann, wenn IdA ⊆ R.
Lemma 13.5. Sei R eine Relation. Dann gilt:
• R ist transitiv auf A genau dann, wenn R ◦ R ⊆ Definition 13.10. Sei Γ ein Operator von P(M )
nach P(M ).
R.
• X ist ein Fixpunkt von Γ, falls Γ(X) = X.
Potenzen und reflexiv, transitiver Abschluss
Die Potenzen Rn und der reflexiv, transitive Abschluss R∗ .
• X ist der kleinste Fixpunkt von Γ, falls X ein
Fixpunkt von Γ ist und für jeden weiteren Fixpunkt Y von Γ gilt, dass X ⊆ Y .
Definition 13.8. Sei R eine Relation auf A. Dann
definieren wir:
Satz 13.1 (Fixpunktsatz). Für die While[
Anweisung gilt:
0
n+1
n
∗
n
R = IdA ,
R
=R◦R ,
R =
R
n∈N
Lemma 13.6. Für alle m, n ∈ N ist R
Rm+n
m
R[while b do s end] = kleinster Fixpunkt von Γb,s
◦ Rn =
wobei der Operator Γb,s von P(State × State) nach
P(State × State) definiert ist durch
∗
R ist die kleinste reflexiv, transitive Relation die R
umfasst.
Γb,s (X) = (X ◦ R[s] ◦ R[b]) ∪ R[not b]
Lemma 13.7. Sei R eine Relation auf A. Dann gilt:
• R∗ ist reflexiv und transitiv auf A und R ⊆ R∗ .
14 Hoare-Logik
• Falls S eine reflexive und transitive Relation auf
A ist mit R ⊆ S, dann ist R∗ ⊆ S.
Axiomatische, syntaktische
Lemma 13.8. Sei R eine Relation auf A. Dann gilt mit Hoare-Tripel:
R∗ = IdA ∪ (R∗ ◦ R)
Programmverifikation
{ϕ}s{ψ}
Dabei sind ϕ und ψ logische Formeln: Zusicherungen.
Funktionale Relationen
Die Komposition von funktionalen Relationen ist Bedeutung: Falls vor der Ausführung der Anweisung
funktional.
s die Formel ϕ gilt und s terminiert, dann gilt ψ nach
der Ausführung von s.
Lemma 13.9.
• Falls R und S funktional sind, dann ist R ◦ S
funktional.
14.1 Das Beweissystem von Hoare
n
• Falls R funktional ist, dann ist R funktional.
{ϕ}skip{ϕ}
Bemerkung. Wenn R funktional ist, folgt nicht dass
R∗ funktional ist.
Axiom (skip)
{ϕ xe }x := e{ϕ}
13.6 Eigenschaften der denationellen
Semantik
Axiom (:=)
{ϕ}s1 {ψ} {ψ}s2 {χ}
{ϕ}s1 ; s2 {χ}
Definition 13.9. Für Boolsche Ausdrücke b sei
Regel (;)
{ϕ ∧ b}s1 {ψ} {ϕ ∧ ¬b}s2 {ψ}
{ϕ}if b then s1 else s2 end{ψ}
R[b] = {hσ, σi|σ ∈ State, B[b]σ = 1}
Theorem 13.3. Für die denotationelle Semantik
von Programmen gilt:
{ϕ ∧ b}s{ϕ}
{ϕ}while b do s end{ϕ ∧ ¬b}
R[skip] = IdState
R[s1 ; s2 ] = R[s2 ] ◦ R[s1 ]
R[if b then s1 else s2 end] = (R[s1 ]◦R[b])∪(R[s2 ]◦R[not b])
R[while b do s end] = R[not b] ◦ (R[s] ◦ R[b])∗
ϕ → ϕ0
{ϕ0 }s{ψ 0 } ψ 0 → ψ
{ϕ}s{ψ}
Regel (if)
Regel (while)
Abschwächung
Definition 14.1. Wir schreiben ` {ϕ}s{ψ}, falls
{ϕ}s{ψ} in dem erweiterten Beweissystem herleitbar
ist.
Lemma 13.10.
R[if b then s end] = (R[s] ◦ R[b]) ∪ R[not b]
13
Definition 14.3. Wir schreiben `tot {ϕ}s{ψ}, falls
{ϕ}s{ψ} in dem Beweissystem mit neuer Regel für
die While-Schlaufe herleitbar ist.
Ableitbare und zulässige Axiome und Regeln
{ϕ ∧ b}s{ψ} ϕ ∧ ¬b → ψ
{ϕ}if b then s end{ψ}
Definition 14.4. Ein Tripel {ϕ}s{ψ} ist wahr
im Sinne der totalen Korrektheit (geschrieben:
tot {ϕ}s{ψ}), falls für alle Belegungen σ mit
FV(s) ⊆ dom(σ) gilt:
{ϕ}s{true}
{false}s{ϕ}
{ϕ}s{ϕ}
Falls T [ϕ]σ = 1, dann gibt es ein σ 0 ∈ State mit
hσ, σ 0 i ∈ R[s] und T [ψ]σ 0 = 1.
falls FV(ϕ) ∩ AV(s) = ∅
{ϕ1 }s{ψ} {ϕ2 }s{ψ}
{ϕ1 ∨ ϕ2 }s{ψ}
tot {ϕ}s{ψ} bedeutet, dass in jedem Anfanszustand, in dem die Vorbedingung ϕ gilt, die Anweisung s terminiert mit einem Endzustand, in dem die
Nachbedingung ψ gilt.
{ϕ}s{ψ1 } {ϕ}s{ψ2 }
{ϕ}s{ψ1 ∧ ψ2 }
{ϕ}s{ψ}
{∃xϕ}s{ψ}
falls x 6∈ FV(s) ∪ FV(ψ)
14.4 Korrektheit der totalen Hoare-Logik
{ϕ}s{ψ}
{ϕ}s{∀xψ}
falls x 6∈ FV(s) ∪ FV(ϕ)
Theorem 14.2. Falls `tot {ϕ}s{ψ}, dann tot
{ϕ}s{ψ}.
14.5 Erweiterung der Hoare-Logik: Arrays
14.2 Korrektheit der partiellen
Hoare-Logik
Axiom für die Array-Zuweisung
Definition 14.2. Ein Tripel {ϕ}s{ψ} ist wahr
im Sinne der partiellen Korrektheit (geschrieben
{ϕ}s{ψ}), falls für alle Belegungen σ, σ 0 gilt:
e2
}a[e1 ] := e2 {ϕ}
{ϕ a[e
1]
e2
Problem: Wie definiert man die Substitution ϕ a[e
?
1]
Falls T [ϕ]σ = 1 und hσ, σ 0 i ∈ R[s],
dann ist T [ψ]σ 0 = 1.
Einfacher Fall:
Falls das Tripel {ϕ}s{ψ} herleitbar ist im Beweissystem von Hoare, dann ist {ϕ}s{ψ} wahr.
{x < a[j]}a[j + 1] := a[j]{x < a[j + 1]}
| {z }
|
{z
}
ϕ
a[j]
Theorem 14.1. Falls ` {ϕ}s{ψ}, dann {ϕ}s{ψ}.
ϕ a[j+1]
Komplizierter Fall:
14.3 Totale Korrektheit von Programmen
(Terminierung)
{x < (k = j + 1?a[j] : a[k])}a[j + 1] := a[j]{x < a[k]}
| {z }
|
{z
}
ϕ
a[j]
ϕ a[j+1]
Die Regel (while) wird ersetzt durch die folgende
Regel (whiletot ):
Neue Ausdrücke: b ? e1 : e2 [if b then e1 else e2 ]
{ϕ ∧ b}s{ϕ}
{ϕ ∧ b ∧ t = z}s{t < z}
ϕ→0≤t
{ϕ}while b do s end{ϕ ∧ ¬b}
15 Dynamische Logik
15.1 Überblick
Dabei muss gelten z 6∈ FV(ϕ)∪FV(t)∪FV(b)∪FV(s).
Die Variable z wird benutzt um sich den Wert von
t vor Ausführung von s zu merken und ihn mit dem
Wert von t nach s zu vergleichen.
Der Term t ist ein Mass, das bei jedem Durchlauf
echt abnimmt und so die Terminierung der WhileSchlaufe garantiert.
Die Prämisse ϕ → 0 ≤ t stellt sicher, dass das Mass
nicht negativ wird.
Der Term t ist eine obere Schranke für die Anzahl
Durchläufe der While-Schlaufe.
Modale Operatoren
[s] (Box s) und hxi (Diamond s)
Bedeutung der Operatoren
[s]ϕ Falls s terminiert, dann gilt ϕ nach der
Ausführung von s.
hsiϕ Die Anweisung s terminiert und ϕ gilt nach der
Ausführung.
[s]ϕ ↔ ¬hsi¬ϕ
14
16 Bytecode Verification
Verifikationsalgorithmus (top-level Loop)
(Byte)Code Verifikation: Das Programm wird,
wenn es geladen wird, statisch analysiert. Nur Programme, die zur Laufzeit keine Checks der defensiven VM verletzen würden, werden vom Verifikator
akzeptiert. Solche Programme können dann auf der
normalen VM ausgeführt werden.
Verify= while Changed 6= ∅ do
choose i ∈ Changed do
if Check(i, locVi , opdVi ) = True then
Changed := Changed\{i};
for all hj, locT, opdT i ∈ Succ(i, locVi , opdVi ) do
Propagate(j, locT, opdT )
else throw ’’Check violated’’
16.1 Verifikationsalgorithmus (Idee)
Das Propagieren der Typen
Propagate(j, locT, opdT ) =
if j 6∈ V isited then
if ValidCodeIndex(j) then
locVj := locT ; opdVj := opdT ;
Visited := Visited ∪ {j}; Changed := Changed ∪ {j}
else throw ’’Invalid code index’’
elseif locT v locVj and opdT v opdVj then skip
elseif length(opdT ) = length(opdVj ) then
locVj := locVj t locT ;
opdVj := locVj t opdT ;
Changed := Changed ∪ {j}
else throw ’’Propagation not possible’’
Die Prozeduren werden einzeln verifiziert.
Der Verifikator führt die Instruktionen symbolisch
aus und rechnet nur mit Typen, nicht mit Werten.
Definition 16.1. Vars(p) = V alueP arams(p) ∪
V arP arams(p) ∪ Locals(p)
Definition 16.2. ValidCodeIndex(j) ⇔ 0 ≤ j ≤
maxCode(p)
Annahme: Alle Variablenparameter sind Outputparameter, d.h. der Verifikator muss sicherstellen, dass Die Struktur der Verify-Typen
bei einer Return-Instruktion die Variablenparameter
Definition 16.3. Der Typ undef ist der grösste Typ:
sicher einen Wert zugewiesen haben.
σ v τ ⇔ σ = τ ∨ τ = undef
16.2 Verifikation (statischer Teil)
Die kleinste untere Schranke σ t τ von zwei Typen ist
Die folgenden statischen Constraints müssen erfüllt int oder adr(n), falls beide int bzw. adr(n), sonst
sein:
undef.
const(i)
load(n)
loada(n)
store(n)
prim(op)
goto(i)
cond(op, i)
invoke(q, n, k)
i∈Z
n ∈ Vars(p)
n ∈ Vars(p)\V arP arams(p)
n ∈ Vars(p)
op ∈ AddOp ∪ MulOp ∪ RelOp
ValidCodeIndex(i)
op ∈ {eq,ne}, ValidCodeIndex(i)
n = |V alueP arams(q)∪
V arP arams(q)|,
k = |Locals(q)|
Vergleich der Typen von Instruktionen
Definition 16.4. Punktweiser Vergleich der Typen
der Variablen:
locS v locT ⇔ dom(locS) = dom(locT )∧
∀i ∈ dom(locS)(locS(i)) v locT (i))
Definition 16.5. Punktweiser Vergleich der Typen
der Operanden:
16.3 Verifikation (dynamischer Teil)
opdS v opdT ⇔ length(opdS) = length(opdT )∧
Anfangszustand der Verifikation von p
∀i ∈ [1 . . . length(opdS)](opdS(i) v opdT (i))
• Visited = Changed = {0}
Die dynamischen Checks für die Instruktionen
• opdV0 = []
Check(j, locT, opdT ) ⇔ case code(j) of
load(n) → locT (n) 6= undef
loadi → length(opdT ) ≥ 1 ∧ IsAddr(top(opdT, 1))
store(n) → length(opdT ) ≥ 1
storei → length(opdT ) ≥ 2 ∧ IsAddr(top(drop(opdT, 1)))
prim(op) → length(opdT ) ≥ 2 ∧ last(opdT, 2) = [int,int]
Cond(op, i) → length(opdT ) ≥ 1 ∧ top(opdT, 2) = int
invoke(q, n, k) → length(opdT ) ≥ n∧
∀i ∈ V alueP arams(q)(opdT (i) = int)∧
∀i ∈ V alueP arams(q)IsAddr(opdT (i))
return → ∀i ∈ V arP arams(p)(locT (adr(i)) 6= undef)
otherwise → True
• locV0 = init(p)
Die Typen der Variablen zu Beginn von p
init(p)
=
∪
∪
∪
{i 7→ int|i ∈ V alueP arams(p)}
{i 7→ adr(i)|i ∈ V arP arams(p)}
{adr(i) 7→ undef|i ∈ V arP arams(p)}
{i 7→ undef|i ∈ Locals(p)}
15
Die Berechnung der Nachfolger
Succ(pc, locT, opdT ) = case code(pc) of
const(i) → {hpc + 1, locT, opdT · [int]i}
load(n) → {hpc + 1, locT, opdT · [locT (n)]i}
loada(n) → {hpc + 1, locT, opdT · [adr(n)]i}
loadi → {hpc + 1, locT, drop(opdT, 1)· [locT (top(opdT ))]i}
store(n) → {hpc + 1, locT [n 7→ top(opdT )], drop(opdT, 1)i}
storei → {hpc + 1, locT [α 7→ top(opdT )], drop(opdT, 2)i}
where α = top(drop(opdT, 1))
prim(op) → {hpc + 1, locT, drop(opdT, 2)· [int]i}
goto(i) → {hi, locT, opdT i}
Cond(op, i) → {hpc + 1, locT, opdT i, hi, locT, opdT i}
invoke(q, n, k) → {hpc + 1, locT ⊕ out(p, opdT ), []i}
return → ∅
Durch einen Prozeduraufruf mit den Argumenten
opdT werden den Variablenargumenten von opdT (=
die Adressen auf opdT ) Werte zugewiesen.
out(p, opdT ) =
{i 7→ int|adr(i) ∈ opdT, i ∈ V alP arams(p) ∪ Locals(p)}∪
{adr(i) 7→ int|adr(i) ∈ opdT, i ∈ V arP arams(p)}
Das Überschreiben von Bindungen in endlichen Funktionen:
f ⊕ g = {(x 7→ y) ∈ f |x 6∈ dom(g)} ∪ g
16.4 Die defensive VM
Bei der defensiven VM tragen die Werte ihren Typ
mit sich herum.
Die defensive VM benutzt dieselben Checks wie der
Verifikator.
Theorem 16.1. Falls in einem Programm jede Prozedur eine Typisierung ihres Code-Arrays hat, dann
verletzt das Programm keine Checks auf der defensiven VM.
Konklusion: Falls ein Programm vom Verifikator akzeptiert wird, dann ist es sicher auf der normalen
VM.
16
Herunterladen