class Bones::Preprocessor

This is the C99 pre-processor for Bones. It has two tasks:

Attributes:

Constants

COPYIN

Copy in directive.

COPYOUT

Copy out directive.

DEFAULT_NAME

Providing a default name in case a algorithm is not named.

IDENTIFIER

Denotes the start of an algorithmic species.

REGEXP_PREFIX

A regular expression captures a prefix in a algorithm (e.g. unordered/multiple).

SCOP_END

Enf of the scop

SCOP_START

Start of the scop

SPECIES_END

This directive denotes the end of a algorithm. It is based on the IDENTIFIER constant.

SPECIES_START

This directive denotes the start of a algorithm. It is based on the IDENTIFIER constant.

SYNC

Synchronise directive.

WHITESPACE

Regular expression to identify whitespaces (tabs, spaces).

Attributes

algorithms[R]
copies[R]
defines[R]
device_header[R]
header_code[R]
scop[R]
target_code[R]

Public Class Methods

new(source_code,directory,filename,scheduler) click to toggle source

This is the method which initializes the preprocessor. Initialization requires the target source code to process, which is then set as the class variable +@source_code+.

   # File lib/bones/preprocessor.rb
47 def initialize(source_code,directory,filename,scheduler)
48         @source_code = source_code
49         @target_code = []
50         @header_code = ''
51         @device_header = ''
52         @directory = directory
53         @filename = filename
54         @algorithms = Array.new
55         @copies = Array.new
56         @defines = {}
57         @found_algorithms = 0
58         @scheduler = scheduler
59 end

Public Instance Methods

process() click to toggle source

This is the method to perform the actual preprocessing. This method takes care of all the pre-processor tasks. The output is stored in the three attributes header_code, algorithms, and target_code.

    # File lib/bones/preprocessor.rb
 65 def process
 66         algorithm_code = ''
 67         species = nil
 68         found = 0
 69         alloc_index, free_index = 0, 0
 70         block_comment = false
 71         a_scop_was_found = false
 72         scop = 0
 73         scop_copies = []
 74         
 75         # Process the file line by line
 76         @source_code.each_line.with_index do |line,index|
 77 
 78                 # Don't consider one-line comments
 79                 if !(line =~ /^#{WHITESPACE}\/\//)
 80 
 81                         # Found the start of a block comment
 82                         if line =~ /\/\*/
 83                                 block_comment = true
 84                         end
 85 
 86                         # Search for the end of the block comment
 87                         if block_comment
 88                                 if line =~ /\*\//
 89                                         block_comment = false
 90                                 end
 91                                 @target_code << line
 92 
 93                         # Not in a block-comment
 94                         else
 95 
 96                                 if line =~ /^#{WHITESPACE}#/
 97                                         
 98                                         # Keep 'include' statements as header code
 99                                         if line =~ /^#{WHITESPACE}#include/
100                                                 @header_code += line
101                                                 if line =~ /"(.*)"/
102                                                         process_header($1)
103                                                 end
104                                         
105                                         # Process 'define' statements for the algorithm code, but also keep as header code
106                                         elsif line =~ /^#{WHITESPACE}#define/
107                                                 @header_code += line
108                                                 @device_header += line
109                                                 match = line.split(/\/\//)[0].scan(/^#{WHITESPACE}#define\s+(\w+)\s+(\S*)/)
110                                                 @defines[match.first[0].to_sym] = match.first[1]
111                                         
112                                         # Found the start of algorithm marker
113                                         elsif line =~ /^#{WHITESPACE}#{SPECIES_START}/
114                                                 if found == 0
115                                                         line = replace_defines(line,@defines)
116                                                         prefix, input, output = marker_to_algorithm(line)
117                                                         puts MESSAGE+'Found algorithm "'+(prefix+' '+input+' '+ARROW+' '+output).lstrip+'"' if VERBOSE
118                                                         species = Bones::Species.new(prefix,input,output)
119                                                         @found_algorithms = @found_algorithms + 1
120                                                 end
121                                                 found = found + 1
122                                                 #@target_code << "int bones_temp_species_start = '#{line.gsub(NL,'')}';"+NL
123                                         
124                                         # Found the end of algorithm marker
125                                         elsif line =~ /^#{WHITESPACE}#{SPECIES_END}/
126                                                 if found == 1
127                                                         name = line.strip.scan(/^#{WHITESPACE}#{SPECIES_END} (.+)/).join
128                                                         name = DEFAULT_NAME if name == ''
129                                                         @algorithms.push(Bones::Algorithm.new(name,@filename,index.to_s,species,algorithm_code))
130                                                         algorithm_code = ''
131                                                 end
132                                                 found = found - 1
133                                                 #@target_code << "int bones_temp_species_end = '#{line.gsub(NL,'')}';"+NL
134                                                 
135                                         # Found a sync marker
136                                         elsif @scheduler && line =~ /^#{WHITESPACE}#{SYNC}/
137                                                 sync = line.strip.scan(/^#{WHITESPACE}#{SYNC} (.+)/).join
138                                                 @target_code << "bones_synchronize(#{sync});"+NL
139                                                 
140                                         # Found a copyin marker
141                                         elsif @scheduler && line =~ /^#{WHITESPACE}#{COPYIN}/
142                                                 copies = line.strip.scan(/^#{WHITESPACE}#{COPYIN} (.+)/).join.split(WEDGE).map{ |c| c.strip }
143                                                 copies.each_with_index do |copy,copynum|
144                                                         name = copy.split('[').first
145                                                         domain = copy.scan(/\[(.+)\]/).join.split(DIM_SEP)
146                                                         deadline = copy.split('|').last
147                                                         @copies.push(Bones::Copy.new(scop,name,domain,deadline,'in',"#{index*100+copynum}"))
148                                                         scop_copies.push(@copies[-1])
149                                                         @target_code << "bones_copyin_#{index*100+copynum}_#{name}(#{name});"+NL
150                                                 end
151                                                 
152                                         # Found a copyout marker
153                                         elsif @scheduler && line =~ /^#{WHITESPACE}#{COPYOUT}/
154                                                 copies = line.strip.scan(/^#{WHITESPACE}#{COPYOUT} (.+)/).join.split(WEDGE).map{ |c| c.strip }
155                                                 copies.each_with_index do |copy,copynum|
156                                                         name = copy.split('[').first
157                                                         domain = copy.scan(/\[(.+)\]/).join.split(DIM_SEP)
158                                                         deadline = copy.split('|').last
159                                                         @copies.push(Bones::Copy.new(scop,name,domain,deadline,'out',"#{index*100+copynum}"))
160                                                         scop_copies.push(@copies[-1])
161                                                         @target_code << "bones_copyout_#{index*100+copynum}_#{name}(#{name});"+NL
162                                                 end
163                                         end
164                                         
165                                         # Check if it was a 'pragma scop' / 'pragma endscop' line
166                                         if line =~ /^#{WHITESPACE}#{SCOP_START}/
167                                                 scop += 1
168                                                 scop_copies = []
169                                                 alloc_index = @target_code.length
170                                                 a_scop_was_found = true
171                                                 @target_code << 'bones_timer_start();'+NL
172                                         elsif line =~ /^#{WHITESPACE}#{SCOP_END}/
173                                                 free_index = @target_code.length
174                                                 @target_code << 'bones_timer_stop();'+NL
175                                                 
176                                                 # Add frees and mallocs
177                                                 if @scheduler
178                                                         alloc_code, free_code = '', ''
179                                                         included_copies = []
180                                                         scop_copies.each do |copy|
181                                                                 if !included_copies.include?(copy.name)
182                                                                         alloc_code += copy.get_function_call('alloc')+NL
183                                                                         free_code += copy.get_function_call('free')+NL
184                                                                         included_copies << copy.name
185                                                                 end
186                                                         end
187                                                         @target_code.insert(alloc_index, alloc_code)
188                                                         @target_code << free_code
189                                                 end
190                                         end
191                                         
192                                 else
193                                         if found > 0
194                                                 algorithm_line = replace_defines(line,@defines)
195                                                 @target_code << algorithm_line
196                                                 algorithm_code += algorithm_line if line !~ /^#{WHITESPACE}#/
197                                         else
198                                                 @target_code << line
199                                         end
200                                 end
201                         end
202                 else
203                         @target_code << line
204                 end
205         end
206         puts WARNING+'Begin/end kernel mismatch ('+@found_algorithms.to_s+' versus '+@algorithms.length.to_s+'), probably missing a "'+SPECIES_END+'"' unless @algorithms.length == @found_algorithms
207         
208         # Print warning if there is no SCoP found
209         if !a_scop_was_found
210                 puts WARNING+'No "#pragma scop" and "#pragma endscop" found!'
211         end
212         
213         # Join the array
214         @target_code = @target_code.join('')
215 end
process_header(filename) click to toggle source

This is the method to preprocess a header file. Currently, it only searches for defines and adds those to a list. In the meanwhile, it also handles ifdef’s.

    # File lib/bones/preprocessor.rb
220 def process_header(filename)
221         ifdefs = [true]
222         
223         # Process the file line by line
224         block_comment = false
225         File.read(File.join(@directory,filename)).each_line.with_index do |line,index|
226                 
227                 # Don't consider one-line comments
228                 if !(line =~ /^#{WHITESPACE}\/\//)
229 
230                         # Found the start of a block comment
231                         if line =~ /\/\*/
232                                 block_comment = true
233                         end
234 
235                         # Search for the end of the block comment
236                         if block_comment
237                                 if line =~ /\*\//
238                                         block_comment = false
239                                 end
240 
241                         # Not in a block-comment
242                         else
243                                 if line =~ /^#{WHITESPACE}#/
244                                         
245                                         # Process 'include' statements
246                                         if line =~ /^#{WHITESPACE}#include/ && ifdefs.last
247                                                 if line =~ /"(.*)"/
248                                                         process_header($1)
249                                                 end
250                                         
251                                         # Process 'define' statements
252                                         elsif line =~ /^#{WHITESPACE}#define/ && ifdefs.last
253                                                 match = line.split(/\/\//)[0].scan(/^#{WHITESPACE}#define\s+(\w+)\s+(\S*)/)
254                                                 @defines[match.first[0].to_sym] = match.first[1].strip
255                                         
256                                         # Process 'ifdef' statements
257                                         elsif line =~ /^#{WHITESPACE}#ifdef#{WHITESPACE}(\w+)/
258                                                 valid = (ifdefs.last) ? @defines.has_key?($1.to_sym) : false
259                                                 ifdefs.push(valid)
260                                                 
261                                         # Process 'endif' statements
262                                         elsif line =~ /^#{WHITESPACE}#endif/
263                                                 ifdefs.pop
264                                         end
265                                 end
266                         end
267                 end
268         end
269 end

Private Instance Methods

marker_to_algorithm(marker) click to toggle source

Method to extract the algorithm details from a marker found in code.

    # File lib/bones/preprocessor.rb
275 def marker_to_algorithm(marker)
276         algorithm = marker.strip.scan(/^#{WHITESPACE}#{SPECIES_START} (.+)/).join
277         prefix = ''
278         if algorithm =~ REGEXP_PREFIX
279                 split = algorithm.partition(' ')
280                 prefix = split[0]
281                 algorithm = split[2]
282         end
283         input  = algorithm.split(ARROW)[0].strip
284         output = algorithm.split(ARROW)[1].strip
285         return prefix, input, output
286 end