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 5110 2010/07/25 16:14:38 bdeegan"
25
26 __doc__ = """
27 SCons C Pre-Processor module
28 """
29
30
31
32
33 import SCons
34
35 import os
36 import re
37 import string
38
39
40
41
42
43
44
45
46
47
48
49
50 cpp_lines_dict = {
51
52
53 ('if', 'elif', 'ifdef', 'ifndef',)
54 : '\s+(.+)',
55
56
57
58 ('import', 'include', 'include_next',)
59 : '\s*(.+)',
60
61
62 ('else', 'endif',) : '',
63
64
65
66
67
68
69 ('define',) : '\s+([_A-Za-z][_A-Za-z0-9_]*)(\([^)]*\))?\s*(.*)',
70
71
72 ('undef',) : '\s+([_A-Za-z][A-Za-z0-9_]*)',
73 }
74
75
76
77
78 Table = {}
79 for op_list, expr in cpp_lines_dict.items():
80 e = re.compile(expr)
81 for op in op_list:
82 Table[op] = e
83 del e
84 del op
85 del op_list
86
87
88
89
90
91 override = {
92 'if' : 'if(?!def)',
93 }
94 l = map(lambda x, o=override: o.get(x, x), Table.keys())
95
96
97
98
99
100
101
102 e = '^\s*#\s*(' + string.join(l, '|') + ')(.*)$'
103
104
105 CPP_Expression = re.compile(e, re.M)
106
107
108
109
110
111
112
113
114
115
116
117
118
119 CPP_to_Python_Ops_Dict = {
120 '!' : ' not ',
121 '!=' : ' != ',
122 '&&' : ' and ',
123 '||' : ' or ',
124 '?' : ' and ',
125 ':' : ' or ',
126 '\r' : '',
127 }
128
129 CPP_to_Python_Ops_Sub = lambda m, d=CPP_to_Python_Ops_Dict: d[m.group(0)]
130
131
132
133
134
135
136
137 l = CPP_to_Python_Ops_Dict.keys()
138 l.sort(lambda a, b: cmp(len(b), len(a)))
139
140
141
142 expr = string.join(map(re.escape, l), '|')
143
144
145 CPP_to_Python_Ops_Expression = re.compile(expr)
146
147
148
149 CPP_to_Python_Eval_List = [
150 ['defined\s+(\w+)', '__dict__.has_key("\\1")'],
151 ['defined\s*\((\w+)\)', '__dict__.has_key("\\1")'],
152 ['/\*.*\*/', ''],
153 ['/\*.*', ''],
154 ['//.*', ''],
155 ['(0x[0-9A-Fa-f]*)[UL]+', '\\1L'],
156 ]
157
158
159
160 for l in CPP_to_Python_Eval_List:
161 l[0] = re.compile(l[0])
162
163
165 """
166 Converts a C pre-processor expression into an equivalent
167 Python expression that can be evaluated.
168 """
169 s = CPP_to_Python_Ops_Expression.sub(CPP_to_Python_Ops_Sub, s)
170 for expr, repl in CPP_to_Python_Eval_List:
171 s = expr.sub(repl, s)
172 return s
173
174
175
176 del expr
177 del l
178 del override
179
180
181
183 """
184 Handles delayed evaluation of a #define function call.
185 """
186 - def __init__(self, name, args, expansion):
187 """
188 Squirrels away the arguments and expansion value of a #define
189 macro function for later evaluation when we must actually expand
190 a value that uses it.
191 """
192 self.name = name
193 self.args = function_arg_separator.split(args)
194 try:
195 expansion = string.split(expansion, '##')
196 except (AttributeError, TypeError):
197
198
199 pass
200 self.expansion = expansion
202 """
203 Evaluates the expansion of a #define macro function called
204 with the specified values.
205 """
206 if len(self.args) != len(values):
207 raise ValueError, "Incorrect number of arguments to `%s'" % self.name
208
209
210
211
212 locals = {}
213 for k, v in zip(self.args, values):
214 locals[k] = v
215
216 parts = []
217 for s in self.expansion:
218 if not s in self.args:
219 s = repr(s)
220 parts.append(s)
221 statement = string.join(parts, ' + ')
222
223 return eval(statement, globals(), locals)
224
225
226
227
228 line_continuations = re.compile('\\\\\r?\n')
229
230
231
232
233 function_name = re.compile('(\S+)\(([^)]*)\)')
234
235
236
237 function_arg_separator = re.compile(',\s*')
238
239
240
242 """
243 The main workhorse class for handling C pre-processing.
244 """
245 - def __init__(self, current=os.curdir, cpppath=(), dict={}, all=0):
246 global Table
247
248 cpppath = tuple(cpppath)
249
250 self.searchpath = {
251 '"' : (current,) + cpppath,
252 '<' : cpppath + (current,),
253 }
254
255
256
257
258
259
260 self.cpp_namespace = dict.copy()
261 self.cpp_namespace['__dict__'] = self.cpp_namespace
262
263 if all:
264 self.do_include = self.all_include
265
266
267
268
269
270
271
272
273 d = {
274 'scons_current_file' : self.scons_current_file
275 }
276 for op in Table.keys():
277 d[op] = getattr(self, 'do_' + op)
278 self.default_table = d
279
280
281
283 """
284 Turns the contents of a file into a list of easily-processed
285 tuples describing the CPP lines in the file.
286
287 The first element of each tuple is the line's preprocessor
288 directive (#if, #include, #define, etc., minus the initial '#').
289 The remaining elements are specific to the type of directive, as
290 pulled apart by the regular expression.
291 """
292 global CPP_Expression, Table
293 contents = line_continuations.sub('', contents)
294 cpp_tuples = CPP_Expression.findall(contents)
295 return map(lambda m, t=Table:
296 (m[0],) + t[m[0]].match(m[1]).groups(),
297 cpp_tuples)
298
300 """
301 Pre-processes a file.
302
303 This is the main public entry point.
304 """
305 self.current_file = file
306 return self.process_contents(self.read_file(file), file)
307
308 - def process_contents(self, contents, fname=None):
309 """
310 Pre-processes a file contents.
311
312 This is the main internal entry point.
313 """
314 self.stack = []
315 self.dispatch_table = self.default_table.copy()
316 self.current_file = fname
317 self.tuples = self.tupleize(contents)
318
319 self.initialize_result(fname)
320 while self.tuples:
321 t = self.tuples.pop(0)
322
323
324
325 self.dispatch_table[t[0]](t)
326 return self.finalize_result(fname)
327
328
329
331 """
332 Pushes the current dispatch table on the stack and re-initializes
333 the current dispatch table to the default.
334 """
335 self.stack.append(self.dispatch_table)
336 self.dispatch_table = self.default_table.copy()
337
339 """
340 Pops the previous dispatch table off the stack and makes it the
341 current one.
342 """
343 try: self.dispatch_table = self.stack.pop()
344 except IndexError: pass
345
346
347
349 """
350 Null method for when we explicitly want the action for a
351 specific preprocessor directive to do nothing.
352 """
353 pass
354
356 self.current_file = t[1]
357
359 """
360 Evaluates a C preprocessor expression.
361
362 This is done by converting it to a Python equivalent and
363 eval()ing it in the C preprocessor namespace we use to
364 track #define values.
365 """
366 t = CPP_to_Python(string.join(t[1:]))
367 try: return eval(t, self.cpp_namespace)
368 except (NameError, TypeError): return 0
369
372
375
377 """
378 Finds the #include file for a given preprocessor tuple.
379 """
380 fname = t[2]
381 for d in self.searchpath[t[1]]:
382 if d == os.curdir:
383 f = fname
384 else:
385 f = os.path.join(d, fname)
386 if os.path.isfile(f):
387 return f
388 return None
389
392
393
394
396 """
397 Causes the PreProcessor object to start processing #import,
398 #include and #include_next lines.
399
400 This method will be called when a #if, #ifdef, #ifndef or #elif
401 evaluates True, or when we reach the #else in a #if, #ifdef,
402 #ifndef or #elif block where a condition already evaluated
403 False.
404
405 """
406 d = self.dispatch_table
407 d['import'] = self.do_import
408 d['include'] = self.do_include
409 d['include_next'] = self.do_include
410
412 """
413 Causes the PreProcessor object to stop processing #import,
414 #include and #include_next lines.
415
416 This method will be called when a #if, #ifdef, #ifndef or #elif
417 evaluates False, or when we reach the #else in a #if, #ifdef,
418 #ifndef or #elif block where a condition already evaluated True.
419 """
420 d = self.dispatch_table
421 d['import'] = self.do_nothing
422 d['include'] = self.do_nothing
423 d['include_next'] = self.do_nothing
424
425
426
427
428
444
450
456
462
472
474 """
475 Default handling of a #else line.
476 """
477 pass
478
480 """
481 Default handling of a #endif line.
482 """
483 self.restore()
484
486 """
487 Default handling of a #define line.
488 """
489 _, name, args, expansion = t
490 try:
491 expansion = int(expansion)
492 except (TypeError, ValueError):
493 pass
494 if args:
495 evaluator = FunctionEvaluator(name, args[1:-1], expansion)
496 self.cpp_namespace[name] = evaluator
497 else:
498 self.cpp_namespace[name] = expansion
499
501 """
502 Default handling of a #undef line.
503 """
504 try: del self.cpp_namespace[t[1]]
505 except KeyError: pass
506
508 """
509 Default handling of a #import line.
510 """
511
512 pass
513
515 """
516 Default handling of a #include line.
517 """
518 t = self.resolve_include(t)
519 include_file = self.find_include_file(t)
520 if include_file:
521
522 self.result.append(include_file)
523 contents = self.read_file(include_file)
524 new_tuples = [('scons_current_file', include_file)] + \
525 self.tupleize(contents) + \
526 [('scons_current_file', self.current_file)]
527 self.tuples[:] = new_tuples + self.tuples
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544 do_include_next = do_include
545
546
547
549 """Resolve a tuple-ized #include line.
550
551 This handles recursive expansion of values without "" or <>
552 surrounding the name until an initial " or < is found, to handle
553 #include FILE
554 where FILE is a #define somewhere else.
555 """
556 s = t[1]
557 while not s[0] in '<"':
558
559 try:
560 s = self.cpp_namespace[s]
561 except KeyError:
562 m = function_name.search(s)
563 s = self.cpp_namespace[m.group(1)]
564 if callable(s):
565 args = function_arg_separator.split(m.group(2))
566 s = apply(s, args)
567 if not s:
568 return None
569 return (t[0], s[0], s[1:-1])
570
575
577 """A preprocessor that ignores all #if/#elif/#else/#endif directives
578 and just reports back *all* of the #include files (like the classic
579 SCons scanner did).
580
581 This is functionally equivalent to using a regular expression to
582 find all of the #include lines, only slower. It exists mainly as
583 an example of how the main PreProcessor class can be sub-classed
584 to tailor its behavior.
585 """
587 apply(PreProcessor.__init__, (self,)+args, kw)
588 d = self.default_table
589 for func in ['if', 'elif', 'else', 'endif', 'ifdef', 'ifndef']:
590 d[func] = d[func] = self.do_nothing
591
592 del __revision__
593
594
595
596
597
598
599