]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/read-md.c
[PR89528] reset debug uses of return value when dropping dead RTL call
[thirdparty/gcc.git] / gcc / read-md.c
index a551ba3590cb53082bedc3a645fd3159552abf06..8247640bd0d03f2cdcd0ffb92d294246c8620ddb 100644 (file)
@@ -1,5 +1,5 @@
 /* MD reader for GCC.
-   Copyright (C) 1987-2015 Free Software Foundation, Inc.
+   Copyright (C) 1987-2019 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -17,13 +17,32 @@ You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
+/* This file is compiled twice: once for the generator programs
+   once for the compiler.  */
+#ifdef GENERATOR_FILE
 #include "bconfig.h"
+#else
+#include "config.h"
+#endif
 #include "system.h"
 #include "coretypes.h"
-#include "hashtab.h"
+#ifdef GENERATOR_FILE
 #include "errors.h"
+#endif /* #ifdef GENERATOR_FILE */
+#include "statistics.h"
+#include "vec.h"
 #include "read-md.h"
 
+#ifndef GENERATOR_FILE
+
+/* Minimal reimplementation of errors.c for use by RTL frontend
+   within cc1.  */
+
+int have_error = 0;
+
+#endif /* #ifndef GENERATOR_FILE */
+
+
 /* Associates PTR (which can be a string, etc.) with the file location
    specified by FILENAME and LINENO.  */
 struct ptr_loc {
@@ -32,68 +51,13 @@ 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;
-
-/* A table of ptr_locs, hashed on the PTR field.  */
-static htab_t ptr_locs;
-
-/* An obstack for the above.  Plain xmalloc is a bit heavyweight for a
-   small structure like ptr_loc.  */
-static struct obstack ptr_loc_obstack;
-
-/* A hash table of triples (A, B, C), where each of A, B and C is a condition
-   and A is equivalent to "B && C".  This is used to keep track of the source
-   of conditions that are made up of separate MD strings (such as the split
-   condition of a define_insn_and_split).  */
-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;
-
-/* A table of md_constant structures, hashed by name.  Null if no
-   constant expansion should occur.  */
-static htab_t md_constants;
+/* Global singleton.  */
 
-/* A table of enum_type structures, hashed by name.  */
-static htab_t enum_types;
-
-static void handle_file (directive_handler_t);
+md_reader *md_reader_ptr;
 
 /* Given an object that starts with a char * name field, return a hash
    code for its name.  */
@@ -132,32 +96,32 @@ leading_ptr_eq_p (const void *def1, const void *def2)
 
 /* Associate PTR with the file position given by FILENAME and LINENO.  */
 
-static void
-set_md_ptr_loc (const void *ptr, const char *filename, int lineno)
+void
+md_reader::set_md_ptr_loc (const void *ptr, const char *filename, int lineno)
 {
   struct ptr_loc *loc;
 
-  loc = (struct ptr_loc *) obstack_alloc (&ptr_loc_obstack,
+  loc = (struct ptr_loc *) obstack_alloc (&m_ptr_loc_obstack,
                                          sizeof (struct ptr_loc));
   loc->ptr = ptr;
   loc->filename = filename;
   loc->lineno = lineno;
-  *htab_find_slot (ptr_locs, loc, INSERT) = loc;
+  *htab_find_slot (m_ptr_locs, loc, INSERT) = loc;
 }
 
 /* Return the position associated with pointer PTR.  Return null if no
    position was set.  */
 
-static const struct ptr_loc *
-get_md_ptr_loc (const void *ptr)
+const struct ptr_loc *
+md_reader::get_md_ptr_loc (const void *ptr)
 {
-  return (const struct ptr_loc *) htab_find (ptr_locs, &ptr);
+  return (const struct ptr_loc *) htab_find (m_ptr_locs, &ptr);
 }
 
 /* Associate NEW_PTR with the same file position as OLD_PTR.  */
 
 void
-copy_md_ptr_loc (const void *new_ptr, const void *old_ptr)
+md_reader::copy_md_ptr_loc (const void *new_ptr, const void *old_ptr)
 {
   const struct ptr_loc *loc = get_md_ptr_loc (old_ptr);
   if (loc != 0)
@@ -168,7 +132,7 @@ copy_md_ptr_loc (const void *new_ptr, const void *old_ptr)
    directive for it to OUTF.  */
 
 void
-fprint_md_ptr_loc (FILE *outf, const void *ptr)
+md_reader::fprint_md_ptr_loc (FILE *outf, const void *ptr)
 {
   const struct ptr_loc *loc = get_md_ptr_loc (ptr);
   if (loc != 0)
@@ -177,7 +141,7 @@ fprint_md_ptr_loc (FILE *outf, const void *ptr)
 
 /* Special fprint_md_ptr_loc for writing to STDOUT.  */
 void
-print_md_ptr_loc (const void *ptr)
+md_reader::print_md_ptr_loc (const void *ptr)
 {
   fprint_md_ptr_loc (stdout, ptr);
 }
@@ -186,7 +150,7 @@ print_md_ptr_loc (const void *ptr)
    may be null or empty.  */
 
 const char *
-join_c_conditions (const char *cond1, const char *cond2)
+md_reader::join_c_conditions (const char *cond1, const char *cond2)
 {
   char *result;
   const void **entry;
@@ -201,11 +165,11 @@ join_c_conditions (const char *cond1, const char *cond2)
     return cond1;
 
   result = concat ("(", cond1, ") && (", cond2, ")", NULL);
-  obstack_ptr_grow (&joined_conditions_obstack, result);
-  obstack_ptr_grow (&joined_conditions_obstack, cond1);
-  obstack_ptr_grow (&joined_conditions_obstack, cond2);
-  entry = XOBFINISH (&joined_conditions_obstack, const void **);
-  *htab_find_slot (joined_conditions, entry, INSERT) = entry;
+  obstack_ptr_grow (&m_joined_conditions_obstack, result);
+  obstack_ptr_grow (&m_joined_conditions_obstack, cond1);
+  obstack_ptr_grow (&m_joined_conditions_obstack, cond2);
+  entry = XOBFINISH (&m_joined_conditions_obstack, const void **);
+  *htab_find_slot (m_joined_conditions, entry, INSERT) = entry;
   return result;
 }
 
@@ -215,9 +179,9 @@ join_c_conditions (const char *cond1, const char *cond2)
    directive for COND if its original file position is known.  */
 
 void
-fprint_c_condition (FILE *outf, const char *cond)
+md_reader::fprint_c_condition (FILE *outf, const char *cond)
 {
-  const char **halves = (const char **) htab_find (joined_conditions, &cond);
+  const char **halves = (const char **) htab_find (m_joined_conditions, &cond);
   if (halves != 0)
     {
       fprintf (outf, "(");
@@ -237,7 +201,7 @@ fprint_c_condition (FILE *outf, const char *cond)
 /* Special fprint_c_condition for writing to STDOUT.  */
 
 void
-print_c_condition (const char *cond)
+md_reader::print_c_condition (const char *cond)
 {
   fprint_c_condition (stdout, cond);
 }
@@ -246,39 +210,51 @@ print_c_condition (const char *cond)
    of the current MD file.  */
 
 static void ATTRIBUTE_PRINTF(2,0)
-message_with_line_1 (int lineno, const char *msg, va_list ap)
+message_at_1 (file_location loc, const char *msg, va_list ap)
 {
-  fprintf (stderr, "%s:%d: ", read_md_filename, lineno);
+  fprintf (stderr, "%s:%d:%d: ", loc.filename, loc.lineno, loc.colno);
   vfprintf (stderr, msg, ap);
   fputc ('\n', stderr);
 }
 
-/* A printf-like function for reporting an error against line LINENO
-   in the current MD file.  */
+/* A printf-like function for reporting a message against location LOC.  */
 
 void
-message_with_line (int lineno, const char *msg, ...)
+message_at (file_location loc, const char *msg, ...)
 {
   va_list ap;
 
   va_start (ap, msg);
-  message_with_line_1 (lineno, msg, ap);
+  message_at_1 (loc, msg, ap);
   va_end (ap);
 }
 
-/* Like message_with_line, but treat the condition as an error.  */
+/* Like message_at, but treat the condition as an error.  */
 
 void
-error_with_line (int lineno, const char *msg, ...)
+error_at (file_location loc, const char *msg, ...)
 {
   va_list ap;
 
   va_start (ap, msg);
-  message_with_line_1 (lineno, msg, ap);
+  message_at_1 (loc, msg, ap);
   va_end (ap);
   have_error = 1;
 }
 
+/* Like message_at, but treat the condition as a fatal error.  */
+
+void
+fatal_at (file_location loc, const char *msg, ...)
+{
+  va_list ap;
+
+  va_start (ap, msg);
+  message_at_1 (loc, msg, ap);
+  va_end (ap);
+  exit (1);
+}
+
 /* A printf-like function for reporting an error against the current
    position in the MD file.  */
 
@@ -292,7 +268,9 @@ 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:%d: error: ", md_reader_ptr->get_filename (),
+          md_reader_ptr->get_lineno (),
+          md_reader_ptr->get_colno ());
   vfprintf (stderr, msg, ap);
   putc ('\n', stderr);
 
@@ -311,8 +289,10 @@ 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:%d: note: following context is `%s'\n",
+          md_reader_ptr->get_filename (),
+          md_reader_ptr->get_lineno (),
+          md_reader_ptr->get_colno (), context);
 
   va_end (ap);
   exit (1);
@@ -380,28 +360,130 @@ read_skip_spaces (void)
     }
 }
 
+/* Consume the next character, issuing a fatal error if it is not
+   EXPECTED.  */
+
+void
+md_reader::require_char (char expected)
+{
+  int ch = read_char ();
+  if (ch != expected)
+    fatal_expected_char (expected, ch);
+}
+
+/* Consume any whitespace, then consume the next non-whitespace
+   character, issuing a fatal error if it is not EXPECTED.  */
+
+void
+md_reader::require_char_ws (char expected)
+{
+  int ch = read_skip_spaces ();
+  if (ch != expected)
+    fatal_expected_char (expected, ch);
+}
+
+/* Consume any whitespace, then consume the next word (as per read_name),
+   issuing a fatal error if it is not EXPECTED.  */
+
+void
+md_reader::require_word_ws (const char *expected)
+{
+  struct md_name name;
+  read_name (&name);
+  if (strcmp (name.string, expected))
+    fatal_with_file_and_line ("missing '%s'", expected);
+}
+
+/* Read the next character from the file.  */
+
+int
+md_reader::read_char (void)
+{
+  int ch;
+
+  ch = getc (m_read_md_file);
+  if (ch == '\n')
+    {
+      m_read_md_lineno++;
+      m_last_line_colno = m_read_md_colno;
+      m_read_md_colno = 0;
+    }
+  else
+    m_read_md_colno++;
+
+  /* If we're filtering lines, treat everything before the range of
+     interest as a space, and as EOF for everything after.  */
+  if (m_first_line && m_last_line)
+    {
+      if (m_read_md_lineno < m_first_line)
+       return ' ';
+      if (m_read_md_lineno > m_last_line)
+       return EOF;
+    }
+
+  return ch;
+}
+
+/* Put back CH, which was the last character read from the file.  */
+
+void
+md_reader::unread_char (int ch)
+{
+  if (ch == '\n')
+    {
+      m_read_md_lineno--;
+      m_read_md_colno = m_last_line_colno;
+    }
+  else
+    m_read_md_colno--;
+  ungetc (ch, m_read_md_file);
+}
+
+/* Peek at the next character from the file without consuming it.  */
+
+int
+md_reader::peek_char (void)
+{
+  int ch = read_char ();
+  unread_char (ch);
+  return ch;
+}
+
 /* Read an rtx code name into NAME.  It is terminated by any of the
    punctuation chars of rtx printed syntax.  */
 
-void
-read_name (struct md_name *name)
+bool
+md_reader::read_name_1 (struct md_name *name, file_location *out_loc)
 {
   int c;
   size_t i;
+  int angle_bracket_depth;
 
   c = read_skip_spaces ();
 
+  *out_loc = get_current_location ();
+
   i = 0;
+  angle_bracket_depth = 0;
   while (1)
     {
+      if (c == '<')
+       angle_bracket_depth++;
+
+      if ((c == '>') && (angle_bracket_depth > 0))
+         angle_bracket_depth--;
+
       if (c == ' ' || c == '\n' || c == '\t' || c == '\f' || c == '\r'
          || c == EOF)
        break;
-      if (c == ':' || c == ')' || c == ']' || c == '"' || c == '/'
-         || c == '(' || c == '[')
+      if (angle_bracket_depth == 0)
        {
-         unread_char (c);
-         break;
+         if (c == ':' || c == ')' || c == ']'
+             || c == '"' || c == '/' || c == '(' || c == '[')
+           {
+             unread_char (c);
+             break;
+           }
        }
 
       if (i == sizeof (name->buffer) - 1)
@@ -412,12 +494,12 @@ read_name (struct md_name *name)
     }
 
   if (i == 0)
-    fatal_with_file_and_line ("missing name or number");
+    return false;
 
   name->buffer[i] = 0;
   name->string = name->buffer;
 
-  if (md_constants)
+  if (m_md_constants)
     {
       /* Do constant expansion.  */
       struct md_constant *def;
@@ -427,19 +509,49 @@ read_name (struct md_name *name)
          struct md_constant tmp_def;
 
          tmp_def.name = name->string;
-         def = (struct md_constant *) htab_find (md_constants, &tmp_def);
+         def = (struct md_constant *) htab_find (m_md_constants, &tmp_def);
          if (def)
            name->string = def->value;
        }
       while (def);
     }
+
+  return true;
+}
+
+/* Read an rtx code name into NAME.  It is terminated by any of the
+   punctuation chars of rtx printed syntax.  */
+
+file_location
+md_reader::read_name (struct md_name *name)
+{
+  file_location loc;
+  if (!read_name_1 (name, &loc))
+    fatal_with_file_and_line ("missing name or number");
+  return loc;
+}
+
+file_location
+md_reader::read_name_or_nil (struct md_name *name)
+{
+  file_location loc;
+  if (!read_name_1 (name, &loc))
+    {
+      file_location loc = get_current_location ();
+      read_skip_construct (0, loc);
+      /* Skip the ')'.  */
+      read_char ();
+      name->buffer[0] = 0;
+      name->string = name->buffer;
+    }
+  return loc;
 }
 
 /* Subroutine of the string readers.  Handles backslash escapes.
    Caller has read the backslash, but not placed it into the obstack.  */
 
-static void
-read_escape (void)
+void
+md_reader::read_escape ()
 {
   int c = read_char ();
 
@@ -467,31 +579,32 @@ read_escape (void)
     case 'a': case 'b': case 'f': case 'n': case 'r': case 't': case 'v':
     case '0': case '1': case '2': case '3': case '4': case '5': case '6':
     case '7': case 'x':
-      obstack_1grow (&string_obstack, '\\');
+      obstack_1grow (&m_string_obstack, '\\');
       break;
 
       /* \; makes stuff for a C string constant containing
         newline and tab.  */
     case ';':
-      obstack_grow (&string_obstack, "\\n\\t", 4);
+      obstack_grow (&m_string_obstack, "\\n\\t", 4);
       return;
 
       /* 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);
-      obstack_1grow (&string_obstack, '\\');
+              get_filename (), get_lineno (),
+              c);
+      obstack_1grow (&m_string_obstack, '\\');
       break;
     }
 
-  obstack_1grow (&string_obstack, c);
+  obstack_1grow (&m_string_obstack, c);
 }
 
 /* Read a double-quoted string onto the obstack.  Caller has scanned
    the leading quote.  */
 
 char *
-read_quoted_string (void)
+md_reader::read_quoted_string ()
 {
   int c;
 
@@ -506,25 +619,25 @@ read_quoted_string (void)
       else if (c == '"' || c == EOF)
        break;
 
-      obstack_1grow (&string_obstack, c);
+      obstack_1grow (&m_string_obstack, c);
     }
 
-  obstack_1grow (&string_obstack, 0);
-  return XOBFINISH (&string_obstack, char *);
+  obstack_1grow (&m_string_obstack, 0);
+  return XOBFINISH (&m_string_obstack, char *);
 }
 
 /* Read a braced string (a la Tcl) onto the string obstack.  Caller
    has scanned the leading brace.  Note that unlike quoted strings,
    the outermost braces _are_ included in the string constant.  */
 
-static char *
-read_braced_string (void)
+char *
+md_reader::read_braced_string ()
 {
   int c;
   int brace_depth = 1;  /* caller-processed */
-  unsigned long starting_read_md_lineno = read_md_lineno;
+  unsigned long starting_read_md_lineno = get_lineno ();
 
-  obstack_1grow (&string_obstack, '{');
+  obstack_1grow (&m_string_obstack, '{');
   while (brace_depth)
     {
       c = read_char (); /* Read the string  */
@@ -543,11 +656,11 @@ read_braced_string (void)
          ("missing closing } for opening brace on line %lu",
           starting_read_md_lineno);
 
-      obstack_1grow (&string_obstack, c);
+      obstack_1grow (&m_string_obstack, c);
     }
 
-  obstack_1grow (&string_obstack, 0);
-  return XOBFINISH (&string_obstack, char *);
+  obstack_1grow (&m_string_obstack, 0);
+  return XOBFINISH (&m_string_obstack, char *);
 }
 
 /* Read some kind of string constant.  This is the high-level routine
@@ -555,7 +668,7 @@ read_braced_string (void)
    and dispatch to the appropriate string constant reader.  */
 
 char *
-read_string (int star_if_braced)
+md_reader::read_string (int star_if_braced)
 {
   char *stringbuf;
   int saw_paren = 0;
@@ -568,26 +681,30 @@ read_string (int star_if_braced)
       c = read_skip_spaces ();
     }
 
-  old_lineno = read_md_lineno;
+  old_lineno = get_lineno ();
   if (c == '"')
     stringbuf = read_quoted_string ();
   else if (c == '{')
     {
       if (star_if_braced)
-       obstack_1grow (&string_obstack, '*');
+       obstack_1grow (&m_string_obstack, '*');
       stringbuf = read_braced_string ();
     }
+  else if (saw_paren && c == 'n')
+    {
+      /* Handle (nil) by returning NULL.  */
+      require_char ('i');
+      require_char ('l');
+      require_char_ws (')');
+      return NULL;
+    }
   else
     fatal_with_file_and_line ("expected `\"' or `{', found `%c'", c);
 
   if (saw_paren)
-    {
-      c = read_skip_spaces ();
-      if (c != ')')
-       fatal_expected_char (')', c);
-    }
+    require_char_ws (')');
 
-  set_md_ptr_loc (stringbuf, read_md_filename, old_lineno);
+  set_md_ptr_loc (stringbuf, get_filename (), old_lineno);
   return stringbuf;
 }
 
@@ -595,7 +712,7 @@ read_string (int star_if_braced)
    is currently nested by DEPTH levels of parentheses.  */
 
 void
-read_skip_construct (int depth, int lineno)
+md_reader::read_skip_construct (int depth, file_location loc)
 {
   struct md_name name;
   int c;
@@ -605,7 +722,7 @@ read_skip_construct (int depth, int lineno)
       c = read_skip_spaces ();
       if (c == EOF)
        {
-         error_with_line (lineno, "unterminated construct");
+         error_at (loc, "unterminated construct");
          exit (1);
        }
       switch (c)
@@ -736,19 +853,17 @@ add_constant (htab_t defs, char *name, char *value,
 /* Process a define_constants directive, starting with the optional space
    after the "define_constants".  */
 
-static void
-handle_constants (void)
+void
+md_reader::handle_constants ()
 {
   int c;
   htab_t defs;
 
-  c = read_skip_spaces ();
-  if (c != '[')
-    fatal_expected_char ('[', c);
+  require_char_ws ('[');
 
   /* Disable constant expansion during definition processing.  */
-  defs = md_constants;
-  md_constants = 0;
+  defs = m_md_constants;
+  m_md_constants = 0;
   while ( (c = read_skip_spaces ()) != ']')
     {
       struct md_name name, value;
@@ -760,11 +875,9 @@ handle_constants (void)
       read_name (&value);
       add_constant (defs, xstrdup (name.string), xstrdup (value.string), 0);
 
-      c = read_skip_spaces ();
-      if (c != ')')
-       fatal_expected_char (')', c);
+      require_char_ws (')');
     }
-  md_constants = defs;
+  m_md_constants = defs;
 }
 
 /* For every constant definition, call CALLBACK with two arguments:
@@ -772,15 +885,15 @@ handle_constants (void)
    Stop when CALLBACK returns zero.  */
 
 void
-traverse_md_constants (htab_trav callback, void *info)
+md_reader::traverse_md_constants (htab_trav callback, void *info)
 {
-  htab_traverse (md_constants, callback, info);
+  htab_traverse (get_md_constants (), callback, info);
 }
 
 /* Return a malloc()ed decimal string that represents number NUMBER.  */
 
 static char *
-decimal_string (int number)
+md_decimal_string (int number)
 {
   /* A safe overestimate.  +1 for sign, +1 for null terminator.  */
   char buffer[sizeof (int) * CHAR_BIT + 1 + 1];
@@ -794,8 +907,8 @@ decimal_string (int number)
    number on which the directive started and MD_P is true if the
    directive is a define_enum rather than a define_c_enum.  */
 
-static void
-handle_enum (int lineno, bool md_p)
+void
+md_reader::handle_enum (file_location loc, bool md_p)
 {
   char *enum_name, *value_name;
   struct md_name name;
@@ -805,13 +918,13 @@ handle_enum (int lineno, bool md_p)
   int c;
 
   enum_name = read_string (false);
-  slot = htab_find_slot (enum_types, &enum_name, INSERT);
+  slot = htab_find_slot (m_enum_types, &enum_name, INSERT);
   if (*slot)
     {
       def = (struct enum_type *) *slot;
       if (def->md_p != md_p)
-       error_with_line (lineno, "redefining `%s' as a different type of enum",
-                        enum_name);
+       error_at (loc, "redefining `%s' as a different type of enum",
+                 enum_name);
     }
   else
     {
@@ -824,15 +937,13 @@ handle_enum (int lineno, bool md_p)
       *slot = def;
     }
 
-  c = read_skip_spaces ();
-  if (c != '[')
-    fatal_expected_char ('[', c);
+  require_char_ws ('[');
 
   while ((c = read_skip_spaces ()) != ']')
     {
       if (c == EOF)
        {
-         error_with_line (lineno, "unterminated construct");
+         error_at (loc, "unterminated construct");
          exit (1);
        }
       unread_char (c);
@@ -851,8 +962,8 @@ handle_enum (int lineno, bool md_p)
          value_name = xstrdup (name.string);
          ev->name = value_name;
        }
-      ev->def = add_constant (md_constants, value_name,
-                             decimal_string (def->num_values), def);
+      ev->def = add_constant (get_md_constants (), value_name,
+                             md_decimal_string (def->num_values), def);
 
       *def->tail_ptr = ev;
       def->tail_ptr = &ev->next;
@@ -863,9 +974,9 @@ handle_enum (int lineno, bool md_p)
 /* Try to find the definition of the given enum.  Return null on failure.  */
 
 struct enum_type *
-lookup_enum_type (const char *name)
+md_reader::lookup_enum_type (const char *name)
 {
-  return (struct enum_type *) htab_find (enum_types, &name);
+  return (struct enum_type *) htab_find (m_enum_types, &name);
 }
 
 /* For every enum definition, call CALLBACK with two arguments:
@@ -873,9 +984,71 @@ lookup_enum_type (const char *name)
    returns zero.  */
 
 void
-traverse_enum_types (htab_trav callback, void *info)
+md_reader::traverse_enum_types (htab_trav callback, void *info)
+{
+  htab_traverse (m_enum_types, callback, info);
+}
+
+
+/* Constructor for md_reader.  */
+
+md_reader::md_reader (bool compact)
+: m_compact (compact),
+  m_toplevel_fname (NULL),
+  m_base_dir (NULL),
+  m_read_md_file (NULL),
+  m_read_md_filename (NULL),
+  m_read_md_lineno (0),
+  m_read_md_colno (0),
+  m_first_dir_md_include (NULL),
+  m_last_dir_md_include_ptr (&m_first_dir_md_include),
+  m_first_line (0),
+  m_last_line (0),
+  m_first_overload (NULL),
+  m_next_overload_ptr (&m_first_overload),
+  m_overloads_htab (NULL)
 {
-  htab_traverse (enum_types, callback, info);
+  /* Set the global singleton pointer.  */
+  md_reader_ptr = this;
+
+  obstack_init (&m_string_obstack);
+
+  m_ptr_locs = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
+  obstack_init (&m_ptr_loc_obstack);
+
+  m_joined_conditions = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
+  obstack_init (&m_joined_conditions_obstack);
+
+  m_md_constants = htab_create (31, leading_string_hash,
+                               leading_string_eq_p, (htab_del) 0);
+
+  m_enum_types = htab_create (31, leading_string_hash,
+                             leading_string_eq_p, (htab_del) 0);
+
+  /* Unlock the stdio streams.  */
+  unlock_std_streams ();
+}
+
+/* md_reader's destructor.  */
+
+md_reader::~md_reader ()
+{
+  free (m_base_dir);
+
+  htab_delete (m_enum_types);
+
+  htab_delete (m_md_constants);
+
+  obstack_free (&m_joined_conditions_obstack, NULL);
+  htab_delete (m_joined_conditions);
+
+  obstack_free (&m_ptr_loc_obstack, NULL);
+  htab_delete (m_ptr_locs);
+
+  obstack_free (&m_string_obstack, NULL);
+
+  /* Clear the global singleton pointer.  */
+  md_reader_ptr = NULL;
 }
 
 /* Process an "include" directive, starting with the optional space
@@ -883,12 +1056,12 @@ traverse_enum_types (htab_trav callback, void *info)
    to process each unknown directive.  LINENO is the line number on
    which the "include" occurred.  */
 
-static void
-handle_include (int lineno, directive_handler_t handle_directive)
+void
+md_reader::handle_include (file_location loc)
 {
   const char *filename;
   const char *old_filename;
-  int old_lineno;
+  int old_lineno, old_colno;
   char *pathname;
   FILE *input_file, *old_file;
 
@@ -901,7 +1074,7 @@ handle_include (int lineno, 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' };
 
@@ -917,8 +1090,8 @@ handle_include (int lineno, 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");
@@ -927,28 +1100,31 @@ handle_include (int lineno, directive_handler_t handle_directive)
   if (input_file == NULL)
     {
       free (pathname);
-      error_with_line (lineno, "include file `%s' not found", filename);
+      error_at (loc, "include file `%s' not found", filename);
       return;
     }
 
   /* 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;
+  old_colno = m_read_md_colno;
 
   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;
+  m_read_md_colno = old_colno;
 
   /* Do not free the pathname.  It is attached to the various rtx
      queue elements.  */
@@ -958,16 +1134,17 @@ handle_include (int lineno, 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
+md_reader::handle_file ()
 {
   struct md_name directive;
-  int c, lineno;
+  int c;
 
-  read_md_lineno = 1;
+  m_read_md_lineno = 1;
+  m_read_md_colno = 0;
   while ((c = read_skip_spaces ()) != EOF)
     {
-      lineno = read_md_lineno;
+      file_location loc = get_current_location ();
       if (c != '(')
        fatal_expected_char ('(', c);
 
@@ -975,57 +1152,59 @@ handle_file (directive_handler_t handle_directive)
       if (strcmp (directive.string, "define_constants") == 0)
        handle_constants ();
       else if (strcmp (directive.string, "define_enum") == 0)
-       handle_enum (lineno, true);
+       handle_enum (loc, true);
       else if (strcmp (directive.string, "define_c_enum") == 0)
-       handle_enum (lineno, false);
+       handle_enum (loc, false);
       else if (strcmp (directive.string, "include") == 0)
-       handle_include (lineno, handle_directive);
-      else if (handle_directive)
-       handle_directive (lineno, directive.string);
+       handle_include (loc);
       else
-       read_skip_construct (1, lineno);
+       handle_unknown_directive (loc, directive.string);
 
-      c = read_skip_spaces ();
-      if (c != ')')
-       fatal_expected_char (')', c);
+      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
+md_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
+md_reader::get_current_location () const
+{
+  return file_location (m_read_md_filename, m_read_md_lineno, m_read_md_colno);
 }
 
 /* Parse a -I option with argument ARG.  */
 
-static void
-parse_include (const char *arg)
+void
+md_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;
 }
 
+#ifdef GENERATOR_FILE
+
 /* The main routine for reading .md files.  Try to process all the .md
    files specified on the command line and return true if no error occurred.
 
@@ -1033,36 +1212,17 @@ 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, char **argv, bool (*parse_opt) (const char *),
-              directive_handler_t handle_directive)
+md_reader::read_md_files (int argc, const char **argv,
+                         bool (*parse_opt) (const char *))
 {
   int i;
   bool no_more_options;
   bool already_read_stdin;
   int num_files;
 
-  /* Initialize global data.  */
-  obstack_init (&string_obstack);
-  ptr_locs = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
-  obstack_init (&ptr_loc_obstack);
-  joined_conditions = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
-  obstack_init (&joined_conditions_obstack);
-  md_constants = htab_create (31, leading_string_hash,
-                             leading_string_eq_p, (htab_del) 0);
-  enum_types = htab_create (31, leading_string_hash,
-                           leading_string_eq_p, (htab_del) 0);
-
-  /* Unlock the stdio streams.  */
-  unlock_std_streams ();
-
   /* First we loop over all the options.  */
   for (i = 1; i < argc; i++)
     if (argv[i][0] == '-')
@@ -1080,9 +1240,9 @@ read_md_files (int argc, 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;
@@ -1110,9 +1270,9 @@ read_md_files (int argc, 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;
            }
@@ -1128,14 +1288,14 @@ read_md_files (int argc, 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++;
     }
 
@@ -1143,10 +1303,57 @@ read_md_files (int argc, 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;
 }
+
+#endif /* #ifdef GENERATOR_FILE */
+
+/* Read FILENAME.  */
+
+bool
+md_reader::read_file (const char *filename)
+{
+  m_read_md_filename = filename;
+  m_read_md_file = fopen (m_read_md_filename, "r");
+  if (m_read_md_file == 0)
+    {
+      perror (m_read_md_filename);
+      return false;
+    }
+  handle_toplevel_file ();
+  return !have_error;
+}
+
+/* Read FILENAME, filtering to just the given lines.  */
+
+bool
+md_reader::read_file_fragment (const char *filename,
+                              int first_line,
+                              int last_line)
+{
+  m_read_md_filename = filename;
+  m_read_md_file = fopen (m_read_md_filename, "r");
+  if (m_read_md_file == 0)
+    {
+      perror (m_read_md_filename);
+      return false;
+    }
+  m_first_line = first_line;
+  m_last_line = last_line;
+  handle_toplevel_file ();
+  return !have_error;
+}
+
+/* class noop_reader : public md_reader */
+
+/* A dummy implementation which skips unknown directives.  */
+void
+noop_reader::handle_unknown_directive (file_location loc, const char *)
+{
+  read_skip_construct (1, loc);
+}