OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [tags/] [gnu-src/] [gcc-4.5.1/] [gcc-4.5.1-or32-1.0rc1/] [gcc/] [gengtype-parse.c] - Diff between revs 280 and 338

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 280 Rev 338
/* Process source files and output type information.
/* Process source files and output type information.
   Copyright (C) 2006, 2007 Free Software Foundation, Inc.
   Copyright (C) 2006, 2007 Free Software Foundation, Inc.
 
 
This file is part of GCC.
This file is part of GCC.
 
 
GCC is free software; you can redistribute it and/or modify it under
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
Software Foundation; either version 3, or (at your option) any later
version.
version.
 
 
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.
for more details.
 
 
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
<http://www.gnu.org/licenses/>.  */
 
 
#include "bconfig.h"
#include "bconfig.h"
#include "system.h"
#include "system.h"
#include "gengtype.h"
#include "gengtype.h"
 
 
/* This is a simple recursive-descent parser which understands a subset of
/* This is a simple recursive-descent parser which understands a subset of
   the C type grammar.
   the C type grammar.
 
 
   Rule functions are suffixed _seq if they scan a sequence of items;
   Rule functions are suffixed _seq if they scan a sequence of items;
   _opt if they may consume zero tokens; _seqopt if both are true.  The
   _opt if they may consume zero tokens; _seqopt if both are true.  The
   "consume_" prefix indicates that a sequence of tokens is parsed for
   "consume_" prefix indicates that a sequence of tokens is parsed for
   syntactic correctness and then thrown away.  */
   syntactic correctness and then thrown away.  */
 
 
/* Simple one-token lookahead mechanism.  */
/* Simple one-token lookahead mechanism.  */
 
 
struct token
struct token
{
{
  const char *value;
  const char *value;
  int code;
  int code;
  bool valid;
  bool valid;
};
};
static struct token T;
static struct token T;
 
 
/* Retrieve the code of the current token; if there is no current token,
/* Retrieve the code of the current token; if there is no current token,
   get the next one from the lexer.  */
   get the next one from the lexer.  */
static inline int
static inline int
token (void)
token (void)
{
{
  if (!T.valid)
  if (!T.valid)
    {
    {
      T.code = yylex (&T.value);
      T.code = yylex (&T.value);
      T.valid = true;
      T.valid = true;
    }
    }
  return T.code;
  return T.code;
}
}
 
 
/* Retrieve the value of the current token (if any) and mark it consumed.
/* Retrieve the value of the current token (if any) and mark it consumed.
   The next call to token() will get another token from the lexer.  */
   The next call to token() will get another token from the lexer.  */
static inline const char *
static inline const char *
advance (void)
advance (void)
{
{
  T.valid = false;
  T.valid = false;
  return T.value;
  return T.value;
}
}
 
 
/* Diagnostics.  */
/* Diagnostics.  */
 
 
/* This array is indexed by the token code minus CHAR_TOKEN_OFFSET.  */
/* This array is indexed by the token code minus CHAR_TOKEN_OFFSET.  */
static const char *const token_names[] = {
static const char *const token_names[] = {
  "GTY",
  "GTY",
  "typedef",
  "typedef",
  "extern",
  "extern",
  "static",
  "static",
  "union",
  "union",
  "struct",
  "struct",
  "enum",
  "enum",
  "VEC",
  "VEC",
  "DEF_VEC_[OP]",
  "DEF_VEC_[OP]",
  "DEF_VEC_I",
  "DEF_VEC_I",
  "DEF_VEC_ALLOC_[IOP]",
  "DEF_VEC_ALLOC_[IOP]",
  "...",
  "...",
  "ptr_alias",
  "ptr_alias",
  "nested_ptr",
  "nested_ptr",
  "a param<N>_is option",
  "a param<N>_is option",
  "a number",
  "a number",
  "a scalar type",
  "a scalar type",
  "an identifier",
  "an identifier",
  "a string constant",
  "a string constant",
  "a character constant",
  "a character constant",
  "an array declarator",
  "an array declarator",
};
};
 
 
/* This array is indexed by token code minus FIRST_TOKEN_WITH_VALUE.  */
/* This array is indexed by token code minus FIRST_TOKEN_WITH_VALUE.  */
static const char *const token_value_format[] = {
static const char *const token_value_format[] = {
  "%s",
  "%s",
  "'%s'",
  "'%s'",
  "'%s'",
  "'%s'",
  "'%s'",
  "'%s'",
  "'\"%s\"'",
  "'\"%s\"'",
  "\"'%s'\"",
  "\"'%s'\"",
  "'[%s]'",
  "'[%s]'",
};
};
 
 
/* Produce a printable representation for a token defined by CODE and
/* Produce a printable representation for a token defined by CODE and
   VALUE.  This sometimes returns pointers into malloc memory and
   VALUE.  This sometimes returns pointers into malloc memory and
   sometimes not, therefore it is unsafe to free the pointer it
   sometimes not, therefore it is unsafe to free the pointer it
   returns, so that memory is leaked.  This does not matter, as this
   returns, so that memory is leaked.  This does not matter, as this
   function is only used for diagnostics, and in a successful run of
   function is only used for diagnostics, and in a successful run of
   the program there will be none.  */
   the program there will be none.  */
static const char *
static const char *
print_token (int code, const char *value)
print_token (int code, const char *value)
{
{
  if (code < CHAR_TOKEN_OFFSET)
  if (code < CHAR_TOKEN_OFFSET)
    return xasprintf ("'%c'", code);
    return xasprintf ("'%c'", code);
  else if (code < FIRST_TOKEN_WITH_VALUE)
  else if (code < FIRST_TOKEN_WITH_VALUE)
    return xasprintf ("'%s'", token_names[code - CHAR_TOKEN_OFFSET]);
    return xasprintf ("'%s'", token_names[code - CHAR_TOKEN_OFFSET]);
  else if (!value)
  else if (!value)
    return token_names[code - CHAR_TOKEN_OFFSET]; /* don't quote these */
    return token_names[code - CHAR_TOKEN_OFFSET]; /* don't quote these */
  else
  else
    return xasprintf (token_value_format[code - FIRST_TOKEN_WITH_VALUE],
    return xasprintf (token_value_format[code - FIRST_TOKEN_WITH_VALUE],
                      value);
                      value);
}
}
 
 
/* Convenience wrapper around print_token which produces the printable
/* Convenience wrapper around print_token which produces the printable
   representation of the current token.  */
   representation of the current token.  */
static inline const char *
static inline const char *
print_cur_token (void)
print_cur_token (void)
{
{
  return print_token (T.code, T.value);
  return print_token (T.code, T.value);
}
}
 
 
/* Report a parse error on the current line, with diagnostic MSG.
/* Report a parse error on the current line, with diagnostic MSG.
   Behaves as standard printf with respect to additional arguments and
   Behaves as standard printf with respect to additional arguments and
   format escapes.  */
   format escapes.  */
static void ATTRIBUTE_PRINTF_1
static void ATTRIBUTE_PRINTF_1
parse_error (const char *msg, ...)
parse_error (const char *msg, ...)
{
{
  va_list ap;
  va_list ap;
 
 
  fprintf (stderr, "%s:%d: parse error: ", lexer_line.file, lexer_line.line);
  fprintf (stderr, "%s:%d: parse error: ", lexer_line.file, lexer_line.line);
 
 
  va_start (ap, msg);
  va_start (ap, msg);
  vfprintf (stderr, msg, ap);
  vfprintf (stderr, msg, ap);
  va_end (ap);
  va_end (ap);
 
 
  fputc ('\n', stderr);
  fputc ('\n', stderr);
 
 
  hit_error = true;
  hit_error = true;
}
}
 
 
/* If the next token does not have code T, report a parse error; otherwise
/* If the next token does not have code T, report a parse error; otherwise
   return the token's value.  */
   return the token's value.  */
static const char *
static const char *
require (int t)
require (int t)
{
{
  int u = token ();
  int u = token ();
  const char *v = advance ();
  const char *v = advance ();
  if (u != t)
  if (u != t)
    {
    {
      parse_error ("expected %s, have %s",
      parse_error ("expected %s, have %s",
                   print_token (t, 0), print_token (u, v));
                   print_token (t, 0), print_token (u, v));
      return 0;
      return 0;
    }
    }
  return v;
  return v;
}
}
 
 
/* If the next token does not have one of the codes T1 or T2, report a
/* If the next token does not have one of the codes T1 or T2, report a
   parse error; otherwise return the token's value.  */
   parse error; otherwise return the token's value.  */
static const char *
static const char *
require2 (int t1, int t2)
require2 (int t1, int t2)
{
{
  int u = token ();
  int u = token ();
  const char *v = advance ();
  const char *v = advance ();
  if (u != t1 && u != t2)
  if (u != t1 && u != t2)
    {
    {
      parse_error ("expected %s or %s, have %s",
      parse_error ("expected %s or %s, have %s",
                   print_token (t1, 0), print_token (t2, 0),
                   print_token (t1, 0), print_token (t2, 0),
                   print_token (u, v));
                   print_token (u, v));
      return 0;
      return 0;
    }
    }
  return v;
  return v;
}
}
 
 
/* Near-terminals.  */
/* Near-terminals.  */
 
 
/* C-style string constant concatenation: STRING+
/* C-style string constant concatenation: STRING+
   Bare STRING should appear nowhere else in this file.  */
   Bare STRING should appear nowhere else in this file.  */
static const char *
static const char *
string_seq (void)
string_seq (void)
{
{
  const char *s1, *s2;
  const char *s1, *s2;
  size_t l1, l2;
  size_t l1, l2;
  char *buf;
  char *buf;
 
 
  s1 = require (STRING);
  s1 = require (STRING);
  if (s1 == 0)
  if (s1 == 0)
    return "";
    return "";
  while (token () == STRING)
  while (token () == STRING)
    {
    {
      s2 = advance ();
      s2 = advance ();
 
 
      l1 = strlen (s1);
      l1 = strlen (s1);
      l2 = strlen (s2);
      l2 = strlen (s2);
      buf = XRESIZEVEC (char, CONST_CAST(char *, s1), l1 + l2 + 1);
      buf = XRESIZEVEC (char, CONST_CAST(char *, s1), l1 + l2 + 1);
      memcpy (buf + l1, s2, l2 + 1);
      memcpy (buf + l1, s2, l2 + 1);
      XDELETE (CONST_CAST (char *, s2));
      XDELETE (CONST_CAST (char *, s2));
      s1 = buf;
      s1 = buf;
    }
    }
  return s1;
  return s1;
}
}
 
 
/* typedef_name: either an ID, or VEC(x,y) which is translated to VEC_x_y.
/* typedef_name: either an ID, or VEC(x,y) which is translated to VEC_x_y.
   Use only where VEC(x,y) is legitimate, i.e. in positions where a
   Use only where VEC(x,y) is legitimate, i.e. in positions where a
   typedef name may appear.  */
   typedef name may appear.  */
static const char *
static const char *
typedef_name (void)
typedef_name (void)
{
{
  if (token () == VEC_TOKEN)
  if (token () == VEC_TOKEN)
    {
    {
      const char *c1, *c2, *r;
      const char *c1, *c2, *r;
      advance ();
      advance ();
      require ('(');
      require ('(');
      c1 = require2 (ID, SCALAR);
      c1 = require2 (ID, SCALAR);
      require (',');
      require (',');
      c2 = require (ID);
      c2 = require (ID);
      require (')');
      require (')');
      r = concat ("VEC_", c1, "_", c2, (char *)0);
      r = concat ("VEC_", c1, "_", c2, (char *)0);
      free (CONST_CAST (char *, c1));
      free (CONST_CAST (char *, c1));
      free (CONST_CAST (char *, c2));
      free (CONST_CAST (char *, c2));
      return r;
      return r;
    }
    }
  else
  else
    return require (ID);
    return require (ID);
}
}
 
 
/* Absorb a sequence of tokens delimited by balanced ()[]{}.  */
/* Absorb a sequence of tokens delimited by balanced ()[]{}.  */
static void
static void
consume_balanced (int opener, int closer)
consume_balanced (int opener, int closer)
{
{
  require (opener);
  require (opener);
  for (;;)
  for (;;)
    switch (token ())
    switch (token ())
      {
      {
      default: advance (); break;
      default: advance (); break;
      case '(': consume_balanced ('(',')'); break;
      case '(': consume_balanced ('(',')'); break;
      case '[': consume_balanced ('[',']'); break;
      case '[': consume_balanced ('[',']'); break;
      case '{': consume_balanced ('{','}'); break;
      case '{': consume_balanced ('{','}'); break;
 
 
      case '}':
      case '}':
      case ']':
      case ']':
      case ')':
      case ')':
        if (token () != closer)
        if (token () != closer)
          parse_error ("unbalanced delimiters - expected '%c', have '%c'",
          parse_error ("unbalanced delimiters - expected '%c', have '%c'",
                       closer, token ());
                       closer, token ());
        advance ();
        advance ();
        return;
        return;
 
 
      case EOF_TOKEN:
      case EOF_TOKEN:
        parse_error ("unexpected end of file within %c%c-delimited construct",
        parse_error ("unexpected end of file within %c%c-delimited construct",
                     opener, closer);
                     opener, closer);
        return;
        return;
      }
      }
}
}
 
 
/* Absorb a sequence of tokens, possibly including ()[]{}-delimited
/* Absorb a sequence of tokens, possibly including ()[]{}-delimited
   expressions, until we encounter a semicolon outside any such
   expressions, until we encounter a semicolon outside any such
   delimiters; absorb that too.  If IMMEDIATE is true, it is an error
   delimiters; absorb that too.  If IMMEDIATE is true, it is an error
   if the semicolon is not the first token encountered.  */
   if the semicolon is not the first token encountered.  */
static void
static void
consume_until_semi (bool immediate)
consume_until_semi (bool immediate)
{
{
  if (immediate && token () != ';')
  if (immediate && token () != ';')
    require (';');
    require (';');
  for (;;)
  for (;;)
    switch (token ())
    switch (token ())
      {
      {
      case ';': advance (); return;
      case ';': advance (); return;
      default:  advance (); break;
      default:  advance (); break;
 
 
      case '(': consume_balanced ('(',')'); break;
      case '(': consume_balanced ('(',')'); break;
      case '[': consume_balanced ('[',']'); break;
      case '[': consume_balanced ('[',']'); break;
      case '{': consume_balanced ('{','}'); break;
      case '{': consume_balanced ('{','}'); break;
 
 
      case '}':
      case '}':
      case ']':
      case ']':
      case ')':
      case ')':
        parse_error ("unmatched '%c' while scanning for ';'", token ());
        parse_error ("unmatched '%c' while scanning for ';'", token ());
        return;
        return;
 
 
      case EOF_TOKEN:
      case EOF_TOKEN:
        parse_error ("unexpected end of file while scanning for ';'");
        parse_error ("unexpected end of file while scanning for ';'");
        return;
        return;
      }
      }
}
}
 
 
/* Absorb a sequence of tokens, possibly including ()[]{}-delimited
/* Absorb a sequence of tokens, possibly including ()[]{}-delimited
   expressions, until we encounter a comma or semicolon outside any
   expressions, until we encounter a comma or semicolon outside any
   such delimiters; absorb that too.  If IMMEDIATE is true, it is an
   such delimiters; absorb that too.  If IMMEDIATE is true, it is an
   error if the comma or semicolon is not the first token encountered.
   error if the comma or semicolon is not the first token encountered.
   Returns true if the loop ended with a comma.  */
   Returns true if the loop ended with a comma.  */
static bool
static bool
consume_until_comma_or_semi (bool immediate)
consume_until_comma_or_semi (bool immediate)
{
{
  if (immediate && token () != ',' && token () != ';')
  if (immediate && token () != ',' && token () != ';')
    require2 (',', ';');
    require2 (',', ';');
  for (;;)
  for (;;)
    switch (token ())
    switch (token ())
      {
      {
      case ',': advance (); return true;
      case ',': advance (); return true;
      case ';': advance (); return false;
      case ';': advance (); return false;
      default:  advance (); break;
      default:  advance (); break;
 
 
      case '(': consume_balanced ('(',')'); break;
      case '(': consume_balanced ('(',')'); break;
      case '[': consume_balanced ('[',']'); break;
      case '[': consume_balanced ('[',']'); break;
      case '{': consume_balanced ('{','}'); break;
      case '{': consume_balanced ('{','}'); break;
 
 
      case '}':
      case '}':
      case ']':
      case ']':
      case ')':
      case ')':
        parse_error ("unmatched '%s' while scanning for ',' or ';'",
        parse_error ("unmatched '%s' while scanning for ',' or ';'",
                     print_cur_token ());
                     print_cur_token ());
        return false;
        return false;
 
 
      case EOF_TOKEN:
      case EOF_TOKEN:
        parse_error ("unexpected end of file while scanning for ',' or ';'");
        parse_error ("unexpected end of file while scanning for ',' or ';'");
        return false;
        return false;
      }
      }
}
}
 
 


/* GTY(()) option handling.  */
/* GTY(()) option handling.  */
static type_p type (options_p *optsp, bool nested);
static type_p type (options_p *optsp, bool nested);
 
 
/* Optional parenthesized string: ('(' string_seq ')')? */
/* Optional parenthesized string: ('(' string_seq ')')? */
static options_p
static options_p
str_optvalue_opt (options_p prev)
str_optvalue_opt (options_p prev)
{
{
  const char *name = advance ();
  const char *name = advance ();
  const char *value = "";
  const char *value = "";
  if (token () == '(')
  if (token () == '(')
    {
    {
      advance ();
      advance ();
      value = string_seq ();
      value = string_seq ();
      require (')');
      require (')');
    }
    }
  return create_option (prev, name, value);
  return create_option (prev, name, value);
}
}
 
 
/* absdecl: type '*'*
/* absdecl: type '*'*
   -- a vague approximation to what the C standard calls an abstract
   -- a vague approximation to what the C standard calls an abstract
   declarator.  The only kinds that are actually used are those that
   declarator.  The only kinds that are actually used are those that
   are just a bare type and those that have trailing pointer-stars.
   are just a bare type and those that have trailing pointer-stars.
   Further kinds should be implemented if and when they become
   Further kinds should be implemented if and when they become
   necessary.  Used only within GTY(()) option values, therefore
   necessary.  Used only within GTY(()) option values, therefore
   further GTY(()) tags within the type are invalid.  Note that the
   further GTY(()) tags within the type are invalid.  Note that the
   return value has already been run through adjust_field_type.  */
   return value has already been run through adjust_field_type.  */
static type_p
static type_p
absdecl (void)
absdecl (void)
{
{
  type_p ty;
  type_p ty;
  options_p opts;
  options_p opts;
 
 
  ty = type (&opts, true);
  ty = type (&opts, true);
  while (token () == '*')
  while (token () == '*')
    {
    {
      ty = create_pointer (ty);
      ty = create_pointer (ty);
      advance ();
      advance ();
    }
    }
 
 
  if (opts)
  if (opts)
    parse_error ("nested GTY(()) options are invalid");
    parse_error ("nested GTY(()) options are invalid");
 
 
  return adjust_field_type (ty, 0);
  return adjust_field_type (ty, 0);
}
}
 
 
/* Type-option: '(' absdecl ')' */
/* Type-option: '(' absdecl ')' */
static options_p
static options_p
type_optvalue (options_p prev, const char *name)
type_optvalue (options_p prev, const char *name)
{
{
  type_p ty;
  type_p ty;
  require ('(');
  require ('(');
  ty = absdecl ();
  ty = absdecl ();
  require (')');
  require (')');
  return create_option (prev, name, ty);
  return create_option (prev, name, ty);
}
}
 
 
/* Nested pointer data: '(' type '*'* ',' string_seq ',' string_seq ')' */
/* Nested pointer data: '(' type '*'* ',' string_seq ',' string_seq ')' */
static options_p
static options_p
nestedptr_optvalue (options_p prev)
nestedptr_optvalue (options_p prev)
{
{
  type_p ty;
  type_p ty;
  const char *from, *to;
  const char *from, *to;
 
 
  require ('(');
  require ('(');
  ty = absdecl ();
  ty = absdecl ();
  require (',');
  require (',');
  to = string_seq ();
  to = string_seq ();
  require (',');
  require (',');
  from = string_seq ();
  from = string_seq ();
  require (')');
  require (')');
 
 
  return create_nested_ptr_option (prev, ty, to, from);
  return create_nested_ptr_option (prev, ty, to, from);
}
}
 
 
/* One GTY(()) option:
/* One GTY(()) option:
         ID str_optvalue_opt
         ID str_optvalue_opt
       | PTR_ALIAS type_optvalue
       | PTR_ALIAS type_optvalue
       | PARAM_IS type_optvalue
       | PARAM_IS type_optvalue
       | NESTED_PTR nestedptr_optvalue
       | NESTED_PTR nestedptr_optvalue
 */
 */
static options_p
static options_p
option (options_p prev)
option (options_p prev)
{
{
  switch (token ())
  switch (token ())
    {
    {
    case ID:
    case ID:
      return str_optvalue_opt (prev);
      return str_optvalue_opt (prev);
 
 
    case PTR_ALIAS:
    case PTR_ALIAS:
      advance ();
      advance ();
      return type_optvalue (prev, "ptr_alias");
      return type_optvalue (prev, "ptr_alias");
 
 
    case PARAM_IS:
    case PARAM_IS:
      return type_optvalue (prev, advance ());
      return type_optvalue (prev, advance ());
 
 
    case NESTED_PTR:
    case NESTED_PTR:
      advance ();
      advance ();
      return nestedptr_optvalue (prev);
      return nestedptr_optvalue (prev);
 
 
    default:
    default:
      parse_error ("expected an option keyword, have %s",
      parse_error ("expected an option keyword, have %s",
                   print_cur_token ());
                   print_cur_token ());
      advance ();
      advance ();
      return create_option (prev, "", "");
      return create_option (prev, "", "");
    }
    }
}
}
 
 
/* One comma-separated list of options.  */
/* One comma-separated list of options.  */
static options_p
static options_p
option_seq (void)
option_seq (void)
{
{
  options_p o;
  options_p o;
 
 
  o = option (0);
  o = option (0);
  while (token () == ',')
  while (token () == ',')
    {
    {
      advance ();
      advance ();
      o = option (o);
      o = option (o);
    }
    }
  return o;
  return o;
}
}
 
 
/* GTY marker: 'GTY' '(' '(' option_seq? ')' ')' */
/* GTY marker: 'GTY' '(' '(' option_seq? ')' ')' */
static options_p
static options_p
gtymarker (void)
gtymarker (void)
{
{
  options_p result = 0;
  options_p result = 0;
  require (GTY_TOKEN);
  require (GTY_TOKEN);
  require ('(');
  require ('(');
  require ('(');
  require ('(');
  if (token () != ')')
  if (token () != ')')
    result = option_seq ();
    result = option_seq ();
  require (')');
  require (')');
  require (')');
  require (')');
  return result;
  return result;
}
}
 
 
/* Optional GTY marker.  */
/* Optional GTY marker.  */
static options_p
static options_p
gtymarker_opt (void)
gtymarker_opt (void)
{
{
  if (token () != GTY_TOKEN)
  if (token () != GTY_TOKEN)
    return 0;
    return 0;
  return gtymarker ();
  return gtymarker ();
}
}


/* Declarators. The logic here is largely lifted from c-parser.c.
/* Declarators. The logic here is largely lifted from c-parser.c.
   Note that we do not have to process abstract declarators, which can
   Note that we do not have to process abstract declarators, which can
   appear only in parameter type lists or casts (but see absdecl,
   appear only in parameter type lists or casts (but see absdecl,
   above).  Also, type qualifiers are thrown out in gengtype-lex.l so
   above).  Also, type qualifiers are thrown out in gengtype-lex.l so
   we don't have to do it.  */
   we don't have to do it.  */
 
 
/* array_and_function_declarators_opt:
/* array_and_function_declarators_opt:
      \epsilon
      \epsilon
      array_and_function_declarators_opt ARRAY
      array_and_function_declarators_opt ARRAY
      array_and_function_declarators_opt '(' ... ')'
      array_and_function_declarators_opt '(' ... ')'
 
 
   where '...' indicates stuff we ignore except insofar as grouping
   where '...' indicates stuff we ignore except insofar as grouping
   symbols ()[]{} must balance.
   symbols ()[]{} must balance.
 
 
   Subroutine of direct_declarator - do not use elsewhere. */
   Subroutine of direct_declarator - do not use elsewhere. */
 
 
static type_p
static type_p
array_and_function_declarators_opt (type_p ty)
array_and_function_declarators_opt (type_p ty)
{
{
  if (token () == ARRAY)
  if (token () == ARRAY)
    {
    {
      const char *array = advance ();
      const char *array = advance ();
      return create_array (array_and_function_declarators_opt (ty), array);
      return create_array (array_and_function_declarators_opt (ty), array);
    }
    }
  else if (token () == '(')
  else if (token () == '(')
    {
    {
      /* We don't need exact types for functions.  */
      /* We don't need exact types for functions.  */
      consume_balanced ('(', ')');
      consume_balanced ('(', ')');
      array_and_function_declarators_opt (ty);
      array_and_function_declarators_opt (ty);
      return create_scalar_type ("function type");
      return create_scalar_type ("function type");
    }
    }
  else
  else
    return ty;
    return ty;
}
}
 
 
static type_p inner_declarator (type_p, const char **, options_p *);
static type_p inner_declarator (type_p, const char **, options_p *);
 
 
/* direct_declarator:
/* direct_declarator:
      '(' inner_declarator ')'
      '(' inner_declarator ')'
      gtymarker_opt ID array_and_function_declarators_opt
      gtymarker_opt ID array_and_function_declarators_opt
 
 
   Subroutine of declarator, mutually recursive with inner_declarator;
   Subroutine of declarator, mutually recursive with inner_declarator;
   do not use elsewhere.  */
   do not use elsewhere.  */
static type_p
static type_p
direct_declarator (type_p ty, const char **namep, options_p *optsp)
direct_declarator (type_p ty, const char **namep, options_p *optsp)
{
{
  /* The first token in a direct-declarator must be an ID, a
  /* The first token in a direct-declarator must be an ID, a
     GTY marker, or an open parenthesis.  */
     GTY marker, or an open parenthesis.  */
  switch (token ())
  switch (token ())
    {
    {
    case GTY_TOKEN:
    case GTY_TOKEN:
      *optsp = gtymarker ();
      *optsp = gtymarker ();
      /* fall through */
      /* fall through */
    case ID:
    case ID:
      *namep = require (ID);
      *namep = require (ID);
      break;
      break;
 
 
    case '(':
    case '(':
      advance ();
      advance ();
      ty = inner_declarator (ty, namep, optsp);
      ty = inner_declarator (ty, namep, optsp);
      require (')');
      require (')');
      break;
      break;
 
 
    default:
    default:
      parse_error ("expected '(', 'GTY', or an identifier, have %s",
      parse_error ("expected '(', 'GTY', or an identifier, have %s",
                   print_cur_token ());
                   print_cur_token ());
      /* Do _not_ advance if what we have is a close squiggle brace, as
      /* Do _not_ advance if what we have is a close squiggle brace, as
         we will get much better error recovery that way.  */
         we will get much better error recovery that way.  */
      if (token () != '}')
      if (token () != '}')
        advance ();
        advance ();
      return 0;
      return 0;
    }
    }
  return array_and_function_declarators_opt (ty);
  return array_and_function_declarators_opt (ty);
}
}
 
 
/* The difference between inner_declarator and declarator is in the
/* The difference between inner_declarator and declarator is in the
   handling of stars.  Consider this declaration:
   handling of stars.  Consider this declaration:
 
 
      char * (*pfc) (void)
      char * (*pfc) (void)
 
 
   It declares a pointer to a function that takes no arguments and
   It declares a pointer to a function that takes no arguments and
   returns a char*.  To construct the correct type for this
   returns a char*.  To construct the correct type for this
   declaration, the star outside the parentheses must be processed
   declaration, the star outside the parentheses must be processed
   _before_ the function type, the star inside the parentheses must
   _before_ the function type, the star inside the parentheses must
   be processed _after_ the function type.  To accomplish this,
   be processed _after_ the function type.  To accomplish this,
   declarator() creates pointers before recursing (it is actually
   declarator() creates pointers before recursing (it is actually
   coded as a while loop), whereas inner_declarator() recurses before
   coded as a while loop), whereas inner_declarator() recurses before
   creating pointers.  */
   creating pointers.  */
 
 
/* inner_declarator:
/* inner_declarator:
     '*' inner_declarator
     '*' inner_declarator
     direct_declarator
     direct_declarator
 
 
   Mutually recursive subroutine of direct_declarator; do not use
   Mutually recursive subroutine of direct_declarator; do not use
   elsewhere.  */
   elsewhere.  */
 
 
static type_p
static type_p
inner_declarator (type_p ty, const char **namep, options_p *optsp)
inner_declarator (type_p ty, const char **namep, options_p *optsp)
{
{
  if (token () == '*')
  if (token () == '*')
    {
    {
      type_p inner;
      type_p inner;
      advance ();
      advance ();
      inner = inner_declarator (ty, namep, optsp);
      inner = inner_declarator (ty, namep, optsp);
      if (inner == 0)
      if (inner == 0)
        return 0;
        return 0;
      else
      else
        return create_pointer (ty);
        return create_pointer (ty);
    }
    }
  else
  else
    return direct_declarator (ty, namep, optsp);
    return direct_declarator (ty, namep, optsp);
}
}
 
 
/* declarator: '*'+ direct_declarator
/* declarator: '*'+ direct_declarator
 
 
   This is the sole public interface to this part of the grammar.
   This is the sole public interface to this part of the grammar.
   Arguments are the type known so far, a pointer to where the name
   Arguments are the type known so far, a pointer to where the name
   may be stored, and a pointer to where GTY options may be stored.
   may be stored, and a pointer to where GTY options may be stored.
   Returns the final type. */
   Returns the final type. */
 
 
static type_p
static type_p
declarator (type_p ty, const char **namep, options_p *optsp)
declarator (type_p ty, const char **namep, options_p *optsp)
{
{
  *namep = 0;
  *namep = 0;
  *optsp = 0;
  *optsp = 0;
  while (token () == '*')
  while (token () == '*')
    {
    {
      advance ();
      advance ();
      ty = create_pointer (ty);
      ty = create_pointer (ty);
    }
    }
  return direct_declarator (ty, namep, optsp);
  return direct_declarator (ty, namep, optsp);
}
}


/* Types and declarations.  */
/* Types and declarations.  */
 
 
/* Structure field(s) declaration:
/* Structure field(s) declaration:
   (
   (
       type bitfield ';'
       type bitfield ';'
     | type declarator bitfield? ( ',' declarator bitfield? )+ ';'
     | type declarator bitfield? ( ',' declarator bitfield? )+ ';'
   )+
   )+
 
 
   Knows that such declarations must end with a close brace (or,
   Knows that such declarations must end with a close brace (or,
   erroneously, at EOF).
   erroneously, at EOF).
 */
 */
static pair_p
static pair_p
struct_field_seq (void)
struct_field_seq (void)
{
{
  pair_p f = 0;
  pair_p f = 0;
  type_p ty, dty;
  type_p ty, dty;
  options_p opts, dopts;
  options_p opts, dopts;
  const char *name;
  const char *name;
  bool another;
  bool another;
 
 
  do
  do
    {
    {
      ty = type (&opts, true);
      ty = type (&opts, true);
      /* Another piece of the IFCVT_EXTRA_FIELDS special case, see type().  */
      /* Another piece of the IFCVT_EXTRA_FIELDS special case, see type().  */
      if (!ty && token () == '}')
      if (!ty && token () == '}')
        break;
        break;
 
 
      if (!ty || token () == ':')
      if (!ty || token () == ':')
        {
        {
          consume_until_semi (false);
          consume_until_semi (false);
          continue;
          continue;
        }
        }
 
 
      do
      do
        {
        {
          dty = declarator (ty, &name, &dopts);
          dty = declarator (ty, &name, &dopts);
          /* There could be any number of weird things after the declarator,
          /* There could be any number of weird things after the declarator,
             notably bitfield declarations and __attribute__s.  If this
             notably bitfield declarations and __attribute__s.  If this
             function returns true, the last thing was a comma, so we have
             function returns true, the last thing was a comma, so we have
             more than one declarator paired with the current type.  */
             more than one declarator paired with the current type.  */
          another = consume_until_comma_or_semi (false);
          another = consume_until_comma_or_semi (false);
 
 
          if (!dty)
          if (!dty)
            continue;
            continue;
 
 
          if (opts && dopts)
          if (opts && dopts)
            parse_error ("two GTY(()) options for field %s", name);
            parse_error ("two GTY(()) options for field %s", name);
          if (opts && !dopts)
          if (opts && !dopts)
            dopts = opts;
            dopts = opts;
 
 
          f = create_field_at (f, dty, name, dopts, &lexer_line);
          f = create_field_at (f, dty, name, dopts, &lexer_line);
        }
        }
      while (another);
      while (another);
    }
    }
  while (token () != '}' && token () != EOF_TOKEN);
  while (token () != '}' && token () != EOF_TOKEN);
  return nreverse_pairs (f);
  return nreverse_pairs (f);
}
}
 
 
/* This is called type(), but what it parses (sort of) is what C calls
/* This is called type(), but what it parses (sort of) is what C calls
   declaration-specifiers and specifier-qualifier-list:
   declaration-specifiers and specifier-qualifier-list:
 
 
     SCALAR
     SCALAR
   | ID     // typedef
   | ID     // typedef
   | (STRUCT|UNION) ID? gtymarker? ( '{' gtymarker? struct_field_seq '}' )?
   | (STRUCT|UNION) ID? gtymarker? ( '{' gtymarker? struct_field_seq '}' )?
   | ENUM ID ( '{' ... '}' )?
   | ENUM ID ( '{' ... '}' )?
 
 
   Returns a partial type; under some conditions (notably
   Returns a partial type; under some conditions (notably
   "struct foo GTY((...)) thing;") it may write an options
   "struct foo GTY((...)) thing;") it may write an options
   structure to *OPTSP.
   structure to *OPTSP.
 */
 */
static type_p
static type_p
type (options_p *optsp, bool nested)
type (options_p *optsp, bool nested)
{
{
  const char *s;
  const char *s;
  *optsp = 0;
  *optsp = 0;
  switch (token ())
  switch (token ())
    {
    {
    case SCALAR:
    case SCALAR:
      s = advance ();
      s = advance ();
      return create_scalar_type (s);
      return create_scalar_type (s);
 
 
    case ID:
    case ID:
    case VEC_TOKEN:
    case VEC_TOKEN:
      s = typedef_name ();
      s = typedef_name ();
      return resolve_typedef (s, &lexer_line);
      return resolve_typedef (s, &lexer_line);
 
 
    case STRUCT:
    case STRUCT:
    case UNION:
    case UNION:
      {
      {
        options_p opts = 0;
        options_p opts = 0;
    /* GTY annotations follow attribute syntax
    /* GTY annotations follow attribute syntax
       GTY_BEFORE_ID is for union/struct declarations
       GTY_BEFORE_ID is for union/struct declarations
       GTY_AFTER_ID is for variable declarations.  */
       GTY_AFTER_ID is for variable declarations.  */
    enum {
    enum {
        NO_GTY,
        NO_GTY,
        GTY_BEFORE_ID,
        GTY_BEFORE_ID,
        GTY_AFTER_ID
        GTY_AFTER_ID
    } is_gty = NO_GTY;
    } is_gty = NO_GTY;
    bool is_union = (token () == UNION);
    bool is_union = (token () == UNION);
        advance ();
        advance ();
 
 
        /* Top-level structures that are not explicitly tagged GTY(())
        /* Top-level structures that are not explicitly tagged GTY(())
           are treated as mere forward declarations.  This is because
           are treated as mere forward declarations.  This is because
           there are a lot of structures that we don't need to know
           there are a lot of structures that we don't need to know
           about, and some of those have weird macro stuff in them
           about, and some of those have weird macro stuff in them
           that we can't handle.  */
           that we can't handle.  */
        if (nested || token () == GTY_TOKEN)
        if (nested || token () == GTY_TOKEN)
          {
          {
        is_gty = GTY_BEFORE_ID;
        is_gty = GTY_BEFORE_ID;
        opts = gtymarker_opt ();
        opts = gtymarker_opt ();
          }
          }
 
 
        if (token () == ID)
        if (token () == ID)
          s = advance ();
          s = advance ();
        else
        else
          s = xasprintf ("anonymous:%s:%d", lexer_line.file, lexer_line.line);
          s = xasprintf ("anonymous:%s:%d", lexer_line.file, lexer_line.line);
 
 
        /* Unfortunately above GTY_TOKEN check does not capture the
        /* Unfortunately above GTY_TOKEN check does not capture the
           typedef struct_type GTY case.  */
           typedef struct_type GTY case.  */
        if (token () == GTY_TOKEN)
        if (token () == GTY_TOKEN)
          {
          {
        is_gty = GTY_AFTER_ID;
        is_gty = GTY_AFTER_ID;
        opts = gtymarker_opt ();
        opts = gtymarker_opt ();
          }
          }
 
 
    if (is_gty)
    if (is_gty)
      {
      {
        if (token () == '{')
        if (token () == '{')
          {
          {
            pair_p fields;
            pair_p fields;
 
 
            if (is_gty == GTY_AFTER_ID)
            if (is_gty == GTY_AFTER_ID)
                parse_error ("GTY must be specified before identifier");
                parse_error ("GTY must be specified before identifier");
 
 
            advance ();
            advance ();
            fields = struct_field_seq ();
            fields = struct_field_seq ();
            require ('}');
            require ('}');
            return new_structure (s, is_union, &lexer_line, fields, opts);
            return new_structure (s, is_union, &lexer_line, fields, opts);
          }
          }
      }
      }
    else if (token () == '{')
    else if (token () == '{')
      consume_balanced ('{', '}');
      consume_balanced ('{', '}');
        if (opts)
        if (opts)
          *optsp = opts;
          *optsp = opts;
        return find_structure (s, is_union);
        return find_structure (s, is_union);
      }
      }
 
 
    case ENUM:
    case ENUM:
      advance ();
      advance ();
        if (token () == ID)
        if (token () == ID)
          s = advance ();
          s = advance ();
        else
        else
          s = xasprintf ("anonymous:%s:%d", lexer_line.file, lexer_line.line);
          s = xasprintf ("anonymous:%s:%d", lexer_line.file, lexer_line.line);
 
 
      if (token () == '{')
      if (token () == '{')
        consume_balanced ('{','}');
        consume_balanced ('{','}');
      return create_scalar_type (s);
      return create_scalar_type (s);
 
 
    default:
    default:
      parse_error ("expected a type specifier, have %s", print_cur_token ());
      parse_error ("expected a type specifier, have %s", print_cur_token ());
      advance ();
      advance ();
      return create_scalar_type ("erroneous type");
      return create_scalar_type ("erroneous type");
    }
    }
}
}


/* Top level constructs.  */
/* Top level constructs.  */
 
 
/* Dispatch declarations beginning with 'typedef'.  */
/* Dispatch declarations beginning with 'typedef'.  */
 
 
static void
static void
typedef_decl (void)
typedef_decl (void)
{
{
  type_p ty, dty;
  type_p ty, dty;
  const char *name;
  const char *name;
  options_p opts;
  options_p opts;
  bool another;
  bool another;
 
 
  gcc_assert (token () == TYPEDEF);
  gcc_assert (token () == TYPEDEF);
  advance ();
  advance ();
 
 
  ty = type (&opts, false);
  ty = type (&opts, false);
  if (!ty)
  if (!ty)
    return;
    return;
  if (opts)
  if (opts)
    parse_error ("GTY((...)) cannot be applied to a typedef");
    parse_error ("GTY((...)) cannot be applied to a typedef");
  do
  do
    {
    {
      dty = declarator (ty, &name, &opts);
      dty = declarator (ty, &name, &opts);
      if (opts)
      if (opts)
        parse_error ("GTY((...)) cannot be applied to a typedef");
        parse_error ("GTY((...)) cannot be applied to a typedef");
 
 
      /* Yet another place where we could have junk (notably attributes)
      /* Yet another place where we could have junk (notably attributes)
         after the declarator.  */
         after the declarator.  */
      another = consume_until_comma_or_semi (false);
      another = consume_until_comma_or_semi (false);
      if (dty)
      if (dty)
        do_typedef (name, dty, &lexer_line);
        do_typedef (name, dty, &lexer_line);
    }
    }
  while (another);
  while (another);
}
}
 
 
/* Structure definition: type() does all the work.  */
/* Structure definition: type() does all the work.  */
 
 
static void
static void
struct_or_union (void)
struct_or_union (void)
{
{
  options_p dummy;
  options_p dummy;
  type (&dummy, false);
  type (&dummy, false);
  /* There may be junk after the type: notably, we cannot currently
  /* There may be junk after the type: notably, we cannot currently
     distinguish 'struct foo *function(prototype);' from 'struct foo;'
     distinguish 'struct foo *function(prototype);' from 'struct foo;'
     ...  we could call declarator(), but it's a waste of time at
     ...  we could call declarator(), but it's a waste of time at
     present.  Instead, just eat whatever token is currently lookahead
     present.  Instead, just eat whatever token is currently lookahead
     and go back to lexical skipping mode. */
     and go back to lexical skipping mode. */
  advance ();
  advance ();
}
}
 
 
/* GC root declaration:
/* GC root declaration:
     (extern|static) gtymarker? type ID array_declarators_opt (';'|'=')
     (extern|static) gtymarker? type ID array_declarators_opt (';'|'=')
   If the gtymarker is not present, we ignore the rest of the declaration.  */
   If the gtymarker is not present, we ignore the rest of the declaration.  */
static void
static void
extern_or_static (void)
extern_or_static (void)
{
{
  options_p opts, opts2, dopts;
  options_p opts, opts2, dopts;
  type_p ty, dty;
  type_p ty, dty;
  const char *name;
  const char *name;
  require2 (EXTERN, STATIC);
  require2 (EXTERN, STATIC);
 
 
  if (token () != GTY_TOKEN)
  if (token () != GTY_TOKEN)
    {
    {
      advance ();
      advance ();
      return;
      return;
    }
    }
 
 
  opts = gtymarker ();
  opts = gtymarker ();
  ty   = type (&opts2, true);  /* if we get here, it's got a GTY(()) */
  ty   = type (&opts2, true);  /* if we get here, it's got a GTY(()) */
  dty  = declarator (ty, &name, &dopts);
  dty  = declarator (ty, &name, &dopts);
 
 
  if ((opts && dopts) || (opts && opts2) || (opts2 && dopts))
  if ((opts && dopts) || (opts && opts2) || (opts2 && dopts))
    parse_error ("GTY((...)) specified more than once for %s", name);
    parse_error ("GTY((...)) specified more than once for %s", name);
  else if (opts2)
  else if (opts2)
    opts = opts2;
    opts = opts2;
  else if (dopts)
  else if (dopts)
    opts = dopts;
    opts = dopts;
 
 
  if (dty)
  if (dty)
    {
    {
      note_variable (name, adjust_field_type (dty, opts), opts, &lexer_line);
      note_variable (name, adjust_field_type (dty, opts), opts, &lexer_line);
      require2 (';', '=');
      require2 (';', '=');
    }
    }
}
}
 
 
/* Definition of a generic VEC structure:
/* Definition of a generic VEC structure:
 
 
   'DEF_VEC_[IPO]' '(' id ')' ';'
   'DEF_VEC_[IPO]' '(' id ')' ';'
 
 
   Scalar VECs require slightly different treatment than otherwise -
   Scalar VECs require slightly different treatment than otherwise -
   that's handled in note_def_vec, we just pass it along.*/
   that's handled in note_def_vec, we just pass it along.*/
static void
static void
def_vec (void)
def_vec (void)
{
{
  bool is_scalar = (token() == DEFVEC_I);
  bool is_scalar = (token() == DEFVEC_I);
  const char *type;
  const char *type;
 
 
  require2 (DEFVEC_OP, DEFVEC_I);
  require2 (DEFVEC_OP, DEFVEC_I);
  require ('(');
  require ('(');
  type = require2 (ID, SCALAR);
  type = require2 (ID, SCALAR);
  require (')');
  require (')');
  require (';');
  require (';');
 
 
  if (!type)
  if (!type)
    return;
    return;
 
 
  note_def_vec (type, is_scalar, &lexer_line);
  note_def_vec (type, is_scalar, &lexer_line);
  note_def_vec_alloc (type, "none", &lexer_line);
  note_def_vec_alloc (type, "none", &lexer_line);
}
}
 
 
/* Definition of an allocation strategy for a VEC structure:
/* Definition of an allocation strategy for a VEC structure:
 
 
   'DEF_VEC_ALLOC_[IPO]' '(' id ',' id ')' ';'
   'DEF_VEC_ALLOC_[IPO]' '(' id ',' id ')' ';'
 
 
   For purposes of gengtype, this just declares a wrapper structure.  */
   For purposes of gengtype, this just declares a wrapper structure.  */
static void
static void
def_vec_alloc (void)
def_vec_alloc (void)
{
{
  const char *type, *astrat;
  const char *type, *astrat;
 
 
  require (DEFVEC_ALLOC);
  require (DEFVEC_ALLOC);
  require ('(');
  require ('(');
  type = require2 (ID, SCALAR);
  type = require2 (ID, SCALAR);
  require (',');
  require (',');
  astrat = require (ID);
  astrat = require (ID);
  require (')');
  require (')');
  require (';');
  require (';');
 
 
  if (!type || !astrat)
  if (!type || !astrat)
    return;
    return;
 
 
  note_def_vec_alloc (type, astrat, &lexer_line);
  note_def_vec_alloc (type, astrat, &lexer_line);
}
}
 
 
/* Parse the file FNAME for GC-relevant declarations and definitions.
/* Parse the file FNAME for GC-relevant declarations and definitions.
   This is the only entry point to this file.  */
   This is the only entry point to this file.  */
void
void
parse_file (const char *fname)
parse_file (const char *fname)
{
{
  yybegin (fname);
  yybegin (fname);
  for (;;)
  for (;;)
    {
    {
      switch (token ())
      switch (token ())
        {
        {
        case EXTERN:
        case EXTERN:
        case STATIC:
        case STATIC:
          extern_or_static ();
          extern_or_static ();
          break;
          break;
 
 
        case STRUCT:
        case STRUCT:
        case UNION:
        case UNION:
          struct_or_union ();
          struct_or_union ();
          break;
          break;
 
 
        case TYPEDEF:
        case TYPEDEF:
          typedef_decl ();
          typedef_decl ();
          break;
          break;
 
 
        case DEFVEC_OP:
        case DEFVEC_OP:
        case DEFVEC_I:
        case DEFVEC_I:
          def_vec ();
          def_vec ();
          break;
          break;
 
 
        case DEFVEC_ALLOC:
        case DEFVEC_ALLOC:
          def_vec_alloc ();
          def_vec_alloc ();
          break;
          break;
 
 
        case EOF_TOKEN:
        case EOF_TOKEN:
          goto eof;
          goto eof;
 
 
        default:
        default:
          parse_error ("unexpected top level token, %s", print_cur_token ());
          parse_error ("unexpected top level token, %s", print_cur_token ());
          goto eof;
          goto eof;
        }
        }
      lexer_toplevel_done = 1;
      lexer_toplevel_done = 1;
    }
    }
 
 
 eof:
 eof:
  advance ();
  advance ();
  yyend ();
  yyend ();
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.