• No results found

Parsing With Haskell

N/A
N/A
Protected

Academic year: 2021

Share "Parsing With Haskell"

Copied!
16
0
0

Loading.... (view fulltext now)

Full text

(1)

Parsing with Haskell

Parsing with Haskell

Lennart Andersson Lennart Andersson Computer Science Computer Science Lund University Lund University October 28, 2001 October 28, 2001

Introduction

Introduction

This will be an extended example that will provide the basis for a small program project resulting This will be an extended example that will provide the basis for a small program project resulting in an

in an ininterterprepreter for ter for an an impeimperatirative languve languageage. . The examThe example will show how abstrple will show how abstractaction andion and higher order functions can be used to make the parsing program look like the grammar for the higher order functions can be used to make the parsing program look like the grammar for the imperative language.

imperative language.

The example will decompose a nontrivial problem into a large number of very small problems. The example will decompose a nontrivial problem into a large number of very small problems. Most of them can be solved with almost trivial functions. Actually, the longest function in the Most of them can be solved with almost trivial functions. Actually, the longest function in the example has just 7 lines of code. To do this decomposition requires a fair amount of experience; example has just 7 lines of code. To do this decomposition requires a fair amount of experience; it shoul

it should d be be a a lot easielot easier r to understo understand the functtand the functionions s and the prograand the program. m. WWe e belibelieveve e it is it is a a goodgood programming strategy to decompose a nontrivial problem into problems that are small and programming strategy to decompose a nontrivial problem into problems that are small and almost trivial.

almost trivial.

The programming language will have statements and integer expressions as its main building The programming language will have statements and integer expressions as its main building stones. Expressions will be represented in the interpreter with the following data type.

stones. Expressions will be represented in the interpreter with the following data type. da

data ta ExExpr pr = = NuNum m InInt t | | VaVar r StStriring ng | | AdAdd d ExExpr pr ExExprpr |

| SuSub b ExExpr Exppr Expr r | | MuMul l ExExpr Exppr Expr r | | DiDiv v ExExpr Exppr Exprr As an example the expression

As an example the expression 2*(x+3)2*(x+3) will be represented bywill be represented by Mu

Mul l (N(Num um 2) 2) (A(Add dd (V(Var ar "x"x") ") (N(Num um 3)3))) Statements will be represented using

Statements will be represented using dat

data a StaStatemtement ent == Ass

Assignignmenment t StrString ing ExpExpr r || ...

...

so that the assignment statement

so that the assignment statement cocoununt t := := cocoununt t + + 11 is represented byis represented by Ass

Assignignmenment t "co"countunt" " (Ad(Add d (Va(Var r "co"countunt") ") (Nu(Num m 1))1))

We are going to define parsing functions that takes such strings as arguments and returns the We are going to define parsing functions that takes such strings as arguments and returns the corres

corresponding represponding representaentation. tion. WWe are e are going to introduce a few going to introduce a few ververy simple parsers and somey simple parsers and some operators for combining parsers that may be used to construct complex parsers.

(2)

A parsing function will usua

A parsing function will usually not parse all of lly not parse all of the input string, but just a prefix. the input string, but just a prefix. The remaindThe remainderer of the string will b

of the string will be the input to e the input to anotheanother parser. r parser. Suppose that we havSuppose that we have a e a parser whicparser which accepts anh accepts an identifier consisting of letters, another one accepting the string “:=” and a third one accepting an identifier consisting of letters, another one accepting the string “:=” and a third one accepting an expre

expression and returning a ssion and returning a pair with some pair with some represrepresententation of ation of the accepted string and a the accepted string and a remainremainderder string:

string: ident

ident "coun"count:=cot:=count+1unt+1;" ;" -> -> ("cou("count", nt", ":=co":=count+unt+1;")1;") becom

becomes es ":=co":=count+1unt+1:" :" -> -> (":="(":=", , "cou"count+1;nt+1;")") exp

expr r "co"countunt+1;+1;" " -> -> (Ad(Add d (Va(Var r "co"countunt") ") (Nu(Num m 1), 1), ";"";")) The arrow

The arrow ->-> denotedenotes evaluas evaluation. tion. WWe can e can comcombine these parsers to bine these parsers to a parser a parser for an for an assignassignmenmentt statement:

statement: ass

assignignmenment t str str = = (As(Assigsignmenment nt id id e, e, resrest3) t3) whewherere (id

(id, , resrest1) = t1) = ideident nt strstr (_,

(_, resrest2) = t2) = becbecomeomes s resrest1t1 (e

(e, , rerestst3) 3) = = exexpr pr rerestst22 The type of such parsers would be The type of such parsers would be

ty

type pe PaParsrser er a a = = StStriring ng -> -> (a(a, , StStriringng)) A

A ParParser ser aa taktakes a es a stristring argumeng argument and nt and retureturns a rns a paipair. r. WWe e wilwill l calcall l the first componethe first component thent the result of the parser and second the remainder string. Thus we have

result of the parser and second the remainder string. Thus we have ide

ident nt :: :: ParParser ser StrStringing bec

becomeomes s :: :: ParParser ser StrStringing exp

expr r :: :: ParParser Exprser Expr assig

assignment nment :: :: ParseParser r StateStatementment

A parser should either accept or reject its input. The Prelude defines a data type for handling A parser should either accept or reject its input. The Prelude defines a data type for handling two such alternatives.

two such alternatives. da

data ta MaMaybybe e a a = = NoNoththining g | | JuJust st aa

This type can be used in any context where a computation either fails or returns some valid This type can be used in any context where a computation either fails or returns some valid result. We redefine our parser type

result. We redefine our parser type typ

type e ParParser a ser a = = StrString -> ing -> MayMaybe be (a,(a,StrStringing)) and the parsers so that e.g.

and the parsers so that e.g.

ident "count:=count+1;" ->

ident "count:=count+1;" -> Just("count",":=Just("count",":=count+1;")count+1;") ident

ident "123:"123:=coun=count+1;" t+1;" -> -> NothNothinging The

The typetype definitions just give synonyms to type expressions; there are no constructors as in thedefinitions just give synonyms to type expressions; there are no constructors as in the case of 

case of datadata definitions.definitions.

Exer

Exercise cise 11 DefineDefine semsemicoicolon lon :: :: ParParser ser ChaCharr so that so that 

sem

semicoicolon lon "; "; skiskip" p" -> -> JusJust(’t(’;’, ;’, " " skiskip")p") semic

semicolon olon "ski"skip" p" -> -> NothNothinging

Exer

Exercise cise 22 DefineDefine becomesbecomes.. Exer

Exercise cise 33 Define a parser Define a parser chachar r :: :: ParParser Charser Char whiwhich ch acacccepts one epts one chacharracteacter. r. The The solsolutioution 

appears on the next page, don’t look!  appears on the next page, don’t look! 

(3)

Basic parsers Basic parsers

The basic parsers are almost trivial. The first one will accept one character and is defined by The basic parsers are almost trivial. The first one will accept one character and is defined by

cha

char r :: :: ParParser Charser Char cha

char r (c:(c:cs) cs) = = JusJust(ct(c,cs,cs)) ch

char ar [] [] = = NoNoththiningg Pars

Parser er CharChar is a synonym foris a synonym for StriString ng -> -> MaybMaybe(Chae(Char,Strr,String)ing). . ThThe e fufuncnctition failon fails s if the inpif the inputut string is empty. Some examples

string is empty. Some examples cha

char r "" "" -> -> NotNothinhingg cha

char r "1" "1" -> -> JusJust(’t(’1’,1’,"")"") char

char "abc" -> "abc" -> Just(Just(’a’,"’a’,"bc")bc") The next parser is even simpler. The next parser is even simpler.

fa

fail il :: :: PaParsrser er aa fa

fail il cs cs = = NoNoththiningg This parser will neve

This parser will never accept any input, so r accept any input, so it seems to it seems to be useless. be useless. ActuallActually we will later y we will later definedefine a similar parser which will prin

a similar parser which will print an t an error message and abort the error message and abort the computcomputation. ation. The nameThe name failfail is define

is defined d in the in the PrePreludlude e so we so we hahave hide it ve hide it whewhen n impoimportinrting g the Prelthe Preludeude. . If you testIf you test failfail byby applying it to a string the system refuses to print

applying it to a string the system refuses to print NothingNothing:: >

> faifail l "ab"abc"c" ERR

ERROR: OR: CanCannot not finfind d "sh"show" ow" funfunctiction on forfor:: ***

*** expexpresressiosion n : : faifail l "ab"abc"c" *

*** ** of of tytype pe : M: Mayaybe be (a(a,[,[CChaharr])])

In order to print (show) the result the Haskell system must know how to print values of type In order to print (show) the result the Haskell system must know how to print values of type a

a which occurs inwhich occurs in Maybe Maybe (a,[C(a,[Char])har]) even if no such value is present ineven if no such value is present in NothingNothing. . SuSupppplylyining ag a printable type fixes the problem:

printable type fixes the problem: >

> fail "abc" fail "abc" :: :: MaybMaybe(Inte(Int,Stri,String)ng) Nothing

Nothing

The same error is reported if you enter an empty list to the system: The same error is reported if you enter an empty list to the system: >

> [][] ERR

ERROR: OR: CanCannot not finfind d "sh"show" ow" funfunctiction on forfor:: *** expre

*** expressission on : : [][] *

**** * oof f ttyyppe e : : [[aa]] While

While failfail is extreme in one way the next parser,is extreme in one way the next parser, returnreturn, is extreme in opposite sense; it will, is extreme in opposite sense; it will always succeed without inspecting the input string. It returns its first argument that may be of  always succeed without inspecting the input string. It returns its first argument that may be of  any type.

any type. re

retuturn :: rn :: a a -> Pars-> Parser aer a ret

return a urn a cs cs = = JusJust(at(a,cs,cs)) Examples

Examples ret

return urn 0 0 "ab"abc" c" -> -> JusJust(0t(0,"a,"abc"bc")) ret

return urn (Ad(Add d (Va(Var r "co"countunt") ") (Nu(Num m 1)) ";" 1)) ";" -> -> JusJust(At(Add dd (Va(Var r "co"countunt") ") (Nu(Num m 1))1)), , ";"";")) The

(4)

Parser operators Parser operators

The first parser operator will be an infix operator denoted by

The first parser operator will be an infix operator denoted by ??. . If If m :: Parser am :: Parser a is a parseris a parser and

and p :: a -> Boolp :: a -> Bool is a predicate thenis a predicate then (m ? p)(m ? p) is a parser which appliesis a parser which applies mm to the input stringto the input string and tests if the result satisfies

and tests if the result satisfies pp.. infix 7 ?

infix 7 ? (?

(?) ) :: Par:: Parseser r a a -> (a -> (a -> Boo-> Bool) -> l) -> PaParsrser aer a (m ? p) cs =

(m ? p) cs = case m cs of case m cs of

Noth

Nothing ing -> -> NothNothinging Jus

Just(at(a,cs,cs) ) -> -> if if p p a a thethen n JusJust(at(a,cs,cs) ) elselse e NotNothinhingg The

The infixinfix directive declaresdirective declares ?? to be an infix operator with precedence 7. The precedence levelsto be an infix operator with precedence 7. The precedence levels for the parser operators will be chosen so that most parentheses may be omitted.

for the parser operators will be chosen so that most parentheses may be omitted. The Prelude contains a predicate for deciding if a character is a digit,

The Prelude contains a predicate for deciding if a character is a digit, isDigitisDigit. . WWe can define can definee a parser accepting one digit

a parser accepting one digit dig

digit it :: :: ParParser Charser Char

digit cs = (char ? isDigit) cs digit cs = (char ? isDigit) cs Examples

Examples

digit "123"

digit "123" -> -> JustJust(’1’,(’1’,"23")"23") dig

digit it "ab"abc" c" -> -> NotNothinhingg

If the right member of a function definition applies an expression not containing the last If the right member of a function definition applies an expression not containing the last argu-men

ment to t to the last argument then this argument may be the last argument then this argument may be remoremoved from both ved from both sides of the sides of the definitdefinition.ion. di

digigit t = = chchar ar ? ? isisDiDigigitt The secon

The second d parsparser er operoperator correator correspondsponds s to to altealternatrnativives es in in the grammathe grammar. r. WWe e wilwill l use an use an infiinfixx operator,

operator, !!, , for this parsfor this parser comber combinainator. tor. If If mm andand nn are parsers of the same type thenare parsers of the same type then (m ! n)(m ! n) will be a parser which first applies

will be a parser which first applies mm to the input string which will be the result unlessto the input string which will be the result unless mm fails.fails. In that case

In that case nn is applied to the input.is applied to the input. The definition is simple:

The definition is simple: in

infifixl 3 xl 3 !! (!

(!) ) :: :: PaParsrser er a a -> -> PaParsrser er a a -> -> PaParsrser er aa (m ! n) cs =

(m ! n) cs = case m cs of case m cs of

No

Noththining g -> -> n n cscs   m

  mcs cs -> -> mcmcss The

The infixlinfixl directive tells the Haskell systemdirective tells the Haskell system !! will be an infix operator which associates to thewill be an infix operator which associates to the left. Left association means that

left. Left association means that m ! n ! km ! n ! k is evaluated asis evaluated as ( m ! n ) ! k( m ! n ) ! k. Some examples:. Some examples: (ch

(char ar ! ! digdigit) it) "ab"abc" c" -> -> JusJust(’t(’a’, a’, "bc"bc")") (di

(digit git ! ! chachar) r) "ab"abc" c" -> -> JusJust(’t(’a’, a’, "bc"bc")") (di

(digit git ! ! retreturn urn ’0’’0’) ) "ab"abc" c" -> -> JusJust(’t(’0’, 0’, "ab"abc")c") (d

(5)

We have assigned precedences to the operators so that

We have assigned precedences to the operators so that m ? p ! nm ? p ! n will meanwill mean ((m ? m ? pp) ! ) ! nn andand not

not m ? ( p ! n )m ? ( p ! n ) which would give a type mismatch error.which would give a type mismatch error.

Exer

Exercise cise 44 The Prelude defines the predicatesThe Prelude defines the predicates isAisAlphlpha, a, isSisSpacpace:: e:: ChaChar r -> -> BooBooll which decidewhich decide

if

if a a chacharracteacter r is is a a lettletter er or or spspacace e chacharracteacter r (bl(blankank, , tab, newline)tab, newline). . DefiDefine ne pparsarsers accers acceptepting a ing a  letter and a space character,

letter and a space character, letletterter, , spaspace ce :: :: ParParser ser ChaCharr..

Exer

Exercise cise 55 Define a parser Define a parser alpalphanhanum um :: :: ParParser ser ChaCharr which accepts a letter or a digit.which accepts a letter or a digit.

A parser accepting a given character is easily defined. A parser accepting a given character is easily defined.

li

lit t :: :: ChChar ar -> -> PaParsrser er ChCharar lit c = char ? (==c)

lit c = char ? (==c) The operator section

The operator section (==c)(==c) is equivalent to the predicateis equivalent to the predicate (\x -> (\x -> x==x==c)c). . The predicThe predicate decideate decidess if the given character is the the same as the one accepted by

if the given character is the the same as the one accepted by charchar.. lit ’a’

lit ’a’ "ab"abc" c" -> -> JusJust t (’a(’a’,"’,"bc"bc")) lit ’b’

lit ’b’ "ab"abc" c" -> -> NotNothinhingg

Exer

Exercise cise 66 RedefineRedefine semsemicoicolon lon :: :: ParParser ser ChaCharr using using litlit. The defin. The definitioition should not incln should not includeude

the string argument. the string argument.

The next parser combinator applies two parsers in sequence where the remainder string from The next parser combinator applies two parsers in sequence where the remainder string from the first one is fed into the other. The results of the two parsers are combined into a pair. the first one is fed into the other. The results of the two parsers are combined into a pair.

in

infifixl 6 xl 6 ## (#

(#) ) :: Pars:: Parser a er a -> Pars-> Parser b er b -> Pars-> Parser (a, er (a, b)b) (m # n) cs =

(m # n) cs = case m cs of case m cs of

Nothi

Nothing ng -> -> NothNothinging Jus

Just(pt(p, , cs’cs’) ) ->-> ca

case n se n cscs’ ’ ofof Noth

Nothing ing -> -> NothNothinging Just

Just(q, (q, cs’’cs’’) ) -> -> Just(Just((p,q)(p,q), , cs’’cs’’)) A

A parser accepting two parser accepting two chacharacters followsracters follows.. (ch

(char ar # # chachar) r) ":=":=1" 1" -> -> JusJust((t((’:’’:’, , ’=’’=’), ), "1""1")) We may name it:

We may name it: two

twochachars rs :: :: ParParser ser (Ch(Char, ar, ChaChar)r) tw

twocochahars rs = = chchar ar # # chcharar

Exer

Exercise cise 77 RedefineRedefine becbecomeomes s :: :: ParParser ser (Ch(Char, ar, ChaChar)r)using using twocharstwochars and theand the ?? operator. Theoperator. The

definition should not include the string argument. definition should not include the string argument.

Sometimes we would like to transform the result of a parser. This may be done with Sometimes we would like to transform the result of a parser. This may be done with

(6)

inf

infixl 5 ixl 5 >->>-> (>

(>->->) ) :: Par:: Parseser r a a -> (a -> (a -> b) -> b) -> Par-> Parseser r bb (m >-> k) cs =

(m >-> k) cs = case m cs of case m cs of

Jus

Just(at(a,cs,cs’) ’) -> -> JusJust(k t(k a, a, cs’cs’)) Noth

Nothing ing -> -> NothNothinging The right operand of 

The right operand of >->>-> namednamed kk is the function defining the transformation. The result of theis the function defining the transformation. The result of the oper

operatioation n is a is a new parsnew parser. er. WWe e mamay use y use it to it to defidefine a ne a parparser whicser which h accacceptepts s a a digdigit and it and retreturnurnss an

an IntInt usingusing digitToIntdigitToIntfrom the Prelude.from the Prelude. dig

digitVitVal al :: :: ParParser ser IntInt dig

digitVitVal al = = digdigit it >-> >-> digdigitTitToInoIntt Example

Example dig

digitVitVal al "12"123" 3" -> -> JusJust(1t(1, , "23"23")") digit

digitVal Val "abc"abc" " -> -> NothNothinging

Exer

Exercise cise 88 Define a parser that accepts a letter and returns an upper case letter. The PreludeDefine a parser that accepts a letter and returns an upper case letter. The Prelude

 function 

 function toUtoUppepper r :: :: ChaChar r -> -> ChaCharr transforms any letter to its uppercase form.transforms any letter to its uppercase form.

Exer

Exercise cise 99 DefineDefinesndsndchachar r :: :: ParParser ser ChaCharrwhich accepts two characters and returns the second which accepts two characters and returns the second 

one. Use

one. Use twocharstwochars and the transformation operator. Examplesand the transformation operator. Examples snd

sndchachar r "ab"abc" c" -> -> JusJust(’t(’b’, b’, "c""c")) snd

sndchachar r "a" "a" -> -> NotNothinhingg

Exer

Exercise cise 1010 RedefineRedefine twoctwochars :: hars :: ParseParser r StriStringng so that it returns a so that it returns a StringString with two charac-with two

charac-ters instead of a pair of characcharac-ters. ters instead of a pair of characters.

Exer

Exercise cise 1111 Define an operator Define an operator (-(-#) :: #) :: PaParsrser a er a -> Pars-> Parser b er b -> Par-> Parseser r bbwhich applies twowhich applies two

parsers in sequence as

parsers in sequence as ## but thrbut throws away the ows away the rresuesult from the first one. lt from the first one. UseUse ## and and >->>-> in thein the definition. Examples

definition. Examples (ch

(char ar -# -# chachar) r) "ab"abc" c" -> -> JusJust(’t(’b’, b’, "c""c")) (ch

(char ar -# -# chachar) r) "a" -> "a" -> NotNothinhingg

Exer

Exercise cise 1212 Define a similar operator Define a similar operator (#(#-) :: -) :: PaParsrser a er a -> Par-> Parseser r b b -> Pars-> Parser aer a which ap-which

ap-plies two parsers in sequence as

plies two parsers in sequence as ## but throws away the result from the second one.but throws away the result from the second one. It is useful to be able to apply a parser iteratively to the input string. First we define

It is useful to be able to apply a parser iteratively to the input string. First we define ititereratate e m m ii which will apply the parser

which will apply the parser mmto the input stringto the input string iitimes with the result in a list withtimes with the result in a list with ii elements.elements. Example

Example ite

iteratrate e digdigitVitVal al 3 3 "12"123453456" 6" -> -> JusJust([t([1, 1, 2, 2, 3], 3], "45"456")6") ite

iteratrate e letletter ter 3 3 "a1"a123" 23" -> -> NotNothinhingg The

(7)

it

itereratate e :: :: PaParsrser er a a -> -> InInt t -> -> PaParsrser er [a[a]] it

itereratate e m m 0 0 = = reretuturn []rn [] it

itereratate e m m i i = = m m # # ititereratate e m m (i(i-1-1) ) >->-> > coconsns where

where co

cons :: ns :: (a(a, , [a[a]) -> ]) -> [a[a]] co

cons ns (h(hd, d, tltl) ) = = hdhd:t:tll The name

The name iterateiterate is defined in the Prelude so it is necessary to hide it or to rename the newis defined in the Prelude so it is necessary to hide it or to rename the new function.

function. It is

It is eveven more usefuen more useful l to bto be e ablable e to iteratto iterate e a a parsparser as er as long as it long as it sucsucceeceeds. ds. AssAssumiuming thatng that iteriter does this we could use it like follows

does this we could use it like follows ite

iter r digdigitVitVal al "12"123ab3abc" c" -> -> JusJust([t([1, 1, 2, 2, 3], 3], "ab"abc")c") ite

iter r digdigit it "12"123ab3abc" c" -> -> JusJust([t([’1’’1’, , ’2’’2’, , ’3’’3’], ], "ab"abc") c") -> -> JusJust("t("123123", ", "ab"abc")c") ite

iter r digdigit it "ab"abc" c" -> -> JusJust([t([], ], "ab"abc") c") -> -> JusJust("t("", ", "ab"abc")c")

The definition will again be recursive but termination will be signaled by the failure of the The definition will again be recursive but termination will be signaled by the failure of the recursive branch. In that case we just return the empty list.

recursive branch. In that case we just return the empty list. it

iter er :: :: PaParsrser er a a -> -> PaParsrser er [a[a]]

iter m = m # iter m >-> cons ! return [] iter m = m # iter m >-> cons ! return []

Inserting parentheses to indicate precedences of the operators we get Inserting parentheses to indicate precedences of the operators we get

it

iter er m m = = ((((m m # # (i(iteter r m)m)) ) >->-> > coconsns) ) ! ! (r(retetururn n [][]))

Exer

Exercise cise 1313 Why is it an error to take the alternatives in the opposite order? Why is it an error to take the alternatives in the opposite order? 

iter m = return [] ! m # iter m >-> cons iter m = return [] ! m # iter m >-> cons We can use

We can use iteriter to define a to define a parsparser for er for a a strstring of ing of letletterters. s. Our first atteOur first attempt ismpt is let

letterters s :: :: ParParser ser StrStringing le

letttterers s = ite= iter letr letteterr

This is OK provided we are willing to accept an empty string.

This is OK provided we are willing to accept an empty string. If this is If this is not the case we definenot the case we define it as

it as le

letttterers s = = leletttter # er # ititer leter letteter r >->-> > coconsns W

We now consider the problem of e now consider the problem of whiteswhitespace, i.e. pace, i.e. blanks and newline chablanks and newline charactersracters, , in the in the input.input. We define

We define tokentoken which for a given parser will return a parser which will remove any whitespacewhich for a given parser will return a parser which will remove any whitespace after the accepted string.

after the accepted string. to

tokeken n :: :: PaParsrser er a a -> Pars-> Parser er aa to

tokeken m n m = m = m #- i#- iteter spr spaacece We now define two very useful parsers. We now define two very useful parsers.

(8)

wor

word d :: :: ParParser ser StrStringing wor

word d = = toktoken en letletterterss acc

accept ept :: :: StrString ing -> -> ParParser ser StrStringing ac

accecept pt w w = = totokeken n (i(iteterarate te chchar ar (s(sizize e w) w) ? ? (=(==w=w)))) Examples

Examples wor

word d "co"count unt := := coucount+nt+1" 1" -> -> JusJust("t("coucount"nt", , ":= ":= coucount+nt+1")1") wor

word d ":= ":= coucount+nt+1" 1" -> -> NotNothinhingg acc

accept ept "wh"whileile" " "wh"while ile x x do do x:=x:=x-1x-1" " -> -> JusJust("t("whiwhile"le", , "x "x do do x:=x:=x-1x-1")") acc

accept "if" ept "if" "wh"while x ile x do do x:=x:=x-1x-1" " -> -> NotNothinhingg Som

Sometietimes we mes we neeneed d to to makmake e the resulthe result t from one from one parparser avser availaailable to ble to anotanotherher. . The folloThe followinwingg operator provides the means.

operator provides the means. infix 4 #>

infix 4 #> (#

(#>) >) :: :: PaParsrser er a a -> -> (a (a -> -> PaParsrser er b) b) -> -> PaParsrser er bb (m #> k) cs =

(m #> k) cs = case m cs of case m cs of

Nothi

Nothing ng -> -> NothiNothingng Ju

Justst(a(a,c,cs’s’) ) -> -> k k a a cscs’’ After applying the parser

After applying the parser mm to the input string both the result and the remainder input stringto the input string both the result and the remainder input string are given to the second operand,

are given to the second operand, k :: a -> Parser bk :: a -> Parser b..

This operator is very useful for parsing numbers and arithmetic expressions with operators that This operator is very useful for parsing numbers and arithmetic expressions with operators that associate to the left like

associate to the left like -- andand //. These parsers will be nontrivial so we start with a simpler and. These parsers will be nontrivial so we start with a simpler and not so useful parser.

not so useful parser. It will accept two chaIt will accept two characters proracters provided they are equal and returning justvided they are equal and returning just one character.

one character. dou

double ble :: :: ParParser ser ChaCharr do

doububle le = = chchar ar #> #> lilitt Remember that

Remember that lilit t :: :: ChChar ar -> -> PaParsrser er ChChararneeds on argument to become a parser which willneeds on argument to become a parser which will accept this character. The character is provided as the result of the first parser. Examples accept this character. The character is provided as the result of the first parser. Examples

dou

double ble "aa"aab" b" -> -> JusJust(’t(’a’, a’, "b""b")) dou

double ble "ab"abb" b" -> -> NotNothinhingg

In order to construct a number parser we define three functions,

In order to construct a number parser we define three functions, bldNumberbldNumber,,number’number’andand numbernumber.. bl

bldNdNumumbeber r :: :: InInt t -> -> InInt t -> -> InIntt bl

bldNdNumumbeber r n n d d = = 1010*n*n+d+d bld

bldNumNumber n ber n dd just “appends” the digitjust “appends” the digit dd afterafter nn.. bld

bldNumNumber 123 ber 123 4 4 -> -> 12312344 nu

numbmberer’ ’ :: :: InInt t -> -> PaParsrser er InIntt nu

numbmberer’ ’ n n == dig

digitVitVal al >-> >-> bldbldNumNumber ber n n #> #> numnumberber’’ !

! reretuturn nrn n num

number ber :: :: ParParser ser IntInt num

(9)

The argument in

The argument innumber’number’will serve as an accumulator which will be returned when no more inputwill serve as an accumulator which will be returned when no more input can be

can be consuconsumed. med. OtherwOtherwise the next ise the next digit is “appended” to digit is “appended” to the accumuthe accumulator and recursivlator and recursivelyely given to

given tonumber’number’. The. The numbernumberparser accepst the parser accepst the first digit withfirst digit with digitValdigitValand sends it toand sends it to number’number’ and finally removes any trailing whitespace. Examples

and finally removes any trailing whitespace. Examples num

numberber’ ’ 1 1 "ab"abc" c" -> -> JusJust(1t(1, , "ab"abc")c") num

numberber’ ’ 1 1 "23 abc" -> "23 abc" -> JusJust(1t(123, " 23, " abcabc")") num

number ber "12"123 3 abcabc" " -> -> JusJust(1t(123, 23, "ab"abc")c")

Exer

Exercise cise 1414 Define the operator Define the operator ## using using #>#>. The solution should not contain . The solution should not contain JustJust or or NothingNothing..

An expression parser An expression parser

We are going to construct a parser for arithmetic expressions with integer numbers, variables, We are going to construct a parser for arithmetic expressions with integer numbers, variables, ad-ditions, subtractions, multiplications, divisions and parentheses with the usual laws for operator ditions, subtractions, multiplications, divisions and parentheses with the usual laws for operator precedence. A grammar is given by

precedence. A grammar is given by ex

expr pr ::::= te= term erm expxpr’r’ ex

exprpr’ ’ ::::= = adaddOdOp p teterm rm exexprpr’ ’ | | ememptptyy te

term rm ::::= fac= factotor terr term’m’ ter

term’ m’ ::= mulOp facto::= mulOp factor r terterm’ m’ | | empemptyty fa

factctoror::::= = nunum m | | vavar r | | "("(" " exexpr pr ")")"" ad

addOdOp p ::::= = "+"+" " | | "-"-""   m

  mululOp Op ::::= = "*"*" " | | "/"/"" The word

The word emptyempty denotedenotes the empty string. s the empty string. In the definition of In the definition of factorfactor,, numnum is a string of digitsis a string of digits and

and varvar a string of letters. There are seva string of letters. There are several grammars desceral grammars describing ordinaribing ordinary expressry expressions. ions. TheThe current one has been chosen since it will be possible to define a parser which is very similar. current one has been chosen since it will be possible to define a parser which is very similar. The result of the parser will be a value of the following type.

The result of the parser will be a value of the following type. da

data ta ExExpr pr == Nu

Num m InInt t | | VaVar r StStriring | ng | AdAdd d ExExpr Exppr Expr r || Su

Sub b ExExpr Expr | pr Expr | MuMul l ExExpr Expr | pr Expr | DiDiv v ExExpr Exprpr Expr

We are going to build the parser from the bottom starting with parsers for

We are going to build the parser from the bottom starting with parsers for mulOpmulOp andand addOpaddOp..  mulOp

 mulOp will accept eitherwill accept either ** oror // and will returnand will return MulMul oror DivDiv. . TheThese parsese parsers are triviars are trivial to l to defidefinene without our parser operators:

without our parser operators:   mulO

  mulOp p (’*’:(’*’:rest) = rest) = Just(Just(Mul, rest)Mul, rest)   mulO

  mulOp p (’/’:(’/’:rest) = rest) = Just(Just(Div, rest)Div, rest)   mu

  mulOp _ lOp _ = = NotNothinhingg W

We prefer, howee prefer, however, to make the definition on the ver, to make the definition on the abstracabstract level. t level. The reason is that The reason is that if we do if we do notnot exploit the fact that the representation by the

exploit the fact that the representation by the MaybeMaybe type is visible outside thetype is visible outside the ParserParser modulemodule then we may change it without changing any module using the

then we may change it without changing any module using the ParserParser module. module. Such a chaSuch a changenge is suggested at the end of this paper.

is suggested at the end of this paper.   mu

  mulOplOp, , addaddOp Op :: :: ParParser ser ((E((Exprxpr, , ExpExpr) r) -> -> ExpExpr)r)   mulOp = lit ’*’ >-> (\_ -> Mul)

  mulOp = lit ’*’ >-> (\_ -> Mul) !

! lilit t ’/’/’ ’ >->-> > (\(\_ _ -> Div-> Div)) Examples

(10)

  mu

  mulOp lOp "*2"*2*3" *3" -> -> JusJust(Mt(Mul, ul, "2*"2*3")3")   mu

  mulOp lOp "/2"/2*3" *3" -> -> JusJust(Dt(Div, iv, "2*"2*2")2")   mu

  mulop lop "+2"+2*3" *3" -> -> NotNothinhingg The

The addOpaddOp parser is analogous.parser is analogous. The

Thenumnum andand varvar parsers are simple; we just give the result fromparsers are simple; we just give the result from wordword andand numbernumberto the relevantto the relevant Expr

Expr constructor.constructor. var ::

var :: ParParser Exprser Expr va

var r = = woword rd >->-> > VaVarr num ::

num :: ParParser Exprser Expr nu

num m = = nunumbmber >-> er >-> NuNumm Examples

Examples va

var r "c"couount nt + + 1" 1" -> -> JuJustst(V(Var ar "c"couountnt", ", "+ "+ 1"1")) num

num "12"123*43*456" 56" -> -> JusJust(Nt(Num um 123123, , "*4"*456"56")) The

Theexprexpr,,termtermandand factorfactorparsers are going to be mutually recursive. It may be simpler to defineparsers are going to be mutually recursive. It may be simpler to define and test such functions if one temporarily eliminates the recursion. We do it by simplifying the and test such functions if one temporarily eliminates the recursion. We do it by simplifying the factor

factor productioproduction.n. fa

factctor :: or :: nunum m | | vavar r | | "("(" " vavar r ")")""

We already have parsers for the two first alternatives. A parser for the last alternative is given We already have parsers for the two first alternatives. A parser for the last alternative is given by

by li

lit t ’(’(’ ’ -# var -# var #- lit ’)’#- lit ’)’ We conclude with

We conclude with fac

factor tor :: :: ParParser ser ExpExprr

factor = num ! var ! lit ’(’ -# var #- lit ’)’ factor = num ! var ! lit ’(’ -# var #- lit ’)’ A straightf

A straightforwarorward implemend implementation of the tation of the rule for terms rule for terms woulwould parse e.g. d parse e.g. the expressthe expression 6ion 6//33//22 as

as 66//(3(3//2) contrary to the ordinary rules. In order to get the interpretation (62) contrary to the ordinary rules. In order to get the interpretation (6 //3)3)//2 we may use2 we may use the same technique as in the definition of 

the same technique as in the definition of number’number’ with a parameter to accumulate the result.with a parameter to accumulate the result. te

termrm’ ’ :: :: ExExpr pr -> -> PaParsrser er ExExprpr term’ e =

term’ e =   m

  mululOp Op # # fafactctor or >->-> > blbldOdOp p e e #> #> tetermrm’ ’ !! ret

return urn ee The parameter

The parameter eewill be the result of the previous parser. If the input doesn’t start with awill be the result of the previous parser. If the input doesn’t start with a mulOpmulOp we just return

we just return ee. . OtheOtherwisrwisee mulmulOp Op # # facfactortor results in a pair which is given toresults in a pair which is given to bldbldOp Op ee. . TThhee transformed result is given recursively to

transformed result is given recursively to term’term’. The transformation. The transformation bldOpbldOp is defined byis defined by bl

bldOdOp p :: :: ExExpr pr -> -> (E(Expxpr r -> -> ExExpr pr -> -> ExExprpr, , ExExprpr) ) -> -> ExExprpr bl

bldOdOp p e e (o(opeper,r,e’e’) ) = = opoper er e e e’e’ Example

(11)

bl

bldOdOp p (N(Num 1) um 1) (M(Mulul, , NuNum m 2) -> 2) -> MuMul l NuNum m 1 1 NuNum m 22 The result of all this is given recursively to

The result of all this is given recursively to term’term’ which will find a newwhich will find a new mulOpmulOp or or terminterminate.ate. te

termrm’ ’ (N(Num um 1) 1) "*"*2" 2" ->-> (m

(mululOp Op # # fafactctor or >->-> > blbldOdOp p (N(Num um 1) 1) #> #> tetermrm’) ’) "*"*2" 2" ->-> (t

(tererm’ m’ (b(bldldOp Op (N(Num um 1) 1) (M(Mulul, , NuNum m 2)2))) )) "" "" ->-> (term’ (Mul (Num 1) (Num 2))) "" ->

(term’ (Mul (Num 1) (Num 2))) "" -> Jus

Just(Mt(Mul ul (Nu(Num m 1) 1) (Nu(Num m 2), "")2), "") The definition of 

The definition of termterm is simple; parse a factor and send the result tois simple; parse a factor and send the result to term’term’.. ter

term m :: :: ParParser Exprser Expr te

term rm = = fafactctor or #> #> tetermrm’’ Examples

Examples te

termrm’ ’ (N(Num um 1) 1) "" "" -> -> JuJustst(N(Num um 1, 1, """")) te

term rm "1"1*2*2" " -> -> JuJustst(M(Mul ul (N(Num um 1) 1) (N(Num um 2)2), , """")) te

term rm "6"6/3/3/2/2" " -> -> JuJustst(D(Div iv (D(Div iv (N(Num um 6) 6) (N(Num um 3)3)) ) (N(Num um 2)2), , """")) The definitions of 

The definitions of expr’expr’ andand exprexpr are are analogouanalogous.s. ex

exprpr’ ’ :: :: ExExpr pr -> -> PaParsrser er ExExprpr expr’ e =

expr’ e = ad

addOdOp p # # teterm rm >->-> > blbldOdOp p e e #> #> exexprpr’ ’ !! ret

return urn ee exp

expr r :: :: ParParser Exprser Expr ex

expr pr = = teterm rm #> #> exexprpr’’ We may now compose the

We may now compose the factorfactor,, termterm andand exprexpr parsers resetting the first one to make themparsers resetting the first one to make them mutually recursive. mutually recursive. fac factor tor == num ! num ! var ! var !

lit ’(’ -# expr #- lit ’)’ ! lit ’(’ -# expr #- lit ’)’ ! err

err "ille"illegal gal factfactor"or" term’ e =

term’ e =   m

  mululOp Op # # fafactctor or >->-> > blbldOdOp p e e #> #> tetermrm’ ’ !! ret

return urn ee te

term rm = = fafactctor or #> #> tetermrm’’ expr’ e =

expr’ e = ad

addOdOp p # # teterm rm >->-> > blbldOdOp p e e #> #> exexprpr’ ’ !! ret

return urn ee ex

expr pr = = teterm rm #> #> exexprpr’’

We have added another alternative parser in

We have added another alternative parser in factorfactor in order to get an informative message forin order to get an informative message for illegal input. Without it, any invalid string argument will just return

illegal input. Without it, any invalid string argument will just return NothingNothing.. The

The errerr parser is defined byparser is defined by er

err r :: :: StStriring ng -> -> PaParsrser er aa er

(12)

It will print the message and the offending input and abort the computation. It will print the message and the offending input and abort the computation.

Exer

Exercise cise 1515 Define a parser Define a parser reqrequiruire e :: :: StrString -> ing -> ParParser aser a that behaves asthat behaves as acceptaccept but emitsbut emits

an error message instead of returning 

an error message instead of returning NothingNothing.. Program structure

Program structure The program parts that

The program parts that we havwe have developed so far e developed so far should be divided into two parser modules andshould be divided into two parser modules and one expres

one expression module. sion module. The first parser module should contThe first parser module should contain the parser type, the basic parsersain the parser type, the basic parsers and parser operators, while the second one contains derived parsers and parser operators. The and parser operators, while the second one contains derived parsers and parser operators. The representation of parsers as values of type

representation of parsers as values of type StrinString g -> -> MaybMaybe(a, String)e(a, String) will not be exploitedwill not be exploited outside the first parser module.

outside the first parser module.

Since we are going to define parsers for more than one data type it is useful to have a type class Since we are going to define parsers for more than one data type it is useful to have a type class decla

declaring the ring the namesnamesparseparseandand toStringtoStringand definingand defining fromStringfromString. We can then use these names. We can then use these names for all the data types and the relevant one will be chosen using the context where the name is for all the data types and the relevant one will be chosen using the context where the name is used. We use the name

used. We use the name ParseParse for the type class.for the type class.

It is inconvenient to use qualified import for the parser module, so we refrain from giving the It is inconvenient to use qualified import for the parser module, so we refrain from giving the parser type

parser type the the convconvententional nameional name TT..

  mod

  module ule CoreCoreParsParser(Per(Parsearser, r, charchar, , retureturn, rn, failfail, , (#), (!), (#), (!), (?), (#>), (?), (#>), (>->(>->),), Pars

Parse, e, parsparse, e, toSttoStringring, , fromfromStriString) ng) wherwheree impo

import rt PrelPrelude ude hidihiding ng (ret(return, urn, failfail)) in infifixl xl 3 3 !! in infifixl xl 7 7 ?? in infifixl xl 6 6 ## in infifixl xl 5 5 >->->> in infifixl xl 4 4 #>#> cla

class ss ParParse se a a whewherere pa

parsrse e :: :: PaParsrser er aa fro

fromStmStriring ng :: :: StrString ing -> -> aa fro

fromStmStriring ng cs cs == ca

case se paparsrse e cs cs ofof Ju

Justst(s(s, , [][]) ) -> -> ss Just

Just(s, (s, cs) cs) -> -> erroerror r ("ga("garbagrbage e ’"++’"++cs++cs++"’")"’") Noth

Nothing ing -> -> erroerror r "Not"Nothinghing"" to

toStStriring ng :: :: a a -> -> StStriringng

ty

type pe PaParsrser er a a = = StStriring ng -> -> MaMaybybe e (a(a, , StStriringng))

cha

char r :: :: ParParser ser ChCharar cha

char r [][]= = NotNothinhingg ch

char ar (c(c:c:cs) s) = = JuJust st (c(c, , cscs))

re

retuturn :: rn :: a a -> -> PaParsrser aer a re

retuturn rn a a cs cs = = JuJust st (a(a, , cscs))

f

faiail :: l :: PaParrseser ar a fa

(13)

(!

(!) ) :: :: PaParsrser er a a -> -> PaParsrser er a a -> -> PaParsrser er aa (m ! n) cs = case m cs of

(m ! n) cs = case m cs of No

Noththining g -> -> n n cscs   m

  mcs cs -> -> mcmcss

(?

(?) ) :: Par:: Parseser r a a -> (a -> (a -> -> BoBoolol) ) -> Par-> Parseser r aa (m ? p) cs =

(m ? p) cs = case m cs of case m cs of Noth

Nothing ing -> -> NothNothinging Ju

Justst(r(r, , s) s) -> -> if if p p r r ththen en JuJustst(r(r, , s) s) elelse se NoNoththiningg

(#

(#) ) :: :: PaParsrser er a a -> -> PaParsrser er b b -> -> PaParsrser er (a(a, , b)b) (m # n) cs =

(m # n) cs = case m cs of case m cs of Noth

Nothing ing -> -> NothNothinging Jus

Just(at(a, , cs’cs’) ) ->-> ca

case n se n cscs’ ’ ofof Noth

Nothing ing -> -> NothNothinging Jus

Just(bt(b, , cs’cs’’) ’) -> -> JuJust(st((a, (a, b), b), cscs’’)’’)

(>

(>->->) ) :: Par:: Parseser r a a -> (a -> (a -> b) -> b) -> -> PaParsrser ber b (m >-> b) cs =

(m >-> b) cs = case m cs of case m cs of Jus

Just(at(a, , cs’cs’) ) -> -> JuJust(st(b b a, a, cs’cs’)) Noth

Nothing ing -> -> NothNothinging

(#

(#>) >) :: :: PaParsrser er a a -> -> (a (a -> -> PaParsrser er b) b) -> -> PaParsrser er bb (p #> k) cs =

(p #> k) cs = case p cs of case p cs of Noth

Nothing ing -> -> NothNothinging Ju

Justst(a(a, , cscs’) ’) -> -> k k a a cscs’’

The derived parsers appear in

The derived parsers appear in Parser.hsParser.hs..   modu

  module le ParseParser(modr(module ule CoreCoreParseParser, r, digitdigit, , digidigitVal, tVal, charschars, , letteletter, r, err,err, lit, number,

lit, number, iteriter, , accepaccept, t, requirequire, re, tokentoken,, spa

spacesces, , worword, d, (-#(-#), ), (#-(#-)) )) whewherere impo

import rt PreluPrelude de hidinhiding g (retu(return, rn, fail)fail) import CoreParser import CoreParser in infifixl xl 7 7 -#-#, , #- #-type T a = Parser a type T a = Parser a er

err r :: :: StStriring ng -> -> PaParsrser er aa err

err mesmessagsage e cs cs = = errerror or (me(messassage+ge++" +" neanear r "++"++cs+cs++"\+"\n")n") it

iter er :: :: PaParsrser er a a -> -> PaParsrser er [a[a]]

iter m = m # iter m >-> cons ! return [] iter m = m # iter m >-> cons ! return [] co

consns(a(a, , b) b) = = a:a:bb .

(14)

The expression module will have a few other functions not mentioned previously. We rename the The expression module will have a few other functions not mentioned previously. We rename the main type to

main type to TT. The. The valuevalue function should evalufunction should evaluate an ate an expreexpression. ssion. It will It will need a need a “dicti“dictionary”onary” to find the values of the variables.

to find the values of the variables.

The expression module will make heavy use of the parser functions so it is convenient to import The expression module will make heavy use of the parser functions so it is convenient to import the parser module without qualification.

the parser module without qualification.   modu

  module le Expr(Expr(Expr, T, Expr, T, parsparse, e, fromSfromStringtring, , valuvalue, e, toStrtoString) ing) wherewhere impo

import rt PreluPrelude de hidinhiding g (retu(return, rn, fail)fail) impo

import rt ParseParserr impo

import rt qualiqualified fied DictiDictionaronaryy da

data ta ExExpr pr = = NuNum m InIntetegeger r | | VaVar r StStriring ng | | AdAdd d ExExpr pr ExExprpr |

| SuSub b ExExpr pr ExExpr pr | | MuMul l ExExpr pr ExExpr pr | | DiDiv v ExExpr pr ExExprpr deriv

deriving ing ShowShow ty

type T pe T = = ExExprpr ... ... inst

instance Parse ance Parse Expr whereExpr where par

parse se = = expexprr to

toStStriring ng = = shshw w 00

Parsing with ambiguous grammars Parsing with ambiguous grammars This descri

This description is mainly inspired by an ption is mainly inspired by an articlarticle by e by Phil WPhil Wadler, [4]. adler, [4]. He uses an He uses an eleganelegant trickt trick to code

to code the failthe failure and the ure and the sucsuccescess s of a of a parparser and findinser and finding g all possiall possible parsble parses of es of a a stristring. ng. TheThe Maybe

Maybe data type may be viewed as a special case of the list type, but with the list either beingdata type may be viewed as a special case of the list type, but with the list either being empty,

empty, NothingNothing, or having one element,, or having one element, JuJust st aa. . FFailuailure will be re will be reprepresresenented by the ted by the empempty listty list while a nonempty list contains all possible successes. He defines the parser type by

while a nonempty list contains all possible successes. He defines the parser type by typ

type e ParParser ser a a = = StrString -> ing -> [(a[(a,St,Strinring)]g)] As an example the number parser will find As an example the number parser will find

number "123abc"

number "123abc" -> -> [(123,"abc"),(1[(123,"abc"),(12,"3abc"),(1,"232,"3abc"),(1,"23abc")]abc")] num

number "abc" -> ber "abc" -> [][] A

A few modificfew modificatiations are ons are neeneeded in ded in the Parsthe Parser moduleer module. . The basiThe basic c parparser musser must t be be chchanganged toed to return lists instead of 

return lists instead of MaybeMaybe values.values. char [] = []

char [] = [] cha

char r (c:(c:cs) cs) = = [(c[(c,cs,cs)])] re

retuturn rn a a cs cs = = [([(a,a,cscs)])] fail cs = []

fail cs = []

The operators must also be adapted. Using list comprehension they become “one-liners” The operators must also be adapted. Using list comprehension they become “one-liners”

(m ? p) cs = [(a,cs’) | (a,cs’) <- m cs, p a] (m ? p) cs = [(a,cs’) | (a,cs’) <- m cs, p a] (m ! n) cs = (m cs) ++ (n cs)

(15)

(m

(m # # n) n) cs cs = = [([((a(a,b,b),),cscs’’’’) ) | | (a(a,c,cs’s’) ) <- <- m m cscs, , (b(b,c,cs’s’’) <- ’) <- n n cscs’]’] (m >-> b) cs = [(b a, cs’) | (a,cs’) <- m cs]

(m >-> b) cs = [(b a, cs’) | (a,cs’) <- m cs] (p

(p #> #> k) k) cs cs = = [([(b,b,cscs’’’’) ) | | (a(a,c,cs’s’) ) <- <- p p cscs, , (b(b,c,cs’s’’) ’) <- k <- k a a cscs’]’] The

The errerr and hence theand hence the requirerequire parsers can no longer be used inparsers can no longer be used in ExprExpr andand ProgramProgram to giveto give adequate error messages.

adequate error messages. Parsec

Parsec

There is a “industrial stength” parser library called

There is a “industrial stength” parser library called ParsecParsec, , [2[2]. ]. It useIt uses basis basicacalllly the samy the samee technique as above, but is larger and uses

technique as above, but is larger and uses dodo notation notation extensextensiveivelyly. . An An expreexpression parser usingssion parser using this

this library follows.library follows. impo

import rt ParseParsecc import ParsecExpr import ParsecExpr da

data ta ExExpr pr = = NuNum m InInt t | | VaVar r StStriring | ng | AdAdd d ExExpr pr ExExprpr |

| SuSub b ExExpr pr ExExpr pr | | MuMul l ExExpr pr ExExpr pr | | DiDiv v ExExpr pr ExExprpr deriv

deriving ing ShowShow e

exxppr r ::: : PPaarrsseer r EExxpprr ex

expr pr = b= buiuildldExExprpresessisiononPaParsrser er tatablble fe facactotorr <?>

<?> "expr"expressioession"n" ta

tablble e = [[op "*= [[op "*" " MuMul Assol AssocLcLefeft, op "/" Div Ast, op "/" Div AssosocLcLefeft]t],, [op "+"

[op "+" Add AssocAdd AssocLefLeft, t, op op "-" Sub "-" Sub AssAssocLocLefteft]]]] where

where

op s f assoc op s f assoc

=

= InInfifix x (d(do{ stro{ strining g s; rets; retururn n f}f}) ) asassosocc fa

factctor or = do= do{ cha{ char ’(’r ’(’ ; x <- expr ; x <- expr ; ; chchar ’)’ar ’)’ ; ; reretuturn rn x}x} <|> <|> numbnumberer <|>

<|> varivariableable <?>

<?> "sim"simple ple exprexpressioession"n" nu

numbmber er :: Pa:: Parsrser Exer Exprpr nu

numbmber er = do{ ds<= do{ ds<- many- many1 dig1 digitit ;

; retreturn urn (Nu(Num m (re(read ad ds)ds))})} <?>

<?> "num"number"ber" var

variabiable le :: :: ParParser ser ExpExprr var

variabiable le = = do{ ds<- do{ ds<- manmany1 y1 letletterter ;

; retreturn (Var urn (Var ds)ds)}} <?>

<?> "var"variableiable""

The library has special support for

The library has special support for parsinparsing expressiog expressions. ns. Operator precedeOperator precedences and associativnces and associativ--ities are given using a table.

ities are given using a table. dodo notation is used to express sequential composition of parsers.notation is used to express sequential composition of parsers. Alternatives are separated by

(16)

References References

[1] Hutton, G. and Meier, E.,

[1] Hutton, G. and Meier, E., Monadic Parser CombinatorsMonadic Parser Combinators, Technical report NOTTCS-TR-, Technical report NOTTCS-TR-96-4, Department of Computer Science, University of Nottingham, 1996.

96-4, Department of Computer Science, University of Nottingham, 1996. [2] Leijen, D.,

[2] Leijen, D., Parsec, a fast combinator parser Parsec, a fast combinator parser , Oct 2001,, Oct 2001, http://www.cs.ruu.nl/˜daan/parsec.html.

http://www.cs.ruu.nl/˜daan/parsec.html. [3] Wadler P.,

[3] Wadler P., How to replace failure by a list of successesHow to replace failure by a list of successes, 2nd International Conference on Func-, 2nd International Conference on Func-tional

tional ProgrammProgramming ing LanguagLanguages es and and ComputComputer er ArchArchitectuitecture, re, SpringSpringer-Ver-Verlag, erlag, Nancy Nancy FFrance,rance, September 1985. http://cm.bell-labs.com/cm/cs/who/wadler/.

September 1985. http://cm.bell-labs.com/cm/cs/who/wadler/. [4] Wadler, P.,

[4] Wadler, P., Monads for functional programming Monads for functional programming , Marktoberdorf Summer School on Program, Marktoberdorf Summer School on Program Design Calculi, Springer Verlag, NATO ASI Series F: Computer and systems sciences, Volume Design Calculi, Springer Verlag, NATO ASI Series F: Computer and systems sciences, Volume 118, August 1992. http://cm.bell-labs.com/cm/cs/who/wadler/.

References

Related documents

The objec- tives of this randomized, controlled, multicenter study (the neo.nEURO. network trial) were (1) to determine whether induction of systemic hypo- thermia to 33°C to 34°C

GAVI: Global Alliance on Vaccines Initiative; GFATM: Global Fund to fight AIDS, Tuberculosis and Malaria; TTR: Treat, Train and Retain Initiative; WHO: World Health Organization;

The primary outcome measure of disability was a disease-specific outcome measure, the Western Ontario Rotator Cuff (WORC) index, and independent variables were sex, age,

You may want a friend or another person to help you prepare your case and be with you at court to support you, or you might want to bring someone who is not a solicitor or barrister

Cloud bursting is an application deployment model in which an application runs in a private cloud or data centre and &#34;bursts&#34; to a public cloud when the

Staphylococcus epidermidis isolates investigated harboring novel ACME types 365. a Abbreviations: PD; periodontal disease, HWI; healthy patients with implants, OH; orally

In synthetic- diet-reared silkworms, integumentary carbonic anhydrase changes between the fifth instar and the middle moulting fluid stage such that Cl~, which was without effect in