1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 __revision__ = "src/engine/SCons/cpp.py 2928 2008/04/29 22:44:09 knight"
25
26 __doc__ = """
27 SCons C Pre-Processor module
28 """
29
30 import SCons.compat
31
32 import os
33 import re
34 import string
35
36
37
38
39
40
41
42
43
44
45
46
47 cpp_lines_dict = {
48
49
50 ('if', 'elif', 'ifdef', 'ifndef',)
51 : '\s+(.+)',
52
53
54
55 ('import', 'include', 'include_next',)
56 : '\s*(.+)',
57
58
59 ('else', 'endif',) : '',
60
61
62
63
64
65
66 ('define',) : '\s+([_A-Za-z][_A-Za-z0-9_]+)(\([^)]*\))?\s*(.*)',
67
68
69 ('undef',) : '\s+([_A-Za-z][A-Za-z0-9_]+)',
70 }
71
72
73
74
75 Table = {}
76 for op_list, expr in cpp_lines_dict.items():
77 e = re.compile(expr)
78 for op in op_list:
79 Table[op] = e
80 del e
81 del op
82 del op_list
83
84
85
86
87
88 override = {
89 'if' : 'if(?!def)',
90 }
91 l = map(lambda x, o=override: o.get(x, x), Table.keys())
92
93
94
95
96
97
98
99 e = '^\s*#\s*(' + string.join(l, '|') + ')(.*)$'
100
101
102 CPP_Expression = re.compile(e, re.M)
103
104
105
106
107
108
109
110
111
112
113
114
115
116 CPP_to_Python_Ops_Dict = {
117 '!' : ' not ',
118 '!=' : ' != ',
119 '&&' : ' and ',
120 '||' : ' or ',
121 '?' : ' and ',
122 ':' : ' or ',
123 '\r' : '',
124 }
125
126 CPP_to_Python_Ops_Sub = lambda m, d=CPP_to_Python_Ops_Dict: d[m.group(0)]
127
128
129
130
131
132
133
134 l = CPP_to_Python_Ops_Dict.keys()
135 l.sort(lambda a, b: cmp(len(b), len(a)))
136
137
138
139 expr = string.join(map(re.escape, l), '|')
140
141
142 CPP_to_Python_Ops_Expression = re.compile(expr)
143
144
145
146 CPP_to_Python_Eval_List = [
147 ['defined\s+(\w+)', '__dict__.has_key("\\1")'],
148 ['defined\s*\((\w+)\)', '__dict__.has_key("\\1")'],
149 ['/\*.*\*/', ''],
150 ['/\*.*', ''],
151 ['//.*', ''],
152 ['(0x[0-9A-Fa-f]*)[UL]+', '\\1L'],
153 ]
154
155
156
157 for l in CPP_to_Python_Eval_List:
158 l[0] = re.compile(l[0])
159
160
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 = expr.sub(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 """
183 - def __init__(self, name, args, expansion):
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 = string.split(expansion, '##')
193 except (AttributeError, TypeError):
194
195
196 pass
197 self.expansion = expansion
199 """
200 Evaluates the expansion of a #define macro function called
201 with the specified values.
202 """
203 if len(self.args) != len(values):
204 raise ValueError, "Incorrect number of arguments to `%s'" % self.name
205
206
207
208
209 locals = {}
210 for k, v in zip(self.args, values):
211 locals[k] = v
212
213 parts = []
214 for s in self.expansion:
215 if not s in self.args:
216 s = repr(s)
217 parts.append(s)
218 statement = string.join(parts, ' + ')
219
220 return eval(statement, globals(), locals)
221
222
223
224
225 line_continuations = re.compile('\\\\\r?\n')
226
227
228
229
230 function_name = re.compile('(\S+)\(([^)]*)\)')
231
232
233
234 function_arg_separator = re.compile(',\s*')
235
236
237
239 """
240 The main workhorse class for handling C pre-processing.
241 """
243 global Table
244
245 cpppath = tuple(cpppath)
246
247 self.searchpath = {
248 '"' : (current,) + cpppath,
249 '<' : cpppath + (current,),
250 }
251
252
253
254
255
256
257 self.cpp_namespace = dict.copy()
258 self.cpp_namespace['__dict__'] = self.cpp_namespace
259
260 if all:
261 self.do_include = self.all_include
262
263
264
265
266
267
268
269
270 d = {
271 'scons_current_file' : self.scons_current_file
272 }
273 for op in Table.keys():
274 d[op] = getattr(self, 'do_' + op)
275 self.default_table = d
276
277
278
280 """
281 Turns the contents of a file into a list of easily-processed
282 tuples describing the CPP lines in the file.
283
284 The first element of each tuple is the line's preprocessor
285 directive (#if, #include, #define, etc., minus the initial '#').
286 The remaining elements are specific to the type of directive, as
287 pulled apart by the regular expression.
288 """
289 global CPP_Expression, Table
290 contents = line_continuations.sub('', contents)
291 cpp_tuples = CPP_Expression.findall(contents)
292 return map(lambda m, t=Table:
293 (m[0],) + t[m[0]].match(m[1]).groups(),
294 cpp_tuples)
295
297 """
298 Pre-processes a file.
299
300 This is the main public entry point.
301 """
302 self.current_file = file
303 return self.process_contents(self.read_file(file), file)
304
305 - def process_contents(self, contents, fname=None):
306 """
307 Pre-processes a file contents.
308
309 This is the main internal entry point.
310 """
311 self.stack = []
312 self.dispatch_table = self.default_table.copy()
313 self.current_file = fname
314 self.tuples = self.tupleize(contents)
315
316 self.initialize_result(fname)
317 while self.tuples:
318 t = self.tuples.pop(0)
319
320
321
322 self.dispatch_table[t[0]](t)
323 return self.finalize_result(fname)
324
325
326
328 """
329 Pushes the current dispatch table on the stack and re-initializes
330 the current dispatch table to the default.
331 """
332 self.stack.append(self.dispatch_table)
333 self.dispatch_table = self.default_table.copy()
334
336 """
337 Pops the previous dispatch table off the stack and makes it the
338 current one.
339 """
340 try: self.dispatch_table = self.stack.pop()
341 except IndexError: pass
342
343
344
346 """
347 Null method for when we explicitly want the action for a
348 specific preprocessor directive to do nothing.
349 """
350 pass
351
353 self.current_file = t[1]
354
356 """
357 Evaluates a C preprocessor expression.
358
359 This is done by converting it to a Python equivalent and
360 eval()ing it in the C preprocessor namespace we use to
361 track #define values.
362 """
363 t = CPP_to_Python(string.join(t[1:]))
364 try: return eval(t, self.cpp_namespace)
365 except (NameError, TypeError): return 0
366
369
372
374 """
375 Finds the #include file for a given preprocessor tuple.
376 """
377 fname = t[2]
378 for d in self.searchpath[t[1]]:
379 if d == os.curdir:
380 f = fname
381 else:
382 f = os.path.join(d, fname)
383 if os.path.isfile(f):
384 return f
385 return None
386
389
390
391
393 """
394 Causes the PreProcessor object to start processing #import,
395 #include and #include_next lines.
396
397 This method will be called when a #if, #ifdef, #ifndef or #elif
398 evaluates True, or when we reach the #else in a #if, #ifdef,
399 #ifndef or #elif block where a condition already evaluated
400 False.
401
402 """
403 d = self.dispatch_table
404 d['import'] = self.do_import
405 d['include'] = self.do_include
406 d['include_next'] = self.do_include
407
409 """
410 Causes the PreProcessor object to stop processing #import,
411 #include and #include_next lines.
412
413 This method will be called when a #if, #ifdef, #ifndef or #elif
414 evaluates False, or when we reach the #else in a #if, #ifdef,
415 #ifndef or #elif block where a condition already evaluated True.
416 """
417 d = self.dispatch_table
418 d['import'] = self.do_nothing
419 d['include'] = self.do_nothing
420 d['include_next'] = self.do_nothing
421
422
423
424
425
441
447
453
459
469
471 """
472 Default handling of a #else line.
473 """
474 pass
475
477 """
478 Default handling of a #endif line.
479 """
480 self.restore()
481
483 """
484 Default handling of a #define line.
485 """
486 _, name, args, expansion = t
487 try:
488 expansion = int(expansion)
489 except (TypeError, ValueError):
490 pass
491 if args:
492 evaluator = FunctionEvaluator(name, args[1:-1], expansion)
493 self.cpp_namespace[name] = evaluator
494 else:
495 self.cpp_namespace[name] = expansion
496
498 """
499 Default handling of a #undef line.
500 """
501 try: del self.cpp_namespace[t[1]]
502 except KeyError: pass
503
505 """
506 Default handling of a #import line.
507 """
508
509 pass
510
512 """
513 Default handling of a #include line.
514 """
515 t = self.resolve_include(t)
516 include_file = self.find_include_file(t)
517 if include_file:
518
519 self.result.append(include_file)
520 contents = self.read_file(include_file)
521 new_tuples = [('scons_current_file', include_file)] + \
522 self.tupleize(contents) + \
523 [('scons_current_file', self.current_file)]
524 self.tuples[:] = new_tuples + self.tuples
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541 do_include_next = do_include
542
543
544
546 """Resolve a tuple-ized #include line.
547
548 This handles recursive expansion of values without "" or <>
549 surrounding the name until an initial " or < is found, to handle
550 #include FILE
551 where FILE is a #define somewhere else.
552 """
553 s = t[1]
554 while not s[0] in '<"':
555
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 = apply(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 apply(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