diff mbox

[1/9] Introduce class rtx_reader

Message ID 1473381053-18817-2-git-send-email-dmalcolm@redhat.com
State New
Headers show

Commit Message

David Malcolm Sept. 9, 2016, 12:30 a.m. UTC
Bundle up various global variables within gensupport.c into a
class rtx_reader, with a view towards making it easier to run the
code more than once in-process.

gcc/ChangeLog:
	* genconstants.c (main): Introduce noop_reader and convert call
	to read_md_files to a method call.
	* genenums.c (main): Likewise.
	* genmddeps.c (main): Likewise.
	* genpreds.c (write_tm_constrs_h): Replace use of "in_fname" with
	rtx_reader_ptr->get_top_level_filename ().
	(write_tm_preds_h): Likewise.
	(write_insn_preds_c): Likewise.
	* gensupport.c (class gen_reader): New subclass of rtx_reader.
	(rtx_handle_directive): Convert to...
	(gen_reader::handle_unknown_directive): ...this.
	(init_rtx_reader_args_cb): Convert return type from bool to
	rtx_reader *.  Create a gen_reader instance, using it for the
	call to read_md_files.  Return it if no errors occur.
	(init_rtx_reader_args): Convert return type from bool to
	rtx_reader *.
	* gensupport.h (init_rtx_reader_args_cb): Likewise.
	(init_rtx_reader_args_cb): Likewise.
	* read-md.c (struct file_name_list): Move to class rtx_reader.
	(read_md_file): Delete in favor of rtx_reader::m_read_md_file.
	(read_md_filename): Delete in favor of
	rtx_reader::m_read_md_filename.
	(read_md_lineno): Delete in favor of rtx_reader::m_read_md_lineno.
	(in_fname): Delete in favor of rtx_reader::m_toplevel_fname.
	(base_dir): Delete in favor of rtx_reader::m_base_dir.
	(first_dir_md_include): Delete in favor of
	rtx_reader::m_first_dir_md_include.
	(last_dir_md_include_ptr): Delete in favor of
	rtx_reader::m_last_dir_md_include_ptr.
	(max_include_len): Delete.
	(rtx_reader_ptr): New.
	(fatal_with_file_and_line): Use get_filename and get_lineno
	accessors of rtx_reader_ptr.
	(require_char_ws): Likewise.
	(rtx_reader::read_char): New method, based on ::read_char.
	(rtx_reader::unread_char): New method, based on ::unread_char.
	(read_escape): Use get_filename and get_lineno accessors of
	rtx_reader_ptr.
	(read_braced_string): Use get_lineno accessor of rtx_reader_ptr.
	(read_string): Use get_filename and get_lineno accessors of
	rtx_reader_ptr.
	(rtx_reader::rtx_reader): New ctor.
	(rtx_reader::~rtx_reader): New dtor.
	(handle_include): Convert from a function to...
	(rtx_reader::handle_include): ...this method, converting
	handle_directive from a callback to a virtual function.
	(handle_file): Likewise, converting to...
	(rtx_reader::handle_file): ...this method.
	(handle_toplevel_file): Likewise, converting to...
	(rtx_reader::handle_toplevel_file): ...this method.
	(rtx_reader::get_current_location): New method.
	(parse_include): Convert from a function to...
	(rtx_reader::add_include_path): ...this method, dropping redundant
	update to unused max_include_len.
	(read_md_files): Convert from a function to...
	(rtx_reader::read_md_files): ...this method, converting
	handle_directive from a callback to a virtual function.
	(noop_reader::handle_unknown_directive): New method.
	* read-md.h (directive_handler_t): Delete this typedef.
	(in_fname): Delete.
	(read_md_file): Delete.
	(read_md_lineno): Delete.
	(read_md_filename): Delete.
	(class rtx_reader): New class.
	(rtx_reader_ptr): New decl.
	(class noop_reader): New subclass of rtx_reader.
	(read_char): Reimplement in terms of rtx_reader::read_char.
	(unread_char): Reimplement in terms of rtx_reader::unread_char.
	(read_md_files): Delete.
	* read-rtl.c (read_rtx_code): Update for deletion of globals
	read_md_filename and read_md_lineno.
---
 gcc/genconstants.c |   3 +-
 gcc/genenums.c     |   3 +-
 gcc/genmddeps.c    |   3 +-
 gcc/genpreds.c     |   9 ++-
 gcc/gensupport.c   |  29 +++++--
 gcc/gensupport.h   |   6 +-
 gcc/read-md.c      | 225 ++++++++++++++++++++++++++++++-----------------------
 gcc/read-md.h      |  98 ++++++++++++++++++-----
 gcc/read-rtl.c     |   3 +-
 9 files changed, 242 insertions(+), 137 deletions(-)

Comments

Jeff Law Sept. 16, 2016, 10:04 p.m. UTC | #1
On 09/08/2016 06:30 PM, David Malcolm wrote:
> Bundle up various global variables within gensupport.c into a
> class rtx_reader, with a view towards making it easier to run the
> code more than once in-process.
>
> gcc/ChangeLog:
> 	* genconstants.c (main): Introduce noop_reader and convert call
> 	to read_md_files to a method call.
> 	* genenums.c (main): Likewise.
> 	* genmddeps.c (main): Likewise.
> 	* genpreds.c (write_tm_constrs_h): Replace use of "in_fname" with
> 	rtx_reader_ptr->get_top_level_filename ().
> 	(write_tm_preds_h): Likewise.
> 	(write_insn_preds_c): Likewise.
> 	* gensupport.c (class gen_reader): New subclass of rtx_reader.
> 	(rtx_handle_directive): Convert to...
> 	(gen_reader::handle_unknown_directive): ...this.
> 	(init_rtx_reader_args_cb): Convert return type from bool to
> 	rtx_reader *.  Create a gen_reader instance, using it for the
> 	call to read_md_files.  Return it if no errors occur.
> 	(init_rtx_reader_args): Convert return type from bool to
> 	rtx_reader *.
> 	* gensupport.h (init_rtx_reader_args_cb): Likewise.
> 	(init_rtx_reader_args_cb): Likewise.
> 	* read-md.c (struct file_name_list): Move to class rtx_reader.
> 	(read_md_file): Delete in favor of rtx_reader::m_read_md_file.
> 	(read_md_filename): Delete in favor of
> 	rtx_reader::m_read_md_filename.
> 	(read_md_lineno): Delete in favor of rtx_reader::m_read_md_lineno.
> 	(in_fname): Delete in favor of rtx_reader::m_toplevel_fname.
> 	(base_dir): Delete in favor of rtx_reader::m_base_dir.
> 	(first_dir_md_include): Delete in favor of
> 	rtx_reader::m_first_dir_md_include.
> 	(last_dir_md_include_ptr): Delete in favor of
> 	rtx_reader::m_last_dir_md_include_ptr.
> 	(max_include_len): Delete.
> 	(rtx_reader_ptr): New.
> 	(fatal_with_file_and_line): Use get_filename and get_lineno
> 	accessors of rtx_reader_ptr.
> 	(require_char_ws): Likewise.
> 	(rtx_reader::read_char): New method, based on ::read_char.
> 	(rtx_reader::unread_char): New method, based on ::unread_char.
> 	(read_escape): Use get_filename and get_lineno accessors of
> 	rtx_reader_ptr.
> 	(read_braced_string): Use get_lineno accessor of rtx_reader_ptr.
> 	(read_string): Use get_filename and get_lineno accessors of
> 	rtx_reader_ptr.
> 	(rtx_reader::rtx_reader): New ctor.
> 	(rtx_reader::~rtx_reader): New dtor.
> 	(handle_include): Convert from a function to...
> 	(rtx_reader::handle_include): ...this method, converting
> 	handle_directive from a callback to a virtual function.
> 	(handle_file): Likewise, converting to...
> 	(rtx_reader::handle_file): ...this method.
> 	(handle_toplevel_file): Likewise, converting to...
> 	(rtx_reader::handle_toplevel_file): ...this method.
> 	(rtx_reader::get_current_location): New method.
> 	(parse_include): Convert from a function to...
> 	(rtx_reader::add_include_path): ...this method, dropping redundant
> 	update to unused max_include_len.
> 	(read_md_files): Convert from a function to...
> 	(rtx_reader::read_md_files): ...this method, converting
> 	handle_directive from a callback to a virtual function.
> 	(noop_reader::handle_unknown_directive): New method.
> 	* read-md.h (directive_handler_t): Delete this typedef.
> 	(in_fname): Delete.
> 	(read_md_file): Delete.
> 	(read_md_lineno): Delete.
> 	(read_md_filename): Delete.
> 	(class rtx_reader): New class.
> 	(rtx_reader_ptr): New decl.
> 	(class noop_reader): New subclass of rtx_reader.
> 	(read_char): Reimplement in terms of rtx_reader::read_char.
> 	(unread_char): Reimplement in terms of rtx_reader::unread_char.
> 	(read_md_files): Delete.
> 	* read-rtl.c (read_rtx_code): Update for deletion of globals
> 	read_md_filename and read_md_lineno.
I don't see anything terribly objectionable here.

It looks like you use a singleton to avoid passing the object around 
everywhere, but given the state of all this prior to this patch, I can 
live with the cleanup as a whole.

I'll note Richard Sandiford. hasn't chimed in here.  You might ping him 
directly to see if he's got any feedback.  If he doesn't prior to say 
Wed, this is OK for the trunk.

jeff
diff mbox

Patch

diff --git a/gcc/genconstants.c b/gcc/genconstants.c
index c10e3e3..e8be5b6 100644
--- a/gcc/genconstants.c
+++ b/gcc/genconstants.c
@@ -79,7 +79,8 @@  main (int argc, const char **argv)
 {
   progname = "genconstants";
 
-  if (!read_md_files (argc, argv, NULL, NULL))
+  noop_reader reader;
+  if (!reader.read_md_files (argc, argv, NULL))
     return (FATAL_EXIT_CODE);
 
   /* Initializing the MD reader has the side effect of loading up
diff --git a/gcc/genenums.c b/gcc/genenums.c
index db46a67..8af8d9a 100644
--- a/gcc/genenums.c
+++ b/gcc/genenums.c
@@ -49,7 +49,8 @@  main (int argc, const char **argv)
 {
   progname = "genenums";
 
-  if (!read_md_files (argc, argv, NULL, NULL))
+  noop_reader reader;
+  if (!reader.read_md_files (argc, argv, NULL))
     return (FATAL_EXIT_CODE);
 
   puts ("/* Generated automatically by the program `genenums'");
diff --git a/gcc/genmddeps.c b/gcc/genmddeps.c
index fd26a33..e3d229d 100644
--- a/gcc/genmddeps.c
+++ b/gcc/genmddeps.c
@@ -47,7 +47,8 @@  main (int argc, const char **argv)
   progname = "genmddeps";
   include_callback = add_filedep;
 
-  if (!read_md_files (argc, argv, NULL, NULL))
+  noop_reader reader;
+  if (!reader.read_md_files (argc, argv, NULL))
     return FATAL_EXIT_CODE;
 
   *last = NULL;
diff --git a/gcc/genpreds.c b/gcc/genpreds.c
index 4c9dfc6..96f75bd 100644
--- a/gcc/genpreds.c
+++ b/gcc/genpreds.c
@@ -1204,7 +1204,8 @@  write_tm_constrs_h (void)
 
   printf ("\
 /* Generated automatically by the program '%s'\n\
-   from the machine description file '%s'.  */\n\n", progname, in_fname);
+   from the machine description file '%s'.  */\n\n", progname,
+	  rtx_reader_ptr->get_top_level_filename ());
 
   puts ("\
 #ifndef GCC_TM_CONSTRS_H\n\
@@ -1403,7 +1404,8 @@  write_tm_preds_h (void)
 
   printf ("\
 /* Generated automatically by the program '%s'\n\
-   from the machine description file '%s'.  */\n\n", progname, in_fname);
+   from the machine description file '%s'.  */\n\n", progname,
+	  rtx_reader_ptr->get_top_level_filename ());
 
   puts ("\
 #ifndef GCC_TM_PREDS_H\n\
@@ -1552,7 +1554,8 @@  write_insn_preds_c (void)
 
   printf ("\
 /* Generated automatically by the program '%s'\n\
-   from the machine description file '%s'.  */\n\n", progname, in_fname);
+   from the machine description file '%s'.  */\n\n", progname,
+	  rtx_reader_ptr->get_top_level_filename ());
 
   puts ("\
 #include \"config.h\"\n\
diff --git a/gcc/gensupport.c b/gcc/gensupport.c
index 7e3aad3..3abb259b 100644
--- a/gcc/gensupport.c
+++ b/gcc/gensupport.c
@@ -2228,10 +2228,18 @@  process_define_subst (void)
     }
 }
 
-/* A read_md_files callback for reading an rtx.  */
+/* A subclass of rtx_reader which reads .md files and calls process_rtx on
+   the top-level elements.  */
 
-static void
-rtx_handle_directive (file_location loc, const char *rtx_name)
+class gen_reader : public rtx_reader
+{
+ public:
+  gen_reader () : rtx_reader () {}
+  void handle_unknown_directive (file_location, const char *);
+};
+
+void
+gen_reader::handle_unknown_directive (file_location loc, const char *rtx_name)
 {
   auto_vec<rtx, 32> subrtxs;
   if (!read_rtx (rtx_name, &subrtxs))
@@ -2502,7 +2510,7 @@  check_define_attr_duplicates ()
 
 /* The entry point for initializing the reader.  */
 
-bool
+rtx_reader *
 init_rtx_reader_args_cb (int argc, const char **argv,
 			 bool (*parse_opt) (const char *))
 {
@@ -2518,7 +2526,8 @@  init_rtx_reader_args_cb (int argc, const char **argv,
   split_sequence_num = 1;
   peephole2_sequence_num = 1;
 
-  read_md_files (argc, argv, parse_opt, rtx_handle_directive);
+  gen_reader *reader = new gen_reader ();
+  reader->read_md_files (argc, argv, parse_opt);
 
   if (define_attr_queue != NULL)
     check_define_attr_duplicates ();
@@ -2534,12 +2543,18 @@  init_rtx_reader_args_cb (int argc, const char **argv,
   if (define_attr_queue != NULL)
     gen_mnemonic_attr ();
 
-  return !have_error;
+  if (have_error)
+    {
+      delete reader;
+      return NULL;
+    }
+
+  return reader;
 }
 
 /* Programs that don't have their own options can use this entry point
    instead.  */
-bool
+rtx_reader *
 init_rtx_reader_args (int argc, const char **argv)
 {
   return init_rtx_reader_args_cb (argc, argv, 0);
diff --git a/gcc/gensupport.h b/gcc/gensupport.h
index 645512c..618359d 100644
--- a/gcc/gensupport.h
+++ b/gcc/gensupport.h
@@ -125,9 +125,9 @@  struct optab_pattern
 };
 
 extern rtx add_implicit_parallel (rtvec);
-extern bool init_rtx_reader_args_cb (int, const char **,
-				     bool (*)(const char *));
-extern bool init_rtx_reader_args (int, const char **);
+extern rtx_reader *init_rtx_reader_args_cb (int, const char **,
+					    bool (*)(const char *));
+extern rtx_reader *init_rtx_reader_args (int, const char **);
 extern bool read_md_rtx (md_rtx_info *);
 extern unsigned int get_num_insn_codes ();
 
diff --git a/gcc/read-md.c b/gcc/read-md.c
index b422d8d..77e558c 100644
--- a/gcc/read-md.c
+++ b/gcc/read-md.c
@@ -31,12 +31,6 @@  struct ptr_loc {
   int lineno;
 };
 
-/* A singly-linked list of filenames.  */
-struct file_name_list {
-  struct file_name_list *next;
-  const char *fname;
-};
-
 /* Obstack used for allocating MD strings.  */
 struct obstack string_obstack;
 
@@ -56,34 +50,13 @@  static htab_t joined_conditions;
 /* An obstack for allocating joined_conditions entries.  */
 static struct obstack joined_conditions_obstack;
 
-/* The file we are reading.  */
-FILE *read_md_file;
-
-/* The filename of READ_MD_FILE.  */
-const char *read_md_filename;
-
-/* The current line number in READ_MD_FILE.  */
-int read_md_lineno;
-
-/* The name of the toplevel file that indirectly included READ_MD_FILE.  */
-const char *in_fname;
-
-/* The directory part of IN_FNAME.  NULL if IN_FNAME is a bare filename.  */
-static char *base_dir;
-
-/* The first directory to search.  */
-static struct file_name_list *first_dir_md_include;
-
-/* A pointer to the null terminator of the md include chain.  */
-static struct file_name_list **last_dir_md_include_ptr = &first_dir_md_include;
-
 /* This callback will be invoked whenever an md include directive is
    processed.  To be used for creation of the dependency file.  */
 void (*include_callback) (const char *);
 
-/* The current maximum length of directory names in the search path
-   for include files.  (Altered as we get more of them.)  */
-static size_t max_include_len;
+/* Global singleton.  */
+
+rtx_reader *rtx_reader_ptr;
 
 /* A table of md_constant structures, hashed by name.  Null if no
    constant expansion should occur.  */
@@ -92,8 +65,6 @@  static htab_t md_constants;
 /* A table of enum_type structures, hashed by name.  */
 static htab_t enum_types;
 
-static void handle_file (directive_handler_t);
-
 /* Given an object that starts with a char * name field, return a hash
    code for its name.  */
 
@@ -303,7 +274,8 @@  fatal_with_file_and_line (const char *msg, ...)
 
   va_start (ap, msg);
 
-  fprintf (stderr, "%s:%d: ", read_md_filename, read_md_lineno);
+  fprintf (stderr, "%s:%d: error: ", rtx_reader_ptr->get_filename (),
+	   rtx_reader_ptr->get_lineno ());
   vfprintf (stderr, msg, ap);
   putc ('\n', stderr);
 
@@ -322,8 +294,9 @@  fatal_with_file_and_line (const char *msg, ...)
     }
   context[i] = '\0';
 
-  fprintf (stderr, "%s:%d: following context is `%s'\n",
-	   read_md_filename, read_md_lineno, context);
+  fprintf (stderr, "%s:%d: note: following context is `%s'\n",
+	   rtx_reader_ptr->get_filename (), rtx_reader_ptr->get_lineno (),
+	   context);
 
   va_end (ap);
   exit (1);
@@ -402,6 +375,30 @@  require_char_ws (char expected)
     fatal_expected_char (expected, ch);
 }
 
+/* Read the next character from the file.  */
+
+int
+rtx_reader::read_char (void)
+{
+  int ch;
+
+  ch = getc (m_read_md_file);
+  if (ch == '\n')
+    m_read_md_lineno++;
+
+  return ch;
+}
+
+/* Put back CH, which was the last character read from the file.  */
+
+void
+rtx_reader::unread_char (int ch)
+{
+  if (ch == '\n')
+    m_read_md_lineno--;
+  ungetc (ch, m_read_md_file);
+}
+
 /* Read an rtx code name into NAME.  It is terminated by any of the
    punctuation chars of rtx printed syntax.  */
 
@@ -512,7 +509,8 @@  read_escape (void)
       /* pass anything else through, but issue a warning.  */
     default:
       fprintf (stderr, "%s:%d: warning: unrecognized escape \\%c\n",
-	       read_md_filename, read_md_lineno, c);
+	       rtx_reader_ptr->get_filename (), rtx_reader_ptr->get_lineno (),
+	       c);
       obstack_1grow (&string_obstack, '\\');
       break;
     }
@@ -555,7 +553,7 @@  read_braced_string (void)
 {
   int c;
   int brace_depth = 1;  /* caller-processed */
-  unsigned long starting_read_md_lineno = read_md_lineno;
+  unsigned long starting_read_md_lineno = rtx_reader_ptr->get_lineno ();
 
   obstack_1grow (&string_obstack, '{');
   while (brace_depth)
@@ -601,7 +599,7 @@  read_string (int star_if_braced)
       c = read_skip_spaces ();
     }
 
-  old_lineno = read_md_lineno;
+  old_lineno = rtx_reader_ptr->get_lineno ();
   if (c == '"')
     stringbuf = read_quoted_string ();
   else if (c == '{')
@@ -616,7 +614,7 @@  read_string (int star_if_braced)
   if (saw_paren)
     require_char_ws (')');
 
-  set_md_ptr_loc (stringbuf, read_md_filename, old_lineno);
+  set_md_ptr_loc (stringbuf, rtx_reader_ptr->get_filename (), old_lineno);
   return stringbuf;
 }
 
@@ -901,13 +899,35 @@  traverse_enum_types (htab_trav callback, void *info)
   htab_traverse (enum_types, callback, info);
 }
 
+
+/* Constructor for rtx_reader.  */
+
+rtx_reader::rtx_reader ()
+: m_toplevel_fname (NULL),
+  m_read_md_filename (NULL),
+  m_read_md_lineno (0),
+  m_first_dir_md_include (NULL),
+  m_last_dir_md_include_ptr (&m_first_dir_md_include)
+{
+  /* Set the global singleton pointer.  */
+  rtx_reader_ptr = this;
+}
+
+/* rtx_reader's destructor.  */
+
+rtx_reader::~rtx_reader ()
+{
+  /* Clear the global singleton pointer.  */
+  rtx_reader_ptr = NULL;
+}
+
 /* Process an "include" directive, starting with the optional space
    after the "include".  Read in the file and use HANDLE_DIRECTIVE
    to process each unknown directive.  LINENO is the line number on
    which the "include" occurred.  */
 
-static void
-handle_include (file_location loc, directive_handler_t handle_directive)
+void
+rtx_reader::handle_include (file_location loc)
 {
   const char *filename;
   const char *old_filename;
@@ -924,7 +944,7 @@  handle_include (file_location loc, directive_handler_t handle_directive)
       struct file_name_list *stackp;
 
       /* Search the directory path, trying to open the file.  */
-      for (stackp = first_dir_md_include; stackp; stackp = stackp->next)
+      for (stackp = m_first_dir_md_include; stackp; stackp = stackp->next)
 	{
 	  static const char sep[2] = { DIR_SEPARATOR, '\0' };
 
@@ -940,8 +960,8 @@  handle_include (file_location loc, directive_handler_t handle_directive)
      filename with BASE_DIR.  */
   if (input_file == NULL)
     {
-      if (base_dir)
-	pathname = concat (base_dir, filename, NULL);
+      if (m_base_dir)
+	pathname = concat (m_base_dir, filename, NULL);
       else
 	pathname = xstrdup (filename);
       input_file = fopen (pathname, "r");
@@ -957,21 +977,22 @@  handle_include (file_location loc, directive_handler_t handle_directive)
   /* Save the old cursor.  Note that the LINENO argument to this
      function is the beginning of the include statement, while
      read_md_lineno has already been advanced.  */
-  old_file = read_md_file;
-  old_filename = read_md_filename;
-  old_lineno = read_md_lineno;
+  old_file = m_read_md_file;
+  old_filename = m_read_md_filename;
+  old_lineno = m_read_md_lineno;
 
   if (include_callback)
     include_callback (pathname);
 
-  read_md_file = input_file;
-  read_md_filename = pathname;
-  handle_file (handle_directive);
+  m_read_md_file = input_file;
+  m_read_md_filename = pathname;
+
+  handle_file ();
 
   /* Restore the old cursor.  */
-  read_md_file = old_file;
-  read_md_filename = old_filename;
-  read_md_lineno = old_lineno;
+  m_read_md_file = old_file;
+  m_read_md_filename = old_filename;
+  m_read_md_lineno = old_lineno;
 
   /* Do not free the pathname.  It is attached to the various rtx
      queue elements.  */
@@ -981,16 +1002,16 @@  handle_include (file_location loc, directive_handler_t handle_directive)
    read_md_filename are valid.  Use HANDLE_DIRECTIVE to handle
    unknown directives.  */
 
-static void
-handle_file (directive_handler_t handle_directive)
+void
+rtx_reader::handle_file ()
 {
   struct md_name directive;
   int c;
 
-  read_md_lineno = 1;
+  m_read_md_lineno = 1;
   while ((c = read_skip_spaces ()) != EOF)
     {
-      file_location loc (read_md_filename, read_md_lineno);
+      file_location loc = get_current_location ();
       if (c != '(')
 	fatal_expected_char ('(', c);
 
@@ -1002,49 +1023,51 @@  handle_file (directive_handler_t handle_directive)
       else if (strcmp (directive.string, "define_c_enum") == 0)
 	handle_enum (loc, false);
       else if (strcmp (directive.string, "include") == 0)
-	handle_include (loc, handle_directive);
-      else if (handle_directive)
-	handle_directive (loc, directive.string);
+	handle_include (loc);
       else
-	read_skip_construct (1, loc);
+	handle_unknown_directive (loc, directive.string);
 
       require_char_ws (')');
     }
-  fclose (read_md_file);
+  fclose (m_read_md_file);
 }
 
-/* Like handle_file, but for top-level files.  Set up in_fname and
-   base_dir accordingly.  */
+/* Like handle_file, but for top-level files.  Set up m_toplevel_fname
+   and m_base_dir accordingly.  */
 
-static void
-handle_toplevel_file (directive_handler_t handle_directive)
+void
+rtx_reader::handle_toplevel_file ()
 {
   const char *base;
 
-  in_fname = read_md_filename;
-  base = lbasename (in_fname);
-  if (base == in_fname)
-    base_dir = NULL;
+  m_toplevel_fname = m_read_md_filename;
+  base = lbasename (m_toplevel_fname);
+  if (base == m_toplevel_fname)
+    m_base_dir = NULL;
   else
-    base_dir = xstrndup (in_fname, base - in_fname);
+    m_base_dir = xstrndup (m_toplevel_fname, base - m_toplevel_fname);
+
+  handle_file ();
+}
 
-  handle_file (handle_directive);
+file_location
+rtx_reader::get_current_location () const
+{
+  return file_location (m_read_md_filename, m_read_md_lineno);
 }
 
 /* Parse a -I option with argument ARG.  */
 
-static void
-parse_include (const char *arg)
+void
+rtx_reader::add_include_path (const char *arg)
 {
   struct file_name_list *dirtmp;
 
   dirtmp = XNEW (struct file_name_list);
   dirtmp->next = 0;
   dirtmp->fname = arg;
-  *last_dir_md_include_ptr = dirtmp;
-  last_dir_md_include_ptr = &dirtmp->next;
-  if (strlen (dirtmp->fname) > max_include_len)
-    max_include_len = strlen (dirtmp->fname);
+  *m_last_dir_md_include_ptr = dirtmp;
+  m_last_dir_md_include_ptr = &dirtmp->next;
 }
 
 /* The main routine for reading .md files.  Try to process all the .md
@@ -1054,16 +1077,11 @@  parse_include (const char *arg)
 
    PARSE_OPT, if nonnull, is passed all unknown command-line arguments.
    It should return true if it recognizes the argument or false if a
-   generic error should be reported.
-
-   If HANDLE_DIRECTIVE is nonnull, the parser calls it for each
-   unknown directive, otherwise it just skips such directives.
-   See the comment above the directive_handler_t definition for
-   details about the callback's interface.  */
+   generic error should be reported.  */
 
 bool
-read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
-	       directive_handler_t handle_directive)
+rtx_reader::read_md_files (int argc, const char **argv,
+			   bool (*parse_opt) (const char *))
 {
   int i;
   bool no_more_options;
@@ -1101,9 +1119,9 @@  read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
 	if (argv[i][1] == 'I')
 	  {
 	    if (argv[i][2] != '\0')
-	      parse_include (argv[i] + 2);
+	      add_include_path (argv[i] + 2);
 	    else if (++i < argc)
-	      parse_include (argv[i]);
+	      add_include_path (argv[i]);
 	    else
 	      fatal ("directory name missing after -I option");
 	    continue;
@@ -1131,9 +1149,9 @@  read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
 	      if (already_read_stdin)
 		fatal ("cannot read standard input twice");
 
-	      read_md_file = stdin;
-	      read_md_filename = "<stdin>";
-	      handle_toplevel_file (handle_directive);
+	      m_read_md_file = stdin;
+	      m_read_md_filename = "<stdin>";
+	      handle_toplevel_file ();
 	      already_read_stdin = true;
 	      continue;
 	    }
@@ -1149,14 +1167,14 @@  read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
 
       /* If we get here we are looking at a non-option argument, i.e.
 	 a file to be processed.  */
-      read_md_filename = argv[i];
-      read_md_file = fopen (read_md_filename, "r");
-      if (read_md_file == 0)
+      m_read_md_filename = argv[i];
+      m_read_md_file = fopen (m_read_md_filename, "r");
+      if (m_read_md_file == 0)
 	{
-	  perror (read_md_filename);
+	  perror (m_read_md_filename);
 	  return false;
 	}
-      handle_toplevel_file (handle_directive);
+      handle_toplevel_file ();
       num_files++;
     }
 
@@ -1164,10 +1182,19 @@  read_md_files (int argc, const char **argv, bool (*parse_opt) (const char *),
      read the standard input now.  */
   if (num_files == 0 && !already_read_stdin)
     {
-      read_md_file = stdin;
-      read_md_filename = "<stdin>";
-      handle_toplevel_file (handle_directive);
+      m_read_md_file = stdin;
+      m_read_md_filename = "<stdin>";
+      handle_toplevel_file ();
     }
 
   return !have_error;
 }
+
+/* class noop_reader : public rtx_reader */
+
+/* A dummy implementation which skips unknown directives.  */
+void
+noop_reader::handle_unknown_directive (file_location loc, const char *)
+{
+  read_skip_construct (1, loc);
+}
diff --git a/gcc/read-md.h b/gcc/read-md.h
index fa25951..82a628b 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -90,16 +90,81 @@  struct enum_type {
   unsigned int num_values;
 };
 
-/* A callback that handles a single .md-file directive, up to but not
-   including the closing ')'.  It takes two arguments: the file position
-   at which the directive started, and the name of the directive.  The next
-   unread character is the optional space after the directive name.  */
-typedef void (*directive_handler_t) (file_location, const char *);
-
-extern const char *in_fname;
-extern FILE *read_md_file;
-extern int read_md_lineno;
-extern const char *read_md_filename;
+class rtx_reader
+{
+ public:
+  rtx_reader ();
+  virtual ~rtx_reader ();
+
+  bool read_md_files (int, const char **, bool (*) (const char *));
+
+  /* A hook that handles a single .md-file directive, up to but not
+     including the closing ')'.  It takes two arguments: the file position
+     at which the directive started, and the name of the directive.  The next
+     unread character is the optional space after the directive name.  */
+  virtual void handle_unknown_directive (file_location, const char *) = 0;
+
+  file_location get_current_location () const;
+
+  int read_char (void);
+  void unread_char (int ch);
+
+  const char *get_top_level_filename () const { return m_toplevel_fname; }
+  const char *get_filename () const { return m_read_md_filename; }
+  int get_lineno () const { return m_read_md_lineno; }
+
+ private:
+  /* A singly-linked list of filenames.  */
+  struct file_name_list {
+    struct file_name_list *next;
+    const char *fname;
+  };
+
+ private:
+  void handle_file ();
+  void handle_toplevel_file ();
+  void handle_include (file_location loc);
+  void add_include_path (const char *arg);
+
+ private:
+  /* The name of the toplevel file that indirectly included
+     m_read_md_file.  */
+  const char *m_toplevel_fname;
+
+  /* The directory part of m_toplevel_fname
+     NULL if m_toplevel_fname is a bare filename.  */
+  char *m_base_dir;
+
+  /* The file we are reading.  */
+  FILE *m_read_md_file;
+
+  /* The filename of m_read_md_file.  */
+  const char *m_read_md_filename;
+
+  /* The current line number in m_read_md_file.  */
+  int m_read_md_lineno;
+
+  /* The first directory to search.  */
+  file_name_list *m_first_dir_md_include;
+
+  /* A pointer to the null terminator of the md include chain.  */
+  file_name_list **m_last_dir_md_include_ptr;
+};
+
+/* Global singleton.  */
+extern rtx_reader *rtx_reader_ptr;
+
+/* An rtx_reader subclass which skips unknown directives.  */
+
+class noop_reader : public rtx_reader
+{
+ public:
+  noop_reader () : rtx_reader () {}
+
+  /* A dummy implementation which skips unknown directives.  */
+  void handle_unknown_directive (file_location, const char *);
+};
+
 extern struct obstack string_obstack;
 extern void (*include_callback) (const char *);
 
@@ -108,12 +173,7 @@  extern void (*include_callback) (const char *);
 static inline int
 read_char (void)
 {
-  int ch;
-
-  ch = getc (read_md_file);
-  if (ch == '\n')
-    read_md_lineno++;
-  return ch;
+  return rtx_reader_ptr->read_char ();
 }
 
 /* Put back CH, which was the last character read from the MD file.  */
@@ -121,9 +181,7 @@  read_char (void)
 static inline void
 unread_char (int ch)
 {
-  if (ch == '\n')
-    read_md_lineno--;
-  ungetc (ch, read_md_file);
+  rtx_reader_ptr->unread_char (ch);
 }
 
 extern hashval_t leading_string_hash (const void *);
@@ -151,7 +209,5 @@  extern void upcase_string (char *);
 extern void traverse_md_constants (htab_trav, void *);
 extern void traverse_enum_types (htab_trav, void *);
 extern struct enum_type *lookup_enum_type (const char *);
-extern bool read_md_files (int, const char **, bool (*) (const char *),
-			   directive_handler_t);
 
 #endif /* GCC_READ_MD_H */
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 4614e35..eda9382 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -1234,6 +1234,7 @@  read_rtx_code (const char *code_name)
 		  || GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT))
 	    {
 	      char line_name[20];
+	      const char *read_md_filename = rtx_reader_ptr->get_filename ();
 	      const char *fn = (read_md_filename ? read_md_filename : "rtx");
 	      const char *slash;
 	      for (slash = fn; *slash; slash ++)
@@ -1241,7 +1242,7 @@  read_rtx_code (const char *code_name)
 		  fn = slash + 1;
 	      obstack_1grow (&string_obstack, '*');
 	      obstack_grow (&string_obstack, fn, strlen (fn));
-	      sprintf (line_name, ":%d", read_md_lineno);
+	      sprintf (line_name, ":%d", rtx_reader_ptr->get_lineno ());
 	      obstack_grow (&string_obstack, line_name, strlen (line_name)+1);
 	      stringbuf = XOBFINISH (&string_obstack, char *);
 	    }