| Home | Trees | Indices | Help |
|
|---|
|
|
1 #
2 # Copyright (c) 2001 - 2019 The SCons Foundation
3 #
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:
11 #
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
14 #
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.
22 #
23
24 __revision__ = "src/engine/SCons/cpp.py 72ae09dc35ac2626f8ff711d8c4b30b6138e08e3 2019-08-08 14:50:06 bdeegan"
25
26 __doc__ = """
27 SCons C Pre-Processor module
28 """
29 import SCons.compat
30
31 import os
32 import re
33
34 #
35 # First "subsystem" of regular expressions that we set up:
36 #
37 # Stuff to turn the C preprocessor directives in a file's contents into
38 # a list of tuples that we can process easily.
39 #
40
41 # A table of regular expressions that fetch the arguments from the rest of
42 # a C preprocessor line. Different directives have different arguments
43 # that we want to fetch, using the regular expressions to which the lists
44 # of preprocessor directives map.
45 cpp_lines_dict = {
46 # Fetch the rest of a #if/#elif as one argument,
47 # with white space optional.
48 ('if', 'elif') : r'\s*(.+)',
49
50 # Fetch the rest of a #ifdef/#ifndef as one argument,
51 # separated from the keyword by white space.
52 ('ifdef', 'ifndef',): r'\s+(.+)',
53
54 # Fetch the rest of a #import/#include/#include_next line as one
55 # argument, with white space optional.
56 ('import', 'include', 'include_next',)
57 : r'\s*(.+)',
58
59 # We don't care what comes after a #else or #endif line.
60 ('else', 'endif',) : '',
61
62 # Fetch three arguments from a #define line:
63 # 1) The #defined keyword.
64 # 2) The optional parentheses and arguments (if it's a function-like
65 # macro, '' if it's not).
66 # 3) The expansion value.
67 ('define',) : r'\s+([_A-Za-z][_A-Za-z0-9_]*)(\([^)]*\))?\s*(.*)',
68
69 # Fetch the #undefed keyword from a #undef line.
70 ('undef',) : r'\s+([_A-Za-z][A-Za-z0-9_]*)',
71 }
72
73 # Create a table that maps each individual C preprocessor directive to
74 # the corresponding compiled regular expression that fetches the arguments
75 # we care about.
76 Table = {}
77 for op_list, expr in cpp_lines_dict.items():
78 e = re.compile(expr)
79 for op in op_list:
80 Table[op] = e
81 del e
82 del op
83 del op_list
84
85 # Create a list of the expressions we'll use to match all of the
86 # preprocessor directives. These are the same as the directives
87 # themselves *except* that we must use a negative lookahead assertion
88 # when matching "if" so it doesn't match the "if" in "ifdef" or "ifndef".
89 override = {
90 'if' : 'if(?!n?def)',
91 }
92 l = [override.get(x, x) for x in list(Table.keys())]
93
94
95 # Turn the list of expressions into one big honkin' regular expression
96 # that will match all the preprocessor lines at once. This will return
97 # a list of tuples, one for each preprocessor line. The preprocessor
98 # directive will be the first element in each tuple, and the rest of
99 # the line will be the second element.
100 e = r'^\s*#\s*(' + '|'.join(l) + ')(.*)$'
101
102 # And last but not least, compile the expression.
103 CPP_Expression = re.compile(e, re.M)
104
105
106
107
108 #
109 # Second "subsystem" of regular expressions that we set up:
110 #
111 # Stuff to translate a C preprocessor expression (as found on a #if or
112 # #elif line) into an equivalent Python expression that we can eval().
113 #
114
115 # A dictionary that maps the C representation of Boolean operators
116 # to their Python equivalents.
117 CPP_to_Python_Ops_Dict = {
118 '!' : ' not ',
119 '!=' : ' != ',
120 '&&' : ' and ',
121 '||' : ' or ',
122 '?' : ' and ',
123 ':' : ' or ',
124 '\r' : '',
125 }
126
127 CPP_to_Python_Ops_Sub = lambda m: CPP_to_Python_Ops_Dict[m.group(0)]
128
129 # We have to sort the keys by length so that longer expressions
130 # come *before* shorter expressions--in particular, "!=" must
131 # come before "!" in the alternation. Without this, the Python
132 # re module, as late as version 2.2.2, empirically matches the
133 # "!" in "!=" first, instead of finding the longest match.
134 # What's up with that?
135 l = sorted(list(CPP_to_Python_Ops_Dict.keys()), key=lambda a: len(a), reverse=True)
136
137 # Turn the list of keys into one regular expression that will allow us
138 # to substitute all of the operators at once.
139 expr = '|'.join(map(re.escape, l))
140
141 # ...and compile the expression.
142 CPP_to_Python_Ops_Expression = re.compile(expr)
143
144 # A separate list of expressions to be evaluated and substituted
145 # sequentially, not all at once.
146 CPP_to_Python_Eval_List = [
147 [r'defined\s+(\w+)', '"\\1" in __dict__'],
148 [r'defined\s*\((\w+)\)', '"\\1" in __dict__'],
149 [r'/\*.*\*/', ''],
150 [r'/\*.*', ''],
151 [r'//.*', ''],
152 [r'(0x[0-9A-Fa-f]*)[UL]+', '\\1'],
153 ]
154
155 # Replace the string representations of the regular expressions in the
156 # list with compiled versions.
157 for l in CPP_to_Python_Eval_List:
158 l[0] = re.compile(l[0])
159
160 # Wrap up all of the above into a handy function.
162 """
163 Converts a C pre-processor expression into an equivalent
164 Python expression that can be evaluated.
165 """
166 s = CPP_to_Python_Ops_Expression.sub(CPP_to_Python_Ops_Sub, s)
167 for expr, repl in CPP_to_Python_Eval_List:
168 s = re.sub(expr, repl, s)
169 return s
170
171
172
173 del expr
174 del l
175 del override
176
177
178
180 """
181 Handles delayed evaluation of a #define function call.
182 """
184 """
185 Squirrels away the arguments and expansion value of a #define
186 macro function for later evaluation when we must actually expand
187 a value that uses it.
188 """
189 self.name = name
190 self.args = function_arg_separator.split(args)
191 try:
192 expansion = expansion.split('##')
193 except AttributeError:
194 pass
195 self.expansion = expansion
197 """
198 Evaluates the expansion of a #define macro function called
199 with the specified values.
200 """
201 if len(self.args) != len(values):
202 raise ValueError("Incorrect number of arguments to `%s'" % self.name)
203 # Create a dictionary that maps the macro arguments to the
204 # corresponding values in this "call." We'll use this when we
205 # eval() the expansion so that arguments will get expanded to
206 # the right values.
207 locals = {}
208 for k, v in zip(self.args, values):
209 locals[k] = v
210
211 parts = []
212 for s in self.expansion:
213 if s not in self.args:
214 s = repr(s)
215 parts.append(s)
216 statement = ' + '.join(parts)
217
218 return eval(statement, globals(), locals)
219
220
221
222 # Find line continuations.
223 line_continuations = re.compile('\\\\\r?\n')
224
225 # Search for a "function call" macro on an expansion. Returns the
226 # two-tuple of the "function" name itself, and a string containing the
227 # arguments within the call parentheses.
228 function_name = re.compile(r'(\S+)\(([^)]*)\)')
229
230 # Split a string containing comma-separated function call arguments into
231 # the separate arguments.
232 function_arg_separator = re.compile(r',\s*')
233
234
235
237 """
238 The main workhorse class for handling C pre-processing.
239 """
241 global Table
242
243 cpppath = tuple(cpppath)
244
245 self.searchpath = {
246 '"' : (current,) + cpppath,
247 '<' : cpppath + (current,),
248 }
249
250 # Initialize our C preprocessor namespace for tracking the
251 # values of #defined keywords. We use this namespace to look
252 # for keywords on #ifdef/#ifndef lines, and to eval() the
253 # expressions on #if/#elif lines (after massaging them from C to
254 # Python).
255 self.cpp_namespace = dict.copy()
256 self.cpp_namespace['__dict__'] = self.cpp_namespace
257
258 if all:
259 self.do_include = self.all_include
260
261 # For efficiency, a dispatch table maps each C preprocessor
262 # directive (#if, #define, etc.) to the method that should be
263 # called when we see it. We accomodate state changes (#if,
264 # #ifdef, #ifndef) by pushing the current dispatch table on a
265 # stack and changing what method gets called for each relevant
266 # directive we might see next at this level (#else, #elif).
267 # #endif will simply pop the stack.
268 d = {
269 'scons_current_file' : self.scons_current_file
270 }
271 for op in list(Table.keys()):
272 d[op] = getattr(self, 'do_' + op)
273 self.default_table = d
274
275 # Controlling methods.
276
278 """
279 Turns the contents of a file into a list of easily-processed
280 tuples describing the CPP lines in the file.
281
282 The first element of each tuple is the line's preprocessor
283 directive (#if, #include, #define, etc., minus the initial '#').
284 The remaining elements are specific to the type of directive, as
285 pulled apart by the regular expression.
286 """
287 global CPP_Expression, Table
288 contents = line_continuations.sub('', contents)
289 cpp_tuples = CPP_Expression.findall(contents)
290 return [(m[0],) + Table[m[0]].match(m[1]).groups() for m in cpp_tuples]
291
293 """
294 Pre-processes a file.
295
296 This is the main public entry point.
297 """
298 self.current_file = file
299 return self.process_contents(self.read_file(file), file)
300
302 """
303 Pre-processes a file contents.
304
305 This is the main internal entry point.
306 """
307 self.stack = []
308 self.dispatch_table = self.default_table.copy()
309 self.current_file = fname
310 self.tuples = self.tupleize(contents)
311
312 self.initialize_result(fname)
313 while self.tuples:
314 t = self.tuples.pop(0)
315 # Uncomment to see the list of tuples being processed (e.g.,
316 # to validate the CPP lines are being translated correctly).
317 #print(t)
318 self.dispatch_table[t[0]](t)
319 return self.finalize_result(fname)
320
321 # Dispatch table stack manipulation methods.
322
324 """
325 Pushes the current dispatch table on the stack and re-initializes
326 the current dispatch table to the default.
327 """
328 self.stack.append(self.dispatch_table)
329 self.dispatch_table = self.default_table.copy()
330
332 """
333 Pops the previous dispatch table off the stack and makes it the
334 current one.
335 """
336 try: self.dispatch_table = self.stack.pop()
337 except IndexError: pass
338
339 # Utility methods.
340
342 """
343 Null method for when we explicitly want the action for a
344 specific preprocessor directive to do nothing.
345 """
346 pass
347
350
352 """
353 Evaluates a C preprocessor expression.
354
355 This is done by converting it to a Python equivalent and
356 eval()ing it in the C preprocessor namespace we use to
357 track #define values.
358 """
359 t = CPP_to_Python(' '.join(t[1:]))
360 try: return eval(t, self.cpp_namespace)
361 except (NameError, TypeError): return 0
362
364 self.result = [fname]
365
367 return self.result[1:]
368
370 """
371 Finds the #include file for a given preprocessor tuple.
372 """
373 fname = t[2]
374 for d in self.searchpath[t[1]]:
375 if d == os.curdir:
376 f = fname
377 else:
378 f = os.path.join(d, fname)
379 if os.path.isfile(f):
380 return f
381 return None
382
386
387 # Start and stop processing include lines.
388
390 """
391 Causes the PreProcessor object to start processing #import,
392 #include and #include_next lines.
393
394 This method will be called when a #if, #ifdef, #ifndef or #elif
395 evaluates True, or when we reach the #else in a #if, #ifdef,
396 #ifndef or #elif block where a condition already evaluated
397 False.
398
399 """
400 d = self.dispatch_table
401 p = self.stack[-1] if self.stack else self.default_table
402
403 for k in ('import', 'include', 'include_next'):
404 d[k] = p[k]
405
407 """
408 Causes the PreProcessor object to stop processing #import,
409 #include and #include_next lines.
410
411 This method will be called when a #if, #ifdef, #ifndef or #elif
412 evaluates False, or when we reach the #else in a #if, #ifdef,
413 #ifndef or #elif block where a condition already evaluated True.
414 """
415 d = self.dispatch_table
416 d['import'] = self.do_nothing
417 d['include'] = self.do_nothing
418 d['include_next'] = self.do_nothing
419
420 # Default methods for handling all of the preprocessor directives.
421 # (Note that what actually gets called for a given directive at any
422 # point in time is really controlled by the dispatch_table.)
423
425 """
426 Common logic for evaluating the conditions on #if, #ifdef and
427 #ifndef lines.
428 """
429 self.save()
430 d = self.dispatch_table
431 if condition:
432 self.start_handling_includes()
433 d['elif'] = self.stop_handling_includes
434 d['else'] = self.stop_handling_includes
435 else:
436 self.stop_handling_includes()
437 d['elif'] = self.do_elif
438 d['else'] = self.start_handling_includes
439
441 """
442 Default handling of a #ifdef line.
443 """
444 self._do_if_else_condition(t[1] in self.cpp_namespace)
445
447 """
448 Default handling of a #ifndef line.
449 """
450 self._do_if_else_condition(t[1] not in self.cpp_namespace)
451
453 """
454 Default handling of a #if line.
455 """
456 self._do_if_else_condition(self.eval_expression(t))
457
459 """
460 Default handling of a #elif line.
461 """
462 d = self.dispatch_table
463 if self.eval_expression(t):
464 self.start_handling_includes()
465 d['elif'] = self.stop_handling_includes
466 d['else'] = self.stop_handling_includes
467
473
479
481 """
482 Default handling of a #define line.
483 """
484 _, name, args, expansion = t
485 try:
486 expansion = int(expansion)
487 except (TypeError, ValueError):
488 pass
489 if args:
490 evaluator = FunctionEvaluator(name, args[1:-1], expansion)
491 self.cpp_namespace[name] = evaluator
492 else:
493 self.cpp_namespace[name] = expansion
494
496 """
497 Default handling of a #undef line.
498 """
499 try: del self.cpp_namespace[t[1]]
500 except KeyError: pass
501
503 """
504 Default handling of a #import line.
505 """
506 # XXX finish this -- maybe borrow/share logic from do_include()...?
507 pass
508
510 """
511 Default handling of a #include line.
512 """
513 t = self.resolve_include(t)
514 include_file = self.find_include_file(t)
515 if include_file:
516 #print("include_file =", include_file)
517 self.result.append(include_file)
518 contents = self.read_file(include_file)
519 new_tuples = [('scons_current_file', include_file)] + \
520 self.tupleize(contents) + \
521 [('scons_current_file', self.current_file)]
522 self.tuples[:] = new_tuples + self.tuples
523
524 # Date: Tue, 22 Nov 2005 20:26:09 -0500
525 # From: Stefan Seefeld <seefeld@sympatico.ca>
526 #
527 # By the way, #include_next is not the same as #include. The difference
528 # being that #include_next starts its search in the path following the
529 # path that let to the including file. In other words, if your system
530 # include paths are ['/foo', '/bar'], and you are looking at a header
531 # '/foo/baz.h', it might issue an '#include_next <baz.h>' which would
532 # correctly resolve to '/bar/baz.h' (if that exists), but *not* see
533 # '/foo/baz.h' again. See http://www.delorie.com/gnu/docs/gcc/cpp_11.html
534 # for more reasoning.
535 #
536 # I have no idea in what context 'import' might be used.
537
538 # XXX is #include_next really the same as #include ?
539 do_include_next = do_include
540
541 # Utility methods for handling resolution of include files.
542
544 """Resolve a tuple-ized #include line.
545
546 This handles recursive expansion of values without "" or <>
547 surrounding the name until an initial " or < is found, to handle
548
549 #include FILE
550
551 where FILE is a #define somewhere else."""
552
553 s = t[1]
554 while not s[0] in '<"':
555 #print("s =", s)
556 try:
557 s = self.cpp_namespace[s]
558 except KeyError:
559 m = function_name.search(s)
560 s = self.cpp_namespace[m.group(1)]
561 if callable(s):
562 args = function_arg_separator.split(m.group(2))
563 s = s(*args)
564 if not s:
565 return None
566 return (t[0], s[0], s[1:-1])
567
572
574 """A preprocessor that ignores all #if/#elif/#else/#endif directives
575 and just reports back *all* of the #include files (like the classic
576 SCons scanner did).
577
578 This is functionally equivalent to using a regular expression to
579 find all of the #include lines, only slower. It exists mainly as
580 an example of how the main PreProcessor class can be sub-classed
581 to tailor its behavior.
582 """
584 PreProcessor.__init__(self, *args, **kw)
585 d = self.default_table
586 for func in ['if', 'elif', 'else', 'endif', 'ifdef', 'ifndef']:
587 d[func] = d[func] = self.do_nothing
588
589 del __revision__
590
591 # Local Variables:
592 # tab-width:4
593 # indent-tabs-mode:nil
594 # End:
595 # vim: set expandtab tabstop=4 shiftwidth=4:
596
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Thu Aug 8 14:51:07 2019 | http://epydoc.sourceforge.net |