|
|
#! /usr/bin/env python3
# Selectively preprocess #ifdef / #ifndef statements.# Usage:# ifdef [-Dname] ... [-Uname] ... [file] ...## This scans the file(s), looking for #ifdef and #ifndef preprocessor# commands that test for one of the names mentioned in the -D and -U# options. On standard output it writes a copy of the input file(s)# minus those code sections that are suppressed by the selected# combination of defined/undefined symbols. The #if(n)def/#else/#else# lines themselfs (if the #if(n)def tests for one of the mentioned# names) are removed as well.
# Features: Arbitrary nesting of recognized and unrecognized# preprocesor statements works correctly. Unrecognized #if* commands# are left in place, so it will never remove too much, only too# little. It does accept whitespace around the '#' character.
# Restrictions: There should be no comments or other symbols on the# #if(n)def lines. The effect of #define/#undef commands in the input# file or in included files is not taken into account. Tests using# #if and the defined() pseudo function are not recognized. The #elif# command is not recognized. Improperly nesting is not detected.# Lines that look like preprocessor commands but which are actually# part of comments or string literals will be mistaken for# preprocessor commands.
import sysimport getopt
defs = []undefs = []
def main(): opts, args = getopt.getopt(sys.argv[1:], 'D:U:') for o, a in opts: if o == '-D': defs.append(a) if o == '-U': undefs.append(a) if not args: args = ['-'] for filename in args: if filename == '-': process(sys.stdin, sys.stdout) else: f = open(filename, 'r') process(f, sys.stdout) f.close()
def process(fpi, fpo): keywords = ('if', 'ifdef', 'ifndef', 'else', 'endif') ok = 1 stack = [] while 1: line = fpi.readline() if not line: break while line[-2:] == '\\\n': nextline = fpi.readline() if not nextline: break line = line + nextline tmp = line.strip() if tmp[:1] != '#': if ok: fpo.write(line) continue tmp = tmp[1:].strip() words = tmp.split() keyword = words[0] if keyword not in keywords: if ok: fpo.write(line) continue if keyword in ('ifdef', 'ifndef') and len(words) == 2: if keyword == 'ifdef': ko = 1 else: ko = 0 word = words[1] if word in defs: stack.append((ok, ko, word)) if not ko: ok = 0 elif word in undefs: stack.append((ok, not ko, word)) if ko: ok = 0 else: stack.append((ok, -1, word)) if ok: fpo.write(line) elif keyword == 'if': stack.append((ok, -1, '')) if ok: fpo.write(line) elif keyword == 'else' and stack: s_ok, s_ko, s_word = stack[-1] if s_ko < 0: if ok: fpo.write(line) else: s_ko = not s_ko ok = s_ok if not s_ko: ok = 0 stack[-1] = s_ok, s_ko, s_word elif keyword == 'endif' and stack: s_ok, s_ko, s_word = stack[-1] if s_ko < 0: if ok: fpo.write(line) del stack[-1] ok = s_ok else: sys.stderr.write('Unknown keyword %s\n' % keyword) if stack: sys.stderr.write('stack: %s\n' % stack)
if __name__ == '__main__': main()
|