crokus 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/crokus +5 -0
- data/lib/crokus.rb +4 -0
- data/lib/crokus/ast.rb +431 -0
- data/lib/crokus/ast_printer.rb +86 -0
- data/lib/crokus/cfg.rb +81 -0
- data/lib/crokus/cfg_builder.rb +169 -0
- data/lib/crokus/cfg_cleaner.rb +62 -0
- data/lib/crokus/cfg_printer.rb +73 -0
- data/lib/crokus/cleaner.rb +10 -0
- data/lib/crokus/code.rb +46 -0
- data/lib/crokus/compiler.rb +124 -0
- data/lib/crokus/generic_lexer.rb +62 -0
- data/lib/crokus/indent.rb +19 -0
- data/lib/crokus/ir_dumper.rb +48 -0
- data/lib/crokus/lexer.rb +113 -0
- data/lib/crokus/parser.rb +1072 -0
- data/lib/crokus/parser_only.rb +993 -0
- data/lib/crokus/pretty_printer.rb +443 -0
- data/lib/crokus/runner.rb +86 -0
- data/lib/crokus/tac_builder.rb +109 -0
- data/lib/crokus/token.rb +43 -0
- data/lib/crokus/transformer.rb +304 -0
- data/lib/crokus/version.rb +3 -0
- data/lib/crokus/visitor.rb +341 -0
- metadata +70 -0
@@ -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
|