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