-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtranslate.hs
157 lines (134 loc) · 5.6 KB
/
translate.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
data Stmt = Conti | Break
| Exp String
| Goto Int -- only support number label
| Label Int -- only support number label
| If String [Stmt] [Stmt] -- If condition true-statements false-statements
| While String [Stmt] -- While condition statements
| Do [Stmt] String -- Do statements condition
| For String String String [Stmt] -- For initial condition increase statements
| Switch String [(String, [Stmt])] [Stmt] -- Switch expression [(constant, statements)] default-statements
deriving (Show)
-- simplified statement
data SStmt = SExp String
| SLabel Int
| SGoto Int
| SIf String SStmt -- If condition true-statement
deriving (Show)
newtype State a = S (Int -> (a, Int))
app :: State a -> Int -> (a, Int)
app (S st) i = st i
instance Functor State where
-- fmap :: (a -> b) -> State a -> State b
fmap g st = S (\s -> let (x, s') = app st s in (g x, s'))
instance Applicative State where
-- pure :: a -> State a
pure x = S (\s -> (x, s))
-- (<*>) :: State (a -> b) -> State a -> State b
stf <*> stx = S (\s ->
let (f, s0) = app stf s in
let (x, s1) = app stx s0 in (f x, s1))
instance Monad State where
-- (>>=) :: State a -> (a -> State b) -> State b
st >>= f = S (\s -> let (x, s0) = app st s in app (f x) s0)
newLabel :: State Int
newLabel = S (\s -> (s, s + 1))
transAll :: [Stmt] -> State [SStmt]
transAll [] = return []
transAll (s : ss) = (++) <$> trans s <*> transAll ss
trans :: Stmt -> State [SStmt]
trans (Exp s) = return [SExp s]
trans (Goto s) = return [SGoto s]
trans (Label s) = return [SLabel s]
trans (If cond ts [])
= trans (If ("!(" ++ cond ++ ")") [] ts)
trans (If cond [] fs)
= do end <- newLabel
fs' <- transAll fs
return (SIf cond (SGoto end) : fs' ++ [SLabel end])
trans (If cond ts fs)
= do tsl <- newLabel; end <- newLabel
ts' <- transAll ts; fs' <- transAll fs
return (SIf cond (SGoto tsl) : fs'
++ SGoto end : SLabel tsl : ts' ++ [SLabel end])
-- trans (While cond []) = return []
trans (While cond sts)
= do start <- newLabel
end <- newLabel
let neosts = replace sts start end
sts' <- trans (If cond (neosts ++ [Goto start]) [])
return (SLabel start : sts' ++ [SLabel end])
-- trans (Do [] cond) = return []
trans (Do sts cond)
= do start <- newLabel
end <- newLabel
let neosts = replace sts start end
sts' <- transAll neosts
return (SLabel start : sts' ++ [SIf cond (SGoto start), SLabel end])
trans (For init cond inc sts)
= do incl <- newLabel
start <- newLabel
end <- newLabel
let neosts = replace sts incl end ++ [Label incl, Exp inc, Goto start]
sts' <- trans (If cond neosts [])
return (SExp init : SLabel start : sts' ++ [SLabel end])
trans (Switch exp [] deft)
= transAll deft
trans (Switch exp [(const, code)] deft)
= trans (If (exp ++ " == " ++ const) code deft)
trans (Switch exp ((const, code) : xs) deft)
= trans (If (exp ++ " == " ++ const) code [(Switch exp xs deft)])
-- replace continue or break, don't replace for loop statements
replace :: [Stmt] -> Int -> Int -> [Stmt]
replace (Conti : rt) ct bk = Goto ct : replace rt ct bk
replace (Exp "continue" : rt) ct bk = replace (Conti : rt) ct bk
replace (Break : rt) ct bk = Goto bk : replace rt ct bk
replace (Exp "break" : rt) ct bk = replace (Break : rt) ct bk
replace (If cond ts fs : rt) ct bk = If cond (replace ts ct bk) (replace fs ct bk) : replace rt ct bk
-- replace (Switch exp [] deft : rt) ct bk = Switch exp [] (replace deft ct bk) : replace rt ct bk
-- replace (Switch exp ((const, code) : xs) deft : rt) ct bk
-- = Switch exp ((const, (replace code ct bk)) : xs') deft' : rt'
-- where
-- (Switch _ xs' deft') : rt' = replace (Switch exp xs deft : rt) ct bk
replace [] _ _ = []
-- skip other kinds of statements
replace (s : ss) ct bk = s : replace ss ct bk
-- print sstmts
printElements :: [SStmt] -> IO ()
printElements (SExp x : xs) = putStrLn (x ++ ";") >> printElements xs
printElements (SLabel x : xs) = putStrLn ("L" ++ show x ++ ":;") >> printElements xs
printElements (SGoto x : xs) = putStrLn ("goto L" ++ show x ++ ";") >> printElements xs
printElements (SIf cond st : xs) = putStr ("if (" ++ cond ++ ") ") >> printElements (st : xs)
printElements [] = return ()
-- use: ts s0
ts :: [Stmt] -> IO ()
ts s = let (ss, _) = app (transAll s) 0 in printElements ss
-- examples
s0 = [Exp "int i = 0", Exp "++i", Exp "printf(\"%d\\n\", i)"]
s1 = [Exp "int i = 0",
If "i == 0" [Exp "printf(\"%d\\n\", j + 1)"] []]
s2 = [Exp "int i = 0",
While "i < 100"
[Exp "printf(\"%d\\n\", i)",
If "i == 66" [Break] [],
Exp "++i"]]
s3 = [Exp "int i = 0", Do [Exp "++i", If "i % 2 == 0" [Conti] [], Exp "printf(\"%d\\n\", i)"] "i < 100"]
s4 = [Exp "int i = 0",
Switch "i"
[("0", [Exp "printf(\"%d = 0\\n\", i)"]),
("1", [Exp "printf(\"%d = 1\\n\", i)"]),
("2", [Exp "printf(\"%d = 2\\n\", i)"])]
[Exp "printf(\"other\\n\")"]]
s4' = [Exp "int i = 0",
Switch "i"
[("0", [Break]),
("1", [Conti])]
[Break]]
-- perfect numbers 1 - 10000
s5 = [Exp "int i = 1",
While "i <= 10000"
[Exp "int acc = 0",
(For "int j = 1" "j < i" "++j"
[If "i % j == 0" [Exp "acc += j"] []]),
(If "i == acc" [Exp "printf(\"%d\\n\", i)"] []),
(Exp "++i")]]
s6 = [If "j % 2 == 0" [If "j % 3 == 0" [Exp "printf(\"%d\\n\", j)", Exp "print j + 1"] []] [], Exp "int i = 0"]