OSDN Git Service

* builtins.c, c-common.c, c-decl.c, c-format.c, c-format.h,
[pf3gnuchains/gcc-fork.git] / gcc / c-parse.in
index 16cbd22..86880ac 100644 (file)
@@ -50,12 +50,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "output.h"
 #include "toplev.h"
 #include "ggc.h"
+#include "c-common.h"
 
-@@ifobjc
-#include "objc-act.h"
-@@end_ifobjc
-
-/* Like YYERROR but do call yyerror.  */
 #define YYERROR1 { yyerror ("syntax error"); YYERROR; }
 
 /* Like the default stack expander, except (1) use realloc when possible,
@@ -102,8 +98,11 @@ do {                                                                        \
 
 %start program
 
-%union {long itype; tree ttype; struct c_expr exprtype; enum tree_code code;
-       location_t location; }
+%union {long itype; tree ttype; void *otype; struct c_expr exprtype;
+       struct c_arg_info *arginfotype; struct c_declarator *dtrtype;
+       struct c_type_name *typenametype; struct c_parm *parmtype;
+       struct c_declspecs *dsptype; struct c_typespec tstype;
+       enum tree_code code; location_t location; }
 
 /* All identifiers that are not reserved words
    and are not declared typedefs in the current block */
@@ -127,6 +126,10 @@ do {                                                                       \
    yylval contains an IDENTIFIER_NODE which indicates which one.  */
 %token TYPE_QUAL
 
+/* Objective-C protocol qualifiers.  These acquire their magic powers
+   only in certain contexts.  */
+%token OBJC_TYPE_QUAL
+
 /* Character or numeric constants.
    yylval is the node for the constant.  */
 %token CONSTANT
@@ -145,7 +148,6 @@ do {                                                                        \
 %token BREAK CONTINUE RETURN GOTO ASM_KEYWORD TYPEOF ALIGNOF
 %token ATTRIBUTE EXTENSION LABEL
 %token REALPART IMAGPART VA_ARG CHOOSE_EXPR TYPES_COMPATIBLE_P
-%token PTR_VALUE PTR_BASE PTR_EXTENT
 %token FUNC_NAME OFFSETOF
 
 /* Add precedence rules to solve dangling else s/r conflict */
@@ -175,8 +177,8 @@ do {                                                                        \
 /* The Objective-C keywords.  These are included in C and in
    Objective C, so that the token codes are the same in both.  */
 %token AT_INTERFACE AT_IMPLEMENTATION AT_END AT_SELECTOR AT_DEFS AT_ENCODE
-%token CLASSNAME AT_PUBLIC AT_PRIVATE AT_PROTECTED AT_PROTOCOL 
-%token OBJECTNAME AT_CLASS AT_ALIAS
+%token CLASSNAME AT_PUBLIC AT_PRIVATE AT_PROTECTED AT_PROTOCOL
+%token AT_CLASS AT_ALIAS
 %token AT_THROW AT_TRY AT_CATCH AT_FINALLY AT_SYNCHRONIZED
 %token OBJC_STRING
 
@@ -187,20 +189,21 @@ do {                                                                      \
 %type <ttype> identifier IDENTIFIER TYPENAME CONSTANT STRING FUNC_NAME
 %type <ttype> nonnull_exprlist exprlist
 %type <exprtype> expr expr_no_commas cast_expr unary_expr primary
-%type <ttype> declspecs_nosc_nots_nosa_noea declspecs_nosc_nots_nosa_ea
-%type <ttype> declspecs_nosc_nots_sa_noea declspecs_nosc_nots_sa_ea
-%type <ttype> declspecs_nosc_ts_nosa_noea declspecs_nosc_ts_nosa_ea
-%type <ttype> declspecs_nosc_ts_sa_noea declspecs_nosc_ts_sa_ea
-%type <ttype> declspecs_sc_nots_nosa_noea declspecs_sc_nots_nosa_ea
-%type <ttype> declspecs_sc_nots_sa_noea declspecs_sc_nots_sa_ea
-%type <ttype> declspecs_sc_ts_nosa_noea declspecs_sc_ts_nosa_ea
-%type <ttype> declspecs_sc_ts_sa_noea declspecs_sc_ts_sa_ea
-%type <ttype> declspecs_ts declspecs_nots
-%type <ttype> declspecs_ts_nosa declspecs_nots_nosa
-%type <ttype> declspecs_nosc_ts declspecs_nosc_nots declspecs_nosc declspecs
-%type <ttype> maybe_type_quals_attrs typespec_nonattr typespec_attr
-%type <ttype> typespec_reserved_nonattr typespec_reserved_attr
-%type <ttype> typespec_nonreserved_nonattr
+%type <dsptype> declspecs_nosc_nots_nosa_noea declspecs_nosc_nots_nosa_ea
+%type <dsptype> declspecs_nosc_nots_sa_noea declspecs_nosc_nots_sa_ea
+%type <dsptype> declspecs_nosc_ts_nosa_noea declspecs_nosc_ts_nosa_ea
+%type <dsptype> declspecs_nosc_ts_sa_noea declspecs_nosc_ts_sa_ea
+%type <dsptype> declspecs_sc_nots_nosa_noea declspecs_sc_nots_nosa_ea
+%type <dsptype> declspecs_sc_nots_sa_noea declspecs_sc_nots_sa_ea
+%type <dsptype> declspecs_sc_ts_nosa_noea declspecs_sc_ts_nosa_ea
+%type <dsptype> declspecs_sc_ts_sa_noea declspecs_sc_ts_sa_ea
+%type <dsptype> declspecs_ts declspecs_nots
+%type <dsptype> declspecs_ts_nosa declspecs_nots_nosa
+%type <dsptype> declspecs_nosc_ts declspecs_nosc_nots declspecs_nosc declspecs
+%type <dsptype> maybe_type_quals_attrs
+%type <tstype> typespec_nonattr typespec_attr
+%type <tstype> typespec_reserved_nonattr typespec_reserved_attr
+%type <tstype> typespec_nonreserved_nonattr
 %type <ttype> offsetof_member_designator
 
 %type <ttype> scspec SCSPEC STATIC TYPESPEC TYPE_QUAL maybe_volatile
@@ -216,50 +219,55 @@ do {                                                                      \
 
 %type <ttype> c99_block_start c99_block_lineno_labeled_stmt
 %type <ttype> if_statement_1 if_statement_2
-%type <ttype> declarator
-%type <ttype> notype_declarator after_type_declarator
-%type <ttype> parm_declarator
-%type <ttype> parm_declarator_starttypename parm_declarator_nostarttypename
-%type <ttype> array_declarator
+%type <dtrtype> declarator
+%type <dtrtype> notype_declarator after_type_declarator
+%type <dtrtype> parm_declarator
+%type <dtrtype> parm_declarator_starttypename parm_declarator_nostarttypename
+%type <dtrtype> array_declarator
 
-%type <ttype> structsp_attr structsp_nonattr
+%type <tstype> structsp_attr structsp_nonattr
 %type <ttype> component_decl_list component_decl_list2
 %type <ttype> component_decl components components_notype component_declarator
 %type <ttype> component_notype_declarator
 %type <ttype> enumlist enumerator
 %type <ttype> struct_head union_head enum_head
-%type <ttype> typename absdcl absdcl1 absdcl1_ea absdcl1_noea
-%type <ttype> direct_absdcl1 absdcl_maybe_attribute
+%type <typenametype> typename
+%type <dtrtype> absdcl absdcl1 absdcl1_ea absdcl1_noea direct_absdcl1
+%type <parmtype> absdcl_maybe_attribute
 %type <ttype> condition xexpr for_cond_expr for_incr_expr
-%type <ttype> parms parm firstparm identifiers
+%type <parmtype> parm firstparm
+%type <ttype> identifiers
 
-%type <ttype> parmlist parmlist_1 parmlist_2
-%type <ttype> parmlist_or_identifiers parmlist_or_identifiers_1
+%type <arginfotype> parms parmlist parmlist_1 parmlist_2
+%type <arginfotype> parmlist_or_identifiers parmlist_or_identifiers_1
 %type <ttype> identifiers_or_typenames
 
 %type <itype> setspecs setspecs_fp extension
 
 %type <location> save_location
+
+%type <otype> save_obstack_position
 \f
 @@ifobjc
 /* the Objective-C nonterminals */
 
-%type <ttype> ivar_decl_list ivar_decls ivar_decl ivars ivar_declarator
 %type <ttype> methoddecl unaryselector keywordselector selector
+%type <code> methodtype
 %type <ttype> keyworddecl receiver objcmessageexpr messageargs
 %type <ttype> keywordexpr keywordarglist keywordarg
-%type <ttype> myparms myparm optparmlist reservedwords objcselectorexpr
+%type <ttype> optparmlist optparms reservedwords objcselectorexpr
 %type <ttype> selectorarg keywordnamelist keywordname objcencodeexpr
 %type <ttype> non_empty_protocolrefs protocolrefs identifier_list objcprotocolexpr
 
-%type <ttype> CLASSNAME OBJECTNAME OBJC_STRING
+%type <ttype> CLASSNAME OBJC_STRING OBJC_TYPE_QUAL
 
-%type <ttype> superclass
+%type <ttype> superclass objc_quals objc_qual objc_typename
+%type <itype> objc_try_catch_stmt optellipsis
 @@end_ifobjc
 \f
 %{
-/* List of types and structure classes of the current declaration.  */
-static GTY(()) tree current_declspecs;
+/* Declaration specifiers of the current declaration.  */
+static struct c_declspecs *current_declspecs;
 static GTY(()) tree prefix_attributes;
 
 /* List of all the attributes applying to the identifier currently being
@@ -267,26 +275,44 @@ static GTY(()) tree prefix_attributes;
    just after a comma.  */
 static GTY(()) tree all_prefix_attributes;
 
+/* Structure to save declaration specifiers.  */
+struct c_declspec_stack {
+  /* Saved value of current_declspecs.  */
+  struct c_declspecs *current_declspecs;
+  /* Saved value of prefix_attributes.  */
+  tree prefix_attributes;
+  /* Saved value of all_prefix_attributes.  */
+  tree all_prefix_attributes;
+  /* Next level of stack.  */
+  struct c_declspec_stack *next;
+};
+
 /* Stack of saved values of current_declspecs, prefix_attributes and
    all_prefix_attributes.  */
-static GTY(()) tree declspec_stack;
+static struct c_declspec_stack *declspec_stack;
+
+/* INDIRECT_REF with a TREE_TYPE of the type being queried for offsetof.  */
+static tree offsetof_base;
 
 /* PUSH_DECLSPEC_STACK is called from setspecs; POP_DECLSPEC_STACK
    should be called from the productions making use of setspecs.  */
-#define PUSH_DECLSPEC_STACK                                             \
-  do {                                                                  \
-    declspec_stack = tree_cons (build_tree_list (prefix_attributes,     \
-                                                all_prefix_attributes), \
-                               current_declspecs,                       \
-                               declspec_stack);                         \
+#define PUSH_DECLSPEC_STACK                                            \
+  do {                                                                 \
+    struct c_declspec_stack *t = XOBNEW (&parser_obstack,              \
+                                        struct c_declspec_stack);      \
+    t->current_declspecs = current_declspecs;                          \
+    t->prefix_attributes = prefix_attributes;                          \
+    t->all_prefix_attributes = all_prefix_attributes;                  \
+    t->next = declspec_stack;                                          \
+    declspec_stack = t;                                                        \
   } while (0)
 
 #define POP_DECLSPEC_STACK                                             \
   do {                                                                 \
-    current_declspecs = TREE_VALUE (declspec_stack);                   \
-    prefix_attributes = TREE_PURPOSE (TREE_PURPOSE (declspec_stack));  \
-    all_prefix_attributes = TREE_VALUE (TREE_PURPOSE (declspec_stack));        \
-    declspec_stack = TREE_CHAIN (declspec_stack);                      \
+    current_declspecs = declspec_stack->current_declspecs;             \
+    prefix_attributes = declspec_stack->prefix_attributes;             \
+    all_prefix_attributes = declspec_stack->all_prefix_attributes;     \
+    declspec_stack = declspec_stack->next;                             \
   } while (0)
 
 /* For __extension__, save/restore the warning flags which are
@@ -308,8 +334,7 @@ static GTY(()) tree declspec_stack;
 @@ifobjc
 /* Objective-C specific parser/lexer information */
 
-static enum tree_code objc_inherit_code;
-static int objc_pq_context = 0, objc_public_flag = 0;
+static int objc_pq_context = 0;
 
 /* The following flag is needed to contextualize ObjC lexical analysis.
    In some cases (e.g., 'int NSObject;'), it is undesirable to bind
@@ -334,7 +359,7 @@ static inline int _yylex (void);
 static int  yylex (void);
 static void init_reswords (void);
 
-  /* Initialisation routine for this file.  */
+  /* Initialization routine for this file.  */
 void
 c_parse_init (void)
 {
@@ -353,11 +378,14 @@ program: /* empty */
 
 /* the reason for the strange actions in this rule
  is so that notype_initdecls when reached via datadef
- can find a valid list of type and sc specs in $0. */
+ can find valid declaration specifiers in $0. */
 
 extdefs:
-       {$<ttype>$ = NULL_TREE; } extdef
-       | extdefs {$<ttype>$ = NULL_TREE; ggc_collect(); } extdef
+       save_obstack_position { $<dsptype>$ = NULL; } extdef
+               { obstack_free (&parser_obstack, $1); }
+       | extdefs save_obstack_position
+               { $<dsptype>$ = NULL; ggc_collect (); } extdef
+               { obstack_free (&parser_obstack, $2); }
        ;
 
 extdef:
@@ -371,31 +399,33 @@ extdef:
 @@end_ifobjc
        ;
 
+/* Record the current position of parser_obstack before a
+   declaration to restore it afterwards.  */
+save_obstack_position:
+               { $$ = obstack_alloc (&parser_obstack, 0); }
+       ;
+
 datadef:
          setspecs notype_initdecls ';'
-               { if (pedantic)
-                   error ("ISO C forbids data definition with no type or storage class");
-                 else
-                   warning ("data definition has no type or storage class");
-
+               { pedwarn ("data definition has no type or storage class");
                  POP_DECLSPEC_STACK; }
         | declspecs_nots setspecs notype_initdecls ';'
                { POP_DECLSPEC_STACK; }
        | declspecs_ts setspecs initdecls ';'
                { POP_DECLSPEC_STACK; }
        | declspecs ';'
-         { shadow_tag ($1); }
+         { shadow_tag (finish_declspecs ($1)); }
        | error ';'
        | error '}'
        | ';'
                { if (pedantic)
-                   pedwarn ("ISO C does not allow extra `;' outside of a function"); }
+                   pedwarn ("ISO C does not allow extra %<;%> outside of a function"); }
        ;
 \f
 fndef:
          declspecs_ts setspecs declarator
-               { if (! start_function (current_declspecs, $3,
-                                       all_prefix_attributes))
+               { if (!start_function (current_declspecs, $3,
+                                      all_prefix_attributes))
                    YYERROR1;
                }
          old_style_parm_decls save_location
@@ -407,8 +437,8 @@ fndef:
        | declspecs_ts setspecs declarator error
                { POP_DECLSPEC_STACK; }
        | declspecs_nots setspecs notype_declarator
-               { if (! start_function (current_declspecs, $3,
-                                       all_prefix_attributes))
+               { if (!start_function (current_declspecs, $3,
+                                      all_prefix_attributes))
                    YYERROR1;
                }
          old_style_parm_decls save_location
@@ -420,8 +450,8 @@ fndef:
        | declspecs_nots setspecs notype_declarator error
                { POP_DECLSPEC_STACK; }
        | setspecs notype_declarator
-               { if (! start_function (NULL_TREE, $2,
-                                       all_prefix_attributes))
+               { if (!start_function (current_declspecs, $2,
+                                      all_prefix_attributes))
                    YYERROR1;
                }
          old_style_parm_decls save_location
@@ -438,7 +468,6 @@ identifier:
        IDENTIFIER
        | TYPENAME
 @@ifobjc
-       | OBJECTNAME
        | CLASSNAME
 @@end_ifobjc
        ;
@@ -502,21 +531,23 @@ unary_expr:
                  $$.original_code = ERROR_MARK; }
        | sizeof unary_expr  %prec UNARY
                { skip_evaluation--;
+                 in_sizeof--;
                  if (TREE_CODE ($2.value) == COMPONENT_REF
                      && DECL_C_BIT_FIELD (TREE_OPERAND ($2.value, 1)))
-                   error ("`sizeof' applied to a bit-field");
-                 $$.value = c_sizeof (TREE_TYPE ($2.value));
-                 $$.original_code = ERROR_MARK; }
+                   error ("%<sizeof%> applied to a bit-field");
+                 $$ = c_expr_sizeof_expr ($2); }
        | sizeof '(' typename ')'  %prec HYPERUNARY
                { skip_evaluation--;
-                 $$.value = c_sizeof (groktypename ($3));
-                 $$.original_code = ERROR_MARK; }
+                 in_sizeof--;
+                 $$ = c_expr_sizeof_type ($3); }
        | alignof unary_expr  %prec UNARY
                { skip_evaluation--;
+                 in_alignof--;
                  $$.value = c_alignof_expr ($2.value);
                  $$.original_code = ERROR_MARK; }
        | alignof '(' typename ')'  %prec HYPERUNARY
                { skip_evaluation--;
+                 in_alignof--;
                  $$.value = c_alignof (groktypename ($3));
                  $$.original_code = ERROR_MARK; }
        | REALPART cast_expr %prec UNARY
@@ -528,15 +559,15 @@ unary_expr:
        ;
 
 sizeof:
-       SIZEOF { skip_evaluation++; }
+       SIZEOF { skip_evaluation++; in_sizeof++; }
        ;
 
 alignof:
-       ALIGNOF { skip_evaluation++; }
+       ALIGNOF { skip_evaluation++; in_alignof++; }
        ;
 
 typeof:
-       TYPEOF { skip_evaluation++; }
+       TYPEOF { skip_evaluation++; in_typeof++; }
        ;
 
 cast_expr:
@@ -638,16 +669,21 @@ primary:
                  $$.original_code = ERROR_MARK; }
        | '(' typename ')' '{'
                { start_init (NULL_TREE, NULL, 0);
-                 $2 = groktypename ($2);
-                 really_start_incremental_init ($2); }
+                 $<ttype>$ = groktypename ($2);
+                 if (C_TYPE_VARIABLE_SIZE ($<ttype>$))
+                   {
+                     error ("compound literal has variable size");
+                     $<ttype>$ = error_mark_node;
+                   }
+                 really_start_incremental_init ($<ttype>$); }
          initlist_maybe_comma '}'  %prec UNARY
                { struct c_expr init = pop_init_level (0);
                  tree constructor = init.value;
-                 tree type = $2;
+                 tree type = $<ttype>5;
                  finish_init ();
                  maybe_warn_string_init (type, init);
 
-                 if (pedantic && ! flag_isoc99)
+                 if (pedantic && !flag_isoc99)
                    pedwarn ("ISO C90 forbids compound literals");
                  $$.value = build_compound_literal (type, constructor);
                  $$.original_code = ERROR_MARK;
@@ -677,8 +713,15 @@ primary:
                { $$.value = build_va_arg ($3.value, groktypename ($5));
                  $$.original_code = ERROR_MARK; }
 
-       | OFFSETOF '(' typename ',' offsetof_member_designator ')'
-               { $$.value = build_offsetof (groktypename ($3), $5);
+       | OFFSETOF '(' typename ','
+               { tree type = groktypename ($3);
+                 if (type == error_mark_node)
+                   offsetof_base = error_mark_node;
+                 else
+                   offsetof_base = build1 (INDIRECT_REF, type, NULL);
+               }
+         offsetof_member_designator ')'
+               { $$.value = fold_offsetof ($6);
                  $$.original_code = ERROR_MARK; }
        | OFFSETOF '(' error ')'
                { $$.value = error_mark_node; $$.original_code = ERROR_MARK; }
@@ -690,7 +733,7 @@ primary:
                   c = fold ($3.value);
                   STRIP_NOPS (c);
                   if (TREE_CODE (c) != INTEGER_CST)
-                    error ("first argument to __builtin_choose_expr not"
+                    error ("first argument to %<__builtin_choose_expr%> not"
                           " a constant");
                   $$ = integer_zerop (c) ? $7 : $5;
                }
@@ -730,36 +773,34 @@ primary:
                  $$.original_code = ERROR_MARK; }
 @@ifobjc
        | objcmessageexpr
-               { $$.value = build_message_expr ($1);
+               { $$.value = objc_build_message_expr ($1);
                  $$.original_code = ERROR_MARK; }
        | objcselectorexpr
-               { $$.value = build_selector_expr ($1);
+               { $$.value = objc_build_selector_expr ($1);
                  $$.original_code = ERROR_MARK; }
        | objcprotocolexpr
-               { $$.value = build_protocol_expr ($1);
+               { $$.value = objc_build_protocol_expr ($1);
                  $$.original_code = ERROR_MARK; }
        | objcencodeexpr
-               { $$.value = build_encode_expr ($1);
+               { $$.value = objc_build_encode_expr ($1);
                  $$.original_code = ERROR_MARK; }
        | OBJC_STRING
-               { $$.value = build_objc_string_object ($1);
+               { $$.value = objc_build_string_object ($1);
                  $$.original_code = ERROR_MARK; }
 @@end_ifobjc
        ;
 
 /* This is the second argument to __builtin_offsetof.  We must have one
    identifier, and beyond that we want to accept sub structure and sub
-   array references.  We return tree list where each element has
-   PURPOSE set for component refs or VALUE set for array refs.  We'll
-   turn this into something real inside build_offsetof.  */
+   array references.  */
 
 offsetof_member_designator:
          identifier
-               { $$ = tree_cons ($1, NULL_TREE, NULL_TREE); }
+               { $$ = build_component_ref (offsetof_base, $1); }
        | offsetof_member_designator '.' identifier
-               { $$ = tree_cons ($3, NULL_TREE, $1); }
+               { $$ = build_component_ref ($1, $3); }
        | offsetof_member_designator '[' expr ']'
-               { $$ = tree_cons (NULL_TREE, $3.value, $1); }
+               { $$ = build_array_ref ($1, $3.value); }
        ;
 
 old_style_parm_decls:
@@ -792,7 +833,7 @@ datadecl:
        | declspecs_nots_nosa setspecs notype_initdecls ';'
                { POP_DECLSPEC_STACK; }
        | declspecs_ts_nosa ';'
-               { shadow_tag_warned ($1, 1);
+               { shadow_tag_warned (finish_declspecs ($1), 1);
                  pedwarn ("empty declaration"); }
        | declspecs_nots_nosa ';'
                { pedwarn ("empty declaration"); }
@@ -814,8 +855,18 @@ lineno_decl:
 setspecs: /* empty */
                { pending_xref_error ();
                  PUSH_DECLSPEC_STACK;
-                 split_specs_attrs ($<ttype>0,
-                                    &current_declspecs, &prefix_attributes);
+                 if ($<dsptype>0)
+                   {
+                     prefix_attributes = $<dsptype>0->attrs;
+                     $<dsptype>0->attrs = NULL_TREE;
+                     current_declspecs = $<dsptype>0;
+                   }
+                 else
+                   {
+                     prefix_attributes = NULL_TREE;
+                     current_declspecs = build_null_declspecs ();
+                   }
+                 current_declspecs = finish_declspecs (current_declspecs);
                  all_prefix_attributes = prefix_attributes; }
        ;
 
@@ -836,7 +887,7 @@ decl:
        | declspecs_nots setspecs notype_nested_function
                { POP_DECLSPEC_STACK; }
        | declspecs ';'
-               { shadow_tag ($1); }
+               { shadow_tag (finish_declspecs ($1)); }
        | extension decl
                { RESTORE_EXT_FLAGS ($1); }
        ;
@@ -852,16 +903,6 @@ decl:
 
    - Attribute specifier lists (attributes).
 
-   These are stored as a TREE_LIST; the head of the list is the last
-   item in the specifier list.  Each entry in the list has either a
-   TREE_PURPOSE that is an attribute specifier list, or a TREE_VALUE that
-   is a single other specifier or qualifier; and a TREE_CHAIN that is the
-   rest of the list.  TREE_STATIC is set on the list if something other
-   than a storage class specifier or attribute has been seen; this is used
-   to warn for the obsolescent usage of storage class specifiers other than
-   at the start of the list.  (Doing this properly would require function
-   specifiers to be handled separately from storage class specifiers.)
-
    The various cases below are classified according to:
 
    (a) Whether a storage class specifier is included or not; some
@@ -890,334 +931,208 @@ decl:
 
 /* Declspecs which contain at least one type specifier or typedef name.
    (Just `const' or `volatile' is not enough.)
-   A typedef'd name following these is taken as a name to be declared.
-   Declspecs have a non-NULL TREE_VALUE, attributes do not.  */
+   A typedef'd name following these is taken as a name to be declared.  */
 
 declspecs_nosc_nots_nosa_noea:
          TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $1, NULL_TREE);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual (build_null_declspecs (), $1); }
        | declspecs_nosc_nots_nosa_noea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_nosc_nots_nosa_ea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        ;
 
 declspecs_nosc_nots_nosa_ea:
          declspecs_nosc_nots_nosa_noea attributes
-               { $$ = tree_cons ($2, NULL_TREE, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_attrs ($1, $2); }
        ;
 
 declspecs_nosc_nots_sa_noea:
          declspecs_nosc_nots_sa_noea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_nosc_nots_sa_ea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        ;
 
 declspecs_nosc_nots_sa_ea:
          attributes
-               { $$ = tree_cons ($1, NULL_TREE, NULL_TREE);
-                 TREE_STATIC ($$) = 0; }
+               { $$ = declspecs_add_attrs (build_null_declspecs (), $1); }
        | declspecs_nosc_nots_sa_noea attributes
-               { $$ = tree_cons ($2, NULL_TREE, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_attrs ($1, $2); }
        ;
 
 declspecs_nosc_ts_nosa_noea:
          typespec_nonattr
-               { $$ = tree_cons (NULL_TREE, $1, NULL_TREE);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type (build_null_declspecs (), $1); }
        | declspecs_nosc_ts_nosa_noea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_nosc_ts_nosa_ea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_nosc_ts_nosa_noea typespec_reserved_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_ts_nosa_ea typespec_reserved_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_nots_nosa_noea typespec_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_nots_nosa_ea typespec_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        ;
 
 declspecs_nosc_ts_nosa_ea:
          typespec_attr
-               { $$ = tree_cons (NULL_TREE, $1, NULL_TREE);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type (build_null_declspecs (), $1); }
        | declspecs_nosc_ts_nosa_noea attributes
-               { $$ = tree_cons ($2, NULL_TREE, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_attrs ($1, $2); }
        | declspecs_nosc_ts_nosa_noea typespec_reserved_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_ts_nosa_ea typespec_reserved_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_nots_nosa_noea typespec_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_nots_nosa_ea typespec_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        ;
 
 declspecs_nosc_ts_sa_noea:
          declspecs_nosc_ts_sa_noea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_nosc_ts_sa_ea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_nosc_ts_sa_noea typespec_reserved_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_ts_sa_ea typespec_reserved_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_nots_sa_noea typespec_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_nots_sa_ea typespec_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        ;
 
 declspecs_nosc_ts_sa_ea:
          declspecs_nosc_ts_sa_noea attributes
-               { $$ = tree_cons ($2, NULL_TREE, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_attrs ($1, $2); }
        | declspecs_nosc_ts_sa_noea typespec_reserved_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_ts_sa_ea typespec_reserved_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_nots_sa_noea typespec_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_nots_sa_ea typespec_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        ;
 
 declspecs_sc_nots_nosa_noea:
          scspec
-               { $$ = tree_cons (NULL_TREE, $1, NULL_TREE);
-                 TREE_STATIC ($$) = 0; }
+               { $$ = declspecs_add_scspec (build_null_declspecs (), $1); }
        | declspecs_sc_nots_nosa_noea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_sc_nots_nosa_ea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_nosc_nots_nosa_noea scspec
-               { if (extra_warnings && TREE_STATIC ($1))
-                   warning ("`%s' is not at beginning of declaration",
-                            IDENTIFIER_POINTER ($2));
-                 $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_scspec ($1, $2); }
        | declspecs_nosc_nots_nosa_ea scspec
-               { if (extra_warnings && TREE_STATIC ($1))
-                   warning ("`%s' is not at beginning of declaration",
-                            IDENTIFIER_POINTER ($2));
-                 $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_scspec ($1, $2); }
        | declspecs_sc_nots_nosa_noea scspec
-               { if (extra_warnings && TREE_STATIC ($1))
-                   warning ("`%s' is not at beginning of declaration",
-                            IDENTIFIER_POINTER ($2));
-                 $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_scspec ($1, $2); }
        | declspecs_sc_nots_nosa_ea scspec
-               { if (extra_warnings && TREE_STATIC ($1))
-                   warning ("`%s' is not at beginning of declaration",
-                            IDENTIFIER_POINTER ($2));
-                 $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_scspec ($1, $2); }
        ;
 
 declspecs_sc_nots_nosa_ea:
          declspecs_sc_nots_nosa_noea attributes
-               { $$ = tree_cons ($2, NULL_TREE, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_attrs ($1, $2); }
        ;
 
 declspecs_sc_nots_sa_noea:
          declspecs_sc_nots_sa_noea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_sc_nots_sa_ea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_nosc_nots_sa_noea scspec
-               { if (extra_warnings && TREE_STATIC ($1))
-                   warning ("`%s' is not at beginning of declaration",
-                            IDENTIFIER_POINTER ($2));
-                 $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_scspec ($1, $2); }
        | declspecs_nosc_nots_sa_ea scspec
-               { if (extra_warnings && TREE_STATIC ($1))
-                   warning ("`%s' is not at beginning of declaration",
-                            IDENTIFIER_POINTER ($2));
-                 $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_scspec ($1, $2); }
        | declspecs_sc_nots_sa_noea scspec
-               { if (extra_warnings && TREE_STATIC ($1))
-                   warning ("`%s' is not at beginning of declaration",
-                            IDENTIFIER_POINTER ($2));
-                 $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_scspec ($1, $2); }
        | declspecs_sc_nots_sa_ea scspec
-               { if (extra_warnings && TREE_STATIC ($1))
-                   warning ("`%s' is not at beginning of declaration",
-                            IDENTIFIER_POINTER ($2));
-                 $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_scspec ($1, $2); }
        ;
 
 declspecs_sc_nots_sa_ea:
          declspecs_sc_nots_sa_noea attributes
-               { $$ = tree_cons ($2, NULL_TREE, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_attrs ($1, $2); }
        ;
 
 declspecs_sc_ts_nosa_noea:
          declspecs_sc_ts_nosa_noea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_sc_ts_nosa_ea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_sc_ts_nosa_noea typespec_reserved_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_ts_nosa_ea typespec_reserved_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_nots_nosa_noea typespec_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_nots_nosa_ea typespec_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_ts_nosa_noea scspec
-               { if (extra_warnings && TREE_STATIC ($1))
-                   warning ("`%s' is not at beginning of declaration",
-                            IDENTIFIER_POINTER ($2));
-                 $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_scspec ($1, $2); }
        | declspecs_nosc_ts_nosa_ea scspec
-               { if (extra_warnings && TREE_STATIC ($1))
-                   warning ("`%s' is not at beginning of declaration",
-                            IDENTIFIER_POINTER ($2));
-                 $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_scspec ($1, $2); }
        | declspecs_sc_ts_nosa_noea scspec
-               { if (extra_warnings && TREE_STATIC ($1))
-                   warning ("`%s' is not at beginning of declaration",
-                            IDENTIFIER_POINTER ($2));
-                 $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_scspec ($1, $2); }
        | declspecs_sc_ts_nosa_ea scspec
-               { if (extra_warnings && TREE_STATIC ($1))
-                   warning ("`%s' is not at beginning of declaration",
-                            IDENTIFIER_POINTER ($2));
-                 $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_scspec ($1, $2); }
        ;
 
 declspecs_sc_ts_nosa_ea:
          declspecs_sc_ts_nosa_noea attributes
-               { $$ = tree_cons ($2, NULL_TREE, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_attrs ($1, $2); }
        | declspecs_sc_ts_nosa_noea typespec_reserved_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_ts_nosa_ea typespec_reserved_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_nots_nosa_noea typespec_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_nots_nosa_ea typespec_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        ;
 
 declspecs_sc_ts_sa_noea:
          declspecs_sc_ts_sa_noea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_sc_ts_sa_ea TYPE_QUAL
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_qual ($1, $2); }
        | declspecs_sc_ts_sa_noea typespec_reserved_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_ts_sa_ea typespec_reserved_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_nots_sa_noea typespec_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_nots_sa_ea typespec_nonattr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_nosc_ts_sa_noea scspec
-               { if (extra_warnings && TREE_STATIC ($1))
-                   warning ("`%s' is not at beginning of declaration",
-                            IDENTIFIER_POINTER ($2));
-                 $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_scspec ($1, $2); }
        | declspecs_nosc_ts_sa_ea scspec
-               { if (extra_warnings && TREE_STATIC ($1))
-                   warning ("`%s' is not at beginning of declaration",
-                            IDENTIFIER_POINTER ($2));
-                 $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_scspec ($1, $2); }
        | declspecs_sc_ts_sa_noea scspec
-               { if (extra_warnings && TREE_STATIC ($1))
-                   warning ("`%s' is not at beginning of declaration",
-                            IDENTIFIER_POINTER ($2));
-                 $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_scspec ($1, $2); }
        | declspecs_sc_ts_sa_ea scspec
-               { if (extra_warnings && TREE_STATIC ($1))
-                   warning ("`%s' is not at beginning of declaration",
-                            IDENTIFIER_POINTER ($2));
-                 $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_scspec ($1, $2); }
        ;
 
 declspecs_sc_ts_sa_ea:
          declspecs_sc_ts_sa_noea attributes
-               { $$ = tree_cons ($2, NULL_TREE, $1);
-                 TREE_STATIC ($$) = TREE_STATIC ($1); }
+               { $$ = declspecs_add_attrs ($1, $2); }
        | declspecs_sc_ts_sa_noea typespec_reserved_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_ts_sa_ea typespec_reserved_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_nots_sa_noea typespec_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        | declspecs_sc_nots_sa_ea typespec_attr
-               { $$ = tree_cons (NULL_TREE, $2, $1);
-                 TREE_STATIC ($$) = 1; }
+               { $$ = declspecs_add_type ($1, $2); }
        ;
 
 /* Particular useful classes of declspecs.  */
@@ -1304,7 +1219,7 @@ declspecs:
 /* A (possibly empty) sequence of type qualifiers and attributes.  */
 maybe_type_quals_attrs:
          /* empty */
-               { $$ = NULL_TREE; }
+               { $$ = NULL; }
        | declspecs_nosc_nots
                { $$ = $1; }
        ;
@@ -1328,7 +1243,7 @@ maybe_type_quals_attrs:
    or are such that any following attributes would
    be parsed as part of the specifier.
 
-   _nonattr: specifiers.  */
+   _nonattr: other specifiers not ending with attributes.  */
 
 typespec_nonattr:
          typespec_reserved_nonattr
@@ -1341,7 +1256,9 @@ typespec_attr:
 
 typespec_reserved_nonattr:
          TYPESPEC
-               { OBJC_NEED_RAW_IDENTIFIER (1); }
+               { OBJC_NEED_RAW_IDENTIFIER (1);
+                 $$.kind = ctsk_resword;
+                 $$.spec = $1; }
        | structsp_nonattr
        ;
 
@@ -1353,26 +1270,39 @@ typespec_nonreserved_nonattr:
          TYPENAME
                { /* For a typedef name, record the meaning, not the name.
                     In case of `foo foo, bar;'.  */
-                 $$ = lookup_name ($1); }
+                 $$.kind = ctsk_typedef;
+                 $$.spec = lookup_name ($1); }
 @@ifobjc
        | CLASSNAME protocolrefs
-               { $$ = get_static_reference ($1, $2); }
-       | OBJECTNAME protocolrefs
-               { $$ = get_protocol_reference ($2); }
+               { $$.kind = ctsk_objc;
+                 $$.spec = objc_get_protocol_qualified_type ($1, $2); }
+       | TYPENAME non_empty_protocolrefs
+               { $$.kind = ctsk_objc;
+                 $$.spec = objc_get_protocol_qualified_type ($1, $2); }
 
 /* Make "<SomeProtocol>" equivalent to "id <SomeProtocol>"
    - nisse@lysator.liu.se */
         | non_empty_protocolrefs
-                { $$ = get_protocol_reference ($1); }
+                { $$.kind = ctsk_objc;
+                 $$.spec = objc_get_protocol_qualified_type (NULL_TREE, $1); }
 @@end_ifobjc
        | typeof '(' expr ')'
                { skip_evaluation--;
+                 in_typeof--;
                  if (TREE_CODE ($3.value) == COMPONENT_REF
                      && DECL_C_BIT_FIELD (TREE_OPERAND ($3.value, 1)))
-                   error ("`typeof' applied to a bit-field");
-                 $$ = TREE_TYPE ($3.value); }
+                   error ("%<typeof%> applied to a bit-field");
+                 $$.kind = ctsk_typeof;
+                 $$.spec = TREE_TYPE ($3.value);
+                 pop_maybe_used (variably_modified_type_p ($$.spec,
+                                                           NULL_TREE)); }
        | typeof '(' typename ')'
-               { skip_evaluation--; $$ = groktypename ($3); }
+               { skip_evaluation--;
+                 in_typeof--;
+                 $$.kind = ctsk_typeof;
+                 $$.spec = groktypename ($3);
+                 pop_maybe_used (variably_modified_type_p ($$.spec,
+                                                           NULL_TREE)); }
        ;
 
 /* typespec_nonreserved_attr does not exist.  */
@@ -1440,7 +1370,7 @@ attribute:
                 '(' '(' attribute_list ')' ')' start_string_translation
                { $$ = $5; }
       | ATTRIBUTE error start_string_translation
-                {}
+                { $$ = NULL_TREE; }
        ;
 
 attribute_list:
@@ -1508,15 +1438,15 @@ initlist1:
    It may use braces.  */
 initelt:
          designator_list '=' initval
-               { if (pedantic && ! flag_isoc99)
+               { if (pedantic && !flag_isoc99)
                    pedwarn ("ISO C90 forbids specifying subobject to initialize"); }
-       | designator initval
+       | array_designator initval
                { if (pedantic)
-                   pedwarn ("obsolete use of designated initializer without `='"); }
+                   pedwarn ("obsolete use of designated initializer without %<=%>"); }
        | identifier ':'
                { set_init_label ($1);
                  if (pedantic)
-                   pedwarn ("obsolete use of designated initializer with `:'"); }
+                   pedwarn ("obsolete use of designated initializer with %<:%>"); }
          initval
                {}
        | initval
@@ -1540,7 +1470,11 @@ designator_list:
 designator:
          '.' identifier
                { set_init_label ($2); }
-       | '[' expr_no_commas ELLIPSIS expr_no_commas ']'
+       | array_designator
+       ;
+
+array_designator:
+         '[' expr_no_commas ELLIPSIS expr_no_commas ']'
                { set_init_index ($2.value, $4.value);
                  if (pedantic)
                    pedwarn ("ISO C forbids specifying range of elements to initialize"); }
@@ -1554,8 +1488,8 @@ nested_function:
                    pedwarn ("ISO C forbids nested functions");
 
                  push_function_context ();
-                 if (! start_function (current_declspecs, $1,
-                                       all_prefix_attributes))
+                 if (!start_function (current_declspecs, $1,
+                                      all_prefix_attributes))
                    {
                      pop_function_context ();
                      YYERROR1;
@@ -1584,8 +1518,8 @@ notype_nested_function:
                    pedwarn ("ISO C forbids nested functions");
 
                  push_function_context ();
-                 if (! start_function (current_declspecs, $1,
-                                       all_prefix_attributes))
+                 if (!start_function (current_declspecs, $1,
+                                      all_prefix_attributes))
                    {
                      pop_function_context ();
                      YYERROR1;
@@ -1628,9 +1562,7 @@ after_type_declarator:
        | '*' maybe_type_quals_attrs after_type_declarator  %prec UNARY
                { $$ = make_pointer_declarator ($2, $3); }
        | TYPENAME
-@@ifobjc
-       | OBJECTNAME
-@@end_ifobjc
+               { $$ = build_id_declarator ($1); }
        ;
 
 /* Kinds of declarator that can appear in a parameter list
@@ -1648,9 +1580,7 @@ parm_declarator_starttypename:
        | parm_declarator_starttypename array_declarator  %prec '.'
                { $$ = set_array_declarator_inner ($2, $1, false); }
        | TYPENAME
-@@ifobjc
-       | OBJECTNAME
-@@end_ifobjc
+               { $$ = build_id_declarator ($1); }
        ;
 
 parm_declarator_nostarttypename:
@@ -1679,6 +1609,7 @@ notype_declarator:
        | notype_declarator array_declarator  %prec '.'
                { $$ = set_array_declarator_inner ($2, $1, false); }
        | IDENTIFIER
+               { $$ = build_id_declarator ($1); }
        ;
 
 struct_head:
@@ -1710,48 +1641,56 @@ enum_head:
 
 structsp_attr:
          struct_head identifier '{'
-               { $$ = start_struct (RECORD_TYPE, $2);
+               { $<ttype>$ = start_struct (RECORD_TYPE, $2);
                  /* Start scope of tag before parsing components.  */
                }
          component_decl_list '}' maybe_attribute
-               { $$ = finish_struct ($<ttype>4, nreverse ($5),
-                                     chainon ($1, $7)); }
+               { $$.spec = finish_struct ($<ttype>4, nreverse ($5),
+                                          chainon ($1, $7));
+                 $$.kind = ctsk_tagdef; }
        | struct_head '{' component_decl_list '}' maybe_attribute
-               { $$ = finish_struct (start_struct (RECORD_TYPE, NULL_TREE),
-                                     nreverse ($3), chainon ($1, $5));
+               { $$.spec = finish_struct (start_struct (RECORD_TYPE,
+                                                        NULL_TREE),
+                                          nreverse ($3), chainon ($1, $5));
+                 $$.kind = ctsk_tagdef;
                }
        | union_head identifier '{'
-               { $$ = start_struct (UNION_TYPE, $2); }
+               { $<ttype>$ = start_struct (UNION_TYPE, $2); }
          component_decl_list '}' maybe_attribute
-               { $$ = finish_struct ($<ttype>4, nreverse ($5),
-                                     chainon ($1, $7)); }
+               { $$.spec = finish_struct ($<ttype>4, nreverse ($5),
+                                          chainon ($1, $7));
+                 $$.kind = ctsk_tagdef; }
        | union_head '{' component_decl_list '}' maybe_attribute
-               { $$ = finish_struct (start_struct (UNION_TYPE, NULL_TREE),
-                                     nreverse ($3), chainon ($1, $5));
+               { $$.spec = finish_struct (start_struct (UNION_TYPE,
+                                                        NULL_TREE),
+                                          nreverse ($3), chainon ($1, $5));
+                 $$.kind = ctsk_tagdef;
                }
        | enum_head identifier '{'
-               { $$ = start_enum ($2); }
+               { $<ttype>$ = start_enum ($2); }
          enumlist maybecomma_warn '}' maybe_attribute
-               { $$ = finish_enum ($<ttype>4, nreverse ($5),
-                                   chainon ($1, $8)); }
+               { $$.spec = finish_enum ($<ttype>4, nreverse ($5),
+                                        chainon ($1, $8));
+                 $$.kind = ctsk_tagdef; }
        | enum_head '{'
-               { $$ = start_enum (NULL_TREE); }
+               { $<ttype>$ = start_enum (NULL_TREE); }
          enumlist maybecomma_warn '}' maybe_attribute
-               { $$ = finish_enum ($<ttype>3, nreverse ($4),
-                                   chainon ($1, $7)); }
+               { $$.spec = finish_enum ($<ttype>3, nreverse ($4),
+                                        chainon ($1, $7));
+                 $$.kind = ctsk_tagdef; }
        ;
 
 structsp_nonattr:
          struct_head identifier
-               { $$ = xref_tag (RECORD_TYPE, $2); }
+               { $$ = parser_xref_tag (RECORD_TYPE, $2); }
        | union_head identifier
-               { $$ = xref_tag (UNION_TYPE, $2); }
+               { $$ = parser_xref_tag (UNION_TYPE, $2); }
        | enum_head identifier
-               { $$ = xref_tag (ENUMERAL_TYPE, $2);
+               { $$ = parser_xref_tag (ENUMERAL_TYPE, $2);
                  /* In ISO C, enumerated types can be referred to
                     only if already defined.  */
-                 if (pedantic && !COMPLETE_TYPE_P ($$))
-                   pedwarn ("ISO C forbids forward references to `enum' types"); }
+                 if (pedantic && !COMPLETE_TYPE_P ($$.spec))
+                   pedwarn ("ISO C forbids forward references to %<enum%> types"); }
        ;
 
 maybecomma:
@@ -1762,7 +1701,7 @@ maybecomma:
 maybecomma_warn:
          /* empty */
        | ','
-               { if (pedantic && ! flag_isoc99)
+               { if (pedantic && !flag_isoc99)
                    pedwarn ("comma at end of enumerator list"); }
        ;
 
@@ -1796,7 +1735,7 @@ component_decl_list2:     /* empty */
 @@ifobjc
        /* foo(sizeof(struct{ @defs(ClassName)})); */
        | AT_DEFS '(' CLASSNAME ')'
-               { $$ = nreverse (get_class_ivars_from_name ($3)); }
+               { $$ = nreverse (objc_get_class_ivars ($3)); }
 @@end_ifobjc
        ;
 
@@ -1809,10 +1748,8 @@ component_decl:
                  /* Support for unnamed structs or unions as members of
                     structs or unions (which is [a] useful and [b] supports
                     MS P-SDK).  */
-                 if (pedantic)
-                   pedwarn ("ISO C doesn't support unnamed structs/unions");
-
-                 $$ = grokfield(NULL, current_declspecs, NULL_TREE);
+                 $$ = grokfield (build_id_declarator (NULL_TREE),
+                                 current_declspecs, NULL_TREE);
                  POP_DECLSPEC_STACK; }
        | declspecs_nosc_nots setspecs components_notype
                { $$ = $3;
@@ -1820,7 +1757,7 @@ component_decl:
        | declspecs_nosc_nots
                { if (pedantic)
                    pedwarn ("ISO C forbids member declarations with no members");
-                 shadow_tag_warned ($1, pedantic);
+                 shadow_tag_warned (finish_declspecs ($1), pedantic);
                  $$ = NULL_TREE; }
        | error
                { $$ = NULL_TREE; }
@@ -1851,7 +1788,8 @@ component_declarator:
                  decl_attributes (&$$,
                                   chainon ($4, all_prefix_attributes), 0); }
        | ':' expr_no_commas maybe_attribute
-               { $$ = grokfield (NULL_TREE, current_declspecs, $2.value);
+               { $$ = grokfield (build_id_declarator (NULL_TREE),
+                                 current_declspecs, $2.value);
                  decl_attributes (&$$,
                                   chainon ($3, all_prefix_attributes), 0); }
        ;
@@ -1866,7 +1804,8 @@ component_notype_declarator:
                  decl_attributes (&$$,
                                   chainon ($4, all_prefix_attributes), 0); }
        | ':' expr_no_commas maybe_attribute
-               { $$ = grokfield (NULL_TREE, current_declspecs, $2.value);
+               { $$ = grokfield (build_id_declarator (NULL_TREE),
+                                 current_declspecs, $2.value);
                  decl_attributes (&$$,
                                   chainon ($3, all_prefix_attributes), 0); }
        ;
@@ -1896,21 +1835,23 @@ enumerator:
 typename:
          declspecs_nosc
                { pending_xref_error ();
-                 $<ttype>$ = $1; }
+                 $<dsptype>$ = finish_declspecs ($1); }
          absdcl
-               { $$ = build_tree_list ($<ttype>2, $3); }
+               { $$ = XOBNEW (&parser_obstack, struct c_type_name);
+                 $$->specs = $<dsptype>2;
+                 $$->declarator = $3; }
        ;
 
 absdcl:   /* an absolute declarator */
        /* empty */
-               { $$ = NULL_TREE; }
+               { $$ = build_id_declarator (NULL_TREE); }
        | absdcl1
        ;
 
 absdcl_maybe_attribute:   /* absdcl maybe_attribute, but not just attributes */
        /* empty */
                { $$ = build_c_parm (current_declspecs, all_prefix_attributes,
-                                    NULL_TREE); }
+                                    build_id_declarator (NULL_TREE)); }
        | absdcl1
                { $$ = build_c_parm (current_declspecs, all_prefix_attributes,
                                     $1); }
@@ -1933,7 +1874,8 @@ absdcl1_noea:
 
 absdcl1_ea:
          '*' maybe_type_quals_attrs
-               { $$ = make_pointer_declarator ($2, NULL_TREE); }
+               { $$ = make_pointer_declarator
+                   ($2, build_id_declarator (NULL_TREE)); }
        | '*' maybe_type_quals_attrs absdcl1_ea
                { $$ = make_pointer_declarator ($2, $3); }
        ;
@@ -1946,9 +1888,11 @@ direct_absdcl1:
        | direct_absdcl1 array_declarator
                { $$ = set_array_declarator_inner ($2, $1, true); }
        | '(' parmlist
-               { $$ = build_function_declarator ($2, NULL_TREE); }
+               { $$ = build_function_declarator
+                   ($2, build_id_declarator (NULL_TREE)); }
        | array_declarator
-               { $$ = set_array_declarator_inner ($1, NULL_TREE, true); }
+               { $$ = set_array_declarator_inner
+                   ($1, build_id_declarator (NULL_TREE), true); }
        ;
 
 /* The [...] part of a declarator for an array type.  */
@@ -2079,7 +2023,7 @@ compstmt_contents_nonempty:
 
 compstmt_primary_start:
        '(' '{'
-               { if (current_function_decl == 0)
+               { if (cur_stmt_list == NULL)
                    {
                      error ("braced-group within expression allowed "
                             "only inside a function");
@@ -2116,9 +2060,9 @@ c99_block_lineno_labeled_stmt:
 
 lineno_stmt:
          save_location stmt
-               { 
+               {
                  /* Two cases cannot and do not have line numbers associated:
-                    If stmt is degenerate, such as "2;", then stmt is an 
+                    If stmt is degenerate, such as "2;", then stmt is an
                     INTEGER_CST, which cannot hold line numbers.  But that's
                     ok because the statement will either be changed to a
                     MODIFY_EXPR during gimplification of the statement expr,
@@ -2303,7 +2247,7 @@ stmt_nocomp:
 
 objc_catch_prefix:
        AT_CATCH '(' parm ')'
-               { objc_begin_catch_clause ($3); }
+               { objc_begin_catch_clause (grokparm ($3)); }
        ;
 
 objc_catch_clause:
@@ -2494,18 +2438,29 @@ parmlist_1:
          parmlist_1
                { $$ = $6; }
        | error ')'
-               { $$ = make_node (TREE_LIST); }
+               { $$ = XOBNEW (&parser_obstack, struct c_arg_info);
+                 $$->parms = 0;
+                 $$->tags = 0;
+                 $$->types = 0;
+                 $$->others = 0; }
        ;
 
 /* This is what appears inside the parens in a function declarator.
-   Is value is represented in the format that grokdeclarator expects.  */
+   Its value is represented in the format that grokdeclarator expects.  */
 parmlist_2:  /* empty */
-               { $$ = make_node (TREE_LIST); }
+               { $$ = XOBNEW (&parser_obstack, struct c_arg_info);
+                 $$->parms = 0;
+                 $$->tags = 0;
+                 $$->types = 0;
+                 $$->others = 0; }
        | ELLIPSIS
-               { $$ = make_node (TREE_LIST); 
+               { $$ = XOBNEW (&parser_obstack, struct c_arg_info);
+                 $$->parms = 0;
+                 $$->tags = 0;
+                 $$->others = 0;
                  /* Suppress -Wold-style-definition for this case.  */
-                 TREE_CHAIN ($$) = error_mark_node;
-                 error ("ISO C requires a named argument before `...'");
+                 $$->types = error_mark_node;
+                 error ("ISO C requires a named argument before %<...%>");
                }
        | parms
                { $$ = get_parm_info (/*ellipsis=*/false); }
@@ -2589,17 +2544,14 @@ parmlist_or_identifiers:
 parmlist_or_identifiers_1:
          parmlist_1
        | identifiers ')'
-               { tree t;
-                 for (t = $1; t; t = TREE_CHAIN (t))
-                   if (TREE_VALUE (t) == NULL_TREE)
-                     error ("`...' in old-style identifier list");
-                 $$ = tree_cons (NULL_TREE, NULL_TREE, $1);
+               { $$ = XOBNEW (&parser_obstack, struct c_arg_info);
+                 $$->parms = 0;
+                 $$->tags = 0;
+                 $$->types = $1;
+                 $$->others = 0;
 
                  /* Make sure we have a parmlist after attributes.  */
-                 if ($<ttype>-1 != 0
-                     && (TREE_CODE ($$) != TREE_LIST
-                         || TREE_PURPOSE ($$) == 0
-                         || TREE_CODE (TREE_PURPOSE ($$)) != PARM_DECL))
+                 if ($<ttype>-1 != 0)
                    YYERROR1;
                }
        ;
@@ -2622,7 +2574,7 @@ identifiers_or_typenames:
 
 extension:
        EXTENSION
-               { $$ = SAVE_EXT_FLAGS();
+               { $$ = SAVE_EXT_FLAGS ();
                  pedantic = 0;
                  warn_pointer_arith = 0;
                  warn_traditional = 0;
@@ -2640,14 +2592,7 @@ objcdef:
        | methoddef
        | AT_END
                {
-                 if (objc_implementation_context)
-                    {
-                     finish_class (objc_implementation_context);
-                     objc_ivar_chain = NULL_TREE;
-                     objc_implementation_context = NULL_TREE;
-                   }
-                 else
-                   warning ("`@end' must appear in an implementation context");
+                 objc_finish_implementation ();
                }
        ;
 
@@ -2686,50 +2631,38 @@ class_ivars:
 classdef:
          AT_INTERFACE identifier superclass protocolrefs
                {
-                 objc_interface_context = objc_ivar_context
-                   = start_class (CLASS_INTERFACE_TYPE, $2, $3, $4);
-                  objc_public_flag = 0;
+                 objc_start_class_interface ($2, $3, $4);
                }
          class_ivars
                {
-                  continue_class (objc_interface_context);
+                 objc_continue_interface ();
                }
          methodprotolist AT_END
                {
-                 finish_class (objc_interface_context);
-                 objc_interface_context = NULL_TREE;
+                 objc_finish_interface ();
                }
 
        | AT_IMPLEMENTATION identifier superclass
                {
-                 objc_implementation_context = objc_ivar_context
-                   = start_class (CLASS_IMPLEMENTATION_TYPE, $2, $3, NULL_TREE);
-                  objc_public_flag = 0;
+                 objc_start_class_implementation ($2, $3);
                }
          class_ivars
                {
-                  objc_ivar_chain
-                   = continue_class (objc_implementation_context);
+                 objc_continue_implementation ();
                }
 
        | AT_INTERFACE identifier '(' identifier ')' protocolrefs
                {
-                 objc_interface_context
-                   = start_class (CATEGORY_INTERFACE_TYPE, $2, $4, $6);
-                  continue_class (objc_interface_context);
+                 objc_start_category_interface ($2, $4, $6);
                }
          methodprotolist AT_END
                {
-                 finish_class (objc_interface_context);
-                 objc_interface_context = NULL_TREE;
+                 objc_finish_interface ();
                }
 
        | AT_IMPLEMENTATION identifier '(' identifier ')'
                {
-                 objc_implementation_context
-                   = start_class (CATEGORY_IMPLEMENTATION_TYPE, $2, $4, NULL_TREE);
-                  objc_ivar_chain
-                   = continue_class (objc_implementation_context);
+                 objc_start_category_implementation ($2, $4);
                }
        ;
 
@@ -2737,14 +2670,12 @@ protocoldef:
          AT_PROTOCOL identifier protocolrefs
                {
                  objc_pq_context = 1;
-                 objc_interface_context
-                   = start_protocol(PROTOCOL_INTERFACE_TYPE, $2, $3);
+                 objc_start_protocol ($2, $3);
                }
          methodprotolist AT_END
                {
                  objc_pq_context = 0;
-                 finish_protocol(objc_interface_context);
-                 objc_interface_context = NULL_TREE;
+                 objc_finish_interface ();
                }
        /* The @protocol forward-declaration production introduces a
           reduce/reduce conflict on ';', which should be resolved in
@@ -2774,109 +2705,67 @@ non_empty_protocolrefs:
        ;
 
 ivar_decl_list:
-          ivar_decl_list visibility_spec ivar_decls
-        | ivar_decls
+         /* empty */
+        | ivar_decl_list visibility_spec ivar_decls
         ;
 
 visibility_spec:
-         AT_PRIVATE { objc_public_flag = 2; }
-       | AT_PROTECTED { objc_public_flag = 0; }
-       | AT_PUBLIC { objc_public_flag = 1; }
+         /* empty */
+       | AT_PRIVATE { objc_set_visibility (2); }
+       | AT_PROTECTED { objc_set_visibility (0); }
+       | AT_PUBLIC { objc_set_visibility (1); }
        ;
 
 ivar_decls:
-          /* empty */
-               {
-                  $$ = NULL_TREE;
-                }
+         /* empty */
        | ivar_decls ivar_decl ';'
        | ivar_decls ';'
                {
-                  if (pedantic)
+                 if (pedantic)
                    pedwarn ("extra semicolon in struct or union specified");
-                }
+               }
        ;
 
-
-/* There is a shift-reduce conflict here, because `components' may
-   start with a `typename'.  It happens that shifting (the default resolution)
-   does the right thing, because it treats the `typename' as part of
-   a `typed_typespecs'.
-
-   It is possible that this same technique would allow the distinction
-   between `notype_initdecls' and `initdecls' to be eliminated.
-   But I am being cautious and not trying it.  */
-
 ivar_decl:
-       declspecs_nosc_ts setspecs ivars
-               { $$ = $3;
-                 POP_DECLSPEC_STACK; }
-       | declspecs_nosc_nots setspecs ivars
-               { $$ = $3;
-                 POP_DECLSPEC_STACK; }
-       | error
-               { $$ = NULL_TREE; }
-       ;
+       component_decl
+               {
+                 /* Comma-separated ivars are chained together in
+                    reverse order; add them one by one.  */
+                 tree ivar = nreverse ($1);
 
-ivars:
-         /* empty */
-               { $$ = NULL_TREE; }
-       | ivar_declarator
-       | ivars ',' maybe_resetattrs ivar_declarator
+                 for (; ivar; ivar = TREE_CHAIN (ivar))
+                   objc_add_instance_variable (copy_node (ivar));
+               }
        ;
 
-ivar_declarator:
-         declarator
-               {
-                 $$ = add_instance_variable (objc_ivar_context,
-                                             objc_public_flag,
-                                             $1, current_declspecs,
-                                             NULL_TREE);
-                }
-       | declarator ':' expr_no_commas
-               {
-                 $$ = add_instance_variable (objc_ivar_context,
-                                             objc_public_flag,
-                                             $1, current_declspecs, $3.value);
-                }
-       | ':' expr_no_commas
+opt_semi:
+         /* NULL */
+       | ';'
                {
-                 $$ = add_instance_variable (objc_ivar_context,
-                                             objc_public_flag,
-                                             NULL_TREE,
-                                             current_declspecs, $2.value);
-                }
+                 if (pedantic)
+                   pedwarn ("extra semicolon in method definition specified");
+               }
        ;
 
 methodtype:
          '+'
-               { objc_inherit_code = CLASS_METHOD_DECL; }
        | '-'
-               { objc_inherit_code = INSTANCE_METHOD_DECL; }
        ;
 
 methoddef:
          methodtype
                {
+                 objc_set_method_type ($1);
                  objc_pq_context = 1;
-                 if (!objc_implementation_context)
-                   fatal_error ("method definition not in class context");
                }
-         methoddecl
+         methoddecl opt_semi
                {
                  objc_pq_context = 0;
-                 objc_add_method (objc_implementation_context,
-                                  $3,
-                                  objc_inherit_code == CLASS_METHOD_DECL);
-                 start_method_def ($3);
-               }
-         optarglist
-               {
-                 continue_method_def ();
+                 objc_start_method_definition ($3);
                }
          compstmt_or_error
                {
-                 finish_method_def ();
+                 objc_finish_method_definition (current_function_decl);
                }
        ;
 
@@ -2898,6 +2787,7 @@ semi_or_error:
 methodproto:
          methodtype
                {
+                 objc_set_method_type ($1);
                  /* Remember protocol qualifiers in prototypes.  */
                  objc_pq_context = 1;
                }
@@ -2905,109 +2795,63 @@ methodproto:
                {
                  /* Forget protocol qualifiers here.  */
                  objc_pq_context = 0;
-                 objc_add_method (objc_interface_context,
-                                  $3,
-                                  objc_inherit_code == CLASS_METHOD_DECL);
+                 objc_add_method_declaration ($3);
                }
          semi_or_error
        ;
 
 methoddecl:
-         '(' typename ')' unaryselector
+         '(' objc_typename ')' unaryselector
                {
-                 $$ = build_method_decl (objc_inherit_code, $2, $4, NULL_TREE);
+                 $$ = objc_build_method_signature ($2, $4, NULL_TREE);
                }
 
        | unaryselector
                {
-                 $$ = build_method_decl (objc_inherit_code, NULL_TREE, $1, NULL_TREE);
+                 $$ = objc_build_method_signature (NULL_TREE, $1, NULL_TREE);
                }
 
-       | '(' typename ')' keywordselector optparmlist
+       | '(' objc_typename ')' keywordselector optparmlist
                {
-                 $$ = build_method_decl (objc_inherit_code, $2, $4, $5);
+                 $$ = objc_build_method_signature ($2, $4, $5);
                }
 
        | keywordselector optparmlist
                {
-                 $$ = build_method_decl (objc_inherit_code, NULL_TREE, $1, $2);
+                 $$ = objc_build_method_signature (NULL_TREE, $1, $2);
                }
        ;
 
-/* "optarglist" assumes that start_method_def has already been called...
-   if it is not, the "xdecls" will not be placed in the proper scope */
-
-optarglist:
-         /* empty */
-       | ';' myxdecls
-       ;
-
-/* to get around the following situation: "int foo (int a) int b; {}" that
-   is synthesized when parsing "- a:a b:b; id c; id d; { ... }" */
-
-myxdecls:
-         /* empty */
-       | mydecls
-       ;
-
-mydecls:
-       mydecl
-       | errstmt
-       | mydecls mydecl
-       | mydecl errstmt
-       ;
-
-mydecl:
-       declspecs_ts setspecs myparms ';'
-               { POP_DECLSPEC_STACK; }
-       | declspecs_ts ';'
-               { shadow_tag ($1); }
-       | declspecs_nots ';'
-               { pedwarn ("empty declaration"); }
-       ;
-
-myparms:
-       myparm
-               { push_parm_decl ($1); }
-       | myparms ',' myparm
-               { push_parm_decl ($3); }
-       ;
+/* Optional ObjC method parameters follow the C syntax, and may include '...'
+   to denote a variable number of arguments.  */
 
-/* A single parameter declaration or parameter type name,
-   as found in a parmlist. DOES NOT ALLOW AN INITIALIZER OR ASMSPEC */
-
-myparm:
-         parm_declarator maybe_attribute
-               { $$ = build_tree_list (build_tree_list (current_declspecs,
-                                                        $1),
-                                       chainon ($2, all_prefix_attributes)); }
-       | notype_declarator maybe_attribute
-               { $$ = build_tree_list (build_tree_list (current_declspecs,
-                                                        $1),
-                                       chainon ($2, all_prefix_attributes)); }
-       | absdcl_maybe_attribute
-               { $$ = $1; }
+optparmlist:
+         optparms optellipsis
+               {
+                 TREE_OVERFLOW ($$) = $2;
+               }
        ;
 
-optparmlist:
-         /* empty */
+optparms:
+         /* NULL */
                {
-                 $$ = NULL_TREE;
+                 $$ = make_node (TREE_LIST);
                }
-       | ',' ELLIPSIS
+       | optparms ',' parm
                {
-                 /* oh what a kludge! */
-                 $$ = objc_ellipsis_node;
+                 $$ = chainon ($1, build_tree_list (NULL_TREE,
+                                                    grokparm ($3)));
                }
-       | ','
+       ;
+
+optellipsis:
+         /* NULL */
                {
-                 push_scope ();
+                 $$ = 0;
                }
-         parmlist_2
+       | ',' ELLIPSIS
                {
-                 /* returns a tree list node generated by get_parm_info */
-                 $$ = $3;
-                 pop_scope ();
+                 $$ = 1;
                }
        ;
 
@@ -3028,36 +2872,61 @@ selector:
          IDENTIFIER
        | TYPENAME
        | CLASSNAME
-       | OBJECTNAME
        | reservedwords
        ;
 
 reservedwords:
-         ENUM | STRUCT | UNION | IF | ELSE | WHILE | DO | FOR
+         ENUM | STRUCT | UNION | IF | ELSE | WHILE | DO | FOR
        | SWITCH | CASE | DEFAULT | BREAK | CONTINUE | RETURN
        | GOTO | ASM_KEYWORD | SIZEOF | TYPEOF | ALIGNOF
-       | TYPESPEC | TYPE_QUAL
+       | TYPESPEC | TYPE_QUAL | OBJC_TYPE_QUAL
+       ;
+
+objc_qual:
+         OBJC_TYPE_QUAL
+       ;
+
+objc_quals:
+         objc_quals objc_qual
+               {
+                 $$ = chainon ($1, build_tree_list (NULL_TREE, $2));
+               }
+       | /* NULL */
+               {
+                 $$ = NULL_TREE;
+               }
+       ;
+
+objc_typename:
+         objc_quals typename
+               {
+                 $$ = build_tree_list ($1, groktypename ($2));
+               }
+       | objc_quals
+               {
+                 $$ = build_tree_list ($1, NULL_TREE);
+               }
        ;
 
 keyworddecl:
-         selector ':' '(' typename ')' identifier
+         selector ':' '(' objc_typename ')' identifier
                {
-                 $$ = build_keyword_decl ($1, $4, $6);
+                 $$ = objc_build_keyword_decl ($1, $4, $6);
                }
 
        | selector ':' identifier
                {
-                 $$ = build_keyword_decl ($1, NULL_TREE, $3);
+                 $$ = objc_build_keyword_decl ($1, NULL_TREE, $3);
                }
 
-       | ':' '(' typename ')' identifier
+       | ':' '(' objc_typename ')' identifier
                {
-                 $$ = build_keyword_decl (NULL_TREE, $3, $5);
+                 $$ = objc_build_keyword_decl (NULL_TREE, $3, $5);
                }
 
        | ':' identifier
                {
-                 $$ = build_keyword_decl (NULL_TREE, NULL_TREE, $2);
+                 $$ = objc_build_keyword_decl (NULL_TREE, NULL_TREE, $2);
                }
        ;
 
@@ -3103,11 +2972,11 @@ receiver:
                { $$ = $1.value; }
        | CLASSNAME
                {
-                 $$ = get_class_reference ($1);
+                 $$ = objc_get_class_reference ($1);
                }
        | TYPENAME
                {
-                 $$ = get_class_reference ($1);
+                 $$ = objc_get_class_reference ($1);
                }
        ;
 
@@ -3213,12 +3082,6 @@ static const struct resword reswords[] =
   { "__inline",                RID_INLINE,     0 },
   { "__inline__",      RID_INLINE,     0 },
   { "__label__",       RID_LABEL,      0 },
-  { "__ptrbase",       RID_PTRBASE,    0 },
-  { "__ptrbase__",     RID_PTRBASE,    0 },
-  { "__ptrextent",     RID_PTREXTENT,  0 },
-  { "__ptrextent__",   RID_PTREXTENT,  0 },
-  { "__ptrvalue",      RID_PTRVALUE,   0 },
-  { "__ptrvalue__",    RID_PTRVALUE,   0 },
   { "__real",          RID_REALPART,   0 },
   { "__real__",                RID_REALPART,   0 },
   { "__restrict",      RID_RESTRICT,   0 },
@@ -3266,8 +3129,8 @@ static const struct resword reswords[] =
   { "void",            RID_VOID,       0 },
   { "volatile",                RID_VOLATILE,   0 },
   { "while",           RID_WHILE,      0 },
+
 @@ifobjc
-  { "id",              RID_ID,                 D_OBJC },
 
   /* These objc keywords are recognized only immediately after
      an '@'.  */
@@ -3331,12 +3194,12 @@ static const short rid_to_yy[RID_MAX] =
   /* RID_MUTABLE */    0,
 
   /* ObjC */
-  /* RID_IN */         TYPE_QUAL,
-  /* RID_OUT */                TYPE_QUAL,
-  /* RID_INOUT */      TYPE_QUAL,
-  /* RID_BYCOPY */     TYPE_QUAL,
-  /* RID_BYREF */      TYPE_QUAL,
-  /* RID_ONEWAY */     TYPE_QUAL,
+  /* RID_IN */         OBJC_TYPE_QUAL,
+  /* RID_OUT */                OBJC_TYPE_QUAL,
+  /* RID_INOUT */      OBJC_TYPE_QUAL,
+  /* RID_BYCOPY */     OBJC_TYPE_QUAL,
+  /* RID_BYREF */      OBJC_TYPE_QUAL,
+  /* RID_ONEWAY */     OBJC_TYPE_QUAL,
 
   /* C */
   /* RID_INT */                TYPESPEC,
@@ -3371,9 +3234,6 @@ static const short rid_to_yy[RID_MAX] =
   /* RID_IMAGPART */   IMAGPART,
   /* RID_REALPART */   REALPART,
   /* RID_LABEL */      LABEL,
-  /* RID_PTRBASE */    PTR_BASE,
-  /* RID_PTREXTENT */  PTR_EXTENT,
-  /* RID_PTRVALUE */   PTR_VALUE,
 
   /* RID_CHOOSE_EXPR */                        CHOOSE_EXPR,
   /* RID_TYPES_COMPATIBLE_P */         TYPES_COMPATIBLE_P,
@@ -3413,7 +3273,6 @@ static const short rid_to_yy[RID_MAX] =
   /* RID_STATCAST */   0,
 
   /* Objective C */
-  /* RID_ID */                 OBJECTNAME,
   /* RID_AT_ENCODE */          AT_ENCODE,
   /* RID_AT_END */             AT_END,
   /* RID_AT_CLASS */           AT_CLASS,
@@ -3482,15 +3341,6 @@ yylexname (void)
       enum rid rid_code = C_RID_CODE (yylval.ttype);
 
 @@ifobjc
-      /* Turn non-typedefed refs to "id" into plain identifiers; this
-        allows constructs like "void foo(id id);" to work.  */
-      if (rid_code == RID_ID)
-      {
-       decl = lookup_name (yylval.ttype);
-       if (decl == NULL_TREE || TREE_CODE (decl) != TYPE_DECL)
-         return IDENTIFIER;
-      }
-
       if (!OBJC_IS_AT_KEYWORD (rid_code)
          && (!OBJC_IS_PQ_KEYWORD (rid_code) || objc_pq_context))
 @@end_ifobjc
@@ -3510,7 +3360,7 @@ yylexname (void)
 @@ifobjc
   else
     {
-      tree objc_interface_decl = is_class_name (yylval.ttype);
+      tree objc_interface_decl = objc_is_class_name (yylval.ttype);
       /* ObjC class names are in the same namespace as variables and
         typedefs, and hence are shadowed by local declarations.  */
       if (objc_interface_decl
@@ -3621,7 +3471,7 @@ _yylex (void)
       /* These tokens should not survive translation phase 4.  */
     case CPP_HASH:
     case CPP_PASTE:
-      error ("syntax error at '%s' token", NAME(last_token));
+      error ("syntax error at %qs token", NAME(last_token));
       goto get_next;
 
     default:
@@ -3653,13 +3503,12 @@ yyprint (FILE *file, int yychar, YYSTYPE yyl)
     {
     case IDENTIFIER:
     case TYPENAME:
-    case OBJECTNAME:
     case TYPESPEC:
     case TYPE_QUAL:
     case SCSPEC:
     case STATIC:
       if (IDENTIFIER_POINTER (t))
-       fprintf (file, " `%s'", IDENTIFIER_POINTER (t));
+       fprintf (file, " '%s'", IDENTIFIER_POINTER (t));
       break;
 
     case CONSTANT:
@@ -3691,4 +3540,21 @@ c_parse_file (void)
     }
 }
 
+#ifdef __XGETTEXT__
+/* Depending on the version of Bison used to compile this grammar,
+   it may issue generic diagnostics spelled "syntax error" or
+   "parse error".  To prevent this from changing the translation
+   template randomly, we list all the variants of this particular
+   diagnostic here.  Translators: there is no fine distinction
+   between diagnostics with "syntax error" in them, and diagnostics
+   with "parse error" in them.  It's okay to give them both the same
+   translation.  */
+const char d1[] = N_("syntax error");
+const char d2[] = N_("parse error");
+const char d3[] = N_("syntax error; also virtual memory exhausted");
+const char d4[] = N_("parse error; also virtual memory exhausted");
+const char d5[] = N_("syntax error: cannot back up");
+const char d6[] = N_("parse error: cannot back up");
+#endif
+
 #include "gt-c-parse.h"