4 # Permission is hereby granted, free of charge, to any person obtaining
5 # a copy of this software and associated documentation files (the
6 # "Software"), to deal in the Software without restriction, including
7 # without limitation the rights to use, copy, modify, merge, publish,
8 # distribute, sublicense, and/or sell copies of the Software, and to
9 # permit persons to whom the Software is furnished to do so, subject to
10 # the following conditions:
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
16 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
27 SCons C Pre-Processor module
30 # TODO(1.5): remove this import
31 # This module doesn't use anything from SCons by name, but we import SCons
32 # here to pull in zip() from the SCons.compat layer for early Pythons.
39 # First "subsystem" of regular expressions that we set up:
41 # Stuff to turn the C preprocessor directives in a file's contents into
42 # a list of tuples that we can process easily.
45 # A table of regular expressions that fetch the arguments from the rest of
46 # a C preprocessor line. Different directives have different arguments
47 # that we want to fetch, using the regular expressions to which the lists
48 # of preprocessor directives map.
50 # Fetch the rest of a #if/#elif/#ifdef/#ifndef as one argument,
51 # separated from the keyword by white space.
52 ('if', 'elif', 'ifdef', 'ifndef',)
55 # Fetch the rest of a #import/#include/#include_next line as one
56 # argument, with white space optional.
57 ('import', 'include', 'include_next',)
60 # We don't care what comes after a #else or #endif line.
61 ('else', 'endif',) : '',
63 # Fetch three arguments from a #define line:
64 # 1) The #defined keyword.
65 # 2) The optional parentheses and arguments (if it's a function-like
66 # macro, '' if it's not).
67 # 3) The expansion value.
68 ('define',) : '\s+([_A-Za-z][_A-Za-z0-9_]*)(\([^)]*\))?\s*(.*)',
70 # Fetch the #undefed keyword from a #undef line.
71 ('undef',) : '\s+([_A-Za-z][A-Za-z0-9_]*)',
74 # Create a table that maps each individual C preprocessor directive to
75 # the corresponding compiled regular expression that fetches the arguments
78 for op_list, expr in cpp_lines_dict.items():
86 # Create a list of the expressions we'll use to match all of the
87 # preprocessor directives. These are the same as the directives
88 # themselves *except* that we must use a negative lookahead assertion
89 # when matching "if" so it doesn't match the "if" in "ifdef."
93 l = [override.get(x, x) for x in Table.keys()]
96 # Turn the list of expressions into one big honkin' regular expression
97 # that will match all the preprocessor lines at once. This will return
98 # a list of tuples, one for each preprocessor line. The preprocessor
99 # directive will be the first element in each tuple, and the rest of
100 # the line will be the second element.
101 e = '^\s*#\s*(' + '|'.join(l) + ')(.*)$'
103 # And last but not least, compile the expression.
104 CPP_Expression = re.compile(e, re.M)
110 # Second "subsystem" of regular expressions that we set up:
112 # Stuff to translate a C preprocessor expression (as found on a #if or
113 # #elif line) into an equivalent Python expression that we can eval().
116 # A dictionary that maps the C representation of Boolean operators
117 # to their Python equivalents.
118 CPP_to_Python_Ops_Dict = {
128 CPP_to_Python_Ops_Sub = lambda m: CPP_to_Python_Ops_Dict[m.group(0)]
130 # We have to sort the keys by length so that longer expressions
131 # come *before* shorter expressions--in particular, "!=" must
132 # come before "!" in the alternation. Without this, the Python
133 # re module, as late as version 2.2.2, empirically matches the
134 # "!" in "!=" first, instead of finding the longest match.
135 # What's up with that?
136 l = sorted(CPP_to_Python_Ops_Dict.keys(), cmp=lambda a, b: cmp(len(b), len(a)))
138 # Turn the list of keys into one regular expression that will allow us
139 # to substitute all of the operators at once.
140 expr = '|'.join(map(re.escape, l))
142 # ...and compile the expression.
143 CPP_to_Python_Ops_Expression = re.compile(expr)
145 # A separate list of expressions to be evaluated and substituted
146 # sequentially, not all at once.
147 CPP_to_Python_Eval_List = [
148 ['defined\s+(\w+)', '"\\1" in __dict__'],
149 ['defined\s*\((\w+)\)', '"\\1" in __dict__'],
153 ['(0x[0-9A-Fa-f]*)[UL]+', '\\1'],
156 # Replace the string representations of the regular expressions in the
157 # list with compiled versions.
158 for l in CPP_to_Python_Eval_List:
159 l[0] = re.compile(l[0])
161 # Wrap up all of the above into a handy function.
162 def CPP_to_Python(s):
164 Converts a C pre-processor expression into an equivalent
165 Python expression that can be evaluated.
167 s = CPP_to_Python_Ops_Expression.sub(CPP_to_Python_Ops_Sub, s)
168 for expr, repl in CPP_to_Python_Eval_List:
169 s = expr.sub(repl, s)
180 class FunctionEvaluator:
182 Handles delayed evaluation of a #define function call.
184 def __init__(self, name, args, expansion):
186 Squirrels away the arguments and expansion value of a #define
187 macro function for later evaluation when we must actually expand
188 a value that uses it.
191 self.args = function_arg_separator.split(args)
193 expansion = expansion.split('##')
194 except (AttributeError, TypeError):
195 # Python 1.5 throws TypeError if "expansion" isn't a string,
196 # later versions throw AttributeError.
198 self.expansion = expansion
199 def __call__(self, *values):
201 Evaluates the expansion of a #define macro function called
202 with the specified values.
204 if len(self.args) != len(values):
205 raise ValueError("Incorrect number of arguments to `%s'" % self.name)
206 # Create a dictionary that maps the macro arguments to the
207 # corresponding values in this "call." We'll use this when we
208 # eval() the expansion so that arguments will get expanded to
211 for k, v in zip(self.args, values):
215 for s in self.expansion:
216 if not s in self.args:
219 statement = ' + '.join(parts)
221 return eval(statement, globals(), locals)
225 # Find line continuations.
226 line_continuations = re.compile('\\\\\r?\n')
228 # Search for a "function call" macro on an expansion. Returns the
229 # two-tuple of the "function" name itself, and a string containing the
230 # arguments within the call parentheses.
231 function_name = re.compile('(\S+)\(([^)]*)\)')
233 # Split a string containing comma-separated function call arguments into
234 # the separate arguments.
235 function_arg_separator = re.compile(',\s*')
241 The main workhorse class for handling C pre-processing.
243 def __init__(self, current=os.curdir, cpppath=(), dict={}, all=0):
246 cpppath = tuple(cpppath)
249 '"' : (current,) + cpppath,
250 '<' : cpppath + (current,),
253 # Initialize our C preprocessor namespace for tracking the
254 # values of #defined keywords. We use this namespace to look
255 # for keywords on #ifdef/#ifndef lines, and to eval() the
256 # expressions on #if/#elif lines (after massaging them from C to
258 self.cpp_namespace = dict.copy()
259 self.cpp_namespace['__dict__'] = self.cpp_namespace
262 self.do_include = self.all_include
264 # For efficiency, a dispatch table maps each C preprocessor
265 # directive (#if, #define, etc.) to the method that should be
266 # called when we see it. We accomodate state changes (#if,
267 # #ifdef, #ifndef) by pushing the current dispatch table on a
268 # stack and changing what method gets called for each relevant
269 # directive we might see next at this level (#else, #elif).
270 # #endif will simply pop the stack.
272 'scons_current_file' : self.scons_current_file
274 for op in Table.keys():
275 d[op] = getattr(self, 'do_' + op)
276 self.default_table = d
278 # Controlling methods.
280 def tupleize(self, contents):
282 Turns the contents of a file into a list of easily-processed
283 tuples describing the CPP lines in the file.
285 The first element of each tuple is the line's preprocessor
286 directive (#if, #include, #define, etc., minus the initial '#').
287 The remaining elements are specific to the type of directive, as
288 pulled apart by the regular expression.
290 global CPP_Expression, Table
291 contents = line_continuations.sub('', contents)
292 cpp_tuples = CPP_Expression.findall(contents)
293 return [(m[0],) + Table[m[0]].match(m[1]).groups() for m in cpp_tuples]
295 def __call__(self, file):
297 Pre-processes a file.
299 This is the main public entry point.
301 self.current_file = file
302 return self.process_contents(self.read_file(file), file)
304 def process_contents(self, contents, fname=None):
306 Pre-processes a file contents.
308 This is the main internal entry point.
311 self.dispatch_table = self.default_table.copy()
312 self.current_file = fname
313 self.tuples = self.tupleize(contents)
315 self.initialize_result(fname)
317 t = self.tuples.pop(0)
318 # Uncomment to see the list of tuples being processed (e.g.,
319 # to validate the CPP lines are being translated correctly).
321 self.dispatch_table[t[0]](t)
322 return self.finalize_result(fname)
324 # Dispatch table stack manipulation methods.
328 Pushes the current dispatch table on the stack and re-initializes
329 the current dispatch table to the default.
331 self.stack.append(self.dispatch_table)
332 self.dispatch_table = self.default_table.copy()
336 Pops the previous dispatch table off the stack and makes it the
339 try: self.dispatch_table = self.stack.pop()
340 except IndexError: pass
344 def do_nothing(self, t):
346 Null method for when we explicitly want the action for a
347 specific preprocessor directive to do nothing.
351 def scons_current_file(self, t):
352 self.current_file = t[1]
354 def eval_expression(self, t):
356 Evaluates a C preprocessor expression.
358 This is done by converting it to a Python equivalent and
359 eval()ing it in the C preprocessor namespace we use to
360 track #define values.
362 t = CPP_to_Python(' '.join(t[1:]))
363 try: return eval(t, self.cpp_namespace)
364 except (NameError, TypeError): return 0
366 def initialize_result(self, fname):
367 self.result = [fname]
369 def finalize_result(self, fname):
370 return self.result[1:]
372 def find_include_file(self, t):
374 Finds the #include file for a given preprocessor tuple.
377 for d in self.searchpath[t[1]]:
381 f = os.path.join(d, fname)
382 if os.path.isfile(f):
386 def read_file(self, file):
387 return open(file).read()
389 # Start and stop processing include lines.
391 def start_handling_includes(self, t=None):
393 Causes the PreProcessor object to start processing #import,
394 #include and #include_next lines.
396 This method will be called when a #if, #ifdef, #ifndef or #elif
397 evaluates True, or when we reach the #else in a #if, #ifdef,
398 #ifndef or #elif block where a condition already evaluated
402 d = self.dispatch_table
403 d['import'] = self.do_import
404 d['include'] = self.do_include
405 d['include_next'] = self.do_include
407 def stop_handling_includes(self, t=None):
409 Causes the PreProcessor object to stop processing #import,
410 #include and #include_next lines.
412 This method will be called when a #if, #ifdef, #ifndef or #elif
413 evaluates False, or when we reach the #else in a #if, #ifdef,
414 #ifndef or #elif block where a condition already evaluated True.
416 d = self.dispatch_table
417 d['import'] = self.do_nothing
418 d['include'] = self.do_nothing
419 d['include_next'] = self.do_nothing
421 # Default methods for handling all of the preprocessor directives.
422 # (Note that what actually gets called for a given directive at any
423 # point in time is really controlled by the dispatch_table.)
425 def _do_if_else_condition(self, condition):
427 Common logic for evaluating the conditions on #if, #ifdef and
431 d = self.dispatch_table
433 self.start_handling_includes()
434 d['elif'] = self.stop_handling_includes
435 d['else'] = self.stop_handling_includes
437 self.stop_handling_includes()
438 d['elif'] = self.do_elif
439 d['else'] = self.start_handling_includes
441 def do_ifdef(self, t):
443 Default handling of a #ifdef line.
445 self._do_if_else_condition(t[1] in self.cpp_namespace)
447 def do_ifndef(self, t):
449 Default handling of a #ifndef line.
451 self._do_if_else_condition(t[1] not in self.cpp_namespace)
455 Default handling of a #if line.
457 self._do_if_else_condition(self.eval_expression(t))
459 def do_elif(self, t):
461 Default handling of a #elif line.
463 d = self.dispatch_table
464 if self.eval_expression(t):
465 self.start_handling_includes()
466 d['elif'] = self.stop_handling_includes
467 d['else'] = self.stop_handling_includes
469 def do_else(self, t):
471 Default handling of a #else line.
475 def do_endif(self, t):
477 Default handling of a #endif line.
481 def do_define(self, t):
483 Default handling of a #define line.
485 _, name, args, expansion = t
487 expansion = int(expansion)
488 except (TypeError, ValueError):
491 evaluator = FunctionEvaluator(name, args[1:-1], expansion)
492 self.cpp_namespace[name] = evaluator
494 self.cpp_namespace[name] = expansion
496 def do_undef(self, t):
498 Default handling of a #undef line.
500 try: del self.cpp_namespace[t[1]]
501 except KeyError: pass
503 def do_import(self, t):
505 Default handling of a #import line.
507 # XXX finish this -- maybe borrow/share logic from do_include()...?
510 def do_include(self, t):
512 Default handling of a #include line.
514 t = self.resolve_include(t)
515 include_file = self.find_include_file(t)
517 #print "include_file =", include_file
518 self.result.append(include_file)
519 contents = self.read_file(include_file)
520 new_tuples = [('scons_current_file', include_file)] + \
521 self.tupleize(contents) + \
522 [('scons_current_file', self.current_file)]
523 self.tuples[:] = new_tuples + self.tuples
525 # Date: Tue, 22 Nov 2005 20:26:09 -0500
526 # From: Stefan Seefeld <seefeld@sympatico.ca>
528 # By the way, #include_next is not the same as #include. The difference
529 # being that #include_next starts its search in the path following the
530 # path that let to the including file. In other words, if your system
531 # include paths are ['/foo', '/bar'], and you are looking at a header
532 # '/foo/baz.h', it might issue an '#include_next <baz.h>' which would
533 # correctly resolve to '/bar/baz.h' (if that exists), but *not* see
534 # '/foo/baz.h' again. See http://www.delorie.com/gnu/docs/gcc/cpp_11.html
535 # for more reasoning.
537 # I have no idea in what context 'import' might be used.
539 # XXX is #include_next really the same as #include ?
540 do_include_next = do_include
542 # Utility methods for handling resolution of include files.
544 def resolve_include(self, t):
545 """Resolve a tuple-ized #include line.
547 This handles recursive expansion of values without "" or <>
548 surrounding the name until an initial " or < is found, to handle
550 where FILE is a #define somewhere else.
553 while not s[0] in '<"':
556 s = self.cpp_namespace[s]
558 m = function_name.search(s)
559 s = self.cpp_namespace[m.group(1)]
561 args = function_arg_separator.split(m.group(2))
565 return (t[0], s[0], s[1:-1])
567 def all_include(self, t):
570 self.result.append(self.resolve_include(t))
572 class DumbPreProcessor(PreProcessor):
573 """A preprocessor that ignores all #if/#elif/#else/#endif directives
574 and just reports back *all* of the #include files (like the classic
577 This is functionally equivalent to using a regular expression to
578 find all of the #include lines, only slower. It exists mainly as
579 an example of how the main PreProcessor class can be sub-classed
580 to tailor its behavior.
582 def __init__(self, *args, **kw):
583 PreProcessor.__init__(self, *args, **kw)
584 d = self.default_table
585 for func in ['if', 'elif', 'else', 'endif', 'ifdef', 'ifndef']:
586 d[func] = d[func] = self.do_nothing
592 # indent-tabs-mode:nil
594 # vim: set expandtab tabstop=4 shiftwidth=4: