Samenvatting hst. 3 sec. 1-3 ( ) :: Parser a b Parser a b Parser a b ( ) :: Parser a (b c) Parser a b Parser a c ( ) :: (b c) Parser a b Parser a c (p q) xs = p xs ++ q xs (p q) xs = [(f b,zs) | (f,ys) p xs, (b,zs) q ys] (f p) xs = [(f b,ys) | (b,ys) p xs] infixl 6 infixl 7 infixr 4
Toepassing: geneste haakjes nGrammatican Abstracte syntax { H , H ( H ) H } data H =Leeg |Paar H H haakjes :: Parser Char H nParser haakjes = epsilon open haakjes sluit haakjes where open = symbol ’(’ sluit = symbol ’)’ (\x Leeg) (\a b c d Paar b d)
Samenvatting hst. 3 sec. 4 nParser combinators voor EBNF nNog wat extra utilities many :: Parser a b Parser a [b] many1 :: Parser a b Parser a [b] option :: Parser a b b Parser a b pack :: Parser a o Parser a b Parser a s Parser a b sequence :: [ Parser a b ] Parser a [b] choice :: [ Parser a b ] Parser a b listOf :: Parser a b Parser a s Parser a [b] chainr :: Parser a b Parser a (b b b) Parser a b
Abstracte syntax voor Expressies data Expr =ConInt |VarString |FunString [Expr] |Expr :+: Expr |Expr :–: Expr |Expr :*: Expr |Expr :/: Expr
Parser voor Expressies (met prioriteiten) expr= chainr term (symbol ‘+’) term= chainr fact (symbol ‘*’) fact= getal gehaakt expr (\o (:+:)) (\o (:*:)) Con ( (\o (:–:)) (symbol ‘–’) ) ( (\o (:/:)) (symbol ‘/’) ) Var naam Fun naam gehaakt (listOf expr (symbol ‘,’) ) chainl is nu beter
Parser voor Expressies (principe) expr= chainr term(… (:+:)…‘+’ … … (:–:)…‘–’ … ) term= chainr fact(… (:*:)…‘*’ … … (:/:)…‘/’ … ) fact= basis gehaakt expr gen ops next = chainr next ( choice …ops… )
Parser voor Expressies (veel prioriteiten) expr= gen ops1 term1 term1= gen ops2 term2 term2= gen ops3 term3 term3= gen ops4 term4 term4= gen ops5 fact fact= basis gehaakt expr expr = foldr gen fact [ops1,ops2,ops3,ops4,ops5] gen ops next = chainr next ( choice …ops… )
Gebruik van parsers nType van parsers nParser voor expressies nOpstarten van de parser type Parser a b = [a] [ (b, [a]) ] expr :: Parser Char Expr geefExpr :: String Expr expr :: String [ (Expr, String) ] geefExpr =exprfilter (null.snd).head.fst.
Gebruik van parsers nGeneralisatie geefExpr :: String Expr geefExpr =exprfilter (null.snd).head. start :: Parser a b [a] b start p =pfilter (null.snd).head. fst.
Ontwerp van een parser nObserveer de taal nBedenk een grammatica uevt. transformeren nMaak datatype voor de ontleedboom nMaak parse-functie uevt. met preprocessor nVoeg semantiek toe uof: als functie op ontleedboom uof: direct tijdens het parsen
Parser-ontwerp (1/5) Observeer de taal nVoorbeeld: reisschema’s Groningen 8:37 9:44 Zwolle 9:49 10:15 Utrecht 10:21 11:05 Rotterdam Utrecht 9:17 9:42 Amsterdam vertrekaankomst Almelo
Parser-ontwerp (2a/5) Bedenk een grammatica Groningen 8:37 9:44 Zwolle 9:49 10:15 Utrecht 10:21 11:05 Rotterdam Schema Schema Tijd Tijd Schema | Stad Tijd Getal : Getal Getal Cijfer + Stad Letter +
Parser-ontwerp (2b/5) Bedenk een grammatica Groningen 8:37 9:44 Zwolle 9:49 10:15 Utrecht 10:21 11:05 Rotterdam Schema Stad Tijd Overstap* Tijd Stad | Stad Overstap Tijd Stad Tijd
Parser-ontwerp (2c/5) Bedenk een grammatica Groningen 8:37 9:44 Zwolle 9:49 10:15 Utrecht 10:21 11:05 Rotterdam Schema Stad Rit* Rit Tijd Tijd Stad
Parser-ontwerp (2d/5) Bedenk een grammatica Groningen 8:37 9:44 Zwolle 9:49 10:15 Utrecht 10:21 11:05 Rotterdam Schema Rit’* Stad Rit’ Stad Tijd Tijd
Parser-ontwerp (3b/5) Maak datatype ontleedboom Schema Stad Tijd Overstap* Tijd Stad | Stad Overstap Tijd Stad Tijd data Schema = Met Stad Tijd [Overstap] Tijd Stad | Zonder Stad type Overstap = ( Tijd, Stad, Tijd )
Parser-ontwerp (3d/5) Maak datatype ontleedboom Schema Rit* Stad Rit Stad Tijd Tijd type Schema’ = ( [Rit], Stad) type Rit = ( Stad, Tijd, Tijd ) type Tijd = ( Int, Int ) type Stad = String
Parser-ontwerp (4b/5) Maak parse-functie Schema Stad Tijd Overstap* Tijd Stad | Stad Overstap Tijd Stad Tijd schema = stad tijd many overstap tijd stad stad overstap = tijd stad tijd tijd = getal symbol ‘:’ getal Met Zonder (\t1 s t2 (t1,s,t2)) (\n1 d n2 (n1,n2))
Parser-ontwerp (4d/5) Maak parse-functie Schema Rit* Stad Rit Stad Tijd Tijd schema’ = many rit stad rit = stad tijd tijd (\rs s (rs,s)) (\s t1 t2 (s,t1,t2))
Parser-ontwerp (5/5) Voeg semantiek toe nBijvoorbeeld: uWachttijd uTotale reistijd uLijst van stations min :: Tijd Int min (u,m) = 60*u + m wachttijd, reistijd :: Schema Int stations :: Schema [String]
Semantische functies data Schema = Met Stad Tijd [Overstap] Tijd Stad | Zonder Stad type Overstap = ( Tijd, Stad, Tijd ) wacht (Zonder _) = 0 wacht (Met _ _ os _ _) = sum (map f os) where f (t1,_,t2) = min t2 – min t1 stats (Zonder s) = [s] stats (Met s1 _ os _ s2) = s1 : map f os ++ [s2] where f (_,s,_) = s reis = … Oei… lastig!
Alternatieve Semantische functies type Schema’ = ( [Rit], Stad) type Rit = ( Stad, Tijd, Tijd ) reis’ (rs,_) = sum (map f rs) where f (s,t1,t2) = min t2 – min t1 stats’ (rs,s) = map f rs ++ [s] where f (s,_,_) = s wacht’ = … Oei… lastig!
Ontleedboom bepalen tijdens het ontleden schema’ :: Parser String Schema’ schema’ = many rit stad rit :: Parser String Rit rit = stad tijd tijd (\rs s (rs,s)) (\s t1 t2 (s,t1,t2))
Semantiek bepalen tijdens het ontleden schemaReis’ :: Parser String Int schemaReis’ = many ritReis stad ritReis :: Parser String Int ritReis = stad tijd tijd (\ns s sum ns) (\s t1 t2 min t2 – min t1)
Ontwerp van een parser nObserveer de taal nBedenk een grammatica uevt. transformeren nMaak datatype voor de ontleedboom nMaak parse-functie uevt. met preprocessor nVoeg semantiek toe uof: als functie op ontleedboom uof: direct tijdes het parsen
De basis-parsers many1 :: Parser a b Parser a [b] naam :: Parser Char String naam = many1 (satisfy isAlpha) getal :: Parser Char Int getal = many (satisfy isDigit) foldl f 0 where f n c = 10*n + ord c – ord ‘0’
Publieksvraag nObserveer de taal van floating-point getallen in standaard programmeertalen 3.141e6-5F E23 float :: Parser Char Float float =
Uitwerking cijfer :: Parser Char Int cijfer = satisfy isDigit (\c ord c–ord’0’) natuurlijk :: Parser Char Int natuurlijk = many cijfer (foldl (\n d 10*n+d) 0) fractie :: Parser Char Float fractie = many cijfer (foldr (\d n (n+d)/10) 0) geheel :: Parser Char Int geheel = option ( symbol ‘–’) natuurlijk (\c neg) id apply eigenlijk moet fromIntegral :: Int Float nog worden gebruikt
Uitwerking (vervolg) fixed :: Parser Char Float fixed = geheel option( symbol ‘.’ fractie ) (\p x x) 0 (+) float :: Parser Char Float float = fixed option( symbol ‘E’ geheel ) (\p x x) 0 f where f gr ex = gr * pow 10 ex fromIntegral