The document describes how to build a parser for Backus-Naur Form (BNF) grammars in Haskell using the attoparsec parsing library. It defines types and parsers to represent BNF syntax, rules, expressions, lists and terms. The parsers use functions like spaces, string, text from attoparsec to parse individual components and combine them using operators like <*>, <|> to build up the full BNF grammar parser.
59. • BNF( )
expr ::= term ‘+’ expr | term
term ::= factor ‘*’ term | factor
factor ::= ‘(‘ expr ‘)’ | nat
nat ::= ‘0’ | ‘1’ | ‘2’ | ...
60. • BNF( )
expr ::= term ‘+’ expr | term
term ::= factor ‘*’ term | factor
→
61. •BNF 1
-- expr ::= term ‘+’ expr | term
expr :: Parser Int
expr = do t <- (term :: Parser Int)
symbol “+”
e <- (expr :: Parser Int)
return (t + e)
+++ term
62. •BNF 2
-- term ::= factor ‘*’ term | factor
term :: Parser Int
term = do f <- (factor :: Parser Int)
symbol “*”
t <- (term :: Parser Int)
return (f * t)
+++ factor
63. •BNF 3
-- factor ::= ‘(‘ expr ‘)’ | nat
factor :: Parser Int
factor = do symbol “(“
e <- (expr :: Parser Int)
symbol “)”
return e
+++ natural
70. {-# LANGUAGE OverloadedStrings #-}
module BNFParser where
import Data.Attoparsec.Text
import Data.Text.Internal (Text)
import Data.Text as T
import Control.Applicative hiding(many)
71. BNF
type BNF = Syntax
type Syntax = [Rule]
data Rule = Rule Text Expr
type Expr = [List]
type List = [Term]
data Term = Lit Text | RuleName Text
72. BNF (10 !)
syntax = many1 rule
rule = Rule <$> (spaces *> "<" .*> text '>' <*. ">") <* spaces
<* string "::=" <* spaces <*> expression <* line_end
spaces = T.pack <$> many (char ' ')
expression = sepBy1 list (spaces *> string "|" <* spaces)
line_end = many1 $ spaces *> endOfLine
list = sepBy1 term spaces
term = Lit <$> literal <|> RuleName <$> "<" .*> text '>' <*. ">"
literal = "'" .*> text ''' <*. "'" <|> """ .*> text '"' <*. """
text c = takeTill (==c)