-
Notifications
You must be signed in to change notification settings - Fork 0
/
parser.hs
138 lines (106 loc) · 3.5 KB
/
parser.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
module Parser where
import Data.List
import Control.Applicative
import Prelude hiding (Num)
newtype Parser a = Parser (String -> [(String, a)])
parse :: Parser a -> String -> [(String, a)]
parse (Parser px) ts = px ts
item :: Parser Char
item = Parser (\ts -> case ts of
[] -> []
(t:ts') -> [(ts', t)])
instance Functor Parser where
--fmap :: (a -> b) -> Parser a -> Parser b
fmap f (Parser px) = Parser (\ts -> [(ts', f x) | (ts', x) <- px ts])
instance Applicative Parser where
--pure :: a -> Parser a
pure x = Parser (\ts -> [(ts, x)])
--(<*>) :: Parser (a -> b) -> Parser a -> Parser b
Parser pf <*> Parser px = Parser (\ts -> [(ts'', f x) | (ts', f) <- pf ts,
(ts'', x) <- px ts'])
-- (<:>) :: Applicative f => f a -> f [a] -> f [a]
px <:> pxs = (:) <$> px <*> pxs
instance Alternative Parser where
--empty :: Parser a
empty = Parser (\ts -> [])
--(<|>) :: Parser a -> Parser a -> Parser a
Parser px <|> Parser py = Parser (\ts -> px ts ++ py ts)
instance Monad Parser where
--return :: a -> Parser a
return = pure
--(>>=) :: Parser a -> (a -> Parser b) -> Parser b
Parser px >>= f = Parser (\ts -> concat [parse (f x) ts' | (ts', x) <- px ts])
satisfy :: (Char -> Bool) -> Parser Char
satisfy p = item >>= \t -> if p t then pure t else empty
char :: Char -> Parser Char
char c = satisfy (c ==)
oneOf :: [Char] -> Parser Char
oneOf = satisfy . flip elem
string :: String -> Parser String
string [] = return ""
string (c:cs) = char c <:> string cs
whitespace :: Parser ()
whitespace = many (oneOf [' ', '\t']) *> pure ()
tok :: String -> Parser String
tok xs = whitespace *> string xs <* whitespace
num :: Parser Integer
num = read <$> some (oneOf ['0' .. '9']) <* whitespace
var :: Parser String
var = some (oneOf ['a' .. 'z']) <* whitespace
-- syntactic categories Num and Var
type Num = Integer
type Var = String
-- semantic types Z and T
type Z = Integer
type T = Bool
data Aexp = Num Num
| Var Var
| Mult Aexp Aexp
| Add Aexp Aexp
| Sub Aexp Aexp
deriving (Show, Eq, Read)
data Bexp = TRUE
| FALSE
| Neg Bexp
| And Bexp Bexp
| Eq Aexp Aexp
| Less Aexp Aexp
deriving (Show, Eq, Read)
data Stm = Skip
| Ass Var Aexp
| Comp Stm Stm
| If Bexp Stm Stm
| While Bexp Stm
deriving (Show, Eq, Read)
-- The while language is a parser of |Stm| terms. We allow multiple
-- semi-colons at the top level.
while :: Parser Stm
while = stms
precedence :: [Parser (a -> a -> a)] -> Parser a -> Parser a
precedence ops arg = foldl' build arg ops
where build term ops = chainl term ops
aexp = precedence [Mult <$ tok "*"
,Add <$ tok "+" <|> Sub <$ tok "-"]
( Num <$> num
<|> Var <$> var
<|> tok "(" *> aexp <* tok ")")
bexp :: Parser Bexp
bexp = precedence [And <$ tok "&"]
( TRUE <$ tok "true"
<|> FALSE <$ tok "false"
<|> Eq <$> aexp <* tok "=" <*> aexp
<|> Less <$> aexp <* tok "<=" <*> aexp
<|> Neg <$ tok "!" <*> bexp
<|> tok "(" *> bexp <* tok ")")
stms :: Parser Stm
stms = chainl stm (Comp <$ tok ";")
stm = Ass <$> var <* tok ":=" <*> aexp
<|> Skip <$ tok "skip"
<|> If <$ tok "if" <*> bexp <* tok "then" <*> stm <* tok "else" <*> stm
<|> While <$ tok "while" <*> bexp <* tok "do" <*> stm
<|> tok "(" *> stms <* tok ")"
chainl p op = p >>= rest where
rest x = do f <- op
y <- p
rest (f x y)
<|> return x