crokus 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,443 @@
1
+
2
+ require_relative 'code'
3
+ require_relative 'visitor'
4
+ require_relative 'cleaner'
5
+
6
+ module Crokus
7
+
8
+ class PrettyPrinter < Visitor
9
+
10
+ include Indent
11
+ attr_accessor :code
12
+
13
+ def initialize
14
+ @ind=-2
15
+ @verbose=false
16
+ end
17
+
18
+ def visit ast
19
+ @code=Code.new
20
+ ast.accept(self)
21
+ c_code=@code.finalize
22
+ c_code=Cleaner.new.clean(c_code)
23
+ return c_code
24
+ end
25
+
26
+ def visitToken tok, args=nil
27
+ tok.to_s
28
+ end
29
+
30
+ def visitDesignUnit du,args=nil
31
+ indent "DesignUnit"
32
+ du.list.each{|e| code << e.accept(self,:body)}
33
+ dedent
34
+ end
35
+
36
+ def visitDecl decl,args=nil
37
+ code=Code.new
38
+ type=decl.type.accept(self)
39
+
40
+ array_size=""
41
+ t=decl.type
42
+
43
+ while t.is_a? ArrayOf
44
+ type=t.name.accept(self)
45
+ size=t.size.accept(self)
46
+ array_size="[#{size}]"+array_size
47
+ t=t.type
48
+ end
49
+ t=nil
50
+
51
+ vname=decl.var.accept(self)
52
+ init=decl.init.accept(self) if decl.init
53
+
54
+ if init.is_a? Code
55
+ init=" = "+init.finalize
56
+ else
57
+ init=" = "+init
58
+ end if decl.init
59
+
60
+ # handle complex declaration that use structs
61
+ if type.is_a? Code
62
+ last=type.lines.pop
63
+ type.lines.each do |line|
64
+ code << line
65
+ end
66
+ last_str=last+" #{vname}#{array_size}#{init}"
67
+
68
+ code << last_str
69
+ else
70
+ ret = "#{type} #{vname}#{array_size}#{init}"
71
+ end
72
+ code << ret
73
+ code << ";"
74
+ return code
75
+ end
76
+
77
+ def visitInclude include,args=nil
78
+ name=include.name.accept(self)
79
+ case include.env
80
+ when :env
81
+ name="<#{name}>"
82
+ when :local
83
+ end
84
+ return "#include #{name}"
85
+ end
86
+
87
+ def visitDefine define,args=nil
88
+ name=define.name.accept(self)
89
+ e=define.expr.accept(self)
90
+ return "#define #{name} #{e}"
91
+ end
92
+
93
+ def visitTypedef typdef,args=nil
94
+ type=typdef.type.accept(self)
95
+ name=typdef.name.accept(self)
96
+ return "typedef #{type} #{name};"
97
+ end
98
+
99
+ def visitType type,args=nil
100
+ precisions=type.precisions.collect{|spec| spec.accept(self)}
101
+ precisions=precisions.join(" ")
102
+ precisions+=" " if precisions.size>0
103
+ name=type.name.accept(self)
104
+ return "#{precisions}#{name}"
105
+ end
106
+
107
+ def visitPointerTo pto,args=nil
108
+ tname=pto.type.accept(self)
109
+ return "#{tname} *"
110
+ end
111
+
112
+ def visitArrayOf aof,args=nil
113
+ type=aof.type.accept(self)
114
+ size=aof.size.accept(self) if aof.size
115
+ aof
116
+ "#{type}" #[size] not returned!
117
+ end
118
+
119
+ def visitStruct struct,args=nil
120
+ name=struct.name.accept(self) if struct.name
121
+ code=Code.new
122
+ code << "struct #{name} {"
123
+ code.indent=2
124
+ struct.decls.each do |decl|
125
+ code << decl.accept(self)
126
+ end
127
+ code.indent=0
128
+ code << "}"
129
+ return code.finalize
130
+ end
131
+
132
+ def visitCasting cast,args=nil
133
+ type=cast.type.accept(self)
134
+ return "#{type} #{cast.modifier}"
135
+ end
136
+
137
+ def visitCastedExpr cexpr, args=nil
138
+ type=cexpr.type.accept(self)
139
+ e=cexpr.expr.accept(self)
140
+ return "(#{type}) #{e}"
141
+ end
142
+ #......... end of types..........
143
+
144
+ def visitFunction func,args=nil
145
+ code=Code.new
146
+ tname=func.type.accept(self)
147
+ fname=func.name.accept(self)
148
+ args=func.args.collect{|arg| arg.accept(self)}
149
+ args=args.join(",")
150
+ code << "\n#{tname} #{fname}(#{args})"
151
+ code.indent=2
152
+ code << func.body.accept(self)
153
+ code.indent=0
154
+ return code
155
+ end
156
+
157
+ def visitFunctionProto func,args=nil
158
+ tname=func.type.accept(self)
159
+ fname=func.name.accept(self)
160
+ args =func.args.collect{|arg| arg.accept(self)}
161
+ args=args.join(",")
162
+ code = "\n#{tname} #{fname}(#{args})"
163
+ return code
164
+ end
165
+
166
+ def visitFormalArg formalArg,args=nil
167
+ tname=formalArg.type.accept(self)
168
+ array_size=""
169
+ t=formalArg.type
170
+ while t.is_a? ArrayOf
171
+ type=t.name.accept(self)
172
+ size=t.size.accept(self) if t.size
173
+ array_size+="[#{size}]"+array_size if tname.size
174
+ t=t.type
175
+ end
176
+
177
+ vname=formalArg.name.accept(self) if formalArg.name # e.g : main(void)
178
+ tname+=" " if formalArg.name
179
+ return "#{tname}#{vname}#{array_size}"
180
+ end
181
+
182
+ #...........stmts...............
183
+ def visitCommaStmt comma,args=nil
184
+ lhs=comma.lhs.accept(self)
185
+ rhs=comma.rhs.accept(self)
186
+ ret="#{lhs},#{rhs}"
187
+ ret
188
+ end
189
+
190
+ def visitAssign assign,args=nil
191
+ lhs=assign.lhs.accept(self)
192
+ op =assign.op.accept(self)
193
+ rhs=assign.rhs.accept(self)
194
+ ret="#{lhs} #{op} #{rhs};"
195
+ ret
196
+ end
197
+
198
+ def visitPostFixAccu accu,args=nil
199
+ lhs=accu.lhs.accept(self) if accu.lhs #++i
200
+ op =accu.op.accept(self)
201
+ ret="#{lhs}#{op}"
202
+ ret
203
+ end
204
+
205
+ def visitPreFixAccu accu,args=nil
206
+ lhs=accu.lhs.accept(self) if accu.lhs #++i
207
+ op =accu.op.accept(self)
208
+ ret="#{lhs}#{op}"
209
+ ret
210
+ end
211
+
212
+ def visitFunCall fcall,as_procedure=nil
213
+ fname=fcall.name.accept(self)
214
+ argus=fcall.args.collect{|argu| argu.accept(self)}
215
+ argus=argus.join(',')
216
+ ret="#{fname}(#{argus})"
217
+ ret+=";" if as_procedure
218
+ ret
219
+ end
220
+
221
+ def visitFor for_,args=nil
222
+ code=Code.new
223
+ init=for_.init.collect do |stmt|
224
+ stmt_init=stmt.accept(self)
225
+ case stmt_init
226
+ when Code
227
+ stmt_init.finalize
228
+ else
229
+ stmt_init
230
+ end
231
+ end
232
+ init=init.join(";")
233
+ cond=for_.cond.accept(self)
234
+ incr=for_.increment.accept(self)
235
+ code << "for(#{init};#{cond};#{incr})"
236
+ code.indent=2
237
+ code << for_.body.accept(self)
238
+ code.indent=0
239
+ return code
240
+ end
241
+
242
+ def visitReturn ret,args=nil
243
+ e=ret.expr.accept(self) if ret.expr
244
+ return "return #{e};"
245
+ end
246
+
247
+ def visitIf if_,args=nil
248
+ cond=if_.cond.accept(self)
249
+ code=Code.new
250
+ code << "if (#{cond})"
251
+ code.indent=2
252
+ code << if_.body.accept(self)
253
+ code.indent=0
254
+ code << if_.else.accept(self,:body) if if_.else
255
+ return code
256
+ end
257
+
258
+ def visitElse else_,args=nil
259
+ code=Code.new
260
+ code << "else"
261
+ code.indent=2
262
+ code << else_.body.accept(self)
263
+ code.indent=0
264
+ return code
265
+ end
266
+
267
+ def visitSwitch sw_,args=nil
268
+ e=sw_.expr.accept(self)
269
+ sw_.cases.each{|case_| case_.accept(self)}
270
+ code=Code.new
271
+ code << "switch(#{e}){"
272
+ code.indent=2
273
+ sw_.cases.each{|case_|
274
+ code << case_.accept(self)
275
+ }
276
+ code.indent=0
277
+ if sw_.default
278
+ code.indent=2
279
+ code << "default:"
280
+ code.indent=4
281
+ code << sw_.default.accept(self)
282
+ code.indent=0
283
+ end
284
+
285
+ code << "}"
286
+ return code
287
+ end
288
+
289
+ def visitCase case_,args=nil
290
+ e=case_.expr.accept(self)
291
+ code=Code.new
292
+ code << "case #{e}:"
293
+ code.indent=2
294
+ code << case_.body.accept(self)
295
+ code.indent=0
296
+ return code
297
+ end
298
+
299
+ def visitWhile while_,args=nil
300
+ cond=while_.cond.accept(self)
301
+ body=while_.body.accept(self)
302
+ code=Code.new
303
+ code << "while (#{cond})"
304
+ code.indent=2
305
+ code << body
306
+ code.indent=0
307
+ return code
308
+ end
309
+
310
+ def visitDoWhile while_,args=nil
311
+ cond=while_.cond.accept(self)
312
+ code=Code.new
313
+ code << "do"
314
+ code.indent=2
315
+ code << while_.body.accept(self)
316
+ code.indent=0
317
+ code << "while #{cond};"
318
+ return code
319
+ end
320
+
321
+ def visitBreak brk,args=nil
322
+ return "break;"
323
+ end
324
+
325
+ def visitContinue cont,args=nil
326
+ return "continue;"
327
+ end
328
+
329
+ def visitLabeledStmt label,args=nil
330
+ stmt=label.stmt.accept(self)
331
+ code=Code.new
332
+ code << stmt
333
+ return code
334
+ end
335
+
336
+ def visitGoto goto,args=nil
337
+ label=goto.label.accept(self)
338
+ return "goto #{label};"
339
+ end
340
+
341
+ #..........expresions..........
342
+ def visitIdent ident,args=nil
343
+ return ident.to_s
344
+ end
345
+
346
+ def visitIntLit lit,args=nil
347
+ return lit.to_s
348
+ end
349
+
350
+ def visitStrLit lit,args=nil
351
+ return lit.to_s
352
+ end
353
+
354
+ def visitCharLit lit,args=nil
355
+ return lit.to_s
356
+ end
357
+
358
+ def visitBinary expr,args=nil
359
+ lhs=expr.lhs.accept(self)
360
+ op =expr.op.accept(self)
361
+ rhs=expr.rhs.accept(self)
362
+ case op
363
+ when "+","-","*","/"
364
+ else
365
+ op=" "+op+" "
366
+ end
367
+ return "#{lhs}#{op}#{rhs}"
368
+ end
369
+
370
+ def visitUnary unary,args=nil
371
+ op=unary.op.accept(self)
372
+ e =unary.rhs.accept(self)
373
+ return unary.postfix ? "#{e}#{op}" : "#{op}#{e}"
374
+ end
375
+
376
+ def visitParenth par,args=nil
377
+ e=par.expr.accept(self)
378
+ return "(#{e})"
379
+ end
380
+
381
+ def visitArrow arrow,args=nil
382
+ lhs=arrow.lhs.accept(self)
383
+ rhs=arrow.rhs.accept(self)
384
+ return "#{lhs}->#{rhs}"
385
+ end
386
+
387
+ def visitIndexed index,args=nil
388
+ lhs=index.lhs.accept(self)
389
+ rhs=index.rhs.accept(self)
390
+ return "#{lhs}[#{rhs}]"
391
+ end
392
+
393
+ def visitArrayOrStructInit init,args=nil
394
+ inits=init.elements.collect{|e| e.accept(self)}
395
+ #handle imbrications
396
+ inits=inits.collect{|init| (init.is_a? Code) ? init.finalize : init}
397
+ code=Code.new
398
+ code << "{"+inits.join(",")+"}"
399
+ return code
400
+ end
401
+
402
+ def visitAddressOf ao,args=nil
403
+ e=ao.expr.accept(self)
404
+ return " &#{e} "
405
+ end
406
+
407
+ def visitDotted dotted,args=nil
408
+ lhs=dotted.lhs.accept(self)
409
+ rhs=dotted.rhs.accept(self)
410
+ return "#{lhs}.#{rhs}"
411
+ end
412
+
413
+ def visitSizeof sizeof,args=nil
414
+ tname=sizeof.type.accept(self)
415
+ return "sizeof(#{tname})"
416
+ end
417
+
418
+ def visitDeref deref,args=nil
419
+ e=deref.expr.accept(self)
420
+ return "*#{e}"
421
+ end
422
+
423
+ def visitBody body,args=nil
424
+ code=Code.new
425
+ code << "{"
426
+ code.indent=2
427
+ body.each do |stmt|
428
+ code << stmt.accept(self,true)
429
+ end
430
+ code.indent=0
431
+ code << "}"
432
+ return code
433
+ end
434
+
435
+ #================= IR ============
436
+ def visitITE ite,args=nil
437
+ cond=ite.cond.accept(self)
438
+ label1=ite.trueBranch.label
439
+ label2=ite.falseBranch.label
440
+ "ite #{cond},#{label1},#{label2}"
441
+ end
442
+ end #class Visitor
443
+ end #module
@@ -0,0 +1,86 @@
1
+ require "optparse"
2
+
3
+ require_relative "compiler"
4
+
5
+ module Crokus
6
+
7
+ class Runner
8
+
9
+ def self.run *arguments
10
+ new.run(arguments)
11
+ end
12
+
13
+ def run arguments
14
+ compiler=Compiler.new
15
+ compiler.options = args = parse_options(arguments)
16
+ if filename=args[:cfile]
17
+ compiler.compile filename
18
+ else
19
+ puts "need a C file : crokus [options] <file.c>"
20
+ end
21
+ end
22
+
23
+ def header
24
+ puts "Crokus (#{VERSION})- (c) JC Le Lann 2016-20"
25
+ end
26
+
27
+ private
28
+ def parse_options(arguments)
29
+ header
30
+
31
+ parser = OptionParser.new
32
+
33
+ no_arguments=arguments.empty?
34
+
35
+ options = {}
36
+
37
+ parser.on("-h", "--help", "Show help message") do
38
+ puts parser
39
+ exit(true)
40
+ end
41
+
42
+ parser.on("-p", "--parse", "parse only") do
43
+ options[:parse_only]=true
44
+ end
45
+
46
+ parser.on("--pp", "pretty print back source code ") do
47
+ options[:pp] = true
48
+ end
49
+
50
+ parser.on("--ast", "abstract syntax tree (AST)") do
51
+ options[:ast] = true
52
+ end
53
+
54
+ parser.on("--cfg", "control-flow graphs for each function") do
55
+ options[:cfg] = true
56
+ end
57
+
58
+ parser.on("--tac", "draw three address code (TAC) CFG") do
59
+ options[:tac] = true
60
+ end
61
+
62
+ parser.on("--emit-ir", "dump textual IR from TAC CFG") do
63
+ options[:emit_ir] = true
64
+ end
65
+
66
+ parser.on("--vv", "verbose") do
67
+ options[:verbose] = true
68
+ end
69
+
70
+ parser.on("-v", "--version", "Show version number") do
71
+ puts VERSION
72
+ exit(true)
73
+ end
74
+
75
+ parser.parse!(arguments)
76
+
77
+ options[:cfile]=arguments.shift #the remaining c file
78
+
79
+ if no_arguments
80
+ puts parser
81
+ end
82
+
83
+ options
84
+ end
85
+ end
86
+ end