import reimport sysdef negate(condition):"""Returns a CPP conditional that is the opposite of the conditional passed in."""if condition.startswith('!'):return condition[1:]return "!" + conditionclass Monitor:"""A simple C preprocessor that scans C source and computes, line by line,what the current C preprocessor #if state is.Doesn't handle everything--for example, if you have /* inside a C string,without a matching */ (also inside a C string), or with a */ inside a Cstring but on another line and with preprocessor macros in between...the parser will get lost.Anyway this implementation seems to work well enough for the CPython sources."""is_a_simple_defined = re.compile(r'^defined\s*\(\s*[A-Za-z0-9_]+\s*\)$').matchdef __init__(self, filename=None, *, verbose=False):self.stack = []self.in_comment = Falseself.continuation = Noneself.line_number = 0self.filename = filenameself.verbose = verbosedef __repr__(self):return ''.join(('<Monitor ',str(id(self))," line=", str(self.line_number)," condition=", repr(self.condition()),">"))def status(self):return str(self.line_number).rjust(4) + ": " + self.condition()def condition(self):"""Returns the current preprocessor state, as a single #if condition."""return " && ".join(condition for token, condition in self.stack)def fail(self, *a):if self.filename:filename = " " + self.filenameelse:filename = ''print("Error at" + filename, "line", self.line_number, ":")print(" ", ' '.join(str(x) for x in a))sys.exit(-1)def close(self):if self.stack:self.fail("Ended file while still in a preprocessor conditional block!")def write(self, s):for line in s.split("\n"):self.writeline(line)def writeline(self, line):self.line_number += 1line = line.strip()def pop_stack():if not self.stack:self.fail("#" + token + " without matching #if / #ifdef / #ifndef!")return self.stack.pop()if self.continuation:line = self.continuation + lineself.continuation = Noneif not line:returnif line.endswith('\\'):self.continuation = line[:-1].rstrip() + " "return# we have to ignore preprocessor commands inside comments## we also have to handle this:# /* start# ...# */ /* <-- tricky!# ...# */# and this:# /* start# ...# */ /* also tricky! */if self.in_comment:if '*/' in line:# snip out the comment and continue## GCC allows# /* comment# */ #include <stdio.h># maybe other compilers too?_, _, line = line.partition('*/')self.in_comment = Falsewhile True:if '/*' in line:if self.in_comment:self.fail("Nested block comment!")before, _, remainder = line.partition('/*')comment, comment_ends, after = remainder.partition('*/')if comment_ends:# snip out the commentline = before.rstrip() + ' ' + after.lstrip()continue# comment continues to eolself.in_comment = Trueline = before.rstrip()break# we actually have some // comments# (but block comments take precedence)before, line_comment, comment = line.partition('//')if line_comment:line = before.rstrip()if not line.startswith('#'):returnline = line[1:].lstrip()assert linefields = line.split()token = fields[0].lower()condition = ' '.join(fields[1:]).strip()if_tokens = {'if', 'ifdef', 'ifndef'}all_tokens = if_tokens | {'elif', 'else', 'endif'}if token not in all_tokens:return# cheat a little here, to reuse the implementation of ifif token == 'elif':pop_stack()token = 'if'if token in if_tokens:if not condition:self.fail("Invalid format for #" + token + " line: no argument!")if token == 'if':if not self.is_a_simple_defined(condition):condition = "(" + condition + ")"else:fields = condition.split()if len(fields) != 1:self.fail("Invalid format for #" + token + " line: should be exactly one argument!")symbol = fields[0]condition = 'defined(' + symbol + ')'if token == 'ifndef':condition = '!' + conditionself.stack.append(("if", condition))if self.verbose:print(self.status())returnprevious_token, previous_condition = pop_stack()if token == 'else':self.stack.append(('else', negate(previous_condition)))elif token == 'endif':passif self.verbose:print(self.status())if __name__ == '__main__':for filename in sys.argv[1:]:with open(filename, "rt") as f:cpp = Monitor(filename, verbose=True)print()print(filename)for line_number, line in enumerate(f.read().split('\n'), 1):cpp.writeline(line)
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。