source: trunk/lib_c/cpp2c.rb @ 3391

Last change on this file since 3391 was 3391, checked in by linmengl, 6 years ago

check in IDISA C library and other support libraries. Some template features still remain.

  • Property svn:executable set to *
File size: 4.2 KB
Line 
1#!/home/linmengl/.rvm/rubies/ruby-1.9.3-p327/bin/ruby
2
3# Translate Cpp header files to C
4# Change IDISA calling signatures like esimd<8>::mergel into esimd_mergel_8
5
6# Opt parse, run me with `./cpp2c.rb -h` to see help
7require 'optparse'
8
9options = {:del_origin => false}
10OptionParser.new do |opts|
11        opts.banner = "Translate Cpp header files to C\nUsage: cpp2c.rb cpp_file [options]"
12
13        opts.on("-v", "--[no-]version", "Show version") do
14                puts "cpp2c.rb, Ver 1.0. By Meng Lin"
15        end
16
17        opts.on("-o", "--output [OutFile]", String, "Output file") do |o_file|
18                options[:output] = o_file
19        end
20
21        opts.on("-d", "--delete", "Delete original file [Default: NO]") do 
22                options[:del_origin] = true
23        end
24
25        opts.on_tail("-h", "--help", "Show this message") do
26                puts opts
27                exit
28        end
29end.parse!
30
31if ARGV.size != 1
32        puts "Wrong arguments, run with -h to see help info."
33        exit
34end
35
36options[:input] = ARGV[0]
37
38unless options.has_key? :output
39        t = options[:input].gsub(/\.hpp/, ".h").gsub(/\.cpp/, ".c")
40        if t == options[:input]
41                t << ".c"
42        end
43        options[:output] = t
44end
45
46puts "Running with #{options.inspect}"
47
48# Function Class
49
50class LineStore
51        @@store = ""
52        def self.get_code
53                @@store 
54        end
55
56        def self.store_line line
57                @@store += line
58
59                # line stored, return a empty line
60                "<empty>"
61        end
62
63        def self.dump
64                return "" if @@store =~ /^[\s\n]*$/
65
66                begin
67                        res = "#if (BLOCK_SIZE == 128) \n"
68                        res += @@store.gsub /(?<=\{\{\{)BLOCK_SIZE\b/, "128"
69                        res += "#else\n"
70                        res += @@store.gsub /(?<=\{\{\{)BLOCK_SIZE\b/, "256"
71                        res += "#endif\n"
72                rescue => err
73                        puts @@store
74                        err
75                end
76
77                @@store = ""
78                res
79        end
80end
81
82class LineTranslator   
83        # Those 3 functions are used as pipeline.       
84
85        # Basic regex translation, including head files, calling signatures
86        def self.t_basic_line line
87                if line =~ /^\#/
88                        line.gsub!(/_HPP/, "_H")
89                        line.gsub!("idisa.hpp", "idisa128_c.h")
90                        line.gsub!("idisa128.hpp", "idisa128_c.h")
91                        line.gsub!(/.hpp\"/, ".h\"")
92                end
93
94                # format_2: opPattern = 0
95                #       class_name<fw>::op(data_type arg, ...)
96                f2 = /(simd\d*|hsimd\d*|esimd\d*|mvmd\d*|bitblock\d*)\<([^>]*)\>::(\w*)\(/
97                m = line.match f2
98                if m
99                        calling = "#{m[1]}_#{m[3]}_{{{#{m[2]}}}}("
100                        line.gsub!(m[0], calling)
101                end
102
103                # format_3: opPattern = 1
104                #       class_name<fw>::op<x>(data_type arg, ...)               
105                f3 = /(simd\d*|hsimd\d*|esimd\d*|mvmd\d*|bitblock\d*)\<([^>]*)\>::(\w*)\<([^>]*)\>\(/
106                m = line.match f3
107                if m
108                        calling = "#{m[1]}_#{m[3]}_{{{#{m[2]}}}}(#{m[4]}, "
109                        line.gsub! m[0], calling
110                end
111
112                # format_4: opPattern = 3
113                #       class_name::op(data_type arg, ...)
114                f4 = /(bitblock\d*)::(\w*)\(/
115                m = line.match f4
116                if m
117                        calling = "#{m[1]}_#{m[2]}("
118                        line.gsub! m[0], calling
119                end
120
121                # format_5: opPattern = 4
122                #       class_name::op<x>(data_type arg, ...)           
123                f5 = /(bitblock\d*)::(\w*)\<([^>]*)\>\(/
124                m = line.match f5
125                if m
126                        calling = "#{m[1]}_#{m[2]}(#{m[3]}, "
127                        line.gsub! m[0], calling
128                end
129
130                # remove redundant comma, e.g. simd_op(, 1) into simd_op(1)
131                line.gsub! /(?<=\(),\s(?=\w+)/, ""
132                # cont. bitblock_srli(sh, ) into bitlblock_srli()
133                line.gsub! /(?<=[\s\w]),\s+(?=\))/, ""
134
135                # Another hack here. simd128 class is basically simd in IDISA C
136                line.gsub! /\b(simd|hsimd|mvmd|esimd)128/, "\\1"
137
138                line
139        end
140
141        # Dealing with BLOCK_SIZE as a template variable.
142        # Also merge continous lines into one "#if #else #endif" block.
143        def self.t_with_line_store line         
144                begin
145                        last = line.clone
146                        line = self.t_basic_line line
147                end while last != line
148
149                if line =~ /\{\{\{BLOCK_SIZE\b/
150                        LineStore.store_line line                       
151                else 
152                        dump = LineStore.dump                   
153                        dump + line
154                end             
155        end
156
157        # Template Evaluation
158        def self.t line
159                line = self.t_with_line_store line
160
161                # Eval all the math inside {{{ }}}, I LOVE RUBY!!!!
162                line.gsub!(/\{\{\{([^\{\}]*)\}\}\}/) { eval($1) }
163
164                line
165        end
166end
167
168# Translation Starts here
169
170begin
171        outfile = File.new(options[:output], "w")
172        outfile.puts("/* Generated by cpp2c.rb from #{options[:input]} \n * Use IDISA C support \n*/\n\n")
173
174        File.open(options[:input], "r") do |infile|
175                while (line = infile.gets)
176                        newline = LineTranslator.t line
177                        outfile.puts(newline) if newline != "<empty>"
178                end
179        end
180        outfile.puts(LineStore.dump) # Dump still stored code lines
181        outfile.close
182
183        if options[:del_origin]
184                puts `rm #{options[:input]}`   
185        end
186rescue => err
187        puts "Exception: #{err}"
188        err
189end
Note: See TracBrowser for help on using the repository browser.