-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparser.hs
206 lines (176 loc) · 6.07 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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
module Parser where
import System.IO
import Control.Monad
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Expr
import Text.ParserCombinators.Parsec.Language
import qualified Text.ParserCombinators.Parsec.Token as Token
-- Part 2
-- Data type for arithmetic expressions
data Aexp
= VarAexp String -- Variable
| NumAexp Int -- Integer constant
| AddAexp Aexp Aexp -- Addition
| SubAexp Aexp Aexp -- Subtraction
| MulAexp Aexp Aexp -- Multiplication
deriving Show
-- Data type for boolean expressions
data Bexp
= BoolConst Bool -- Boolean constant False
| IntEq Aexp Aexp -- Equality
| IntIneq Aexp Aexp -- Inequality
| BoolEq Bexp Bexp -- Boolean Equality
| BoolAnd Bexp Bexp -- Boolean And
| Not Bexp -- Negation
deriving Show
-- Data type for statements
data Stm
= Assign String Aexp -- Assignment: x := a
| Seq [Stm] -- Sequence: various instructions
| If Bexp Stm Stm -- Conditional: if b then instr1 else instr2
| While Bexp Stm -- Loop: while b do instr
| Skip -- Skip: Does Nothing - Just a useful statement
deriving Show
type Program = [Stm]
-- Defines the language syntax
languageDef =
emptyDef {
Token.identStart = letter
, Token.identLetter = alphaNum
, Token.reservedNames = [ "if"
, "then"
, "else"
, "while"
, "do"
, "True"
, "False"
, "not"
, "and"
]
, Token.reservedOpNames = ["+", "-", "*", ":="
, "<=", "and", "not"
]
}
-- Lexer for the language
lexer = Token.makeTokenParser languageDef
-- Parsers for different components
identifier = Token.identifier lexer -- parses an identifier
reserved = Token.reserved lexer -- parses a reserved name
reservedOp = Token.reservedOp lexer -- parses an operator
parens = Token.parens lexer -- parses surrounding parenthesis:
integer = Token.integer lexer -- parses an integer
semi = Token.semi lexer -- parses a semicolon
whiteSpace = Token.whiteSpace lexer -- parses whitespace
-- Top-level parser for the language
whileParser :: Parser Stm
whileParser = whiteSpace >> statement
-- Parser for the statements
statement :: Parser Stm
statement = parens statement
<|> sequenceOfStm
-- Parser for sequences of statements
sequenceOfStm =
do list <- sepBy statement' semi
return $ if length list == 1 then head list else Seq list
-- Parser for a statement
statement' :: Parser Stm
statement' = ifStm
<|> whileStm
<|> assignStm
<|> (try (lookAhead (string "else")) >> return Skip)
<|> (try (string "" >> notFollowedBy alphaNum) >> return Skip)
-- Parser for If statements
ifStm :: Parser Stm
ifStm = do
reserved "if"
cond <- bExpression
reserved "then"
stmt1 <- statement
reserved "else"
stmt2 <- ifElseParser
return $ If cond stmt1 stmt2
-- Parser for optional Else clause in If statements
ifElseParser :: Parser Stm
ifElseParser = whileStm <|> ifStm <|> assignStm <|> parens statement
-- Parser for While statements
whileStm :: Parser Stm
whileStm =
do reserved "while"
cond <- bExpression
reserved "do"
stmt <- statement
return $ While cond stmt
-- Parser for Assignment statements
assignStm :: Parser Stm
assignStm =
do var <- identifier
reservedOp ":="
expr <- aExpression
return $ Assign var expr
-- Parser for Arithmetic expressions
aExpression :: Parser Aexp
aExpression = buildExpressionParser aOperators aTerm
-- Parser for Boolean expressions
bExpression :: Parser Bexp
bExpression = buildExpressionParser bOperators bTerm
-- Operator precedence and associativity for Arithmetic expressions
aOperators = [ [Infix (reservedOp "*" >> return MulAexp) AssocLeft]
, [Infix (reservedOp "+" >> return AddAexp) AssocLeft,
Infix (reservedOp "-" >> return SubAexp) AssocLeft]
]
-- Operator precedence and associativity for Boolean expressions
bOperators = [ [Prefix (reservedOp "not" >> return Not ) ]
, [Infix (reservedOp "=" >> return BoolEq) AssocLeft]
, [Infix (reservedOp "and" >> return BoolAnd) AssocLeft]
]
-- Parser for atomic Arithmetic expressions
aTerm = parens aExpression
<|> liftM VarAexp identifier
<|> liftM (NumAexp . fromIntegral) integer
-- Parser for atomic Boolean expressions
bTerm = parens bExpression
<|> (reserved "True" >> return (BoolConst True))
<|> (reserved "False" >> return (BoolConst False))
<|> try intEqExpression
<|> try intIneqExpression
-- Parser for Addition expressions
addExpression :: Parser Aexp
addExpression =
do a1 <- aExpression
reservedOp "+"
a2 <- aExpression
return $ AddAexp a1 a2
-- Parser for Subtraction expressions
subExpression :: Parser Aexp
subExpression =
do a1 <- aExpression
reservedOp "-"
a2 <- aExpression
return $ SubAexp a1 a2
-- Parser for Multiplication expressions
mulExpression :: Parser Aexp
mulExpression =
do a1 <- aExpression
reservedOp "*"
a2 <- aExpression
return $ MulAexp a1 a2
-- Parser for Integer Equality expressions
intEqExpression :: Parser Bexp
intEqExpression = do
a1 <- aExpression
reservedOp "=="
a2 <- aExpression
return $ IntEq a1 a2
-- Parser for Integer Inequality expressions
intIneqExpression :: Parser Bexp
intIneqExpression = do
a1 <- aExpression
reservedOp "<="
a2 <- aExpression
return $ IntIneq a1 a2
-- Entry point for parsing a program
parse :: String -> Program
parse str =
case Text.ParserCombinators.Parsec.parse whileParser "" str of
Left e -> error $ show e
Right r -> [r]