crokus 0.0.3 → 0.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ef8bbae26ccb8fc2b32c8dd40bf6635272055ba5e158a0ed9b7e22aead35018a
4
- data.tar.gz: 922d2ce547b6875e8cb99364f0ca5ba2edfd0c066cd888065bb84149a07a32c3
3
+ metadata.gz: 852a2b5bdf274b42fa37edba80142da8b481cad7203637a5b86ab7a5b83f7b10
4
+ data.tar.gz: f199ddb9ac49df0c8bb5a456c332677ccb2cbd21baa469d0cee514d400b4ae78
5
5
  SHA512:
6
- metadata.gz: 72bc1089bcbc9edb53afb4e3bada17d4daa19b5e174c22516be36755e10478facadf68a6651edf6e9eb4c8574ad8fa82203b73b1a7c947f117080bcb3296755e
7
- data.tar.gz: ca37c64d365528a95548ce2517d3f92bdd90ad62f071609695aebdb6b64e21f8e0b9ea6e525b495d7ec4d77ac5c24ae08e7d23a129aa87551d141edc8b860d91
6
+ metadata.gz: ec54d76cffdfeeb764fcc06463fd67b01b88dd642246496f6d6de07d5462113e3fda0e34af0bf60750552397e14be4d6cd1d36eec0a6fd8d27ed88cdd27ea1f3
7
+ data.tar.gz: 602f8152c74bda51fde3c991fa969192d3a2c542688650b822158fdcfab654d7ac62cb869b9243d3d512b880c168938d8e9848388cb2f5c097f0c46a853b7502
@@ -0,0 +1,199 @@
1
+ module Crokus
2
+
3
+ class PrinterC
4
+
5
+ attr_accessor :cfg
6
+
7
+ def initialize
8
+ @visited=[]
9
+ @prp=PrettyPrinter.new
10
+ end
11
+
12
+ def print cfg
13
+ puts " |-->[+] generating C code from cfg '#{cfg.name}'"
14
+ @cfg=cfg
15
+ code=Code.new
16
+ code << "//"+"-"*60
17
+ code << "// automatically generated by Crokus compiler"
18
+ code << "// date : #{Time.now.strftime("%a %d,%B %Y - %H:%M:%S")}"
19
+ code << "//"+"-"*60
20
+ code.newline
21
+ code << "#include <stdio.h>"
22
+ code << "#include <stdlib.h>"
23
+ code.newline
24
+ io=[decl_inputs,decl_outputs].join(',')
25
+ code << "int #{cfg.name}(#{io}){"
26
+ code.indent=2
27
+ code << decl_vars()
28
+ code << decl_loop_indexes()
29
+ code << decl_arrays()
30
+ code << visit_rec(cfg.starter)
31
+ code << output_assigns()
32
+ code << "return 0;"
33
+ code.indent=0
34
+ code << "}"
35
+ code.newline
36
+ code << main(cfg)
37
+ puts code.finalize
38
+ code.save_as "#{cfg.name}.c"
39
+ end
40
+
41
+ def main cfg
42
+ code=Code.new
43
+ code << "int main(void){"
44
+ code.indent=2
45
+ inputs,outputs=[],[]
46
+ cfg.infos["inputs"].each do |input|
47
+ code << "int #{input} = #{rand 0..255};"
48
+ inputs << input
49
+ end
50
+ cfg.infos["outputs"].each do |output|
51
+ code << "int #{output};"
52
+ outputs << "&#{output}"
53
+ end
54
+ params=[inputs,outputs].flatten.join(',')
55
+ code << "#{cfg.name}(#{params});"
56
+ cfg.infos["outputs"].each do |output|
57
+ code << "printf(\"#{output} = %d\\n\",#{output});"
58
+ end
59
+ code << "return 0;"
60
+ code.indent=0
61
+ code << "}"
62
+ code
63
+ end
64
+
65
+ def decl_inputs
66
+ if h=cfg.infos["inputs"]
67
+ return h.map{|ident| "int #{ident}"}
68
+ end
69
+ end
70
+
71
+ def decl_outputs
72
+ if h=cfg.infos["outputs"]
73
+ return h.map{|ident| "int *#{ident}"}
74
+ end
75
+ end
76
+
77
+ def decl_vars
78
+ code=Code.new
79
+ if h=cfg.infos["int_vars"]
80
+ h.each{|ident| code << "int #{ident} = #{rand(0..255)};"}
81
+ end
82
+ code.newline
83
+ code
84
+ end
85
+
86
+ def decl_loop_indexes
87
+ code=Code.new
88
+ if cfg.infos["loop_indexes"]
89
+ code << "// loop indexes"
90
+ cfg.infos["loop_indexes"].each do |index|
91
+ code << "int #{index};"
92
+ end
93
+ code.newline
94
+ end
95
+ code
96
+ end
97
+
98
+ def decl_arrays
99
+ code=Code.new
100
+ cfg.infos["internal_arrays"].each do |h|
101
+ name,size_lit=h.first
102
+ size_int=size_lit.to_s.to_i
103
+ init=Array.new(size_int){rand(255)}.join(",")
104
+ size=size_lit.accept(@prp)
105
+ code << "int #{name}[#{size}] ={#{init}};"
106
+ end
107
+ code.newline
108
+ code
109
+ end
110
+
111
+ def output_assigns
112
+ code=Code.new
113
+ code.newline
114
+ code << "//------- output assignments ------"
115
+ if ary=cfg.infos["output_assigns"]
116
+ ary.each{|h|
117
+ out,expr=h.first
118
+ rhs=expr.accept(@prp)
119
+ code << "*#{out} = #{rhs};"
120
+ }
121
+ end
122
+ code
123
+ end
124
+
125
+ def visit_rec bb
126
+ unless bb.nil? or @visited.include?(bb)
127
+ if bb.infos[:start_if]
128
+ gen_if(bb)
129
+ elsif bb.infos[:start_while]
130
+ gen_while(bb)
131
+ elsif bb.infos[:start_for]
132
+ gen_for(bb)
133
+ else
134
+ gen_plain(bb)
135
+ end
136
+ end
137
+ end
138
+
139
+ def gen_plain bb
140
+ code=Code.new
141
+ @visited << bb
142
+ #code << "// bb #{bb.label}"
143
+ bb.stmts.each{|assign|
144
+ code << assign.accept(@prp)
145
+ }
146
+ code << visit_rec(bb.nextBranch)
147
+ code
148
+ end
149
+
150
+ def gen_if bb
151
+ code=Code.new
152
+ @visited << bb
153
+ #code << "// bb 'if' #{bb.label}"
154
+ bb.stmts.each{|stmt| code << stmt.accept(@prp)}
155
+ cond=bb.infos[:cond].accept(@prp)
156
+ code << "if (#{cond}){"
157
+ code.indent=2
158
+ code << visit_rec(bb.trueBranch)
159
+ code.indent=0
160
+ code << "}"
161
+ code << "else {"
162
+ code.indent=2
163
+ code << visit_rec(bb.falseBranch)
164
+ code.indent=0
165
+ code << "}"
166
+ code
167
+ end
168
+
169
+ def gen_while bb
170
+ code=Code.new
171
+ @visited << bb
172
+ bb.stmts.each{|stmt| code << stmt.accept(@prp)}
173
+ cond=bb.infos[:cond].accept(@prp)
174
+ code << "while (#{cond}){"
175
+ code.indent=2
176
+ code << visit_rec(bb.trueBranch)
177
+ code.indent=0
178
+ code << "}"
179
+ code << visit_rec(bb.falseBranch)
180
+ code
181
+ end
182
+
183
+ def gen_for bb
184
+ code=Code.new
185
+ @visited << bb
186
+ #code << "// bb 'for' #{bb.label}"
187
+ bb.stmts.each{|stmt| code << stmt.accept(@prp)}
188
+ index=bb.infos["loop_index"]
189
+ index_bound=bb.infos["loop_index_bound"]
190
+ code << "for(#{index}=0;#{index} < #{index_bound};#{index}++){"
191
+ code.indent=2
192
+ code << visit_rec(bb.trueBranch)
193
+ code.indent=0
194
+ code << "}"
195
+ code << visit_rec(bb.falseBranch)
196
+ code
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,312 @@
1
+ require 'yaml'
2
+ require 'distribution'
3
+
4
+ require_relative 'cfg_printer_c'
5
+
6
+ class Hash
7
+ def sample
8
+ k=keys.sample
9
+ [k,self[k]]
10
+ end
11
+ end
12
+
13
+ module Crokus
14
+
15
+ class RandomGen
16
+ attr_accessor :cfg
17
+
18
+ def run params
19
+ puts "[+] running random C generation"
20
+ puts " |-->[+] reading parameters file '#{params}'"
21
+ @params=YAML.load(File.read(params))
22
+ init_cfg
23
+ init_random_generators
24
+ create_inputs
25
+ create_outputs
26
+ create_variables
27
+ create_internal_arrays
28
+ create_output_assigns
29
+ create_cfg
30
+ gen_dot # to see the structure, before hacking the content
31
+ populate_all
32
+ generate_c
33
+ #print_infos
34
+ end
35
+
36
+
37
+ def print_infos
38
+ puts " |-->[+] infos about CFG :"
39
+ puts " |-->[+] #basic blocks : #{@cfg.size}"
40
+ end
41
+
42
+ def gen_dot
43
+ @cfg.print verbose=false
44
+ end
45
+
46
+ def init_cfg
47
+ @cfg=CFG.new(@params["name"])
48
+ @current=@cfg.starter
49
+ end
50
+
51
+ def init_random_generators
52
+ puts " |-->[+] init parameterized random generators"
53
+ @rng={}
54
+ @params.each do |key,val|
55
+ if key.start_with? "avg_"
56
+ name=key[4..-1]
57
+ @rng[name]=Distribution::Normal.rng(mean=val,sigma=0.5) #sigma=1 ?
58
+ end
59
+ end
60
+ end
61
+
62
+ def register_readables ary
63
+ @readables||=[]
64
+ @readables << ary
65
+ @readables.flatten!
66
+ end
67
+
68
+ def create_inputs
69
+ name="in_0"
70
+ @inputs=(1..@params["nb_inputs"]).map{|idx| Ident.new(Token.create name=name.succ)}
71
+ register_readables @inputs
72
+ @cfg.infos["inputs"]=@inputs
73
+ end
74
+
75
+ def create_outputs
76
+ name="out_0"
77
+ @outputs=(1..@params["nb_outputs"]).map{|idx| Ident.new(Token.create name=name.succ)}
78
+ @cfg.infos["outputs"]=@outputs
79
+ end
80
+
81
+ def create_variables
82
+ name="`" # succ is 'a'
83
+ @vars=(1..@params["nb_int_vars"]).map{|idx| Ident.new(Token.create name=name.succ)}
84
+ register_readables @vars
85
+ @cfg.infos["int_vars"]=@vars
86
+ end
87
+
88
+ def create_output_assigns
89
+ @cfg.infos["output_assigns"]||=[]
90
+ @outputs.each do |ident|
91
+ @cfg.infos["output_assigns"] << {ident => create_expression}
92
+ end
93
+ end
94
+
95
+ def create_internal_arrays
96
+ @cfg.infos["internal_arrays"]||=[]
97
+ (1..@params["nb_int_arrays"]).each do |idx|
98
+ size=@rng["size_int_arrays"].call.to_i
99
+ size=IntLit.new(Token.create(size.to_s))
100
+ @cfg.infos["internal_arrays"] << {Ident.new(Token.create("t#{idx}")) => size}
101
+ end
102
+ end
103
+
104
+ def create_cfg
105
+ puts " |-->[+] building cfg"
106
+ while @cfg.size < @params["nb_basic_blocks"]
107
+ rec_create_bbs
108
+ end
109
+ end
110
+
111
+ def rec_create_bbs level=0
112
+ if @cfg.size < @params["nb_basic_blocks"]
113
+ type = [:plain,:if,:while,:for].sample
114
+ case type
115
+ when :plain
116
+ gen_plain_block(level)
117
+ when :if
118
+ gen_if_block(level)
119
+ when :while
120
+ gen_while_block(level) if @params["accept_while_loops"]
121
+ when :for
122
+ gen_for_block(level)
123
+ else
124
+ raise "unknown cfg type : #{type}"
125
+ end
126
+ end
127
+ end
128
+
129
+ def gen_plain_block level
130
+ @cfg << bb=BasicBlock.new
131
+ @current.to bb
132
+ @current=bb
133
+ end
134
+
135
+ def gen_if_block level
136
+ @current.infos[:cond]=create_condition
137
+ @current.infos[:start_if]=true
138
+ @cfg << trueBranch =BasicBlock.new
139
+ @cfg << falseBranch=BasicBlock.new
140
+ @cfg << mergeBranch=BasicBlock.new
141
+ @current.to trueBranch
142
+ @current.to falseBranch
143
+
144
+ @current=trueBranch
145
+ rec_create_bbs(level+1)
146
+ @current.to mergeBranch
147
+
148
+ @current=falseBranch
149
+ rec_create_bbs(level+1)
150
+ @current.to mergeBranch
151
+
152
+ @current=mergeBranch
153
+ end
154
+
155
+ def gen_while_block level
156
+ @cfg << cond_bb = BasicBlock.new(:start_while => true)
157
+ cond_bb.infos[:cond]=create_condition
158
+ @cfg << trueBranch = BasicBlock.new
159
+ @cfg << falseBranch = BasicBlock.new
160
+ @current.to cond_bb
161
+ cond_bb.to trueBranch
162
+ cond_bb.to falseBranch
163
+ @current = trueBranch
164
+ rec_create_bbs(level+1)
165
+ @current.to cond_bb
166
+ @current=falseBranch
167
+ end
168
+
169
+ def gen_for_block level
170
+ @cfg << cond_bb = BasicBlock.new(:start_for => true)
171
+ @index||="idx_0"
172
+ @index=@index.succ
173
+ loop_index=Ident.new Token.create @index
174
+ cond_bb.infos["loop_index"]=loop_index
175
+ @cfg.infos["loop_indexes"]||=[]
176
+ @cfg.infos["loop_indexes"] << loop_index
177
+ cond_bb.infos["loop_index_bound"]=@rng["forloop_iterations"].call.to_i
178
+ @cfg << trueBranch = BasicBlock.new
179
+ @cfg << falseBranch = BasicBlock.new
180
+ @cfg << postBranch = BasicBlock.new(:loop_body_end => true)
181
+ @current.to cond_bb
182
+ cond_bb.to trueBranch
183
+ cond_bb.to falseBranch
184
+ @current= trueBranch
185
+ rec_create_bbs(level+1)
186
+ @current.to postBranch
187
+ @current=postBranch
188
+ @current.to cond_bb
189
+ @current=falseBranch
190
+ end
191
+
192
+ def populate_all
193
+ puts " |-->[+] populate cfg"
194
+ @cfg.each{|bb| populate bb}
195
+ end
196
+
197
+ def populate bb
198
+ @rng["assigns_per_bbs"].call.to_i.times do
199
+ bb << create_assign
200
+ end
201
+ end
202
+
203
+ def create_assign
204
+ lhs=create_assignee
205
+ rhs=create_expression()
206
+ Assign.new(lhs,ASSIGN,rhs)
207
+ end
208
+
209
+ def create_assignee
210
+ if @params["nb_int_arrays"]>0
211
+ case r=rand(0..10)
212
+ when 0..3
213
+ name,size=@cfg.infos["internal_arrays"].sample.first
214
+ var=@readables.sample
215
+ @readables.rotate!
216
+ abs_func=Ident.new(Token.create "abs")
217
+ return Indexed.new(name,FunCall.new(abs_func,[Binary.new(var,MOD,size)]))
218
+ end
219
+ end
220
+ assignee=@vars.first
221
+ @vars.rotate!
222
+ return assignee
223
+ end
224
+
225
+ def create_condition
226
+ lhs=create_expression()
227
+ op =create_cond_op()
228
+ rhs=create_expression()
229
+ Binary.new(lhs,op,rhs)
230
+ end
231
+
232
+ def create_expression
233
+ depth=@rng["assigns_expression_depth"].call.to_i
234
+ return create_binary_expression(depth)
235
+ end
236
+
237
+ def create_binary_expression depth
238
+ if depth <= 1
239
+ lhs=create_unary_expression
240
+ rhs=create_unary_expression
241
+ else
242
+ lhs=create_binary_expression(depth-1)
243
+ rhs=create_binary_expression(depth-1)
244
+ end
245
+ op=create_binary_op
246
+ if op.val=="/" and lhs.to_s=="0"
247
+ return create_binary_expression(depth)
248
+ else
249
+ return Parenth.new(Binary.new(lhs,op,rhs))
250
+ end
251
+ end
252
+
253
+ ARITH={
254
+ :add => "+",
255
+ :sub => "-",
256
+ :mul => "*",
257
+ :div => "/",
258
+ #:shift_r => ">>",
259
+ #:shift_l => "<<",
260
+ }
261
+
262
+ COMP={
263
+ :gt => ">",
264
+ :gte => ">=",
265
+ :lt => "<",
266
+ :lte => "<=",
267
+ :eq => "==",
268
+ :neq => "!="
269
+
270
+ }
271
+
272
+ COMPA=[:gt,:lt,:eq,:neq,:gte,:lte]
273
+ ACCUM=[:add_assign,:sub_assign,:mul_assign,:div_assign]
274
+ LOGIC=[:or,:and,:xor]
275
+ MINUS=Token.new [:sub,"-",[0,0]]
276
+
277
+ def create_binary_op
278
+ kind,val=ARITH.sample
279
+ if @params["accept_integer_division"]==false and kind==:div
280
+ return create_binary_op # retry
281
+ end
282
+ Token.new([kind,val,[0,0]])
283
+ end
284
+
285
+ def create_cond_op
286
+ kind,val=COMP.sample
287
+ Token.new([kind,val,[0,0]])
288
+ end
289
+
290
+ def create_unary_expression
291
+ r=rand(0..10)
292
+ case r
293
+ when 1
294
+ return IntLit.new Token.create rand(0..255).to_s
295
+ when 2
296
+ return Parenth.new(Unary.new(MINUS,@readables.sample))
297
+ when 3
298
+ name,size=@cfg.infos["internal_arrays"].sample.first
299
+ var=@readables.sample
300
+ abs_func=Ident.new(Token.create "abs")
301
+ index=FunCall.new(abs_func,[Binary.new(var,MOD,size)])
302
+ return Indexed.new(name,index) #eg : t[abs(a % 4)]
303
+ else
304
+ return @readables.sample
305
+ end
306
+ end
307
+
308
+ def generate_c
309
+ PrinterC.new.print(cfg)
310
+ end
311
+ end
312
+ end
@@ -1,3 +1,3 @@
1
1
  module Crokus
2
- VERSION="0.0.3"
2
+ VERSION="0.0.4"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: crokus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean-Christophe Le Lann
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-03 00:00:00.000000000 Z
11
+ date: 2019-10-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: distribution
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.7.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: colorize
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 0.8.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 0.8.1
27
41
  description: Crokus is developped in Ruby and aims at providing simple basis for C
28
42
  transformations. It has been use for teaching purposes and applied to Electronic
29
43
  System Level experiments.
@@ -41,6 +55,8 @@ files:
41
55
  - lib/crokus/cfg_builder.rb
42
56
  - lib/crokus/cfg_cleaner.rb
43
57
  - lib/crokus/cfg_printer.rb
58
+ - lib/crokus/cfg_printer_c.rb
59
+ - lib/crokus/cfg_random_gen.rb
44
60
  - lib/crokus/cleaner.rb
45
61
  - lib/crokus/code.rb
46
62
  - lib/crokus/compiler.rb