-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCPrint.hs
305 lines (240 loc) · 6.86 KB
/
CPrint.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
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
module CPrint where
import CLang
import Data.List
import Data.Monoid
import Control.Monad
import Control.Monad.Writer
import Control.Monad.Identity
type PM = WriterT [String] Identity
cprint :: String -> Prog -> String
cprint prologue p = let m' = runWriterT (p_prog prologue p)
(r, lines) = runIdentity m'
in concat (intersperse "\n" lines)
line :: String -> PM ()
line s = tell [s]
indent :: PM a -> PM a
indent (WriterT { runWriterT = r }) =
WriterT { runWriterT = do (a, w) <- r
let w' = map (\s -> if s /= "" then '\t':s else s) w
return (a, w') }
p_prog :: String -> Prog -> PM ()
p_prog prologue p =
do mapM p_inc (includes p)
line ""
tell (lines prologue)
line ""
mapM p_unit (units p)
return ()
p_inc :: String -> PM ()
p_inc f = line ("#include <" ++ f ++ ".h>")
comment s = line ("/* " ++ s ++ " */")
p_fun_proto ft =
do let p = if elem Static (mods ft) then "static " else ""
rt <- p_typ (ret ft)
as <- p_args (args ft)
return $ p ++ rt ++ " " ++ name ft ++ "(" ++ as ++ ")"
p_unit (Decl d@(VarDecl n t me _)) =
do p_decl d
p_unit (FunDecl ft) =
do p <- p_fun_proto ft
line $ p ++ ";"
p_unit (FunDef ft b) =
do line ""
p <- p_fun_proto ft
line p
line "{"
indent $ p_block b
line "}"
summarize [] = []
summarize [d] = [[d]]
summarize (l:r:ds) =
let VarDecl n t me mods = l
VarDecl n' t' me' mods' = r
s:ss = summarize (r:ds)
in if t == t' && me == Nothing && me' == Nothing && mods == []
&& mods' == []
then (l:s):ss
else [l]:s:ss
p_block ([], stmt) =
do p_stmt stmt
p_block (decls, stmt) =
do mapM p_sum_decl (summarize decls)
line ""
p_stmt stmt
dname (VarDecl n _ _ _) = n
dtype (VarDecl _ t _ _) = t
p_sum_decl [d] = p_decl d
p_sum_decl [] = error "wat"
p_sum_decl ds =
do let names = map dname ds
typ = dtype (head ds)
tv <- p_typed_var "" typ
line $ tv ++ (commas names) ++ ";"
p_decl (VarDecl n t me mods) =
do init <- case me of
Nothing -> do return ""
Just e -> do (e', _) <- p_expr e
return $ " = " ++ e'
tv <- p_typed_var n t
line $ tv ++ init ++ ";"
p_stmt (Seq l r) =
do p_stmt l
p_stmt r
p_stmt (Comment s) =
do comment s
p_stmt Skip =
do return ()
p_stmt s@(If _ _ _) =
do p_if "" s
p_stmt (Expr e) =
do (e', _) <- p_expr e
line $ e' ++ ";"
p_stmt (Return e) =
do (ee, _) <- p_expr e
line $ "return " ++ ee ++ ";"
p_stmt (For s c i b) =
do (ss, _) <- p_expr s
(cc, _) <- p_expr c
(ii, _) <- p_expr i
line $ "for (" ++ ss ++ "; " ++ cc ++ "; " ++ ii ++ ") {"
indent $ p_block b
line "}"
p_typ Int = do return "int"
p_typ Bool = do return "bool"
p_typ UChar = do return "unsigned char"
p_typ (Custom s) = do return s
data Assoc = L | R | N
deriving (Show, Eq)
b_prec Member = (1, L)
b_prec Prod = (3, L)
b_prec Div = (3, L)
b_prec Mod = (3, L)
b_prec Plus = (4, L)
b_prec Minus = (4, L)
b_prec Lt = (6, L)
b_prec Le = (6, L)
b_prec Gt = (6, L)
b_prec Ge = (6, L)
b_prec Eq = (7, L)
b_prec Neq = (7, L)
b_prec Band = (8, N)
b_prec Xor = (8, N)
b_prec Bor = (8, N)
b_prec And = (11, L)
b_prec Or = (12, L)
b_prec Assign = (14, R)
u_prec NegateNum = (2, R)
u_prec Not = (2, R)
u_prec Bnot = (2, R)
u_prec Address = (2, R)
u_prec Deref = (2, R)
p_expr (BinOp op l r) =
do oo <- p_binop op
(ll, lp) <- p_expr l
(rr, rp) <- p_expr r
let (p, a) = b_prec op
let ls = if p < lp || (p == lp && a /= L)
then paren ll
else ll
let rs = if p < rp || (p == rp && a /= R)
then paren rr
else rr
return (ls ++ oo ++ rs, p)
p_expr (UnOp op l) =
do oo <- p_unop op
(ll, lp) <- p_expr l
let (p, a) = u_prec op
let ls = if p < lp || (p == lp && a /= L)
then paren ll
else ll
return (oo ++ ls, p)
p_expr (ConstInt i) =
do return (show i, 0)
p_expr (ConstBool b) =
do return (if b == True then "true" else "false", 0)
p_expr (ConstFloat f) =
do return (show f, 0)
p_expr (Call s args) =
do (as, _) <- liftM unzip $ mapM p_expr args
return (s ++ "(" ++ commas as ++ ")", 0)
p_expr (LV lv) =
do lvs <- p_lvalue lv
return (lvs, 0)
p_expr (Arr es) =
do (p_es, _) <- liftM unzip $ mapM p_expr es
return (brace $ commas p_es, 0)
p_expr (ConstStr s) =
do return ("\"" ++ s ++ "\"", 0)
p_expr (StructVal attrs) =
do ts <- mapM p_attr attrs
return (brace (commas ts), 0)
p_attr (name, expr) =
do (e, _) <- p_expr expr
return $ "." ++ name ++ " = " ++ e
paren s = "(" ++ s ++ ")"
brace s = "{" ++ s ++ "}"
square s = "[" ++ s ++ "]"
commas ss = concat $ intersperse ", " ss
p_args l =
do as <- mapM (uncurry p_typed_var) l
return $ commas as
p_typed_var n Int =
do return $ "int " ++ n
p_typed_var n Bool =
do return $ "bool " ++ n
p_typed_var n UChar =
do return $ "unsigned char " ++ n
p_typed_var n (Custom s) =
do return $ s ++ " " ++ n
p_typed_var n (ArrT t Nothing) =
do tv <- p_typed_var n t
return $ tv ++ "[]"
p_typed_var n (ArrT t (Just l)) =
do tv <- p_typed_var n t
return $ tv ++ "[" ++ show l ++ "]"
p_if lead (If c t (_, Skip)) =
do (cc, _) <- p_expr c
line (lead ++ "if (" ++ cc ++ ") {")
indent $ p_block t
line "}"
p_if lead (If c t ([], i@(If _ _ _))) =
do (cc, _) <- p_expr c
line (lead ++ "if (" ++ cc ++ ") {")
indent $ p_block t
p_if "} else " i
p_if lead (If c t e) =
do (cc, _) <- p_expr c
line (lead ++ "if (" ++ cc ++ ") {")
indent $ p_block t
line "} else {"
indent $ p_block e
line "}"
p_binop Plus = do return " + "
p_binop Minus = do return " - "
p_binop Prod = do return " * "
p_binop Div = do return " / "
p_binop Eq = do return " == "
p_binop Neq = do return " != "
p_binop Mod = do return " % "
p_binop And = do return " && "
p_binop Or = do return " || "
p_binop Lt = do return " < "
p_binop Gt = do return " > "
p_binop Le = do return " <= "
p_binop Ge = do return " >= "
p_binop Assign = do return " = "
p_binop Band = do return " & "
p_binop Xor = do return " ^ "
p_binop Bor = do return " | "
p_binop Member = do return "->"
p_unop NegateNum = do return "-"
p_unop Not = do return "!"
p_unop Bnot = do return "~"
p_unop Address = do return "&"
p_unop Deref = do return "*"
p_lvalue (LVar s) =
do return s
p_lvalue (Access a i) =
do (aa, _) <- p_expr a
(ii, _) <- p_expr i
return $ aa ++ square ii