LCOV - code coverage report
Current view: top level - gcc - read-md.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 40.6 % 567 230
Test Date: 2026-02-28 14:20:25 Functions: 42.6 % 54 23
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* MD reader for GCC.
       2              :    Copyright (C) 1987-2026 Free Software Foundation, Inc.
       3              : 
       4              : This file is part of GCC.
       5              : 
       6              : GCC is free software; you can redistribute it and/or modify it under
       7              : the terms of the GNU General Public License as published by the Free
       8              : Software Foundation; either version 3, or (at your option) any later
       9              : version.
      10              : 
      11              : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      12              : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13              : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14              : for more details.
      15              : 
      16              : You should have received a copy of the GNU General Public License
      17              : along with GCC; see the file COPYING3.  If not see
      18              : <http://www.gnu.org/licenses/>.  */
      19              : 
      20              : /* This file is compiled twice: once for the generator programs
      21              :    once for the compiler.  */
      22              : #ifdef GENERATOR_FILE
      23              : #include "bconfig.h"
      24              : #else
      25              : #include "config.h"
      26              : #endif
      27              : #include "system.h"
      28              : #include "coretypes.h"
      29              : #ifdef GENERATOR_FILE
      30              : #include "errors.h"
      31              : #endif /* #ifdef GENERATOR_FILE */
      32              : #include "statistics.h"
      33              : #include "vec.h"
      34              : #include "read-md.h"
      35              : 
      36              : #ifndef GENERATOR_FILE
      37              : 
      38              : /* Minimal reimplementation of errors.cc for use by RTL frontend
      39              :    within cc1.  */
      40              : 
      41              : int have_error = 0;
      42              : 
      43              : #endif /* #ifndef GENERATOR_FILE */
      44              : 
      45              : 
      46              : /* This callback will be invoked whenever an md include directive is
      47              :    processed.  To be used for creation of the dependency file.  */
      48              : void (*include_callback) (const char *);
      49              : 
      50              : /* Global singleton.  */
      51              : 
      52              : md_reader *md_reader_ptr;
      53              : 
      54              : /* Given an object that starts with a char * name field, return a hash
      55              :    code for its name.  */
      56              : 
      57              : hashval_t
      58         8930 : leading_string_hash (const void *def)
      59              : {
      60         8930 :   return htab_hash_string (*(const char *const *) def);
      61              : }
      62              : 
      63              : /* Given two objects that start with char * name fields, return true if
      64              :    they have the same name.  */
      65              : 
      66              : int
      67            0 : leading_string_eq_p (const void *def1, const void *def2)
      68              : {
      69            0 :   return strcmp (*(const char *const *) def1,
      70            0 :                  *(const char *const *) def2) == 0;
      71              : }
      72              : 
      73              : /* Return a hash value for the pointer pointed to by DEF.  */
      74              : 
      75              : static hashval_t
      76          118 : leading_ptr_hash (const void *def)
      77              : {
      78          118 :   return htab_hash_pointer (*(const void *const *) def);
      79              : }
      80              : 
      81              : /* Return true if DEF1 and DEF2 are pointers to the same pointer.  */
      82              : 
      83              : static int
      84            1 : leading_ptr_eq_p (const void *def1, const void *def2)
      85              : {
      86            1 :   return *(const void *const *) def1 == *(const void *const *) def2;
      87              : }
      88              : 
      89              : /* Associate PTR with the file position given by FILE_LOC.  */
      90              : 
      91              : void
      92          118 : md_reader::set_md_ptr_loc (const void *ptr, file_location file_loc)
      93              : {
      94          118 :   struct ptr_loc *loc;
      95              : 
      96          118 :   loc = (struct ptr_loc *) obstack_alloc (&m_ptr_loc_obstack,
      97              :                                           sizeof (struct ptr_loc));
      98          118 :   loc->ptr = ptr;
      99          118 :   loc->loc = file_loc;
     100          118 :   *htab_find_slot (m_ptr_locs, loc, INSERT) = loc;
     101          118 : }
     102              : 
     103              : /* Return the position associated with pointer PTR.  Return null if no
     104              :    position was set.  */
     105              : 
     106              : const md_reader::ptr_loc *
     107            0 : md_reader::get_md_ptr_loc (const void *ptr)
     108              : {
     109            0 :   return (const struct ptr_loc *) htab_find (m_ptr_locs, &ptr);
     110              : }
     111              : 
     112              : /* Associate NEW_PTR with the same file position as OLD_PTR.  */
     113              : 
     114              : void
     115            0 : md_reader::copy_md_ptr_loc (const void *new_ptr, const void *old_ptr)
     116              : {
     117            0 :   const struct ptr_loc *loc = get_md_ptr_loc (old_ptr);
     118            0 :   if (loc != 0)
     119            0 :     set_md_ptr_loc (new_ptr, loc->loc);
     120            0 : }
     121              : 
     122              : /* If PTR is associated with a known file position, print a #line
     123              :    directive for it to OUTF.  */
     124              : 
     125              : void
     126            0 : md_reader::fprint_md_ptr_loc (FILE *outf, const void *ptr)
     127              : {
     128            0 :   const struct ptr_loc *loc = get_md_ptr_loc (ptr);
     129            0 :   if (loc != 0)
     130            0 :     fprintf (outf, "#line %d \"%s\"\n", loc->loc.lineno, loc->loc.filename);
     131            0 : }
     132              : 
     133              : /* Special fprint_md_ptr_loc for writing to STDOUT.  */
     134              : void
     135            0 : md_reader::print_md_ptr_loc (const void *ptr, FILE *file)
     136              : {
     137            0 :   fprint_md_ptr_loc (file, ptr);
     138            0 : }
     139              : 
     140              : /* Return a condition that satisfies both COND1 and COND2.  Either string
     141              :    may be null or empty.  */
     142              : 
     143              : const char *
     144            0 : md_reader::join_c_conditions (const char *cond1, const char *cond2)
     145              : {
     146            0 :   char *result;
     147            0 :   const void **entry;
     148              : 
     149            0 :   if (cond1 == 0 || cond1[0] == 0)
     150              :     return cond2;
     151              : 
     152            0 :   if (cond2 == 0 || cond2[0] == 0)
     153              :     return cond1;
     154              : 
     155            0 :   if (strcmp (cond1, cond2) == 0)
     156              :     return cond1;
     157              : 
     158            0 :   result = concat ("(", cond1, ") && (", cond2, ")", NULL);
     159            0 :   obstack_ptr_grow (&m_joined_conditions_obstack, result);
     160            0 :   obstack_ptr_grow (&m_joined_conditions_obstack, cond1);
     161            0 :   obstack_ptr_grow (&m_joined_conditions_obstack, cond2);
     162            0 :   entry = XOBFINISH (&m_joined_conditions_obstack, const void **);
     163            0 :   *htab_find_slot (m_joined_conditions, entry, INSERT) = entry;
     164            0 :   return result;
     165              : }
     166              : 
     167              : /* Print condition COND to OUTF, wrapped in brackets.  If COND was created
     168              :    by join_c_conditions, recursively invoke this function for the original
     169              :    conditions and join the result with "&&".  Otherwise print a #line
     170              :    directive for COND if its original file position is known.  */
     171              : 
     172              : void
     173            0 : md_reader::fprint_c_condition (FILE *outf, const char *cond)
     174              : {
     175            0 :   const char **halves = (const char **) htab_find (m_joined_conditions, &cond);
     176            0 :   if (halves != 0)
     177              :     {
     178            0 :       fprintf (outf, "(");
     179            0 :       fprint_c_condition (outf, halves[1]);
     180            0 :       fprintf (outf, " && ");
     181            0 :       fprint_c_condition (outf, halves[2]);
     182            0 :       fprintf (outf, ")");
     183              :     }
     184              :   else
     185              :     {
     186            0 :       fputc ('\n', outf);
     187            0 :       fprint_md_ptr_loc (outf, cond);
     188            0 :       fprintf (outf, "(%s)", cond);
     189              :     }
     190            0 : }
     191              : 
     192              : /* Special fprint_c_condition for writing to STDOUT.  */
     193              : 
     194              : void
     195            0 : md_reader::print_c_condition (FILE *outf, const char *cond)
     196              : {
     197            0 :   fprint_c_condition (outf, cond);
     198            0 : }
     199              : 
     200              : /* A vfprintf-like function for reporting an error against line LINENO
     201              :    of the current MD file.  */
     202              : 
     203              : static void ATTRIBUTE_PRINTF(2,0)
     204            0 : message_at_1 (file_location loc, const char *msg, va_list ap)
     205              : {
     206            0 :   fprintf (stderr, "%s:%d:%d: ", loc.filename, loc.lineno, loc.colno);
     207            0 :   vfprintf (stderr, msg, ap);
     208            0 :   fputc ('\n', stderr);
     209            0 : }
     210              : 
     211              : /* A printf-like function for reporting a message against location LOC.  */
     212              : 
     213              : void
     214            0 : message_at (file_location loc, const char *msg, ...)
     215              : {
     216            0 :   va_list ap;
     217              : 
     218            0 :   va_start (ap, msg);
     219            0 :   message_at_1 (loc, msg, ap);
     220            0 :   va_end (ap);
     221            0 : }
     222              : 
     223              : /* Like message_at, but treat the condition as an error.  */
     224              : 
     225              : void
     226            0 : error_at (file_location loc, const char *msg, ...)
     227              : {
     228            0 :   va_list ap;
     229              : 
     230            0 :   va_start (ap, msg);
     231            0 :   message_at_1 (loc, msg, ap);
     232            0 :   va_end (ap);
     233            0 :   have_error = 1;
     234            0 : }
     235              : 
     236              : /* Like message_at, but treat the condition as a fatal error.  */
     237              : 
     238              : void
     239            0 : fatal_at (file_location loc, const char *msg, ...)
     240              : {
     241            0 :   va_list ap;
     242              : 
     243            0 :   va_start (ap, msg);
     244            0 :   message_at_1 (loc, msg, ap);
     245            0 :   va_end (ap);
     246            0 :   exit (1);
     247              : }
     248              : 
     249              : /* A printf-like function for reporting an error against the current
     250              :    position in the MD file.  */
     251              : 
     252              : void
     253            1 : fatal_with_file_and_line (const char *msg, ...)
     254              : {
     255            1 :   char context[64];
     256            1 :   size_t i;
     257            1 :   int c;
     258            1 :   va_list ap;
     259              : 
     260            1 :   va_start (ap, msg);
     261              : 
     262            1 :   fprintf (stderr, "%s:%d:%d: error: ", md_reader_ptr->get_filename (),
     263              :            md_reader_ptr->get_lineno (),
     264              :            md_reader_ptr->get_colno ());
     265            1 :   vfprintf (stderr, msg, ap);
     266            1 :   putc ('\n', stderr);
     267              : 
     268              :   /* Gather some following context.  */
     269           43 :   for (i = 0; i < sizeof (context)-1; ++i)
     270              :     {
     271           42 :       c = read_char ();
     272           42 :       if (c == EOF)
     273              :         break;
     274           42 :       if (c == '\r' || c == '\n')
     275              :         {
     276            1 :           unread_char (c);
     277            1 :           break;
     278              :         }
     279           41 :       context[i] = c;
     280              :     }
     281            1 :   context[i] = '\0';
     282              : 
     283            1 :   fprintf (stderr, "%s:%d:%d: note: following context is `%s'\n",
     284              :            md_reader_ptr->get_filename (),
     285              :            md_reader_ptr->get_lineno (),
     286              :            md_reader_ptr->get_colno (), context);
     287              : 
     288            1 :   va_end (ap);
     289            1 :   exit (1);
     290              : }
     291              : 
     292              : /* Report that we found character ACTUAL when we expected to find
     293              :    character EXPECTED.  */
     294              : 
     295              : void
     296            0 : fatal_expected_char (int expected, int actual)
     297              : {
     298            0 :   if (actual == EOF)
     299            0 :     fatal_with_file_and_line ("expected character `%c', found EOF",
     300              :                               expected);
     301              :   else
     302            0 :     fatal_with_file_and_line ("expected character `%c', found `%c'",
     303              :                               expected, actual);
     304              : }
     305              : 
     306              : /* Read chars from the MD file until a non-whitespace char and return that.
     307              :    Comments, both Lisp style and C style, are treated as whitespace.  */
     308              : 
     309              : int
     310        21427 : read_skip_spaces (void)
     311              : {
     312        58399 :   int c;
     313              : 
     314        58399 :   while (1)
     315              :     {
     316        58399 :       c = read_char ();
     317        58399 :       switch (c)
     318              :         {
     319              :         case ' ': case '\t': case '\f': case '\r': case '\n':
     320              :           break;
     321              : 
     322         5390 :         case ';':
     323         5390 :           do
     324         5390 :             c = read_char ();
     325         5390 :           while (c != '\n' && c != EOF);
     326              :           break;
     327              : 
     328            4 :         case '/':
     329            4 :           {
     330            4 :             int prevc;
     331            4 :             c = read_char ();
     332            4 :             if (c != '*')
     333              :               {
     334            0 :                 unread_char (c);
     335            0 :                 fatal_with_file_and_line ("stray '/' in file");
     336              :               }
     337              : 
     338              :             prevc = 0;
     339          580 :             while ((c = read_char ()) && c != EOF)
     340              :               {
     341          580 :                 if (prevc == '*' && c == '/')
     342              :                   break;
     343              :                 prevc = c;
     344              :               }
     345              :           }
     346              :           break;
     347              : 
     348        21427 :         default:
     349        21427 :           return c;
     350              :         }
     351              :     }
     352              : }
     353              : 
     354              : /* Consume the next character, issuing a fatal error if it is not
     355              :    EXPECTED.  */
     356              : 
     357              : void
     358          582 : md_reader::require_char (char expected)
     359              : {
     360          582 :   int ch = read_char ();
     361          582 :   if (ch != expected)
     362            0 :     fatal_expected_char (expected, ch);
     363          582 : }
     364              : 
     365              : /* Consume any whitespace, then consume the next non-whitespace
     366              :    character, issuing a fatal error if it is not EXPECTED.  */
     367              : 
     368              : void
     369         5521 : md_reader::require_char_ws (char expected)
     370              : {
     371         5521 :   int ch = read_skip_spaces ();
     372         5521 :   if (ch != expected)
     373            0 :     fatal_expected_char (expected, ch);
     374         5521 : }
     375              : 
     376              : /* Consume any whitespace, then consume the next word (as per read_name),
     377              :    issuing a fatal error if it is not EXPECTED.  */
     378              : 
     379              : void
     380          300 : md_reader::require_word_ws (const char *expected)
     381              : {
     382          300 :   struct md_name name;
     383          300 :   read_name (&name);
     384          300 :   if (strcmp (name.string, expected))
     385            0 :     fatal_with_file_and_line ("missing '%s'", expected);
     386          300 : }
     387              : 
     388              : /* Read the next character from the file.  */
     389              : 
     390              : int
     391       113320 : md_reader::read_char (void)
     392              : {
     393       113320 :   int ch;
     394              : 
     395       113320 :   ch = getc (m_read_md_file);
     396       113320 :   if (ch == '\n')
     397              :     {
     398         3295 :       m_read_md_lineno++;
     399         3295 :       m_last_line_colno = m_read_md_colno;
     400         3295 :       m_read_md_colno = 0;
     401              :     }
     402              :   else
     403       110025 :     m_read_md_colno++;
     404              : 
     405              :   /* If we're filtering lines, treat everything before the range of
     406              :      interest as a space, and as EOF for everything after.  */
     407       113320 :   if (m_first_line && m_last_line)
     408              :     {
     409        72524 :       if (m_read_md_lineno < m_first_line)
     410              :         return ' ';
     411        58983 :       if (m_read_md_lineno > m_last_line)
     412           38 :         return EOF;
     413              :     }
     414              : 
     415              :   return ch;
     416              : }
     417              : 
     418              : /* Put back CH, which was the last character read from the file.  */
     419              : 
     420              : void
     421        12371 : md_reader::unread_char (int ch)
     422              : {
     423        12371 :   if (ch == '\n')
     424              :     {
     425          453 :       m_read_md_lineno--;
     426          453 :       m_read_md_colno = m_last_line_colno;
     427              :     }
     428              :   else
     429        11918 :     m_read_md_colno--;
     430        12371 :   ungetc (ch, m_read_md_file);
     431        12371 : }
     432              : 
     433              : /* Peek at the next character from the file without consuming it.  */
     434              : 
     435              : int
     436         2320 : md_reader::peek_char (void)
     437              : {
     438         2320 :   int ch = read_char ();
     439         2320 :   unread_char (ch);
     440         2320 :   return ch;
     441              : }
     442              : 
     443              : /* Read an rtx code name into NAME.  It is terminated by any of the
     444              :    punctuation chars of rtx printed syntax.  */
     445              : 
     446              : bool
     447         7310 : md_reader::read_name_1 (struct md_name *name, file_location *out_loc)
     448              : {
     449         7310 :   int c;
     450         7310 :   size_t i;
     451         7310 :   int angle_bracket_depth;
     452              : 
     453         7310 :   c = read_skip_spaces ();
     454              : 
     455         7310 :   *out_loc = get_current_location ();
     456              : 
     457         7310 :   i = 0;
     458         7310 :   angle_bracket_depth = 0;
     459        65976 :   while (1)
     460              :     {
     461        36643 :       if (c == '<')
     462          291 :         angle_bracket_depth++;
     463              : 
     464        36643 :       if ((c == '>') && (angle_bracket_depth > 0))
     465          291 :           angle_bracket_depth--;
     466              : 
     467        36643 :       if (c == ' ' || c == '\n' || c == '\t' || c == '\f' || c == '\r'
     468              :           || c == EOF)
     469              :         break;
     470        31897 :       if (angle_bracket_depth == 0)
     471              :         {
     472        31289 :           if (c == ':' || c == ')' || c == ']'
     473              :               || c == '"' || c == '/' || c == '(' || c == '[')
     474              :             {
     475         2564 :               unread_char (c);
     476         2564 :               break;
     477              :             }
     478              :         }
     479              : 
     480        29333 :       if (i == sizeof (name->buffer) - 1)
     481            0 :         fatal_with_file_and_line ("name too long");
     482        29333 :       name->buffer[i++] = c;
     483              : 
     484        29333 :       c = read_char ();
     485              :     }
     486              : 
     487         7310 :   if (i == 0)
     488              :     return false;
     489              : 
     490         7310 :   name->buffer[i] = 0;
     491         7310 :   name->string = name->buffer;
     492              : 
     493         7310 :   if (m_md_constants)
     494              :     {
     495              :       /* Do constant expansion.  */
     496         7310 :       struct md_constant *def;
     497              : 
     498         7310 :       do
     499              :         {
     500         7310 :           struct md_constant tmp_def;
     501              : 
     502         7310 :           tmp_def.name = name->string;
     503         7310 :           def = (struct md_constant *) htab_find (m_md_constants, &tmp_def);
     504         7310 :           if (def)
     505            0 :             name->string = def->value;
     506              :         }
     507         7310 :       while (def);
     508              :     }
     509              : 
     510              :   return true;
     511              : }
     512              : 
     513              : /* Read an rtx code name into NAME.  It is terminated by any of the
     514              :    punctuation chars of rtx printed syntax.  */
     515              : 
     516              : file_location
     517         7310 : md_reader::read_name (struct md_name *name)
     518              : {
     519         7310 :   file_location loc;
     520         7310 :   if (!read_name_1 (name, &loc))
     521            0 :     fatal_with_file_and_line ("missing name or number");
     522         7310 :   return loc;
     523              : }
     524              : 
     525              : file_location
     526            0 : md_reader::read_name_or_nil (struct md_name *name)
     527              : {
     528            0 :   file_location loc;
     529            0 :   if (!read_name_1 (name, &loc))
     530              :     {
     531            0 :       file_location loc = get_current_location ();
     532            0 :       read_skip_construct (0, loc);
     533              :       /* Skip the ')'.  */
     534            0 :       read_char ();
     535            0 :       name->buffer[0] = 0;
     536            0 :       name->string = name->buffer;
     537              :     }
     538            0 :   return loc;
     539              : }
     540              : 
     541              : /* Subroutine of the string readers.  Handles backslash escapes.
     542              :    Caller has read the backslash, but not placed it into the obstack.  */
     543              : 
     544              : void
     545            0 : md_reader::read_escape ()
     546              : {
     547            0 :   int c = read_char ();
     548              : 
     549            0 :   switch (c)
     550              :     {
     551              :       /* Backslash-newline is replaced by nothing, as in C.  */
     552              :     case '\n':
     553              :       return;
     554              : 
     555              :       /* \" \' \\ are replaced by the second character.  */
     556              :     case '\\':
     557              :     case '"':
     558              :     case '\'':
     559              :       break;
     560              : 
     561              :       /* Standard C string escapes:
     562              :          \a \b \f \n \r \t \v
     563              :          \[0-7] \x
     564              :          all are passed through to the output string unmolested.
     565              :          In normal use these wind up in a string constant processed
     566              :          by the C compiler, which will translate them appropriately.
     567              :          We do not bother checking that \[0-7] are followed by up to
     568              :          two octal digits, or that \x is followed by N hex digits.
     569              :          \? \u \U are left out because they are not in traditional C.  */
     570            0 :     case 'a': case 'b': case 'f': case 'n': case 'r': case 't': case 'v':
     571            0 :     case '0': case '1': case '2': case '3': case '4': case '5': case '6':
     572            0 :     case '7': case 'x':
     573            0 :       obstack_1grow (&m_string_obstack, '\\');
     574            0 :       break;
     575              : 
     576              :       /* \; makes stuff for a C string constant containing
     577              :          newline and tab.  */
     578            0 :     case ';':
     579            0 :       obstack_grow (&m_string_obstack, "\\n\\t", 4);
     580            0 :       return;
     581              : 
     582              :       /* pass anything else through, but issue a warning.  */
     583            0 :     default:
     584            0 :       fprintf (stderr, "%s:%d: warning: unrecognized escape \\%c\n",
     585              :                get_filename (), get_lineno (),
     586              :                c);
     587            0 :       obstack_1grow (&m_string_obstack, '\\');
     588            0 :       break;
     589              :     }
     590              : 
     591            0 :   obstack_1grow (&m_string_obstack, c);
     592              : }
     593              : 
     594              : /* Read a double-quoted string onto the obstack.  Caller has scanned
     595              :    the leading quote.  */
     596              : 
     597              : char *
     598          605 : md_reader::read_quoted_string ()
     599              : {
     600        11654 :   int c;
     601              : 
     602        11654 :   while (1)
     603              :     {
     604        11654 :       c = read_char (); /* Read the string  */
     605        11654 :       if (c == '\\')
     606              :         {
     607            0 :           read_escape ();
     608            0 :           continue;
     609              :         }
     610        11654 :       else if (c == '"' || c == EOF)
     611              :         break;
     612              : 
     613        11049 :       obstack_1grow (&m_string_obstack, c);
     614              :     }
     615              : 
     616          605 :   obstack_1grow (&m_string_obstack, 0);
     617          605 :   return XOBFINISH (&m_string_obstack, char *);
     618              : }
     619              : 
     620              : /* Read a braced string (a la Tcl) onto the string obstack.  Caller
     621              :    has scanned the leading brace.  Note that unlike quoted strings,
     622              :    the outermost braces _are_ included in the string constant.  */
     623              : 
     624              : char *
     625            0 : md_reader::read_braced_string ()
     626              : {
     627            0 :   int c;
     628            0 :   int brace_depth = 1;  /* caller-processed */
     629            0 :   unsigned long starting_read_md_lineno = get_lineno ();
     630              : 
     631            0 :   obstack_1grow (&m_string_obstack, '{');
     632            0 :   while (brace_depth)
     633              :     {
     634            0 :       c = read_char (); /* Read the string  */
     635              : 
     636            0 :       if (c == '{')
     637            0 :         brace_depth++;
     638            0 :       else if (c == '}')
     639            0 :         brace_depth--;
     640            0 :       else if (c == '\\')
     641              :         {
     642            0 :           read_escape ();
     643            0 :           continue;
     644              :         }
     645            0 :       else if (c == EOF)
     646            0 :         fatal_with_file_and_line
     647            0 :           ("missing closing } for opening brace on line %lu",
     648              :            starting_read_md_lineno);
     649              : 
     650            0 :       obstack_1grow (&m_string_obstack, c);
     651              :     }
     652              : 
     653            0 :   obstack_1grow (&m_string_obstack, 0);
     654            0 :   return XOBFINISH (&m_string_obstack, char *);
     655              : }
     656              : 
     657              : /* Read some kind of string constant.  This is the high-level routine
     658              :    used by read_rtx.  It handles surrounding parentheses, leading star,
     659              :    and dispatch to the appropriate string constant reader.  */
     660              : 
     661              : char *
     662          126 : md_reader::read_string (int star_if_braced)
     663              : {
     664          126 :   char *stringbuf;
     665          126 :   int saw_paren = 0;
     666          126 :   int c;
     667              : 
     668          126 :   c = read_skip_spaces ();
     669          126 :   if (c == '(')
     670              :     {
     671           26 :       saw_paren = 1;
     672           26 :       c = read_skip_spaces ();
     673              :     }
     674              : 
     675          126 :   file_location loc = get_current_location ();
     676          126 :   if (c == '"')
     677          118 :     stringbuf = read_quoted_string ();
     678            8 :   else if (c == '{')
     679              :     {
     680            0 :       if (star_if_braced)
     681            0 :         obstack_1grow (&m_string_obstack, '*');
     682            0 :       stringbuf = read_braced_string ();
     683              :     }
     684            8 :   else if (saw_paren && c == 'n')
     685              :     {
     686              :       /* Handle (nil) by returning NULL.  */
     687            8 :       require_char ('i');
     688            8 :       require_char ('l');
     689            8 :       require_char_ws (')');
     690            8 :       return NULL;
     691              :     }
     692              :   else
     693            0 :     fatal_with_file_and_line ("expected `\"' or `{', found `%c'", c);
     694              : 
     695          118 :   if (saw_paren)
     696           18 :     require_char_ws (')');
     697              : 
     698          118 :   set_md_ptr_loc (stringbuf, loc);
     699          118 :   return stringbuf;
     700              : }
     701              : 
     702              : /* Skip the rest of a construct that started at line LINENO and that
     703              :    is currently nested by DEPTH levels of parentheses.  */
     704              : 
     705              : void
     706            0 : md_reader::read_skip_construct (int depth, file_location loc)
     707              : {
     708            0 :   struct md_name name;
     709            0 :   int c;
     710              : 
     711            0 :   do
     712              :     {
     713            0 :       c = read_skip_spaces ();
     714            0 :       if (c == EOF)
     715              :         {
     716            0 :           error_at (loc, "unterminated construct");
     717            0 :           exit (1);
     718              :         }
     719            0 :       switch (c)
     720              :         {
     721            0 :         case '(':
     722            0 :           depth++;
     723            0 :           break;
     724              : 
     725            0 :         case ')':
     726            0 :           depth--;
     727            0 :           break;
     728              : 
     729              :         case ':':
     730              :         case '[':
     731              :         case ']':
     732              :         case '/':
     733              :           break;
     734              : 
     735            0 :         case '\"':
     736            0 :         case '{':
     737            0 :           unread_char (c);
     738            0 :           read_string (false);
     739            0 :           break;
     740              : 
     741            0 :         default:
     742            0 :           unread_char (c);
     743            0 :           read_name (&name);
     744            0 :           break;
     745              :         }
     746              :     }
     747            0 :   while (depth > 0);
     748            0 :   unread_char (c);
     749            0 : }
     750              : 
     751              : /* Given a string, return the number of comma-separated elements in it.
     752              :    Return 0 for the null string.  */
     753              : 
     754              : int
     755            0 : n_comma_elts (const char *s)
     756              : {
     757            0 :   int n;
     758              : 
     759            0 :   if (*s == '\0')
     760              :     return 0;
     761              : 
     762            0 :   for (n = 1; *s; s++)
     763            0 :     if (*s == ',')
     764            0 :       n++;
     765              : 
     766              :   return n;
     767              : }
     768              : 
     769              : /* Given a pointer to a (char *), return a pointer to the beginning of the
     770              :    next comma-separated element in the string.  Advance the pointer given
     771              :    to the end of that element.  Return NULL if at end of string.  Caller
     772              :    is responsible for copying the string if necessary.  White space between
     773              :    a comma and an element is ignored.  */
     774              : 
     775              : const char *
     776            0 : scan_comma_elt (const char **pstr)
     777              : {
     778            0 :   const char *start;
     779            0 :   const char *p = *pstr;
     780              : 
     781            0 :   if (*p == ',')
     782            0 :     p++;
     783            0 :   while (ISSPACE (*p))
     784            0 :     p++;
     785              : 
     786            0 :   if (*p == '\0')
     787              :     return NULL;
     788              : 
     789              :   start = p;
     790              : 
     791            0 :   while (*p != ',' && *p != '\0')
     792            0 :     p++;
     793              : 
     794            0 :   *pstr = p;
     795            0 :   return start;
     796              : }
     797              : 
     798              : /* Convert STRING to uppercase.  */
     799              : 
     800              : void
     801            0 : upcase_string (char *string)
     802              : {
     803            0 :   int i;
     804              : 
     805            0 :   for (i = 0; string[i]; i++)
     806            0 :     string[i] = TOUPPER (string[i]);
     807            0 : }
     808              : 
     809              : /* Add a NAME = VALUE definition to md_constants-style hash table DEFS,
     810              :    where both NAME and VALUE are malloc()ed strings.  PARENT_ENUM is the
     811              :    enum to which NAME belongs, or null if NAME is a stand-alone constant.  */
     812              : 
     813              : static struct md_constant *
     814            0 : add_constant (htab_t defs, char *name, char *value,
     815              :               struct enum_type *parent_enum)
     816              : {
     817            0 :   struct md_constant *def, tmp_def;
     818            0 :   void **entry_ptr;
     819              : 
     820            0 :   tmp_def.name = name;
     821            0 :   entry_ptr = htab_find_slot (defs, &tmp_def, INSERT);
     822            0 :   if (*entry_ptr)
     823              :     {
     824            0 :       def = (struct md_constant *) *entry_ptr;
     825            0 :       if (strcmp (def->value, value) != 0)
     826            0 :         fatal_with_file_and_line ("redefinition of `%s', was `%s', now `%s'",
     827              :                                   def->name, def->value, value);
     828            0 :       else if (parent_enum || def->parent_enum)
     829            0 :         fatal_with_file_and_line ("redefinition of `%s'", def->name);
     830            0 :       free (name);
     831            0 :       free (value);
     832              :     }
     833              :   else
     834              :     {
     835            0 :       def = XNEW (struct md_constant);
     836            0 :       def->name = name;
     837            0 :       def->value = value;
     838            0 :       def->parent_enum = parent_enum;
     839            0 :       *entry_ptr = def;
     840              :     }
     841            0 :   return def;
     842              : }
     843              : 
     844              : /* Process a define_constants directive, starting with the optional space
     845              :    after the "define_constants".  */
     846              : 
     847              : void
     848            0 : md_reader::handle_constants ()
     849              : {
     850            0 :   int c;
     851            0 :   htab_t defs;
     852              : 
     853            0 :   require_char_ws ('[');
     854              : 
     855              :   /* Disable constant expansion during definition processing.  */
     856            0 :   defs = m_md_constants;
     857            0 :   m_md_constants = 0;
     858            0 :   while ( (c = read_skip_spaces ()) != ']')
     859              :     {
     860            0 :       struct md_name name, value;
     861              : 
     862            0 :       if (c != '(')
     863            0 :         fatal_expected_char ('(', c);
     864              : 
     865            0 :       read_name (&name);
     866            0 :       read_name (&value);
     867            0 :       add_constant (defs, xstrdup (name.string), xstrdup (value.string), 0);
     868              : 
     869            0 :       require_char_ws (')');
     870              :     }
     871            0 :   m_md_constants = defs;
     872            0 : }
     873              : 
     874              : /* For every constant definition, call CALLBACK with two arguments:
     875              :    a pointer a pointer to the constant definition and INFO.
     876              :    Stop when CALLBACK returns zero.  */
     877              : 
     878              : void
     879            0 : md_reader::traverse_md_constants (htab_trav callback, void *info)
     880              : {
     881            0 :   htab_traverse (get_md_constants (), callback, info);
     882            0 : }
     883              : 
     884              : /* Return a malloc()ed decimal string that represents number NUMBER.  */
     885              : 
     886              : static char *
     887            0 : md_decimal_string (int number)
     888              : {
     889              :   /* A safe overestimate.  +1 for sign, +1 for null terminator.  */
     890            0 :   char buffer[sizeof (int) * CHAR_BIT + 1 + 1];
     891              : 
     892            0 :   sprintf (buffer, "%d", number);
     893            0 :   return xstrdup (buffer);
     894              : }
     895              : 
     896              : /* Process a define_enum or define_c_enum directive, starting with
     897              :    the optional space after the "define_enum".  LINENO is the line
     898              :    number on which the directive started and MD_P is true if the
     899              :    directive is a define_enum rather than a define_c_enum.  */
     900              : 
     901              : void
     902            0 : md_reader::handle_enum (file_location loc, bool md_p)
     903              : {
     904            0 :   char *enum_name, *value_name;
     905            0 :   unsigned int cur_value;
     906            0 :   struct md_name name, value;
     907            0 :   struct enum_type *def;
     908            0 :   struct enum_value *ev;
     909            0 :   void **slot;
     910            0 :   int c;
     911              : 
     912            0 :   enum_name = read_string (false);
     913            0 :   slot = htab_find_slot (m_enum_types, &enum_name, INSERT);
     914            0 :   if (*slot)
     915              :     {
     916            0 :       def = (struct enum_type *) *slot;
     917            0 :       if (def->md_p != md_p)
     918            0 :         error_at (loc, "redefining `%s' as a different type of enum",
     919              :                   enum_name);
     920              :     }
     921              :   else
     922              :     {
     923            0 :       def = XNEW (struct enum_type);
     924            0 :       def->name = enum_name;
     925            0 :       def->md_p = md_p;
     926            0 :       def->values = 0;
     927            0 :       def->tail_ptr = &def->values;
     928            0 :       def->num_values = 0;
     929            0 :       *slot = def;
     930              :     }
     931              : 
     932            0 :   cur_value = def->num_values;
     933            0 :   require_char_ws ('[');
     934              : 
     935            0 :   while ((c = read_skip_spaces ()) != ']')
     936              :     {
     937            0 :       if (c == EOF)
     938              :         {
     939            0 :           error_at (loc, "unterminated construct");
     940            0 :           exit (1);
     941              :         }
     942            0 :       if (c == '(')
     943              :         {
     944            0 :           read_name (&name);
     945            0 :           read_name (&value);
     946            0 :           require_char_ws (')');
     947            0 :           cur_value = atoi (value.string);
     948              :         }
     949              :       else
     950              :         {
     951            0 :           unread_char (c);
     952            0 :           read_name (&name);
     953              :         }
     954              : 
     955            0 :       ev = XNEW (struct enum_value);
     956            0 :       ev->next = 0;
     957            0 :       if (md_p)
     958              :         {
     959            0 :           value_name = concat (def->name, "_", name.string, NULL);
     960            0 :           upcase_string (value_name);
     961            0 :           ev->name = xstrdup (name.string);
     962              :         }
     963              :       else
     964              :         {
     965            0 :           value_name = xstrdup (name.string);
     966            0 :           ev->name = value_name;
     967              :         }
     968            0 :       ev->def = add_constant (get_md_constants (), value_name,
     969              :                               md_decimal_string (cur_value), def);
     970              : 
     971            0 :       *def->tail_ptr = ev;
     972            0 :       def->tail_ptr = &ev->next;
     973            0 :       def->num_values++;
     974            0 :       cur_value++;
     975              :     }
     976            0 : }
     977              : 
     978              : /* Try to find the definition of the given enum.  Return null on failure.  */
     979              : 
     980              : struct enum_type *
     981            0 : md_reader::lookup_enum_type (const char *name)
     982              : {
     983            0 :   return (struct enum_type *) htab_find (m_enum_types, &name);
     984              : }
     985              : 
     986              : /* For every enum definition, call CALLBACK with two arguments:
     987              :    a pointer to the constant definition and INFO.  Stop when CALLBACK
     988              :    returns zero.  */
     989              : 
     990              : void
     991            0 : md_reader::traverse_enum_types (htab_trav callback, void *info)
     992              : {
     993            0 :   htab_traverse (m_enum_types, callback, info);
     994            0 : }
     995              : 
     996              : 
     997              : /* Constructor for md_reader.  */
     998              : 
     999          100 : md_reader::md_reader (bool compact)
    1000          100 : : m_compact (compact),
    1001          100 :   m_toplevel_fname (NULL),
    1002          100 :   m_base_dir (NULL),
    1003          100 :   m_read_md_file (NULL),
    1004          100 :   m_read_md_filename (NULL),
    1005          100 :   m_read_md_lineno (0),
    1006          100 :   m_read_md_colno (0),
    1007          100 :   m_first_dir_md_include (NULL),
    1008          100 :   m_last_dir_md_include_ptr (&m_first_dir_md_include),
    1009          100 :   m_first_line (0),
    1010          100 :   m_last_line (0),
    1011          100 :   m_first_overload (NULL),
    1012          100 :   m_next_overload_ptr (&m_first_overload),
    1013          100 :   m_overloads_htab (NULL)
    1014              : {
    1015              :   /* Set the global singleton pointer.  */
    1016          100 :   md_reader_ptr = this;
    1017              : 
    1018          100 :   obstack_init (&m_string_obstack);
    1019              : 
    1020          100 :   m_ptr_locs = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
    1021          100 :   obstack_init (&m_ptr_loc_obstack);
    1022              : 
    1023          100 :   m_joined_conditions = htab_create (161, leading_ptr_hash, leading_ptr_eq_p, 0);
    1024          100 :   obstack_init (&m_joined_conditions_obstack);
    1025              : 
    1026          100 :   m_md_constants = htab_create (31, leading_string_hash,
    1027              :                                 leading_string_eq_p, (htab_del) 0);
    1028              : 
    1029          100 :   m_enum_types = htab_create (31, leading_string_hash,
    1030              :                               leading_string_eq_p, (htab_del) 0);
    1031              : 
    1032              :   /* Unlock the stdio streams.  */
    1033          100 :   unlock_std_streams ();
    1034          100 : }
    1035              : 
    1036              : /* md_reader's destructor.  */
    1037              : 
    1038           99 : md_reader::~md_reader ()
    1039              : {
    1040           99 :   free (m_base_dir);
    1041              : 
    1042           99 :   htab_delete (m_enum_types);
    1043              : 
    1044           99 :   htab_delete (m_md_constants);
    1045              : 
    1046           99 :   obstack_free (&m_joined_conditions_obstack, NULL);
    1047           99 :   htab_delete (m_joined_conditions);
    1048              : 
    1049           99 :   obstack_free (&m_ptr_loc_obstack, NULL);
    1050           99 :   htab_delete (m_ptr_locs);
    1051              : 
    1052           99 :   obstack_free (&m_string_obstack, NULL);
    1053              : 
    1054              :   /* Clear the global singleton pointer.  */
    1055           99 :   md_reader_ptr = NULL;
    1056           99 : }
    1057              : 
    1058              : /* Process an "include" directive, starting with the optional space
    1059              :    after the "include".  Read in the file and use HANDLE_DIRECTIVE
    1060              :    to process each unknown directive.  LINENO is the line number on
    1061              :    which the "include" occurred.  */
    1062              : 
    1063              : void
    1064            0 : md_reader::handle_include (file_location loc)
    1065              : {
    1066            0 :   const char *filename;
    1067            0 :   const char *old_filename;
    1068            0 :   int old_lineno, old_colno;
    1069            0 :   char *pathname;
    1070            0 :   FILE *input_file, *old_file;
    1071              : 
    1072            0 :   filename = read_string (false);
    1073            0 :   input_file = NULL;
    1074              : 
    1075              :   /* If the specified file name is absolute, skip the include stack.  */
    1076            0 :   if (!IS_ABSOLUTE_PATH (filename))
    1077              :     {
    1078            0 :       struct file_name_list *stackp;
    1079              : 
    1080              :       /* Search the directory path, trying to open the file.  */
    1081            0 :       for (stackp = m_first_dir_md_include; stackp; stackp = stackp->next)
    1082              :         {
    1083            0 :           static const char sep[2] = { DIR_SEPARATOR, '\0' };
    1084              : 
    1085            0 :           pathname = concat (stackp->fname, sep, filename, NULL);
    1086            0 :           input_file = fopen (pathname, "r");
    1087            0 :           if (input_file != NULL)
    1088              :             break;
    1089            0 :           free (pathname);
    1090              :         }
    1091              :     }
    1092              : 
    1093              :   /* If we haven't managed to open the file yet, try combining the
    1094              :      filename with BASE_DIR.  */
    1095            0 :   if (input_file == NULL)
    1096              :     {
    1097            0 :       if (m_base_dir)
    1098            0 :         pathname = concat (m_base_dir, filename, NULL);
    1099              :       else
    1100            0 :         pathname = xstrdup (filename);
    1101            0 :       input_file = fopen (pathname, "r");
    1102              :     }
    1103              : 
    1104            0 :   if (input_file == NULL)
    1105              :     {
    1106            0 :       free (pathname);
    1107            0 :       error_at (loc, "include file `%s' not found", filename);
    1108            0 :       return;
    1109              :     }
    1110              : 
    1111              :   /* Save the old cursor.  Note that the LINENO argument to this
    1112              :      function is the beginning of the include statement, while
    1113              :      read_md_lineno has already been advanced.  */
    1114            0 :   old_file = m_read_md_file;
    1115            0 :   old_filename = m_read_md_filename;
    1116            0 :   old_lineno = m_read_md_lineno;
    1117            0 :   old_colno = m_read_md_colno;
    1118              : 
    1119            0 :   if (include_callback)
    1120            0 :     include_callback (pathname);
    1121              : 
    1122            0 :   m_read_md_file = input_file;
    1123            0 :   m_read_md_filename = pathname;
    1124              : 
    1125            0 :   handle_file ();
    1126              : 
    1127              :   /* Restore the old cursor.  */
    1128            0 :   m_read_md_file = old_file;
    1129            0 :   m_read_md_filename = old_filename;
    1130            0 :   m_read_md_lineno = old_lineno;
    1131            0 :   m_read_md_colno = old_colno;
    1132              : 
    1133              :   /* Do not free the pathname.  It is attached to the various rtx
    1134              :      queue elements.  */
    1135              : }
    1136              : 
    1137              : /* Process the current file, assuming that read_md_file and
    1138              :    read_md_filename are valid.  Use HANDLE_DIRECTIVE to handle
    1139              :    unknown directives.  */
    1140              : 
    1141              : void
    1142          100 : md_reader::handle_file ()
    1143              : {
    1144          100 :   struct md_name directive;
    1145          100 :   int c;
    1146              : 
    1147          100 :   m_read_md_lineno = 1;
    1148          100 :   m_read_md_colno = 0;
    1149          199 :   while ((c = read_skip_spaces ()) != EOF)
    1150              :     {
    1151          100 :       file_location loc = get_current_location ();
    1152          100 :       if (c != '(')
    1153            0 :         fatal_expected_char ('(', c);
    1154              : 
    1155          100 :       read_name (&directive);
    1156          100 :       if (strcmp (directive.string, "define_constants") == 0)
    1157            0 :         handle_constants ();
    1158          100 :       else if (strcmp (directive.string, "define_enum") == 0)
    1159            0 :         handle_enum (loc, true);
    1160          100 :       else if (strcmp (directive.string, "define_c_enum") == 0)
    1161            0 :         handle_enum (loc, false);
    1162          100 :       else if (strcmp (directive.string, "include") == 0)
    1163            0 :         handle_include (loc);
    1164              :       else
    1165          100 :         handle_unknown_directive (loc, directive.string);
    1166              : 
    1167           99 :       require_char_ws (')');
    1168              :     }
    1169           99 :   fclose (m_read_md_file);
    1170           99 : }
    1171              : 
    1172              : /* Like handle_file, but for top-level files.  Set up m_toplevel_fname
    1173              :    and m_base_dir accordingly.  */
    1174              : 
    1175              : void
    1176          100 : md_reader::handle_toplevel_file ()
    1177              : {
    1178          100 :   const char *base;
    1179              : 
    1180          100 :   m_toplevel_fname = m_read_md_filename;
    1181          100 :   base = lbasename (m_toplevel_fname);
    1182          100 :   if (base == m_toplevel_fname)
    1183            0 :     m_base_dir = NULL;
    1184              :   else
    1185          100 :     m_base_dir = xstrndup (m_toplevel_fname, base - m_toplevel_fname);
    1186              : 
    1187          100 :   handle_file ();
    1188           99 : }
    1189              : 
    1190              : file_location
    1191         9685 : md_reader::get_current_location () const
    1192              : {
    1193         9685 :   return file_location (m_read_md_filename, m_read_md_lineno, m_read_md_colno);
    1194              : }
    1195              : 
    1196              : /* Parse a -I option with argument ARG.  */
    1197              : 
    1198              : void
    1199            0 : md_reader::add_include_path (const char *arg)
    1200              : {
    1201            0 :   struct file_name_list *dirtmp;
    1202              : 
    1203            0 :   dirtmp = XNEW (struct file_name_list);
    1204            0 :   dirtmp->next = 0;
    1205            0 :   dirtmp->fname = arg;
    1206            0 :   *m_last_dir_md_include_ptr = dirtmp;
    1207            0 :   m_last_dir_md_include_ptr = &dirtmp->next;
    1208            0 : }
    1209              : 
    1210              : #ifdef GENERATOR_FILE
    1211              : 
    1212              : /* The main routine for reading .md files.  Try to process all the .md
    1213              :    files specified on the command line and return true if no error occurred.
    1214              : 
    1215              :    ARGC and ARGV are the arguments to main.
    1216              : 
    1217              :    PARSE_OPT, if nonnull, is passed all unknown command-line arguments.
    1218              :    It should return true if it recognizes the argument or false if a
    1219              :    generic error should be reported.  */
    1220              : 
    1221              : bool
    1222              : md_reader::read_md_files (int argc, const char **argv,
    1223              :                           bool (*parse_opt) (const char *))
    1224              : {
    1225              :   int i;
    1226              :   bool no_more_options;
    1227              :   bool already_read_stdin;
    1228              :   int num_files;
    1229              : 
    1230              :   /* First we loop over all the options.  */
    1231              :   for (i = 1; i < argc; i++)
    1232              :     if (argv[i][0] == '-')
    1233              :       {
    1234              :         /* An argument consisting of exactly one dash is a request to
    1235              :            read stdin.  This will be handled in the second loop.  */
    1236              :         if (argv[i][1] == '\0')
    1237              :           continue;
    1238              : 
    1239              :         /* An argument consisting of just two dashes causes option
    1240              :            parsing to cease.  */
    1241              :         if (argv[i][1] == '-' && argv[i][2] == '\0')
    1242              :           break;
    1243              : 
    1244              :         if (argv[i][1] == 'I')
    1245              :           {
    1246              :             if (argv[i][2] != '\0')
    1247              :               add_include_path (argv[i] + 2);
    1248              :             else if (++i < argc)
    1249              :               add_include_path (argv[i]);
    1250              :             else
    1251              :               fatal ("directory name missing after -I option");
    1252              :             continue;
    1253              :           }
    1254              : 
    1255              :         /* The program may have provided a callback so it can
    1256              :            accept its own options.  */
    1257              :         if (parse_opt && parse_opt (argv[i]))
    1258              :           continue;
    1259              : 
    1260              :         fatal ("invalid option `%s'", argv[i]);
    1261              :       }
    1262              : 
    1263              :   /* Now loop over all input files.  */
    1264              :   num_files = 0;
    1265              :   no_more_options = false;
    1266              :   already_read_stdin = false;
    1267              :   for (i = 1; i < argc; i++)
    1268              :     {
    1269              :       if (argv[i][0] == '-')
    1270              :         {
    1271              :           if (argv[i][1] == '\0')
    1272              :             {
    1273              :               /* Read stdin.  */
    1274              :               if (already_read_stdin)
    1275              :                 fatal ("cannot read standard input twice");
    1276              : 
    1277              :               m_read_md_file = stdin;
    1278              :               m_read_md_filename = "<stdin>";
    1279              :               handle_toplevel_file ();
    1280              :               already_read_stdin = true;
    1281              :               continue;
    1282              :             }
    1283              :           else if (argv[i][1] == '-' && argv[i][2] == '\0')
    1284              :             {
    1285              :               /* No further arguments are to be treated as options.  */
    1286              :               no_more_options = true;
    1287              :               continue;
    1288              :             }
    1289              :           else if (!no_more_options)
    1290              :             continue;
    1291              :         }
    1292              : 
    1293              :       /* If we get here we are looking at a non-option argument, i.e.
    1294              :          a file to be processed.  */
    1295              :       m_read_md_filename = argv[i];
    1296              :       m_read_md_file = fopen (m_read_md_filename, "r");
    1297              :       if (m_read_md_file == 0)
    1298              :         {
    1299              :           perror (m_read_md_filename);
    1300              :           return false;
    1301              :         }
    1302              :       handle_toplevel_file ();
    1303              :       num_files++;
    1304              :     }
    1305              : 
    1306              :   /* If we get to this point without having seen any files to process,
    1307              :      read the standard input now.  */
    1308              :   if (num_files == 0 && !already_read_stdin)
    1309              :     {
    1310              :       m_read_md_file = stdin;
    1311              :       m_read_md_filename = "<stdin>";
    1312              :       handle_toplevel_file ();
    1313              :     }
    1314              : 
    1315              :   return !have_error;
    1316              : }
    1317              : 
    1318              : #endif /* #ifdef GENERATOR_FILE */
    1319              : 
    1320              : /* Read FILENAME.  */
    1321              : 
    1322              : bool
    1323           76 : md_reader::read_file (const char *filename)
    1324              : {
    1325           76 :   m_read_md_filename = filename;
    1326           76 :   m_read_md_file = fopen (m_read_md_filename, "r");
    1327           76 :   if (m_read_md_file == 0)
    1328              :     {
    1329            0 :       perror (m_read_md_filename);
    1330            0 :       return false;
    1331              :     }
    1332           76 :   handle_toplevel_file ();
    1333           76 :   return !have_error;
    1334              : }
    1335              : 
    1336              : /* Read FILENAME, filtering to just the given lines.  */
    1337              : 
    1338              : bool
    1339           24 : md_reader::read_file_fragment (const char *filename,
    1340              :                                int first_line,
    1341              :                                int last_line)
    1342              : {
    1343           24 :   m_read_md_filename = filename;
    1344           24 :   m_read_md_file = fopen (m_read_md_filename, "r");
    1345           24 :   if (m_read_md_file == 0)
    1346              :     {
    1347            0 :       perror (m_read_md_filename);
    1348            0 :       return false;
    1349              :     }
    1350           24 :   m_first_line = first_line;
    1351           24 :   m_last_line = last_line;
    1352           24 :   handle_toplevel_file ();
    1353           23 :   return !have_error;
    1354              : }
    1355              : 
    1356              : /* class noop_reader : public md_reader */
    1357              : 
    1358              : /* A dummy implementation which skips unknown directives.  */
    1359              : void
    1360            0 : noop_reader::handle_unknown_directive (file_location loc, const char *)
    1361              : {
    1362            0 :   read_skip_construct (1, loc);
    1363            0 : }
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.