diff --git a/bin/verilator_ccache_report b/bin/verilator_ccache_report index 43c4543f9..92355a898 100755 --- a/bin/verilator_ccache_report +++ b/bin/verilator_ccache_report @@ -16,8 +16,7 @@ parser = argparse.ArgumentParser( For documentation see https://verilator.org/guide/latest/exe_verilator_ccache_report.html""", - epilog= - """Copyright 2002-2024 by Wilson Snyder. This program is free software; you + epilog="""Copyright 2002-2024 by Wilson Snyder. This program is free software; you can redistribute it and/or modify it under the terms of either the GNU Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. @@ -67,30 +66,23 @@ else: wnames = max(len(_) for _ in results) + 1 wresults = max(len(_) for _ in results.values()) + 1 for k in sorted(results.keys()): - args.o.write("{:{wnames}} : {:{wresults}} : {}s\n".format( - k, - results[k], - elapsed[k].total_seconds(), - wnames=wnames, - wresults=wresults)) + args.o.write("{:{wnames}} : {:{wresults}} : {}s\n".format(k, + results[k], + elapsed[k].total_seconds(), + wnames=wnames, + wresults=wresults)) args.o.write("\nSummary:\n") counts = collections.Counter(_ for _ in results.values()) total = sum(counts.values()) for k in sorted(counts.keys()): c = counts[k] - args.o.write("{:{width}}| {} ({:.2%})\n".format(k, - c, - c / total, - width=wresults)) + args.o.write("{:{width}}| {} ({:.2%})\n".format(k, c, c / total, width=wresults)) args.o.write("\nLongest:\n") - longest = sorted(list(elapsed.items()), - key=lambda kv: -kv[1].total_seconds()) + longest = sorted(list(elapsed.items()), key=lambda kv: -kv[1].total_seconds()) for i, (k, v) in enumerate(longest): - args.o.write("{:{width}}| {}s\n".format(k, - v.total_seconds(), - width=wnames)) + args.o.write("{:{width}}| {}s\n".format(k, v.total_seconds(), width=wnames)) if i > 4: break diff --git a/bin/verilator_difftree b/bin/verilator_difftree index 9bc590213..1b77e3832 100755 --- a/bin/verilator_difftree +++ b/bin/verilator_difftree @@ -47,8 +47,7 @@ def diff_dir(a, b): diff_file(a, b) anyfile = True if not anyfile: - sys.stderr.write( - "%Warning: No .tree files found that have similar base names\n") + sys.stderr.write("%Warning: No .tree files found that have similar base names\n") def diff_file(a, b): @@ -109,18 +108,14 @@ parser = argparse.ArgumentParser( Verilator_difftree is used for debugging Verilator tree output files. It performs a diff between two files, or all files common between two directories, ignoring irrelevant pointer differences.""", - epilog= - """Copyright 2005-2024 by Wilson Snyder. This program is free software; you + epilog="""Copyright 2005-2024 by Wilson Snyder. This program is free software; you can redistribute it and/or modify it under the terms of either the GNU Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""") -parser.add_argument('--debug', - action='store_const', - const=9, - help='enable debug') +parser.add_argument('--debug', action='store_const', const=9, help='enable debug') parser.add_argument('--no-lineno', action='store_false', help='do not show differences in line numbering') diff --git a/bin/verilator_gantt b/bin/verilator_gantt index 8f0c166e1..40450d299 100755 --- a/bin/verilator_gantt +++ b/bin/verilator_gantt @@ -15,11 +15,7 @@ LongestVcdStrValueLength = 0 Threads = collections.defaultdict(lambda: []) # List of records per thread id Mtasks = collections.defaultdict(lambda: {'elapsed': 0, 'end': 0}) Cpus = collections.defaultdict(lambda: {'mtask_time': 0}) -Global = { - 'args': {}, - 'cpuinfo': collections.defaultdict(lambda: {}), - 'stats': {} -} +Global = {'args': {}, 'cpuinfo': collections.defaultdict(lambda: {}), 'stats': {}} ElapsedTime = None # total elapsed time ExecGraphTime = 0 # total elapsed time excuting an exec graph ExecGraphIntervals = [] # list of (start, end) pairs @@ -31,8 +27,7 @@ def read_data(filename): with open(filename, "r", encoding="utf8") as fh: re_thread = re.compile(r'^VLPROFTHREAD (\d+)$') re_record = re.compile(r'^VLPROFEXEC (\S+) (\d+)(.*)$') - re_payload_mtaskBegin = re.compile( - r'id (\d+) predictStart (\d+) cpu (\d+)') + re_payload_mtaskBegin = re.compile(r'id (\d+) predictStart (\d+) cpu (\d+)') re_payload_mtaskEnd = re.compile(r'id (\d+) predictCost (\d+)') re_arg1 = re.compile(r'VLPROF arg\s+(\S+)\+([0-9.]*)\s*') @@ -57,8 +52,7 @@ def read_data(filename): tick = int(tick) payload = payload.strip() if kind == "SECTION_PUSH": - LongestVcdStrValueLength = max(LongestVcdStrValueLength, - len(payload)) + LongestVcdStrValueLength = max(LongestVcdStrValueLength, len(payload)) SectionStack.append(payload) Sections.append((tick, tuple(SectionStack))) elif kind == "SECTION_POP": @@ -66,15 +60,13 @@ def read_data(filename): SectionStack.pop() Sections.append((tick, tuple(SectionStack))) elif kind == "MTASK_BEGIN": - mtask, predict_start, ecpu = re_payload_mtaskBegin.match( - payload).groups() + mtask, predict_start, ecpu = re_payload_mtaskBegin.match(payload).groups() mtask = int(mtask) predict_start = int(predict_start) ecpu = int(ecpu) mTaskThread[mtask] = thread records = Threads[thread] - assert not records or records[-1]['start'] <= records[-1][ - 'end'] <= tick + assert not records or records[-1]['start'] <= records[-1]['end'] <= tick records.append({ 'start': tick, 'mtask': mtask, @@ -85,8 +77,7 @@ def read_data(filename): Mtasks[mtask]['thread'] = thread Mtasks[mtask]['predict_start'] = predict_start elif kind == "MTASK_END": - mtask, predict_cost = re_payload_mtaskEnd.match( - payload).groups() + mtask, predict_cost = re_payload_mtaskEnd.match(payload).groups() mtask = int(mtask) predict_cost = int(predict_cost) begin = Mtasks[mtask]['begin'] @@ -163,8 +154,7 @@ def report(): print("\nSummary:") print(" Total elapsed time = {} rdtsc ticks".format(ElapsedTime)) - print(" Parallelized code = {:.2%} of elapsed time".format( - ExecGraphTime / ElapsedTime)) + print(" Parallelized code = {:.2%} of elapsed time".format(ExecGraphTime / ElapsedTime)) print(" Total threads = %d" % nthreads) print(" Total CPUs used = %d" % ncpus) print(" Total mtasks = %d" % len(Mtasks)) @@ -176,15 +166,12 @@ def report(): if nthreads > ncpus: print() - print("%%Warning: There were fewer CPUs (%d) than threads (%d)." % - (ncpus, nthreads)) + print("%%Warning: There were fewer CPUs (%d) than threads (%d)." % (ncpus, nthreads)) print(" : See docs on use of numactl.") else: if 'cpu_socket_cores_warning' in Global: print() - print( - "%Warning: Multiple threads scheduled on same hyperthreaded core." - ) + print("%Warning: Multiple threads scheduled on same hyperthreaded core.") print(" : See docs on use of numactl.") if 'cpu_sockets_warning' in Global: print() @@ -228,8 +215,7 @@ def report_mtasks(): serialTime = ElapsedTime - ExecGraphTime def subReport(elapsed, work): - print(" Thread utilization = {:7.2%}".format(work / - (elapsed * nthreads))) + print(" Thread utilization = {:7.2%}".format(work / (elapsed * nthreads))) print(" Speedup = {:6.3}x".format(work / elapsed)) print("\nParallelized code, measured:") @@ -256,8 +242,7 @@ def report_mtasks(): if Mtasks[mtask]['elapsed'] > 0: if Mtasks[mtask]['predict_cost'] == 0: Mtasks[mtask]['predict_cost'] = 1 # don't log(0) below - p2e_ratio = math.log(Mtasks[mtask]['predict_cost'] / - Mtasks[mtask]['elapsed']) + p2e_ratio = math.log(Mtasks[mtask]['predict_cost'] / Mtasks[mtask]['elapsed']) p2e_ratios.append(p2e_ratio) if p2e_ratio > max_p2e: @@ -269,18 +254,14 @@ def report_mtasks(): print("\nMTask statistics:") print(" Longest mtask id = {}".format(long_mtask)) - print(" Longest mtask time = {:.2%} of time elapsed in parallelized code". - format(long_mtask_time / ExecGraphTime)) + print(" Longest mtask time = {:.2%} of time elapsed in parallelized code".format( + long_mtask_time / ExecGraphTime)) print(" min log(p2e) = %0.3f" % min_p2e, end="") - print(" from mtask %d (predict %d," % - (min_mtask, Mtasks[min_mtask]['predict_cost']), - end="") + print(" from mtask %d (predict %d," % (min_mtask, Mtasks[min_mtask]['predict_cost']), end="") print(" elapsed %d)" % Mtasks[min_mtask]['elapsed']) print(" max log(p2e) = %0.3f" % max_p2e, end="") - print(" from mtask %d (predict %d," % - (max_mtask, Mtasks[max_mtask]['predict_cost']), - end="") + print(" from mtask %d (predict %d," % (max_mtask, Mtasks[max_mtask]['predict_cost']), end="") print(" elapsed %d)" % Mtasks[max_mtask]['elapsed']) stddev = statistics.pstdev(p2e_ratios) @@ -315,8 +296,8 @@ def report_cpus(): model = cpuinfo['model_name'] print(" {:3d} | {:7.2%} / {:16d} | {:>6s} | {:>4s} | {}".format( - cpu, Cpus[cpu]['mtask_time'] / ElapsedTime, - Cpus[cpu]['mtask_time'], socket, core, model)) + cpu, Cpus[cpu]['mtask_time'] / ElapsedTime, Cpus[cpu]['mtask_time'], socket, core, + model)) if len(Global['cpu_sockets']) > 1: Global['cpu_sockets_warning'] = True @@ -366,8 +347,8 @@ def report_sections(): def printTree(prefix, name, entries, tree): print(" {:7.2%} | {:7.2%} | {:8} | {:10.2f} | {}".format( - treeSum(tree) / ElapsedTime, tree[0] / ElapsedTime, tree[2], - tree[2] / entries, prefix + name)) + treeSum(tree) / ElapsedTime, tree[0] / ElapsedTime, tree[2], tree[2] / entries, + prefix + name)) for k in sorted(tree[1], key=lambda _: -treeSum(tree[1][_])): printTree(prefix + " ", k, tree[2], tree[1][k]) @@ -438,10 +419,8 @@ def write_vcd(filename): addValue(code, start, mtask) addValue(code, end, None) - tStart = sorted(_['start'] for records in Threads.values() - for _ in records) - tEnd = sorted(_['end'] for records in Threads.values() - for _ in records) + tStart = sorted(_['start'] for records in Threads.values() for _ in records) + tEnd = sorted(_['end'] for records in Threads.values() for _ in records) # Predicted graph for start, end in ExecGraphIntervals: @@ -455,11 +434,10 @@ def write_vcd(filename): # Predict mtasks that fill the time the execution occupied for mtask in Mtasks: thread = Mtasks[mtask]['thread'] - pred_scaled_start = start + int( - Mtasks[mtask]['predict_start'] * measured_scaling) + pred_scaled_start = start + int(Mtasks[mtask]['predict_start'] * measured_scaling) pred_scaled_end = start + int( - (Mtasks[mtask]['predict_start'] + - Mtasks[mtask]['predict_cost']) * measured_scaling) + (Mtasks[mtask]['predict_start'] + Mtasks[mtask]['predict_cost']) * + measured_scaling) if pred_scaled_start == pred_scaled_end: continue @@ -545,8 +523,7 @@ Verilator_gantt creates a visual representation to help analyze Verilator For documentation see https://verilator.org/guide/latest/exe_verilator_gantt.html""", - epilog= - """Copyright 2018-2024 by Wilson Snyder. This program is free software; you + epilog="""Copyright 2018-2024 by Wilson Snyder. This program is free software; you can redistribute it and/or modify it under the terms of either the GNU Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. @@ -554,12 +531,8 @@ Version 2.0. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""") parser.add_argument('--debug', action='store_true', help='enable debug') -parser.add_argument('--no-vcd', - help='disable creating vcd', - action='store_true') -parser.add_argument('--vcd', - help='filename for vcd outpue', - default='profile_exec.vcd') +parser.add_argument('--no-vcd', help='disable creating vcd', action='store_true') +parser.add_argument('--vcd', help='filename for vcd outpue', default='profile_exec.vcd') parser.add_argument('filename', help='input profile_exec.dat filename to process', default='profile_exec.dat') diff --git a/bin/verilator_profcfunc b/bin/verilator_profcfunc index e5487f127..dabd8af97 100755 --- a/bin/verilator_profcfunc +++ b/bin/verilator_profcfunc @@ -34,9 +34,8 @@ def profcfunc(filename): # Older gprofs have no call column for single-call functions # %time cumesec selfsec {stuff} name - match = re.match( - r'^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$', - line) + match = re.match(r'^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$', + line) if match: pct = float(match.group(1)) sec = float(match.group(2)) @@ -143,12 +142,9 @@ def profcfunc(filename): print(" These are split into three categories:") print(" C++: Time in non-Verilated C++ code") print(" Prof: Time in profile overhead") - print(" VBlock: Time attributable to a block in a" + - " Verilog file and line") - print(" VCommon: Time in a Verilated module," + - " due to all parts of the design") - print(" VLib: Time in Verilated common libraries," + - " called by the Verilated code") + print(" VBlock: Time attributable to a block in a" + " Verilog file and line") + print(" VCommon: Time in a Verilated module," + " due to all parts of the design") + print(" VLib: Time in Verilated common libraries," + " called by the Verilated code") print() print(" % cumulative self ") @@ -156,13 +152,11 @@ def profcfunc(filename): "s type filename and line number") % "design") cume = 0 - for func in sorted(vfuncs.keys(), - key=lambda f: vfuncs[f]['sec'], - reverse=True): + for func in sorted(vfuncs.keys(), key=lambda f: vfuncs[f]['sec'], reverse=True): cume += vfuncs[func]['sec'] print(("%6.2f %9.2f %8.2f %10d %-" + str(design_width) + "s %s") % - (vfuncs[func]['pct'], cume, vfuncs[func]['sec'], - vfuncs[func]['calls'], vfuncs[func]['design'], func)) + (vfuncs[func]['pct'], cume, vfuncs[func]['sec'], vfuncs[func]['calls'], + vfuncs[func]['design'], func)) ###################################################################### @@ -180,18 +174,14 @@ in each Verilog block. For documentation see https://verilator.org/guide/latest/exe_verilator_profcfunc.html""", - epilog= - """Copyright 2002-2024 by Wilson Snyder. This program is free software; you + epilog="""Copyright 2002-2024 by Wilson Snyder. This program is free software; you can redistribute it and/or modify it under the terms of either the GNU Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""") -parser.add_argument('--debug', - action='store_const', - const=9, - help='enable debug') +parser.add_argument('--debug', action='store_const', const=9, help='enable debug') parser.add_argument('filename', help='input gprof output to process') Args = parser.parse_args() diff --git a/docs/bin/vl_sphinx_extract b/docs/bin/vl_sphinx_extract index 6762d7886..75a7585bf 100755 --- a/docs/bin/vl_sphinx_extract +++ b/docs/bin/vl_sphinx_extract @@ -23,9 +23,7 @@ class VlSphinxExtract: outname = match.group(1) print("Writing %s" % outname) fhw = open(outname, "w", encoding="utf8") # pylint: disable=consider-using-with - fhw.write( - ".. comment: generated by vl_sphinx_extract from " + - filename + "\n") + fhw.write(".. comment: generated by vl_sphinx_extract from " + filename + "\n") fhw.write(".. code-block::\n") elif re.match(r'^[=a-zA-Z0-9_]', line): fhw = None @@ -39,18 +37,14 @@ parser = argparse.ArgumentParser( allow_abbrev=False, formatter_class=argparse.RawDescriptionHelpFormatter, description="""Read a file and extract documentation data.""", - epilog= - """ Copyright 2021-2024 by Wilson Snyder. This package is free software; + epilog=""" Copyright 2021-2024 by Wilson Snyder. This package is free software; you can redistribute it and/or modify it under the terms of either the GNU Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""") -parser.add_argument('--debug', - action='store_const', - const=9, - help='enable debug') +parser.add_argument('--debug', action='store_const', const=9, help='enable debug') parser.add_argument('path', help='path to extract from') Args = parser.parse_args() diff --git a/docs/bin/vl_sphinx_fix b/docs/bin/vl_sphinx_fix index 51eda1c4c..d0e607a48 100755 --- a/docs/bin/vl_sphinx_fix +++ b/docs/bin/vl_sphinx_fix @@ -18,8 +18,7 @@ class VlSphinxFix: if os.path.isdir(path): for basefile in os.listdir(path): file = os.path.join(path, basefile) - if ((basefile != ".") and (basefile != "..") - and basefile not in self.SkipBasenames + if ((basefile != ".") and (basefile != "..") and basefile not in self.SkipBasenames and not os.path.islink(file)): self.process(file) elif re.search(r'\.(html|tex)$', path): @@ -54,18 +53,14 @@ parser = argparse.ArgumentParser( allow_abbrev=False, formatter_class=argparse.RawDescriptionHelpFormatter, description="""Post-process Sphinx HTML.""", - epilog= - """ Copyright 2021-2024 by Wilson Snyder. This package is free software; + epilog=""" Copyright 2021-2024 by Wilson Snyder. This package is free software; you can redistribute it and/or modify it under the terms of either the GNU Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""") -parser.add_argument('--debug', - action='store_const', - const=9, - help='enable debug') +parser.add_argument('--debug', action='store_const', const=9, help='enable debug') parser.add_argument('path', help='path to edit') Args = parser.parse_args() diff --git a/docs/guide/conf.py b/docs/guide/conf.py index 12fd0db39..a01718c9e 100644 --- a/docs/guide/conf.py +++ b/docs/guide/conf.py @@ -23,8 +23,7 @@ def get_vlt_version(): filename = "../../Makefile" with open(filename, "r", encoding="utf8") as fh: for line in fh: - match = re.search(r"PACKAGE_VERSION *= *([a-z0-9.]+) +([-0-9]+)", - line) + match = re.search(r"PACKAGE_VERSION *= *([a-z0-9.]+) +([-0-9]+)", line) if match: return match.group(1), match.group(2) match = re.search(r"PACKAGE_VERSION *= *([a-z0-9.]+) +devel", line) @@ -75,8 +74,7 @@ extensions = [] # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. exclude_patterns = [ - '_build', 'Thumbs.db', '.DS_Store', 'internals.rst', 'xml.rst', 'gen/ex_*', - 'CONTRIBUTING.rst' + '_build', 'Thumbs.db', '.DS_Store', 'internals.rst', 'xml.rst', 'gen/ex_*', 'CONTRIBUTING.rst' ] # Warn about refs diff --git a/examples/json_py/vl_file_copy b/examples/json_py/vl_file_copy index 6425ffb33..96b138fa1 100755 --- a/examples/json_py/vl_file_copy +++ b/examples/json_py/vl_file_copy @@ -25,8 +25,7 @@ class VlFileCopy: self.debug = debug - with NamedTemporaryFile() as tree_temp, NamedTemporaryFile( - ) as meta_temp: + with NamedTemporaryFile() as tree_temp, NamedTemporaryFile() as meta_temp: vargs = [ '--json-only-output', tree_temp.name, @@ -61,8 +60,7 @@ class VlFileCopy: print("\t%s " % command) status = subprocess.call(command, shell=True) if status != 0: - raise RuntimeError("Command failed running Verilator with '" + - command + "', stopped") + raise RuntimeError("Command failed running Verilator with '" + command + "', stopped") ####################################################################### @@ -71,8 +69,7 @@ if __name__ == '__main__': parser = argparse.ArgumentParser( allow_abbrev=False, formatter_class=argparse.RawTextHelpFormatter, - description= - """Example of using Verilator JSON output to copy a list of files to an + description="""Example of using Verilator JSON output to copy a list of files to an output directory (-odir, defaults to 'copied'), e.g. to easily create a tarball of the design to pass to others. @@ -95,11 +92,7 @@ This file ONLY is placed under the Creative Commons Public Domain, for any use, without warranty, 2019 by Wilson Snyder. SPDX-License-Identifier: CC0-1.0 """) - parser.add_argument('-debug', - '--debug', - action='store_const', - const=9, - help='enable debug') + parser.add_argument('-debug', '--debug', action='store_const', const=9, help='enable debug') parser.add_argument('-odir', '--odir', action='store', @@ -108,9 +101,7 @@ SPDX-License-Identifier: CC0-1.0 help='target output directory') (args, rem) = parser.parse_known_args() - print( - "NOTE: vl_file_copy is only an example starting point for writing your own tool." - ) + print("NOTE: vl_file_copy is only an example starting point for writing your own tool.") # That is: # 1. We will accept basic patches # 2. We are not expecting to make this globally useful. (e.g. we don't cleanup obj_dir) diff --git a/examples/json_py/vl_hier_graph b/examples/json_py/vl_hier_graph index fd6bfc2e1..6070768b3 100755 --- a/examples/json_py/vl_hier_graph +++ b/examples/json_py/vl_hier_graph @@ -24,8 +24,7 @@ class VlHierGraph: self.next_vertex_number = 0 self.addr_to_number = {} - with NamedTemporaryFile() as tree_temp, NamedTemporaryFile( - ) as meta_temp: + with NamedTemporaryFile() as tree_temp, NamedTemporaryFile() as meta_temp: vargs = [ '--json-only-output', tree_temp.name, @@ -45,9 +44,7 @@ class VlHierGraph: fh.write("digraph {\n") fh.write(" dpi=300;\n") fh.write(" order=LR;\n") - fh.write( - " node [fontsize=8 shape=\"box\" margin=0.01 width=0 height=0]" - ) + fh.write(" node [fontsize=8 shape=\"box\" margin=0.01 width=0 height=0]") fh.write(" edge [fontsize=6]") # Find cells modules = self.flatten(self.tree, lambda n: n['type'] == "MODULE") @@ -101,8 +98,7 @@ class VlHierGraph: print("\t%s " % command) status = subprocess.call(command, shell=True) if status != 0: - raise RuntimeError("Command failed running Verilator with '" + - command + "', stopped") + raise RuntimeError("Command failed running Verilator with '" + command + "', stopped") ####################################################################### @@ -111,8 +107,7 @@ if __name__ == '__main__': parser = argparse.ArgumentParser( allow_abbrev=False, formatter_class=argparse.RawTextHelpFormatter, - description= - """Example of using Verilator JSON output to create a .dot file showing the + description="""Example of using Verilator JSON output to create a .dot file showing the design module hierarchy. Example usage: @@ -134,11 +129,7 @@ This file ONLY is placed under the Creative Commons Public Domain, for any use, without warranty, 2019 by Wilson Snyder. SPDX-License-Identifier: CC0-1.0 """) - parser.add_argument('-debug', - '--debug', - action='store_const', - const=9, - help='enable debug') + parser.add_argument('-debug', '--debug', action='store_const', const=9, help='enable debug') parser.add_argument('-o', '--o', action='store', @@ -147,18 +138,14 @@ SPDX-License-Identifier: CC0-1.0 help='output filename') (args, rem) = parser.parse_known_args() - print( - "NOTE: vl_hier_graph is only an example starting point for writing your own tool." - ) + print("NOTE: vl_hier_graph is only an example starting point for writing your own tool.") # That is: # 1. We will accept basic patches # 2. We are not expecting to make this globally useful. (e.g. we don't cleanup obj_dir) # 3. "make install" will not install this. # 4. This has not had production-worthy validation. - fc = VlHierGraph(output_filename=args.o, - debug=args.debug, - verilator_args=rem) + fc = VlHierGraph(output_filename=args.o, debug=args.debug, verilator_args=rem) ###################################################################### # Local Variables: diff --git a/nodist/clang_check_attributes b/nodist/clang_check_attributes index 5317dc7c3..601a99110 100755 --- a/nodist/clang_check_attributes +++ b/nodist/clang_check_attributes @@ -106,9 +106,8 @@ class VlAnnotations: def is_mt_safe_call(self): return (not self.is_mt_unsafe_call() - and (self.mt_safe or self.mt_safe_postinit or self.pure - or self.requires or self.excludes or self.acquire - or self.release)) + and (self.mt_safe or self.mt_safe_postinit or self.pure or self.requires + or self.excludes or self.acquire or self.release)) def is_pure_call(self): return self.pure @@ -203,9 +202,7 @@ class FunctionInfo: annotations: VlAnnotations ftype: FunctionType - _hash: Optional[int] = dataclasses.field(default=None, - init=False, - repr=False) + _hash: Optional[int] = dataclasses.field(default=None, init=False, repr=False) @property def name(self): @@ -220,15 +217,13 @@ class FunctionInfo: return self._hash def __eq__(self, other): - return (self.usr == other.usr and self.file == other.file - and self.line == other.line) + return (self.usr == other.usr and self.file == other.file and self.line == other.line) def copy(self, /, **changes): return dataclasses.replace(self, **changes) @staticmethod - def from_decl_file_line_and_refd_node(file: str, line: int, - refd: clang.cindex.Cursor, + def from_decl_file_line_and_refd_node(file: str, line: int, refd: clang.cindex.Cursor, annotations: VlAnnotations): file = os.path.abspath(file) refd = refd.canonical @@ -277,14 +272,11 @@ class Diagnostic: source_ctx: FunctionInfo kind: DiagnosticKind - _hash: Optional[int] = dataclasses.field(default=None, - init=False, - repr=False) + _hash: Optional[int] = dataclasses.field(default=None, init=False, repr=False) def __hash__(self): if not self._hash: - self._hash = hash( - hash(self.target) ^ hash(self.source_ctx) ^ hash(self.kind)) + self._hash = hash(hash(self.target) ^ hash(self.source_ctx) ^ hash(self.kind)) return self._hash @@ -292,9 +284,9 @@ class CallAnnotationsValidator: def __init__(self, diagnostic_cb: Callable[[Diagnostic], None], is_ignored_top_level: Callable[[clang.cindex.Cursor], bool], - is_ignored_def: Callable[ - [clang.cindex.Cursor, clang.cindex.Cursor], bool], - is_ignored_call: Callable[[clang.cindex.Cursor], bool]): + is_ignored_def: Callable[[clang.cindex.Cursor, clang.cindex.Cursor], + bool], is_ignored_call: Callable[[clang.cindex.Cursor], + bool]): self._diagnostic_cb = diagnostic_cb self._is_ignored_top_level = is_ignored_top_level self._is_ignored_call = is_ignored_call @@ -329,8 +321,7 @@ class CallAnnotationsValidator: with open(source_file, "r", encoding="utf-8") as file: for line in file: line = line.strip() - match = re.fullmatch( - r"^#\s*(define\s+(\w+)(?:\s+(.*))?|include\s+.*)$", line) + match = re.fullmatch(r"^#\s*(define\s+(\w+)(?:\s+(.*))?|include\s+.*)$", line) if match: if match.group(1).startswith("define"): key = match.group(2) @@ -341,16 +332,14 @@ class CallAnnotationsValidator: return defs @staticmethod - def filter_out_unsupported_compiler_args( - args: list[str]) -> tuple[list[str], dict[str, str]]: + def filter_out_unsupported_compiler_args(args: list[str]) -> tuple[list[str], dict[str, str]]: filtered_args = [] defines = {} args_iter = iter(args) try: while arg := next(args_iter): # Skip positional arguments (input file name). - if not arg.startswith("-") and (arg.endswith(".cpp") - or arg.endswith(".c") + if not arg.startswith("-") and (arg.endswith(".cpp") or arg.endswith(".c") or arg.endswith(".h")): continue @@ -367,8 +356,7 @@ class CallAnnotationsValidator: # Preserved options with separate value argument. if arg in [ "-x" - "-Xclang", "-I", "-isystem", "-iquote", "-include", - "-include-pch" + "-Xclang", "-I", "-isystem", "-iquote", "-include", "-include-pch" ]: filtered_args += [arg, next(args_iter)] continue @@ -406,14 +394,12 @@ class CallAnnotationsValidator: return (filtered_args, defines) - def compile_and_analyze_file(self, source_file: str, - compiler_args: list[str], + def compile_and_analyze_file(self, source_file: str, compiler_args: list[str], build_dir: Optional[str]): filename = os.path.abspath(source_file) initial_cwd = "." - filtered_args, defines = self.filter_out_unsupported_compiler_args( - compiler_args) + filtered_args, defines = self.filter_out_unsupported_compiler_args(compiler_args) defines.update(self.parse_initial_defines(source_file)) if build_dir: @@ -451,8 +437,7 @@ class CallAnnotationsValidator: self._diagnostic_cb(Diagnostic(target, source, source_ctx, kind)) else: self._diagnostic_cb( - Diagnostic(FunctionInfo.from_node(target), source, source_ctx, - kind)) + Diagnostic(FunctionInfo.from_node(target), source, source_ctx, kind)) def iterate_children(self, children: Iterable[clang.cindex.Cursor], handler: Callable[[clang.cindex.Cursor], None]): @@ -465,8 +450,7 @@ class CallAnnotationsValidator: @staticmethod def get_referenced_node_info( node: clang.cindex.Cursor - ) -> tuple[bool, Optional[clang.cindex.Cursor], VlAnnotations, - Iterable[clang.cindex.Cursor]]: + ) -> tuple[bool, Optional[clang.cindex.Cursor], VlAnnotations, Iterable[clang.cindex.Cursor]]: if not node.spelling and not node.displayname: return (False, None, VlAnnotations(), []) @@ -480,8 +464,7 @@ class CallAnnotationsValidator: annotations = VlAnnotations.from_nodes_list(children) return (True, refd, annotations, children) - def check_mt_safe_call(self, node: clang.cindex.Cursor, - refd: clang.cindex.Cursor, + def check_mt_safe_call(self, node: clang.cindex.Cursor, refd: clang.cindex.Cursor, annotations: VlAnnotations): is_mt_safe = False @@ -513,8 +496,7 @@ class CallAnnotationsValidator: # we are calling local method. It is MT safe # only if this method is also only calling local methods or # MT-safe methods - self.iterate_children(refd.get_children(), - self.dispatch_node_inside_definition) + self.iterate_children(refd.get_children(), self.dispatch_node_inside_definition) is_mt_safe = True # class/struct member elif refn and refn.kind == CursorKind.MEMBER_REF_EXPR and refn.referenced: @@ -525,18 +507,15 @@ class CallAnnotationsValidator: if self.is_constructor_context() and refn.semantic_parent: # we are in constructor, so calling local members is MT_SAFE, # make sure object that we are calling is local to the constructor - constructor_class = self._constructor_context[ - -1].semantic_parent + constructor_class = self._constructor_context[-1].semantic_parent if refn.semantic_parent.spelling == constructor_class.spelling: if check_class_member_exists(constructor_class, refn): is_mt_safe = True else: # check if this class inherits from some base class - base_class = get_base_class(constructor_class, - refn.semantic_parent) + base_class = get_base_class(constructor_class, refn.semantic_parent) if base_class: - if check_class_member_exists( - base_class.get_declaration(), refn): + if check_class_member_exists(base_class.get_declaration(), refn): is_mt_safe = True # variable elif refn and refn.kind == CursorKind.DECL_REF_EXPR and refn.referenced: @@ -567,8 +546,7 @@ class CallAnnotationsValidator: # Call handling - def process_method_call(self, node: clang.cindex.Cursor, - refd: clang.cindex.Cursor, + def process_method_call(self, node: clang.cindex.Cursor, refd: clang.cindex.Cursor, annotations: VlAnnotations): assert self._call_location ctx = self._call_location.annotations @@ -576,58 +554,48 @@ class CallAnnotationsValidator: # MT-safe context if ctx.is_mt_safe_context(): if not self.check_mt_safe_call(node, refd, annotations): - self.emit_diagnostic( - FunctionInfo.from_node(refd, refd, annotations), - DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX) + self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations), + DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX) # stable tree context if ctx.is_stabe_tree_context(): if annotations.is_mt_unsafe_call() or not ( - annotations.is_stabe_tree_call() - or annotations.is_pure_call() + annotations.is_stabe_tree_call() or annotations.is_pure_call() or self.check_mt_safe_call(node, refd, annotations)): - self.emit_diagnostic( - FunctionInfo.from_node(refd, refd, annotations), - DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX) + self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations), + DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX) # pure context if ctx.is_pure_context(): if not annotations.is_pure_call(): - self.emit_diagnostic( - FunctionInfo.from_node(refd, refd, annotations), - DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX) + self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations), + DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX) - def process_function_call(self, refd: clang.cindex.Cursor, - annotations: VlAnnotations): + def process_function_call(self, refd: clang.cindex.Cursor, annotations: VlAnnotations): assert self._call_location ctx = self._call_location.annotations # MT-safe context if ctx.is_mt_safe_context(): if not annotations.is_mt_safe_call(): - self.emit_diagnostic( - FunctionInfo.from_node(refd, refd, annotations), - DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX) + self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations), + DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX) # stable tree context if ctx.is_stabe_tree_context(): - if annotations.is_mt_unsafe_call() or not ( - annotations.is_pure_call() - or annotations.is_mt_safe_call() - or annotations.is_stabe_tree_call()): - self.emit_diagnostic( - FunctionInfo.from_node(refd, refd, annotations), - DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX) + if annotations.is_mt_unsafe_call() or not (annotations.is_pure_call() + or annotations.is_mt_safe_call() + or annotations.is_stabe_tree_call()): + self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations), + DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX) # pure context if ctx.is_pure_context(): if not annotations.is_pure_call(): - self.emit_diagnostic( - FunctionInfo.from_node(refd, refd, annotations), - DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX) + self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations), + DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX) - def process_constructor_call(self, refd: clang.cindex.Cursor, - annotations: VlAnnotations): + def process_constructor_call(self, refd: clang.cindex.Cursor, annotations: VlAnnotations): assert self._call_location ctx = self._call_location.annotations @@ -635,31 +603,26 @@ class CallAnnotationsValidator: # only if they call local methods or MT-safe functions. if ctx.is_mt_safe_context() or self.is_constructor_context(): self._constructor_context.append(refd) - self.iterate_children(refd.get_children(), - self.dispatch_node_inside_definition) + self.iterate_children(refd.get_children(), self.dispatch_node_inside_definition) self._constructor_context.pop() # stable tree context if ctx.is_stabe_tree_context(): self._constructor_context.append(refd) - self.iterate_children(refd.get_children(), - self.dispatch_node_inside_definition) + self.iterate_children(refd.get_children(), self.dispatch_node_inside_definition) self._constructor_context.pop() # pure context if ctx.is_pure_context(): - if not annotations.is_pure_call( - ) and not refd.is_default_constructor(): - self.emit_diagnostic( - FunctionInfo.from_node(refd, refd, annotations), - DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX) + if not annotations.is_pure_call() and not refd.is_default_constructor(): + self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations), + DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX) def dispatch_call_node(self, node: clang.cindex.Cursor): [supported, refd, annotations, _] = self.get_referenced_node_info(node) if not supported: - self.iterate_children(node.get_children(), - self.dispatch_node_inside_definition) + self.iterate_children(node.get_children(), self.dispatch_node_inside_definition) return True assert refd is not None @@ -676,19 +639,14 @@ class CallAnnotationsValidator: assert self._call_location is not None node_file = os.path.abspath(node.location.file.name) - self._call_location = self._call_location.copy(file=node_file, - line=node.location.line) + self._call_location = self._call_location.copy(file=node_file, line=node.location.line) # Standalone functions and static class methods if (refd.kind == CursorKind.FUNCTION_DECL - or refd.kind == CursorKind.CXX_METHOD - and refd.is_static_method()): + or refd.kind == CursorKind.CXX_METHOD and refd.is_static_method()): self.process_function_call(refd, annotations) # Function pointer - elif refd.kind in [ - CursorKind.VAR_DECL, CursorKind.FIELD_DECL, - CursorKind.PARM_DECL - ]: + elif refd.kind in [CursorKind.VAR_DECL, CursorKind.FIELD_DECL, CursorKind.PARM_DECL]: self.process_function_call(refd, annotations) # Non-static class methods elif refd.kind == CursorKind.CXX_METHOD: @@ -726,14 +684,13 @@ class CallAnnotationsValidator: if self.dispatch_call_node(node) is False: return None elif node.is_definition() and node.kind in [ - CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL, - CursorKind.CONSTRUCTOR, CursorKind.CONVERSION_FUNCTION + CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL, CursorKind.CONSTRUCTOR, + CursorKind.CONVERSION_FUNCTION ]: self.process_function_definition(node) return None - return self.iterate_children(node.get_children(), - self.dispatch_node_inside_definition) + return self.iterate_children(node.get_children(), self.dispatch_node_inside_definition) def process_function_definition(self, node: clang.cindex.Cursor): [supported, refd, annotations, _] = self.get_referenced_node_info(node) @@ -768,14 +725,12 @@ class CallAnnotationsValidator: self._caller = FunctionInfo.from_node(node, refd, def_annotations) self._call_location = self._caller - self.emit_diagnostic( - FunctionInfo.from_node(refd, refd, annotations), - DiagnosticKind.ANNOTATIONS_DEF_DECL_MISMATCH) + self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations), + DiagnosticKind.ANNOTATIONS_DEF_DECL_MISMATCH) # Use concatenation of definition and declaration annotations # for calls validation. - self._caller = FunctionInfo.from_node(node, refd, - def_annotations | annotations) + self._caller = FunctionInfo.from_node(node, refd, def_annotations | annotations) prev_call_location = self._call_location self._call_location = self._caller @@ -793,8 +748,7 @@ class CallAnnotationsValidator: if declarations: del self._external_decls[usr] - self.iterate_children(node_children, - self.dispatch_node_inside_definition) + self.iterate_children(node_children, self.dispatch_node_inside_definition) self._call_location = prev_call_location self._caller = prev_call_location @@ -805,8 +759,8 @@ class CallAnnotationsValidator: def dispatch_node(self, node: clang.cindex.Cursor): if node.kind in [ - CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL, - CursorKind.CONSTRUCTOR, CursorKind.CONVERSION_FUNCTION + CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL, CursorKind.CONSTRUCTOR, + CursorKind.CONVERSION_FUNCTION ]: if node.is_definition(): return self.process_function_definition(node) @@ -815,14 +769,12 @@ class CallAnnotationsValidator: return self.iterate_children(node.get_children(), self.dispatch_node) - def process_translation_unit( - self, translation_unit: clang.cindex.TranslationUnit): + def process_translation_unit(self, translation_unit: clang.cindex.TranslationUnit): self._level += 1 kv_defines = sorted([f"{k}={v}" for k, v in self._defines.items()]) concat_defines = '\n'.join(kv_defines) # List of headers already processed in a TU with specified set of defines. - tu_processed_headers = self._processed_headers.setdefault( - concat_defines, set()) + tu_processed_headers = self._processed_headers.setdefault(concat_defines, set()) for child in translation_unit.cursor.get_children(): if self._is_ignored_top_level(child): continue @@ -833,10 +785,8 @@ class CallAnnotationsValidator: self.dispatch_node(child) self._level -= 1 - tu_processed_headers.update([ - os.path.abspath(str(hdr.source)) - for hdr in translation_unit.get_includes() - ]) + tu_processed_headers.update( + [os.path.abspath(str(hdr.source)) for hdr in translation_unit.get_includes()]) @dataclass @@ -857,8 +807,7 @@ def get_filter_funcs(verilator_root: str): filename = os.path.abspath(node.location.file.name) return not filename.startswith(verilator_root) - def is_ignored_def(node: clang.cindex.Cursor, - refd: clang.cindex.Cursor) -> bool: + def is_ignored_def(node: clang.cindex.Cursor, refd: clang.cindex.Cursor) -> bool: # __* if str(refd.spelling).startswith("__"): return True @@ -901,8 +850,7 @@ def precompile_header(compile_command: CompileCommand, tmp_dir: str) -> str: os.chdir(compile_command.directory) index = Index.create() - translation_unit = index.parse(compile_command.filename, - compile_command.args) + translation_unit = index.parse(compile_command.filename, compile_command.args) for diag in translation_unit.diagnostics: if diag.severity >= clang.cindex.Diagnostic.Error: errors.append(str(diag)) @@ -910,23 +858,20 @@ def precompile_header(compile_command: CompileCommand, tmp_dir: str) -> str: if len(errors) == 0: pch_file = os.path.join( tmp_dir, - f"{compile_command.refid:02}_{os.path.basename(compile_command.filename)}.pch" - ) + f"{compile_command.refid:02}_{os.path.basename(compile_command.filename)}.pch") translation_unit.save(pch_file) if pch_file: return pch_file - except (TranslationUnitSaveError, TranslationUnitLoadError, - OSError) as exception: + except (TranslationUnitSaveError, TranslationUnitLoadError, OSError) as exception: print(f"%Warning: {exception}", file=sys.stderr) finally: os.chdir(initial_cwd) - print( - f"%Warning: Precompilation failed, skipping: {compile_command.filename}", - file=sys.stderr) + print(f"%Warning: Precompilation failed, skipping: {compile_command.filename}", + file=sys.stderr) for error in errors: print(f" {error}", file=sys.stderr) return "" @@ -934,10 +879,8 @@ def precompile_header(compile_command: CompileCommand, tmp_dir: str) -> str: # Compile and analyze inputs in a single process. def run_analysis(ccl: Iterable[CompileCommand], pccl: Iterable[CompileCommand], - diagnostic_cb: Callable[[Diagnostic], - None], verilator_root: str): - (is_ignored_top_level, is_ignored_def, - is_ignored_call) = get_filter_funcs(verilator_root) + diagnostic_cb: Callable[[Diagnostic], None], verilator_root: str): + (is_ignored_top_level, is_ignored_def, is_ignored_call) = get_filter_funcs(verilator_root) prefix = "verilator_clang_check_attributes_" with tempfile.TemporaryDirectory(prefix=prefix) as tmp_dir: @@ -947,8 +890,8 @@ def run_analysis(ccl: Iterable[CompileCommand], pccl: Iterable[CompileCommand], if pch_file: extra_args += ["-include-pch", pch_file] - cav = CallAnnotationsValidator(diagnostic_cb, is_ignored_top_level, - is_ignored_def, is_ignored_call) + cav = CallAnnotationsValidator(diagnostic_cb, is_ignored_top_level, is_ignored_def, + is_ignored_call) for compile_command in ccl: cav.compile_and_analyze_file(compile_command.filename, extra_args + compile_command.args, @@ -963,12 +906,11 @@ class ParallelAnalysisProcess: @staticmethod def init_data(verilator_root: str, tmp_dir: str): - (is_ignored_top_level, is_ignored_def, - is_ignored_call) = get_filter_funcs(verilator_root) + (is_ignored_top_level, is_ignored_def, is_ignored_call) = get_filter_funcs(verilator_root) ParallelAnalysisProcess.cav = CallAnnotationsValidator( - ParallelAnalysisProcess._diagnostic_handler, is_ignored_top_level, - is_ignored_def, is_ignored_call) + ParallelAnalysisProcess._diagnostic_handler, is_ignored_top_level, is_ignored_def, + is_ignored_call) ParallelAnalysisProcess.tmp_dir = tmp_dir @staticmethod @@ -979,31 +921,27 @@ class ParallelAnalysisProcess: def analyze_cpp_file(compile_command: CompileCommand) -> set[Diagnostic]: ParallelAnalysisProcess.diags = set() assert ParallelAnalysisProcess.cav is not None - ParallelAnalysisProcess.cav.compile_and_analyze_file( - compile_command.filename, compile_command.args, - compile_command.directory) + ParallelAnalysisProcess.cav.compile_and_analyze_file(compile_command.filename, + compile_command.args, + compile_command.directory) return ParallelAnalysisProcess.diags @staticmethod def precompile_header(compile_command: CompileCommand) -> str: - return precompile_header(compile_command, - ParallelAnalysisProcess.tmp_dir) + return precompile_header(compile_command, ParallelAnalysisProcess.tmp_dir) # Compile and analyze inputs in multiple processes. -def run_parallel_analysis(ccl: Iterable[CompileCommand], - pccl: Iterable[CompileCommand], - diagnostic_cb: Callable[[Diagnostic], None], - jobs_count: int, verilator_root: str): +def run_parallel_analysis(ccl: Iterable[CompileCommand], pccl: Iterable[CompileCommand], + diagnostic_cb: Callable[[Diagnostic], + None], jobs_count: int, verilator_root: str): prefix = "verilator_clang_check_attributes_" with tempfile.TemporaryDirectory(prefix=prefix) as tmp_dir: - with multiprocessing.Pool( - processes=jobs_count, - initializer=ParallelAnalysisProcess.init_data, - initargs=[verilator_root, tmp_dir]) as pool: + with multiprocessing.Pool(processes=jobs_count, + initializer=ParallelAnalysisProcess.init_data, + initargs=[verilator_root, tmp_dir]) as pool: extra_args = [] - for pch_file in pool.imap_unordered( - ParallelAnalysisProcess.precompile_header, pccl): + for pch_file in pool.imap_unordered(ParallelAnalysisProcess.precompile_header, pccl): if pch_file: extra_args += ["-include-pch", pch_file] @@ -1011,8 +949,7 @@ def run_parallel_analysis(ccl: Iterable[CompileCommand], for compile_command in ccl: compile_command.args = compile_command.args + extra_args - for diags in pool.imap_unordered( - ParallelAnalysisProcess.analyze_cpp_file, ccl, 1): + for diags in pool.imap_unordered(ParallelAnalysisProcess.analyze_cpp_file, ccl, 1): for diag in diags: diagnostic_cb(diag) @@ -1057,8 +994,7 @@ class TopDownSummaryPrinter(): row_groups: dict[str, list[list[str]]] = {} column_widths = [0, 0] for func in sorted(self._funcs.values(), - key=lambda func: - (func.info.file, func.info.line, func.info.usr)): + key=lambda func: (func.info.file, func.info.line, func.info.usr)): func_info = func.info relfile = os.path.relpath(func_info.file, root_dir) @@ -1082,31 +1018,23 @@ class TopDownSummaryPrinter(): if func.mismatch: mrelfile = os.path.relpath(func.mismatch.file, root_dir) row_group.append([ - f"{mrelfile}:{func.mismatch.line}:", - f"[{func.mismatch.annotations}]", + f"{mrelfile}:{func.mismatch.line}:", f"[{func.mismatch.annotations}]", func.mismatch.name + " [declaration]" ]) - row_group.append([ - f"{relfile}:{func_info.line}:", f"[{func_info.annotations}]", - func_info.name - ]) + row_group.append( + [f"{relfile}:{func_info.line}:", f"[{func_info.annotations}]", func_info.name]) - for callee in sorted(func.calees, - key=lambda func: - (func.file, func.line, func.usr)): + for callee in sorted(func.calees, key=lambda func: (func.file, func.line, func.usr)): crelfile = os.path.relpath(callee.file, root_dir) - row_group.append([ - f"{crelfile}:{callee.line}:", f"[{callee.annotations}]", - " " + callee.name - ]) + row_group.append( + [f"{crelfile}:{callee.line}:", f"[{callee.annotations}]", " " + callee.name]) row_groups[name] = row_group for row in row_group: for row_id, value in enumerate(row[0:-1]): - column_widths[row_id] = max(column_widths[row_id], - len(value)) + column_widths[row_id] = max(column_widths[row_id], len(value)) for label, rows in sorted(row_groups.items(), key=lambda kv: kv[0]): self.begin_group(label) @@ -1114,21 +1042,17 @@ class TopDownSummaryPrinter(): print(f"{row[0]:<{column_widths[0]}} " f"{row[1]:<{column_widths[1]}} " f"{row[2]}") - print( - f"Number of functions reported unsafe: {len(self._unsafe_in_safe)}" - ) + print(f"Number of functions reported unsafe: {len(self._unsafe_in_safe)}") def main(): - default_verilator_root = os.path.abspath( - os.path.join(os.path.dirname(__file__), "..")) + default_verilator_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) parser = argparse.ArgumentParser( allow_abbrev=False, formatter_class=argparse.RawDescriptionHelpFormatter, description="""Check function annotations for correctness""", - epilog= - """Copyright 2022-2024 by Wilson Snyder. Verilator is free software; + epilog="""Copyright 2022-2024 by Wilson Snyder. Verilator is free software; you can redistribute it and/or modify it under the terms of either the GNU Lesser General Public License Version 3 or the Apache License 2.0. SPDX-License-Identifier: LGPL-3.0-only OR Apache-2.0""") @@ -1142,29 +1066,23 @@ def main(): type=int, default=0, help="Number of parallel jobs to use.") - parser.add_argument( - "--compile-commands-dir", - type=str, - default=None, - help="Path to directory containing compile_commands.json.") + parser.add_argument("--compile-commands-dir", + type=str, + default=None, + help="Path to directory containing compile_commands.json.") parser.add_argument("--cxxflags", type=str, default=None, help="Extra flags passed to clang++.") - parser.add_argument( - "--compilation-root", - type=str, - default=os.getcwd(), - help="Directory used as CWD when compiling source files.") - parser.add_argument( - "-c", - "--precompile", - action="append", - help="Header file to be precompiled and cached at the start.") - parser.add_argument("file", + parser.add_argument("--compilation-root", type=str, - nargs="+", - help="Source file to analyze.") + default=os.getcwd(), + help="Directory used as CWD when compiling source files.") + parser.add_argument("-c", + "--precompile", + action="append", + help="Header file to be precompiled and cached at the start.") + parser.add_argument("file", type=str, nargs="+", help="Source file to analyze.") cmdline = parser.parse_args() @@ -1179,8 +1097,7 @@ def main(): compdb: Optional[CompilationDatabase] = None if cmdline.compile_commands_dir: - compdb = CompilationDatabase.fromDirectory( - cmdline.compile_commands_dir) + compdb = CompilationDatabase.fromDirectory(cmdline.compile_commands_dir) if cmdline.cxxflags is not None: common_cxxflags = shlex.split(cmdline.cxxflags) @@ -1230,8 +1147,7 @@ def main(): summary_printer.handle_diagnostic, verilator_root) else: run_parallel_analysis(compile_commands_list, precompile_commands_list, - summary_printer.handle_diagnostic, cmdline.jobs, - verilator_root) + summary_printer.handle_diagnostic, cmdline.jobs, verilator_root) summary_printer.print_summary(verilator_root) diff --git a/nodist/code_coverage b/nodist/code_coverage index 87534b0b7..cdc9483be 100755 --- a/nodist/code_coverage +++ b/nodist/code_coverage @@ -58,15 +58,12 @@ def test(): if not Args.scenarios or re.match('dist', Args.scenarios): run("make examples VERILATOR_NO_OPT_BUILD=1") run("make test_regress VERILATOR_NO_OPT_BUILD=1" + - (" SCENARIOS='" + Args.scenarios + - "'" if Args.scenarios else "") + - (" DRIVER_HASHSET='--hashset=" + Args.hashset + - "'" if Args.hashset else "") + + (" SCENARIOS='" + Args.scenarios + "'" if Args.scenarios else "") + + (" DRIVER_HASHSET='--hashset=" + Args.hashset + "'" if Args.hashset else "") + ('' if Args.stop else ' || true')) else: for test in Args.tests: - if not os.path.exists(test) and os.path.exists( - "test_regress/t/" + test): + if not os.path.exists(test) and os.path.exists("test_regress/t/" + test): test = "test_regress/t/" + test run(test) ci_fold_end() @@ -78,8 +75,7 @@ def test(): os.makedirs(cc_dir, exist_ok=True) os.makedirs(cc_dir + "/info", exist_ok=True) - with subprocess.Popen("find . -print | grep .gcda", - shell=True, + with subprocess.Popen("find . -print | grep .gcda", shell=True, stdout=subprocess.PIPE) as sp: datout = sp.stdout.read() @@ -98,8 +94,7 @@ def test(): del dats[dat] break - with subprocess.Popen("find . -print | grep .gcno", - shell=True, + with subprocess.Popen("find . -print | grep .gcno", shell=True, stdout=subprocess.PIPE) as sp: datout = sp.stdout.read() @@ -116,8 +111,7 @@ def test(): if gbase in gcnos: os.symlink(gcnos[gbase], gcno) else: - print("MISSING .gcno for a .gcda: " + gcno, - file=sys.stderr) + print("MISSING .gcno for a .gcda: " + gcno, file=sys.stderr) ci_fold_end() if Args.stage_enabled[5]: @@ -142,8 +136,7 @@ def test(): if Args.stage_enabled[11]: ci_fold_start("dirs") print("Stage 11: Cleanup paths") - cleanup_abs_paths_info(cc_dir, cc_dir + "/app_total.info", - cc_dir + "/app_total.info") + cleanup_abs_paths_info(cc_dir, cc_dir + "/app_total.info", cc_dir + "/app_total.info") ci_fold_end() if Args.stage_enabled[12]: @@ -164,17 +157,15 @@ def test(): inc = "--include " + inc if exc != '': exc = "--exclude " + exc - run("cd " + cc_dir + " ; " + RealPath + - "/fastcov.py -C app_total.info " + inc + " " + exc + - " -x --lcov -o app_total_f.info") + run("cd " + cc_dir + " ; " + RealPath + "/fastcov.py -C app_total.info " + inc + " " + + exc + " -x --lcov -o app_total_f.info") ci_fold_end() if Args.stage_enabled[17]: ci_fold_start("report") print("Stage 17: Create HTML") run("cd " + cc_dir + " ; genhtml app_total_f.info --demangle-cpp" + - " --rc lcov_branch_coverage=1 --rc genhtml_hi_limit=100 --output-directory html" - ) + " --rc lcov_branch_coverage=1 --rc genhtml_hi_limit=100 --output-directory html") ci_fold_end() if Args.stage_enabled[18]: @@ -186,8 +177,7 @@ def test(): # So, remove gcno files before calling codecov upload_dir = "nodist/obj_dir/upload" os.makedirs(upload_dir, exist_ok=True) - cmd = ("ci/codecov -v upload-process -Z" + " -f " + cc_dir + - "/app_total.info )") + cmd = ("ci/codecov -v upload-process -Z" + " -f " + cc_dir + "/app_total.info )") print("print: Not running:") print(" export CODECOV_TOKEN=") print(" find . -name '*.gcno' -exec rm {} \\;") @@ -198,9 +188,7 @@ def test(): print("*-* All Finished *-*") print("") print("* See report in " + cc_dir + "/html/index.html") - print( - "* Remember to make distclean && ./configure before working on non-coverage" - ) + print("* Remember to make distclean && ./configure before working on non-coverage") def clone_sources(cc_dir): @@ -209,9 +197,8 @@ def clone_sources(cc_dir): for globf in Source_Globs: for infile in glob.glob(globf): if re.match(r'^/', infile): - sys.exit( - "%Error: source globs should be relative not absolute filenames, " - + infile) + sys.exit("%Error: source globs should be relative not absolute filenames, " + + infile) outfile = cc_dir + "/" + infile outpath = re.sub(r'/[^/]*$', '', outfile, count=1) os.makedirs(outpath, exist_ok=True) @@ -252,10 +239,8 @@ def clone_sources(cc_dir): done = True ofh.write(line + "\n") - print("Number of source lines automatically LCOV_EXCL_LINE'ed: %d" % - excluded_lines) - print("Number of source lines automatically LCOV_EXCL_BR_LINE'ed: %d" % - excluded_br_lines) + print("Number of source lines automatically LCOV_EXCL_LINE'ed: %d" % excluded_lines) + print("Number of source lines automatically LCOV_EXCL_BR_LINE'ed: %d" % excluded_br_lines) def cleanup_abs_paths_info(cc_dir, infile, outfile): @@ -263,20 +248,11 @@ def cleanup_abs_paths_info(cc_dir, infile, outfile): with open(infile, "r", encoding="utf8") as fh: for line in fh: if re.search(r'^SF:', line) and not re.search(r'^SF:/usr/', line): - line = re.sub(os.environ['VERILATOR_ROOT'] + '/', - '', - line, - count=1) + line = re.sub(os.environ['VERILATOR_ROOT'] + '/', '', line, count=1) line = re.sub(cc_dir + '/', '', line, count=1) - line = re.sub(r'^SF:.*?/include/', - 'SF:include/', - line, - count=1) + line = re.sub(r'^SF:.*?/include/', 'SF:include/', line, count=1) line = re.sub(r'^SF:.*?/src/', 'SF:src/', line, count=1) - line = re.sub(r'^SF:.*?/test_regress/', - 'SF:test_regress/', - line, - count=1) + line = re.sub(r'^SF:.*?/test_regress/', 'SF:test_regress/', line, count=1) line = re.sub(r'obj_dbg/verilog.y$', 'verilog.y', line) # print("Remaining SF: "+line) lines.append(line) @@ -358,15 +334,13 @@ def ci_fold_end(): parser = argparse.ArgumentParser( allow_abbrev=False, formatter_class=argparse.RawDescriptionHelpFormatter, - description= - """code_coverage builds Verilator with C++ coverage support and runs + description="""code_coverage builds Verilator with C++ coverage support and runs tests with coverage enabled. This will rebuild the current object files. Run as: cd $VERILATOR_ROOT nodist/code_coverage""", - epilog= - """Copyright 2019-2024 by Wilson Snyder. This program is free software; you + epilog="""Copyright 2019-2024 by Wilson Snyder. This program is free software; you can redistribute it and/or modify it under the terms of either the GNU Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. @@ -380,19 +354,16 @@ parser.add_argument('--hashset', parser.add_argument('--scenarios', action='store', help='pass test scenarios onto driver.pl test harness') -parser.add_argument( - '--stages', - '--stage', - action='store', - help='runs a specific stage or range of stages (see the script)') +parser.add_argument('--stages', + '--stage', + action='store', + help='runs a specific stage or range of stages (see the script)') parser.add_argument( '--tests', '--test', action='append', default=[], - help= - 'Instead of normal regressions, run the specified test(s), may be used multiple times' -) + help='Instead of normal regressions, run the specified test(s), may be used multiple times') parser.add_argument('--no-stop', dest='stop', action='store_false', diff --git a/nodist/dot_importer b/nodist/dot_importer index c2a8215fe..33dba831b 100755 --- a/nodist/dot_importer +++ b/nodist/dot_importer @@ -20,8 +20,7 @@ def dotread(filename): vnum = 0 vertex_re = re.compile(r'^\t([a-zA-Z0-9_]+)\t(.*)$') - edge_re = re.compile( - r'^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s*(.*)$') + edge_re = re.compile(r'^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s*(.*)$') for line in fh: vertex_match = re.search(vertex_re, line) @@ -29,11 +28,7 @@ def dotread(filename): if vertex_match: if vertex_match.group(1) != 'nTITLE': header = False - Vertexes.append({ - 'num': vnum, - 'line': line, - 'name': vertex_match.group(1) - }) + Vertexes.append({'num': vnum, 'line': line, 'name': vertex_match.group(1)}) vnum += 1 elif edge_match: fromv = edge_match.group(1) @@ -65,14 +60,13 @@ def cwrite(filename): fh.write("void V3GraphTestImport::dotImport() {\n") fh.write(" auto* gp = &m_graph;\n") for ver in sorted(Vertexes, key=lambda ver: ver['num']): - fh.write( - " auto* %s = new V3GraphTestVertex{gp, \"%s\"}; if (%s) {}\n" - % (ver['name'], ver['name'], ver['name'])) + fh.write(" auto* %s = new V3GraphTestVertex{gp, \"%s\"}; if (%s) {}\n" % + (ver['name'], ver['name'], ver['name'])) fh.write("\n") for edge in Edges: - fh.write(" new V3GraphEdge{gp, %s, %s, %s, %s};\n" % - (edge['from'], edge['to'], edge['weight'], - "true" if edge['cutable'] else "false")) + fh.write( + " new V3GraphEdge{gp, %s, %s, %s, %s};\n" % + (edge['from'], edge['to'], edge['weight'], "true" if edge['cutable'] else "false")) fh.write("}\n") @@ -82,22 +76,17 @@ def cwrite(filename): parser = argparse.ArgumentParser( allow_abbrev=False, formatter_class=argparse.RawDescriptionHelpFormatter, - description= - """dot_importer takes a graphvis .dot file and converts into .cpp file. + description="""dot_importer takes a graphvis .dot file and converts into .cpp file. This x.cpp file is then manually included in V3GraphTest.cpp to verify various xsub-algorithms.""", - epilog= - """Copyright 2005-2024 by Wilson Snyder. This program is free software; you + epilog="""Copyright 2005-2024 by Wilson Snyder. This program is free software; you can redistribute it and/or modify it under the terms of either the GNU Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""") -parser.add_argument('--debug', - action='store_const', - const=9, - help='enable debug') +parser.add_argument('--debug', action='store_const', const=9, help='enable debug') parser.add_argument('filename', help='input .dot filename to process') Args = parser.parse_args() diff --git a/nodist/fuzzer/actual_fail b/nodist/fuzzer/actual_fail index 8a8f2fdc8..9bca018f3 100755 --- a/nodist/fuzzer/actual_fail +++ b/nodist/fuzzer/actual_fail @@ -19,9 +19,12 @@ from argparse import ArgumentParser def interesting(s): - if 'assert' in s: return 1 - if 'Assert' in s: return 1 - if 'Aborted' in s: return 1 + if 'assert' in s: + return 1 + if 'Assert' in s: + return 1 + if 'Aborted' in s: + return 1 if 'terminate' in s: if 'unterminated' in s: return 0 @@ -41,8 +44,7 @@ def main(): for infile in glob(args.dir + '/*'): # Input filenames are known not to contain spaces or other unusual # characters, therefore this works. - status, output = getstatusoutput('../../bin/verilator_bin --cc ' + - infile) + status, output = getstatusoutput('../../bin/verilator_bin --cc ' + infile) if interesting(output): print(infile) print(status) diff --git a/nodist/fuzzer/generate_dictionary b/nodist/fuzzer/generate_dictionary index c03c899ed..d58bd4c73 100755 --- a/nodist/fuzzer/generate_dictionary +++ b/nodist/fuzzer/generate_dictionary @@ -51,9 +51,11 @@ def write_file(filename, contents): def parse_line(s): # str->maybe str - if len(s) == 0: return None + if len(s) == 0: + return None part = skip_while(lambda x: x != '"', s) - if len(part) == 0 or part[0] != '"': return None + if len(part) == 0 or part[0] != '"': + return None literal_part = take_while(lambda x: x != '"', part[1:]) return ''.join(filter(lambda x: x != '\\', literal_part)) diff --git a/nodist/install_test b/nodist/install_test index cfb9afebb..bf15fd796 100755 --- a/nodist/install_test +++ b/nodist/install_test @@ -41,8 +41,7 @@ def test(): run("/bin/mkdir -p " + prefix) run("cd " + blddir + " && make install") run("test -e " + prefix + "/share/man/man1/verilator.1") - run("test -e " + prefix + - "/share/verilator/examples/make_tracing_c/Makefile") + run("test -e " + prefix + "/share/verilator/examples/make_tracing_c/Makefile") run("test -e " + prefix + "/share/verilator/include/verilated.h") run("test -e " + prefix + "/bin/verilator") run("test -e " + prefix + "/bin/verilator_bin") @@ -58,10 +57,8 @@ def test(): run("/bin/mkdir -p " + odir) path = prefix + "/bin" + ":" + prefix + "/share/bin" write_verilog(odir) - run("cd " + odir + " && PATH=" + path + - ":$PATH verilator --cc top.v --exe sim_main.cpp") - run("cd " + odir + "/obj_dir && PATH=" + path + - ":$PATH make -f Vtop.mk") + run("cd " + odir + " && PATH=" + path + ":$PATH verilator --cc top.v --exe sim_main.cpp") + run("cd " + odir + "/obj_dir && PATH=" + path + ":$PATH make -f Vtop.mk") run("cd " + odir + " && PATH=" + path + ":$PATH obj_dir/Vtop") # run a test using exact path to binary @@ -72,8 +69,7 @@ def test(): run("/bin/mkdir -p " + odir) write_verilog(odir) bin1 = prefix + "/bin" - run("cd " + odir + " && " + bin1 + - "/verilator --cc top.v --exe sim_main.cpp") + run("cd " + odir + " && " + bin1 + "/verilator --cc top.v --exe sim_main.cpp") run("cd " + odir + "/obj_dir && make -f Vtop.mk") run("cd " + odir + "/obj_dir && ./Vtop") @@ -88,8 +84,7 @@ def write_verilog(odir): def cleanenv(): for var in os.environ: - if var in ('VERILATOR_ROOT', 'VERILATOR_INCLUDE', - 'VERILATOR_NO_OPT_BUILD'): + if var in ('VERILATOR_ROOT', 'VERILATOR_INCLUDE', 'VERILATOR_NO_OPT_BUILD'): print("unset %s # Was '%s'" % (var, os.environ[var])) del os.environ[var] @@ -113,21 +108,16 @@ def run(command): parser = argparse.ArgumentParser( allow_abbrev=False, formatter_class=argparse.RawDescriptionHelpFormatter, - description= - """install_test performs several make-and-install iterations to verify the + description="""install_test performs several make-and-install iterations to verify the Verilator kit. It isn't part of the normal "make test" due to the number of builds required.""", - epilog= - """Copyright 2009-2024 by Wilson Snyder. This program is free software; you + epilog="""Copyright 2009-2024 by Wilson Snyder. This program is free software; you can redistribute it and/or modify it under the terms of either the GNU Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""") -parser.add_argument('--debug', - action='store_const', - const=9, - help='enable debug') +parser.add_argument('--debug', action='store_const', const=9, help='enable debug') parser.add_argument('--stage', type=int, default=0, diff --git a/nodist/log_changes b/nodist/log_changes index 9a0df69d3..a6ec47276 100755 --- a/nodist/log_changes +++ b/nodist/log_changes @@ -101,8 +101,7 @@ parser = argparse.ArgumentParser( allow_abbrev=False, prog="log_changes", description="Create example entries for 'Changes' from parsing 'git log'", - epilog= - """Copyright 2019-2024 by Wilson Snyder. This program is free software; you + epilog="""Copyright 2019-2024 by Wilson Snyder. This program is free software; you can redistribute it and/or modify it under the terms of either the GNU Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. diff --git a/src/.gdbinit.py b/src/.gdbinit.py index 767f88387..e7090604c 100644 --- a/src/.gdbinit.py +++ b/src/.gdbinit.py @@ -47,9 +47,12 @@ class AstseeCmd(gdb.Command): def _null_check(self, old, new): err = "" - if old == "\n": err += "old == \n" - if new == "\n": err += "new == " - if err: raise gdb.GdbError(err.strip("\n")) + if old == "\n": + err += "old == \n" + if new == "\n": + err += "new == " + if err: + raise gdb.GdbError(err.strip("\n")) def invoke(self, arg_str, from_tty): from astsee import verilator_cli as astsee # pylint: disable=import-error,import-outside-toplevel @@ -58,8 +61,8 @@ class AstseeCmd(gdb.Command): # We hack `astsee_verilator`'s arg parser to find arguments with nodes # After finding them, we replace them with proper files astsee_args = astsee.parser.parse_args(gdb.string_to_argv(arg_str)) - with _vltgdb_tmpfile() as oldfile, _vltgdb_tmpfile( - ) as newfile, _vltgdb_tmpfile() as metafile: + with _vltgdb_tmpfile() as oldfile, _vltgdb_tmpfile() as newfile, _vltgdb_tmpfile( + ) as metafile: if astsee_args.file: _vltgdb_fwrite(oldfile, _vltgdb_get_dump(astsee_args.file)) astsee_args.file = oldfile.name @@ -68,8 +71,7 @@ class AstseeCmd(gdb.Command): astsee_args.newfile = newfile.name if astsee_args.meta is None: # pass - gdb.execute( - f'call AstNode::dumpJsonMetaFileGdb("{metafile.name}")') + gdb.execute(f'call AstNode::dumpJsonMetaFileGdb("{metafile.name}")') astsee_args.meta = metafile.name try: astsee.main(astsee_args) diff --git a/src/astgen b/src/astgen index 942dc6747..70aa3941c 100755 --- a/src/astgen +++ b/src/astgen @@ -89,8 +89,7 @@ class Node: assert not self.isCompleted # Sort sub-classes and convert to tuple, which marks completion self._subClasses = tuple( - sorted(self._subClasses, - key=lambda _: (bool(_._subClasses), _.name))) # pylint: disable=protected-access + sorted(self._subClasses, key=lambda _: (bool(_._subClasses), _.name))) # pylint: disable=protected-access self._ordIdx = ordIdx ordIdx = ordIdx + 1 @@ -128,8 +127,7 @@ class Node: if self.superClass is None: self._allSuperClasses = () else: - self._allSuperClasses = self.superClass.allSuperClasses + ( - self.superClass, ) + self._allSuperClasses = self.superClass.allSuperClasses + (self.superClass, ) return self._allSuperClasses @property @@ -139,9 +137,8 @@ class Node: if self.isLeaf: self._allSubClasses = () else: - self._allSubClasses = self.subClasses + tuple( - _ for subClass in self.subClasses - for _ in subClass.allSubClasses) + self._allSubClasses = self.subClasses + tuple(_ for subClass in self.subClasses + for _ in subClass.allSubClasses) return self._allSubClasses @property @@ -210,8 +207,7 @@ class Cpt: self._exec_syms = {} def error(self, txt): - sys.exit("%%Error: %s:%d: %s" % - (self.in_filename, self.in_linenum, txt)) + sys.exit("%%Error: %s:%d: %s" % (self.in_filename, self.in_linenum, txt)) def print(self, txt): self.out_lines.append(txt) @@ -220,8 +216,7 @@ class Cpt: self.out_lines.append(func) def _output_line(self): - self.print("#line " + str(self.out_linenum + 2) + " \"" + - self.out_filename + "\"\n") + self.print("#line " + str(self.out_linenum + 2) + " \"" + self.out_filename + "\"\n") def process(self, in_filename, out_filename): self.in_filename = in_filename @@ -234,8 +229,7 @@ class Cpt: for line in fhi: ln += 1 if not didln: - self.print("#line " + str(ln) + " \"" + self.in_filename + - "\"\n") + self.print("#line " + str(ln) + " \"" + self.in_filename + "\"\n") didln = True match = re.match(r'^\s+(TREE.*)$', line) if match: @@ -245,8 +239,8 @@ class Cpt: self.output_func(lambda self: self._output_line()) self.tree_line(func) didln = False - elif not re.match(r'^\s*(#define|/[/\*])\s*TREE', - line) and re.search(r'\s+TREE', line): + elif not re.match(r'^\s*(#define|/[/\*])\s*TREE', line) and re.search( + r'\s+TREE', line): self.error("Unknown astgen line: " + line) else: self.print(line) @@ -275,8 +269,7 @@ class Cpt: # 1 2 3 4 r'TREEOP(1?)([ACSV]?)\s*\(\s*\"([^\"]*)\"\s*,\s*\"([^\"]*)\"\s*\)', func) - match_skip = re.search(r'TREE_SKIP_VISIT\s*\(\s*\"([^\"]*)\"\s*\)', - func) + match_skip = re.search(r'TREE_SKIP_VISIT\s*\(\s*\"([^\"]*)\"\s*\)', func) if match: order = match.group(1) @@ -314,20 +307,18 @@ class Cpt: if re.match(r'^\$([a-zA-Z0-9]+)$', subnode): continue # "$lhs" is just a comment that this op has a lhs subnodeif = subnode - subnodeif = re.sub( - r'\$([a-zA-Z0-9]+)\.cast([A-Z][A-Za-z0-9]+)$', - r'VN_IS(nodep->\1(),\2)', subnodeif) - subnodeif = re.sub(r'\$([a-zA-Z0-9]+)\.([a-zA-Z0-9]+)$', - r'nodep->\1()->\2()', subnodeif) + subnodeif = re.sub(r'\$([a-zA-Z0-9]+)\.cast([A-Z][A-Za-z0-9]+)$', + r'VN_IS(nodep->\1(),\2)', subnodeif) + subnodeif = re.sub(r'\$([a-zA-Z0-9]+)\.([a-zA-Z0-9]+)$', r'nodep->\1()->\2()', + subnodeif) subnodeif = self.add_nodep(subnodeif) if mif != "" and subnodeif != "": mif += " && " mif += subnodeif exec_func = self.treeop_exec_func(to) - exec_func = re.sub( - r'([-()a-zA-Z0-9_>]+)->cast([A-Z][A-Za-z0-9]+)\(\)', - r'VN_CAST(\1,\2)', exec_func) + exec_func = re.sub(r'([-()a-zA-Z0-9_>]+)->cast([A-Z][A-Za-z0-9]+)\(\)', + r'VN_CAST(\1,\2)', exec_func) if typen not in self.treeop: self.treeop[typen] = [] @@ -431,14 +422,12 @@ class Cpt: self._exec_nsyms = 0 self._exec_syms_recurse(aref) - for sym in sorted(self._exec_syms.keys(), - key=lambda val: self._exec_syms[val]): + for sym in sorted(self._exec_syms.keys(), key=lambda val: self._exec_syms[val]): argnp = self._exec_syms[sym] arg = self.add_nodep(sym) out += "AstNodeExpr* " + argnp + " = " + arg + "->unlinkFrBack();\n" - out += "AstNodeExpr* newp = " + self._exec_new_recurse( - aref) + ";\n" + out += "AstNodeExpr* newp = " + self._exec_new_recurse(aref) + ";\n" out += "nodep->replaceWith(newp);" out += "VL_DO_DANGLING(nodep->deleteTree(), nodep);" elif func == "NEVER": @@ -454,19 +443,15 @@ class Cpt: self.tree_base() def tree_match(self): - self.print( - " // TREEOP functions, each return true if they matched & transformed\n" - ) + self.print(" // TREEOP functions, each return true if they matched & transformed\n") for base in sorted(self.treeop.keys()): for typefunc in self.treeop[base]: self.print(" // Generated by astgen\n") - self.print(" bool " + typefunc['match_func'] + "(Ast" + - base + "* nodep) {\n") + self.print(" bool " + typefunc['match_func'] + "(Ast" + base + "* nodep) {\n") self.print("\t// " + typefunc['comment'] + "\n") self.print("\tif (" + typefunc['match_if'] + ") {\n") - self.print("\t UINFO(" + str(typefunc['uinfo_level']) + - ", cvtToHex(nodep)" + " << \" " + - typefunc['uinfo'] + "\\n\");\n") + self.print("\t UINFO(" + str(typefunc['uinfo_level']) + ", cvtToHex(nodep)" + + " << \" " + typefunc['uinfo'] + "\\n\");\n") self.print("\t " + typefunc['exec_func'] + "\n") self.print("\t return true;\n") self.print("\t}\n") @@ -475,9 +460,7 @@ class Cpt: def tree_base(self): self.print(" // TREEOP visitors, call each base type's match\n") - self.print( - " // Bottom class up, as more simple transforms are generally better\n" - ) + self.print(" // Bottom class up, as more simple transforms are generally better\n") for node in AstNodeList: out_for_type_sc = [] out_for_type = [] @@ -488,15 +471,11 @@ class Cpt: if base not in self.treeop: continue for typefunc in self.treeop[base]: - lines = [ - " if (" + typefunc['match_func'] + - "(nodep)) return;\n" - ] + lines = [" if (" + typefunc['match_func'] + "(nodep)) return;\n"] if typefunc['short_circuit']: # short-circuit match fn out_for_type_sc.extend(lines) else: # Standard match fn - if typefunc[ - 'order']: # TREEOP1's go in front of others + if typefunc['order']: # TREEOP1's go in front of others out_for_type = lines + out_for_type else: out_for_type.extend(lines) @@ -509,32 +488,26 @@ class Cpt: # For types without short-circuits, we just use iterateChildren, which # saves one comparison. if len(out_for_type_sc) > 0: # Short-circuited types - self.print( - " // Generated by astgen with short-circuiting\n" + - " void visit(Ast" + node.name + - "* nodep) override {\n" + - " iterateAndNextNull(nodep->{op1}());\n".format( - op1=node.getOp(1)[0]) + "".join(out_for_type_sc)) + self.print(" // Generated by astgen with short-circuiting\n" + + " void visit(Ast" + node.name + "* nodep) override {\n" + + " iterateAndNextNull(nodep->{op1}());\n".format( + op1=node.getOp(1)[0]) + "".join(out_for_type_sc)) if out_for_type[0]: self.print( - " iterateAndNextNull(nodep->{op2}());\n".format( - op2=node.getOp(2)[0])) + " iterateAndNextNull(nodep->{op2}());\n".format(op2=node.getOp(2)[0])) if node.isSubClassOf(AstNodes["NodeTriop"]): - self.print( - " iterateAndNextNull(nodep->{op3}());\n". - format(op3=node.getOp(3)[0])) + self.print(" iterateAndNextNull(nodep->{op3}());\n".format( + op3=node.getOp(3)[0])) self.print("".join(out_for_type) + " }\n") elif len(out_for_type) > 0: # Other types with something to print skip = node.name in self.tree_skip_visit gen = "Gen" if skip else "" virtual = "virtual " if skip else "" override = "" if skip else " override" - self.print( - " // Generated by astgen\n" + " " + virtual + - "void visit" + gen + "(Ast" + node.name + "* nodep)" + - override + " {\n" + - ("" if skip else " iterateChildren(nodep);\n") + - ''.join(out_for_type) + " }\n") + self.print(" // Generated by astgen\n" + " " + virtual + "void visit" + gen + + "(Ast" + node.name + "* nodep)" + override + " {\n" + + ("" if skip else " iterateChildren(nodep);\n") + + ''.join(out_for_type) + " }\n") ###################################################################### @@ -565,8 +538,7 @@ def read_types(filename, Nodes, prefix): def error(lineno, message): nonlocal hasErrors - print(filename + ":" + str(lineno) + ": %Error: " + message, - file=sys.stderr) + print(filename + ":" + str(lineno) + ": %Error: " + message, file=sys.stderr) hasErrors = True node = None @@ -579,8 +551,7 @@ def read_types(filename, Nodes, prefix): if not hasAstgenMembers: error( node.lineno, - "'{p}{n}' does not contain 'ASTGEN_MEMBERS_{p}{n};'".format( - p=prefix, n=node.name)) + "'{p}{n}' does not contain 'ASTGEN_MEMBERS_{p}{n};'".format(p=prefix, n=node.name)) hasAstgenMembers = False with open(filename, "r", encoding="utf8") as fh: @@ -598,8 +569,7 @@ def read_types(filename, Nodes, prefix): classn = re.sub(r'^' + prefix, '', classn) supern = re.sub(r'^' + prefix, '', supern) if not supern: - sys.exit("%Error: '{p}{c}' has no super-class".format( - p=prefix, c=classn)) + sys.exit("%Error: '{p}{c}' has no super-class".format(p=prefix, c=classn)) checkFinishedNode(node) superClass = Nodes[supern] node = Node(classn, superClass, filename, lineno) @@ -608,8 +578,7 @@ def read_types(filename, Nodes, prefix): if not node: continue - if re.match(r'^\s*ASTGEN_MEMBERS_' + prefix + node.name + ';', - line): + if re.match(r'^\s*ASTGEN_MEMBERS_' + prefix + node.name + ';', line): hasAstgenMembers = True if prefix != "Ast": @@ -631,36 +600,29 @@ def read_types(filename, Nodes, prefix): ident = ident.strip() if not sep or not re.match(r'^\w+$', ident): error( - lineno, "Malformed '@astgen " + what + - "' directive (expecting '" + what + - " := : ': " + decl) + lineno, "Malformed '@astgen " + what + "' directive (expecting '" + + what + " := : ': " + decl) else: kind = parseOpType(kind) if not kind: error( lineno, "Bad type for '@astgen " + what + - "' (expecting Ast*, Optional[Ast*], or List[Ast*]):" - + decl) + "' (expecting Ast*, Optional[Ast*], or List[Ast*]):" + decl) elif node.getOp(n) is not None: - error( - lineno, "Already defined " + what + " for " + - node.name) + error(lineno, "Already defined " + what + " for " + node.name) else: node.addOp(n, ident, *kind) - elif what in ("alias op1", "alias op2", "alias op3", - "alias op4"): + elif what in ("alias op1", "alias op2", "alias op3", "alias op4"): n = int(what[-1]) ident = rest.strip() if not re.match(r'^\w+$', ident): error( - lineno, "Malformed '@astgen " + what + - "' directive (expecting '" + what + - " := ': " + decl) + lineno, "Malformed '@astgen " + what + "' directive (expecting '" + + what + " := ': " + decl) else: op = node.getOp(n) if op is None: - error(lineno, - "Aliased op" + str(n) + " is not defined") + error(lineno, "Aliased op" + str(n) + " is not defined") else: node.addOp(n, ident, *op[1:]) elif what == "ptr": @@ -670,8 +632,7 @@ def read_types(filename, Nodes, prefix): if not kind: error( lineno, "Bad type for '@astgen " + what + - "' (expecting Ast*, Optional[Ast*], or List[Ast*]):" - + decl) + "' (expecting Ast*, Optional[Ast*], or List[Ast*]):" + decl) if not re.match(r'^m_(\w+)$', ident): error( lineno, "Malformed '@astgen ptr'" @@ -680,20 +641,15 @@ def read_types(filename, Nodes, prefix): node.addPtr(ident, *kind) else: error( - lineno, - "Malformed @astgen what (expecting 'op1'..'op4'," + + lineno, "Malformed @astgen what (expecting 'op1'..'op4'," + " 'alias op1'.., 'ptr'): " + what) else: line = re.sub(r'//.*$', '', line) if re.match(r'.*[Oo]p[1-9].*', line): - error(lineno, - "Use generated accessors to access op operands") + error(lineno, "Use generated accessors to access op operands") - if re.match( - r'^\s*Ast[A-Z][A-Za-z0-9_]+\s*\*(\s*const)?\s+m_[A-Za-z0-9_]+\s*;', - line): - error(lineno, - "Use '@astgen ptr' for Ast pointer members: " + line) + if re.match(r'^\s*Ast[A-Z][A-Za-z0-9_]+\s*\*(\s*const)?\s+m_[A-Za-z0-9_]+\s*;', line): + error(lineno, "Use '@astgen ptr' for Ast pointer members: " + line) checkFinishedNode(node) if hasErrors: @@ -707,33 +663,24 @@ def check_types(sortedTypes, prefix, abstractPrefix): for node in sortedTypes: if re.match(r'^' + abstractPrefix, node.name): if node.isLeaf: - sys.exit( - "%Error: Final {b} subclasses must not be named {b}*: {p}{n}" - .format(b=baseClass, p=prefix, n=node.name)) + sys.exit("%Error: Final {b} subclasses must not be named {b}*: {p}{n}".format( + b=baseClass, p=prefix, n=node.name)) else: if not node.isLeaf: - sys.exit( - "%Error: Non-final {b} subclasses must be named {b}*: {p}{n}" - .format(b=baseClass, p=prefix, n=node.name)) + sys.exit("%Error: Non-final {b} subclasses must be named {b}*: {p}{n}".format( + b=baseClass, p=prefix, n=node.name)) # Check ordering of node definitions hasOrderingError = False - files = tuple( - sorted(set(_.file for _ in sortedTypes if _.file is not None))) + files = tuple(sorted(set(_.file for _ in sortedTypes if _.file is not None))) for file in files: nodes = tuple(filter(lambda _, f=file: _.file == f, sortedTypes)) expectOrder = tuple(sorted(nodes, key=lambda _: (_.isLeaf, _.ordIdx))) actualOrder = tuple(sorted(nodes, key=lambda _: _.lineno)) - expect = { - node: pred - for pred, node in zip((None, ) + expectOrder[:-1], expectOrder) - } - actual = { - node: pred - for pred, node in zip((None, ) + actualOrder[:-1], actualOrder) - } + expect = {node: pred for pred, node in zip((None, ) + expectOrder[:-1], expectOrder)} + actual = {node: pred for pred, node in zip((None, ) + actualOrder[:-1], actualOrder)} for node in nodes: if expect[node] != actual[node]: hasOrderingError = True @@ -749,8 +696,7 @@ def check_types(sortedTypes, prefix, abstractPrefix): file=sys.stderr) if hasOrderingError: - sys.exit( - "%Error: Stopping due to out of order definitions listed above") + sys.exit("%Error: Stopping due to out of order definitions listed above") def read_stages(filename): @@ -783,8 +729,7 @@ def read_refs(filename): if ref not in ClassRefs: ClassRefs[ref] = {'newed': {}, 'used': {}} ClassRefs[ref]['used'][basename] = 1 - for match in re.finditer( - r'(VN_IS|VN_AS|VN_CAST)\([^.]+, ([A-Za-z0-9_]+)', line): + for match in re.finditer(r'(VN_IS|VN_AS|VN_CAST)\([^.]+, ([A-Za-z0-9_]+)', line): ref = "Ast" + match.group(2) if ref not in ClassRefs: ClassRefs[ref] = {'newed': {}, 'used': {}} @@ -796,9 +741,7 @@ def open_file(filename): if re.search(r'\.txt$', filename): fh.write("// Generated by astgen\n") else: - fh.write( - '// Generated by astgen // -*- mode: C++; c-file-style: "cc-mode" -*-' - + "\n") + fh.write('// Generated by astgen // -*- mode: C++; c-file-style: "cc-mode" -*-' + "\n") return fh @@ -808,9 +751,7 @@ def open_file(filename): def write_report(filename): with open_file(filename) as fh: - fh.write( - "Processing stages (approximate, based on order in Verilator.cpp):\n" - ) + fh.write("Processing stages (approximate, based on order in Verilator.cpp):\n") for classn in sorted(Stages.keys(), key=lambda val: Stages[val]): fh.write(" " + classn + "\n") @@ -831,14 +772,12 @@ def write_report(filename): refs = ClassRefs["Ast" + node.name] fh.write(" newed: ") for stage in sorted(refs['newed'].keys(), - key=lambda val: Stages[val] - if (val in Stages) else -1): + key=lambda val: Stages[val] if (val in Stages) else -1): fh.write(stage + " ") fh.write("\n") fh.write(" used: ") for stage in sorted(refs['used'].keys(), - key=lambda val: Stages[val] - if (val in Stages) else -1): + key=lambda val: Stages[val] if (val in Stages) else -1): fh.write(stage + " ") fh.write("\n") fh.write("\n") @@ -852,8 +791,7 @@ def write_report(filename): def write_forward_class_decls(prefix, nodeList): with open_file("V3{p}__gen_forward_class_decls.h".format(p=prefix)) as fh: for node in nodeList: - fh.write("class {p}{n:<17} // ".format(p=prefix, - n=node.name + ";")) + fh.write("class {p}{n:<17} // ".format(p=prefix, n=node.name + ";")) for superClass in node.allSuperClasses: fh.write("{p}{n:<12} ".format(p=prefix, n=superClass.name)) fh.write("\n") @@ -863,8 +801,7 @@ def write_visitor_decls(prefix, nodeList): with open_file("V3{p}__gen_visitor_decls.h".format(p=prefix)) as fh: for node in nodeList: if not node.isRoot: - fh.write("virtual void visit({p}{n}*);\n".format(p=prefix, - n=node.name)) + fh.write("virtual void visit({p}{n}*);\n".format(p=prefix, n=node.name)) def write_visitor_defns(prefix, nodeList, visitor): @@ -873,13 +810,8 @@ def write_visitor_defns(prefix, nodeList, visitor): for node in nodeList: base = node.superClass if base is not None: - fh.write( - "void {c}::visit({p}{n}* {v}) {{ visit(static_cast<{p}{b}*>({v})); }}\n" - .format(c=visitor, - p=prefix, - n=node.name, - b=base.name, - v=variable)) + fh.write("void {c}::visit({p}{n}* {v}) {{ visit(static_cast<{p}{b}*>({v})); }}\n". + format(c=visitor, p=prefix, n=node.name, b=base.name, v=variable)) def write_type_enum(prefix, nodeList): @@ -887,27 +819,21 @@ def write_type_enum(prefix, nodeList): with open_file("V3{p}__gen_type_enum.h".format(p=prefix)) as fh: fh.write(" enum en : uint16_t {\n") - for node in sorted(filter(lambda _: _.isLeaf, nodeList), - key=lambda _: _.typeId): - fh.write(" at{t} = {n},\n".format(t=node.name, - n=node.typeId)) + for node in sorted(filter(lambda _: _.isLeaf, nodeList), key=lambda _: _.typeId): + fh.write(" at{t} = {n},\n".format(t=node.name, n=node.typeId)) fh.write(" _ENUM_END = {n}\n".format(n=root.typeIdMax + 1)) fh.write(" };\n") fh.write(" enum bounds : uint16_t {\n") - for node in sorted(filter(lambda _: not _.isLeaf, nodeList), - key=lambda _: _.typeIdMin): - fh.write(" first{t} = {n},\n".format(t=node.name, - n=node.typeIdMin)) - fh.write(" last{t} = {n},\n".format(t=node.name, - n=node.typeIdMax)) + for node in sorted(filter(lambda _: not _.isLeaf, nodeList), key=lambda _: _.typeIdMin): + fh.write(" first{t} = {n},\n".format(t=node.name, n=node.typeIdMin)) + fh.write(" last{t} = {n},\n".format(t=node.name, n=node.typeIdMax)) fh.write(" _BOUNDS_END\n") fh.write(" };\n") fh.write(" const char* ascii() const VL_MT_SAFE {\n") fh.write(" static const char* const names[_ENUM_END + 1] = {\n") - for node in sorted(filter(lambda _: _.isLeaf, nodeList), - key=lambda _: _.typeId): + for node in sorted(filter(lambda _: _.isLeaf, nodeList), key=lambda _: _.typeId): fh.write(' "{T}",\n'.format(T=node.name.upper())) fh.write(" \"_ENUM_END\"\n") fh.write(" };\n") @@ -928,8 +854,8 @@ def write_type_tests(prefix, nodeList): enum = "VDfgType" for node in nodeList: fh.write( - "template<> inline bool {b}::privateTypeTest<{p}{n}>(const {b}* {v}) {{ " - .format(b=base, p=prefix, n=node.name, v=variable)) + "template<> inline bool {b}::privateTypeTest<{p}{n}>(const {b}* {v}) {{ ".format( + b=base, p=prefix, n=node.name, v=variable)) if node.isRoot: fh.write("return true;") elif not node.isLeaf: @@ -937,8 +863,9 @@ def write_type_tests(prefix, nodeList): "return static_cast({v}->type()) >= static_cast({e}::first{t}) && static_cast({v}->type()) <= static_cast({e}::last{t});" .format(v=variable, e=enum, t=node.name)) else: - fh.write("return {v}->type() == {e}::at{t};".format( - v=variable, e=enum, t=node.name)) + fh.write("return {v}->type() == {e}::at{t};".format(v=variable, + e=enum, + t=node.name)) fh.write(" }\n") @@ -949,8 +876,7 @@ def write_type_tests(prefix, nodeList): def write_ast_type_info(filename): with open_file(filename) as fh: - for node in sorted(filter(lambda _: _.isLeaf, AstNodeList), - key=lambda _: _.typeId): + for node in sorted(filter(lambda _: _.isLeaf, AstNodeList), key=lambda _: _.typeId): opTypeList = [] opNameList = [] for n in range(1, 5): @@ -968,12 +894,11 @@ def write_ast_type_info(filename): opTypeList.append('OP_LIST') opNameList.append(name) # opTypeStr = ', '.join(opTypeList) - opTypeStr = ', '.join( - ['VNTypeInfo::{0}'.format(s) for s in opTypeList]) + opTypeStr = ', '.join(['VNTypeInfo::{0}'.format(s) for s in opTypeList]) opNameStr = ', '.join(['"{0}"'.format(s) for s in opNameList]) fh.write( - ' {{ "Ast{name}", {{{opTypeStr}}}, {{{opNameStr}}}, sizeof(Ast{name}) }},\n' - .format( + ' {{ "Ast{name}", {{{opTypeStr}}}, {{{opNameStr}}}, sizeof(Ast{name}) }},\n'. + format( name=node.name, opTypeStr=opTypeStr, opNameStr=opNameStr, @@ -984,23 +909,19 @@ def write_ast_impl(filename): with open_file(filename) as fh: def emitBlock(pattern, **fmt): - fh.write( - textwrap.indent(textwrap.dedent(pattern), - " ").format(**fmt)) + fh.write(textwrap.indent(textwrap.dedent(pattern), " ").format(**fmt)) for node in AstNodeList: if node.name == "Node": continue - emitBlock("const char* Ast{t}::brokenGen() const {{\n", - t=node.name) + emitBlock("const char* Ast{t}::brokenGen() const {{\n", t=node.name) if node.superClass.name != 'Node': emitBlock(" BROKEN_BASE_RTN(Ast{base}::brokenGen());\n", base=node.superClass.name) for ptr in node.ptrs: if ptr['monad'] == 'Optional': - emitBlock( - " BROKEN_RTN(m_{name} && !m_{name}->brokeExists());\n", - name=ptr['name']) + emitBlock(" BROKEN_RTN(m_{name} && !m_{name}->brokeExists());\n", + name=ptr['name']) else: emitBlock(" BROKEN_RTN(!m_{name});\n" + " BROKEN_RTN(!m_{name}->brokeExists());\n", @@ -1010,8 +931,7 @@ def write_ast_impl(filename): emitBlock("void Ast{t}::cloneRelinkGen() {{\n", t=node.name) if node.superClass.name != 'Node': - emitBlock(" Ast{base}::cloneRelinkGen();\n", - base=node.superClass.name) + emitBlock(" Ast{base}::cloneRelinkGen();\n", base=node.superClass.name) for ptr in node.ptrs: emitBlock( " if (m_{name} && m_{name}->clonep()) m_{name} = m_{name}->clonep();\n", @@ -1020,14 +940,11 @@ def write_ast_impl(filename): emitBlock("}}\n") - emitBlock("void Ast{t}::dumpJsonGen(std::ostream& str) const {{\n", - t=node.name) + emitBlock("void Ast{t}::dumpJsonGen(std::ostream& str) const {{\n", t=node.name) if node.superClass.name != 'Node': - emitBlock(" Ast{base}::dumpJson(str);\n", - base=node.superClass.name) + emitBlock(" Ast{base}::dumpJson(str);\n", base=node.superClass.name) for ptr in node.ptrs: - emitBlock(" dumpJsonPtr(str, \"{name}\", m_{name});\n", - name=ptr['name']) + emitBlock(" dumpJsonPtr(str, \"{name}\", m_{name});\n", name=ptr['name']) emitBlock("}}\n") emitBlock( @@ -1038,9 +955,7 @@ def write_ast_impl(filename): if op is None: continue name, _, _ = op - emitBlock( - " dumpNodeListJson(str, {name}(), \"{name}\", indent);\n", - name=name) + emitBlock(" dumpNodeListJson(str, {name}(), \"{name}\", indent);\n", name=name) emitBlock("}}\n") @@ -1059,9 +974,7 @@ def write_ast_macros(filename): if not any_ptr: fh.write("private: \\\n") any_ptr = True - emitBlock("Ast{kind}* m_{name} = nullptr;", - name=ptr['name'], - kind=ptr['kind']) + emitBlock("Ast{kind}* m_{name} = nullptr;", name=ptr['name'], kind=ptr['kind']) if any_ptr: fh.write("public: \\\n") # TODO pointer accessors @@ -1108,8 +1021,8 @@ def write_ast_macros(filename): if not op: continue name, monad, kind = op - retrieve = ("VN_DBG_AS(op{n}p(), {kind})" if kind != "Node" - else "op{n}p()").format(n=n, kind=kind) + retrieve = ("VN_DBG_AS(op{n}p(), {kind})" + if kind != "Node" else "op{n}p()").format(n=n, kind=kind) superOp = node.superClass.getOp(n) superName = None if superOp: @@ -1126,8 +1039,7 @@ def write_ast_macros(filename): n=n, retrieve=retrieve) if superOp: - hiddenMethods.append("add" + superName[0].upper() + - superName[1:]) + hiddenMethods.append("add" + superName[0].upper() + superName[1:]) elif monad == "Optional": emitBlock('''\ Ast{kind}* {name}() const VL_MT_STABLE {{ return {retrieve}; }} @@ -1150,27 +1062,24 @@ def write_ast_macros(filename): if hiddenMethods: fh.write("private: \\\n") for method in hiddenMethods: - fh.write(" using Ast{sup}::{method}; \\\n".format( - sup=node.superClass.name, method=method)) + fh.write(" using Ast{sup}::{method}; \\\n".format(sup=node.superClass.name, + method=method)) fh.write("public: \\\n") - fh.write( - " static_assert(true, \"\")\n") # Swallowing the semicolon + fh.write(" static_assert(true, \"\")\n") # Swallowing the semicolon # Only care about leaf classes for the rest if node.isLeaf: fh.write( - "#define ASTGEN_SUPER_{t}(...) Ast{b}(VNType::at{t}, __VA_ARGS__)\n" - .format(t=node.name, b=node.superClass.name)) + "#define ASTGEN_SUPER_{t}(...) Ast{b}(VNType::at{t}, __VA_ARGS__)\n".format( + t=node.name, b=node.superClass.name)) fh.write("\n") def write_ast_yystype(filename): with open_file(filename) as fh: for node in AstNodeList: - fh.write("Ast{t}* {m}p;\n".format(t=node.name, - m=node.name[0].lower() + - node.name[1:])) + fh.write("Ast{t}* {m}p;\n".format(t=node.name, m=node.name[0].lower() + node.name[1:])) ################################################################################ @@ -1207,8 +1116,7 @@ def write_dfg_macros(filename): name=name, n=n - 1) - operandNames = tuple( - node.getOp(n)[0] for n in range(1, node.arity + 1)) + operandNames = tuple(node.getOp(n)[0] for n in range(1, node.arity + 1)) if operandNames: emitBlock('''\ const std::string srcName(size_t idx) const override {{ @@ -1217,10 +1125,8 @@ def write_dfg_macros(filename): }} ''', a=node.arity, - ns=", ".join( - map(lambda _: '"' + _ + '"', operandNames))) - fh.write( - " static_assert(true, \"\")\n") # Swallowing the semicolon + ns=", ".join(map(lambda _: '"' + _ + '"', operandNames))) + fh.write(" static_assert(true, \"\")\n") # Swallowing the semicolon def write_dfg_auto_classes(filename): @@ -1254,11 +1160,8 @@ def write_dfg_ast_to_dfg(filename): if (node.file is not None) or (not node.isLeaf): continue - fh.write( - "void visit(Ast{t}* nodep) override {{\n".format(t=node.name)) - fh.write( - ' UASSERT_OBJ(!nodep->user1p(), nodep, "Already has Dfg vertex");\n\n' - ) + fh.write("void visit(Ast{t}* nodep) override {{\n".format(t=node.name)) + fh.write(' UASSERT_OBJ(!nodep->user1p(), nodep, "Already has Dfg vertex");\n\n') fh.write(" if (unhandled(nodep)) return;\n\n") for i in range(node.arity): fh.write(" iterate(nodep->op{j}p());\n".format(j=i + 1)) @@ -1267,9 +1170,8 @@ def write_dfg_ast_to_dfg(filename): ' UASSERT_OBJ(nodep->op{j}p()->user1p(), nodep, "Child {j} missing Dfg vertex");\n' .format(j=i + 1)) fh.write("\n") - fh.write( - " Dfg{t}* const vtxp = makeVertex(nodep, *m_dfgp);\n" - .format(t=node.name)) + fh.write(" Dfg{t}* const vtxp = makeVertex(nodep, *m_dfgp);\n".format( + t=node.name)) fh.write(" if (!vtxp) {\n") fh.write(" m_foundUnhandled = true;\n") fh.write(" ++m_ctx.m_nonRepNode;\n") @@ -1277,8 +1179,8 @@ def write_dfg_ast_to_dfg(filename): fh.write(" }\n\n") for i in range(node.arity): fh.write( - " vtxp->relinkSource<{i}>(nodep->op{j}p()->user1u().to());\n" - .format(i=i, j=i + 1)) + " vtxp->relinkSource<{i}>(nodep->op{j}p()->user1u().to());\n". + format(i=i, j=i + 1)) fh.write("\n") fh.write(" m_uncommittedVertices.push_back(vtxp);\n") fh.write(" nodep->user1p(vtxp);\n") @@ -1292,14 +1194,12 @@ def write_dfg_dfg_to_ast(filename): if (node.file is not None) or (not node.isLeaf): continue - fh.write( - "void visit(Dfg{t}* vtxp) override {{\n".format(t=node.name)) + fh.write("void visit(Dfg{t}* vtxp) override {{\n".format(t=node.name)) for i in range(node.arity): fh.write( " AstNodeExpr* const op{j}p = convertDfgVertexToAstNodeExpr(vtxp->source<{i}>());\n" .format(i=i, j=i + 1)) - fh.write( - " m_resultp = makeNode(vtxp".format(t=node.name)) + fh.write(" m_resultp = makeNode(vtxp".format(t=node.name)) for i in range(node.arity): fh.write(", op{j}p".format(j=i + 1)) fh.write(");\n") @@ -1313,8 +1213,7 @@ parser = argparse.ArgumentParser( allow_abbrev=False, formatter_class=argparse.RawDescriptionHelpFormatter, description="""Generate V3Ast headers to reduce C++ code duplication.""", - epilog= - """Copyright 2002-2024 by Wilson Snyder. This program is free software; you + epilog="""Copyright 2002-2024 by Wilson Snyder. This program is free software; you can redistribute it and/or modify it under the terms of either the GNU Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. @@ -1322,15 +1221,9 @@ Version 2.0. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""") parser.add_argument('-I', action='store', help='source code include directory') -parser.add_argument('--astdef', - action='append', - help='add AST definition file (relative to -I)') -parser.add_argument('--dfgdef', - action='append', - help='add DFG definition file (relative to -I)') -parser.add_argument('--classes', - action='store_true', - help='makes class declaration files') +parser.add_argument('--astdef', action='append', help='add AST definition file (relative to -I)') +parser.add_argument('--dfgdef', action='append', help='add DFG definition file (relative to -I)') +parser.add_argument('--classes', action='store_true', help='makes class declaration files') parser.add_argument('--debug', action='store_true', help='enable debug') parser.add_argument('infiles', nargs='*', help='list of input .cpp filenames') @@ -1409,8 +1302,7 @@ for node in AstNodeList: # Compute derived properties over the whole DfgVertex hierarchy DfgVertices["Vertex"].complete() -DfgVertexList = tuple(map(lambda _: DfgVertices[_], - sorted(DfgVertices.keys()))) +DfgVertexList = tuple(map(lambda _: DfgVertices[_], sorted(DfgVertices.keys()))) check_types(DfgVertexList, "Dfg", "Vertex") @@ -1457,8 +1349,7 @@ for cpt in Args.infiles: if not re.search(r'.cpp$', cpt): sys.exit("%Error: Expected argument to be .cpp file: " + cpt) cpt = re.sub(r'.cpp$', '', cpt) - Cpt().process(in_filename=Args.I + "/" + cpt + ".cpp", - out_filename=cpt + "__gen.cpp") + Cpt().process(in_filename=Args.I + "/" + cpt + ".cpp", out_filename=cpt + "__gen.cpp") ###################################################################### # Local Variables: diff --git a/src/bisonpre b/src/bisonpre index 3f97f0f2c..e684256ea 100755 --- a/src/bisonpre +++ b/src/bisonpre @@ -28,15 +28,13 @@ def process(): + (" -d" if Args.definitions else "") # + (" -k" if Args.token_table else "") # + (" -v" if Args.verbose else "") # - + (" --report=itemset --report=lookahead" if - (Args.verbose and supports_report) else "") + + (" --report=itemset --report=lookahead" if (Args.verbose and supports_report) else "") # Useful but slow: # (" -Wcounterexamples" if # (Args.verbose and supports_counter_examples) else "") # # -p required for GLR parsers; they write to -p basename, not -o - + ((" -p " + Args.name_prefix) if Args.name_prefix else "") + " -b " + - tmp_prefix() # + + ((" -p " + Args.name_prefix) if Args.name_prefix else "") + " -b " + tmp_prefix() # + " -o " + tmp_prefix() + ".c" # + " " + tmp_prefix() + ".y") @@ -44,11 +42,10 @@ def process(): status = subprocess.call(command, shell=True) if status != 0: unlink_outputs() - sys.exit("bisonpre: %Error: " + Args.yacc + " version " + - str(Bison_Version) + " run failed due to errors\n") + sys.exit("bisonpre: %Error: " + Args.yacc + " version " + str(Bison_Version) + + " run failed due to errors\n") - clean_output(tmp_prefix() + ".output", - output_prefix() + ".output", True, False) + clean_output(tmp_prefix() + ".output", output_prefix() + ".output", True, False) warning_check(output_prefix() + ".output") clean_output(tmp_prefix() + ".c", output_prefix() + ".c", False, True) @@ -88,9 +85,7 @@ def unlink_outputs(): def bison_version_check(): - with subprocess.Popen(Args.yacc + " --version", - shell=True, - stdout=subprocess.PIPE) as sp: + with subprocess.Popen(Args.yacc + " --version", shell=True, stdout=subprocess.PIPE) as sp: out = str(sp.stdout.read()) match = re.search(r'([0-9]+\.[0-9]+)', out) if match: @@ -102,8 +97,7 @@ def bison_version_check(): Bison_Version = v return - sys.exit("bisonpre: %Error: '" + Args.yacc + - "' is not installed, or not working\n") + sys.exit("bisonpre: %Error: '" + Args.yacc + "' is not installed, or not working\n") def clean_output(filename, outname, is_output, is_c): @@ -141,8 +135,7 @@ def clean_output(filename, outname, is_output, is_c): if is_c: token_values = {} for line in lines: - if re.search(r'enum\s+yytokentype', - line) and not re.search(r';', line): + if re.search(r'enum\s+yytokentype', line) and not re.search(r';', line): match = re.search(r'\b(\S+) = (\d+)', line) if match: token_values[match.group(2)] = match.group(1) @@ -151,8 +144,7 @@ def clean_output(filename, outname, is_output, is_c): if _enaline(line) and re.search(r'BISONPRE_TOKEN_NAMES', line): out.append(line) for tv in sorted(token_values.keys()): - out.append("\tcase %d: return \"%s\";\n" % - (tv, token_values[tv])) + out.append("\tcase %d: return \"%s\";\n" % (tv, token_values[tv])) continue out.append(line) lines = out @@ -165,8 +157,7 @@ def clean_output(filename, outname, is_output, is_c): # Fix bison 2.3 and GCC 4.2.1 line = re.sub(r'\(YY_\("', '(YY_((char*)"', line) # Fix bison 2.3 glr-parser warning about yyerrorloc.YYTYPE::yydummy uninit - line = re.sub(r'(YYLTYPE yyerrloc;)', - r'\1 yyerrloc.yydummy=0;/*bisonpre*/', line) + line = re.sub(r'(YYLTYPE yyerrloc;)', r'\1 yyerrloc.yydummy=0;/*bisonpre*/', line) # Fix bison 3.6.1 unexpected nested-comment line = re.sub(r'/\* "/\*.*\*/" \*/', '', line) fh.write(line) @@ -177,11 +168,8 @@ def warning_check(filename): linenum = 0 for line in fh: linenum += 1 - if re.search(r'(conflicts|warning:|^useless)', - line, - flags=re.IGNORECASE): - sys.exit("%Error: " + filename + ":" + str(linenum) + ": " + - line + "\n") + if re.search(r'(conflicts|warning:|^useless)', line, flags=re.IGNORECASE): + sys.exit("%Error: " + filename + ":" + str(linenum) + ": " + line + "\n") ###################################################################### @@ -214,12 +202,9 @@ def clean_input(filename, outname): # ^/ to prevent comments from matching if re.match(r'^[a-zA-Z0-9_<>]+:[^/]*[a-zA-Z]', line): sys.exit("%Error: " + filename + ":" + str(lineno) + - ": Move text on rule line to next line: " + line + - "\n") + ": Move text on rule line to next line: " + line + "\n") - matcha = re.match(r'^([a-zA-Z0-9_]+)<(\S*)>(.*)$', - line, - flags=re.DOTALL) + matcha = re.match(r'^([a-zA-Z0-9_]+)<(\S*)>(.*)$', line, flags=re.DOTALL) matchb = re.match(r'^([a-zA-Z0-9_]+):', line) if re.match(r'^%%', line): @@ -231,8 +216,8 @@ def clean_input(filename, outname): dtype = matcha.group(2) line = name + matcha.group(3) if name in Rules: - sys.exit("%Error: " + filename + ":" + str(lineno) + - ": Redeclaring '" + name + "': " + line) + sys.exit("%Error: " + filename + ":" + str(lineno) + ": Redeclaring '" + name + + "': " + line) if dtype not in types: types[dtype] = {} types[dtype][name] = 1 @@ -250,8 +235,8 @@ def clean_input(filename, outname): name = matchb.group(1) if name not in ('public', 'private'): if name in Rules: - sys.exit("%Error: " + filename + ":" + str(lineno) + - ": Redeclaring '" + name + "': " + line) + sys.exit("%Error: " + filename + ":" + str(lineno) + ": Redeclaring '" + + name + "': " + line) Rules[name] = { 'name': name, 'type': "", @@ -268,8 +253,7 @@ def clean_input(filename, outname): cline = re.sub(r'//.*$', '\n', line) if re.match(r'^\s*;', cline): if not last_rule: - sys.exit("%Error: " + filename + ":" + str(lineno) + - ": Stray semicolon\n") + sys.exit("%Error: " + filename + ":" + str(lineno) + ": Stray semicolon\n") last_rule = None elif last_rule: Rules[last_rule]['rules_and_productions'] += cline @@ -279,8 +263,8 @@ def clean_input(filename, outname): dtype = match.group(1) tok = match.group(2) if tok in tokens: - sys.exit("%Error: " + filename + ":" + str(lineno) + - ": Redeclaring '" + tok + "': " + line) + sys.exit("%Error: " + filename + ":" + str(lineno) + ": Redeclaring '" + tok + + "': " + line) tokens[tok] = dtype for tok in re.split(r'[^a-zA-Z0-9_]+', cline): @@ -299,17 +283,16 @@ def clean_input(filename, outname): lineno += 1 if _enaline(line) and re.search(r'BISONPRE_VERSION', line): # 1 2 3 4 - match = re.search( - r'BISONPRE_VERSION\((\S+)\s*,\s*((\S+)\s*,)?\s*([^\),]+)\)\s*$', - line) + match = re.search(r'BISONPRE_VERSION\((\S+)\s*,\s*((\S+)\s*,)?\s*([^\),]+)\)\s*$', + line) if not match: sys.exit("%Error: " + filename + ":" + str(lineno) + ": Bad form of BISONPRE_VERSION: " + line) ver = match.group(1) ver_max = match.group(3) cmd = match.group(4) - if Bison_Version >= float(ver) and ( - not ver_max or Bison_Version <= float(ver_max)): + if Bison_Version >= float(ver) and (not ver_max + or Bison_Version <= float(ver_max)): line = cmd + "\n" else: line = "//NOP: " + line @@ -323,10 +306,9 @@ def clean_input(filename, outname): for line in linesin: lineno += 1 if _enaline(line) and re.search(r'BISONPRE_NOT', line): - match = re.search( - r'(.*)BISONPRE_NOT\((\S+)\)\s*(\{[^}]+})\s*(.*)$', - line, - flags=re.DOTALL) + match = re.search(r'(.*)BISONPRE_NOT\((\S+)\)\s*(\{[^}]+})\s*(.*)$', + line, + flags=re.DOTALL) if not match: sys.exit("%Error: " + filename + ":" + str(lineno) + ": Bad form of BISONPRE_NOT: " + line) @@ -337,8 +319,7 @@ def clean_input(filename, outname): for etok in endtoks: if etok not in tokens: sys.exit("%Error: " + filename + ":" + str(lineno) + - ": Can't find definition for token: " + etok + - "\n") + ": Can't find definition for token: " + etok + "\n") # Push it all onto one line to avoid error messages changing pipe = "" for tok in sorted(tokens.keys()): @@ -397,10 +378,8 @@ def clean_input(filename, outname): # Bison doesn't have a #line directive, so we need somewhere to insert into line = re.sub(r'^\s*//.*$', '', line) if not re.match(r'^\s*$', line): - sys.exit( - "%Error: " + filename + ":" + str(lineno) + ": Need " + - str(needmore) + - " more blank lines to keep line numbers constant\n") + sys.exit("%Error: " + filename + ":" + str(lineno) + ": Need " + + str(needmore) + " more blank lines to keep line numbers constant\n") needmore -= 1 else: lines.append(line) @@ -418,8 +397,8 @@ def _bisonpre_copy(text, lineno, depth): text, flags=re.DOTALL) if not match: - sys.exit("%Error: " + Filename + ":" + str(lineno) + - ": Bad form of BISONPRE_NOT: " + text) + sys.exit("%Error: " + Filename + ":" + str(lineno) + ": Bad form of BISONPRE_NOT: " + + text) text = match.group(1) + '{HERE}' + match.group(5) once = match.group(2) rule = match.group(3) @@ -448,8 +427,7 @@ def _bisonpre_copy(text, lineno, depth): insert = re.sub(left, right, insert) insert = re.sub(r'[ \t\n]+\n', "\n", insert) - insert = re.sub(r'\n', " ", - insert) # Optional - preserve line numbering + insert = re.sub(r'\n', " ", insert) # Optional - preserve line numbering text = re.sub(r'{HERE}', insert, text) depth += 1 return text @@ -465,8 +443,7 @@ def _enaline(line): parser = argparse.ArgumentParser( allow_abbrev=False, formatter_class=argparse.RawDescriptionHelpFormatter, - description= - """Bisonpre is a wrapper for the Bison YACC replacement. Input to Bison is + description="""Bisonpre is a wrapper for the Bison YACC replacement. Input to Bison is preprocessed with substitution as described below under EXTENSIONS. Output from Bison is checked for additional errors, and corrected to work around various compile warnings.""", @@ -522,35 +499,17 @@ parser.add_argument('--yacc', help='name of the bison executable, defaults to "bison"') # Arguments passed through to bison -parser.add_argument('-b', - '--file-prefix', - action='store', - help='Passed to bison.') -parser.add_argument('-d', - '--definitions', - action='store_true', - help='Passed to bison.') -parser.add_argument('-k', - '--token-table', - action='store_true', - help='Passed to bison.') +parser.add_argument('-b', '--file-prefix', action='store', help='Passed to bison.') +parser.add_argument('-d', '--definitions', action='store_true', help='Passed to bison.') +parser.add_argument('-k', '--token-table', action='store_true', help='Passed to bison.') parser.add_argument('-o', '--output', action='store', required=True, help='Passed to bison. Sets output file name') -parser.add_argument('-p', - '--name-prefix', - action='store', - help='Passed to bison.') -parser.add_argument('-t', - '--debug', - action='store_true', - help='Passed to bison.') -parser.add_argument('-v', - '--verbose', - action='store_true', - help='Passed to bison.') +parser.add_argument('-p', '--name-prefix', action='store', help='Passed to bison.') +parser.add_argument('-t', '--debug', action='store_true', help='Passed to bison.') +parser.add_argument('-v', '--verbose', action='store_true', help='Passed to bison.') parser.add_argument('input', help='Passed to bison. Input grammar file.') diff --git a/src/cppcheck_filtered b/src/cppcheck_filtered index b158f724e..894c1aad7 100755 --- a/src/cppcheck_filtered +++ b/src/cppcheck_filtered @@ -115,11 +115,9 @@ def _suppress(filename, linenum, eid): return True if eid == 'constParameter' and re.search(r'gtkwave/', filename): return True - if eid == 'ctuOneDefinitionRuleViolation' and re.search( - r'vltstd/', filename): + if eid == 'ctuOneDefinitionRuleViolation' and re.search(r'vltstd/', filename): return True - if eid == 'duplicateConditionalAssign' and re.search( - r'gtkwave/', filename): + if eid == 'duplicateConditionalAssign' and re.search(r'gtkwave/', filename): return True if eid == 'knownConditionTrueFalse' and re.search(r'gtkwave/', filename): return True @@ -151,8 +149,7 @@ def _suppress(filename, linenum, eid): return True if not os.path.exists(filename): - print("%Warning: " + filename + " does not exist, ignored", - file=sys.stderr) + print("%Warning: " + filename + " does not exist, ignored", file=sys.stderr) return False with open(filename, "r", encoding="utf8") as fh: @@ -160,13 +157,11 @@ def _suppress(filename, linenum, eid): for line in fh: lineno += 1 if (lineno + 1) == linenum: - match = re.search( - r'(cppcheck|cppcheck-has-bug|cppverilator)-suppress((\s+\S+)+)', - line) + match = re.search(r'(cppcheck|cppcheck-has-bug|cppverilator)-suppress((\s+\S+)+)', + line) if match: for supid in match.group(2).split(): - if (supid == eid or (eid in SuppressMap - and supid == SuppressMap[eid])): + if (supid == eid or (eid in SuppressMap and supid == SuppressMap[eid])): return True return False @@ -182,8 +177,7 @@ filters out unnecessary warnings related to Verilator. Run as: cd $VERILATOR_ROOT make -k cppcheck""", - epilog= - """Copyright 2014-2024 by Wilson Snyder. This program is free software; you + epilog="""Copyright 2014-2024 by Wilson Snyder. This program is free software; you can redistribute it and/or modify it under the terms of either the GNU Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. diff --git a/src/flexfix b/src/flexfix index 64f95a385..13abaec70 100755 --- a/src/flexfix +++ b/src/flexfix @@ -16,23 +16,19 @@ import sys for line in sys.stdin: # Fix flex 2.6.1 warning - line = re.sub( - r'for \( i = 0; i < _yybytes_len; \+\+i \)', - r'for ( i = 0; (yy_size_t)(i) < (yy_size_t)(_yybytes_len); ++i )', - line) + line = re.sub(r'for \( i = 0; i < _yybytes_len; \+\+i \)', + r'for ( i = 0; (yy_size_t)(i) < (yy_size_t)(_yybytes_len); ++i )', line) # Fix flex 2.6.0 warning line = re.sub( r'\(\(int\) \(\(yy_n_chars\) \+ number_to_move\) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size\)', r'((int) ((yy_n_chars) + number_to_move) > (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size)', line) - line = re.sub(r' number_to_move == YY_MORE_ADJ ', - r' (int)number_to_move == (int)YY_MORE_ADJ ', line) - # Fix flex 2.5.4 namespace omission - line = re.sub(r'^class istream;', - '#include \nusing namespace std;\n', line) - # Fix flex 2.5.31 redefinition - line = re.sub(r'(\#define\s+yyFlexLexer\s+yyFlexLexer)', r'//flexfix: \1', + line = re.sub(r' number_to_move == YY_MORE_ADJ ', r' (int)number_to_move == (int)YY_MORE_ADJ ', line) + # Fix flex 2.5.4 namespace omission + line = re.sub(r'^class istream;', '#include \nusing namespace std;\n', line) + # Fix flex 2.5.31 redefinition + line = re.sub(r'(\#define\s+yyFlexLexer\s+yyFlexLexer)', r'//flexfix: \1', line) # Fix flex 2.5.1 yytext_ptr undef line = re.sub(r'(\#undef\s+yytext_ptr)', r'//flexfix: \1', line) # Fix flex 2.5.4 and GCC 4.1.0 warn_unused_result @@ -41,8 +37,7 @@ for line in sys.stdin: line = re.sub(r'for \( n = 0; n < max_size && ', r'for ( n = 0; ((size_t)n < (size_t)max_size) && ', line) # Fix flex 2.5.4 and GCC 4.0.2 under FLEX_DEBUG - line = re.sub(r'--accepting rule at line %d ', - r'--accepting rule at line %ld ', line) + line = re.sub(r'--accepting rule at line %d ', r'--accepting rule at line %ld ', line) # Fix compiler warning filenames line = re.sub(r'(#line \d+ ".*)_pretmp', r'\1', line) # Fix 'register' storage class specifier is deprecated and incompatible with C++17 diff --git a/src/vlcovgen b/src/vlcovgen index 960b9c691..819556b6f 100755 --- a/src/vlcovgen +++ b/src/vlcovgen @@ -19,11 +19,9 @@ def read_keys(filename): if re.match(r'^\s*$', line): continue if re.search(r'^\s*VLCOVGEN_ITEM', line): - match = re.search(r'^\s*VLCOVGEN_ITEM *\( *"([^"]+)" *\)', - line) + match = re.search(r'^\s*VLCOVGEN_ITEM *\( *"([^"]+)" *\)', line) if not match: - sys.exit("%Error: " + filename + - ": vlcovgen misformed VLCOVGEN_ITEM line") + sys.exit("%Error: " + filename + ": vlcovgen misformed VLCOVGEN_ITEM line") code = "{" + match.group(1) + "}" data = eval(code) # pprint(data) @@ -59,9 +57,8 @@ def write_keys(filename): deleting = True out.append(line) for keyref in sorted(Items, key=lambda a: a['name']): - out.append( - " if (key == \"%s\") return VL_CIK_%s;\n" % - (keyref['name'], keyref['name'].upper())) + out.append(" if (key == \"%s\") return VL_CIK_%s;\n" % + (keyref['name'], keyref['name'].upper())) elif re.search(r'VLCOVGEN_.*AUTO_EDIT_END', line): deleting = False out.append(line) @@ -80,19 +77,15 @@ def write_keys(filename): parser = argparse.ArgumentParser( allow_abbrev=False, formatter_class=argparse.RawDescriptionHelpFormatter, - description= - """Generate verilated_cov headers to reduce C++ code duplication.""", - epilog= - """Copyright 2002-2024 by Wilson Snyder. This program is free software; you + description="""Generate verilated_cov headers to reduce C++ code duplication.""", + epilog="""Copyright 2002-2024 by Wilson Snyder. This program is free software; you can redistribute it and/or modify it under the terms of either the GNU Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""") -parser.add_argument('--srcdir', - action='store', - help='directory containing Verilator sources') +parser.add_argument('--srcdir', action='store', help='directory containing Verilator sources') parser.set_defaults(srcdir=".") diff --git a/test_regress/t/t_pipe_filter.pf b/test_regress/t/t_pipe_filter.pf index fe52740c7..698d68bef 100755 --- a/test_regress/t/t_pipe_filter.pf +++ b/test_regress/t/t_pipe_filter.pf @@ -42,8 +42,7 @@ for cmd in sys.stdin: if 'example_lint' in line: # We don't have a way to specify this yet, so just for now # sys.stderr.write($line) - prefixes.append("int lint_off_line_" + str(lineno) + - " = 1;\n") + prefixes.append("int lint_off_line_" + str(lineno) + " = 1;\n") lineno += 1 pos = newpos + 1