Path: blob/main/Tools/c-analyzer/c_parser/__main__.py
12 views
import logging1import sys23from c_common.scriptutil import (4add_verbosity_cli,5add_traceback_cli,6add_kind_filtering_cli,7add_files_cli,8add_commands_cli,9process_args_by_key,10configure_logger,11get_prog,12main_for_filenames,13)14from .preprocessor.__main__ import (15add_common_cli as add_preprocessor_cli,16)17from .info import KIND18from . import parse_file as _iter_parsed192021logger = logging.getLogger(__name__)222324def _format_vartype(vartype):25if isinstance(vartype, str):26return vartype2728data = vartype29try:30vartype = data['vartype']31except KeyError:32storage, typequal, typespec, abstract = vartype.values()33else:34storage = data.get('storage')35if storage:36_, typequal, typespec, abstract = vartype.values()37else:38storage, typequal, typespec, abstract = vartype.values()3940vartype = f'{typespec} {abstract}'41if typequal:42vartype = f'{typequal} {vartype}'43if storage:44vartype = f'{storage} {vartype}'45return vartype464748def _get_preprocessor(filename, **kwargs):49return get_processor(filename,50log_err=print,51**kwargs52)535455#######################################56# the formats5758def fmt_raw(filename, item, *, showfwd=None):59yield str(tuple(item))606162def fmt_summary(filename, item, *, showfwd=None):63if item.filename != filename:64yield f'> {item.filename}'6566if showfwd is None:67LINE = ' {lno:>5} {kind:10} {funcname:40} {fwd:1} {name:40} {data}'68else:69LINE = ' {lno:>5} {kind:10} {funcname:40} {name:40} {data}'70lno = kind = funcname = fwd = name = data = ''71MIN_LINE = len(LINE.format(**locals()))7273fileinfo, kind, funcname, name, data = item74lno = fileinfo.lno if fileinfo and fileinfo.lno >= 0 else ''75funcname = funcname or ' --'76name = name or ' --'77isforward = False78if kind is KIND.FUNCTION:79storage, inline, params, returntype, isforward = data.values()80returntype = _format_vartype(returntype)81data = returntype + params82if inline:83data = f'inline {data}'84if storage:85data = f'{storage} {data}'86elif kind is KIND.VARIABLE:87data = _format_vartype(data)88elif kind is KIND.STRUCT or kind is KIND.UNION:89if data is None:90isforward = True91else:92fields = data93data = f'({len(data)}) {{ '94indent = ',\n' + ' ' * (MIN_LINE + len(data))95data += ', '.join(f.name for f in fields[:5])96fields = fields[5:]97while fields:98data = f'{data}{indent}{", ".join(f.name for f in fields[:5])}'99fields = fields[5:]100data += ' }'101elif kind is KIND.ENUM:102if data is None:103isforward = True104else:105names = [d if isinstance(d, str) else d.name106for d in data]107data = f'({len(data)}) {{ '108indent = ',\n' + ' ' * (MIN_LINE + len(data))109data += ', '.join(names[:5])110names = names[5:]111while names:112data = f'{data}{indent}{", ".join(names[:5])}'113names = names[5:]114data += ' }'115elif kind is KIND.TYPEDEF:116data = f'typedef {data}'117elif kind == KIND.STATEMENT:118pass119else:120raise NotImplementedError(item)121if isforward:122fwd = '*'123if not showfwd and showfwd is not None:124return125elif showfwd:126return127kind = kind.value128yield LINE.format(**locals())129130131def fmt_full(filename, item, *, showfwd=None):132raise NotImplementedError133134135FORMATS = {136'raw': fmt_raw,137'summary': fmt_summary,138'full': fmt_full,139}140141142def add_output_cli(parser):143parser.add_argument('--format', dest='fmt', default='summary', choices=tuple(FORMATS))144parser.add_argument('--showfwd', action='store_true', default=None)145parser.add_argument('--no-showfwd', dest='showfwd', action='store_false', default=None)146147def process_args(args, *, argv=None):148pass149return process_args150151152#######################################153# the commands154155def _cli_parse(parser, excluded=None, **prepr_kwargs):156process_output = add_output_cli(parser)157process_kinds = add_kind_filtering_cli(parser)158process_preprocessor = add_preprocessor_cli(parser, **prepr_kwargs)159process_files = add_files_cli(parser, excluded=excluded)160return [161process_output,162process_kinds,163process_preprocessor,164process_files,165]166167168def cmd_parse(filenames, *,169fmt='summary',170showfwd=None,171iter_filenames=None,172relroot=None,173**kwargs174):175if 'get_file_preprocessor' not in kwargs:176kwargs['get_file_preprocessor'] = _get_preprocessor()177try:178do_fmt = FORMATS[fmt]179except KeyError:180raise ValueError(f'unsupported fmt {fmt!r}')181for filename, relfile in main_for_filenames(filenames, iter_filenames, relroot):182for item in _iter_parsed(filename, **kwargs):183item = item.fix_filename(relroot, fixroot=False, normalize=False)184for line in do_fmt(relfile, item, showfwd=showfwd):185print(line)186187188def _cli_data(parser):189...190191return []192193194def cmd_data(filenames,195**kwargs196):197# XXX198raise NotImplementedError199200201COMMANDS = {202'parse': (203'parse the given C source & header files',204[_cli_parse],205cmd_parse,206),207'data': (208'check/manage local data (e.g. excludes, macros)',209[_cli_data],210cmd_data,211),212}213214215#######################################216# the script217218def parse_args(argv=sys.argv[1:], prog=sys.argv[0], *, subset='parse'):219import argparse220parser = argparse.ArgumentParser(221prog=prog or get_prog,222)223224processors = add_commands_cli(225parser,226commands={k: v[1] for k, v in COMMANDS.items()},227commonspecs=[228add_verbosity_cli,229add_traceback_cli,230],231subset=subset,232)233234args = parser.parse_args(argv)235ns = vars(args)236237cmd = ns.pop('cmd')238239verbosity, traceback_cm = process_args_by_key(240args,241argv,242processors[cmd],243['verbosity', 'traceback_cm'],244)245246return cmd, ns, verbosity, traceback_cm247248249def main(cmd, cmd_kwargs):250try:251run_cmd = COMMANDS[cmd][0]252except KeyError:253raise ValueError(f'unsupported cmd {cmd!r}')254run_cmd(**cmd_kwargs)255256257if __name__ == '__main__':258cmd, cmd_kwargs, verbosity, traceback_cm = parse_args()259configure_logger(verbosity)260with traceback_cm:261main(cmd, cmd_kwargs)262263264