cpp.py (scons-4.2.0) | : | cpp.py (SCons-4.3.0) | ||
---|---|---|---|---|
skipping to change at line 176 | skipping to change at line 176 | |||
s = CPP_to_Python_Ops_Expression.sub(CPP_to_Python_Ops_Sub, s) | s = CPP_to_Python_Ops_Expression.sub(CPP_to_Python_Ops_Sub, s) | |||
for expr, repl in CPP_to_Python_Eval_List: | for expr, repl in CPP_to_Python_Eval_List: | |||
s = re.sub(expr, repl, s) | s = re.sub(expr, repl, s) | |||
return s | return s | |||
del expr | del expr | |||
del l | del l | |||
del override | del override | |||
class FunctionEvaluator: | class FunctionEvaluator: | |||
""" | """Handles delayed evaluation of a #define function call.""" | |||
Handles delayed evaluation of a #define function call. | ||||
""" | ||||
def __init__(self, name, args, expansion): | def __init__(self, name, args, expansion): | |||
""" | """ | |||
Squirrels away the arguments and expansion value of a #define | Squirrels away the arguments and expansion value of a #define | |||
macro function for later evaluation when we must actually expand | macro function for later evaluation when we must actually expand | |||
a value that uses it. | a value that uses it. | |||
""" | """ | |||
self.name = name | self.name = name | |||
self.args = function_arg_separator.split(args) | self.args = function_arg_separator.split(args) | |||
try: | try: | |||
expansion = expansion.split('##') | expansion = expansion.split('##') | |||
except AttributeError: | except AttributeError: | |||
pass | pass | |||
self.expansion = expansion | self.expansion = expansion | |||
def __call__(self, *values): | def __call__(self, *values): | |||
""" | """ | |||
Evaluates the expansion of a #define macro function called | Evaluates the expansion of a #define macro function called | |||
with the specified values. | with the specified values. | |||
""" | """ | |||
if len(self.args) != len(values): | if len(self.args) != len(values): | |||
raise ValueError("Incorrect number of arguments to `%s'" % self.name ) | raise ValueError("Incorrect number of arguments to `%s'" % self.name ) | |||
# Create a dictionary that maps the macro arguments to the | # Create a dictionary that maps the macro arguments to the | |||
# corresponding values in this "call." We'll use this when we | # corresponding values in this "call." We'll use this when we | |||
# eval() the expansion so that arguments will get expanded to | # eval() the expansion so that arguments will get expanded to | |||
# the right values. | # the right values. | |||
locals = {} | args = self.args | |||
for k, v in zip(self.args, values): | localvars = {k: v for k, v in zip(args, values)} | |||
locals[k] = v | parts = [s if s in args else repr(s) for s in self.expansion] | |||
parts = [] | ||||
for s in self.expansion: | ||||
if s not in self.args: | ||||
s = repr(s) | ||||
parts.append(s) | ||||
statement = ' + '.join(parts) | statement = ' + '.join(parts) | |||
return eval(statement, globals(), locals) | return eval(statement, globals(), localvars) | |||
# Find line continuations. | # Find line continuations. | |||
line_continuations = re.compile('\\\\\r?\n') | line_continuations = re.compile('\\\\\r?\n') | |||
# Search for a "function call" macro on an expansion. Returns the | # Search for a "function call" macro on an expansion. Returns the | |||
# two-tuple of the "function" name itself, and a string containing the | # two-tuple of the "function" name itself, and a string containing the | |||
# arguments within the call parentheses. | # arguments within the call parentheses. | |||
function_name = re.compile(r'(\S+)\(([^)]*)\)') | function_name = re.compile(r'(\S+)\(([^)]*)\)') | |||
# Split a string containing comma-separated function call arguments into | # Split a string containing comma-separated function call arguments into | |||
# the separate arguments. | # the separate arguments. | |||
function_arg_separator = re.compile(r',\s*') | function_arg_separator = re.compile(r',\s*') | |||
class PreProcessor: | class PreProcessor: | |||
"""The main workhorse class for handling C pre-processing.""" | ||||
""" | ||||
The main workhorse class for handling C pre-processing. | ||||
""" | ||||
def __init__(self, current=os.curdir, cpppath=(), dict={}, all=0, depth=-1): | def __init__(self, current=os.curdir, cpppath=(), dict={}, all=0, depth=-1): | |||
global Table | global Table | |||
cpppath = tuple(cpppath) | cpppath = tuple(cpppath) | |||
self.searchpath = { | self.searchpath = { | |||
'"' : (current,) + cpppath, | '"': (current,) + cpppath, | |||
'<' : cpppath + (current,), | '<': cpppath + (current,), | |||
} | } | |||
# Initialize our C preprocessor namespace for tracking the | # Initialize our C preprocessor namespace for tracking the | |||
# values of #defined keywords. We use this namespace to look | # values of #defined keywords. We use this namespace to look | |||
# for keywords on #ifdef/#ifndef lines, and to eval() the | # for keywords on #ifdef/#ifndef lines, and to eval() the | |||
# expressions on #if/#elif lines (after massaging them from C to | # expressions on #if/#elif lines (after massaging them from C to | |||
# Python). | # Python). | |||
self.cpp_namespace = dict.copy() | self.cpp_namespace = dict.copy() | |||
self.cpp_namespace['__dict__'] = self.cpp_namespace | self.cpp_namespace['__dict__'] = self.cpp_namespace | |||
# Return all includes without resolving | # Return all includes without resolving | |||
if all: | if all: | |||
self.do_include = self.all_include | self.do_include = self.all_include | |||
# Max depth of nested includes: | # Max depth of nested includes: | |||
# -1 = unlimited | # -1 = unlimited | |||
# 0 - disabled nesting | # 0 - disabled nesting | |||
# >0 - number of allowed nested includes | # >0 - number of allowed nested includes | |||
self.depth = depth | self.depth = depth | |||
# For efficiency, a dispatch table maps each C preprocessor | # For efficiency, a dispatch table maps each C preprocessor | |||
# directive (#if, #define, etc.) to the method that should be | # directive (#if, #define, etc.) to the method that should be | |||
# called when we see it. We accomodate state changes (#if, | # called when we see it. We accomodate state changes (#if, | |||
# #ifdef, #ifndef) by pushing the current dispatch table on a | # #ifdef, #ifndef) by pushing the current dispatch table on a | |||
# stack and changing what method gets called for each relevant | # stack and changing what method gets called for each relevant | |||
# directive we might see next at this level (#else, #elif). | # directive we might see next at this level (#else, #elif). | |||
# #endif will simply pop the stack. | # #endif will simply pop the stack. | |||
d = { | d = {'scons_current_file': self.scons_current_file} | |||
'scons_current_file' : self.scons_current_file | ||||
} | ||||
for op in Table.keys(): | for op in Table.keys(): | |||
d[op] = getattr(self, 'do_' + op) | d[op] = getattr(self, 'do_' + op) | |||
self.default_table = d | self.default_table = d | |||
def __call__(self, file): | def __call__(self, file): | |||
""" | """ | |||
Pre-processes a file. | Pre-processes a file. | |||
This is the main public entry point. | This is the main public entry point. | |||
""" | """ | |||
End of changes. 9 change blocks. | ||||
22 lines changed or deleted | 12 lines changed or added |