Föreläsning [14.. 15] i programmeringsparadigm. Jag har ju delat ut Lite grann om syntax, semantik och syntaxanalys. Några ex finns på Nadas kursexpedidition. Labben "Danska räkneord" ska göras med en syntaxanlysator skriven med någon av de metoder som finns i häftet. Du kan välja mellan: Vårt parser-språk (byggt på Haskell, kapitel 2, sid 12). Hjälp på filen /info/progp05/parser.hs DCG (byggt på Prolog, kapitel 5 sid 35, Brna Chapter 8, p 78) "Imperativ Haskell" (kapitel 4, sid 30). Hjälp på filen /info/progp05/imphaskellparser.hs Java. (kapitel 3, sid 22) Hjälp på filen /info/progp05/terminallist.java Om multiparadigm-språket OZ och en tjock bok. Peter van Roy, Seif Haridi : Concepts, Techniques, and Models of Computer Programming: Denna ny bok är grandiost försök att i ett språk (Oz, dock kort om Haskell, Erlang, Java och Prolog) och i en bok och samanhängande förklara alla sorters programmering ("paradigm", ett begrepp som författarna delvis är kritiska mot.). Mycket om jämlöpande programmering (concurrency).tänkbar kursbok om denna kurs var på ca 8 p. Alla programmeringssätt i nedanstående bild programmeras med Oz och förklaras med att man börjar med ett liten "kärnspråksdel" av Oz som beggs ut på olika sätt. Relations programmering Logikprogrammering Prolog Funktion. prog namn = värde Haskell Deklarativa modellen namn = writeonce-variabler Explicit State Tillstånd, dvs "vanliga" programmeringsvariabler Objektinriktad programmering OO Java Declarative concurrency väntan/skrivning på namn = writeonce-variabler Message-passing concurrency Erlang Shared State concurrency, dvs "vanlig" reaktiv programmering
Ett Haskell-verktyg för syntaxanalys utan semantik. På sidorna [13..15] beskrivs verktyget, som finns på /info/progp05/parsernosemantics. En sammanfattning : module ParserNoSemantics where -- at /info/progp05/parsernosemantics -- Our Domain Specific Language (>>>) ::(a -> b) -> (b -> c) -> a -> c (>>>) parser1 parser2 = parser2. parser1 parser1 >>> parser2 accept :: (a -> Bool) -> [a] -> [a] accept p [] = error (" Error, end of code") accept p (c:cs) p c = cs otherwise = error (" Error " ) pass :: [a] -> [a] pass [] = error (" Error, end of code") pass (c:cs) = cs p test accept p pass --- skriv namnet på icke-slutsymbolen ( ) (p, parser1) parser2 (c:cs) p c = parser1 (c:cs) otherwise = parser2 (c:cs) ( ) (c1, p1) p2 [] = [] infixr 5 p test parser1 parser2 empty :: [a] -> [a] empty cs = cs -- error skall vara något av tidigare alternativ, men möjligt att detta inte är fallet
Ett exempel: Syntaxkontroll av aritmetiska uttryck (mindre komplettering av vad som står på sidan 15 i syntaxhäftet) : module CalculatorNoSemantics where import ParserNoSemantics type Tokentype = Char -- at /info/progp05/ expr, moreterms, term, morefactors, factor, number, digit, moredigits :: [Tokentype] -> [Tokentype] expr = term >>> moreterms moreterms = ((== + ), pass >>> term >>> moreterms) ((== - ), pass >>> term >>> moreterms) empty term = factor >>> morefactors morefactors = ((== * ), pass >>> factor >>> morefactors) ((== / ), pass >>> factor >>> morefactors) empty factor = (isdigit, number) ((== ( ), pass >>> expr >>> accept (== ) ) ) error ("Can not find factor ") number = digit >>> moredigits digit = (isdigit, pass) error ("Expecting digit, found ") moredigits = (isdigit, digit >>> moredigits ) empty {- Körningar : Calculator> expr "3*12" "" Calculator> expr "(3+124)*5" "" Calculator> expr "(3+-12*/*4)+5" Program error: Can not find factor -} Lägg märke till likhet mellan skripet och BNF-grammatiken (häftet sid 7 med nummer som ickeslutsymbol på sid 11 ). Hur vi går omkring i parse-trädet vid analys av term "3*12". term "3*12" factor morefactors "12" number * factor morefactors digit moredigits number ε "*12" ε 3 digit moredigits "2" digit moredigits 1 "" 2 ε Argumenten till funktionerna utskrivna i fetstil varje gång de förnyas. T ex är "3*12" argument till term, factor, number och digit i början men digit "strippar" 3 så att argumentet till moredigts "*12"
Ytterligare ett exempel: Syntaxkontroll av Brnas engelska minispråk: module EngelskaNOSematics where -- at /info/progp05/engelskanosematics -- English sentance Brna : 78 <= page <= 85 import ParserNoSemantics type Tokentype = String sentence, nounphrase, verbphrase, determiner, noun, verb :: [Tokentype] -> [Tokentype] sentence = nounphrase >>> verbphrase nounphrase = determiner >>> noun verbphrase = verb >>> nounphrase determiner = ((=="a"), pass) ((=="the"), pass) error "Expecting determiner" noun = ((=="man"), pass) ((=="cake"), pass) error "Expecting noun" verb = ((=="ate"), pass) error "Expecting verb" {- Körningar : Engelska> sentence (words "the man ate a cake") -- Haskellfunktionen [] -- words :: String -> [String] Engelska> sentence (words "the cake ate a cake") -- finns i Prelude [] -- och delar upp sentence (words "man the a cake ate") -- strängar i ord. Program error: Expecting determiner -} Haskell-verktyget för syntaxanalys med semantik. Sidorna [16..17] i syntaxhäftet + parse på sid 19. Finns på /info/progp05/parser. Den som gör laborationen "Danska räknord" med Haskellverktyget importerar lämpligen denna fil. Genom att lägga till semantik till uttryckssyntaxen, se sid 17 i häfte, får vi en räknedosa för artimetiska uttryck. I filen finns också en funktion parse som gör att vi istället för att köra term ("3*12", []) och få resultatet ("", [36]) kan köra parse term "3*12" och få resultatet 36.
Hur vi går omkring i parse-trädet vid analys av term ("3*12", []). ("3*12",[]) factor term morefactors Argumenten till funktionerna utskrivna i fetstil varje gång de förnyas. number pass morefactors * factor pop2do * ε ("12", [1]) ("",[36]) digit number moredigits digit moredigits ε digit pop2do (\p->\d->10*2+d) moredigits ("*12",[1]) ("2",[1,3]) ("",[2, 1, 3]) ("",[12, 3]) ε passdo digittoint passdo digittoint passdo digittoint 3 1 2 Reduktionerna utskrivna, låt f = (\p ->\d ->10*p+d): (reservation för fel). term ( "3*12", []) factor ( "3*12", []) >>> morefactors number( "3*12", []) >>> morefactors digit( "3*12", []) >>> moredigits >>> morefactors passdo digittoint ("3*12", []) >>> moredigits >>> morefactors moredigits( "*12", [3]) >>> morefactors empty( "*12", [3]) >>> morefactors morefactors("*12", [3]) pass ("*12", [3]) >>> factor >>> pop2do (*)>>> morefactors factor ( "12", [3]) >>> pop2do (*) >>> morefactors number( "12", [3]) >>> pop2do (*) >>> morefactors digit ( "12", [3]) >>> moredigits >>> pop2do (*) >>> morefactors passdo digittoint( "12", [3]) >>>moredigits>>>pop2do(*)>>>morefactors moredigits ( "2", [1, 3]) >>> pop2do (*) >>> morefactors digit ( "2", [1, 3]) >>> pop2do f >>> moredigits >>> pop2do (*) >>>.. passdo( "2", [1, 3]) >>> pop2do f >>> moredigits >>> pop2do (*) >>>.. pop2do f ( "", [2, 1, 3]) >>> moredigits >>> pop2do(*)>>> morefactors moredigits( "", [12, 3]) >>> pop2do(*)>>> morefactors empty( "", [12, 3]) >>> pop2do(*)>>> morefactors pop2do(*)( "", [12,3]) >>> morefactors morefactors( "", [36])... ( "", [36]) För att kunna läsa exemplet nedan skall man observera att factor (3*12, []) >>> morefactors enligt definitionen av >>> är samma sak som morefactors( factor (3*12, []) ) Exempel på en reduktion av listan "2*10*3", finns i häftet.
Syntaxanalys med Prolog. Syntaxhäftet kapitel 5 sid 35 och Brna Chapter 8 sid 78. DCG utan semantik Ett exempel; Brnas engelska minispråk. Brna (sid 82) definierar sentence med denna DCG-grammatik (på /info/progp05/expr.pl): sentence --> nounphrase, verbphrase. nounphrase --> determiner, noun. verbphrase --> verb, nounphrase. determiner --> [a]. determiner --> [the]. noun --> [man]. noun --> [cake]. verb --> [ate]. En körning av sentence([the, man, ate, a, cake], []). Resultat om man har aktiverat trace:?- trace. % The debugger will first creep -- showing everything (trace) % trace,source_info?- sentence([the, man, ate, a, cake], []). 1 1 Call: sentence([the,man,ate,a,cake],[])? 2 2 Call: nounphrase([the,man,ate,a,cake],_1068)? 3 3 Call: determiner([the,man,ate,a,cake],_1500)? 4 4 Call: C ([the,man,ate,a,cake],a,_1500)? 4 4 Fail: C ([the,man,ate,a,cake],a,_1500)? 5 4 Call: C ([the,man,ate,a,cake],the,_1500)? 5 4 Exit: C ([the,man,ate,a,cake],the,[man,ate,a,cake])? 3 3 Exit: determiner([the,man,ate,a,cake],[man,ate,a,cake])? % 2) 6 3 Call: noun([man,ate,a,cake],_1068)? 7 4 Call: C ([man,ate,a,cake],man,_1068)? 7 4 Exit: C ([man,ate,a,cake],man,[ate,a,cake])? 6 3 Exit: noun([man,ate,a,cake],[ate,a,cake])? 2 2 Exit: nounphrase([the,man,ate,a,cake],[ate,a,cake])? % 1) 8 2 Call: verbphrase([ate,a,cake],[])? 9 3 Call: verb([ate,a,cake],_5628)? 10 4 Call: C ([ate,a,cake],ate,_5628)? 10 4 Exit: C ([ate,a,cake],ate,[a,cake])? 9 3 Exit: verb([ate,a,cake],[a,cake])? 11 3 Call: nounphrase([a,cake],[])? 12 4 Call: determiner([a,cake],_7704)? 13 5 Call: C ([a,cake],a,_7704)? 13 5 Exit: C ([a,cake],a,[cake])? 12 4 Exit: determiner([a,cake],[cake])? 14 4 Call: noun([cake],[])? 15 5 Call: C ([cake],man,[])? 15 5 Fail: C ([cake],man,[])? 16 5 Call: C ([cake],cake,[])? 16 5 Exit: C ([cake],cake,[])? 14 4 Exit: noun([cake],[])? 11 3 Exit: nounphrase([a,cake],[])? 8 2 Exit: verbphrase([ate,a,cake],[])? 1 1 Exit: sentence([the,man,ate,a,cake],[])? % 1) här se vi att %_1068=[ate,a,cake] 2) här se vi att _1500 = [man,ate,a,cake]
Ytterligare ett exempel; aritmetiska uttryck. Vi definerar expr med DCG-grammatik på sidan 35 i syntaxhäftet. Finns på /info/progp05/expr.pl. Delar av en körning av term([3, *, 1, 2], []). Resultat om man har aktiverat trace:?- trace. % The debugger will first creep -- showing everything (trace) % trace,source_info?- term([3, *, 1, 2], []). 1 1 Call: term([3,*,1,2],[])? 2 2 Call: factor([3,*,1,2],_1048)? 3 3 Call: number([3,*,1,2],_1048)? 4 4 Call: digit([3,*,1,2],_1904)? 5 5 Call: C ([3,*,1,2],0,_1904)? 5 5 Fail: C ([3,*,1,2],0,_1904)? 6 5 Call: C ([3,*,1,2],1,_1904)?... pss prövar vi för 2 8 5 Call: C ([3,*,1,2],3,_1904)? 8 5 Exit: C ([3,*,1,2],3,[*,1,2])? 4 4 Exit: digit([3,*,1,2],[*,1,2])? 9 4 Call: moredigits([*,1,2],_1048)? 10 5 Call: digit([*,1,2],_3983)? 11 6 Call: C ([*,1,2],0,_3983)?... pss prövar vi för 1,2,..., 8 20 6 Call: C ([*,1,2],9,_3983)? 20 6 Fail: C ([*,1,2],9,_3983)? 10 5 Fail: digit([*,1,2],_3983)?... osv 36 8 Call: C ([],0,_12279)?... pss prövar vi för 1,2,..., 8 45 8 Call: C ([],9,_12279)? 45 8 Fail: C ([],9,_12279)? 35 7 Fail: digit([],_12279)? 46 7 Call: _6439=[]? % Omskrivning moredigits --> [] 46 7 Exit: []=[]? % moredigits(begin, Rest) :- Begin = Rest 34 6 Exit: moredigits([],[])? 29 5 Exit: moredigits([2],[])? 25 4 Exit: number([1,2],[])? 24 3 Exit: factor([1,2],[])? 47 3 Call: morefactors([],[])? 48 4 Call: C ([],*,_15147)? 48 4 Fail: C ([],*,_15147)? 49 4 Call: C ([],/,_15147)? 49 4 Fail: C ([],/,_15147)? 50 4 Call: []=[]? 50 4 Exit: []=[]? 47 3 Exit: morefactors([],[])? 22 2 Exit: morefactors([*,1,2],[])? 1 1 Exit: term([3,*,1,2],[])? % trace,source_info
DCG med semantik. Ett exempel; aritmetiska uttryck. Vi definierar expr med DCG-grammatik med semantik på sidan 36 i syntaxhäftet. Finns också på /info/progp05/expr.pl inom kommentarer. En körning av term(r, [3, *, 1, 2], []):?- term(r, [3, *, 1, 2], []). R = 36? Genom att lägga till semantik till uttryckssyntaxen får vi en räknedosa för artimetiska uttryck skriven med DCG.. Delar av en körning av term(r, [3, *, 1, 2], []). Resultat om man har aktiverat trace:?- trace. % The debugger will first creep -- showing everything (trace) % trace,source_info?- term(r, [3, *, 1, 2], []). 1 1 Call: term(_430,[3,*,1,2],[])? % R = _430 2 2 Call: factor(_1089,[3,*,1,2],_1091)? 3 3 Call: number(_1089,[3,*,1,2],_1091)? 4 4 Call: digit(_1953,[3,*,1,2],_1955)? 5 5 Call: C ([3,*,1,2],0,_1955)? 5 5 Fail: C ([3,*,1,2],0,_1955)? 6 5 Call: C ([3,*,1,2],1,_1955)? 6 5 Fail: C ([3,*,1,2],1,_1955)? 7 5 Call: C ([3,*,1,2],2,_1955)? 7 5 Fail: C ([3,*,1,2],2,_1955)? 8 5 Call: C ([3,*,1,2],3,_1955)? 8 5 Exit: C ([3,*,1,2],3,[*,1,2])? 4 4 Exit: digit(3,[3,*,1,2],[*,1,2])? 9 4 Call: moredigits([3],_1089,[*,1,2],_1091)? 10 5 Call: digit(_4039,[*,1,2],_4041)? 11 6 Call: C ([*,1,2],0,_4041)?...... 27 4 Exit: moredigits([3],3,[*,1,2],[*,1,2])? 3 3 Exit: number(3,[3,*,1,2],[*,1,2])? 2 2 Exit: factor(3,[3,*,1,2],[*,1,2])? 27 3 Exit: factor(12,[1,2],[])? 55 3 Call: _8987 is 3*12? % Acc1 is Acc*F 55 3 Exit: 36 is 3*12?... 56 3 Exit: morefactors(36,36,[],[])? % [] slut på insträngen 25 2 Exit: morefactors(3,36,[*,1,2],[])? 1 1 Exit: term(36,[3,*,1,2],[]) % term(t)-->factor(f),morefactors(f,t). R = 36?