Created
September 11, 2018 02:58
-
-
Save pansila/b48d0e72e907ef692bf15fa60e8aa232 to your computer and use it in GitHub Desktop.
Add comments to mark the start and stop position of C macro directives, including ifdef, else, endif, etc., to make them more legible
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/python | |
import sys, os | |
import argparse | |
class macro_directive(object): | |
def __init__(self, name, comment): | |
self.name = name[1:] if name[0] == "#" else name | |
self.comment = comment | |
self.path = True | |
self.last_seen = 0 | |
class macro_commenter(object): | |
lines = 0 | |
def __init__(self, skip_lines): | |
self.namestack = [] | |
self.skip_lines = skip_lines | |
def get_commenter(self, directive): | |
try: | |
return getattr(self, "comment_" + directive.name) | |
except: | |
return None | |
def comment_ifdef(self, fp, directive, line): | |
directive.path = True | |
directive.last_seen = self.lines | |
self.namestack.append([directive]) | |
fp.write(line) | |
def comment_ifndef(self, fp, directive, line): | |
directive.path = False | |
directive.last_seen = self.lines | |
self.namestack.append([directive]) | |
fp.write(line) | |
def comment_else(self, fp, directive, line): | |
line = line.rstrip() | |
last_stack = self.namestack[-1] | |
last_directive = last_stack[-1] | |
if directive.comment == None and self.should_comment(last_directive): | |
comments = [self.left_delimter(el.path) + el.comment for el in last_stack] | |
comment = " && ".join(comments) | |
fp.write(line + " /* " + comment + " */\n") | |
else: # don't comment if there was one | |
fp.write(line + "\n") | |
last_directive.last_seen = self.lines | |
del directive | |
def comment_endif(self, fp, directive, line): | |
line = line.rstrip() | |
last_stack = self.namestack.pop() | |
# always add the comment for endif | |
if directive.comment == None: | |
comments = [el.comment for el in last_stack] | |
comment = ", ".join(comments) | |
fp.write(line + " /* " + comment + " */\n") | |
else: | |
fp.write(line + "\n") | |
del last_stack | |
del directive | |
def comment_elif(self, fp, directive, line): | |
line = line.rstrip() | |
last_stack = self.namestack[-1] | |
last_directive = last_stack[-1] | |
directive.path = None | |
directive.last_seen = self.lines | |
if self.should_comment(last_directive): | |
comments = [self.left_delimter(el.path) + el.comment for el in last_stack] | |
comment = ", ".join(comments) | |
fp.write(line + " /* " + comment + " */\n") | |
else: | |
fp.write(line + "\n") | |
last_stack.append(directive) | |
def comment_if(self, fp, directive, line): | |
directive.path = None | |
directive.last_seen = self.lines | |
self.namestack.append([directive]) | |
fp.write(line) | |
def comment_defined(self, fp, directive, line): | |
pass | |
def should_comment(self, directive): | |
return self.lines - directive.last_seen > self.skip_lines | |
@staticmethod | |
def left_delimter(path): | |
if path == None: | |
return "?" | |
if path: | |
return "!" | |
else: | |
return "" | |
@classmethod | |
def count_lines(cls): | |
cls.lines += 1 | |
class macro_parser(object): | |
def __init__(self, fp, in_place, skip_lines): | |
self.origfile = fp | |
self.in_place = in_place | |
self.tempfile = fp+".tmp" | |
self.commenter = macro_commenter(skip_lines) | |
def process(self, fp, directive, line): | |
if directive is None: | |
fp.write(line) | |
return | |
commenter = self.commenter.get_commenter(directive) | |
if commenter is None: | |
fp.write(line) | |
else: | |
commenter(fp, directive, line) | |
def parse(self, line): | |
directive = None | |
line = line.lstrip() | |
if line.startswith("#"): | |
parts = line.split() | |
if parts[0] == "#": | |
parts.pop(0) | |
parts[0] = "#" + parts[0] | |
name = parts[0] | |
comment = parts[1] if len(parts) > 1 else None | |
directive = macro_directive(name, comment) | |
return directive | |
elif line.startswith("/*"): | |
idx = line.find("*/") | |
if idx > 0: | |
line = line[idx+2:] | |
return self.parse(line) | |
return directive | |
def run(self): | |
with open(self.origfile) as origfp, open(self.tempfile, "w") as tempfp: | |
for line in origfp: | |
self.commenter.count_lines() | |
directive = self.parse(line) | |
if directive is None: | |
tempfp.write(line) | |
continue | |
self.process(tempfp, directive, line) | |
if self.in_place == 1: | |
os.remove(self.origfile) | |
os.rename(self.tempfile, self.origfile) | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser() | |
parser.add_argument("--in-place", type=int, default=0, help="whether to modify the file in place") | |
parser.add_argument("--skip-line", type=int, default=5, help="least lines to comment between two macros") | |
parser.add_argument("file", type=str, help="need a file path to proceed") | |
args = parser.parse_args() | |
macro_parser = macro_parser(args.file, args.in_place, args.skip_line) | |
macro_parser.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage
Example
Before
After