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.
- 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
|