public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/2] Rewrite make-target-delegates in Python
@ 2022-02-14 19:28 Tom Tromey
  2022-02-14 19:28 ` [PATCH 1/2] Move copyright code from gdbarch.py to new file Tom Tromey
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Tom Tromey @ 2022-02-14 19:28 UTC (permalink / raw)
  To: gdb-patches

This series rewrites make-target-delegates in Python.  Perl is on the
wane a bit and I feel that, as a group, gdb has a bit more Python
expertise.  Also, this lets us share the copyright-generation code,
which is reused both in this series, and in an upcoming series I'll be
sending in the future.

Tested by rebuilding, and by examining the diffs of the generated
files, which are minimal.

Let me know what you think.

Tom



^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] Move copyright code from gdbarch.py to new file
  2022-02-14 19:28 [PATCH 0/2] Rewrite make-target-delegates in Python Tom Tromey
@ 2022-02-14 19:28 ` Tom Tromey
  2022-02-14 19:28 ` [PATCH 2/2] Rewrite make-target-delegates in Python Tom Tromey
  2022-03-02 16:10 ` [PATCH 0/2] " Tom Tromey
  2 siblings, 0 replies; 5+ messages in thread
From: Tom Tromey @ 2022-02-14 19:28 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This moves the copyright code from gdbarch.py to a new Python source
file, gdbcopyright.py.  The function in this file will find the
copyright dates by scanning the calling script.  This will be reused
in a future patch.

This involved minor changes to the output of gdbarch.py.  Also, I've
updated copyright.py to remove the reference to gdbarch.sh.  We don't
need to mention gdbarch.py there, either.
---
 gdb/copyright.py    |  1 -
 gdb/gdbarch-gen.h   |  4 +++-
 gdb/gdbarch.c       |  4 +++-
 gdb/gdbarch.py      | 29 ++++---------------------
 gdb/gdbcopyright.py | 52 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 62 insertions(+), 28 deletions(-)
 create mode 100644 gdb/gdbcopyright.py

diff --git a/gdb/copyright.py b/gdb/copyright.py
index 8ae9ffff65b..48192e80560 100644
--- a/gdb/copyright.py
+++ b/gdb/copyright.py
@@ -245,7 +245,6 @@ BY_HAND = (
 MULTIPLE_COPYRIGHT_HEADERS = (
     "gdb/doc/gdb.texinfo",
     "gdb/doc/refcard.tex",
-    "gdb/gdbarch.sh",
     "gdb/syscalls/update-netbsd.sh",
 )
 
diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h
index d9d81b7d386..b7beb73d36d 100644
--- a/gdb/gdbarch-gen.h
+++ b/gdb/gdbarch-gen.h
@@ -20,7 +20,9 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-/* This file was created with the aid of ``gdbarch.py''.  */
+/* To regenerate this file, run:
+   ./gdbarch.py
+*/
 
 
 
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 3f7a1e35789..55dd602b27f 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -20,7 +20,9 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-/* This file was created with the aid of ``gdbarch.py''.  */
+/* To regenerate this file, run:
+   ./gdbarch.py
+*/
 
 
 /* Maintain the struct gdbarch object.  */
diff --git a/gdb/gdbarch.py b/gdb/gdbarch.py
index 9b538a7d5c6..3bd6400355e 100755
--- a/gdb/gdbarch.py
+++ b/gdb/gdbarch.py
@@ -20,11 +20,11 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import textwrap
+import gdbcopyright
 
 # All the components created in gdbarch-components.py.
 components = []
 
-
 def join_type_and_name(t, n):
     "Combine the type T and the name N into a C declaration."
     if t.endswith("*") or t.endswith("&"):
@@ -161,30 +161,9 @@ class Method(Function):
 with open("gdbarch-components.py") as fd:
     exec(fd.read())
 
-copyright = """/* *INDENT-OFF* */ /* THIS FILE IS GENERATED -*- buffer-read-only: t -*- */
-/* vi:set ro: */
-
-/* Dynamic architecture support for GDB, the GNU debugger.
-
-   Copyright (C) 1998-2022 Free Software Foundation, Inc.
-
-   This file is part of GDB.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-
-/* This file was created with the aid of ``gdbarch.py''.  */
-"""
+copyright = gdbcopyright.copyright(
+    "gdbarch.py", "Dynamic architecture support for GDB, the GNU debugger."
+)
 
 
 def info(c):
diff --git a/gdb/gdbcopyright.py b/gdb/gdbcopyright.py
new file mode 100644
index 00000000000..9526eac4e20
--- /dev/null
+++ b/gdb/gdbcopyright.py
@@ -0,0 +1,52 @@
+# Copyright constant for Python code to use.
+#
+# Copyright (C) 2022 Free Software Foundation, Inc.
+#
+# This file is part of GDB.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+def copyright(tool, description):
+    # Search the tool source itself for the correct copyright years.
+    with open(tool, 'r') as f:
+        for line in f:
+            if line.startswith('# Copyright (C) '):
+                dateline = line[1:].strip()
+                break
+    return f"""/* *INDENT-OFF* */ /* THIS FILE IS GENERATED -*- buffer-read-only: t -*- */
+/* vi:set ro: */
+
+/* {description}
+
+   {dateline}
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* To regenerate this file, run:
+   ./{tool}
+*/
+"""
-- 
2.31.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 2/2] Rewrite make-target-delegates in Python
  2022-02-14 19:28 [PATCH 0/2] Rewrite make-target-delegates in Python Tom Tromey
  2022-02-14 19:28 ` [PATCH 1/2] Move copyright code from gdbarch.py to new file Tom Tromey
@ 2022-02-14 19:28 ` Tom Tromey
  2022-03-02 16:19   ` Pedro Alves
  2022-03-02 16:10 ` [PATCH 0/2] " Tom Tromey
  2 siblings, 1 reply; 5+ messages in thread
From: Tom Tromey @ 2022-02-14 19:28 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

I think gdb is probably better off having fewer languages involved
when generating code.  'sh' is unavoidable for build-time generation,
but for other things, let's use Python.

This rewrites make-target-delegates in Python.  I've stuck pretty
closely to the original code in this rewrite, so it may look slightly
weird from a Python perspective.

The only output difference is that a copyright header is now
generated, using the code introduced in the previous patch.

make-target-delegates.py is simpler to invoke, as it knows the correct
input file to scan and it creates the output file itself.
---
 gdb/make-target-delegates    | 421 -----------------------------------
 gdb/make-target-delegates.py | 340 ++++++++++++++++++++++++++++
 gdb/target-delegates.c       |  26 ++-
 3 files changed, 363 insertions(+), 424 deletions(-)
 delete mode 100755 gdb/make-target-delegates
 create mode 100755 gdb/make-target-delegates.py

diff --git a/gdb/make-target-delegates b/gdb/make-target-delegates
deleted file mode 100755
index f759b5507ca..00000000000
--- a/gdb/make-target-delegates
+++ /dev/null
@@ -1,421 +0,0 @@
-#!/usr/bin/perl
-
-# Copyright (C) 2013-2022 Free Software Foundation, Inc.
-#
-# This file is part of GDB.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-
-# Usage:
-#    make-target-delegates target.h > target-delegates.c
-
-# The line we search for in target.h that marks where we should start
-# looking for methods.
-$TRIGGER = qr,^struct target_ops$,;
-# The end of the methods part.
-$ENDER = qr,^\s*};$,;
-
-# Match a C symbol.
-$SYMBOL = qr,[a-zA-Z_][a-zA-Z0-9_]*,;
-# Match the name part of a method in struct target_ops.
-$NAME_PART = qr,(?<name>${SYMBOL}+)\s,;
-# Match the arguments to a method.
-$ARGS_PART = qr,(?<args>\(.*\)),;
-# We strip the indentation so here we only need the caret.
-$INTRO_PART = qr,^,;
-
-$POINTER_PART = qr,\s*(\*)?\s*,;
-
-# Match a C++ symbol, including scope operators and template
-# parameters.  E.g., 'std::vector<something>'.
-$CP_SYMBOL = qr,[a-zA-Z_][a-zA-Z0-9_<>:]*,;
-# Match the return type when it is "ordinary".
-$SIMPLE_RETURN_PART = qr,((struct|class|enum|union)\s+)?${CP_SYMBOL}+,;
-
-# Match a return type.
-$RETURN_PART = qr,((const|volatile)\s+)?(${SIMPLE_RETURN_PART})${POINTER_PART},;
-
-# Match "virtual".
-$VIRTUAL_PART = qr,virtual\s,;
-
-# Match the TARGET_DEFAULT_* attribute for a method.
-$TARGET_DEFAULT_PART = qr,TARGET_DEFAULT_(?<style>[A-Z_]+)\s*\((?<default_arg>.*)\),;
-
-# Match the arguments and trailing attribute of a method definition.
-# Note we don't match the trailing ";".
-$METHOD_TRAILER = qr,\s*${TARGET_DEFAULT_PART}$,;
-
-# Match an entire method definition.
-$METHOD = ($INTRO_PART . $VIRTUAL_PART . "(?<return_type>" . $RETURN_PART . ")"
-	   . $NAME_PART . $ARGS_PART
-	   . $METHOD_TRAILER);
-
-# Match TARGET_DEBUG_PRINTER in an argument type.
-# This must match the whole "sub-expression" including the parens.
-# Reference $1 must refer to the function argument.
-$TARGET_DEBUG_PRINTER = qr,\s*TARGET_DEBUG_PRINTER\s*\(([^)]*)\)\s*,;
-
-sub trim($) {
-    my ($result) = @_;
-
-    $result =~ s,^\s+,,;
-    $result =~ s,\s+$,,;
-
-    return $result;
-}
-
-# Read from the input files until we find the trigger line.
-# Die if not found.
-sub find_trigger() {
-    while (<>) {
-	chomp;
-	return if m/$TRIGGER/;
-    }
-
-    die "could not find trigger line\n";
-}
-
-# Scan target.h and return a list of possible target_ops method entries.
-sub scan_target_h() {
-    my $all_the_text = '';
-
-    find_trigger();
-    while (<>) {
-	chomp;
-	# Skip the open brace.
-	next if /{/;
-	last if m/$ENDER/;
-
-	# Strip // comments.
-	$_ =~ s,//.*$,,;
-
-	$all_the_text .= $_;
-    }
-
-    # Now strip out the C comments.
-    $all_the_text =~ s,/\*(.*?)\*/,,g;
-
-    # Replace sequences of tabs and/or whitespace with a single
-    # whitespace character.  We need the whitespace because the method
-    # may have been split between multiple lines, like e.g.:
-    #
-    #  virtual std::vector<long_type_name>
-    #    my_long_method_name ()
-    #    TARGET_DEFAULT_IGNORE ();
-    #
-    # If we didn't preserve the whitespace, then we'd end up with:
-    #
-    #  virtual std::vector<long_type_name>my_long_method_name ()TARGET_DEFAULT_IGNORE ()
-    #
-    # ... which wouldn't later be parsed correctly.
-    $all_the_text =~ s/[\t\s]+/ /g;
-
-    return split (/;/, $all_the_text);
-}
-
-# Parse arguments into a list.
-sub parse_argtypes($) {
-    my ($typestr) = @_;
-
-    $typestr =~ s/^\((.*)\)$/\1/;
-
-    my (@typelist) = split (/,\s*/, $typestr);
-    my (@result, $iter, $onetype);
-
-    foreach $iter (@typelist) {
-	if ($iter =~ m/^(enum\s+${SYMBOL}\s*)(${SYMBOL})?$/) {
-	    $onetype = $1;
-	} elsif ($iter =~ m/^(.*(enum\s+)?${SYMBOL}.*(\s|\*|&))${SYMBOL}+$/) {
-	    $onetype = $1;
-	} elsif ($iter eq 'void') {
-	    next;
-	} else {
-	    $onetype = $iter;
-	}
-	push @result, trim ($onetype);
-    }
-
-    return @result;
-}
-
-sub dname($) {
-    my ($name) = @_;
-    return "target_ops::" . $name;
-}
-
-# Write function header given name, return type, and argtypes.
-# Returns a list of actual argument names.
-sub write_function_header($$$@) {
-    my ($decl, $name, $return_type, @argtypes) = @_;
-
-    print $return_type;
-
-    if ($decl) {
-	if ($return_type !~ m,\*$,) {
-	    print " ";
-	}
-    } else {
-	print "\n";
-    }
-
-    print $name . ' (';
-
-    my $iter;
-    my @argdecls;
-    my @actuals;
-    my $i = 0;
-    foreach $iter (@argtypes) {
-	my $val = $iter;
-
-	$val =~ s/$TARGET_DEBUG_PRINTER//;
-
-	if ($iter !~ m,(\*|&)$,) {
-	    $val .= ' ';
-	}
-
-	my $vname;
-	$vname .= "arg$i";
-	$val .= $vname;
-
-	push @argdecls, $val;
-	push @actuals, $vname;
-	++$i;
-    }
-
-    print join (', ', @argdecls) . ")";
-
-    if ($decl) {
-	print " override;\n";
-    } else {
-	print "\n{\n";
-    }
-
-    return @actuals;
-}
-
-# Write out a declaration.
-sub write_declaration($$@) {
-    my ($name, $return_type, @argtypes) = @_;
-
-    write_function_header (1, $name, $return_type, @argtypes);
-}
-
-# Write out a delegation function.
-sub write_delegator($$@) {
-    my ($name, $return_type, @argtypes) = @_;
-
-    my (@names) = write_function_header (0, dname ($name),
-					 $return_type, @argtypes);
-
-    print "  ";
-    if ($return_type ne 'void') {
-	print "return ";
-    }
-    print "this->beneath ()->" . $name . " (";
-    print join (', ', @names);
-    print ");\n";
-    print "}\n\n";
-}
-
-sub tdname ($) {
-    my ($name) = @_;
-    return "dummy_target::" . $name;
-}
-
-# Write out a default function.
-sub write_tdefault($$$$@) {
-    my ($content, $style, $name, $return_type, @argtypes) = @_;
-
-    my (@names) = write_function_header (0, tdname ($name),
-					 $return_type, @argtypes);
-
-    if ($style eq 'FUNC') {
-	print "  ";
-	if ($return_type ne 'void') {
-	    print "return ";
-	}
-	print $content . " (this";
-	if (@names) {
-	    print ", ";
-	}
-	print join (', ', @names);
-	print ");\n";
-    } elsif ($style eq 'RETURN') {
-	print "  return $content;\n";
-    } elsif ($style eq 'NORETURN') {
-	print "  $content;\n";
-    } elsif ($style eq 'IGNORE') {
-	# Nothing.
-    } else {
-	die "unrecognized style: $style\n";
-    }
-
-    print "}\n\n";
-
-    return tdname ($name);
-}
-
-sub munge_type($) {
-    my ($typename) = @_;
-    my ($result);
-
-    if ($typename =~ m/$TARGET_DEBUG_PRINTER/) {
-	$result = $1;
-    } else {
-	($result = $typename) =~ s/\s+$//;
-	$result =~ s/[ ()<>:]/_/g;
-	$result =~ s/[*]/p/g;
-	$result =~ s/&/r/g;
-
-	# Identifers with double underscores are reserved to the C++
-	# implementation.
-	$result =~ s/_+/_/g;
-
-	# Avoid ending the function name with underscore, for
-	# cosmetics.  Trailing underscores appear after munging types
-	# with template parameters, like e.g. "foo<int>".
-	$result =~ s/_$//g;
-
-	$result = 'target_debug_print_' . $result;
-    }
-
-    return $result;
-}
-
-# Write out a debug method.
-sub write_debugmethod($$$@) {
-    my ($content, $name, $return_type, @argtypes) = @_;
-
-    my ($debugname) = "debug_target::" . $name;
-    my ($targetname) = $name;
-
-    my (@names) = write_function_header (0, $debugname, $return_type, @argtypes);
-
-    if ($return_type ne 'void') {
-	print "  $return_type result;\n";
-    }
-
-    print "  fprintf_unfiltered (gdb_stdlog, \"-> %s->$name (...)\\n\", this->beneath ()->shortname ());\n";
-
-    # Delegate to the beneath target.
-    print "  ";
-    if ($return_type ne 'void') {
-	print "result = ";
-    }
-    print "this->beneath ()->" . $name . " (";
-    print join (', ', @names);
-    print ");\n";
-
-    # Now print the arguments.
-    print "  fprintf_unfiltered (gdb_stdlog, \"<- %s->$name (\", this->beneath ()->shortname ());\n";
-    for my $i (0 .. $#argtypes) {
-	if ($i > 0) {
-	    print "  fputs_unfiltered (\", \", gdb_stdlog);\n"
-	}
-	my $printer = munge_type ($argtypes[$i]);
-	print "  $printer ($names[$i]);\n";
-    }
-    if ($return_type ne 'void') {
-	print "  fputs_unfiltered (\") = \", gdb_stdlog);\n";
-	my $printer = munge_type ($return_type);
-	print "  $printer (result);\n";
-	print "  fputs_unfiltered (\"\\n\", gdb_stdlog);\n";
-    } else {
-	print "  fputs_unfiltered (\")\\n\", gdb_stdlog);\n";
-    }
-
-    if ($return_type ne 'void') {
-	print "  return result;\n";
-    }
-
-    print "}\n\n";
-
-    return $debugname;
-}
-
-print "/* THIS FILE IS GENERATED -*- buffer-read-only: t -*- */\n";
-print "/* vi:set ro: */\n\n";
-print "/* To regenerate this file, run:*/\n";
-print "/*      make-target-delegates target.h > target-delegates.c */\n";
-print "\n";
-
-@lines = scan_target_h();
-
-@delegators = ();
-@return_types = ();
-@tdefaults = ();
-@styles = ();
-@argtypes_array = ();
-
-foreach $current_line (@lines) {
-    # See comments in scan_target_h.  Here we strip away the leading
-    # and trailing whitespace.
-    $current_line = trim ($current_line);
-
-    next unless $current_line =~ m/$METHOD/;
-
-    my $name = $+{name};
-    my $current_line = $+{args};
-    my $return_type = trim ($+{return_type});
-    my $current_args = $+{args};
-    my $tdefault = $+{default_arg};
-    my $style = $+{style};
-
-    my @argtypes = parse_argtypes ($current_args);
-
-    push @delegators, $name;
-
-    $return_types{$name} = $return_type;
-    $tdefaults{$name} = $tdefault;
-    $styles{$name} = $style;
-    $argtypes_array{$name} = \@argtypes;
-}
-
-sub print_class($) {
-    my ($name) = @_;
-
-    print "struct " . $name . " : public target_ops\n";
-    print "{\n";
-    print "  const target_info &info () const override;\n";
-    print "\n";
-    print "  strata stratum () const override;\n";
-    print "\n";
-
-    for $name (@delegators) {
-	my $return_type = $return_types{$name};
-	my @argtypes = @{$argtypes_array{$name}};
-
-	print "  ";
-	write_declaration ($name, $return_type, @argtypes);
-    }
-
-    print "};\n\n";
-}
-
-print_class ("dummy_target");
-print_class ("debug_target");
-
-for $name (@delegators) {
-    my $tdefault = $tdefaults{$name};
-    my $return_type = $return_types{$name};
-    my $style = $styles{$name};
-    my @argtypes = @{$argtypes_array{$name}};
-
-    write_delegator ($name, $return_type, @argtypes);
-
-    write_tdefault ($tdefault, $style, $name, $return_type, @argtypes);
-
-    write_debugmethod ($tdefault, $name, $return_type, @argtypes);
-}
diff --git a/gdb/make-target-delegates.py b/gdb/make-target-delegates.py
new file mode 100755
index 00000000000..97178072a37
--- /dev/null
+++ b/gdb/make-target-delegates.py
@@ -0,0 +1,340 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2013-2022 Free Software Foundation, Inc.
+#
+# This file is part of GDB.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Usage:
+#    make-target-delegates.py
+
+import re
+import gdbcopyright
+
+
+# The line we search for in target.h that marks where we should start
+# looking for methods.
+TRIGGER = re.compile(r"^struct target_ops$")
+# The end of the methods part.
+ENDER = re.compile(r"^\s*};$")
+
+# Match a C symbol.
+SYMBOL = "[a-zA-Z_][a-zA-Z0-9_]*"
+# Match the name part of a method in struct target_ops.
+NAME_PART = r"(?P<name>" + SYMBOL + ")\s"
+# Match the arguments to a method.
+ARGS_PART = r"(?P<args>\(.*\))"
+# We strip the indentation so here we only need the caret.
+INTRO_PART = r"^"
+
+POINTER_PART = r"\s*(\*)?\s*"
+
+# Match a C++ symbol, including scope operators and template
+# parameters.  E.g., 'std::vector<something>'.
+CP_SYMBOL = r"[a-zA-Z_][a-zA-Z0-9_<>:]*"
+# Match the return type when it is "ordinary".
+SIMPLE_RETURN_PART = r"((struct|class|enum|union)\s+)?" + CP_SYMBOL
+
+# Match a return type.
+RETURN_PART = r"((const|volatile)\s+)?(" + SIMPLE_RETURN_PART + ")" + POINTER_PART
+
+# Match "virtual".
+VIRTUAL_PART = r"virtual\s"
+
+# Match the TARGET_DEFAULT_* attribute for a method.
+TARGET_DEFAULT_PART = r"TARGET_DEFAULT_(?P<style>[A-Z_]+)\s*\((?P<default_arg>.*)\)"
+
+# Match the arguments and trailing attribute of a method definition.
+# Note we don't match the trailing ";".
+METHOD_TRAILER = r"\s*" + TARGET_DEFAULT_PART + "$"
+
+# Match an entire method definition.
+METHOD = re.compile(
+    INTRO_PART
+    + VIRTUAL_PART
+    + "(?P<return_type>"
+    + RETURN_PART
+    + ")"
+    + NAME_PART
+    + ARGS_PART
+    + METHOD_TRAILER
+)
+
+# Regular expression used to dissect argument types.
+ARGTYPES = re.compile(
+    "^("
+    + r"(?P<E>enum\s+"
+    + SYMBOL
+    + r"\s*)("
+    + SYMBOL
+    + ")?"
+    + r"|(?P<T>.*(enum\s+)?"
+    + SYMBOL
+    + r".*(\s|\*|&))"
+    + SYMBOL
+    + ")$"
+)
+
+# Match TARGET_DEBUG_PRINTER in an argument type.
+# This must match the whole "sub-expression" including the parens.
+TARGET_DEBUG_PRINTER = r"\s*TARGET_DEBUG_PRINTER\s*\((?P<arg>[^)]*)\)\s*"
+
+
+def scan_target_h():
+    found_trigger = False
+    all_the_text = ""
+    with open("target.h", "r") as target_h:
+        for line in target_h:
+            line = line.strip()
+            if not found_trigger:
+                if TRIGGER.match(line):
+                    found_trigger = True
+            elif "{" in line:
+                # Skip the open brace.
+                pass
+            elif ENDER.match(line):
+                break
+            else:
+                # Strip // comments.
+                line = re.split("//", line)[0]
+                all_the_text = all_the_text + " " + line
+    if not found_trigger:
+        raise "Could not find trigger line"
+    # Now strip out the C comments.
+    all_the_text = re.sub(r"/\*(.*?)\*/", "", all_the_text)
+    # Replace sequences whitespace with a single space character.
+    # We need the space because the method may have been split
+    # between multiple lines, like e.g.:
+    #
+    #  virtual std::vector<long_type_name>
+    #    my_long_method_name ()
+    #    TARGET_DEFAULT_IGNORE ();
+    #
+    # If we didn't preserve the space, then we'd end up with:
+    #
+    #  virtual std::vector<long_type_name>my_long_method_name ()TARGET_DEFAULT_IGNORE ()
+    #
+    # ... which wouldn't later be parsed correctly.
+    all_the_text = re.sub(r"\s+", " ", all_the_text)
+    return all_the_text.split(";")
+
+
+# Parse arguments into a list.
+def parse_argtypes(typestr):
+    # Remove the outer parens.
+    typestr = re.sub(r"^\((.*)\)$", r"\1", typestr)
+    result = []
+    for item in re.split(r",\s*", typestr):
+        if item == "void" or item == "":
+            continue
+        m = ARGTYPES.match(item)
+        if m:
+            if m.group("E"):
+                onetype = m.group("E")
+            else:
+                onetype = m.group("T")
+        else:
+            onetype = item
+        result.append(onetype.strip())
+    return result
+
+
+# Write function header given name, return type, and argtypes.
+# Returns a list of actual argument names.
+def write_function_header(f, decl, name, return_type, argtypes):
+    print(return_type, file=f, end="")
+    if decl:
+        if not return_type.endswith("*"):
+            print(" ", file=f, end="")
+    else:
+        print("", file=f)
+    print(name + " (", file=f, end="")
+    argdecls = []
+    actuals = []
+    for i in range(len(argtypes)):
+        val = re.sub(TARGET_DEBUG_PRINTER, "", argtypes[i])
+        if not val.endswith("*") and not val.endswith("&"):
+            val = val + " "
+        vname = "arg" + str(i)
+        val = val + vname
+        argdecls.append(val)
+        actuals.append(vname)
+    print(", ".join(argdecls) + ")", file=f, end="")
+    if decl:
+        print(" override;", file=f)
+    else:
+        print("\n{", file=f)
+    return actuals
+
+
+# Write out a declaration.
+def write_declaration(f, name, return_type, argtypes):
+    write_function_header(f, True, name, return_type, argtypes)
+
+
+# Write out a delegation function.
+def write_delegator(f, name, return_type, argtypes):
+    names = write_function_header(
+        f, False, "target_ops::" + name, return_type, argtypes
+    )
+    print("  ", file=f, end="")
+    if return_type != "void":
+        print("return ", file=f, end="")
+    print("this->beneath ()->" + name + " (", file=f, end="")
+    print(", ".join(names), file=f, end="")
+    print(");", file=f)
+    print("}\n", file=f)
+
+
+# Write out a default function.
+def write_tdefault(f, content, style, name, return_type, argtypes):
+    name = "dummy_target::" + name
+    names = write_function_header(f, False, name, return_type, argtypes)
+    if style == "FUNC":
+        print("  ", file=f, end="")
+        if return_type != "void":
+            print("return ", file=f, end="")
+        print(content + " (", file=f, end="")
+        names.insert(0, "this")
+        print(", ".join(names) + ");", file=f)
+    elif style == "RETURN":
+        print("  return " + content + ";", file=f)
+    elif style == "NORETURN":
+        print("  " + content + ";", file=f)
+    elif style == "IGNORE":
+        # Nothing.
+        pass
+    else:
+        raise "unrecognized style: " + style
+    print("}\n", file=f)
+
+
+def munge_type(typename):
+    m = re.search(TARGET_DEBUG_PRINTER, typename)
+    if m:
+        return m.group("arg")
+    typename = typename.rstrip()
+    typename = re.sub("[ ()<>:]", "_", typename)
+    typename = re.sub("[*]", "p", typename)
+    typename = re.sub("&", "r", typename)
+    # Identifers with double underscores are reserved to the C++
+    # implementation.
+    typename = re.sub("_+", "_", typename)
+    # Avoid ending the function name with underscore, for
+    # cosmetics.  Trailing underscores appear after munging types
+    # with template parameters, like e.g. "foo<int>".
+    typename = re.sub("_+$", "", typename)
+    return "target_debug_print_" + typename
+
+
+# Write out a debug method.
+def write_debugmethod(f, content, name, return_type, argtypes):
+    debugname = "debug_target::" + name
+    names = write_function_header(f, False, debugname, return_type, argtypes)
+    if return_type != "void":
+        print("  " + return_type + " result;", file=f)
+    print(
+        '  fprintf_unfiltered (gdb_stdlog, "-> %s->'
+        + name
+        + ' (...)\\n", this->beneath ()->shortname ());',
+        file=f,
+    )
+
+    # Delegate to the beneath target.
+    print("  ", file=f, end="")
+    if return_type != "void":
+        print("result = ", file=f, end="")
+    print("this->beneath ()->" + name + " (", file=f, end="")
+    print(", ".join(names), file=f, end="")
+    print(");", file=f)
+
+    # Now print the arguments.
+    print(
+        '  fprintf_unfiltered (gdb_stdlog, "<- %s->'
+        + name
+        + ' (", this->beneath ()->shortname ());',
+        file=f,
+    )
+    for i in range(len(argtypes)):
+        if i > 0:
+            print('  fputs_unfiltered (", ", gdb_stdlog);', file=f)
+        printer = munge_type(argtypes[i])
+        print("  " + printer + " (" + names[i] + ");", file=f)
+    if return_type != "void":
+        print('  fputs_unfiltered (") = ", gdb_stdlog);', file=f)
+        printer = munge_type(return_type)
+        print("  " + printer + " (result);", file=f)
+        print('  fputs_unfiltered ("\\n", gdb_stdlog);', file=f)
+    else:
+        print('  fputs_unfiltered (")\\n", gdb_stdlog);', file=f)
+
+    if return_type != "void":
+        print("  return result;", file=f)
+
+    print("}\n", file=f)
+
+
+def print_class(f, class_name, delegators, entries):
+    print("struct " + class_name + " : public target_ops", file=f)
+    print("{", file=f)
+    print("  const target_info &info () const override;", file=f)
+    print("", file=f)
+    print("  strata stratum () const override;", file=f)
+    print("", file=f)
+
+    for name in delegators:
+        return_type = entries[name]["return_type"]
+        argtypes = entries[name]["argtypes"]
+        print("  ", file=f, end="")
+        write_declaration(f, name, return_type, argtypes)
+
+    print("};\n", file=f)
+
+
+delegators = []
+entries = {}
+for current_line in scan_target_h():
+    # See comments in scan_target_h.  Here we strip away the leading
+    # and trailing whitespace.
+    current_line = current_line.strip()
+    m = METHOD.match(current_line)
+    if not m:
+        continue
+    data = m.groupdict()
+    data["argtypes"] = parse_argtypes(data["args"])
+    data["return_type"] = data["return_type"].strip()
+    entries[data["name"]] = data
+
+    delegators.append(data["name"])
+
+with open("target-delegates.c", "w") as f:
+    print(
+        gdbcopyright.copyright(
+            "make-target-delegates.py", "Boilerplate target methods for GDB"
+        ),
+        file=f,
+    )
+    print_class(f, "dummy_target", delegators, entries)
+    print_class(f, "debug_target", delegators, entries)
+
+    for name in delegators:
+        tdefault = entries[name]["default_arg"]
+        return_type = entries[name]["return_type"]
+        style = entries[name]["style"]
+        argtypes = entries[name]["argtypes"]
+
+        write_delegator(f, name, return_type, argtypes)
+        write_tdefault(f, tdefault, style, name, return_type, argtypes)
+        write_debugmethod(f, tdefault, name, return_type, argtypes)
diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c
index ca1734f86ba..fd01b640f7c 100644
--- a/gdb/target-delegates.c
+++ b/gdb/target-delegates.c
@@ -1,8 +1,28 @@
-/* THIS FILE IS GENERATED -*- buffer-read-only: t -*- */
+/* *INDENT-OFF* */ /* THIS FILE IS GENERATED -*- buffer-read-only: t -*- */
 /* vi:set ro: */
 
-/* To regenerate this file, run:*/
-/*      make-target-delegates target.h > target-delegates.c */
+/* Boilerplate target methods for GDB
+
+   Copyright (C) 2013-2022 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* To regenerate this file, run:
+   ./make-target-delegates.py
+*/
 
 struct dummy_target : public target_ops
 {
-- 
2.31.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/2] Rewrite make-target-delegates in Python
  2022-02-14 19:28 [PATCH 0/2] Rewrite make-target-delegates in Python Tom Tromey
  2022-02-14 19:28 ` [PATCH 1/2] Move copyright code from gdbarch.py to new file Tom Tromey
  2022-02-14 19:28 ` [PATCH 2/2] Rewrite make-target-delegates in Python Tom Tromey
@ 2022-03-02 16:10 ` Tom Tromey
  2 siblings, 0 replies; 5+ messages in thread
From: Tom Tromey @ 2022-03-02 16:10 UTC (permalink / raw)
  To: Tom Tromey via Gdb-patches; +Cc: Tom Tromey

>>>>> "Tom" == Tom Tromey via Gdb-patches <gdb-patches@sourceware.org> writes:

Tom> This series rewrites make-target-delegates in Python.  Perl is on the
Tom> wane a bit and I feel that, as a group, gdb has a bit more Python
Tom> expertise.  Also, this lets us share the copyright-generation code,
Tom> which is reused both in this series, and in an upcoming series I'll be
Tom> sending in the future.

Tom> Tested by rebuilding, and by examining the diffs of the generated
Tom> files, which are minimal.

I'm checking this in.

Tom

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] Rewrite make-target-delegates in Python
  2022-02-14 19:28 ` [PATCH 2/2] Rewrite make-target-delegates in Python Tom Tromey
@ 2022-03-02 16:19   ` Pedro Alves
  0 siblings, 0 replies; 5+ messages in thread
From: Pedro Alves @ 2022-03-02 16:19 UTC (permalink / raw)
  To: Tom Tromey, gdb-patches

On 2022-02-14 19:28, Tom Tromey via Gdb-patches wrote:
> make-target-delegates.py is simpler to invoke, as it knows the correct
> input file to scan and it creates the output file itself.

+10000000

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2022-03-02 16:19 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-14 19:28 [PATCH 0/2] Rewrite make-target-delegates in Python Tom Tromey
2022-02-14 19:28 ` [PATCH 1/2] Move copyright code from gdbarch.py to new file Tom Tromey
2022-02-14 19:28 ` [PATCH 2/2] Rewrite make-target-delegates in Python Tom Tromey
2022-03-02 16:19   ` Pedro Alves
2022-03-02 16:10 ` [PATCH 0/2] " Tom Tromey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).