colleges recursieve datastructuren college 9 prioriteit van operatoren prioriteit in recursive descent parser

Vergelijkbare documenten
templates: het probleem recursieve datastructuren college 10 gebruik template wat zouden we willen templates exceptions type-parameters!

software constructie recursieve datastructuren college 15 5 stappen plan ontwerpen de software bestaat uiteindelijk uit datatypen functies

Modelleren en Programmeren

Overerving & Polymorfisme

compileren & interpreteren - compileren: vertalen (omzetten) - interpreteren: vertolken

Als een PSD selecties bevat, deelt de lijn van het programma zich op met de verschillende antwoorden op het vraagstuk.

Datastructuren Programmeeropdracht 3: Expressies. 1 Expressies. Deadline. Dinsdag 8 december 23:59.

Universiteit van Amsterdam FNWI. Voorbeeld van tussentoets Inleiding programmeren

PYTHON REEKS 1: BASICS. Mathias Polfliet

Practicumopgave 3: SAT-solver

HOOFDSTUK 3. Imperatief programmeren. 3.1 Stapsgewijs programmeren. 3.2 If Then Else. Module 4 Programmeren

Het omzetten van reguliere expressies naar eindige automaten, zie de vakken Fundamentele Informatica 1 en 2.

Semantiek (2IT40) Bas Luttik. HG 7.14 tel.: Hoorcollege 8 (7 juni 2007)

Een topprogrammeur in het OO programmeren is Graig Larman. Hij bedacht de volgende zin:

Logica voor Informatici najaar 2000 Opgaven en Oplossingen Hoofdstuk 3

Modelleren en Programmeren

HOGESCHOOL VAN AMSTERDAM Informatica Opleiding. CPP 1 van 10

Datastructuren: stapels, rijen en binaire bomen

Modelleren en Programmeren

Syntax- (compile), runtime- en logische fouten Binaire operatoren

Vakgroep CW KAHO Sint-Lieven

Modelleren en Programmeren

Datastructuren college 10

Voorbeeldtentamen Inleiding programmeren (IN1608WI), Oktober 2003, , Technische Universiteit Delft, Faculteit EWI, Afdeling 2.

Tentamen Objectgeorienteerd Programmeren IN1205 Voorbeeld

College Notatie, Recursie, Lijsten

Objectgericht programmeren 1.

start -> id (k (f c s) (g s c)) -> k (f c s) (g s c) -> f c s -> s c

Programmeermethoden. Recursie. week 11: november kosterswa/pm/

Een typisch programma in C en C++ bestaat uit een aantal onderdelen:

Uitwerking Aanvullend tentamen Imperatief programmeren Woensdag 24 december 2014, uur

Tentamen Object Georiënteerd Programmeren TI januari 2013, Afdeling SCT, Faculteit EWI, TU Delft

Programmeren in Java les 3

Deeltentamen Grammatica s en ontleden 22 december 2005

Tentamen Imperatief en Object-georiënteerd programmeren in Java voor CKI

Aanvullende toets Gameprogrammeren (INFOB1GP) Woensdag 24 december 2014, uur

Recursive-Descent Parsing

Logica voor Informatica

Tentamen Objectgeorienteerd Programmeren TI februari Afdeling ST Faculteit EWI TU Delft

Datastructuren: stapels, rijen en binaire bomen

Let op dat de scoping regels gerespecteerd blijven; het volgende voorbeeld mag geen fout melden.

Programmeermethoden. Pointers. Walter Kosters. week 10: november kosterswa/pm/

Modelleren en Programmeren: Prolog

Variabelen en statements in ActionScript

Modelleren en Programmeren

Kwis (3) class X { public void a() { System.out.println("x"); public static void main(string[] args) { X x = new X();

Modelleren en Programmeren

OEFENINGEN PYTHON REEKS 1

College Introductie

Datastructuren Programmeeropdracht 2: Expressies. 1 Expressies. Deadlines. Woensdag 12 oktober 23:59, resp. woensdag 2 november 23:59.

Algoritmen en Datastructuren 1. Functies

Verzamelingen, Lijsten, Functioneel Programmeren

Zelftest Inleiding Programmeren

Datatypes Een datatype is de sort van van een waarde van een variabele, veel gebruikte datatypes zijn: String, int, Bool, char en double.

recursie Hoofdstuk 5 Studeeraanwijzingen De studielast van deze leereenheid bedraagt circa 6 uur. Terminologie

voegtoe: eerst methode bevat gebruiken, alleen toevoegen als bevat() false is

Een eenvoudig algoritme om permutaties te genereren

Programmeren met Arduino-software

OEFENINGEN PYTHON REEKS 1

De Leidsche Flesch Studievereniging voor Natuurkunde, Sterrenkunde, Wiskunde en Informatica sinds DLF Pointerworkshop

Tweede college algoritmiek. 12 februari Grafen en bomen

ALGORITMIEK: antwoorden werkcollege 5

Succes! Theo DʼHondt 13 juni 2010

Tentamen Kunstmatige Intelligentie (INFOB2KI)

Programmeermethoden. Functies vervolg. Walter Kosters. week 5: 1 5 oktober kosterswa/pm/

Lab Webdesign: Javascript 3 maart 2008

Kleine cursus PHP5. Auteur: Raymond Moesker

APPLICATIEBOUW 3E COLLEGE: OBJECT GEORIËNTEERD PROGRAMMEREN, METHODEN, PARAMETERS, SCOPE VAN VARIABELEN. Onderdeel van SmartProducts

Verzamelingen, Lijsten, Functioneel Programmeren

Compilers.

Programmeren 1 20 januari 2012 Prof. T. Schrijvers

Compilers (2IC25) docent: G. Zwaan, HG 5.41, tel. ( )4291, webpagina:

1 Inleiding in Functioneel Programmeren

Hoofdstuk 1: Inleiding. Hoofdstuk 2: Klassen en objecten Datahiding: afschermen van implementatiedetails. Naar de buitenwereld toe enkel interfaces.

Haskell: programmeren in een luie, puur functionele taal

REEKS I. Zaterdag 6 november 2010, 9u

Java Programma structuur

Tentamen Compilers (2IC25) 21 juni 2010, 9.00u-12.00u

ALGORITMIEK: antwoorden werkcollege 5

ALGORITMIEK: antwoorden werkcollege 5

Beginselen van programmeren Practicum 1 (Doolhof) : Oplossing

17 Operaties op bits Bitoperatoren en bitexpressies

Verzamelingen, Lijsten, Functioneel Programmeren

Tentamen Compilers (2M220) 19 maart 2002, 9.00u-12.00u

Samenvatting hst. 3 sec. 1-3

Programmeermethoden. Recursie. Walter Kosters. week 11: november kosterswa/pm/

inleiding theoretische informatica practicum 1 deadline woensdag 20 februari 2008 om uur

Elementary Data Structures 3

9 Meer over datatypen


Programmeermethoden NA. Week 5: Functies (vervolg)

Reguliere talen: overzicht

oefening JavaScript - antwoorden

Inhoud leereenheid 4. Inleiding JavaScript. Introductie 99. Leerkern 100. Zelftoets 108. Terugkoppeling 109

INFORMATICA 1STE BACHELOR IN DE INGENIEURSWETENSCAPPEN

Ingebouwde klassen & methodes

Javascript oefenblad 1

Python. Vraag 1: Expressies en types. Vraag 1 b: Types -Ingebouwde functies- Vraag 1 a 3/10/14

Tentamen Imperatief Programmeren

Wat is FP? The Haskell School of Expression. Functies. Types 1+1=2. Iedere expressie (en waarde) heeft een type.

Transcriptie:

colleges recursieve datastructuren college 9 interpreteren: waarde van bomen bepalen transformeren: vorm van bomen veranderen parseren herkennen van expressie in de tekst herkennen van functies onderwerp van vorig college onderwerpen van dit college interpreteren waarde van expressie berekenen voor gegeven x en y transformeren de expressies zelf veranderen 1 2 prioriteit in recursive descent parser prioriteit van operatoren versleutel de prioriteit in de syntax b.v.: expr = term + expr term term = fact * term fact fact = var int ( expr ) var ( args ) args = ε arg2 arg2 = expr expr, arg2 kun je hier met look ahead 1 steeds de juiste keuze maken? gaat dit ook goed als je operator toevoegt? los dit op in de regels van de grammatica i.p.v. E -> E * E E + E ( E ) num schrijven we E -> E + T T T -> T * F F F -> ( E ) num helaas is dit weer linksrecursief, maar we weten hoe we dit moeten aanpakken let ook op bindingsrichting 3 3 2 1 = ( 3 2 ) 1 = 0 maar 3 ( 2 1 ) = 3 1 = 2 voor sommige operatoren is dit geen probleem 4 1

parser voor factor Knoop* parsef () E -> E + T T T -> T * F F Knoop* n = scanner. token (); F -> num switch ( n -> id ) case Int: scanner. volgendetoken (); return n; case Einde: return n; default: Error ( "parse error: integer, of einde verwacht" ); return n; 5 parser voor term Knoop* parset ( ) Knoop* f = parsef ( ); Knoop* o = scanner.token ( ); switch ( o -> id ) case Op: if ( o -> soort[0] == '*') o -> child ( 0 ) = f; scanner. volgendetoken (); o -> child ( 1 ) = parset ( ); return o; else return f; case Einde: return f; default: Error ( "parse error: * of einde verwacht" ); return f; E -> E + T T T -> T * F F F -> num E -> T (+ E)? T -> F (* T)? F -> num hoewel het een operator is, kunnen we o->op niet gebruiken 6 parser voor expressie Knoop* parsee ( ) Knoop* t = parset ( ); Knoop* o = scanner.token ( ); switch ( o -> id ) case Op: if ( o -> soort[0] == '+' ) o -> child ( 0 ) = t; scanner. volgendetoken ( ); o -> child ( 1 ) = parsee ( ); return o; else return t; case Einde: return t; default: Error ( "parse error: + of einde verwacht" ); return t; E -> E + T T T -> T * F F F -> num E -> T (+ E)? T -> F (* T)? F -> num 7 statische tests je kunt niet alles met een parser voor een CFG controleren wat kun je nog meer controleren? hele input gelezen operatoren zijn bekend variabelen zijn bekend functies zijn bekend operatoren hebben juiste aantal argumenten functies hebben juiste aantal argumenten types? 8 2

syntax sequents ϕ 1 ϕ n o ψ 1 ψ m met ϕ i en ψ j logische formules bedenk een handig symbool voor o, dat niet botst met namen van variabelen en operatoren ϕ, ψ = p, p, p q, p q, p q, p q, (p) ook hier hoort volgens de standaard interpretatie een prioriteit bij operatoren bindt sterker dan en : p q = ( p) q sterker dan : p q r = (p q) r (volg de standaard logica regels) het is handig als variabelen namen langer dan 1 letter mogen zijn twee aanpakken 1: interpretatie expressies evalueren we beperken ons tot interpretatie pak direct de syntax boom en bepaal waarde expressies relatief eenvoudig, maar niet erg efficient geen aparte compilatie nodig 2: vertalen (compileren) genereer code die waarde expressie bepaalt ingewikkelder, maar circa 10 keer sneller dan interpretatie er bestaan ook mengvormen b.v. Java byte-code of.net genereer hoog niveau code (platform onafhankelijk) interpreteer die code 9 10 interpretatie basis: denotationele semantiek geeft betekenis aan expressies ingrediënten: syntax operatie pattern-match op syntax Scott brackets: geeft match op syntax aan E [[ a 1 + a 2 ]] = E [[ a 1 ]] + E [[ a 2 ]] E [[ a 1 * a 2 ]] = E [[ a 1 ]] * E [[ a 2 ]] E [[ n ]] = n voor getallen functie die binding van variabelen kent state :: Var -> Int we nemen altijd aan dat het een juiste boom is: bindingen kloppen 11 binding van variabelen wiskundig: state is functie van variabelen naar waarde state :: Var -> Int b.v. s = x 1, y 2 dan s x = 1 en s y = 2 mooi voor semantische regeltjes lastig te maken in C++ maak een datastructuur voeg wat functies toe 12 3

syntax n numeral x variable a expression a = n x a 1 + a 2 a 1 * a 2 semantiek basis semantiek A [[ a 1 + a 2 ]] s = A [[ a 1 ]] s + A [[ a 2 ]] s A [[ a 1 * a 2 ]] s = A [[ a 1 ]] s * A [[ a 2 ]] s A [[ n ]] s = n A [[ x ]] s = s x voorbeeld met s = x 1, y 2 A [[ x + 3 ]] s = A [[ x ]] s + A [[ 3 ]] s = s x + 3 = 1 + 3 getal = 4 syntax context geeft verschil aan 13 syntax booleans b = True False a 1 == a 2 a 1 < a 2 b 1 /\ b 2 semantiek B [[ True ]] s B [[ False ]] s B [[ a 1 == a 2 ]] s B [[ a 1 < a 2 ]] s B [[ b 1 /\ b 2 ]] s syntax = true echte vergelijking = false syntax = A [[ a 1 ]] s == A [[ a 2 ]] s = A [[ a 1 ]] s < A [[ a 2 ]] s = if ( B [[ b 1 ]] s ) B [[ b 2 ]] s else false voorbeeld met s = x 1, y 2 logische waarde luiheid zit hier ingebakken B [[ x + 3 < y ]] s = A [[ x + 3 ]] s < A [[ y ]] s = A [[ x ]] s + A [[ 3 ]] s < s y = s x + 3 < 2 = 1 + 3 < 2 = 4 < 2 = false 14 expressies we hebben dus 2 semantische functies A [[ a ]] s levert een getal B [[ b ]] s levert een logische waarde hoe implementeren we dat? twee aparte evaluatie functies één functie met getypeerd resultaat gebruik de C-truc: 0 false, 1 true alle methoden hebben voor- en nadelen kies wat in gegeven situatie het beste past implementatie context in moderne talen kan dat direct in C++ is het handiger A [[ x ]] s = s x te vervangen door A [[ x ]] s = lookup x s ook het binden van een variabele doen we met een functie 15 16 4

context in C++ maak een lijst van bindingen class ENV public: char * naam; int val; ENV * next; met deze expressies geen update nodig ENV ( char s [], int n, ENV* p = NULL ) : val ( n ), next ( p ) naam = new char [ strlen ( s )+1 ]; strcpy ( naam, s ); ; context in C++ 2 int lookup ( ENV* env, char s [] ) had de checker if ( env == NULL ) moeten zien Error ( "Naam niet gevonden" ); else if ( strcmp ( s, env->naam ) == 0 ) return env -> val; else return lookup ( env -> next, s ); ENV*& bind ( char s [], int n, ENV* e ) return e = new ENV ( s, n, e ); 17 18 implementatie A [[ a ]] s minstens 3 mogelijkheden: overloaded functies functie die gevalsonderscheid doet methode eval bij knopen we zullen de mogelijkheden verder bekijken 19 A [[ a ]] s met overloaded functie int eval ( Getal * g ) return g->waarde ( ); int eval ( Operator *o ) int x = eval ( o -> child ( 0 )); int y = eval ( o -> child ( 1 )); switch ( o->op ) case '+': return x+y; case '*': return x*y; compiler wil hier statisch de juiste kiezen, maar dat kan niet dynamic binding bij methoden had de parser moeten zien default: Error ( "Onbekende operator in eval" ); 20 5

A [[ a ]] s met gevalsonderscheid int eval ( Knoop *k ) switch ( k -> id ) case Num: return k -> waarde ( ); case Op: switch ( k -> op ) case '+': int x = eval ( k -> child ( 0 )); int y = eval ( k -> child ( 1 )); return x+y; case '*': compiler ziet niet dat dit goed gaat, mag dus niet default: Error ( "Onbekende operator in eval" ); 21 A [[ a ]] s met gevalsonderscheid 2 int eval ( Knoop *k ) switch ( k -> id ) case Op: Operator * o = static_cast <Operator*> ( k ); switch ( o -> op ) case '+': int x = eval ( o -> child ( 0 )); int y = eval ( o -> child ( 1 )); return x+y; case '*': expliciete type conversie nu kan dit wel je kunt alles naar alles casten, foutgevoelig default: Error ( "Onbekende operator in eval" ); 22 class Knoop protected: Knoop** children; int stap; char * soort; public: KnoopType id; int arity; A [[ a ]] s met methode eval alleen als er variabelen zijn Knoop (.) : arity ( a ), stap ( 3 ), id ( kt ) virtual int eval ( ENV* e ) Error ( "Kan de basisklasse Knoop niet evalueren" ); ; nieuwe methode eval getal class Getal : public Knoop int w; public: Getal ( int n ) : w ( n ), Knoop ( "Getal", Int, 0 ) int waarde ( ) return w; int eval ( ENV* e ) return w; ; nieuwe methode 23 24 6

int Var :: eval ( ENV* e ) if ( arity==0 ) return lookup ( e, name ); else Error ( ) ; pas op: eval variabele met argumenten is het een functie had de checker moeten zien eigenlijk moet je verschil maken tussen x + 1 x () + 1 functies en variabelen kunnen eigenlijk dus niet zo maar in zelfde klasse eval operator int Operator :: eval ( ENV* e ) int x = child ( 0 ) -> eval ( e ); int y = child ( 1 ) -> eval ( e ); switch ( op ) case '+': return x+y; case '*': return x*y; default: Error ( "Onbekende operator in eval" ); had de checker moeten zien 25 26 syntax keuze n numeral x variable a expression a = n x a 1 + a 2 a 1 * a 2 if b then a 1 else a 2 semantiek A [[ a 1 + a 2 ]] s = A [[ a 1 ]] s + A [[ a 2 ]] s A [[ a 1 * a 2 ]] s = A [[ a 1 ]] s * A [[ a 2 ]] s A [[ n ]] s = n A [[ x ]] s = s x A [[ if b then a 1 else a 2 ]] s = if ( B [[ b ]] s ) A [[ a 1 ]] s A [[ a 2 ]] s zorg dat A 1 of A 2 wordt geëvalueerd moet het zo? door het aannemen van een bovengrens voor aantal variabelen wordt de implementatie iets eenvoudiger rij i.p.v. lijst lijsten mogen echter geen probleem meer zijn 27 28 7

moet het echt zo? transformaties kunnen we niet zonder environment? idee: vervang alle variabelen door waarde in boom uitrekenen kan zonder environment nadelen je moet ook kopie van expressie maken voor substitutie heb je toch een environment nodig werkt zo iets ook bij functies? ook hier bedenken we eerst wat we willen bijvoorbeeld optimalisatie: T [[ 0 + x ]] = T [[ x ]] T [[ x + 0 ]] = T [[ x ]] T [[ 0 * x ]] = T [[ 0 ]] T [[ x * 0 ]] = T [[ 0 ]] T [[ 1 * x ]] = T [[ x ]] T [[ x * 1 ]] = T [[ x ]] T [[ n * m ]] = n * m T [[ n + m ]] = n + m simpele wiskunde regeltjes wat als die recursief zijn? 29 geen environment nodig 30 implementatie mogelijkheden nieuwe methoden Knoop overloaded functie kan niet, want je kunt niet statisch de juiste kiezen gevalsonderscheid daarvoor heeft Knoop een enum KnoopType Int, Op,.. ; er zijn dan type_casts nodig, niet leuk nieuwe methode toevoegen dynamic binding gebruiken vaak de mooiste oplossing we hoeven alleen te weten of een Knoop een getal is, indien dat zo is willen we ook de waarde 31 class Knoop.. public: virtual bool waarde ( int& v) return false; virtual void opti ( Knoop *& root ); ; waarom die? T [[ 0 + x ]] = T [[ x ]] T [[ x + 0 ]] = T [[ x ]] T [[ 0 * x ]] = T [[ 0 ]] T [[ x * 0 ]] = T [[ 0 ]] T [[ 1 * x ]] = T [[ x ]] T [[ x * 1 ]] = T [[ x ]] T [[ n * m ]] = n * m T [[ n + m ]] = n + m 32 8

waarde voor getallen class Getal : public Knoop int w; public: bool waarde ( int & v ) v = w; return true; ; voor alle andere knopen voldoet de default dit moet bottum-up: optimalisatie knopen void Knoop :: opti (Knoop *& root) for ( int i=0; i<arity; i+=1 ) child ( i ) -> opti ( child ( i )); maf, maar nodig als er voor deze knoop niets speciaals te doen is, optimaliseer dan in ieder geval de kinderen 33 34 optimalisatie operatoren void Operator :: opti ( Knoop *& root ) for ( int i=0; i<arity; i+=1 ) child ( i ) -> opti ( child ( i )); int x, y; if ( child ( 0 ) -> waarde ( x )) if ( child ( 1 ) -> waarde ( y )) switch (op).. case '+': root = new Getal ( x + y ); return; case '*': root = new Getal ( x * y ); return; default: return; root nodig eigenlijk delete nodig bottum up 2 getallen, reken uit T [[ 0 + x ]] = T [[ x ]] T [[ x + 0 ]] = T [[ x ]] T [[ 0 * x ]] = T [[ 0 ]] T [[ x * 0 ]] = T [[ 0 ]] T [[ 1 * x ]] = T [[ x ]] T [[ x * 1 ]] = T [[ x ]] T [[ n * m ]] = n * m T [[ n + m ]] = n + m 35 optimalisatie operatoren 2 else // x is getal, y niet switch ( op ) case '+': if ( x == 0 ) root = child ( 1 ); return; case '*': switch ( x ) case 0: root = new Getal ( 0 ); return; case 1: root = child ( 1 ); return; default: return; default: return;.. 1 * x 0 + x 0 * x T [[ 0 + x ]] = T [[ x ]] T [[ x + 0 ]] = T [[ x ]] T [[ 0 * x ]] = T [[ 0 ]] T [[ x * 0 ]] = T [[ 0 ]] T [[ 1 * x ]] = T [[ x ]] T [[ x * 1 ]] = T [[ x ]] T [[ n * m ]] = n * m T [[ n + m ]] = n + m 36 9

voorbeeld optimalisatie resultaat optimalisatie int main ( ) invoer = new stringinvoer ( "1*x*1 + 3* ( 0*tmp + 4 )" ); scanner. volgendetoken ( ); Knoop* k = parsee ( ); k -> drukaf ( ); k -> opti ( k ); cout << "---- optimized ----\n"; k -> drukaf ( ); system("pause"); return EXIT_SUCCESS; 37 1*x*1 + 3* ( 0*tmp + 4 ) ---------------------- 4 + tmp * 0 * 3 + 1 * x * 1 ---- optimized ---- 12 + x vindt dit alles? T [[ 0 + x ]] = T [[ x ]] T [[ x + 0 ]] = T [[ x ]] T [[ 0 * x ]] = T [[ 0 ]] T [[ x * 0 ]] = T [[ 0 ]] T [[ 1 * x ]] = T [[ x ]] T [[ x * 1 ]] = T [[ x ]] T [[ n * m ]] = n * m T [[ n + m ]] = n + m 38 gevalsonderscheid subtypen het helpt om een attribuut in de klasse te stoppen dat het (sub)type aangeeft om hier echt gebruik van te maken heb je vaak een type_cast nodig, niet zo mooi dus overloaded functies werken meestal niet goed te gebruiken regel wordt statisch bepaald een extra methode is meestal de beste oplossing maak de methode virtual geef nieuwe implementatie als er iets speciaals moet gebeuren in die subklasse zou ook het probleem met operator namen beter oplossen dan soort[0] semantiek algemeen assignments: pas waarde van variabele in environment aan evaluatie levert dus waarde + nieuwe environment C++ is lastig omdat environment kan veranderen tijdens evaluatie globale objecten: zitten ook in de environment moeten er weer uitgehaald worden als de scope stopt andere vormen van semantiek: behalve deze denotationele semantiek zijn er nog vele anderen: operational, natural, axiomatic, maken redeneren over programma's mogelijk 39 40 10

herschrijven voor sequents gebruik de gegeven regeltjes regeltjes veranderen expressie i.t.t. de interpretatie van numerieke expressies besluit of je de afleidingsboom wil bouwen of niet je kunt strategie kiezen eerst een kant alles herschrijven probeer regels in de gegeven volgorde bedenk iets slims onthouden waar je bent pointer bewerkte deel bevat alleen variabelen, die kun je ook speciaal bewaren weet waar je aan begint kopieren van expressies zelfs als je geen boom bouwt moet je sequents kopieren b.v. Φ ο α β, Ψ R : Φ ο α, Ψ Φ ο β, Ψ maak een goede copy operator vergeet niet te veranderen wat nodig is bedenk hoe je de te evalueren sequents beheert bedenk hoe je resultaten combineert 41 42 denotationele semantiek sequents ook hier kun je semantiekregeltjes opstellen geven transformaties + strategie gebruik verzameling variabelen als environment strategie: b.v. maak eerst linkerkant leeg door volgorde van semantische regels S [[ ϕ, Φ ο Ψ ]] e = S [[ Φ ο ϕ, Ψ ]] e S [[ α β, Φ ο Ψ ]] e = S [[ α, Φ ο Ψ ]] e S [[ β, Φ ο Ψ ]] e S [[ v, Φ ο Ψ ]] e = S [[ Φ ο Ψ ]] ( e v ) S [[ ο ϕ, Ψ ]] e = S [[ ϕ ο Ψ ]] e S [[ ο α β, Ψ ]] e = S [[ ο α, Ψ ]] e S [[ ο β, Ψ ]] e S [[ ο v, Ψ ]] e = Closed, if v e 43 terminatie van het herschrijven we hoeven niet altijd het hele tableau uit te werken bij zelfde variabele links en rechts is sequent gesloten bij één tegenvoorbeeld is de bewering al ongeldig bewering is gesloten als alle sequents gesloten zijn 44 11

correctheid wanneer is je implementatie correct? als hij voor alle mogelijke sequents het goede antwoord geeft hoe kun je dat nagaan? kijk naar de code voor alle regeltjes test de juiste implementatie met minstens 1 voorbeeld test open en gesloten tableaus gebruik b.v. unittest voor het uitvoeren van deze tests volgende week toets over lijsten en bomen telt als 2 practicumopgaven gesloten boek pen en papier individueel opgave mag een week later ingeleverd worden Sjaak Smetsers geeft college 45 46 wat hebben we gedaan interpreteren basis is semantiek + goede parse tree nauwelijks of niet in boek en dictaat veel literatuur over imperatief: www.daimi.au.dk/~hrn heel T3 gaat over semantiek in vertalerbouw maak je een programma dat code genereert die expressies evalueert 47 12