-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathPR10_ProceduralParser.hs
232 lines (189 loc) · 5.01 KB
/
PR10_ProceduralParser.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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
module PR10_ProceduralParser where
import Text.ParserCombinators.Parsec
import PR10_ProceduralLang
-- UTILS
number :: Parser Int
number = do
s <- option "" (string "-")
ds <- many1 digit
return $ read (s ++ ds)
infOp :: String -> (a -> a -> a) -> Parser (a -> a -> a)
infOp x f = string x >> return f
lexem :: Parser a -> Parser a
lexem p = do { a <- p; spaces; return a}
reserved :: String -> Parser ()
reserved s = do { _ <- string s; spaces }
parens :: Parser a -> Parser a
parens p = do {reserved "("; n <- lexem p; reserved ")"; return n}
int :: Parser Exp
int = do {n <- lexem number; return (Const n)}
latinAlf :: String
latinAlf = ['A'..'Z'] ++ ['a'..'z']
nums :: String
nums = ['0'..'9']
firstLetter :: String
firstLetter = latinAlf
subseqLetter :: String
subseqLetter = latinAlf ++ nums ++ "_$#@"
idf :: Parser String
idf = do
st <- oneOf firstLetter
nx <- many (oneOf subseqLetter)
return (st:nx)
idp :: Parser Exp
idp = do
st <- lexem idf
return (Var st)
-- ARITHMETIC
addopA, mulopA :: Parser (Exp -> Exp -> Exp)
addopA = infOp "+" (OpApp Add) <|> (infOp "-"(OpApp Minus))
mulopA = infOp "*"(OpApp Mul)
cmpOpA = infOp "==" (OpApp Equal)
<|> infOp "<" (OpApp Less)
-- EXPRESSIONS
exprA, termA, factorA :: Parser Exp
factorA = int <|> try funcApp <|> try indexExp <|> idp <|> parens exprA
termA = chainl1 factorA (lexem mulopA)
eqTermA = chainl1 termA (lexem addopA)
exprA = condExp (chainl1 eqTermA (lexem cmpOpA))
condExp :: Parser Exp -> Parser Exp
condExp p = do
expr <- p
cond expr <|> return expr
where
cond expr = do
reserved "?"
thenV <- condExp p
reserved ":"
elseV <- condExp p
return (Cond expr thenV elseV)
funcApp :: Parser Exp
funcApp = do
nm <- lexem idf
args <- callArgs
return (FunApp nm args)
indexOp :: Parser Exp
indexOp = do
reserved "["
ix <- exprA
reserved "]"
return ix
indexExp :: Parser Exp
indexExp = do
nm <- lexem idf
ix <- indexOp
return (OpApp Index (Var nm) ix)
callArgs :: Parser [Exp]
callArgs = parens (option [] (commaSep exprA))
varDef :: Parser VarDef
varDef = do
nm <- idf
mbA <- optionMaybe (string "[]")
return (case mbA of
Nothing -> (Int nm)
(Just _) -> (Arr nm))
-- SEQUENCE
data SeqEx a = Lit a | Seq (SeqEx a) (SeqEx a)
seqToList :: SeqEx a -> [a]
seqToList (Lit x) = [x]
seqToList (Seq x y) = seqToList x ++ seqToList y
commaSep :: Parser a -> Parser [a]
commaSep p = do
seq <- chainl1 (Lit <$> (lexem p)) (lexem (infOp "," Seq))
return (seqToList seq)
commaSepOpt :: Parser a -> Parser [a]
commaSepOpt p = option [] (commaSep p)
-- STATEMENTS
semicolon :: Parser a -> Parser a
semicolon p = do { v <- lexem p; reserved ";"; return v}
statement :: Parser Stmt
statement = try whileSt <|> try callSt <|> assignSt <|> blockSt
assignSt :: Parser Stmt
assignSt = do
nm <- lexem idf
mbIx <- optionMaybe indexOp
reserved "="
ex <- exprA
return (case mbIx of
Nothing -> Assign nm ex
(Just ix) -> AssignA nm ix ex)
whileSt :: Parser Stmt
whileSt = do
reserved "while"
cnd <- parens exprA
sm <- statement
return (While cnd sm)
callSt :: Parser Stmt
callSt = do
reserved "call"
nm <- lexem idf
args <- callArgs
return (Call nm args)
blockSt :: Parser Stmt
blockSt = do
reserved "{"
vars <- many (try (semicolon varDef))
stmts <- sepBy statement (reserved ";")
reserved "}"
return (Block vars stmts)
-- FUNCTION DEFINITION
funcDef :: Parser FunDef
funcDef = do
reserved "func"
nm <- lexem idf
vars <- parens (commaSep varDef)
reserved "="
ex <- exprA
return (nm, (vars, ex))
-- PROCEDURE DEFINITION
procDef :: Parser ProcDef
procDef = do
reserved "proc"
nm <- lexem idf
vars <- parens (commaSepOpt varDef)
sm <- statement
return (nm, (vars, sm))
full :: Parser a -> Parser a
full p = do { _ <- spaces; v <- p; eof; return v}
-- TESTS
dfSumA :: String
dfSumA = "func sumA(a[],n) = (n<0 ? 0 : a[n] + sumA (a,n-1))"
dfFib :: String
dfFib = "func fib(n) = (n<3 ? 1 : fib(n-1) + fib(n-2))"
dpGAdd :: String
dpGAdd = "proc gAdd(x,y) gSum = x + y "
dpSumA1 :: String
dpSumA1 = "proc sumA1(a[],n) {i;limit;"
++ "sA=0; i=0; limit=n+1;"
++ "while (i<limit){sA=sA+a[i]; i=i+1}"
++ "}"
dPr1 :: String
dPr1 = "gSum; "
++ "proc gAdd(x,y) gSum = x + y "
++ "proc main() call gAdd(5,10) "
dPr2 :: String
dPr2 = "sA;"
++"proc sumA1(a[],n) {i;limit;"
++ "sA=0; i=0; limit=n+1;"
++ "while (i<limit){sA=sA+a[i]; i=i+1}"
++ "}"
++ "proc main() {b[]; b[0]=9; b[2]=5; b[3]=7; b[5]=1;"
++ "call sumA1 (b,5)"
++ "}"
prog :: Parser Program
prog = do
vars <- many (try (semicolon varDef))
fns <- many funcDef
procs <- many procDef
return (vars, fns, procs)
parseOrThrow :: Parser a -> String -> a
parseOrThrow p str =
case parse ((full) p) "" str of
(Left x) -> error (show x)
(Right x) -> x
-- parseOrThrow funcDef dfSumA == sumA
-- parseOrThrow funcDef dfFib == fib
-- parseOrThrow procDef dpGAdd == gAdd
-- parseOrThrow procDef dpSumA1 == sumA1
-- parseOrThrow prog dPr1 == pr1
-- parseOrThrow prog dPr2 == pr2