QUDA  1.0.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
wrap.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
33 usage_string = \
34 '''Usage: wrap.py [-fgd] [-i pmpi_init] [-c mpicc_name] [-o file] wrapper.w [...]
35  Python script for creating PMPI wrappers. Roughly follows the syntax of
36  the Argonne PMPI wrapper generator, with some enhancements.
37  Options:"
38  -d Just dump function declarations parsed out of mpi.h
39  -f Generate fortran wrappers in addition to C wrappers.
40  -g Generate reentry guards around wrapper functions.
41  -s Skip writing #includes, #defines, and other front-matter (for non-C output).
42  -c exe Provide name of MPI compiler (for parsing mpi.h). Default is \'mpicc\'.
43  -I dir Provide an extra include directory to use when parsing mpi.h.
44  -i pmpi_init Specify proper binding for the fortran pmpi_init function.
45  Default is \'pmpi_init_\'. Wrappers compiled for PIC will guess the
46  right binding automatically (use -DPIC when you compile dynamic libs).
47  -o file Send output to a file instead of stdout.
48  by Todd Gamblin, tgamblin@llnl.gov
49 '''
50 import tempfile, getopt, subprocess, sys, os, re, StringIO, types, itertools
51 
52 # Default values for command-line parameters
53 mpicc = 'mpicc' # Default name for the MPI compiler
54 includes = [] # Default set of directories to inlucde when parsing mpi.h
55 pmpi_init_binding = "pmpi_init_" # Default binding for pmpi_init
56 output_fortran_wrappers = False # Don't print fortran wrappers by default
57 output_guards = False # Don't print reentry guards by default
58 skip_headers = False # Skip header information and defines (for non-C output)
59 dump_prototypes = False # Just exit and dump MPI protos if false.
60 
61 # Possible legal bindings for the fortran version of PMPI_Init()
62 pmpi_init_bindings = ["PMPI_INIT", "pmpi_init", "pmpi_init_", "pmpi_init__"]
63 
64 # Possible function return types to consider, used for declaration parser.
65 # In general, all MPI calls we care about return int. We include double
66 # to grab MPI_Wtick and MPI_Wtime, but we'll ignore the f2c and c2f calls
67 # that return MPI_Datatypes and other such things.
68 rtypes = ['int', 'double' ]
69 
70 # If we find these strings in a declaration, exclude it from consideration.
71 exclude_strings = [ "c2f", "f2c", "typedef" ]
72 
73 # Regular expressions for start and end of declarations in mpi.h. These are
74 # used to get the declaration strings out for parsing with formal_re below.
75 begin_decl_re = re.compile("(" + "|".join(rtypes) + ")\s+(MPI_\w+)\s*\(")
76 exclude_re = re.compile("|".join(exclude_strings))
77 end_decl_re = re.compile("\).*\;")
78 
79 # Regular Expression for splitting up args. Matching against this
80 # returns three groups: type info, arg name, and array info
81 formal_re = re.compile(
82  "\s*(" + # Start type
83  "(?:const)?\s*" + # Initial const
84  "\w+" # Type name (note: doesn't handle 'long long', etc. right now)
85  ")\s*(" + # End type, begin pointers
86  "(?:\s*\*(?:\s*const)?)*" + # Look for 0 or more pointers with optional 'const'
87  ")\s*" # End pointers
88  "(?:(\w+)\s*)?" + # Argument name. Optional.
89  "(\[.*\])?\s*$" # Array type. Also optional. Works for multidimensions b/c it's greedy.
90  )
91 
92 # Fortran wrapper suffix
93 f_wrap_suffix = "_fortran_wrapper"
94 
95 # Initial includes and defines for wrapper files.
96 wrapper_includes = '''
97 #include <mpi.h>
98 #include <stdio.h>
99 #include <stdlib.h>
100 #ifndef _EXTERN_C_
101 #ifdef __cplusplus
102 #define _EXTERN_C_ extern "C"
103 #else /* __cplusplus */
104 #define _EXTERN_C_
105 #endif /* __cplusplus */
106 #endif /* _EXTERN_C_ */
107 #ifdef MPICH_HAS_C2F
108 _EXTERN_C_ void *MPIR_ToPointer(int);
109 #endif // MPICH_HAS_C2F
110 #ifdef PIC
111 /* For shared libraries, declare these weak and figure out which one was linked
112  based on which init wrapper was called. See mpi_init wrappers. */
113 #pragma weak pmpi_init
114 #pragma weak PMPI_INIT
115 #pragma weak pmpi_init_
116 #pragma weak pmpi_init__
117 #endif /* PIC */
118 _EXTERN_C_ void pmpi_init(MPI_Fint *ierr);
119 _EXTERN_C_ void PMPI_INIT(MPI_Fint *ierr);
120 _EXTERN_C_ void pmpi_init_(MPI_Fint *ierr);
121 _EXTERN_C_ void pmpi_init__(MPI_Fint *ierr);
122 '''
123 
124 # Default modifiers for generated bindings
125 default_modifiers = ["_EXTERN_C_"] # _EXTERN_C_ is #defined (or not) in wrapper_includes. See above.
126 
127 # Set of MPI Handle types
128 mpi_handle_types = set(["MPI_Comm", "MPI_Errhandler", "MPI_File", "MPI_Group", "MPI_Info",
129  "MPI_Op", "MPI_Request", "MPI_Status", "MPI_Datatype", "MPI_Win" ])
130 
131 # MPI Calls that have array parameters, and mappings from the array parameter positions to the position
132 # of the 'count' paramters that determine their size
133 mpi_array_calls = {
134  "MPI_Startall" : { 1:0 },
135  "MPI_Testall" : { 1:0, 3:0 },
136  "MPI_Testany" : { 1:0 },
137  "MPI_Testsome" : { 1:0, 4:0 },
138  "MPI_Type_create_struct" : { 3:0 },
139  "MPI_Type_get_contents" : { 6:1 },
140  "MPI_Type_struct" : { 3:0 },
141  "MPI_Waitall" : { 1:0, 2:0 },
142  "MPI_Waitany" : { 1:0 },
143  "MPI_Waitsome" : { 1:0, 4:0 }
144 }
145 
146 
147 def find_matching_paren(string, index, lparen='(', rparen=')'):
148  """Find the closing paren corresponding to the open paren at <index>
149  in <string>. Optionally, can provide other characters to match on.
150  If found, returns the index of the matching parenthesis. If not found,
151  returns -1.
152  """
153  if not string[index] == lparen:
154  raise ValueError("Character at index %d is '%s'. Expected '%s'"
155  % (index, string[index], lparen))
156  index += 1
157  count = 1
158  while index < len(string) and count > 0:
159  while index < len(string) and string[index] not in (lparen, rparen):
160  index += 1
161  if string[index] == lparen:
162  count += 1
163  elif string[index] == rparen:
164  count -= 1
165 
166  if count == 0:
167  return index
168  else:
169  return -1
170 
171 
172 def isindex(str):
173  """True if a string is something we can index an array with."""
174  try:
175  int(str)
176  return True
177  except ValueError:
178  return False
179 
180 def once(function):
181  if not hasattr(function, "did_once"):
182  function()
183  function.did_once = True
184 
185 # Returns MPI_Blah_[f2c,c2f] prefix for a handle type. MPI_Datatype is a special case.
186 def conversion_prefix(handle_type):
187  if handle_type == "MPI_Datatype":
188  return "MPI_Type"
189  else:
190  return handle_type
191 
192 # Special join function for joining lines together. Puts "\n" at the end too.
193 def joinlines(list, sep="\n"):
194  if list:
195  return sep.join(list) + sep
196  else:
197  return ""
198 
199 # Possible types of Tokens in input.
200 LBRACE, RBRACE, TEXT, IDENTIFIER = range(4)
201 
202 class Token:
203  """Represents tokens; generated from input by lexer and fed to parse()."""
204  def __init__(self, type, value, line=0):
205  self.type = type # Type of token
206  self.value = value # Text value
207  self.line = line
208 
209  def __str__(self):
210  return "'%s'" % re.sub(r'\n', "\\\\n", self.value)
211 
212  def isa(self, type):
213  return self.type == type
214 
215 
216 class LineTrackingLexer(object):
217  """Base class for Lexers that keep track of line numbers."""
218  def __init__(self, lexicon):
219  self.line_no = -1
220  self.scanner = re.Scanner(lexicon)
221 
222  def make_token(self, type, value):
223  token = Token(type, value, self.line_no)
224  self.line_no += value.count("\n")
225  return token
226 
227  def lex(self, text):
228  self.line_no = 0
229  tokens, remainder = self.scanner.scan(text)
230  if remainder:
231  sys.stderr.write("Unlexable input:\n%s\n" % remainder)
232  sys.exit(1)
233  self.line_no = -1
234  return tokens
235 
236 class OuterRegionLexer(LineTrackingLexer):
237  def __init__(self):
238  super(OuterRegionLexer, self).__init__([
239  (r'{{', self.lbrace),
240  (r'}}', self.rbrace),
241  (r'({(?!{)|}(?!})|[^{}])*', self.text)])
242  def lbrace(self, scanner, token): return self.make_token(LBRACE, token)
243  def rbrace(self, scanner, token): return self.make_token(RBRACE, token)
244  def text(self, scanner, token): return self.make_token(TEXT, token)
245 
246 class OuterCommentLexer(OuterRegionLexer):
247  def __init__(self):
248  super(OuterRegionLexer, self).__init__([
249  (r'/\*(.|[\r\n])*?\*/', self.text), # multiline comment
250  (r'//(.|[\r\n])*?(?=[\r\n])', self.text), # single line comment
251  (r'{{', self.lbrace),
252  (r'}}', self.rbrace),
253  (r'({(?!{)|}(?!})|/(?![/*])|[^{}/])*', self.text)])
254 
255 class InnerLexer(OuterRegionLexer):
256  def __init__(self):
257  super(OuterRegionLexer, self).__init__([
258  (r'{{', self.lbrace),
259  (r'}}', self.rbrace),
260  (r'(["\'])?((?:(?!\1)[^\\]|\\.)*)\1', self.quoted_id),
261  (r'([^\s]+)', self.identifier),
262  (r'\s+', None)])
263  def identifier(self, scanner, token): return self.make_token(IDENTIFIER, token)
264  def quoted_id(self, scanner, token):
265  # remove quotes from quoted ids. Note that ids and quoted ids are pretty much the same thing;
266  # the quotes are just optional. You only need them if you need spaces in your expression.
267  return self.make_token(IDENTIFIER, re.sub(r'^["\'](.*)["\']$', '\\1', token))
268 
269 # Global current filename and function name for error msgs
270 cur_filename = ""
271 cur_function = None
272 
273 class WrapSyntaxError:
274  """Simple Class for syntax errors raised by the wrapper generator (rather than python)"""
275  pass
276 
277 def syntax_error(msg):
278  # TODO: make line numbers actually work.
279  sys.stderr.write("%s:%d: %s\n" % (cur_filename, 0, msg))
280  if cur_function:
281  sys.stderr.write(" While handling %s.\n" % cur_function)
282  raise WrapSyntaxError
283 
284 
289 class Scope:
290  """ This is the very basic class for scopes in the wrapper generator. Scopes
291  are hierarchical and support nesting. They contain string keys mapped
292  to either string values or to macro functions.
293  Scopes also keep track of the particular macro they correspond to (macro_name).
294  """
295  def __init__(self, enclosing_scope=None):
296  self.map = {}
297  self.enclosing_scope = enclosing_scope
298  self.macro_name = None # For better debugging error messages
299 
300  def __getitem__(self, key):
301  if key in self.map: return self.map[key]
302  elif self.enclosing_scope: return self.enclosing_scope[key]
303  else: raise KeyError(key + " is not in scope.")
304 
305  def __contains__(self, key):
306  if key in self.map: return True
307  elif self.enclosing_scope: return key in self.enclosing_scope
308  else: return False
309 
310  def __setitem__(self, key, value):
311  self.map[key] = value
312 
313  def include(self, map):
314  """Add entire contents of the map (or scope) to this scope."""
315  self.map.update(map)
316 
317 
323 mpi_functions = {}
324 
325 class Param:
326  """Descriptor for formal parameters of MPI functions.
327  Doesn't represent a full parse, only the initial type information,
328  name, and array info of the argument split up into strings.
329  """
330  def __init__(self, type, pointers, name, array, pos):
331  self.type = type # Name of arg's type (might include things like 'const')
332  self.pointers = pointers # Pointers
333  self.name = name # Formal parameter name (from header or autogenerated)
334  self.array = array # Any array type information after the name
335  self.pos = pos # Position of arg in declartion
336  self.decl = None # This gets set later by Declaration
337 
338  def setDeclaration(self, decl):
339  """Needs to be called by Declaration to finish initing the arg."""
340  self.decl = decl
341 
342  def isHandleArray(self):
343  """True if this Param represents an array of MPI handle values."""
344  return (self.decl.name in mpi_array_calls
345  and self.pos in mpi_array_calls[self.decl.name])
346 
347  def countParam(self):
348  """If this Param is a handle array, returns the Param that represents the count of its elements"""
349  return self.decl.args[mpi_array_calls[self.decl.name][self.pos]]
350 
351  def isHandle(self):
352  """True if this Param is one of the MPI builtin handle types."""
353  return self.type in mpi_handle_types
354 
355  def isStatus(self):
356  """True if this Param is an MPI_Status. MPI_Status is handled differently
357  in c2f/f2c calls from the other handle types.
358  """
359  return self.type == "MPI_Status"
360 
361  def fortranFormal(self):
362  """Prints out a formal parameter for a fortran wrapper."""
363  # There are only a few possible fortran arg types in our wrappers, since
364  # everything is a pointer.
365  if self.type == "MPI_Aint" or self.type.endswith("_function"):
366  ftype = self.type
367  else:
368  ftype = "MPI_Fint"
369 
370  # Arrays don't come in as pointers (they're passed as arrays)
371  # Everything else is a pointer.
372  if self.pointers:
373  pointers = self.pointers
374  elif self.array:
375  pointers = ""
376  else:
377  pointers = "*"
378 
379  # Put it all together and return the fortran wrapper type here.
380  arr = self.array or ''
381  return "%s %s%s%s" % (ftype, pointers, self.name, arr)
382 
383  def cType(self):
384  if not self.type:
385  return ''
386  else:
387  arr = self.array or ''
388  pointers = self.pointers or ''
389  return "%s%s%s" % (self.type, pointers, arr)
390 
391  def cFormal(self):
392  """Prints out a formal parameter for a C wrapper."""
393  if not self.type:
394  return self.name # special case for '...'
395  else:
396  arr = self.array or ''
397  pointers = self.pointers or ''
398  return "%s %s%s%s" % (self.type, pointers, self.name, arr)
399 
400  def castType(self):
401  arr = self.array or ''
402  pointers = self.pointers or ''
403  if '[]' in arr:
404  if arr.count('[') > 1:
405  pointers += '(*)' # need extra parens for, e.g., int[][3] -> int(*)[3]
406  else:
407  pointers += '*' # justa single array; can pass pointer.
408  arr = arr.replace('[]', '')
409  return "%s%s%s" % (self.type, pointers, arr)
410 
411  def __str__(self):
412  return self.cFormal()
413 
414 
415 class Declaration:
416  """ Descriptor for simple MPI function declarations.
417  Contains return type, name of function, and a list of args.
418  """
419  def __init__(self, rtype, name):
420  self.rtype = rtype
421  self.name = name
422  self.args = []
423 
424  def addArgument(self, arg):
425  arg.setDeclaration(self)
426  self.args.append(arg)
427 
428  def __iter__(self):
429  for arg in self.args: yield arg
430 
431  def __str__(self):
432  return self.prototype()
433 
434  def retType(self):
435  return self.rtype
436 
437  def formals(self):
438  return [arg.cFormal() for arg in self.args]
439 
440  def types(self):
441  return [arg.cType() for arg in self.args]
442 
443  def argsNoEllipsis(self):
444  return filter(lambda arg: arg.name != "...", self.args)
445 
446  def returnsErrorCode(self):
447  """This is a special case for MPI_Wtime and MPI_Wtick.
448  These functions actually return a double value instead of an int error code.
449  """
450  return self.rtype == "int"
451 
452  def argNames(self):
453  return [arg.name for arg in self.argsNoEllipsis()]
454 
455  def getArgName(self, index):
456  return self.argsNoEllipsis()[index].name
457 
458  def fortranFormals(self):
459  formals = map(Param.fortranFormal, self.argsNoEllipsis())
460  if self.name == "MPI_Init": formals = [] # Special case for init: no args in fortran
461 
462  ierr = []
463  if self.returnsErrorCode(): ierr = ["MPI_Fint *ierr"]
464  return formals + ierr
465 
466  def fortranArgNames(self):
467  names = self.argNames()
468  if self.name == "MPI_Init": names = []
469 
470  ierr = []
471  if self.returnsErrorCode(): ierr = ["ierr"]
472  return names + ierr
473 
474  def prototype(self, modifiers=""):
475  if modifiers: modifiers = joinlines(modifiers, " ")
476  return "%s%s %s(%s)" % (modifiers, self.retType(), self.name, ", ".join(self.formals()))
477 
478  def pmpi_prototype(self, modifiers=""):
479  if modifiers: modifiers = joinlines(modifiers, " ")
480  return "%s%s P%s(%s)" % (modifiers, self.retType(), self.name, ", ".join(self.formals()))
481 
482  def fortranPrototype(self, name=None, modifiers=""):
483  if not name: name = self.name
484  if modifiers: modifiers = joinlines(modifiers, " ")
485 
486  if self.returnsErrorCode():
487  rtype = "void" # Fortran calls use ierr parameter instead
488  else:
489  rtype = self.rtype
490  return "%s%s %s(%s)" % (modifiers, rtype, name, ", ".join(self.fortranFormals()))
491 
492 
493 types = set()
494 all_pointers = set()
495 
496 def enumerate_mpi_declarations(mpicc, includes):
497  """ Invokes mpicc's C preprocessor on a C file that includes mpi.h.
498  Parses the output for declarations, and yields each declaration to
499  the caller.
500  """
501  # Create an input file that just includes <mpi.h>
502  tmpfile = tempfile.NamedTemporaryFile('w+b', -1, '.c')
503  tmpname = "%s" % tmpfile.name
504  tmpfile.write('#include <mpi.h>')
505  tmpfile.write("\n")
506  tmpfile.flush()
507 
508  # Run the mpicc -E on the temp file and pipe the output
509  # back to this process for parsing.
510  string_includes = ["-I"+dir for dir in includes]
511  mpicc_cmd = "%s -E %s" % (mpicc, " ".join(string_includes))
512  try:
513  popen = subprocess.Popen("%s %s" % (mpicc_cmd, tmpname), shell=True,
514  stdout=subprocess.PIPE, stderr=subprocess.PIPE)
515  except IOError:
516  sys.stderr.write("IOError: couldn't run '" + mpicc_cmd + "' for parsing mpi.h\n")
517  sys.exit(1)
518 
519  # Parse out the declarations from the MPI file
520  mpi_h = popen.stdout
521  for line in mpi_h:
522  line = line.strip()
523  begin = begin_decl_re.search(line)
524  if begin and not exclude_re.search(line):
525  # Grab return type and fn name from initial parse
526  return_type, fn_name = begin.groups()
527 
528  # Accumulate rest of declaration (possibly multi-line)
529  while not end_decl_re.search(line):
530  line += " " + mpi_h.next().strip()
531 
532  # Split args up by commas so we can parse them independently
533  fn_and_paren = r'(%s\s*\()' % fn_name
534  match = re.search(fn_and_paren, line)
535  lparen = match.start(1) + len(match.group(1)) - 1
536  rparen = find_matching_paren(line, lparen)
537  if rparen < 0:
538  raise ValueError("Malformed declaration in header: '%s'" % line)
539 
540  arg_string = line[lparen+1:rparen]
541  arg_list = map(lambda s: s.strip(), arg_string.split(","))
542 
543  # Handle functions that take no args specially
544  if arg_list == ['void']:
545  arg_list = []
546 
547  # Parse formal parameter descriptors out of args
548  decl = Declaration(return_type, fn_name)
549  arg_num = 0
550  for arg in arg_list:
551  if arg == '...': # Special case for Pcontrol.
552  decl.addArgument(Param(None, None, '...', None, arg_num))
553  else:
554  match = formal_re.match(arg)
555  if not match:
556  sys.stderr.write("MATCH FAILED FOR: '%s' in %s\n" % (arg, fn_name))
557  sys.exit(1)
558 
559  type, pointers, name, array = match.groups()
560  types.add(type)
561  all_pointers.add(pointers)
562  # If there's no name, make one up.
563  if not name: name = "arg_" + str(arg_num)
564 
565  decl.addArgument(Param(type.strip(), pointers, name, array, arg_num))
566  arg_num += 1
567 
568  yield decl
569 
570  mpi_h.close()
571  return_code = popen.wait()
572  if return_code != 0:
573  sys.stderr.write("Error: Couldn't run '%s' for parsing mpi.h.\n" % mpicc_cmd)
574  sys.stderr.write(" Process exited with code %d.\n" % return_code)
575  sys.exit(1)
576 
577  # Do some cleanup once we're done reading.
578  tmpfile.close()
579 
580 
581 def write_enter_guard(out, decl):
582  """Prevent us from entering wrapper functions if we're already in a wrapper function.
583  Just call the PMPI function w/o the wrapper instead."""
584  if output_guards:
585  out.write(" if (in_wrapper) return P%s(%s);\n" % (decl.name, ", ".join(decl.argNames())))
586  out.write(" in_wrapper = 1;\n")
587 
588 def write_exit_guard(out):
589  """After a call, set in_wrapper back to 0 so we can enter the next call."""
590  if output_guards:
591  out.write(" in_wrapper = 0;\n")
592 
593 
594 def write_c_wrapper(out, decl, return_val, write_body):
595  """Write the C wrapper for an MPI function."""
596  # Write the PMPI prototype here in case mpi.h doesn't define it
597  # (sadly the case with some MPI implementaitons)
598  out.write(decl.pmpi_prototype(default_modifiers))
599  out.write(";\n")
600 
601  # Now write the wrapper function, which will call the PMPI function we declared.
602  out.write(decl.prototype(default_modifiers))
603  out.write(" { \n")
604  out.write(" %s %s = 0;\n" % (decl.retType(), return_val))
605 
606  write_enter_guard(out, decl)
607  write_body(out)
608  write_exit_guard(out)
609 
610  out.write(" return %s;\n" % return_val)
611  out.write("}\n\n")
612 
613 
614 def write_fortran_binding(out, decl, delegate_name, binding, stmts=None):
615  """Outputs a wrapper for a particular fortran binding that delegates to the
616  primary Fortran wrapper. Optionally takes a list of statements to execute
617  before delegating.
618  """
619  out.write(decl.fortranPrototype(binding, default_modifiers))
620  out.write(" { \n")
621  if stmts:
622  out.write(joinlines(map(lambda s: " " + s, stmts)))
623  if decl.returnsErrorCode():
624  # regular MPI fortran functions use an error code
625  out.write(" %s(%s);\n" % (delegate_name, ", ".join(decl.fortranArgNames())))
626  else:
627  # wtick and wtime return a value
628  out.write(" return %s(%s);\n" % (delegate_name, ", ".join(decl.fortranArgNames())))
629  out.write("}\n\n")
630 
631 
632 class FortranDelegation:
633  """Class for constructing a call to a Fortran wrapper delegate function. Provides
634  storage for local temporary variables, copies of parameters, callsites for MPI-1 and
635  MPI-2, and writebacks to local pointer types.
636  """
637  def __init__(self, decl, return_val):
638  self.decl = decl
639  self.return_val = return_val
640 
641  self.temps = set()
642  self.copies = []
643  self.writebacks = []
644  self.actuals = []
645  self.mpich_actuals = []
646 
647  def addTemp(self, type, name):
648  """Adds a temp var with a particular name. Adds the same var only once."""
649  temp = " %s %s;" % (type, name)
650  self.temps.add(temp)
651 
652  def addActual(self, actual):
653  self.actuals.append(actual)
654  self.mpich_actuals.append(actual)
655 
656  def addActualMPICH(self, actual):
657  self.mpich_actuals.append(actual)
658 
659  def addActualMPI2(self, actual):
660  self.actuals.append(actual)
661 
662  def addWriteback(self, stmt):
663  self.writebacks.append(" %s" % stmt)
664 
665  def addCopy(self, stmt):
666  self.copies.append(" %s" % stmt)
667 
668  def write(self, out):
669  assert len(self.actuals) == len(self.mpich_actuals)
670 
671  call = " %s = %s" % (self.return_val, self.decl.name)
672  mpich_call = "%s(%s);\n" % (call, ", ".join(self.mpich_actuals))
673  mpi2_call = "%s(%s);\n" % (call, ", ".join(self.actuals))
674 
675  out.write(" %s %s = 0;\n" % (self.decl.retType(), self.return_val))
676  if mpich_call == mpi2_call and not (self.temps or self.copies or self.writebacks):
677  out.write(mpich_call)
678  else:
679  out.write("#if (!defined(MPICH_HAS_C2F) && defined(MPICH_NAME) && (MPICH_NAME == 1)) /* MPICH test */\n")
680  out.write(mpich_call)
681  out.write("#else /* MPI-2 safe call */\n")
682  out.write(joinlines(self.temps))
683  out.write(joinlines(self.copies))
684  out.write(mpi2_call)
685  out.write(joinlines(self.writebacks))
686  out.write("#endif /* MPICH test */\n")
687 
688 
689 def write_fortran_wrappers(out, decl, return_val):
690  """Writes primary fortran wrapper that handles arg translation.
691  Also outputs bindings for this wrapper for different types of fortran compilers.
692  """
693  delegate_name = decl.name + f_wrap_suffix
694  out.write(decl.fortranPrototype(delegate_name, ["static"]))
695  out.write(" { \n")
696 
697  call = FortranDelegation(decl, return_val)
698 
699  if decl.name == "MPI_Init":
700  # Use out.write() here so it comes at very beginning of wrapper function
701  out.write(" int argc = 0;\n");
702  out.write(" char ** argv = NULL;\n");
703  call.addActual("&argc");
704  call.addActual("&argv");
705  call.write(out)
706  out.write(" *ierr = %s;\n" % return_val)
707  out.write("}\n\n")
708 
709  # Write out various bindings that delegate to the main fortran wrapper
710  write_fortran_binding(out, decl, delegate_name, "MPI_INIT", ["fortran_init = 1;"])
711  write_fortran_binding(out, decl, delegate_name, "mpi_init", ["fortran_init = 2;"])
712  write_fortran_binding(out, decl, delegate_name, "mpi_init_", ["fortran_init = 3;"])
713  write_fortran_binding(out, decl, delegate_name, "mpi_init__", ["fortran_init = 4;"])
714  return
715 
716  # This look processes the rest of the call for all other routines.
717  for arg in decl.args:
718  if arg.name == "...": # skip ellipsis
719  continue
720 
721  if not (arg.pointers or arg.array):
722  if not arg.isHandle():
723  # These are pass-by-value arguments, so just deref and pass thru
724  dereferenced = "*%s" % arg.name
725  call.addActual(dereferenced)
726  else:
727  # Non-ptr, non-arr handles need to be converted with MPI_Blah_f2c
728  # No special case for MPI_Status here because MPI_Statuses are never passed by value.
729  call.addActualMPI2("%s_f2c(*%s)" % (conversion_prefix(arg.type), arg.name))
730  call.addActualMPICH("(%s)(*%s)" % (arg.type, arg.name))
731 
732  else:
733  if not arg.isHandle():
734  # Non-MPI handle pointer types can be passed w/o dereferencing, but need to
735  # cast to correct pointer type first (from MPI_Fint*).
736  call.addActual("(%s)%s" % (arg.castType(), arg.name))
737  else:
738  # For MPI-1, assume ints, cross fingers, and pass things straight through.
739  call.addActualMPICH("(%s*)%s" % (arg.type, arg.name))
740  conv = conversion_prefix(arg.type)
741  temp = "temp_%s" % arg.name
742 
743  # For MPI-2, other pointer and array types need temporaries and special conversions.
744  if not arg.isHandleArray():
745  call.addTemp(arg.type, temp)
746  call.addActualMPI2("&%s" % temp)
747 
748  if arg.isStatus():
749  call.addCopy("%s_f2c(%s, &%s);" % (conv, arg.name, temp))
750  call.addWriteback("%s_c2f(&%s, %s);" % (conv, temp, arg.name))
751  else:
752  call.addCopy("%s = %s_f2c(*%s);" % (temp, conv, arg.name))
753  call.addWriteback("*%s = %s_c2f(%s);" % (arg.name, conv, temp))
754  else:
755  # Make temporary variables for the array and the loop var
756  temp_arr_type = "%s*" % arg.type
757  call.addTemp(temp_arr_type, temp)
758  call.addTemp("int", "i")
759 
760  # generate a copy and a writeback statement for this type of handle
761  if arg.isStatus():
762  copy = " %s_f2c(&%s[i], &%s[i])" % (conv, arg.name, temp)
763  writeback = " %s_c2f(&%s[i], &%s[i])" % (conv, temp, arg.name)
764  else:
765  copy = " temp_%s[i] = %s_f2c(%s[i])" % (arg.name, conv, arg.name)
766  writeback = " %s[i] = %s_c2f(temp_%s[i])" % (arg.name, conv, arg.name)
767 
768  # Generate the call surrounded by temp array allocation, copies, writebacks, and temp free
769  count = "*%s" % arg.countParam().name
770  call.addCopy("%s = (%s)malloc(sizeof(%s) * %s);" %
771  (temp, temp_arr_type, arg.type, count))
772  call.addCopy("for (i=0; i < %s; i++)" % count)
773  call.addCopy("%s;" % copy)
774  call.addActualMPI2(temp)
775  call.addWriteback("for (i=0; i < %s; i++)" % count)
776  call.addWriteback("%s;" % writeback)
777  call.addWriteback("free(%s);" % temp)
778 
779  call.write(out)
780  if decl.returnsErrorCode():
781  out.write(" *ierr = %s;\n" % return_val)
782  else:
783  out.write(" return %s;\n" % return_val)
784  out.write("}\n\n")
785 
786  # Write out various bindings that delegate to the main fortran wrapper
787  write_fortran_binding(out, decl, delegate_name, decl.name.upper())
788  write_fortran_binding(out, decl, delegate_name, decl.name.lower())
789  write_fortran_binding(out, decl, delegate_name, decl.name.lower() + "_")
790  write_fortran_binding(out, decl, delegate_name, decl.name.lower() + "__")
791 
792 
793 
800 macros = {}
801 
802 # This decorator adds macro functions to the outermost function scope.
803 def macro(macro_name, **attrs):
804  def decorate(fun):
805  macros[macro_name] = fun # Add macro to outer scope under supplied name
806  fun.has_body = False # By default, macros have no body.
807  for key in attrs: # Optionally set/override attributes
808  setattr(fun, key, attrs[key])
809  return fun
810  return decorate
811 
812 def handle_list(list_name, list, args):
813  """This function handles indexing lists used as macros in the wrapper generator.
814  There are two syntaxes:
815  {{<list_name>}} Evaluates to the whole list, e.g. 'foo, bar, baz'
816  {{<list_name> <index>}} Evaluates to a particular element of a list.
817  """
818  if not args:
819  return list
820  else:
821  len(args) == 1 or syntax_error("Wrong number of args for list expression.")
822  try:
823  return list[int(args[0])]
824  except ValueError:
825  syntax_error("Invald index value: '%s'" % args[0])
826  except IndexError:
827  syntax_error("Index out of range in '%s': %d" % (list_name, index))
828 
829 class TypeApplier:
830  """This class implements a Macro function for applying something callable to
831  args in a decl with a particular type.
832  """
833  def __init__(self, decl):
834  self.decl = decl
835 
836  def __call__(self, out, scope, args, children):
837  len(args) == 2 or syntax_error("Wrong number of args in apply macro.")
838  type, macro_name = args
839  for arg in self.decl.args:
840  if arg.cType() == type:
841  out.write("%s(%s);\n" % (macro_name, arg.name))
842 
843 def include_decl(scope, decl):
844  """This function is used by macros to include attributes MPI declarations in their scope."""
845  scope["ret_type"] = decl.retType()
846  scope["args"] = decl.argNames()
847  scope["nargs"] = len(decl.argNames())
848  scope["types"] = decl.types()
849  scope["formals"] = decl.formals()
850  scope["apply_to_type"] = TypeApplier(decl)
851  scope.function_name = decl.name
852 
853  # These are old-stype, deprecated names.
854  def get_arg(out, scope, args, children):
855  return handle_list("args", decl.argNames(), args)
856  scope["get_arg"] = get_arg
857  scope["applyToType"] = scope["apply_to_type"]
858  scope["retType"] = scope["ret_type"]
859  scope["argList"] = "(%s)" % ", ".join(scope["args"])
860  scope["argTypeList"] = "(%s)" % ", ".join(scope["formals"])
861 
862 def all_but(fn_list):
863  """Return a list of all mpi functions except those in fn_list"""
864  all_mpi = set(mpi_functions.keys())
865  diff = all_mpi - set(fn_list)
866  return [x for x in diff]
867 
868 @macro("foreachfn", has_body=True)
869 def foreachfn(out, scope, args, children):
870  """Iterate over all functions listed in args."""
871  args or syntax_error("Error: foreachfn requires function name argument.")
872  global cur_function
873 
874  fn_var = args[0]
875  for fn_name in args[1:]:
876  cur_function = fn_name
877  if not fn_name in mpi_functions:
878  syntax_error(fn_name + " is not an MPI function")
879 
880  fn = mpi_functions[fn_name]
881  fn_scope = Scope(scope)
882  fn_scope[fn_var] = fn_name
883  include_decl(fn_scope, fn)
884 
885  for child in children:
886  child.evaluate(out, fn_scope)
887  cur_function = None
888 
889 @macro("fn", has_body=True)
890 def fn(out, scope, args, children):
891  """Iterate over listed functions and generate skeleton too."""
892  args or syntax_error("Error: fn requires function name argument.")
893  global cur_function
894 
895  fn_var = args[0]
896  for fn_name in args[1:]:
897  cur_function = fn_name
898  if not fn_name in mpi_functions:
899  syntax_error(fn_name + " is not an MPI function")
900 
901  fn = mpi_functions[fn_name]
902  return_val = "_wrap_py_return_val"
903 
904  fn_scope = Scope(scope)
905  fn_scope[fn_var] = fn_name
906  include_decl(fn_scope, fn)
907 
908  fn_scope["ret_val"] = return_val
909  fn_scope["returnVal"] = fn_scope["ret_val"] # deprecated name.
910 
911  c_call = "%s = P%s(%s);" % (return_val, fn.name, ", ".join(fn.argNames()))
912  if fn_name == "MPI_Init" and output_fortran_wrappers:
913  def callfn(out, scope, args, children):
914  # All this is to deal with fortran, since fortran's MPI_Init() function is different
915  # from C's. We need to make sure to delegate specifically to the fortran init wrapping.
916  # For dynamic libs, we use weak symbols to pick it automatically. For static libs, need
917  # to rely on input from the user via pmpi_init_binding and the -i option.
918  out.write(" if (fortran_init) {\n")
919  out.write("#ifdef PIC\n")
920  out.write(" if (!PMPI_INIT && !pmpi_init && !pmpi_init_ && !pmpi_init__) {\n")
921  out.write(" fprintf(stderr, \"ERROR: Couldn't find fortran pmpi_init function. Link against static library instead.\\n\");\n")
922  out.write(" exit(1);\n")
923  out.write(" }")
924  out.write(" switch (fortran_init) {\n")
925  out.write(" case 1: PMPI_INIT(&%s); break;\n" % return_val)
926  out.write(" case 2: pmpi_init(&%s); break;\n" % return_val)
927  out.write(" case 3: pmpi_init_(&%s); break;\n" % return_val)
928  out.write(" case 4: pmpi_init__(&%s); break;\n" % return_val)
929  out.write(" default:\n")
930  out.write(" fprintf(stderr, \"NO SUITABLE FORTRAN MPI_INIT BINDING\\n\");\n")
931  out.write(" break;\n")
932  out.write(" }\n")
933  out.write("#else /* !PIC */\n")
934  out.write(" %s(&%s);\n" % (pmpi_init_binding, return_val))
935  out.write("#endif /* !PIC */\n")
936  out.write(" } else {\n")
937  out.write(" %s\n" % c_call)
938  out.write(" }\n")
939 
940  fn_scope["callfn"] = callfn
941 
942  def write_fortran_init_flag():
943  output.write("static int fortran_init = 0;\n")
944  once(write_fortran_init_flag)
945 
946  else:
947  fn_scope["callfn"] = c_call
948 
949  def write_body(out):
950  for child in children:
951  child.evaluate(out, fn_scope)
952 
953  out.write("/* ================== C Wrappers for %s ================== */\n" % fn_name)
954  write_c_wrapper(out, fn, return_val, write_body)
955  if output_fortran_wrappers:
956  out.write("/* =============== Fortran Wrappers for %s =============== */\n" % fn_name)
957  write_fortran_wrappers(out, fn, return_val)
958  out.write("/* ================= End Wrappers for %s ================= */\n\n\n" % fn_name)
959  cur_function = None
960 
961 @macro("forallfn", has_body=True)
962 def forallfn(out, scope, args, children):
963  """Iterate over all but the functions listed in args."""
964  args or syntax_error("Error: forallfn requires function name argument.")
965  foreachfn(out, scope, [args[0]] + all_but(args[1:]), children)
966 
967 @macro("fnall", has_body=True)
968 def fnall(out, scope, args, children):
969  """Iterate over all but listed functions and generate skeleton too."""
970  args or syntax_error("Error: fnall requires function name argument.")
971  fn(out, scope, [args[0]] + all_but(args[1:]), children)
972 
973 @macro("sub")
974 def sub(out, scope, args, children):
975  """{{sub <string> <regexp> <substitution>}}
976  Replaces value of <string> with all instances of <regexp> replaced with <substitution>.
977  """
978  len(args) == 3 or syntax_error("'sub' macro takes exactly 4 arguments.")
979  string, regex, substitution = args
980  if isinstance(string, list):
981  return [re.sub(regex, substitution, s) for s in string]
982  if not isinstance(regex, str):
983  syntax_error("Invalid regular expression in 'sub' macro: '%s'" % regex)
984  else:
985  return re.sub(regex, substitution, string)
986 
987 @macro("zip")
988 def zip_macro(out, scope, args, children):
989  len(args) == 2 or syntax_error("'zip' macro takes exactly 2 arguments.")
990  if not all([isinstance(a, list) for a in args]):
991  syntax_error("Arguments to 'zip' macro must be lists.")
992  a, b = args
993  return ["%s %s" % x for x in zip(a, b)]
994 
995 @macro("def")
996 def def_macro(out, scope, args, children):
997  len(args) == 2 or syntax_error("'def' macro takes exactly 2 arguments.")
998  scope[args[0]] = args[1]
999 
1000 @macro("list")
1001 def list_macro(out, scope, args, children):
1002  result = []
1003  for arg in args:
1004  if isinstance(arg, list):
1005  result.extend(arg)
1006  else:
1007  result.append(arg)
1008  return result
1009 
1010 @macro("filter")
1011 def filter_macro(out, scope, args, children):
1012  """{{filter <regex> <list>}}
1013  Returns a list containing all elements of <list> that <regex> matches.
1014  """
1015  len(args) == 2 or syntax_error("'filter' macro takes exactly 2 arguments.")
1016  regex, l = args
1017  if not isinstance(l, list):
1018  syntax_error("Invalid list in 'filter' macro: '%s'" % str(list))
1019  if not isinstance(regex, str):
1020  syntax_error("Invalid regex in 'filter' macro: '%s'" % str(regex))
1021  def match(s):
1022  return re.search(regex, s)
1023  return filter(match, l)
1024 
1025 @macro("fn_num")
1026 def fn_num(out, scope, args, children):
1027  val = fn_num.val
1028  fn_num.val += 1
1029  return val
1030 fn_num.val = 0 # init the counter here.
1031 
1032 
1033 
1038 class Chunk:
1039  """Represents a piece of a wrapper file. Is either a text chunk
1040  or a macro chunk with children to which the macro should be applied.
1041  macros are evaluated lazily, so the macro is just a string until
1042  execute is called and it is fetched from its enclosing scope."""
1043  def __init__(self):
1044  self.macro = None
1045  self.args = []
1046  self.text = None
1047  self.children = []
1048 
1049  def iwrite(self, file, level, text):
1050  """Write indented text."""
1051  for x in xrange(level):
1052  file.write(" ")
1053  file.write(text)
1054 
1055  def write(self, file=sys.stdout, l=0):
1056  if self.macro: self.iwrite(file, l, "{{%s %s}}" % (self.macro, " ".join([str(arg) for arg in self.args])))
1057  if self.text: self.iwrite(file, l, "TEXT\n")
1058  for child in self.children:
1059  child.write(file, l+1)
1060 
1061  def execute(self, out, scope):
1062  """This function executes a chunk. For strings, lists, text chunks, etc., this just
1063  entails returning the chunk's value. For callable macros, this executes and returns
1064  the chunk's value.
1065  """
1066  if not self.macro:
1067  out.write(self.text)
1068  else:
1069  if not self.macro in scope:
1070  error_msg = "Invalid macro: '%s'" % self.macro
1071  if scope.function_name:
1072  error_msg += " for " + scope.function_name
1073  syntax_error(error_msg)
1074 
1075  value = scope[self.macro]
1076  if hasattr(value, "__call__"):
1077  # It's a macro, so we need to execute it. But first evaluate its args.
1078  def eval_arg(arg):
1079  if isinstance(arg, Chunk):
1080  return arg.execute(out, scope)
1081  else:
1082  return arg
1083  args = [eval_arg(arg) for arg in self.args]
1084  return value(out, scope, args, self.children)
1085  elif isinstance(value, list):
1086  # Special case for handling lists and list indexing
1087  return handle_list(self.macro, value, self.args)
1088  else:
1089  # Just return the value of anything else
1090  return value
1091 
1092  def stringify(self, value):
1093  """Used by evaluate() to print the return values of chunks out to the output file."""
1094  if isinstance(value, list):
1095  return ", ".join(value)
1096  else:
1097  return str(value)
1098 
1099  def evaluate(self, out, scope):
1100  """This is an 'interactive' version of execute. This should be called when
1101  the chunk's value (if any) should be written out. Body macros and the outermost
1102  scope should use this instead of execute().
1103  """
1104  value = self.execute(out, scope)
1105  if value is not None: # Note the distinction here -- 0 is false but we want to print it!
1106  out.write(self.stringify(value))
1107 
1108 class Parser:
1109  """Parser for the really simple wrappergen grammar.
1110  This parser has support for multiple lexers. self.tokens is a list of iterables, each
1111  representing a new token stream. You can add additional tokens to be lexed using push_tokens.
1112  This will cause the pushed tokens to be handled before any others. This allows us to switch
1113  lexers while parsing, so that the outer part of the file is processed in a language-agnostic
1114  way, but stuff inside macros is handled as its own macro language.
1115  """
1116  def __init__(self, macros):
1117  self.macros = macros
1118  self.macro_lexer = InnerLexer()
1119  self.tokens = iter([]) # iterators over tokens, handled in order. Starts empty.
1120  self.token = None # last accepted token
1121  self.next = None # next token
1122 
1123  def gettok(self):
1124  """Puts the next token in the input stream into self.next."""
1125  try:
1126  self.next = self.tokens.next()
1127  except StopIteration:
1128  self.next = None
1129 
1130  def push_tokens(self, iterable):
1131  """Adds all tokens in some iterable to the token stream."""
1132  self.tokens = itertools.chain(iter(iterable), iter([self.next]), self.tokens)
1133  self.gettok()
1134 
1135  def accept(self, id):
1136  """Puts the next symbol in self.token if we like it. Then calls gettok()"""
1137  if self.next.isa(id):
1138  self.token = self.next
1139  self.gettok()
1140  return True
1141  return False
1142 
1143  def unexpected_token(self):
1144  syntax_error("Unexpected token: %s." % self.next)
1145 
1146  def expect(self, id):
1147  """Like accept(), but fails if we don't like the next token."""
1148  if self.accept(id):
1149  return True
1150  else:
1151  if self.next:
1152  self.unexpected_token()
1153  else:
1154  syntax_error("Unexpected end of file.")
1155  sys.exit(1)
1156 
1157  def is_body_macro(self, name):
1158  """Shorthand for testing whether a particular name is the name of a macro that has a body.
1159  Need this for parsing the language b/c things like {{fn}} need a corresponding {{endfn}}.
1160  """
1161  return name in self.macros and self.macros[name].has_body
1162 
1163  def macro(self, accept_body_macros=True):
1164  # lex inner-macro text as wrapper language if we encounter text here.
1165  if self.accept(TEXT):
1166  self.push_tokens(self.macro_lexer.lex(self.token.value))
1167 
1168  # Now proceed with parsing the macro language's tokens
1169  chunk = Chunk()
1170  self.expect(IDENTIFIER)
1171  chunk.macro = self.token.value
1172 
1173  if not accept_body_macros and self.is_body_macro(chunk.macro):
1174  syntax_error("Cannot use body macros in expression context: '%s'" % chunk.macro)
1175  eys.exit(1)
1176 
1177  while True:
1178  if self.accept(LBRACE):
1179  chunk.args.append(self.macro(False))
1180  elif self.accept(IDENTIFIER):
1181  chunk.args.append(self.token.value)
1182  elif self.accept(TEXT):
1183  self.push_tokens(self.macro_lexer.lex(self.token.value))
1184  else:
1185  self.expect(RBRACE)
1186  break
1187  return chunk
1188 
1189  def text(self, end_macro = None):
1190  chunks = []
1191  while self.next:
1192  if self.accept(TEXT):
1193  chunk = Chunk()
1194  chunk.text = self.token.value
1195  chunks.append(chunk)
1196  elif self.accept(LBRACE):
1197  chunk = self.macro()
1198  name = chunk.macro
1199 
1200  if name == end_macro:
1201  # end macro: just break and don't append
1202  break
1203  elif isindex(chunk.macro):
1204  # Special case for indices -- raw number macros index 'args' list
1205  chunk.macro = "args"
1206  chunk.args = [name]
1207  elif self.is_body_macro(name):
1208  chunk.children = self.text("end"+name)
1209  chunks.append(chunk)
1210  else:
1211  self.unexpected_token()
1212 
1213  return chunks
1214 
1215  def parse(self, text):
1216  if skip_headers:
1217  outer_lexer = OuterRegionLexer() # Not generating C code, text is text.
1218  else:
1219  outer_lexer = OuterCommentLexer() # C code. Considers C-style comments.
1220  self.push_tokens(outer_lexer.lex(text))
1221  return self.text()
1222 
1223 
1227 def usage():
1228  sys.stderr.write(usage_string)
1229  sys.exit(2)
1230 
1231 # Let the user specify another mpicc to get mpi.h from
1232 output = sys.stdout
1233 output_filename = None
1234 
1235 try:
1236  opts, args = getopt.gnu_getopt(sys.argv[1:], "fsgdc:o:i:I:")
1237 except getopt.GetoptError, err:
1238  sys.stderr.write(err + "\n")
1239  usage()
1240 
1241 for opt, arg in opts:
1242  if opt == "-d": dump_prototypes = True
1243  if opt == "-f": output_fortran_wrappers = True
1244  if opt == "-s": skip_headers = True
1245  if opt == "-g": output_guards = True
1246  if opt == "-c": mpicc = arg
1247  if opt == "-o": output_filename = arg
1248  if opt == "-I":
1249  stripped = arg.strip()
1250  if stripped: includes.append(stripped)
1251  if opt == "-i":
1252  if not arg in pmpi_init_bindings:
1253  sys.stderr.write("ERROR: PMPI_Init binding must be one of:\n %s\n" % " ".join(possible_bindings))
1254  usage()
1255  else:
1256  pmpi_init_binding = arg
1257 
1258 if len(args) < 1 and not dump_prototypes:
1259  usage()
1260 
1261 # Parse mpi.h and put declarations into a map.
1262 for decl in enumerate_mpi_declarations(mpicc, includes):
1263  mpi_functions[decl.name] = decl
1264  if dump_prototypes: print decl
1265 
1266 # Fail gracefully if we didn't find anything.
1267 if not mpi_functions:
1268  sys.stderr.write("Error: Found no declarations in mpi.h.\n")
1269  sys.exit(1)
1270 
1271 # If we're just dumping prototypes, we can just exit here.
1272 if dump_prototypes: sys.exit(0)
1273 
1274 # Open the output file here if it was specified
1275 if output_filename:
1276  try:
1277  output = open(output_filename, "w")
1278  except IOError:
1279  sys.stderr.write("Error: couldn't open file " + arg + " for writing.\n")
1280  sys.exit(1)
1281 
1282 try:
1283  # Start with some headers and definitions.
1284  if not skip_headers:
1285  output.write(wrapper_includes)
1286  if output_guards: output.write("static int in_wrapper = 0;\n")
1287 
1288  # Parse each file listed on the command line and execute
1289  # it once it's parsed.
1290  fileno = 0
1291  for f in args:
1292  cur_filename = f
1293  file = open(cur_filename)
1294 
1295  # Outer scope contains fileno and the fundamental macros.
1296  outer_scope = Scope()
1297  outer_scope["fileno"] = str(fileno)
1298  outer_scope.include(macros)
1299 
1300  parser = Parser(macros)
1301  chunks = parser.parse(file.read())
1302 
1303  for chunk in chunks:
1304  chunk.evaluate(output, Scope(outer_scope))
1305  fileno += 1
1306 
1307 except WrapSyntaxError:
1308  output.close()
1309  if output_filename: os.remove(output_filename)
1310  sys.exit(1)
1311 
1312 output.close()
__host__ __device__ double set(double &x)
Definition: blas_helper.cuh:58
static void sub(Float *dst, Float *a, Float *b, int cnt)
Definition: dslash_util.h:14
std::map< TuneKey, TuneParam > map
Definition: tune.cpp:28
void usage(char **)
Definition: test_util.cpp:1783
__host__ __device__ constexpr bool match()