-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathInterpreter.hs
More file actions
379 lines (334 loc) · 9.99 KB
/
Interpreter.hs
File metadata and controls
379 lines (334 loc) · 9.99 KB
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
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
module Interpreter
( interpreter
) where
import qualified Data.Set as Set (
Set(..)
, difference
, findMax
, findMin
, fold
, fromList
, intersection
, map
, member
, null
, size
, toAscList
, toDescList
, union
)
import Data.Maybe (fromJust)
import Data.List (elemIndex)
import Control.Monad.Trans (lift)
import Control.Monad.Trans.State (StateT, get, put, evalStateT)
import System.IO (hFlush, stdout)
import Tokens (Pos(..), isTokenError, printError)
import Lexer (alexScanTokens)
import AST(
Direction(..)
, Exp(..)
, Inst(..)
, Id(..)
, BinOp(..)
, UnOp(..)
, Type(..)
)
import Parser (parsr)
import SymbolTable (
Variable(..)
, SymbolTable(..)
, update
, deepLookup
, deepUpdate
, varType
)
import Scoper (scoper'')
type Executor a = StateT [SymbolTable] IO a
interpreter :: String -> String -> IO ()
interpreter text name = do
putStrLn $ "Interpreter (" ++ name ++ "):\n"
let toks = alexScanTokens text
if any isTokenError toks
then mapM_ printError $ filter isTokenError toks
else let scope = scoper'' . parsr $ toks
in case scope of
Left error -> putStr error
Right st -> interpret st
putStrLn ""
interpret :: SymbolTable -> IO ()
interpret st@(SymbolTable _ _ d [i]) =
case i of
(Block _ _ _) -> evalStateT (execute i) [head d, st]
_ -> evalStateT (execute i) [st]
maybeRead :: Read a => String -> Maybe a
maybeRead s =
case reads s of
[(x, "")] -> Just x
_ -> Nothing
execute :: Inst -> Executor ()
-- Assign Instruction --
execute (Assign (Id name _) value pos) =
do
sts <- get
let sts' = deepUpdate name (evaluate sts value) sts
put sts'
-- Block Instruction --
execute (Block declares insts pos) =
do
sts <- get
execAll sts insts insts
where
execAll sts insts [] = return ()
execAll sts insts (i:is) = do
sts <- get
execute' sts insts i
execAll sts insts is
execute' :: [SymbolTable] -> [Inst] -> Inst -> Executor ()
execute' sts insts b@(Block _ _ _) = do
put $ ((daughters $ head sts) !! (fromJust $ elemIndex b insts')):sts
execute b
sts <- get
put (tail sts)
execute' sts insts f@(For _ _ _ _ _) = do
put $ ((daughters $ head sts) !! (fromJust $ elemIndex f insts')):sts
execute f
sts <- get
put (tail sts)
execute' sts _ i = do
put sts
execute i
insts' = filter hasScope insts
hasScope :: Inst -> Bool
hasScope (Block _ _ _) = True
hasScope (For _ _ _ _ _) = True
hasScope (If _ _ _ _) = True
hasScope (RWD _ _ _ _) = True
hasScope _ = False
-- Scan Instruction --
execute (Scan (Id name _) pos) =
do
sts <- get
let scanType = varType . fst . fromJust $ (deepLookup name sts)
case scanType of
IntType ->
do
input <- lift getLine
case maybeRead input of
Just x ->
if checkInt x
then
let sts' = deepUpdate name (IntVar x) sts
in put sts'
else
error $ "Integer value out of bounds; `scan` at " ++
show pos ++ "."
Nothing ->
error $ "Couldn't parse integer value; `scan` at " ++
show pos ++ "."
BoolType ->
do
input <- lift getLine
case maybeRead input of
Just x ->
let sts' = deepUpdate name (BoolVar x) sts
in put sts'
Nothing ->
error $ "Couldn't parse Boolean value, `scan` at " ++
show pos ++ "."
-- Print Instruction --
execute (Print exps pos) =
do
sts <- get
let evaluated = concat $ map show $ map (evaluate sts) exps
lift $ putStr evaluated
lift $ hFlush stdout
-- If Instruction --
execute (If cond thn els pos) =
do
sts <- get
let BoolVar c = evaluate sts cond
if c
then do execute thn
else case els of
Nothing -> return ()
Just inst -> execute inst
-- RWD Instruction --
execute rwd@(RWD (Just r) cond (Just d) pos) =
do
execute r
sts <- get
let BoolVar c = evaluate sts cond
if c
then do
execute d
sts <- get
let BoolVar c' = evaluate sts cond
if c'
then execute rwd
else return ()
else return ()
execute rw@(RWD (Just r) cond Nothing pos) =
do
execute r
sts <- get
let BoolVar c = evaluate sts cond
if c
then execute rw
else return ()
execute wd@(RWD Nothing cond (Just d) pos) =
do
sts <- get
let BoolVar c = evaluate sts cond
if c
then do
execute d
execute wd
else return ()
-- For Instruction --
execute (For (Id name _) direction range inst pos) =
do
sts <- get
let elems = if direction == Min
then Set.toAscList (getSet (evaluate sts range))
else Set.toDescList (getSet (evaluate sts range))
mapM_ (execute' inst) elems
where
execute' :: Inst -> Int -> Executor ()
execute' i n = do
st:sts <- get
let sts' = ((update name (IntVar n) st):sts)
put sts'
execute i
evaluate :: [SymbolTable] -> Exp -> Variable
evaluate sts (Binary binOp exp0 exp1) =
case binOp of
Plus p -> if okay
then IntVar result
else error $ "Overflow at " ++ show p ++ "."
where
okay = checkInt result
result = int0 + int1
Minus p -> if okay
then IntVar result
else error $ "Overflow at " ++ show p ++ "."
where
okay = checkInt result
result = int0 - int1
Times p -> if okay
then IntVar result
else error $ "Overflow at " ++ show p ++ "."
where
okay = checkInt result
result = int0 * int1
Div p -> if int1 == 0
then error $ "Division by zero at " ++ show p ++ "."
else IntVar (int0 `div` int1)
Mod p -> if int1 == 0
then error $ "Modulation by zero at " ++ show p ++ "."
else IntVar (int0 `mod` int1)
SetUnion p -> SetVar (Set.union set0 set1)
SetMinus p -> SetVar (Set.difference set0 set1)
SetInter p -> SetVar (Set.intersection set0 set1)
MapPlus p -> if okay
then SetVar result
else error $ "Overflow at " ++ show p ++ "."
where
okay = checkSet result
result = (
case type0 of
IntType -> Set.map (int0 +) set1
SetType -> Set.map (+ int1) set0
)
MapMinus p -> if okay
then SetVar result
else error $ "Overflow at " ++ show p ++ "."
where
okay = checkSet result
result = (
case type0 of
IntType -> Set.map (int0 -) set1
SetType -> Set.map (subtract int1) set0
)
MapTimes p -> if okay
then SetVar result
else error $ "Overflow at " ++ show p ++ "."
where
okay = checkSet result
result = (
case type0 of
IntType -> Set.map (int0 *) set1
SetType -> Set.map (* int1) set0
)
MapDiv p -> SetVar (case type0 of
IntType -> if 0 `Set.member` set1
then error "Division by zero."
else Set.map (int0 `div`) set1
SetType -> if int1 == 0
then error "Division by zero."
else Set.map (`div` int1) set0
)
MapMod p -> SetVar (case type0 of
IntType -> if 0 `Set.member` set1
then error "Modulation by zero."
else Set.map (int0 `mod`) set1
SetType -> if int1 == 0
then error "Modulation by zero."
else Set.map (`mod` int1) set0
)
CompLT p -> BoolVar (int0 < int1)
CompLE p -> BoolVar (int0 <= int1)
CompGT p -> BoolVar (int0 > int1)
CompGE p -> BoolVar (int0 >= int1)
CompEQ p -> BoolVar (val0 == val1)
CompNE p -> BoolVar (val0 /= val1)
CompAt p -> BoolVar (int0 `Set.member` set1)
And p -> BoolVar (bool0 && bool1)
Or p -> BoolVar (bool0 || bool1)
where
val0 = evaluate sts exp0
int0 = getInt val0
bool0 = getBool val0
set0 = getSet val0
type0 = varType val0
val1 = evaluate sts exp1
int1 = getInt val1
bool1 = getBool val1
set1 = getSet val1
type1 = varType val1
evaluate sts (Unary unOp exp0) =
case unOp of
SetMax p -> if Set.null set0
then error $ "Max of empty set at " ++ show p ++ "."
else IntVar (Set.findMax set0)
SetMin p -> if Set.null set0
then error $ "Min of empty set at " ++ show p ++ "."
else IntVar (Set.findMin set0)
SetSize p -> IntVar (Set.size set0)
Not p -> BoolVar (not bool0)
Negative p -> IntVar (negate int0)
where
val0 = evaluate sts exp0
int0 = getInt val0
bool0 = getBool val0
set0 = getSet val0
type0 = varType val0
evaluate sts (Set exps _) =
SetVar list
where
list = Set.fromList ints
ints = map getInt vars
vars = map (evaluate sts) exps
evaluate _ (BoolConst b) = BoolVar b
evaluate _ (IntConst i) = IntVar i
evaluate _ (StrConst s) = StrVar s
evaluate sts (Var (Id var pos)) =
case deepLookup var sts of
Just x -> fst x
Nothing -> error (show sts)
checkInt :: Int -> Bool
checkInt n
| n < -2^31 = False
| n < 2^31 = True
| otherwise = False
checkSet :: (Set.Set Int) -> Bool
checkSet = Set.fold (\x acc -> (checkInt x) && acc) True