summaryrefslogtreecommitdiff
path: root/gnu
diff options
context:
space:
mode:
authorphil <phil@NetBSD.org>1996-02-28 21:01:27 +0000
committerphil <phil@NetBSD.org>1996-02-28 21:01:27 +0000
commit4d30f3b4686a8afa41cc5ea8f1cc535b44cc8446 (patch)
tree2d52de83432f5191e1804733261f3937f5874108 /gnu
parent2d885d15e97e336e6c7fb30125806c14d1b93191 (diff)
Updates to get the .y files in our source tree.
Diffstat (limited to 'gnu')
-rw-r--r--gnu/usr.bin/gcc/cc1/c-parse.y2068
-rw-r--r--gnu/usr.bin/gcc/cc1obj/objc-parse.y2820
-rw-r--r--gnu/usr.bin/gcc/cc1plus/parse.y3906
-rw-r--r--gnu/usr.bin/gcc/common/bi-parser.y169
-rw-r--r--gnu/usr.bin/gcc/common/c-parse.y2068
-rw-r--r--gnu/usr.bin/gcc/cpp/cexp.y1047
-rw-r--r--gnu/usr.bin/gcc/gcc2netbsd12
7 files changed, 12085 insertions, 5 deletions
diff --git a/gnu/usr.bin/gcc/cc1/c-parse.y b/gnu/usr.bin/gcc/cc1/c-parse.y
new file mode 100644
index 00000000000..e7aed2c036c
--- /dev/null
+++ b/gnu/usr.bin/gcc/cc1/c-parse.y
@@ -0,0 +1,2068 @@
+/* YACC parser for C syntax and for Objective C. -*-c-*-
+ Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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 Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* This file defines the grammar of C and that of Objective C.
+ ifobjc ... end ifobjc conditionals contain code for Objective C only.
+ ifc ... end ifc conditionals contain code for C only.
+ Sed commands in Makefile.in are used to convert this file into
+ c-parse.y and into objc-parse.y. */
+
+/* To whomever it may concern: I have heard that such a thing was once
+ written by AT&T, but I have never seen it. */
+
+%expect 34
+
+/* These are the 23 conflicts you should get in parse.output;
+ the state numbers may vary if minor changes in the grammar are made.
+
+State 42 contains 1 shift/reduce conflict. (Two ways to parse ATTRIBUTE.)
+State 44 contains 1 shift/reduce conflict. (Two ways to recover from error.)
+State 103 contains 1 shift/reduce conflict. (Two ways to recover from error.)
+State 110 contains 1 shift/reduce conflict. (Two ways to parse ATTRIBUTE.)
+State 111 contains 1 shift/reduce conflict. (Two ways to recover from error.)
+State 115 contains 1 shift/reduce conflict. (Two ways to recover from error.)
+State 132 contains 1 shift/reduce conflict. (See comment at component_decl.)
+State 180 contains 1 shift/reduce conflict. (Two ways to parse ATTRIBUTE.)
+State 194 contains 2 shift/reduce conflict. (Four ways to parse this.)
+State 202 contains 1 shift/reduce conflict. (Two ways to recover from error.)
+State 214 contains 1 shift/reduce conflict. (Two ways to recover from error.)
+State 220 contains 1 shift/reduce conflict. (Two ways to recover from error.)
+State 304 contains 2 shift/reduce conflicts. (Four ways to parse this.)
+State 335 contains 2 shift/reduce conflicts. (Four ways to parse this.)
+State 347 contains 1 shift/reduce conflict. (Two ways to parse ATTRIBUTES.)
+State 352 contains 1 shift/reduce conflict. (Two ways to parse ATTRIBUTES.)
+State 383 contains 2 shift/reduce conflicts. (Four ways to parse this.)
+State 434 contains 2 shift/reduce conflicts. (Four ways to parse this.) */
+
+
+%{
+#include <stdio.h>
+#include <errno.h>
+#include <setjmp.h>
+
+#include "config.h"
+#include "tree.h"
+#include "input.h"
+#include "c-lex.h"
+#include "c-tree.h"
+#include "flags.h"
+
+#ifdef MULTIBYTE_CHARS
+#include <stdlib.h>
+#include <locale.h>
+#endif
+
+
+/* Since parsers are distinct for each language, put the language string
+ definition here. */
+char *language_string = "GNU C";
+
+#ifndef errno
+extern int errno;
+#endif
+
+void yyerror ();
+
+/* Like YYERROR but do call yyerror. */
+#define YYERROR1 { yyerror ("syntax error"); YYERROR; }
+
+/* Cause the `yydebug' variable to be defined. */
+#define YYDEBUG 1
+%}
+
+%start program
+
+%union {long itype; tree ttype; enum tree_code code;
+ char *filename; int lineno; int ends_in_label; }
+
+/* All identifiers that are not reserved words
+ and are not declared typedefs in the current block */
+%token IDENTIFIER
+
+/* All identifiers that are declared typedefs in the current block.
+ In some contexts, they are treated just like IDENTIFIER,
+ but they can also serve as typespecs in declarations. */
+%token TYPENAME
+
+/* Reserved words that specify storage class.
+ yylval contains an IDENTIFIER_NODE which indicates which one. */
+%token SCSPEC
+
+/* Reserved words that specify type.
+ yylval contains an IDENTIFIER_NODE which indicates which one. */
+%token TYPESPEC
+
+/* Reserved words that qualify type: "const" or "volatile".
+ yylval contains an IDENTIFIER_NODE which indicates which one. */
+%token TYPE_QUAL
+
+/* Character or numeric constants.
+ yylval is the node for the constant. */
+%token CONSTANT
+
+/* String constants in raw form.
+ yylval is a STRING_CST node. */
+%token STRING
+
+/* "...", used for functions with variable arglists. */
+%token ELLIPSIS
+
+/* the reserved words */
+/* SCO include files test "ASM", so use something else. */
+%token SIZEOF ENUM STRUCT UNION IF ELSE WHILE DO FOR SWITCH CASE DEFAULT
+%token BREAK CONTINUE RETURN GOTO ASM_KEYWORD TYPEOF ALIGNOF
+%token ATTRIBUTE EXTENSION LABEL
+%token REALPART IMAGPART
+
+/* Add precedence rules to solve dangling else s/r conflict */
+%nonassoc IF
+%nonassoc ELSE
+
+/* Define the operator tokens and their precedences.
+ The value is an integer because, if used, it is the tree code
+ to use in the expression made from the operator. */
+
+%right <code> ASSIGN '='
+%right <code> '?' ':'
+%left <code> OROR
+%left <code> ANDAND
+%left <code> '|'
+%left <code> '^'
+%left <code> '&'
+%left <code> EQCOMPARE
+%left <code> ARITHCOMPARE
+%left <code> LSHIFT RSHIFT
+%left <code> '+' '-'
+%left <code> '*' '/' '%'
+%right <code> UNARY PLUSPLUS MINUSMINUS
+%left HYPERUNARY
+%left <code> POINTSAT '.' '(' '['
+
+/* The Objective-C keywords. These are included in C and in
+ Objective C, so that the token codes are the same in both. */
+%token INTERFACE IMPLEMENTATION END SELECTOR DEFS ENCODE
+%token CLASSNAME PUBLIC PRIVATE PROTECTED PROTOCOL OBJECTNAME CLASS ALIAS
+
+/* Objective-C string constants in raw form.
+ yylval is an OBJC_STRING_CST node. */
+%token OBJC_STRING
+
+
+%type <code> unop
+
+%type <ttype> identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist exprlist
+%type <ttype> expr_no_commas cast_expr unary_expr primary string STRING
+%type <ttype> typed_declspecs reserved_declspecs
+%type <ttype> typed_typespecs reserved_typespecquals
+%type <ttype> declmods typespec typespecqual_reserved
+%type <ttype> SCSPEC TYPESPEC TYPE_QUAL nonempty_type_quals maybe_type_qual
+%type <ttype> initdecls notype_initdecls initdcl notype_initdcl
+%type <ttype> init maybeasm
+%type <ttype> asm_operands nonnull_asm_operands asm_operand asm_clobbers
+%type <ttype> maybe_attribute attributes attribute attribute_list attrib
+%type <ttype> any_word
+
+%type <ttype> compstmt
+
+%type <ttype> declarator
+%type <ttype> notype_declarator after_type_declarator
+%type <ttype> parm_declarator
+
+%type <ttype> structsp component_decl_list component_decl_list2
+%type <ttype> component_decl components component_declarator
+%type <ttype> enumlist enumerator
+%type <ttype> typename absdcl absdcl1 type_quals
+%type <ttype> xexpr parms parm identifiers
+
+%type <ttype> parmlist parmlist_1 parmlist_2
+%type <ttype> parmlist_or_identifiers parmlist_or_identifiers_1
+%type <ttype> identifiers_or_typenames
+
+%type <itype> setspecs
+
+%type <ends_in_label> lineno_stmt_or_label lineno_stmt_or_labels stmt_or_label
+
+%type <filename> save_filename
+%type <lineno> save_lineno
+
+
+%{
+/* Number of statements (loosely speaking) seen so far. */
+static int stmt_count;
+
+/* Input file and line number of the end of the body of last simple_if;
+ used by the stmt-rule immediately after simple_if returns. */
+static char *if_stmt_file;
+static int if_stmt_line;
+
+/* List of types and structure classes of the current declaration. */
+static tree current_declspecs;
+static tree prefix_attributes = NULL_TREE;
+
+/* Stack of saved values of current_declspecs and prefix_attributes. */
+static tree declspec_stack;
+
+/* 1 if we explained undeclared var errors. */
+static int undeclared_variable_notice;
+
+
+/* Tell yyparse how to print a token's value, if yydebug is set. */
+
+#define YYPRINT(FILE,YYCHAR,YYLVAL) yyprint(FILE,YYCHAR,YYLVAL)
+extern void yyprint ();
+%}
+
+%%
+program: /* empty */
+ { if (pedantic)
+ pedwarn ("ANSI C forbids an empty source file");
+ finish_file ();
+ }
+ | extdefs
+ {
+ /* In case there were missing closebraces,
+ get us back to the global binding level. */
+ while (! global_bindings_p ())
+ poplevel (0, 0, 0);
+ finish_file ();
+ }
+ ;
+
+/* 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. */
+
+extdefs:
+ {$<ttype>$ = NULL_TREE; } extdef
+ | extdefs {$<ttype>$ = NULL_TREE; } extdef
+ ;
+
+extdef:
+ fndef
+ | datadef
+ | ASM_KEYWORD '(' expr ')' ';'
+ { STRIP_NOPS ($3);
+ if ((TREE_CODE ($3) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND ($3, 0)) == STRING_CST)
+ || TREE_CODE ($3) == STRING_CST)
+ assemble_asm ($3);
+ else
+ error ("argument of `asm' is not a constant string"); }
+ ;
+
+datadef:
+ setspecs notype_initdecls ';'
+ { if (pedantic)
+ error ("ANSI C forbids data definition with no type or storage class");
+ else if (!flag_traditional)
+ warning ("data definition has no type or storage class");
+
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($1); }
+ | declmods setspecs notype_initdecls ';'
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs setspecs initdecls ';'
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods ';'
+ { pedwarn ("empty declaration"); }
+ | typed_declspecs ';'
+ { shadow_tag ($1); }
+ | error ';'
+ | error '}'
+ | ';'
+ { if (pedantic)
+ pedwarn ("ANSI C does not allow extra `;' outside of a function"); }
+ ;
+
+fndef:
+ typed_declspecs setspecs declarator
+ { if (! start_function ($1, $3, prefix_attributes,
+ NULL_TREE, 0))
+ YYERROR1;
+ reinit_parse_for_function (); }
+ xdecls
+ { store_parm_decls (); }
+ compstmt_or_error
+ { finish_function (0);
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs setspecs declarator error
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods setspecs notype_declarator
+ { if (! start_function ($1, $3, prefix_attributes,
+ NULL_TREE, 0))
+ YYERROR1;
+ reinit_parse_for_function (); }
+ xdecls
+ { store_parm_decls (); }
+ compstmt_or_error
+ { finish_function (0);
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods setspecs notype_declarator error
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | setspecs notype_declarator
+ { if (! start_function (NULL_TREE, $2,
+ prefix_attributes, NULL_TREE, 0))
+ YYERROR1;
+ reinit_parse_for_function (); }
+ xdecls
+ { store_parm_decls (); }
+ compstmt_or_error
+ { finish_function (0);
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($1); }
+ | setspecs notype_declarator error
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($1); }
+ ;
+
+identifier:
+ IDENTIFIER
+ | TYPENAME
+ ;
+
+unop: '&'
+ { $$ = ADDR_EXPR; }
+ | '-'
+ { $$ = NEGATE_EXPR; }
+ | '+'
+ { $$ = CONVERT_EXPR; }
+ | PLUSPLUS
+ { $$ = PREINCREMENT_EXPR; }
+ | MINUSMINUS
+ { $$ = PREDECREMENT_EXPR; }
+ | '~'
+ { $$ = BIT_NOT_EXPR; }
+ | '!'
+ { $$ = TRUTH_NOT_EXPR; }
+ ;
+
+expr: nonnull_exprlist
+ { $$ = build_compound_expr ($1); }
+ ;
+
+exprlist:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | nonnull_exprlist
+ ;
+
+nonnull_exprlist:
+ expr_no_commas
+ { $$ = build_tree_list (NULL_TREE, $1); }
+ | nonnull_exprlist ',' expr_no_commas
+ { chainon ($1, build_tree_list (NULL_TREE, $3)); }
+ ;
+
+unary_expr:
+ primary
+ | '*' cast_expr %prec UNARY
+ { $$ = build_indirect_ref ($2, "unary *"); }
+ /* __extension__ turns off -pedantic for following primary. */
+ | EXTENSION
+ { $<itype>1 = pedantic;
+ pedantic = 0; }
+ cast_expr %prec UNARY
+ { $$ = $3;
+ pedantic = $<itype>1; }
+ | unop cast_expr %prec UNARY
+ { $$ = build_unary_op ($1, $2, 0);
+ overflow_warning ($$); }
+ /* Refer to the address of a label as a pointer. */
+ | ANDAND identifier
+ { tree label = lookup_label ($2);
+ if (pedantic)
+ pedwarn ("ANSI C forbids `&&'");
+ if (label == 0)
+ $$ = null_pointer_node;
+ else
+ {
+ TREE_USED (label) = 1;
+ $$ = build1 (ADDR_EXPR, ptr_type_node, label);
+ TREE_CONSTANT ($$) = 1;
+ }
+ }
+/* This seems to be impossible on some machines, so let's turn it off.
+ You can use __builtin_next_arg to find the anonymous stack args.
+ | '&' ELLIPSIS
+ { tree types = TYPE_ARG_TYPES (TREE_TYPE (current_function_decl));
+ $$ = error_mark_node;
+ if (TREE_VALUE (tree_last (types)) == void_type_node)
+ error ("`&...' used in function with fixed number of arguments");
+ else
+ {
+ if (pedantic)
+ pedwarn ("ANSI C forbids `&...'");
+ $$ = tree_last (DECL_ARGUMENTS (current_function_decl));
+ $$ = build_unary_op (ADDR_EXPR, $$, 0);
+ } }
+*/
+ | SIZEOF unary_expr %prec UNARY
+ { if (TREE_CODE ($2) == COMPONENT_REF
+ && DECL_BIT_FIELD (TREE_OPERAND ($2, 1)))
+ error ("`sizeof' applied to a bit-field");
+ $$ = c_sizeof (TREE_TYPE ($2)); }
+ | SIZEOF '(' typename ')' %prec HYPERUNARY
+ { $$ = c_sizeof (groktypename ($3)); }
+ | ALIGNOF unary_expr %prec UNARY
+ { $$ = c_alignof_expr ($2); }
+ | ALIGNOF '(' typename ')' %prec HYPERUNARY
+ { $$ = c_alignof (groktypename ($3)); }
+ | REALPART cast_expr %prec UNARY
+ { $$ = build_unary_op (REALPART_EXPR, $2, 0); }
+ | IMAGPART cast_expr %prec UNARY
+ { $$ = build_unary_op (IMAGPART_EXPR, $2, 0); }
+ ;
+
+cast_expr:
+ unary_expr
+ | '(' typename ')' cast_expr %prec UNARY
+ { tree type = groktypename ($2);
+ $$ = build_c_cast (type, $4); }
+ | '(' typename ')' '{'
+ { start_init (NULL_TREE, NULL, 0);
+ $2 = groktypename ($2);
+ really_start_incremental_init ($2); }
+ initlist_maybe_comma '}' %prec UNARY
+ { char *name;
+ tree result = pop_init_level (0);
+ tree type = $2;
+ finish_init ();
+
+ if (pedantic)
+ pedwarn ("ANSI C forbids constructor expressions");
+ if (TYPE_NAME (type) != 0)
+ {
+ if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
+ name = IDENTIFIER_POINTER (TYPE_NAME (type));
+ else
+ name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
+ }
+ else
+ name = "";
+ $$ = result;
+ if (TREE_CODE (type) == ARRAY_TYPE && TYPE_SIZE (type) == 0)
+ {
+ int failure = complete_array_type (type, $$, 1);
+ if (failure)
+ abort ();
+ }
+ }
+ ;
+
+expr_no_commas:
+ cast_expr
+ | expr_no_commas '+' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '-' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '*' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '/' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '%' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas LSHIFT expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas RSHIFT expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas ARITHCOMPARE expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas EQCOMPARE expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '&' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '|' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '^' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas ANDAND expr_no_commas
+ { $$ = parser_build_binary_op (TRUTH_ANDIF_EXPR, $1, $3); }
+ | expr_no_commas OROR expr_no_commas
+ { $$ = parser_build_binary_op (TRUTH_ORIF_EXPR, $1, $3); }
+ | expr_no_commas '?' xexpr ':' expr_no_commas
+ { $$ = build_conditional_expr ($1, $3, $5); }
+ | expr_no_commas '=' expr_no_commas
+ { $$ = build_modify_expr ($1, NOP_EXPR, $3);
+ C_SET_EXP_ORIGINAL_CODE ($$, MODIFY_EXPR); }
+ | expr_no_commas ASSIGN expr_no_commas
+ { $$ = build_modify_expr ($1, $2, $3);
+ /* This inhibits warnings in truthvalue_conversion. */
+ C_SET_EXP_ORIGINAL_CODE ($$, ERROR_MARK); }
+ ;
+
+primary:
+ IDENTIFIER
+ {
+ $$ = lastiddecl;
+ if (!$$ || $$ == error_mark_node)
+ {
+ if (yychar == YYEMPTY)
+ yychar = YYLEX;
+ if (yychar == '(')
+ {
+ {
+ /* Ordinary implicit function declaration. */
+ $$ = implicitly_declare ($1);
+ assemble_external ($$);
+ TREE_USED ($$) = 1;
+ }
+ }
+ else if (current_function_decl == 0)
+ {
+ error ("`%s' undeclared here (not in a function)",
+ IDENTIFIER_POINTER ($1));
+ $$ = error_mark_node;
+ }
+ else
+ {
+ {
+ if (IDENTIFIER_GLOBAL_VALUE ($1) != error_mark_node
+ || IDENTIFIER_ERROR_LOCUS ($1) != current_function_decl)
+ {
+ error ("`%s' undeclared (first use this function)",
+ IDENTIFIER_POINTER ($1));
+
+ if (! undeclared_variable_notice)
+ {
+ error ("(Each undeclared identifier is reported only once");
+ error ("for each function it appears in.)");
+ undeclared_variable_notice = 1;
+ }
+ }
+ $$ = error_mark_node;
+ /* Prevent repeated error messages. */
+ IDENTIFIER_GLOBAL_VALUE ($1) = error_mark_node;
+ IDENTIFIER_ERROR_LOCUS ($1) = current_function_decl;
+ }
+ }
+ }
+ else if (TREE_TYPE ($$) == error_mark_node)
+ $$ = error_mark_node;
+ else if (C_DECL_ANTICIPATED ($$))
+ {
+ /* The first time we see a build-in function used,
+ if it has not been declared. */
+ C_DECL_ANTICIPATED ($$) = 0;
+ if (yychar == YYEMPTY)
+ yychar = YYLEX;
+ if (yychar == '(')
+ {
+ /* Omit the implicit declaration we
+ would ordinarily do, so we don't lose
+ the actual built in type.
+ But print a diagnostic for the mismatch. */
+ if (TREE_CODE ($$) != FUNCTION_DECL)
+ error ("`%s' implicitly declared as function",
+ IDENTIFIER_POINTER (DECL_NAME ($$)));
+ else if ((TYPE_MODE (TREE_TYPE (TREE_TYPE ($$)))
+ != TYPE_MODE (integer_type_node))
+ && (TREE_TYPE (TREE_TYPE ($$))
+ != void_type_node))
+ pedwarn ("type mismatch in implicit declaration for built-in function `%s'",
+ IDENTIFIER_POINTER (DECL_NAME ($$)));
+ /* If it really returns void, change that to int. */
+ if (TREE_TYPE (TREE_TYPE ($$)) == void_type_node)
+ TREE_TYPE ($$)
+ = build_function_type (integer_type_node,
+ TYPE_ARG_TYPES (TREE_TYPE ($$)));
+ }
+ else
+ pedwarn ("built-in function `%s' used without declaration",
+ IDENTIFIER_POINTER (DECL_NAME ($$)));
+
+ /* Do what we would ordinarily do when a fn is used. */
+ assemble_external ($$);
+ TREE_USED ($$) = 1;
+ }
+ else
+ {
+ assemble_external ($$);
+ TREE_USED ($$) = 1;
+ }
+
+ if (TREE_CODE ($$) == CONST_DECL)
+ {
+ $$ = DECL_INITIAL ($$);
+ /* This is to prevent an enum whose value is 0
+ from being considered a null pointer constant. */
+ $$ = build1 (NOP_EXPR, TREE_TYPE ($$), $$);
+ TREE_CONSTANT ($$) = 1;
+ }
+ }
+ | CONSTANT
+ | string
+ { $$ = combine_strings ($1); }
+ | '(' expr ')'
+ { char class = TREE_CODE_CLASS (TREE_CODE ($2));
+ if (class == 'e' || class == '1'
+ || class == '2' || class == '<')
+ C_SET_EXP_ORIGINAL_CODE ($2, ERROR_MARK);
+ $$ = $2; }
+ | '(' error ')'
+ { $$ = error_mark_node; }
+ | '('
+ { if (current_function_decl == 0)
+ {
+ error ("braced-group within expression allowed only inside a function");
+ YYERROR;
+ }
+ /* We must force a BLOCK for this level
+ so that, if it is not expanded later,
+ there is a way to turn off the entire subtree of blocks
+ that are contained in it. */
+ keep_next_level ();
+ push_iterator_stack ();
+ push_label_level ();
+ $<ttype>$ = expand_start_stmt_expr (); }
+ compstmt ')'
+ { tree rtl_exp;
+ if (pedantic)
+ pedwarn ("ANSI C forbids braced-groups within expressions");
+ pop_iterator_stack ();
+ pop_label_level ();
+ rtl_exp = expand_end_stmt_expr ($<ttype>2);
+ /* The statements have side effects, so the group does. */
+ TREE_SIDE_EFFECTS (rtl_exp) = 1;
+
+ if (TREE_CODE ($3) == BLOCK)
+ {
+ /* Make a BIND_EXPR for the BLOCK already made. */
+ $$ = build (BIND_EXPR, TREE_TYPE (rtl_exp),
+ NULL_TREE, rtl_exp, $3);
+ /* Remove the block from the tree at this point.
+ It gets put back at the proper place
+ when the BIND_EXPR is expanded. */
+ delete_block ($3);
+ }
+ else
+ $$ = $3;
+ }
+ | primary '(' exprlist ')' %prec '.'
+ { $$ = build_function_call ($1, $3); }
+ | primary '[' expr ']' %prec '.'
+ { $$ = build_array_ref ($1, $3); }
+ | primary '.' identifier
+ {
+ $$ = build_component_ref ($1, $3);
+ }
+ | primary POINTSAT identifier
+ {
+ tree expr = build_indirect_ref ($1, "->");
+
+ $$ = build_component_ref (expr, $3);
+ }
+ | primary PLUSPLUS
+ { $$ = build_unary_op (POSTINCREMENT_EXPR, $1, 0); }
+ | primary MINUSMINUS
+ { $$ = build_unary_op (POSTDECREMENT_EXPR, $1, 0); }
+ ;
+
+/* Produces a STRING_CST with perhaps more STRING_CSTs chained onto it. */
+string:
+ STRING
+ | string STRING
+ { $$ = chainon ($1, $2); }
+ ;
+
+
+xdecls:
+ /* empty */
+ | datadecls
+ | datadecls ELLIPSIS
+ /* ... is used here to indicate a varargs function. */
+ { c_mark_varargs ();
+ if (pedantic)
+ pedwarn ("ANSI C does not permit use of `varargs.h'"); }
+ ;
+
+/* The following are analogous to lineno_decl, decls and decl
+ except that they do not allow nested functions.
+ They are used for old-style parm decls. */
+lineno_datadecl:
+ save_filename save_lineno datadecl
+ { }
+ ;
+
+datadecls:
+ lineno_datadecl
+ | errstmt
+ | datadecls lineno_datadecl
+ | lineno_datadecl errstmt
+ ;
+
+datadecl:
+ typed_declspecs setspecs initdecls ';'
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods setspecs notype_initdecls ';'
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs ';'
+ { shadow_tag_warned ($1, 1);
+ pedwarn ("empty declaration"); }
+ | declmods ';'
+ { pedwarn ("empty declaration"); }
+ ;
+
+/* This combination which saves a lineno before a decl
+ is the normal thing to use, rather than decl itself.
+ This is to avoid shift/reduce conflicts in contexts
+ where statement labels are allowed. */
+lineno_decl:
+ save_filename save_lineno decl
+ { }
+ ;
+
+decls:
+ lineno_decl
+ | errstmt
+ | decls lineno_decl
+ | lineno_decl errstmt
+ ;
+
+/* records the type and storage class specs to use for processing
+ the declarators that follow.
+ Maintains a stack of outer-level values of current_declspecs,
+ for the sake of parm declarations nested in function declarators. */
+setspecs: /* empty */
+ { $$ = suspend_momentary ();
+ pending_xref_error ();
+ declspec_stack = tree_cons (prefix_attributes,
+ current_declspecs,
+ declspec_stack);
+ current_declspecs = $<ttype>0;
+ prefix_attributes = NULL_TREE; }
+ ;
+
+setattrs: /* empty */
+ { prefix_attributes = chainon (prefix_attributes, $<ttype>0); }
+ ;
+
+decl:
+ typed_declspecs setspecs initdecls ';'
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods setspecs notype_initdecls ';'
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs setspecs nested_function
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods setspecs notype_nested_function
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs ';'
+ { shadow_tag ($1); }
+ | declmods ';'
+ { pedwarn ("empty declaration"); }
+ ;
+
+/* 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. */
+
+typed_declspecs:
+ typespec reserved_declspecs
+ { $$ = tree_cons (NULL_TREE, $1, $2); }
+ | declmods typespec reserved_declspecs
+ { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); }
+ ;
+
+reserved_declspecs: /* empty */
+ { $$ = NULL_TREE; }
+ | reserved_declspecs typespecqual_reserved
+ { $$ = tree_cons (NULL_TREE, $2, $1); }
+ | reserved_declspecs SCSPEC
+ { if (extra_warnings)
+ warning ("`%s' is not at beginning of declaration",
+ IDENTIFIER_POINTER ($2));
+ $$ = tree_cons (NULL_TREE, $2, $1); }
+ ;
+
+/* List of just storage classes and type modifiers.
+ A declaration can start with just this, but then it cannot be used
+ to redeclare a typedef-name. */
+
+declmods:
+ TYPE_QUAL
+ { $$ = tree_cons (NULL_TREE, $1, NULL_TREE);
+ TREE_STATIC ($$) = 1; }
+ | SCSPEC
+ { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); }
+ | declmods TYPE_QUAL
+ { $$ = tree_cons (NULL_TREE, $2, $1);
+ TREE_STATIC ($$) = 1; }
+ | declmods 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); }
+ ;
+
+
+/* Used instead of declspecs where storage classes are not allowed
+ (that is, for typenames and structure components).
+ Don't accept a typedef-name if anything but a modifier precedes it. */
+
+typed_typespecs:
+ typespec reserved_typespecquals
+ { $$ = tree_cons (NULL_TREE, $1, $2); }
+ | nonempty_type_quals typespec reserved_typespecquals
+ { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); }
+ ;
+
+reserved_typespecquals: /* empty */
+ { $$ = NULL_TREE; }
+ | reserved_typespecquals typespecqual_reserved
+ { $$ = tree_cons (NULL_TREE, $2, $1); }
+ ;
+
+/* A typespec (but not a type qualifier).
+ Once we have seen one of these in a declaration,
+ if a typedef name appears then it is being redeclared. */
+
+typespec: TYPESPEC
+ | structsp
+ | TYPENAME
+ { /* For a typedef name, record the meaning, not the name.
+ In case of `foo foo, bar;'. */
+ $$ = lookup_name ($1); }
+ | TYPEOF '(' expr ')'
+ { $$ = TREE_TYPE ($3); }
+ | TYPEOF '(' typename ')'
+ { $$ = groktypename ($3); }
+ ;
+
+/* A typespec that is a reserved word, or a type qualifier. */
+
+typespecqual_reserved: TYPESPEC
+ | TYPE_QUAL
+ | structsp
+ ;
+
+initdecls:
+ initdcl
+ | initdecls ',' initdcl
+ ;
+
+notype_initdecls:
+ notype_initdcl
+ | notype_initdecls ',' initdcl
+ ;
+
+maybeasm:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | ASM_KEYWORD '(' string ')'
+ { if (TREE_CHAIN ($3)) $3 = combine_strings ($3);
+ $$ = $3;
+ }
+ ;
+
+initdcl:
+ declarator maybeasm maybe_attribute '='
+ { $<ttype>$ = start_decl ($1, current_declspecs, 1,
+ $3, prefix_attributes);
+ start_init ($<ttype>$, $2, global_bindings_p ()); }
+ init
+/* Note how the declaration of the variable is in effect while its init is parsed! */
+ { finish_init ();
+ finish_decl ($<ttype>5, $6, $2); }
+ | declarator maybeasm maybe_attribute
+ { tree d = start_decl ($1, current_declspecs, 0,
+ $3, prefix_attributes);
+ finish_decl (d, NULL_TREE, $2);
+ }
+ ;
+
+notype_initdcl:
+ notype_declarator maybeasm maybe_attribute '='
+ { $<ttype>$ = start_decl ($1, current_declspecs, 1,
+ $3, prefix_attributes);
+ start_init ($<ttype>$, $2, global_bindings_p ()); }
+ init
+/* Note how the declaration of the variable is in effect while its init is parsed! */
+ { finish_init ();
+ decl_attributes ($<ttype>5, $3, prefix_attributes);
+ finish_decl ($<ttype>5, $6, $2); }
+ | notype_declarator maybeasm maybe_attribute
+ { tree d = start_decl ($1, current_declspecs, 0,
+ $3, prefix_attributes);
+ finish_decl (d, NULL_TREE, $2); }
+ ;
+/* the * rules are dummies to accept the Apollo extended syntax
+ so that the header files compile. */
+maybe_attribute:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | attributes
+ { $$ = $1; }
+ ;
+
+attributes:
+ attribute
+ { $$ = $1; }
+ | attributes attribute
+ { $$ = chainon ($1, $2); }
+ ;
+
+attribute:
+ ATTRIBUTE '(' '(' attribute_list ')' ')'
+ { $$ = $4; }
+ ;
+
+attribute_list:
+ attrib
+ { $$ = $1; }
+ | attribute_list ',' attrib
+ { $$ = chainon ($1, $3); }
+ ;
+
+attrib:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | any_word
+ { $$ = build_tree_list ($1, NULL_TREE); }
+ | any_word '(' IDENTIFIER ')'
+ { $$ = build_tree_list ($1, build_tree_list (NULL_TREE, $3)); }
+ | any_word '(' IDENTIFIER ',' nonnull_exprlist ')'
+ { $$ = build_tree_list ($1, tree_cons (NULL_TREE, $3, $5)); }
+ | any_word '(' exprlist ')'
+ { $$ = build_tree_list ($1, $3); }
+ ;
+
+/* This still leaves out most reserved keywords,
+ shouldn't we include them? */
+
+any_word:
+ identifier
+ | SCSPEC
+ | TYPESPEC
+ | TYPE_QUAL
+ ;
+
+/* Initializers. `init' is the entry point. */
+
+init:
+ expr_no_commas
+ | '{'
+ { really_start_incremental_init (NULL_TREE);
+ /* Note that the call to clear_momentary
+ is in process_init_element. */
+ push_momentary (); }
+ initlist_maybe_comma '}'
+ { $$ = pop_init_level (0);
+ if ($$ == error_mark_node
+ && ! (yychar == STRING || yychar == CONSTANT))
+ pop_momentary ();
+ else
+ pop_momentary_nofree (); }
+
+ | error
+ { $$ = error_mark_node; }
+ ;
+
+/* `initlist_maybe_comma' is the guts of an initializer in braces. */
+initlist_maybe_comma:
+ /* empty */
+ { if (pedantic)
+ pedwarn ("ANSI C forbids empty initializer braces"); }
+ | initlist1 maybecomma
+ ;
+
+initlist1:
+ initelt
+ | initlist1 ',' initelt
+ ;
+
+/* `initelt' is a single element of an initializer.
+ It may use braces. */
+initelt:
+ expr_no_commas
+ { process_init_element ($1); }
+ | '{'
+ { push_init_level (0); }
+ initlist_maybe_comma '}'
+ { process_init_element (pop_init_level (0)); }
+ | error
+ /* These are for labeled elements. The syntax for an array element
+ initializer conflicts with the syntax for an Objective-C message,
+ so don't include these productions in the Objective-C grammar. */
+ | '[' expr_no_commas ELLIPSIS expr_no_commas ']' '='
+ { set_init_index ($2, $4); }
+ initelt
+ | '[' expr_no_commas ']' '='
+ { set_init_index ($2, NULL_TREE); }
+ initelt
+ | '[' expr_no_commas ']'
+ { set_init_index ($2, NULL_TREE); }
+ initelt
+ | identifier ':'
+ { set_init_label ($1); }
+ initelt
+ | '.' identifier '='
+ { set_init_label ($2); }
+ initelt
+ ;
+
+nested_function:
+ declarator
+ { push_c_function_context ();
+ if (! start_function (current_declspecs, $1,
+ prefix_attributes, NULL_TREE, 1))
+ {
+ pop_c_function_context ();
+ YYERROR1;
+ }
+ reinit_parse_for_function (); }
+ xdecls
+ { store_parm_decls (); }
+/* This used to use compstmt_or_error.
+ That caused a bug with input `f(g) int g {}',
+ where the use of YYERROR1 above caused an error
+ which then was handled by compstmt_or_error.
+ There followed a repeated execution of that same rule,
+ which called YYERROR1 again, and so on. */
+ compstmt
+ { finish_function (1);
+ pop_c_function_context (); }
+ ;
+
+notype_nested_function:
+ notype_declarator
+ { push_c_function_context ();
+ if (! start_function (current_declspecs, $1,
+ prefix_attributes, NULL_TREE, 1))
+ {
+ pop_c_function_context ();
+ YYERROR1;
+ }
+ reinit_parse_for_function (); }
+ xdecls
+ { store_parm_decls (); }
+/* This used to use compstmt_or_error.
+ That caused a bug with input `f(g) int g {}',
+ where the use of YYERROR1 above caused an error
+ which then was handled by compstmt_or_error.
+ There followed a repeated execution of that same rule,
+ which called YYERROR1 again, and so on. */
+ compstmt
+ { finish_function (1);
+ pop_c_function_context (); }
+ ;
+
+/* Any kind of declarator (thus, all declarators allowed
+ after an explicit typespec). */
+
+declarator:
+ after_type_declarator
+ | notype_declarator
+ ;
+
+/* A declarator that is allowed only after an explicit typespec. */
+
+after_type_declarator:
+ '(' after_type_declarator ')'
+ { $$ = $2; }
+ | after_type_declarator '(' parmlist_or_identifiers %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
+/* | after_type_declarator '(' error ')' %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE);
+ poplevel (0, 0, 0); } */
+ | after_type_declarator '[' expr ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, $3); }
+ | after_type_declarator '[' ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
+ | '*' type_quals after_type_declarator %prec UNARY
+ { $$ = make_pointer_declarator ($2, $3); }
+ | attributes setattrs after_type_declarator
+ { $$ = $3; }
+ | TYPENAME
+ ;
+
+/* Kinds of declarator that can appear in a parameter list
+ in addition to notype_declarator. This is like after_type_declarator
+ but does not allow a typedef name in parentheses as an identifier
+ (because it would conflict with a function with that typedef as arg). */
+
+parm_declarator:
+ parm_declarator '(' parmlist_or_identifiers %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
+/* | parm_declarator '(' error ')' %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE);
+ poplevel (0, 0, 0); } */
+ | parm_declarator '[' expr ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, $3); }
+ | parm_declarator '[' ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
+ | '*' type_quals parm_declarator %prec UNARY
+ { $$ = make_pointer_declarator ($2, $3); }
+ | attributes setattrs parm_declarator
+ { $$ = $3; }
+ | TYPENAME
+ ;
+
+/* A declarator allowed whether or not there has been
+ an explicit typespec. These cannot redeclare a typedef-name. */
+
+notype_declarator:
+ notype_declarator '(' parmlist_or_identifiers %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
+/* | notype_declarator '(' error ')' %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE);
+ poplevel (0, 0, 0); } */
+ | '(' notype_declarator ')'
+ { $$ = $2; }
+ | '*' type_quals notype_declarator %prec UNARY
+ { $$ = make_pointer_declarator ($2, $3); }
+ | notype_declarator '[' expr ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, $3); }
+ | notype_declarator '[' ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
+ | attributes setattrs notype_declarator
+ { $$ = $3; }
+ | IDENTIFIER
+ ;
+
+structsp:
+ STRUCT identifier '{'
+ { $$ = start_struct (RECORD_TYPE, $2);
+ /* Start scope of tag before parsing components. */
+ }
+ component_decl_list '}' maybe_attribute
+ { $$ = finish_struct ($<ttype>4, $5, $7); }
+ | STRUCT '{' component_decl_list '}' maybe_attribute
+ { $$ = finish_struct (start_struct (RECORD_TYPE, NULL_TREE),
+ $3, $5);
+ }
+ | STRUCT identifier
+ { $$ = xref_tag (RECORD_TYPE, $2); }
+ | UNION identifier '{'
+ { $$ = start_struct (UNION_TYPE, $2); }
+ component_decl_list '}' maybe_attribute
+ { $$ = finish_struct ($<ttype>4, $5, $7); }
+ | UNION '{' component_decl_list '}' maybe_attribute
+ { $$ = finish_struct (start_struct (UNION_TYPE, NULL_TREE),
+ $3, $5);
+ }
+ | UNION identifier
+ { $$ = xref_tag (UNION_TYPE, $2); }
+ | ENUM identifier '{'
+ { $<itype>3 = suspend_momentary ();
+ $$ = start_enum ($2); }
+ enumlist maybecomma_warn '}' maybe_attribute
+ { $$ = finish_enum ($<ttype>4, nreverse ($5), $8);
+ resume_momentary ($<itype>3); }
+ | ENUM '{'
+ { $<itype>2 = suspend_momentary ();
+ $$ = start_enum (NULL_TREE); }
+ enumlist maybecomma_warn '}' maybe_attribute
+ { $$ = finish_enum ($<ttype>3, nreverse ($4), $7);
+ resume_momentary ($<itype>2); }
+ | ENUM identifier
+ { $$ = xref_tag (ENUMERAL_TYPE, $2); }
+ ;
+
+maybecomma:
+ /* empty */
+ | ','
+ ;
+
+maybecomma_warn:
+ /* empty */
+ | ','
+ { if (pedantic) pedwarn ("comma at end of enumerator list"); }
+ ;
+
+component_decl_list:
+ component_decl_list2
+ { $$ = $1; }
+ | component_decl_list2 component_decl
+ { $$ = chainon ($1, $2);
+ pedwarn ("no semicolon at end of struct or union"); }
+ ;
+
+component_decl_list2: /* empty */
+ { $$ = NULL_TREE; }
+ | component_decl_list2 component_decl ';'
+ { $$ = chainon ($1, $2); }
+ | component_decl_list2 ';'
+ { 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. */
+
+component_decl:
+ typed_typespecs setspecs components
+ { $$ = $3;
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_typespecs
+ { if (pedantic)
+ pedwarn ("ANSI C forbids member declarations with no members");
+ shadow_tag($1);
+ $$ = NULL_TREE; }
+ | nonempty_type_quals setspecs components
+ { $$ = $3;
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | nonempty_type_quals
+ { if (pedantic)
+ pedwarn ("ANSI C forbids member declarations with no members");
+ shadow_tag($1);
+ $$ = NULL_TREE; }
+ | error
+ { $$ = NULL_TREE; }
+ ;
+
+components:
+ component_declarator
+ | components ',' component_declarator
+ { $$ = chainon ($1, $3); }
+ ;
+
+component_declarator:
+ save_filename save_lineno declarator maybe_attribute
+ { $$ = grokfield ($1, $2, $3, current_declspecs, NULL_TREE);
+ decl_attributes ($$, $4, prefix_attributes); }
+ | save_filename save_lineno
+ declarator ':' expr_no_commas maybe_attribute
+ { $$ = grokfield ($1, $2, $3, current_declspecs, $5);
+ decl_attributes ($$, $6, prefix_attributes); }
+ | save_filename save_lineno ':' expr_no_commas maybe_attribute
+ { $$ = grokfield ($1, $2, NULL_TREE, current_declspecs, $4);
+ decl_attributes ($$, $5, prefix_attributes); }
+ ;
+
+/* We chain the enumerators in reverse order.
+ They are put in forward order where enumlist is used.
+ (The order used to be significant, but no longer is so.
+ However, we still maintain the order, just to be clean.) */
+
+enumlist:
+ enumerator
+ | enumlist ',' enumerator
+ { if ($1 == error_mark_node)
+ $$ = $1;
+ else
+ $$ = chainon ($3, $1); }
+ | error
+ { $$ = error_mark_node; }
+ ;
+
+
+enumerator:
+ identifier
+ { $$ = build_enumerator ($1, NULL_TREE); }
+ | identifier '=' expr_no_commas
+ { $$ = build_enumerator ($1, $3); }
+ ;
+
+typename:
+ typed_typespecs absdcl
+ { $$ = build_tree_list ($1, $2); }
+ | nonempty_type_quals absdcl
+ { $$ = build_tree_list ($1, $2); }
+ ;
+
+absdcl: /* an absolute declarator */
+ /* empty */
+ { $$ = NULL_TREE; }
+ | absdcl1
+ ;
+
+nonempty_type_quals:
+ TYPE_QUAL
+ { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); }
+ | nonempty_type_quals TYPE_QUAL
+ { $$ = tree_cons (NULL_TREE, $2, $1); }
+ ;
+
+type_quals:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | type_quals TYPE_QUAL
+ { $$ = tree_cons (NULL_TREE, $2, $1); }
+ ;
+
+absdcl1: /* a nonempty absolute declarator */
+ '(' absdcl1 ')'
+ { $$ = $2; }
+ /* `(typedef)1' is `int'. */
+ | '*' type_quals absdcl1 %prec UNARY
+ { $$ = make_pointer_declarator ($2, $3); }
+ | '*' type_quals %prec UNARY
+ { $$ = make_pointer_declarator ($2, NULL_TREE); }
+ | absdcl1 '(' parmlist %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
+ | absdcl1 '[' expr ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, $3); }
+ | absdcl1 '[' ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
+ | '(' parmlist %prec '.'
+ { $$ = build_nt (CALL_EXPR, NULL_TREE, $2, NULL_TREE); }
+ | '[' expr ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, NULL_TREE, $2); }
+ | '[' ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, NULL_TREE, NULL_TREE); }
+ | attributes setattrs absdcl1
+ { $$ = $3; }
+ ;
+
+/* at least one statement, the first of which parses without error. */
+/* stmts is used only after decls, so an invalid first statement
+ is actually regarded as an invalid decl and part of the decls. */
+
+stmts:
+ lineno_stmt_or_labels
+ {
+ if (pedantic && $1)
+ pedwarn ("ANSI C forbids label at end of compound statement");
+ }
+ ;
+
+lineno_stmt_or_labels:
+ lineno_stmt_or_label
+ | lineno_stmt_or_labels lineno_stmt_or_label
+ { $$ = $2; }
+ | lineno_stmt_or_labels errstmt
+ { $$ = 0; }
+ ;
+
+xstmts:
+ /* empty */
+ | stmts
+ ;
+
+errstmt: error ';'
+ ;
+
+pushlevel: /* empty */
+ { emit_line_note (input_filename, lineno);
+ pushlevel (0);
+ clear_last_expr ();
+ push_momentary ();
+ expand_start_bindings (0);
+ }
+ ;
+
+/* Read zero or more forward-declarations for labels
+ that nested functions can jump to. */
+maybe_label_decls:
+ /* empty */
+ | label_decls
+ { if (pedantic)
+ pedwarn ("ANSI C forbids label declarations"); }
+ ;
+
+label_decls:
+ label_decl
+ | label_decls label_decl
+ ;
+
+label_decl:
+ LABEL identifiers_or_typenames ';'
+ { tree link;
+ for (link = $2; link; link = TREE_CHAIN (link))
+ {
+ tree label = shadow_label (TREE_VALUE (link));
+ C_DECLARED_LABEL_FLAG (label) = 1;
+ declare_nonlocal_label (label);
+ }
+ }
+ ;
+
+/* This is the body of a function definition.
+ It causes syntax errors to ignore to the next openbrace. */
+compstmt_or_error:
+ compstmt
+ {}
+ | error compstmt
+ ;
+
+compstmt: '{' '}'
+ { $$ = convert (void_type_node, integer_zero_node); }
+ | '{' pushlevel maybe_label_decls decls xstmts '}'
+ { emit_line_note (input_filename, lineno);
+ expand_end_bindings (getdecls (), 1, 0);
+ $$ = poplevel (1, 1, 0);
+ if (yychar == CONSTANT || yychar == STRING)
+ pop_momentary_nofree ();
+ else
+ pop_momentary (); }
+ | '{' pushlevel maybe_label_decls error '}'
+ { emit_line_note (input_filename, lineno);
+ expand_end_bindings (getdecls (), kept_level_p (), 0);
+ $$ = poplevel (kept_level_p (), 0, 0);
+ if (yychar == CONSTANT || yychar == STRING)
+ pop_momentary_nofree ();
+ else
+ pop_momentary (); }
+ | '{' pushlevel maybe_label_decls stmts '}'
+ { emit_line_note (input_filename, lineno);
+ expand_end_bindings (getdecls (), kept_level_p (), 0);
+ $$ = poplevel (kept_level_p (), 0, 0);
+ if (yychar == CONSTANT || yychar == STRING)
+ pop_momentary_nofree ();
+ else
+ pop_momentary (); }
+ ;
+
+/* Value is number of statements counted as of the closeparen. */
+simple_if:
+ if_prefix lineno_labeled_stmt
+/* Make sure expand_end_cond is run once
+ for each call to expand_start_cond.
+ Otherwise a crash is likely. */
+ | if_prefix error
+ ;
+
+if_prefix:
+ IF '(' expr ')'
+ { emit_line_note ($<filename>-1, $<lineno>0);
+ expand_start_cond (truthvalue_conversion ($3), 0);
+ $<itype>$ = stmt_count;
+ if_stmt_file = $<filename>-1;
+ if_stmt_line = $<lineno>0;
+ position_after_white_space (); }
+ ;
+
+/* This is a subroutine of stmt.
+ It is used twice, once for valid DO statements
+ and once for catching errors in parsing the end test. */
+do_stmt_start:
+ DO
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ /* See comment in `while' alternative, above. */
+ emit_nop ();
+ expand_start_loop_continue_elsewhere (1);
+ position_after_white_space (); }
+ lineno_labeled_stmt WHILE
+ { expand_loop_continue_here (); }
+ ;
+
+save_filename:
+ { $$ = input_filename; }
+ ;
+
+save_lineno:
+ { $$ = lineno; }
+ ;
+
+lineno_labeled_stmt:
+ save_filename save_lineno stmt
+ { }
+/* | save_filename save_lineno error
+ { }
+*/
+ | save_filename save_lineno label lineno_labeled_stmt
+ { }
+ ;
+
+lineno_stmt_or_label:
+ save_filename save_lineno stmt_or_label
+ { $$ = $3; }
+ ;
+
+stmt_or_label:
+ stmt
+ { $$ = 0; }
+ | label
+ { $$ = 1; }
+ ;
+
+/* Parse a single real statement, not including any labels. */
+stmt:
+ compstmt
+ { stmt_count++; }
+ | all_iter_stmt
+ | expr ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+/* It appears that this should not be done--that a non-lvalue array
+ shouldn't get an error if the value isn't used.
+ Section 3.2.2.1 says that an array lvalue gets converted to a pointer
+ if it appears as a top-level expression,
+ but says nothing about non-lvalue arrays. */
+#if 0
+ /* Call default_conversion to get an error
+ on referring to a register array if pedantic. */
+ if (TREE_CODE (TREE_TYPE ($1)) == ARRAY_TYPE
+ || TREE_CODE (TREE_TYPE ($1)) == FUNCTION_TYPE)
+ $1 = default_conversion ($1);
+#endif
+ iterator_expand ($1);
+ clear_momentary (); }
+ | simple_if ELSE
+ { expand_start_else ();
+ $<itype>1 = stmt_count;
+ position_after_white_space (); }
+ lineno_labeled_stmt
+ { expand_end_cond ();
+ if (extra_warnings && stmt_count == $<itype>1)
+ warning ("empty body in an else-statement"); }
+ | simple_if %prec IF
+ { expand_end_cond ();
+ /* This warning is here instead of in simple_if, because we
+ do not want a warning if an empty if is followed by an
+ else statement. Increment stmt_count so we don't
+ give a second error if this is a nested `if'. */
+ if (extra_warnings && stmt_count++ == $<itype>1)
+ warning_with_file_and_line (if_stmt_file, if_stmt_line,
+ "empty body in an if-statement"); }
+/* Make sure expand_end_cond is run once
+ for each call to expand_start_cond.
+ Otherwise a crash is likely. */
+ | simple_if ELSE error
+ { expand_end_cond (); }
+ | WHILE
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ /* The emit_nop used to come before emit_line_note,
+ but that made the nop seem like part of the preceding line.
+ And that was confusing when the preceding line was
+ inside of an if statement and was not really executed.
+ I think it ought to work to put the nop after the line number.
+ We will see. --rms, July 15, 1991. */
+ emit_nop (); }
+ '(' expr ')'
+ { /* Don't start the loop till we have succeeded
+ in parsing the end test. This is to make sure
+ that we end every loop we start. */
+ expand_start_loop (1);
+ emit_line_note (input_filename, lineno);
+ expand_exit_loop_if_false (NULL_PTR,
+ truthvalue_conversion ($4));
+ position_after_white_space (); }
+ lineno_labeled_stmt
+ { expand_end_loop (); }
+ | do_stmt_start
+ '(' expr ')' ';'
+ { emit_line_note (input_filename, lineno);
+ expand_exit_loop_if_false (NULL_PTR,
+ truthvalue_conversion ($3));
+ expand_end_loop ();
+ clear_momentary (); }
+/* This rule is needed to make sure we end every loop we start. */
+ | do_stmt_start error
+ { expand_end_loop ();
+ clear_momentary (); }
+ | FOR
+ '(' xexpr ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ /* See comment in `while' alternative, above. */
+ emit_nop ();
+ if ($3) c_expand_expr_stmt ($3);
+ /* Next step is to call expand_start_loop_continue_elsewhere,
+ but wait till after we parse the entire for (...).
+ Otherwise, invalid input might cause us to call that
+ fn without calling expand_end_loop. */
+ }
+ xexpr ';'
+ /* Can't emit now; wait till after expand_start_loop... */
+ { $<lineno>7 = lineno;
+ $<filename>$ = input_filename; }
+ xexpr ')'
+ {
+ /* Start the loop. Doing this after parsing
+ all the expressions ensures we will end the loop. */
+ expand_start_loop_continue_elsewhere (1);
+ /* Emit the end-test, with a line number. */
+ emit_line_note ($<filename>8, $<lineno>7);
+ if ($6)
+ expand_exit_loop_if_false (NULL_PTR,
+ truthvalue_conversion ($6));
+ /* Don't let the tree nodes for $9 be discarded by
+ clear_momentary during the parsing of the next stmt. */
+ push_momentary ();
+ $<lineno>7 = lineno;
+ $<filename>8 = input_filename;
+ position_after_white_space (); }
+ lineno_labeled_stmt
+ { /* Emit the increment expression, with a line number. */
+ emit_line_note ($<filename>8, $<lineno>7);
+ expand_loop_continue_here ();
+ if ($9)
+ c_expand_expr_stmt ($9);
+ if (yychar == CONSTANT || yychar == STRING)
+ pop_momentary_nofree ();
+ else
+ pop_momentary ();
+ expand_end_loop (); }
+ | SWITCH '(' expr ')'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ c_expand_start_case ($3);
+ /* Don't let the tree nodes for $3 be discarded by
+ clear_momentary during the parsing of the next stmt. */
+ push_momentary ();
+ position_after_white_space (); }
+ lineno_labeled_stmt
+ { expand_end_case ($3);
+ if (yychar == CONSTANT || yychar == STRING)
+ pop_momentary_nofree ();
+ else
+ pop_momentary (); }
+ | BREAK ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ if ( ! expand_exit_something ())
+ error ("break statement not within loop or switch"); }
+ | CONTINUE ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ if (! expand_continue_loop (NULL_PTR))
+ error ("continue statement not within a loop"); }
+ | RETURN ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ c_expand_return (NULL_TREE); }
+ | RETURN expr ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ c_expand_return ($2); }
+ | ASM_KEYWORD maybe_type_qual '(' expr ')' ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ STRIP_NOPS ($4);
+ if ((TREE_CODE ($4) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND ($4, 0)) == STRING_CST)
+ || TREE_CODE ($4) == STRING_CST)
+ expand_asm ($4);
+ else
+ error ("argument of `asm' is not a constant string"); }
+ /* This is the case with just output operands. */
+ | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ')' ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ c_expand_asm_operands ($4, $6, NULL_TREE, NULL_TREE,
+ $2 == ridpointers[(int)RID_VOLATILE],
+ input_filename, lineno); }
+ /* This is the case with input operands as well. */
+ | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ':' asm_operands ')' ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ c_expand_asm_operands ($4, $6, $8, NULL_TREE,
+ $2 == ridpointers[(int)RID_VOLATILE],
+ input_filename, lineno); }
+ /* This is the case with clobbered registers as well. */
+ | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ':'
+ asm_operands ':' asm_clobbers ')' ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ c_expand_asm_operands ($4, $6, $8, $10,
+ $2 == ridpointers[(int)RID_VOLATILE],
+ input_filename, lineno); }
+ | GOTO identifier ';'
+ { tree decl;
+ stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ decl = lookup_label ($2);
+ if (decl != 0)
+ {
+ TREE_USED (decl) = 1;
+ expand_goto (decl);
+ }
+ }
+ | GOTO '*' expr ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ expand_computed_goto (convert (ptr_type_node, $3)); }
+ | ';'
+ ;
+
+all_iter_stmt:
+ all_iter_stmt_simple
+/* | all_iter_stmt_with_decl */
+ ;
+
+all_iter_stmt_simple:
+ FOR '(' primary ')'
+ {
+ /* The value returned by this action is */
+ /* 1 if everything is OK */
+ /* 0 in case of error or already bound iterator */
+
+ $<itype>$ = 0;
+ if (TREE_CODE ($3) != VAR_DECL)
+ error ("invalid `for (ITERATOR)' syntax");
+ else if (! ITERATOR_P ($3))
+ error ("`%s' is not an iterator",
+ IDENTIFIER_POINTER (DECL_NAME ($3)));
+ else if (ITERATOR_BOUND_P ($3))
+ error ("`for (%s)' inside expansion of same iterator",
+ IDENTIFIER_POINTER (DECL_NAME ($3)));
+ else
+ {
+ $<itype>$ = 1;
+ iterator_for_loop_start ($3);
+ }
+ }
+ lineno_labeled_stmt
+ {
+ if ($<itype>5)
+ iterator_for_loop_end ($3);
+ }
+
+/* This really should allow any kind of declaration,
+ for generality. Fix it before turning it back on.
+
+all_iter_stmt_with_decl:
+ FOR '(' ITERATOR pushlevel setspecs iterator_spec ')'
+ {
+*/ /* The value returned by this action is */
+ /* 1 if everything is OK */
+ /* 0 in case of error or already bound iterator */
+/*
+ iterator_for_loop_start ($6);
+ }
+ lineno_labeled_stmt
+ {
+ iterator_for_loop_end ($6);
+ emit_line_note (input_filename, lineno);
+ expand_end_bindings (getdecls (), 1, 0);
+ $<ttype>$ = poplevel (1, 1, 0);
+ if (yychar == CONSTANT || yychar == STRING)
+ pop_momentary_nofree ();
+ else
+ pop_momentary ();
+ }
+*/
+
+/* Any kind of label, including jump labels and case labels.
+ ANSI C accepts labels only before statements, but we allow them
+ also at the end of a compound statement. */
+
+label: CASE expr_no_commas ':'
+ { register tree value = check_case_value ($2);
+ register tree label
+ = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+
+ stmt_count++;
+
+ if (value != error_mark_node)
+ {
+ tree duplicate;
+ int success = pushcase (value, convert_and_check,
+ label, &duplicate);
+ if (success == 1)
+ error ("case label not within a switch statement");
+ else if (success == 2)
+ {
+ error ("duplicate case value");
+ error_with_decl (duplicate, "this is the first entry for that value");
+ }
+ else if (success == 3)
+ warning ("case value out of range");
+ else if (success == 5)
+ error ("case label within scope of cleanup or variable array");
+ }
+ position_after_white_space (); }
+ | CASE expr_no_commas ELLIPSIS expr_no_commas ':'
+ { register tree value1 = check_case_value ($2);
+ register tree value2 = check_case_value ($4);
+ register tree label
+ = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+
+ stmt_count++;
+
+ if (value1 != error_mark_node && value2 != error_mark_node)
+ {
+ tree duplicate;
+ int success = pushcase_range (value1, value2,
+ convert_and_check, label,
+ &duplicate);
+ if (success == 1)
+ error ("case label not within a switch statement");
+ else if (success == 2)
+ {
+ error ("duplicate case value");
+ error_with_decl (duplicate, "this is the first entry for that value");
+ }
+ else if (success == 3)
+ warning ("case value out of range");
+ else if (success == 4)
+ warning ("empty case range");
+ else if (success == 5)
+ error ("case label within scope of cleanup or variable array");
+ }
+ position_after_white_space (); }
+ | DEFAULT ':'
+ {
+ tree duplicate;
+ register tree label
+ = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+ int success = pushcase (NULL_TREE, 0, label, &duplicate);
+ stmt_count++;
+ if (success == 1)
+ error ("default label not within a switch statement");
+ else if (success == 2)
+ {
+ error ("multiple default labels in one switch");
+ error_with_decl (duplicate, "this is the first default label");
+ }
+ position_after_white_space (); }
+ | identifier ':'
+ { tree label = define_label (input_filename, lineno, $1);
+ stmt_count++;
+ emit_nop ();
+ if (label)
+ expand_label (label);
+ position_after_white_space (); }
+ ;
+
+/* Either a type-qualifier or nothing. First thing in an `asm' statement. */
+
+maybe_type_qual:
+ /* empty */
+ { emit_line_note (input_filename, lineno);
+ $$ = NULL_TREE; }
+ | TYPE_QUAL
+ { emit_line_note (input_filename, lineno); }
+ ;
+
+xexpr:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | expr
+ ;
+
+/* These are the operands other than the first string and colon
+ in asm ("addextend %2,%1": "=dm" (x), "0" (y), "g" (*x)) */
+asm_operands: /* empty */
+ { $$ = NULL_TREE; }
+ | nonnull_asm_operands
+ ;
+
+nonnull_asm_operands:
+ asm_operand
+ | nonnull_asm_operands ',' asm_operand
+ { $$ = chainon ($1, $3); }
+ ;
+
+asm_operand:
+ STRING '(' expr ')'
+ { $$ = build_tree_list ($1, $3); }
+ ;
+
+asm_clobbers:
+ string
+ { $$ = tree_cons (NULL_TREE, combine_strings ($1), NULL_TREE); }
+ | asm_clobbers ',' string
+ { $$ = tree_cons (NULL_TREE, combine_strings ($3), $1); }
+ ;
+
+/* This is what appears inside the parens in a function declarator.
+ Its value is a list of ..._TYPE nodes. */
+parmlist:
+ { pushlevel (0);
+ clear_parm_order ();
+ declare_parm_level (0); }
+ parmlist_1
+ { $$ = $2;
+ parmlist_tags_warning ();
+ poplevel (0, 0, 0); }
+ ;
+
+parmlist_1:
+ parmlist_2 ')'
+ | parms ';'
+ { tree parm;
+ if (pedantic)
+ pedwarn ("ANSI C forbids forward parameter declarations");
+ /* Mark the forward decls as such. */
+ for (parm = getdecls (); parm; parm = TREE_CHAIN (parm))
+ TREE_ASM_WRITTEN (parm) = 1;
+ clear_parm_order (); }
+ parmlist_1
+ { $$ = $4; }
+ | error ')'
+ { $$ = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE); }
+ ;
+
+/* This is what appears inside the parens in a function declarator.
+ Is value is represented in the format that grokdeclarator expects. */
+parmlist_2: /* empty */
+ { $$ = get_parm_info (0); }
+ | ELLIPSIS
+ { $$ = get_parm_info (0);
+ /* Gcc used to allow this as an extension. However, it does
+ not work for all targets, and thus has been disabled.
+ Also, since func (...) and func () are indistinguishable,
+ it caused problems with the code in expand_builtin which
+ tries to verify that BUILT_IN_NEXT_ARG is being used
+ correctly. */
+ error ("ANSI C requires a named argument before `...'");
+ }
+ | parms
+ { $$ = get_parm_info (1); }
+ | parms ',' ELLIPSIS
+ { $$ = get_parm_info (0); }
+ ;
+
+parms:
+ parm
+ { push_parm_decl ($1); }
+ | parms ',' parm
+ { push_parm_decl ($3); }
+ ;
+
+/* A single parameter declaration or parameter type name,
+ as found in a parmlist. */
+parm:
+ typed_declspecs setspecs parm_declarator maybe_attribute
+ { $$ = build_tree_list (build_tree_list (current_declspecs,
+ $3),
+ build_tree_list (prefix_attributes,
+ $4));
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs setspecs notype_declarator maybe_attribute
+ { $$ = build_tree_list (build_tree_list (current_declspecs,
+ $3),
+ build_tree_list (prefix_attributes,
+ $4));
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs setspecs absdcl maybe_attribute
+ { $$ = build_tree_list (build_tree_list (current_declspecs,
+ $3),
+ build_tree_list (prefix_attributes,
+ $4));
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods setspecs notype_declarator maybe_attribute
+ { $$ = build_tree_list (build_tree_list (current_declspecs,
+ $3),
+ build_tree_list (prefix_attributes,
+ $4));
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+
+ | declmods setspecs absdcl maybe_attribute
+ { $$ = build_tree_list (build_tree_list (current_declspecs,
+ $3),
+ build_tree_list (prefix_attributes,
+ $4));
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ ;
+
+/* This is used in a function definition
+ where either a parmlist or an identifier list is ok.
+ Its value is a list of ..._TYPE nodes or a list of identifiers. */
+parmlist_or_identifiers:
+ { pushlevel (0);
+ clear_parm_order ();
+ declare_parm_level (1); }
+ parmlist_or_identifiers_1
+ { $$ = $2;
+ parmlist_tags_warning ();
+ poplevel (0, 0, 0); }
+ ;
+
+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); }
+ ;
+
+/* A nonempty list of identifiers. */
+identifiers:
+ IDENTIFIER
+ { $$ = build_tree_list (NULL_TREE, $1); }
+ | identifiers ',' IDENTIFIER
+ { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); }
+ ;
+
+/* A nonempty list of identifiers, including typenames. */
+identifiers_or_typenames:
+ identifier
+ { $$ = build_tree_list (NULL_TREE, $1); }
+ | identifiers_or_typenames ',' identifier
+ { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); }
+ ;
+
+%%
diff --git a/gnu/usr.bin/gcc/cc1obj/objc-parse.y b/gnu/usr.bin/gcc/cc1obj/objc-parse.y
new file mode 100644
index 00000000000..81b2e85b538
--- /dev/null
+++ b/gnu/usr.bin/gcc/cc1obj/objc-parse.y
@@ -0,0 +1,2820 @@
+/* YACC parser for C syntax and for Objective C. -*-c-*-
+ Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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 Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* This file defines the grammar of C and that of Objective C.
+ ifobjc ... end ifobjc conditionals contain code for Objective C only.
+ ifc ... end ifc conditionals contain code for C only.
+ Sed commands in Makefile.in are used to convert this file into
+ c-parse.y and into objc-parse.y. */
+
+/* To whomever it may concern: I have heard that such a thing was once
+ written by AT&T, but I have never seen it. */
+
+%expect 48
+
+%{
+#include <stdio.h>
+#include <errno.h>
+#include <setjmp.h>
+
+#include "config.h"
+#include "tree.h"
+#include "input.h"
+#include "c-lex.h"
+#include "c-tree.h"
+#include "flags.h"
+
+#ifdef MULTIBYTE_CHARS
+#include <stdlib.h>
+#include <locale.h>
+#endif
+
+#include "objc-act.h"
+
+/* Since parsers are distinct for each language, put the language string
+ definition here. */
+char *language_string = "GNU Obj-C";
+
+#ifndef errno
+extern int errno;
+#endif
+
+void yyerror ();
+
+/* Like YYERROR but do call yyerror. */
+#define YYERROR1 { yyerror ("syntax error"); YYERROR; }
+
+/* Cause the `yydebug' variable to be defined. */
+#define YYDEBUG 1
+%}
+
+%start program
+
+%union {long itype; tree ttype; enum tree_code code;
+ char *filename; int lineno; int ends_in_label; }
+
+/* All identifiers that are not reserved words
+ and are not declared typedefs in the current block */
+%token IDENTIFIER
+
+/* All identifiers that are declared typedefs in the current block.
+ In some contexts, they are treated just like IDENTIFIER,
+ but they can also serve as typespecs in declarations. */
+%token TYPENAME
+
+/* Reserved words that specify storage class.
+ yylval contains an IDENTIFIER_NODE which indicates which one. */
+%token SCSPEC
+
+/* Reserved words that specify type.
+ yylval contains an IDENTIFIER_NODE which indicates which one. */
+%token TYPESPEC
+
+/* Reserved words that qualify type: "const" or "volatile".
+ yylval contains an IDENTIFIER_NODE which indicates which one. */
+%token TYPE_QUAL
+
+/* Character or numeric constants.
+ yylval is the node for the constant. */
+%token CONSTANT
+
+/* String constants in raw form.
+ yylval is a STRING_CST node. */
+%token STRING
+
+/* "...", used for functions with variable arglists. */
+%token ELLIPSIS
+
+/* the reserved words */
+/* SCO include files test "ASM", so use something else. */
+%token SIZEOF ENUM STRUCT UNION IF ELSE WHILE DO FOR SWITCH CASE DEFAULT
+%token BREAK CONTINUE RETURN GOTO ASM_KEYWORD TYPEOF ALIGNOF
+%token ATTRIBUTE EXTENSION LABEL
+%token REALPART IMAGPART
+
+/* Add precedence rules to solve dangling else s/r conflict */
+%nonassoc IF
+%nonassoc ELSE
+
+/* Define the operator tokens and their precedences.
+ The value is an integer because, if used, it is the tree code
+ to use in the expression made from the operator. */
+
+%right <code> ASSIGN '='
+%right <code> '?' ':'
+%left <code> OROR
+%left <code> ANDAND
+%left <code> '|'
+%left <code> '^'
+%left <code> '&'
+%left <code> EQCOMPARE
+%left <code> ARITHCOMPARE
+%left <code> LSHIFT RSHIFT
+%left <code> '+' '-'
+%left <code> '*' '/' '%'
+%right <code> UNARY PLUSPLUS MINUSMINUS
+%left HYPERUNARY
+%left <code> POINTSAT '.' '(' '['
+
+/* The Objective-C keywords. These are included in C and in
+ Objective C, so that the token codes are the same in both. */
+%token INTERFACE IMPLEMENTATION END SELECTOR DEFS ENCODE
+%token CLASSNAME PUBLIC PRIVATE PROTECTED PROTOCOL OBJECTNAME CLASS ALIAS
+
+/* Objective-C string constants in raw form.
+ yylval is an OBJC_STRING_CST node. */
+%token OBJC_STRING
+
+
+%type <code> unop
+
+%type <ttype> identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist exprlist
+%type <ttype> expr_no_commas cast_expr unary_expr primary string STRING
+%type <ttype> typed_declspecs reserved_declspecs
+%type <ttype> typed_typespecs reserved_typespecquals
+%type <ttype> declmods typespec typespecqual_reserved
+%type <ttype> SCSPEC TYPESPEC TYPE_QUAL nonempty_type_quals maybe_type_qual
+%type <ttype> initdecls notype_initdecls initdcl notype_initdcl
+%type <ttype> init maybeasm
+%type <ttype> asm_operands nonnull_asm_operands asm_operand asm_clobbers
+%type <ttype> maybe_attribute attributes attribute attribute_list attrib
+%type <ttype> any_word
+
+%type <ttype> compstmt
+
+%type <ttype> declarator
+%type <ttype> notype_declarator after_type_declarator
+%type <ttype> parm_declarator
+
+%type <ttype> structsp component_decl_list component_decl_list2
+%type <ttype> component_decl components component_declarator
+%type <ttype> enumlist enumerator
+%type <ttype> typename absdcl absdcl1 type_quals
+%type <ttype> xexpr parms parm identifiers
+
+%type <ttype> parmlist parmlist_1 parmlist_2
+%type <ttype> parmlist_or_identifiers parmlist_or_identifiers_1
+%type <ttype> identifiers_or_typenames
+
+%type <itype> setspecs
+
+%type <ends_in_label> lineno_stmt_or_label lineno_stmt_or_labels stmt_or_label
+
+%type <filename> save_filename
+%type <lineno> save_lineno
+
+/* the Objective-C nonterminals */
+
+%type <ttype> ivar_decl_list ivar_decls ivar_decl ivars ivar_declarator
+%type <ttype> methoddecl unaryselector keywordselector selector
+%type <ttype> keyworddecl receiver objcmessageexpr messageargs
+%type <ttype> keywordexpr keywordarglist keywordarg
+%type <ttype> myparms myparm optparmlist reservedwords objcselectorexpr
+%type <ttype> selectorarg keywordnamelist keywordname objcencodeexpr
+%type <ttype> objc_string protocolrefs identifier_list objcprotocolexpr
+%type <ttype> CLASSNAME OBJC_STRING OBJECTNAME
+
+%{
+/* Number of statements (loosely speaking) seen so far. */
+static int stmt_count;
+
+/* Input file and line number of the end of the body of last simple_if;
+ used by the stmt-rule immediately after simple_if returns. */
+static char *if_stmt_file;
+static int if_stmt_line;
+
+/* List of types and structure classes of the current declaration. */
+static tree current_declspecs;
+static tree prefix_attributes = NULL_TREE;
+
+/* Stack of saved values of current_declspecs and prefix_attributes. */
+static tree declspec_stack;
+
+/* 1 if we explained undeclared var errors. */
+static int undeclared_variable_notice;
+
+/* Objective-C specific information */
+
+tree objc_interface_context;
+tree objc_implementation_context;
+tree objc_method_context;
+tree objc_ivar_chain;
+tree objc_ivar_context;
+enum tree_code objc_inherit_code;
+int objc_receiver_context;
+int objc_public_flag;
+
+
+/* Tell yyparse how to print a token's value, if yydebug is set. */
+
+#define YYPRINT(FILE,YYCHAR,YYLVAL) yyprint(FILE,YYCHAR,YYLVAL)
+extern void yyprint ();
+%}
+
+%%
+program: /* empty */
+ { if (pedantic)
+ pedwarn ("ANSI C forbids an empty source file");
+ finish_file ();
+ }
+ | extdefs
+ {
+ /* In case there were missing closebraces,
+ get us back to the global binding level. */
+ while (! global_bindings_p ())
+ poplevel (0, 0, 0);
+ finish_file ();
+ }
+ ;
+
+/* 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. */
+
+extdefs:
+ {$<ttype>$ = NULL_TREE; } extdef
+ | extdefs {$<ttype>$ = NULL_TREE; } extdef
+ ;
+
+extdef:
+ fndef
+ | datadef
+ | objcdef
+ | ASM_KEYWORD '(' expr ')' ';'
+ { STRIP_NOPS ($3);
+ if ((TREE_CODE ($3) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND ($3, 0)) == STRING_CST)
+ || TREE_CODE ($3) == STRING_CST)
+ assemble_asm ($3);
+ else
+ error ("argument of `asm' is not a constant string"); }
+ ;
+
+datadef:
+ setspecs notype_initdecls ';'
+ { if (pedantic)
+ error ("ANSI C forbids data definition with no type or storage class");
+ else if (!flag_traditional)
+ warning ("data definition has no type or storage class");
+
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($1); }
+ | declmods setspecs notype_initdecls ';'
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs setspecs initdecls ';'
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods ';'
+ { pedwarn ("empty declaration"); }
+ | typed_declspecs ';'
+ { shadow_tag ($1); }
+ | error ';'
+ | error '}'
+ | ';'
+ { if (pedantic)
+ pedwarn ("ANSI C does not allow extra `;' outside of a function"); }
+ ;
+
+fndef:
+ typed_declspecs setspecs declarator
+ { if (! start_function ($1, $3, prefix_attributes,
+ NULL_TREE, 0))
+ YYERROR1;
+ reinit_parse_for_function (); }
+ xdecls
+ { store_parm_decls (); }
+ compstmt_or_error
+ { finish_function (0);
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs setspecs declarator error
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods setspecs notype_declarator
+ { if (! start_function ($1, $3, prefix_attributes,
+ NULL_TREE, 0))
+ YYERROR1;
+ reinit_parse_for_function (); }
+ xdecls
+ { store_parm_decls (); }
+ compstmt_or_error
+ { finish_function (0);
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods setspecs notype_declarator error
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | setspecs notype_declarator
+ { if (! start_function (NULL_TREE, $2,
+ prefix_attributes, NULL_TREE, 0))
+ YYERROR1;
+ reinit_parse_for_function (); }
+ xdecls
+ { store_parm_decls (); }
+ compstmt_or_error
+ { finish_function (0);
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($1); }
+ | setspecs notype_declarator error
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($1); }
+ ;
+
+identifier:
+ IDENTIFIER
+ | TYPENAME
+ | OBJECTNAME
+ | CLASSNAME
+ ;
+
+unop: '&'
+ { $$ = ADDR_EXPR; }
+ | '-'
+ { $$ = NEGATE_EXPR; }
+ | '+'
+ { $$ = CONVERT_EXPR; }
+ | PLUSPLUS
+ { $$ = PREINCREMENT_EXPR; }
+ | MINUSMINUS
+ { $$ = PREDECREMENT_EXPR; }
+ | '~'
+ { $$ = BIT_NOT_EXPR; }
+ | '!'
+ { $$ = TRUTH_NOT_EXPR; }
+ ;
+
+expr: nonnull_exprlist
+ { $$ = build_compound_expr ($1); }
+ ;
+
+exprlist:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | nonnull_exprlist
+ ;
+
+nonnull_exprlist:
+ expr_no_commas
+ { $$ = build_tree_list (NULL_TREE, $1); }
+ | nonnull_exprlist ',' expr_no_commas
+ { chainon ($1, build_tree_list (NULL_TREE, $3)); }
+ ;
+
+unary_expr:
+ primary
+ | '*' cast_expr %prec UNARY
+ { $$ = build_indirect_ref ($2, "unary *"); }
+ /* __extension__ turns off -pedantic for following primary. */
+ | EXTENSION
+ { $<itype>1 = pedantic;
+ pedantic = 0; }
+ cast_expr %prec UNARY
+ { $$ = $3;
+ pedantic = $<itype>1; }
+ | unop cast_expr %prec UNARY
+ { $$ = build_unary_op ($1, $2, 0);
+ overflow_warning ($$); }
+ /* Refer to the address of a label as a pointer. */
+ | ANDAND identifier
+ { tree label = lookup_label ($2);
+ if (pedantic)
+ pedwarn ("ANSI C forbids `&&'");
+ if (label == 0)
+ $$ = null_pointer_node;
+ else
+ {
+ TREE_USED (label) = 1;
+ $$ = build1 (ADDR_EXPR, ptr_type_node, label);
+ TREE_CONSTANT ($$) = 1;
+ }
+ }
+/* This seems to be impossible on some machines, so let's turn it off.
+ You can use __builtin_next_arg to find the anonymous stack args.
+ | '&' ELLIPSIS
+ { tree types = TYPE_ARG_TYPES (TREE_TYPE (current_function_decl));
+ $$ = error_mark_node;
+ if (TREE_VALUE (tree_last (types)) == void_type_node)
+ error ("`&...' used in function with fixed number of arguments");
+ else
+ {
+ if (pedantic)
+ pedwarn ("ANSI C forbids `&...'");
+ $$ = tree_last (DECL_ARGUMENTS (current_function_decl));
+ $$ = build_unary_op (ADDR_EXPR, $$, 0);
+ } }
+*/
+ | SIZEOF unary_expr %prec UNARY
+ { if (TREE_CODE ($2) == COMPONENT_REF
+ && DECL_BIT_FIELD (TREE_OPERAND ($2, 1)))
+ error ("`sizeof' applied to a bit-field");
+ $$ = c_sizeof (TREE_TYPE ($2)); }
+ | SIZEOF '(' typename ')' %prec HYPERUNARY
+ { $$ = c_sizeof (groktypename ($3)); }
+ | ALIGNOF unary_expr %prec UNARY
+ { $$ = c_alignof_expr ($2); }
+ | ALIGNOF '(' typename ')' %prec HYPERUNARY
+ { $$ = c_alignof (groktypename ($3)); }
+ | REALPART cast_expr %prec UNARY
+ { $$ = build_unary_op (REALPART_EXPR, $2, 0); }
+ | IMAGPART cast_expr %prec UNARY
+ { $$ = build_unary_op (IMAGPART_EXPR, $2, 0); }
+ ;
+
+cast_expr:
+ unary_expr
+ | '(' typename ')' cast_expr %prec UNARY
+ { tree type = groktypename ($2);
+ $$ = build_c_cast (type, $4); }
+ | '(' typename ')' '{'
+ { start_init (NULL_TREE, NULL, 0);
+ $2 = groktypename ($2);
+ really_start_incremental_init ($2); }
+ initlist_maybe_comma '}' %prec UNARY
+ { char *name;
+ tree result = pop_init_level (0);
+ tree type = $2;
+ finish_init ();
+
+ if (pedantic)
+ pedwarn ("ANSI C forbids constructor expressions");
+ if (TYPE_NAME (type) != 0)
+ {
+ if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
+ name = IDENTIFIER_POINTER (TYPE_NAME (type));
+ else
+ name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
+ }
+ else
+ name = "";
+ $$ = result;
+ if (TREE_CODE (type) == ARRAY_TYPE && TYPE_SIZE (type) == 0)
+ {
+ int failure = complete_array_type (type, $$, 1);
+ if (failure)
+ abort ();
+ }
+ }
+ ;
+
+expr_no_commas:
+ cast_expr
+ | expr_no_commas '+' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '-' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '*' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '/' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '%' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas LSHIFT expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas RSHIFT expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas ARITHCOMPARE expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas EQCOMPARE expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '&' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '|' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '^' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas ANDAND expr_no_commas
+ { $$ = parser_build_binary_op (TRUTH_ANDIF_EXPR, $1, $3); }
+ | expr_no_commas OROR expr_no_commas
+ { $$ = parser_build_binary_op (TRUTH_ORIF_EXPR, $1, $3); }
+ | expr_no_commas '?' xexpr ':' expr_no_commas
+ { $$ = build_conditional_expr ($1, $3, $5); }
+ | expr_no_commas '=' expr_no_commas
+ { $$ = build_modify_expr ($1, NOP_EXPR, $3);
+ C_SET_EXP_ORIGINAL_CODE ($$, MODIFY_EXPR); }
+ | expr_no_commas ASSIGN expr_no_commas
+ { $$ = build_modify_expr ($1, $2, $3);
+ /* This inhibits warnings in truthvalue_conversion. */
+ C_SET_EXP_ORIGINAL_CODE ($$, ERROR_MARK); }
+ ;
+
+primary:
+ IDENTIFIER
+ {
+ $$ = lastiddecl;
+ if (!$$ || $$ == error_mark_node)
+ {
+ if (yychar == YYEMPTY)
+ yychar = YYLEX;
+ if (yychar == '(')
+ {
+ tree decl;
+
+ if (objc_receiver_context
+ && ! (objc_receiver_context
+ && strcmp (IDENTIFIER_POINTER ($1), "super")))
+ /* we have a message to super */
+ $$ = get_super_receiver ();
+ else if (objc_method_context
+ && (decl = is_ivar (objc_ivar_chain, $1)))
+ {
+ if (is_private (decl))
+ $$ = error_mark_node;
+ else
+ $$ = build_ivar_reference ($1);
+ }
+ else
+ {
+ /* Ordinary implicit function declaration. */
+ $$ = implicitly_declare ($1);
+ assemble_external ($$);
+ TREE_USED ($$) = 1;
+ }
+ }
+ else if (current_function_decl == 0)
+ {
+ error ("`%s' undeclared here (not in a function)",
+ IDENTIFIER_POINTER ($1));
+ $$ = error_mark_node;
+ }
+ else
+ {
+ tree decl;
+
+ if (objc_receiver_context
+ && ! strcmp (IDENTIFIER_POINTER ($1), "super"))
+ /* we have a message to super */
+ $$ = get_super_receiver ();
+ else if (objc_method_context
+ && (decl = is_ivar (objc_ivar_chain, $1)))
+ {
+ if (is_private (decl))
+ $$ = error_mark_node;
+ else
+ $$ = build_ivar_reference ($1);
+ }
+ else
+ {
+ if (IDENTIFIER_GLOBAL_VALUE ($1) != error_mark_node
+ || IDENTIFIER_ERROR_LOCUS ($1) != current_function_decl)
+ {
+ error ("`%s' undeclared (first use this function)",
+ IDENTIFIER_POINTER ($1));
+
+ if (! undeclared_variable_notice)
+ {
+ error ("(Each undeclared identifier is reported only once");
+ error ("for each function it appears in.)");
+ undeclared_variable_notice = 1;
+ }
+ }
+ $$ = error_mark_node;
+ /* Prevent repeated error messages. */
+ IDENTIFIER_GLOBAL_VALUE ($1) = error_mark_node;
+ IDENTIFIER_ERROR_LOCUS ($1) = current_function_decl;
+ }
+ }
+ }
+ else if (TREE_TYPE ($$) == error_mark_node)
+ $$ = error_mark_node;
+ else if (C_DECL_ANTICIPATED ($$))
+ {
+ /* The first time we see a build-in function used,
+ if it has not been declared. */
+ C_DECL_ANTICIPATED ($$) = 0;
+ if (yychar == YYEMPTY)
+ yychar = YYLEX;
+ if (yychar == '(')
+ {
+ /* Omit the implicit declaration we
+ would ordinarily do, so we don't lose
+ the actual built in type.
+ But print a diagnostic for the mismatch. */
+ if (objc_method_context
+ && is_ivar (objc_ivar_chain, $1))
+ error ("Instance variable `%s' implicitly declared as function",
+ IDENTIFIER_POINTER (DECL_NAME ($$)));
+ else
+ if (TREE_CODE ($$) != FUNCTION_DECL)
+ error ("`%s' implicitly declared as function",
+ IDENTIFIER_POINTER (DECL_NAME ($$)));
+ else if ((TYPE_MODE (TREE_TYPE (TREE_TYPE ($$)))
+ != TYPE_MODE (integer_type_node))
+ && (TREE_TYPE (TREE_TYPE ($$))
+ != void_type_node))
+ pedwarn ("type mismatch in implicit declaration for built-in function `%s'",
+ IDENTIFIER_POINTER (DECL_NAME ($$)));
+ /* If it really returns void, change that to int. */
+ if (TREE_TYPE (TREE_TYPE ($$)) == void_type_node)
+ TREE_TYPE ($$)
+ = build_function_type (integer_type_node,
+ TYPE_ARG_TYPES (TREE_TYPE ($$)));
+ }
+ else
+ pedwarn ("built-in function `%s' used without declaration",
+ IDENTIFIER_POINTER (DECL_NAME ($$)));
+
+ /* Do what we would ordinarily do when a fn is used. */
+ assemble_external ($$);
+ TREE_USED ($$) = 1;
+ }
+ else
+ {
+ assemble_external ($$);
+ TREE_USED ($$) = 1;
+ /* we have a definition - still check if iVariable */
+
+ if (!objc_receiver_context
+ || (objc_receiver_context
+ && strcmp (IDENTIFIER_POINTER ($1), "super")))
+ {
+ tree decl;
+
+ if (objc_method_context
+ && (decl = is_ivar (objc_ivar_chain, $1)))
+ {
+ if (IDENTIFIER_LOCAL_VALUE ($1))
+ warning ("local declaration of `%s' hides instance variable",
+ IDENTIFIER_POINTER ($1));
+ else
+ {
+ if (is_private (decl))
+ $$ = error_mark_node;
+ else
+ $$ = build_ivar_reference ($1);
+ }
+ }
+ }
+ else /* we have a message to super */
+ $$ = get_super_receiver ();
+ }
+
+ if (TREE_CODE ($$) == CONST_DECL)
+ {
+ $$ = DECL_INITIAL ($$);
+ /* This is to prevent an enum whose value is 0
+ from being considered a null pointer constant. */
+ $$ = build1 (NOP_EXPR, TREE_TYPE ($$), $$);
+ TREE_CONSTANT ($$) = 1;
+ }
+ }
+ | CONSTANT
+ | string
+ { $$ = combine_strings ($1); }
+ | '(' expr ')'
+ { char class = TREE_CODE_CLASS (TREE_CODE ($2));
+ if (class == 'e' || class == '1'
+ || class == '2' || class == '<')
+ C_SET_EXP_ORIGINAL_CODE ($2, ERROR_MARK);
+ $$ = $2; }
+ | '(' error ')'
+ { $$ = error_mark_node; }
+ | '('
+ { if (current_function_decl == 0)
+ {
+ error ("braced-group within expression allowed only inside a function");
+ YYERROR;
+ }
+ /* We must force a BLOCK for this level
+ so that, if it is not expanded later,
+ there is a way to turn off the entire subtree of blocks
+ that are contained in it. */
+ keep_next_level ();
+ push_iterator_stack ();
+ push_label_level ();
+ $<ttype>$ = expand_start_stmt_expr (); }
+ compstmt ')'
+ { tree rtl_exp;
+ if (pedantic)
+ pedwarn ("ANSI C forbids braced-groups within expressions");
+ pop_iterator_stack ();
+ pop_label_level ();
+ rtl_exp = expand_end_stmt_expr ($<ttype>2);
+ /* The statements have side effects, so the group does. */
+ TREE_SIDE_EFFECTS (rtl_exp) = 1;
+
+ if (TREE_CODE ($3) == BLOCK)
+ {
+ /* Make a BIND_EXPR for the BLOCK already made. */
+ $$ = build (BIND_EXPR, TREE_TYPE (rtl_exp),
+ NULL_TREE, rtl_exp, $3);
+ /* Remove the block from the tree at this point.
+ It gets put back at the proper place
+ when the BIND_EXPR is expanded. */
+ delete_block ($3);
+ }
+ else
+ $$ = $3;
+ }
+ | primary '(' exprlist ')' %prec '.'
+ { $$ = build_function_call ($1, $3); }
+ | primary '[' expr ']' %prec '.'
+ { $$ = build_array_ref ($1, $3); }
+ | primary '.' identifier
+ {
+ if (doing_objc_thang)
+ {
+ if (is_public ($1, $3))
+ $$ = build_component_ref ($1, $3);
+ else
+ $$ = error_mark_node;
+ }
+ else
+ $$ = build_component_ref ($1, $3);
+ }
+ | primary POINTSAT identifier
+ {
+ tree expr = build_indirect_ref ($1, "->");
+
+ if (doing_objc_thang)
+ {
+ if (is_public (expr, $3))
+ $$ = build_component_ref (expr, $3);
+ else
+ $$ = error_mark_node;
+ }
+ else
+ $$ = build_component_ref (expr, $3);
+ }
+ | primary PLUSPLUS
+ { $$ = build_unary_op (POSTINCREMENT_EXPR, $1, 0); }
+ | primary MINUSMINUS
+ { $$ = build_unary_op (POSTDECREMENT_EXPR, $1, 0); }
+ | objcmessageexpr
+ { $$ = build_message_expr ($1); }
+ | objcselectorexpr
+ { $$ = build_selector_expr ($1); }
+ | objcprotocolexpr
+ { $$ = build_protocol_expr ($1); }
+ | objcencodeexpr
+ { $$ = build_encode_expr ($1); }
+ | objc_string
+ { $$ = build_objc_string_object ($1); }
+ ;
+
+/* Produces a STRING_CST with perhaps more STRING_CSTs chained onto it. */
+string:
+ STRING
+ | string STRING
+ { $$ = chainon ($1, $2); }
+ ;
+
+/* Produces an OBJC_STRING_CST with perhaps more OBJC_STRING_CSTs chained
+ onto it. */
+objc_string:
+ OBJC_STRING
+ | objc_string OBJC_STRING
+ { $$ = chainon ($1, $2); }
+ ;
+
+xdecls:
+ /* empty */
+ | datadecls
+ | datadecls ELLIPSIS
+ /* ... is used here to indicate a varargs function. */
+ { c_mark_varargs ();
+ if (pedantic)
+ pedwarn ("ANSI C does not permit use of `varargs.h'"); }
+ ;
+
+/* The following are analogous to lineno_decl, decls and decl
+ except that they do not allow nested functions.
+ They are used for old-style parm decls. */
+lineno_datadecl:
+ save_filename save_lineno datadecl
+ { }
+ ;
+
+datadecls:
+ lineno_datadecl
+ | errstmt
+ | datadecls lineno_datadecl
+ | lineno_datadecl errstmt
+ ;
+
+datadecl:
+ typed_declspecs setspecs initdecls ';'
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods setspecs notype_initdecls ';'
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs ';'
+ { shadow_tag_warned ($1, 1);
+ pedwarn ("empty declaration"); }
+ | declmods ';'
+ { pedwarn ("empty declaration"); }
+ ;
+
+/* This combination which saves a lineno before a decl
+ is the normal thing to use, rather than decl itself.
+ This is to avoid shift/reduce conflicts in contexts
+ where statement labels are allowed. */
+lineno_decl:
+ save_filename save_lineno decl
+ { }
+ ;
+
+decls:
+ lineno_decl
+ | errstmt
+ | decls lineno_decl
+ | lineno_decl errstmt
+ ;
+
+/* records the type and storage class specs to use for processing
+ the declarators that follow.
+ Maintains a stack of outer-level values of current_declspecs,
+ for the sake of parm declarations nested in function declarators. */
+setspecs: /* empty */
+ { $$ = suspend_momentary ();
+ pending_xref_error ();
+ declspec_stack = tree_cons (prefix_attributes,
+ current_declspecs,
+ declspec_stack);
+ current_declspecs = $<ttype>0;
+ prefix_attributes = NULL_TREE; }
+ ;
+
+setattrs: /* empty */
+ { prefix_attributes = chainon (prefix_attributes, $<ttype>0); }
+ ;
+
+decl:
+ typed_declspecs setspecs initdecls ';'
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods setspecs notype_initdecls ';'
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs setspecs nested_function
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods setspecs notype_nested_function
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs ';'
+ { shadow_tag ($1); }
+ | declmods ';'
+ { pedwarn ("empty declaration"); }
+ ;
+
+/* 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. */
+
+typed_declspecs:
+ typespec reserved_declspecs
+ { $$ = tree_cons (NULL_TREE, $1, $2); }
+ | declmods typespec reserved_declspecs
+ { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); }
+ ;
+
+reserved_declspecs: /* empty */
+ { $$ = NULL_TREE; }
+ | reserved_declspecs typespecqual_reserved
+ { $$ = tree_cons (NULL_TREE, $2, $1); }
+ | reserved_declspecs SCSPEC
+ { if (extra_warnings)
+ warning ("`%s' is not at beginning of declaration",
+ IDENTIFIER_POINTER ($2));
+ $$ = tree_cons (NULL_TREE, $2, $1); }
+ ;
+
+/* List of just storage classes and type modifiers.
+ A declaration can start with just this, but then it cannot be used
+ to redeclare a typedef-name. */
+
+declmods:
+ TYPE_QUAL
+ { $$ = tree_cons (NULL_TREE, $1, NULL_TREE);
+ TREE_STATIC ($$) = 1; }
+ | SCSPEC
+ { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); }
+ | declmods TYPE_QUAL
+ { $$ = tree_cons (NULL_TREE, $2, $1);
+ TREE_STATIC ($$) = 1; }
+ | declmods 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); }
+ ;
+
+
+/* Used instead of declspecs where storage classes are not allowed
+ (that is, for typenames and structure components).
+ Don't accept a typedef-name if anything but a modifier precedes it. */
+
+typed_typespecs:
+ typespec reserved_typespecquals
+ { $$ = tree_cons (NULL_TREE, $1, $2); }
+ | nonempty_type_quals typespec reserved_typespecquals
+ { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); }
+ ;
+
+reserved_typespecquals: /* empty */
+ { $$ = NULL_TREE; }
+ | reserved_typespecquals typespecqual_reserved
+ { $$ = tree_cons (NULL_TREE, $2, $1); }
+ ;
+
+/* A typespec (but not a type qualifier).
+ Once we have seen one of these in a declaration,
+ if a typedef name appears then it is being redeclared. */
+
+typespec: TYPESPEC
+ | structsp
+ | TYPENAME
+ { /* For a typedef name, record the meaning, not the name.
+ In case of `foo foo, bar;'. */
+ $$ = lookup_name ($1); }
+ | CLASSNAME protocolrefs
+ { $$ = get_static_reference ($1, $2); }
+ | OBJECTNAME protocolrefs
+ { $$ = get_object_reference ($2); }
+ | TYPEOF '(' expr ')'
+ { $$ = TREE_TYPE ($3); }
+ | TYPEOF '(' typename ')'
+ { $$ = groktypename ($3); }
+ ;
+
+/* A typespec that is a reserved word, or a type qualifier. */
+
+typespecqual_reserved: TYPESPEC
+ | TYPE_QUAL
+ | structsp
+ ;
+
+initdecls:
+ initdcl
+ | initdecls ',' initdcl
+ ;
+
+notype_initdecls:
+ notype_initdcl
+ | notype_initdecls ',' initdcl
+ ;
+
+maybeasm:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | ASM_KEYWORD '(' string ')'
+ { if (TREE_CHAIN ($3)) $3 = combine_strings ($3);
+ $$ = $3;
+ }
+ ;
+
+initdcl:
+ declarator maybeasm maybe_attribute '='
+ { $<ttype>$ = start_decl ($1, current_declspecs, 1,
+ $3, prefix_attributes);
+ start_init ($<ttype>$, $2, global_bindings_p ()); }
+ init
+/* Note how the declaration of the variable is in effect while its init is parsed! */
+ { finish_init ();
+ finish_decl ($<ttype>5, $6, $2); }
+ | declarator maybeasm maybe_attribute
+ { tree d = start_decl ($1, current_declspecs, 0,
+ $3, prefix_attributes);
+ finish_decl (d, NULL_TREE, $2);
+ }
+ ;
+
+notype_initdcl:
+ notype_declarator maybeasm maybe_attribute '='
+ { $<ttype>$ = start_decl ($1, current_declspecs, 1,
+ $3, prefix_attributes);
+ start_init ($<ttype>$, $2, global_bindings_p ()); }
+ init
+/* Note how the declaration of the variable is in effect while its init is parsed! */
+ { finish_init ();
+ decl_attributes ($<ttype>5, $3, prefix_attributes);
+ finish_decl ($<ttype>5, $6, $2); }
+ | notype_declarator maybeasm maybe_attribute
+ { tree d = start_decl ($1, current_declspecs, 0,
+ $3, prefix_attributes);
+ finish_decl (d, NULL_TREE, $2); }
+ ;
+/* the * rules are dummies to accept the Apollo extended syntax
+ so that the header files compile. */
+maybe_attribute:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | attributes
+ { $$ = $1; }
+ ;
+
+attributes:
+ attribute
+ { $$ = $1; }
+ | attributes attribute
+ { $$ = chainon ($1, $2); }
+ ;
+
+attribute:
+ ATTRIBUTE '(' '(' attribute_list ')' ')'
+ { $$ = $4; }
+ ;
+
+attribute_list:
+ attrib
+ { $$ = $1; }
+ | attribute_list ',' attrib
+ { $$ = chainon ($1, $3); }
+ ;
+
+attrib:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | any_word
+ { $$ = build_tree_list ($1, NULL_TREE); }
+ | any_word '(' IDENTIFIER ')'
+ { $$ = build_tree_list ($1, build_tree_list (NULL_TREE, $3)); }
+ | any_word '(' IDENTIFIER ',' nonnull_exprlist ')'
+ { $$ = build_tree_list ($1, tree_cons (NULL_TREE, $3, $5)); }
+ | any_word '(' exprlist ')'
+ { $$ = build_tree_list ($1, $3); }
+ ;
+
+/* This still leaves out most reserved keywords,
+ shouldn't we include them? */
+
+any_word:
+ identifier
+ | SCSPEC
+ | TYPESPEC
+ | TYPE_QUAL
+ ;
+
+/* Initializers. `init' is the entry point. */
+
+init:
+ expr_no_commas
+ | '{'
+ { really_start_incremental_init (NULL_TREE);
+ /* Note that the call to clear_momentary
+ is in process_init_element. */
+ push_momentary (); }
+ initlist_maybe_comma '}'
+ { $$ = pop_init_level (0);
+ if ($$ == error_mark_node
+ && ! (yychar == STRING || yychar == CONSTANT))
+ pop_momentary ();
+ else
+ pop_momentary_nofree (); }
+
+ | error
+ { $$ = error_mark_node; }
+ ;
+
+/* `initlist_maybe_comma' is the guts of an initializer in braces. */
+initlist_maybe_comma:
+ /* empty */
+ { if (pedantic)
+ pedwarn ("ANSI C forbids empty initializer braces"); }
+ | initlist1 maybecomma
+ ;
+
+initlist1:
+ initelt
+ | initlist1 ',' initelt
+ ;
+
+/* `initelt' is a single element of an initializer.
+ It may use braces. */
+initelt:
+ expr_no_commas
+ { process_init_element ($1); }
+ | '{'
+ { push_init_level (0); }
+ initlist_maybe_comma '}'
+ { process_init_element (pop_init_level (0)); }
+ | error
+ /* These are for labeled elements. The syntax for an array element
+ initializer conflicts with the syntax for an Objective-C message,
+ so don't include these productions in the Objective-C grammar. */
+ | identifier ':'
+ { set_init_label ($1); }
+ initelt
+ | '.' identifier '='
+ { set_init_label ($2); }
+ initelt
+ ;
+
+nested_function:
+ declarator
+ { push_c_function_context ();
+ if (! start_function (current_declspecs, $1,
+ prefix_attributes, NULL_TREE, 1))
+ {
+ pop_c_function_context ();
+ YYERROR1;
+ }
+ reinit_parse_for_function (); }
+ xdecls
+ { store_parm_decls (); }
+/* This used to use compstmt_or_error.
+ That caused a bug with input `f(g) int g {}',
+ where the use of YYERROR1 above caused an error
+ which then was handled by compstmt_or_error.
+ There followed a repeated execution of that same rule,
+ which called YYERROR1 again, and so on. */
+ compstmt
+ { finish_function (1);
+ pop_c_function_context (); }
+ ;
+
+notype_nested_function:
+ notype_declarator
+ { push_c_function_context ();
+ if (! start_function (current_declspecs, $1,
+ prefix_attributes, NULL_TREE, 1))
+ {
+ pop_c_function_context ();
+ YYERROR1;
+ }
+ reinit_parse_for_function (); }
+ xdecls
+ { store_parm_decls (); }
+/* This used to use compstmt_or_error.
+ That caused a bug with input `f(g) int g {}',
+ where the use of YYERROR1 above caused an error
+ which then was handled by compstmt_or_error.
+ There followed a repeated execution of that same rule,
+ which called YYERROR1 again, and so on. */
+ compstmt
+ { finish_function (1);
+ pop_c_function_context (); }
+ ;
+
+/* Any kind of declarator (thus, all declarators allowed
+ after an explicit typespec). */
+
+declarator:
+ after_type_declarator
+ | notype_declarator
+ ;
+
+/* A declarator that is allowed only after an explicit typespec. */
+
+after_type_declarator:
+ '(' after_type_declarator ')'
+ { $$ = $2; }
+ | after_type_declarator '(' parmlist_or_identifiers %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
+/* | after_type_declarator '(' error ')' %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE);
+ poplevel (0, 0, 0); } */
+ | after_type_declarator '[' expr ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, $3); }
+ | after_type_declarator '[' ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
+ | '*' type_quals after_type_declarator %prec UNARY
+ { $$ = make_pointer_declarator ($2, $3); }
+ | attributes setattrs after_type_declarator
+ { $$ = $3; }
+ | TYPENAME
+ | OBJECTNAME
+ ;
+
+/* Kinds of declarator that can appear in a parameter list
+ in addition to notype_declarator. This is like after_type_declarator
+ but does not allow a typedef name in parentheses as an identifier
+ (because it would conflict with a function with that typedef as arg). */
+
+parm_declarator:
+ parm_declarator '(' parmlist_or_identifiers %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
+/* | parm_declarator '(' error ')' %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE);
+ poplevel (0, 0, 0); } */
+ | parm_declarator '[' expr ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, $3); }
+ | parm_declarator '[' ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
+ | '*' type_quals parm_declarator %prec UNARY
+ { $$ = make_pointer_declarator ($2, $3); }
+ | attributes setattrs parm_declarator
+ { $$ = $3; }
+ | TYPENAME
+ ;
+
+/* A declarator allowed whether or not there has been
+ an explicit typespec. These cannot redeclare a typedef-name. */
+
+notype_declarator:
+ notype_declarator '(' parmlist_or_identifiers %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
+/* | notype_declarator '(' error ')' %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE);
+ poplevel (0, 0, 0); } */
+ | '(' notype_declarator ')'
+ { $$ = $2; }
+ | '*' type_quals notype_declarator %prec UNARY
+ { $$ = make_pointer_declarator ($2, $3); }
+ | notype_declarator '[' expr ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, $3); }
+ | notype_declarator '[' ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
+ | attributes setattrs notype_declarator
+ { $$ = $3; }
+ | IDENTIFIER
+ ;
+
+structsp:
+ STRUCT identifier '{'
+ { $$ = start_struct (RECORD_TYPE, $2);
+ /* Start scope of tag before parsing components. */
+ }
+ component_decl_list '}' maybe_attribute
+ { $$ = finish_struct ($<ttype>4, $5, $7); }
+ | STRUCT '{' component_decl_list '}' maybe_attribute
+ { $$ = finish_struct (start_struct (RECORD_TYPE, NULL_TREE),
+ $3, $5);
+ }
+ | STRUCT identifier
+ { $$ = xref_tag (RECORD_TYPE, $2); }
+ | UNION identifier '{'
+ { $$ = start_struct (UNION_TYPE, $2); }
+ component_decl_list '}' maybe_attribute
+ { $$ = finish_struct ($<ttype>4, $5, $7); }
+ | UNION '{' component_decl_list '}' maybe_attribute
+ { $$ = finish_struct (start_struct (UNION_TYPE, NULL_TREE),
+ $3, $5);
+ }
+ | UNION identifier
+ { $$ = xref_tag (UNION_TYPE, $2); }
+ | ENUM identifier '{'
+ { $<itype>3 = suspend_momentary ();
+ $$ = start_enum ($2); }
+ enumlist maybecomma_warn '}' maybe_attribute
+ { $$ = finish_enum ($<ttype>4, nreverse ($5), $8);
+ resume_momentary ($<itype>3); }
+ | ENUM '{'
+ { $<itype>2 = suspend_momentary ();
+ $$ = start_enum (NULL_TREE); }
+ enumlist maybecomma_warn '}' maybe_attribute
+ { $$ = finish_enum ($<ttype>3, nreverse ($4), $7);
+ resume_momentary ($<itype>2); }
+ | ENUM identifier
+ { $$ = xref_tag (ENUMERAL_TYPE, $2); }
+ ;
+
+maybecomma:
+ /* empty */
+ | ','
+ ;
+
+maybecomma_warn:
+ /* empty */
+ | ','
+ { if (pedantic) pedwarn ("comma at end of enumerator list"); }
+ ;
+
+component_decl_list:
+ component_decl_list2
+ { $$ = $1; }
+ | component_decl_list2 component_decl
+ { $$ = chainon ($1, $2);
+ pedwarn ("no semicolon at end of struct or union"); }
+ ;
+
+component_decl_list2: /* empty */
+ { $$ = NULL_TREE; }
+ | component_decl_list2 component_decl ';'
+ { $$ = chainon ($1, $2); }
+ | component_decl_list2 ';'
+ { if (pedantic)
+ pedwarn ("extra semicolon in struct or union specified"); }
+ /* foo(sizeof(struct{ @defs(ClassName)})); */
+ | DEFS '(' CLASSNAME ')'
+ {
+ tree interface = lookup_interface ($3);
+
+ if (interface)
+ $$ = get_class_ivars (interface);
+ else
+ {
+ error ("Cannot find interface declaration for `%s'",
+ IDENTIFIER_POINTER ($3));
+ $$ = NULL_TREE;
+ }
+ }
+ ;
+
+/* 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. */
+
+component_decl:
+ typed_typespecs setspecs components
+ { $$ = $3;
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_typespecs
+ { if (pedantic)
+ pedwarn ("ANSI C forbids member declarations with no members");
+ shadow_tag($1);
+ $$ = NULL_TREE; }
+ | nonempty_type_quals setspecs components
+ { $$ = $3;
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | nonempty_type_quals
+ { if (pedantic)
+ pedwarn ("ANSI C forbids member declarations with no members");
+ shadow_tag($1);
+ $$ = NULL_TREE; }
+ | error
+ { $$ = NULL_TREE; }
+ ;
+
+components:
+ component_declarator
+ | components ',' component_declarator
+ { $$ = chainon ($1, $3); }
+ ;
+
+component_declarator:
+ save_filename save_lineno declarator maybe_attribute
+ { $$ = grokfield ($1, $2, $3, current_declspecs, NULL_TREE);
+ decl_attributes ($$, $4, prefix_attributes); }
+ | save_filename save_lineno
+ declarator ':' expr_no_commas maybe_attribute
+ { $$ = grokfield ($1, $2, $3, current_declspecs, $5);
+ decl_attributes ($$, $6, prefix_attributes); }
+ | save_filename save_lineno ':' expr_no_commas maybe_attribute
+ { $$ = grokfield ($1, $2, NULL_TREE, current_declspecs, $4);
+ decl_attributes ($$, $5, prefix_attributes); }
+ ;
+
+/* We chain the enumerators in reverse order.
+ They are put in forward order where enumlist is used.
+ (The order used to be significant, but no longer is so.
+ However, we still maintain the order, just to be clean.) */
+
+enumlist:
+ enumerator
+ | enumlist ',' enumerator
+ { if ($1 == error_mark_node)
+ $$ = $1;
+ else
+ $$ = chainon ($3, $1); }
+ | error
+ { $$ = error_mark_node; }
+ ;
+
+
+enumerator:
+ identifier
+ { $$ = build_enumerator ($1, NULL_TREE); }
+ | identifier '=' expr_no_commas
+ { $$ = build_enumerator ($1, $3); }
+ ;
+
+typename:
+ typed_typespecs absdcl
+ { $$ = build_tree_list ($1, $2); }
+ | nonempty_type_quals absdcl
+ { $$ = build_tree_list ($1, $2); }
+ ;
+
+absdcl: /* an absolute declarator */
+ /* empty */
+ { $$ = NULL_TREE; }
+ | absdcl1
+ ;
+
+nonempty_type_quals:
+ TYPE_QUAL
+ { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); }
+ | nonempty_type_quals TYPE_QUAL
+ { $$ = tree_cons (NULL_TREE, $2, $1); }
+ ;
+
+type_quals:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | type_quals TYPE_QUAL
+ { $$ = tree_cons (NULL_TREE, $2, $1); }
+ ;
+
+absdcl1: /* a nonempty absolute declarator */
+ '(' absdcl1 ')'
+ { $$ = $2; }
+ /* `(typedef)1' is `int'. */
+ | '*' type_quals absdcl1 %prec UNARY
+ { $$ = make_pointer_declarator ($2, $3); }
+ | '*' type_quals %prec UNARY
+ { $$ = make_pointer_declarator ($2, NULL_TREE); }
+ | absdcl1 '(' parmlist %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
+ | absdcl1 '[' expr ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, $3); }
+ | absdcl1 '[' ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
+ | '(' parmlist %prec '.'
+ { $$ = build_nt (CALL_EXPR, NULL_TREE, $2, NULL_TREE); }
+ | '[' expr ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, NULL_TREE, $2); }
+ | '[' ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, NULL_TREE, NULL_TREE); }
+ | attributes setattrs absdcl1
+ { $$ = $3; }
+ ;
+
+/* at least one statement, the first of which parses without error. */
+/* stmts is used only after decls, so an invalid first statement
+ is actually regarded as an invalid decl and part of the decls. */
+
+stmts:
+ lineno_stmt_or_labels
+ {
+ if (pedantic && $1)
+ pedwarn ("ANSI C forbids label at end of compound statement");
+ }
+ ;
+
+lineno_stmt_or_labels:
+ lineno_stmt_or_label
+ | lineno_stmt_or_labels lineno_stmt_or_label
+ { $$ = $2; }
+ | lineno_stmt_or_labels errstmt
+ { $$ = 0; }
+ ;
+
+xstmts:
+ /* empty */
+ | stmts
+ ;
+
+errstmt: error ';'
+ ;
+
+pushlevel: /* empty */
+ { emit_line_note (input_filename, lineno);
+ pushlevel (0);
+ clear_last_expr ();
+ push_momentary ();
+ expand_start_bindings (0);
+ if (objc_method_context)
+ add_objc_decls ();
+ }
+ ;
+
+/* Read zero or more forward-declarations for labels
+ that nested functions can jump to. */
+maybe_label_decls:
+ /* empty */
+ | label_decls
+ { if (pedantic)
+ pedwarn ("ANSI C forbids label declarations"); }
+ ;
+
+label_decls:
+ label_decl
+ | label_decls label_decl
+ ;
+
+label_decl:
+ LABEL identifiers_or_typenames ';'
+ { tree link;
+ for (link = $2; link; link = TREE_CHAIN (link))
+ {
+ tree label = shadow_label (TREE_VALUE (link));
+ C_DECLARED_LABEL_FLAG (label) = 1;
+ declare_nonlocal_label (label);
+ }
+ }
+ ;
+
+/* This is the body of a function definition.
+ It causes syntax errors to ignore to the next openbrace. */
+compstmt_or_error:
+ compstmt
+ {}
+ | error compstmt
+ ;
+
+compstmt: '{' '}'
+ { $$ = convert (void_type_node, integer_zero_node); }
+ | '{' pushlevel maybe_label_decls decls xstmts '}'
+ { emit_line_note (input_filename, lineno);
+ expand_end_bindings (getdecls (), 1, 0);
+ $$ = poplevel (1, 1, 0);
+ if (yychar == CONSTANT || yychar == STRING)
+ pop_momentary_nofree ();
+ else
+ pop_momentary (); }
+ | '{' pushlevel maybe_label_decls error '}'
+ { emit_line_note (input_filename, lineno);
+ expand_end_bindings (getdecls (), kept_level_p (), 0);
+ $$ = poplevel (kept_level_p (), 0, 0);
+ if (yychar == CONSTANT || yychar == STRING)
+ pop_momentary_nofree ();
+ else
+ pop_momentary (); }
+ | '{' pushlevel maybe_label_decls stmts '}'
+ { emit_line_note (input_filename, lineno);
+ expand_end_bindings (getdecls (), kept_level_p (), 0);
+ $$ = poplevel (kept_level_p (), 0, 0);
+ if (yychar == CONSTANT || yychar == STRING)
+ pop_momentary_nofree ();
+ else
+ pop_momentary (); }
+ ;
+
+/* Value is number of statements counted as of the closeparen. */
+simple_if:
+ if_prefix lineno_labeled_stmt
+/* Make sure expand_end_cond is run once
+ for each call to expand_start_cond.
+ Otherwise a crash is likely. */
+ | if_prefix error
+ ;
+
+if_prefix:
+ IF '(' expr ')'
+ { emit_line_note ($<filename>-1, $<lineno>0);
+ expand_start_cond (truthvalue_conversion ($3), 0);
+ $<itype>$ = stmt_count;
+ if_stmt_file = $<filename>-1;
+ if_stmt_line = $<lineno>0;
+ position_after_white_space (); }
+ ;
+
+/* This is a subroutine of stmt.
+ It is used twice, once for valid DO statements
+ and once for catching errors in parsing the end test. */
+do_stmt_start:
+ DO
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ /* See comment in `while' alternative, above. */
+ emit_nop ();
+ expand_start_loop_continue_elsewhere (1);
+ position_after_white_space (); }
+ lineno_labeled_stmt WHILE
+ { expand_loop_continue_here (); }
+ ;
+
+save_filename:
+ { $$ = input_filename; }
+ ;
+
+save_lineno:
+ { $$ = lineno; }
+ ;
+
+lineno_labeled_stmt:
+ save_filename save_lineno stmt
+ { }
+/* | save_filename save_lineno error
+ { }
+*/
+ | save_filename save_lineno label lineno_labeled_stmt
+ { }
+ ;
+
+lineno_stmt_or_label:
+ save_filename save_lineno stmt_or_label
+ { $$ = $3; }
+ ;
+
+stmt_or_label:
+ stmt
+ { $$ = 0; }
+ | label
+ { $$ = 1; }
+ ;
+
+/* Parse a single real statement, not including any labels. */
+stmt:
+ compstmt
+ { stmt_count++; }
+ | all_iter_stmt
+ | expr ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+/* It appears that this should not be done--that a non-lvalue array
+ shouldn't get an error if the value isn't used.
+ Section 3.2.2.1 says that an array lvalue gets converted to a pointer
+ if it appears as a top-level expression,
+ but says nothing about non-lvalue arrays. */
+#if 0
+ /* Call default_conversion to get an error
+ on referring to a register array if pedantic. */
+ if (TREE_CODE (TREE_TYPE ($1)) == ARRAY_TYPE
+ || TREE_CODE (TREE_TYPE ($1)) == FUNCTION_TYPE)
+ $1 = default_conversion ($1);
+#endif
+ iterator_expand ($1);
+ clear_momentary (); }
+ | simple_if ELSE
+ { expand_start_else ();
+ $<itype>1 = stmt_count;
+ position_after_white_space (); }
+ lineno_labeled_stmt
+ { expand_end_cond ();
+ if (extra_warnings && stmt_count == $<itype>1)
+ warning ("empty body in an else-statement"); }
+ | simple_if %prec IF
+ { expand_end_cond ();
+ /* This warning is here instead of in simple_if, because we
+ do not want a warning if an empty if is followed by an
+ else statement. Increment stmt_count so we don't
+ give a second error if this is a nested `if'. */
+ if (extra_warnings && stmt_count++ == $<itype>1)
+ warning_with_file_and_line (if_stmt_file, if_stmt_line,
+ "empty body in an if-statement"); }
+/* Make sure expand_end_cond is run once
+ for each call to expand_start_cond.
+ Otherwise a crash is likely. */
+ | simple_if ELSE error
+ { expand_end_cond (); }
+ | WHILE
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ /* The emit_nop used to come before emit_line_note,
+ but that made the nop seem like part of the preceding line.
+ And that was confusing when the preceding line was
+ inside of an if statement and was not really executed.
+ I think it ought to work to put the nop after the line number.
+ We will see. --rms, July 15, 1991. */
+ emit_nop (); }
+ '(' expr ')'
+ { /* Don't start the loop till we have succeeded
+ in parsing the end test. This is to make sure
+ that we end every loop we start. */
+ expand_start_loop (1);
+ emit_line_note (input_filename, lineno);
+ expand_exit_loop_if_false (NULL_PTR,
+ truthvalue_conversion ($4));
+ position_after_white_space (); }
+ lineno_labeled_stmt
+ { expand_end_loop (); }
+ | do_stmt_start
+ '(' expr ')' ';'
+ { emit_line_note (input_filename, lineno);
+ expand_exit_loop_if_false (NULL_PTR,
+ truthvalue_conversion ($3));
+ expand_end_loop ();
+ clear_momentary (); }
+/* This rule is needed to make sure we end every loop we start. */
+ | do_stmt_start error
+ { expand_end_loop ();
+ clear_momentary (); }
+ | FOR
+ '(' xexpr ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ /* See comment in `while' alternative, above. */
+ emit_nop ();
+ if ($3) c_expand_expr_stmt ($3);
+ /* Next step is to call expand_start_loop_continue_elsewhere,
+ but wait till after we parse the entire for (...).
+ Otherwise, invalid input might cause us to call that
+ fn without calling expand_end_loop. */
+ }
+ xexpr ';'
+ /* Can't emit now; wait till after expand_start_loop... */
+ { $<lineno>7 = lineno;
+ $<filename>$ = input_filename; }
+ xexpr ')'
+ {
+ /* Start the loop. Doing this after parsing
+ all the expressions ensures we will end the loop. */
+ expand_start_loop_continue_elsewhere (1);
+ /* Emit the end-test, with a line number. */
+ emit_line_note ($<filename>8, $<lineno>7);
+ if ($6)
+ expand_exit_loop_if_false (NULL_PTR,
+ truthvalue_conversion ($6));
+ /* Don't let the tree nodes for $9 be discarded by
+ clear_momentary during the parsing of the next stmt. */
+ push_momentary ();
+ $<lineno>7 = lineno;
+ $<filename>8 = input_filename;
+ position_after_white_space (); }
+ lineno_labeled_stmt
+ { /* Emit the increment expression, with a line number. */
+ emit_line_note ($<filename>8, $<lineno>7);
+ expand_loop_continue_here ();
+ if ($9)
+ c_expand_expr_stmt ($9);
+ if (yychar == CONSTANT || yychar == STRING)
+ pop_momentary_nofree ();
+ else
+ pop_momentary ();
+ expand_end_loop (); }
+ | SWITCH '(' expr ')'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ c_expand_start_case ($3);
+ /* Don't let the tree nodes for $3 be discarded by
+ clear_momentary during the parsing of the next stmt. */
+ push_momentary ();
+ position_after_white_space (); }
+ lineno_labeled_stmt
+ { expand_end_case ($3);
+ if (yychar == CONSTANT || yychar == STRING)
+ pop_momentary_nofree ();
+ else
+ pop_momentary (); }
+ | BREAK ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ if ( ! expand_exit_something ())
+ error ("break statement not within loop or switch"); }
+ | CONTINUE ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ if (! expand_continue_loop (NULL_PTR))
+ error ("continue statement not within a loop"); }
+ | RETURN ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ c_expand_return (NULL_TREE); }
+ | RETURN expr ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ c_expand_return ($2); }
+ | ASM_KEYWORD maybe_type_qual '(' expr ')' ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ STRIP_NOPS ($4);
+ if ((TREE_CODE ($4) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND ($4, 0)) == STRING_CST)
+ || TREE_CODE ($4) == STRING_CST)
+ expand_asm ($4);
+ else
+ error ("argument of `asm' is not a constant string"); }
+ /* This is the case with just output operands. */
+ | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ')' ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ c_expand_asm_operands ($4, $6, NULL_TREE, NULL_TREE,
+ $2 == ridpointers[(int)RID_VOLATILE],
+ input_filename, lineno); }
+ /* This is the case with input operands as well. */
+ | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ':' asm_operands ')' ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ c_expand_asm_operands ($4, $6, $8, NULL_TREE,
+ $2 == ridpointers[(int)RID_VOLATILE],
+ input_filename, lineno); }
+ /* This is the case with clobbered registers as well. */
+ | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ':'
+ asm_operands ':' asm_clobbers ')' ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ c_expand_asm_operands ($4, $6, $8, $10,
+ $2 == ridpointers[(int)RID_VOLATILE],
+ input_filename, lineno); }
+ | GOTO identifier ';'
+ { tree decl;
+ stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ decl = lookup_label ($2);
+ if (decl != 0)
+ {
+ TREE_USED (decl) = 1;
+ expand_goto (decl);
+ }
+ }
+ | GOTO '*' expr ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ expand_computed_goto (convert (ptr_type_node, $3)); }
+ | ';'
+ ;
+
+all_iter_stmt:
+ all_iter_stmt_simple
+/* | all_iter_stmt_with_decl */
+ ;
+
+all_iter_stmt_simple:
+ FOR '(' primary ')'
+ {
+ /* The value returned by this action is */
+ /* 1 if everything is OK */
+ /* 0 in case of error or already bound iterator */
+
+ $<itype>$ = 0;
+ if (TREE_CODE ($3) != VAR_DECL)
+ error ("invalid `for (ITERATOR)' syntax");
+ else if (! ITERATOR_P ($3))
+ error ("`%s' is not an iterator",
+ IDENTIFIER_POINTER (DECL_NAME ($3)));
+ else if (ITERATOR_BOUND_P ($3))
+ error ("`for (%s)' inside expansion of same iterator",
+ IDENTIFIER_POINTER (DECL_NAME ($3)));
+ else
+ {
+ $<itype>$ = 1;
+ iterator_for_loop_start ($3);
+ }
+ }
+ lineno_labeled_stmt
+ {
+ if ($<itype>5)
+ iterator_for_loop_end ($3);
+ }
+
+/* This really should allow any kind of declaration,
+ for generality. Fix it before turning it back on.
+
+all_iter_stmt_with_decl:
+ FOR '(' ITERATOR pushlevel setspecs iterator_spec ')'
+ {
+*/ /* The value returned by this action is */
+ /* 1 if everything is OK */
+ /* 0 in case of error or already bound iterator */
+/*
+ iterator_for_loop_start ($6);
+ }
+ lineno_labeled_stmt
+ {
+ iterator_for_loop_end ($6);
+ emit_line_note (input_filename, lineno);
+ expand_end_bindings (getdecls (), 1, 0);
+ $<ttype>$ = poplevel (1, 1, 0);
+ if (yychar == CONSTANT || yychar == STRING)
+ pop_momentary_nofree ();
+ else
+ pop_momentary ();
+ }
+*/
+
+/* Any kind of label, including jump labels and case labels.
+ ANSI C accepts labels only before statements, but we allow them
+ also at the end of a compound statement. */
+
+label: CASE expr_no_commas ':'
+ { register tree value = check_case_value ($2);
+ register tree label
+ = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+
+ stmt_count++;
+
+ if (value != error_mark_node)
+ {
+ tree duplicate;
+ int success = pushcase (value, convert_and_check,
+ label, &duplicate);
+ if (success == 1)
+ error ("case label not within a switch statement");
+ else if (success == 2)
+ {
+ error ("duplicate case value");
+ error_with_decl (duplicate, "this is the first entry for that value");
+ }
+ else if (success == 3)
+ warning ("case value out of range");
+ else if (success == 5)
+ error ("case label within scope of cleanup or variable array");
+ }
+ position_after_white_space (); }
+ | CASE expr_no_commas ELLIPSIS expr_no_commas ':'
+ { register tree value1 = check_case_value ($2);
+ register tree value2 = check_case_value ($4);
+ register tree label
+ = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+
+ stmt_count++;
+
+ if (value1 != error_mark_node && value2 != error_mark_node)
+ {
+ tree duplicate;
+ int success = pushcase_range (value1, value2,
+ convert_and_check, label,
+ &duplicate);
+ if (success == 1)
+ error ("case label not within a switch statement");
+ else if (success == 2)
+ {
+ error ("duplicate case value");
+ error_with_decl (duplicate, "this is the first entry for that value");
+ }
+ else if (success == 3)
+ warning ("case value out of range");
+ else if (success == 4)
+ warning ("empty case range");
+ else if (success == 5)
+ error ("case label within scope of cleanup or variable array");
+ }
+ position_after_white_space (); }
+ | DEFAULT ':'
+ {
+ tree duplicate;
+ register tree label
+ = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+ int success = pushcase (NULL_TREE, 0, label, &duplicate);
+ stmt_count++;
+ if (success == 1)
+ error ("default label not within a switch statement");
+ else if (success == 2)
+ {
+ error ("multiple default labels in one switch");
+ error_with_decl (duplicate, "this is the first default label");
+ }
+ position_after_white_space (); }
+ | identifier ':'
+ { tree label = define_label (input_filename, lineno, $1);
+ stmt_count++;
+ emit_nop ();
+ if (label)
+ expand_label (label);
+ position_after_white_space (); }
+ ;
+
+/* Either a type-qualifier or nothing. First thing in an `asm' statement. */
+
+maybe_type_qual:
+ /* empty */
+ { emit_line_note (input_filename, lineno);
+ $$ = NULL_TREE; }
+ | TYPE_QUAL
+ { emit_line_note (input_filename, lineno); }
+ ;
+
+xexpr:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | expr
+ ;
+
+/* These are the operands other than the first string and colon
+ in asm ("addextend %2,%1": "=dm" (x), "0" (y), "g" (*x)) */
+asm_operands: /* empty */
+ { $$ = NULL_TREE; }
+ | nonnull_asm_operands
+ ;
+
+nonnull_asm_operands:
+ asm_operand
+ | nonnull_asm_operands ',' asm_operand
+ { $$ = chainon ($1, $3); }
+ ;
+
+asm_operand:
+ STRING '(' expr ')'
+ { $$ = build_tree_list ($1, $3); }
+ ;
+
+asm_clobbers:
+ string
+ { $$ = tree_cons (NULL_TREE, combine_strings ($1), NULL_TREE); }
+ | asm_clobbers ',' string
+ { $$ = tree_cons (NULL_TREE, combine_strings ($3), $1); }
+ ;
+
+/* This is what appears inside the parens in a function declarator.
+ Its value is a list of ..._TYPE nodes. */
+parmlist:
+ { pushlevel (0);
+ clear_parm_order ();
+ declare_parm_level (0); }
+ parmlist_1
+ { $$ = $2;
+ parmlist_tags_warning ();
+ poplevel (0, 0, 0); }
+ ;
+
+parmlist_1:
+ parmlist_2 ')'
+ | parms ';'
+ { tree parm;
+ if (pedantic)
+ pedwarn ("ANSI C forbids forward parameter declarations");
+ /* Mark the forward decls as such. */
+ for (parm = getdecls (); parm; parm = TREE_CHAIN (parm))
+ TREE_ASM_WRITTEN (parm) = 1;
+ clear_parm_order (); }
+ parmlist_1
+ { $$ = $4; }
+ | error ')'
+ { $$ = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE); }
+ ;
+
+/* This is what appears inside the parens in a function declarator.
+ Is value is represented in the format that grokdeclarator expects. */
+parmlist_2: /* empty */
+ { $$ = get_parm_info (0); }
+ | ELLIPSIS
+ { $$ = get_parm_info (0);
+ /* Gcc used to allow this as an extension. However, it does
+ not work for all targets, and thus has been disabled.
+ Also, since func (...) and func () are indistinguishable,
+ it caused problems with the code in expand_builtin which
+ tries to verify that BUILT_IN_NEXT_ARG is being used
+ correctly. */
+ error ("ANSI C requires a named argument before `...'");
+ }
+ | parms
+ { $$ = get_parm_info (1); }
+ | parms ',' ELLIPSIS
+ { $$ = get_parm_info (0); }
+ ;
+
+parms:
+ parm
+ { push_parm_decl ($1); }
+ | parms ',' parm
+ { push_parm_decl ($3); }
+ ;
+
+/* A single parameter declaration or parameter type name,
+ as found in a parmlist. */
+parm:
+ typed_declspecs setspecs parm_declarator maybe_attribute
+ { $$ = build_tree_list (build_tree_list (current_declspecs,
+ $3),
+ build_tree_list (prefix_attributes,
+ $4));
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs setspecs notype_declarator maybe_attribute
+ { $$ = build_tree_list (build_tree_list (current_declspecs,
+ $3),
+ build_tree_list (prefix_attributes,
+ $4));
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs setspecs absdcl maybe_attribute
+ { $$ = build_tree_list (build_tree_list (current_declspecs,
+ $3),
+ build_tree_list (prefix_attributes,
+ $4));
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods setspecs notype_declarator maybe_attribute
+ { $$ = build_tree_list (build_tree_list (current_declspecs,
+ $3),
+ build_tree_list (prefix_attributes,
+ $4));
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+
+ | declmods setspecs absdcl maybe_attribute
+ { $$ = build_tree_list (build_tree_list (current_declspecs,
+ $3),
+ build_tree_list (prefix_attributes,
+ $4));
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ ;
+
+/* This is used in a function definition
+ where either a parmlist or an identifier list is ok.
+ Its value is a list of ..._TYPE nodes or a list of identifiers. */
+parmlist_or_identifiers:
+ { pushlevel (0);
+ clear_parm_order ();
+ declare_parm_level (1); }
+ parmlist_or_identifiers_1
+ { $$ = $2;
+ parmlist_tags_warning ();
+ poplevel (0, 0, 0); }
+ ;
+
+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); }
+ ;
+
+/* A nonempty list of identifiers. */
+identifiers:
+ IDENTIFIER
+ { $$ = build_tree_list (NULL_TREE, $1); }
+ | identifiers ',' IDENTIFIER
+ { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); }
+ ;
+
+/* A nonempty list of identifiers, including typenames. */
+identifiers_or_typenames:
+ identifier
+ { $$ = build_tree_list (NULL_TREE, $1); }
+ | identifiers_or_typenames ',' identifier
+ { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); }
+ ;
+
+/* Objective-C productions. */
+
+objcdef:
+ classdef
+ | classdecl
+ | aliasdecl
+ | protocoldef
+ | methoddef
+ | 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");
+ }
+ ;
+
+/* A nonempty list of identifiers. */
+identifier_list:
+ identifier
+ { $$ = build_tree_list (NULL_TREE, $1); }
+ | identifier_list ',' identifier
+ { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); }
+ ;
+
+classdecl:
+ CLASS identifier_list ';'
+ {
+ objc_declare_class ($2);
+ }
+
+aliasdecl:
+ ALIAS identifier identifier ';'
+ {
+ objc_declare_alias ($2, $3);
+ }
+
+classdef:
+ INTERFACE identifier protocolrefs '{'
+ {
+ objc_interface_context = objc_ivar_context
+ = start_class (CLASS_INTERFACE_TYPE, $2, NULL_TREE, $3);
+ objc_public_flag = 0;
+ }
+ ivar_decl_list '}'
+ {
+ continue_class (objc_interface_context);
+ }
+ methodprotolist
+ END
+ {
+ finish_class (objc_interface_context);
+ objc_interface_context = NULL_TREE;
+ }
+
+ | INTERFACE identifier protocolrefs
+ {
+ objc_interface_context
+ = start_class (CLASS_INTERFACE_TYPE, $2, NULL_TREE, $3);
+ continue_class (objc_interface_context);
+ }
+ methodprotolist
+ END
+ {
+ finish_class (objc_interface_context);
+ objc_interface_context = NULL_TREE;
+ }
+
+ | INTERFACE identifier ':' identifier protocolrefs '{'
+ {
+ objc_interface_context = objc_ivar_context
+ = start_class (CLASS_INTERFACE_TYPE, $2, $4, $5);
+ objc_public_flag = 0;
+ }
+ ivar_decl_list '}'
+ {
+ continue_class (objc_interface_context);
+ }
+ methodprotolist
+ END
+ {
+ finish_class (objc_interface_context);
+ objc_interface_context = NULL_TREE;
+ }
+
+ | INTERFACE identifier ':' identifier protocolrefs
+ {
+ objc_interface_context
+ = start_class (CLASS_INTERFACE_TYPE, $2, $4, $5);
+ continue_class (objc_interface_context);
+ }
+ methodprotolist
+ END
+ {
+ finish_class (objc_interface_context);
+ objc_interface_context = NULL_TREE;
+ }
+
+ | IMPLEMENTATION identifier '{'
+ {
+ objc_implementation_context = objc_ivar_context
+ = start_class (CLASS_IMPLEMENTATION_TYPE, $2, NULL_TREE, NULL_TREE);
+ objc_public_flag = 0;
+ }
+ ivar_decl_list '}'
+ {
+ objc_ivar_chain
+ = continue_class (objc_implementation_context);
+ }
+
+ | IMPLEMENTATION identifier
+ {
+ objc_implementation_context
+ = start_class (CLASS_IMPLEMENTATION_TYPE, $2, NULL_TREE, NULL_TREE);
+ objc_ivar_chain
+ = continue_class (objc_implementation_context);
+ }
+
+ | IMPLEMENTATION identifier ':' identifier '{'
+ {
+ objc_implementation_context = objc_ivar_context
+ = start_class (CLASS_IMPLEMENTATION_TYPE, $2, $4, NULL_TREE);
+ objc_public_flag = 0;
+ }
+ ivar_decl_list '}'
+ {
+ objc_ivar_chain
+ = continue_class (objc_implementation_context);
+ }
+
+ | IMPLEMENTATION identifier ':' identifier
+ {
+ objc_implementation_context
+ = start_class (CLASS_IMPLEMENTATION_TYPE, $2, $4, NULL_TREE);
+ objc_ivar_chain
+ = continue_class (objc_implementation_context);
+ }
+
+ | INTERFACE identifier '(' identifier ')' protocolrefs
+ {
+ objc_interface_context
+ = start_class (CATEGORY_INTERFACE_TYPE, $2, $4, $6);
+ continue_class (objc_interface_context);
+ }
+ methodprotolist
+ END
+ {
+ finish_class (objc_interface_context);
+ objc_interface_context = NULL_TREE;
+ }
+
+ | IMPLEMENTATION identifier '(' identifier ')'
+ {
+ objc_implementation_context
+ = start_class (CATEGORY_IMPLEMENTATION_TYPE, $2, $4, NULL_TREE);
+ objc_ivar_chain
+ = continue_class (objc_implementation_context);
+ }
+ ;
+
+protocoldef:
+ PROTOCOL identifier protocolrefs
+ {
+ remember_protocol_qualifiers ();
+ objc_interface_context
+ = start_protocol(PROTOCOL_INTERFACE_TYPE, $2, $3);
+ }
+ methodprotolist END
+ {
+ forget_protocol_qualifiers();
+ finish_protocol(objc_interface_context);
+ objc_interface_context = NULL_TREE;
+ }
+ ;
+
+protocolrefs:
+ /* empty */
+ {
+ $$ = NULL_TREE;
+ }
+ | ARITHCOMPARE identifier_list ARITHCOMPARE
+ {
+ if ($1 == LT_EXPR && $3 == GT_EXPR)
+ $$ = $2;
+ else
+ YYERROR1;
+ }
+ ;
+
+ivar_decl_list:
+ ivar_decl_list visibility_spec ivar_decls
+ | ivar_decls
+ ;
+
+visibility_spec:
+ PRIVATE { objc_public_flag = 2; }
+ | PROTECTED { objc_public_flag = 0; }
+ | PUBLIC { objc_public_flag = 1; }
+ ;
+
+ivar_decls:
+ /* empty */
+ {
+ $$ = NULL_TREE;
+ }
+ | ivar_decls ivar_decl ';'
+ | ivar_decls ';'
+ {
+ 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:
+ typed_typespecs setspecs ivars
+ { $$ = $3;
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | nonempty_type_quals setspecs ivars
+ { $$ = $3;
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | error
+ { $$ = NULL_TREE; }
+ ;
+
+ivars:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | ivar_declarator
+ | ivars ',' ivar_declarator
+ ;
+
+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);
+ }
+ | ':' expr_no_commas
+ {
+ $$ = add_instance_variable (objc_ivar_context,
+ objc_public_flag,
+ NULL_TREE,
+ current_declspecs, $2);
+ }
+ ;
+
+methoddef:
+ '+'
+ {
+ remember_protocol_qualifiers ();
+ if (objc_implementation_context)
+ objc_inherit_code = CLASS_METHOD_DECL;
+ else
+ fatal ("method definition not in class context");
+ }
+ methoddecl
+ {
+ forget_protocol_qualifiers ();
+ add_class_method (objc_implementation_context, $3);
+ start_method_def ($3);
+ objc_method_context = $3;
+ }
+ optarglist
+ {
+ continue_method_def ();
+ }
+ compstmt_or_error
+ {
+ finish_method_def ();
+ objc_method_context = NULL_TREE;
+ }
+
+ | '-'
+ {
+ remember_protocol_qualifiers ();
+ if (objc_implementation_context)
+ objc_inherit_code = INSTANCE_METHOD_DECL;
+ else
+ fatal ("method definition not in class context");
+ }
+ methoddecl
+ {
+ forget_protocol_qualifiers ();
+ add_instance_method (objc_implementation_context, $3);
+ start_method_def ($3);
+ objc_method_context = $3;
+ }
+ optarglist
+ {
+ continue_method_def ();
+ }
+ compstmt_or_error
+ {
+ finish_method_def ();
+ objc_method_context = NULL_TREE;
+ }
+ ;
+
+/* 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. */
+
+methodprotolist:
+ /* empty */
+ | {$<ttype>$ = NULL_TREE; } methodprotolist2
+ ;
+
+methodprotolist2: /* eliminates a shift/reduce conflict */
+ methodproto
+ | datadef
+ | methodprotolist2 methodproto
+ | methodprotolist2 {$<ttype>$ = NULL_TREE; } datadef
+ ;
+
+semi_or_error:
+ ';'
+ | error
+ ;
+
+methodproto:
+ '+'
+ {
+ objc_inherit_code = CLASS_METHOD_DECL;
+ }
+ methoddecl
+ {
+ add_class_method (objc_interface_context, $3);
+ }
+ semi_or_error
+
+ | '-'
+ {
+ objc_inherit_code = INSTANCE_METHOD_DECL;
+ }
+ methoddecl
+ {
+ add_instance_method (objc_interface_context, $3);
+ }
+ semi_or_error
+ ;
+
+methoddecl:
+ '(' typename ')' unaryselector
+ {
+ $$ = build_method_decl (objc_inherit_code, $2, $4, NULL_TREE);
+ }
+
+ | unaryselector
+ {
+ $$ = build_method_decl (objc_inherit_code, NULL_TREE, $1, NULL_TREE);
+ }
+
+ | '(' typename ')' keywordselector optparmlist
+ {
+ $$ = build_method_decl (objc_inherit_code, $2, $4, $5);
+ }
+
+ | keywordselector optparmlist
+ {
+ $$ = build_method_decl (objc_inherit_code, 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:
+ typed_declspecs setspecs myparms ';'
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs ';'
+ { shadow_tag ($1); }
+ | declmods ';'
+ { pedwarn ("empty declaration"); }
+ ;
+
+myparms:
+ myparm
+ { push_parm_decl ($1); }
+ | myparms ',' myparm
+ { push_parm_decl ($3); }
+ ;
+
+/* 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),
+ build_tree_list (prefix_attributes,
+ $2)); }
+ | notype_declarator maybe_attribute
+ { $$ = build_tree_list (build_tree_list (current_declspecs,
+ $1),
+ build_tree_list (prefix_attributes,
+ $2)); }
+ | absdcl maybe_attribute
+ { $$ = build_tree_list (build_tree_list (current_declspecs,
+ $1),
+ build_tree_list (prefix_attributes,
+ $2)); }
+ ;
+
+optparmlist:
+ /* empty */
+ {
+ $$ = NULL_TREE;
+ }
+ | ',' ELLIPSIS
+ {
+ /* oh what a kludge! */
+ $$ = (tree)1;
+ }
+ | ','
+ {
+ pushlevel (0);
+ }
+ parmlist_2
+ {
+ /* returns a tree list node generated by get_parm_info */
+ $$ = $3;
+ poplevel (0, 0, 0);
+ }
+ ;
+
+unaryselector:
+ selector
+ ;
+
+keywordselector:
+ keyworddecl
+
+ | keywordselector keyworddecl
+ {
+ $$ = chainon ($1, $2);
+ }
+ ;
+
+selector:
+ IDENTIFIER
+ | TYPENAME
+ | OBJECTNAME
+ | reservedwords
+ ;
+
+reservedwords:
+ ENUM { $$ = get_identifier (token_buffer); }
+ | STRUCT { $$ = get_identifier (token_buffer); }
+ | UNION { $$ = get_identifier (token_buffer); }
+ | IF { $$ = get_identifier (token_buffer); }
+ | ELSE { $$ = get_identifier (token_buffer); }
+ | WHILE { $$ = get_identifier (token_buffer); }
+ | DO { $$ = get_identifier (token_buffer); }
+ | FOR { $$ = get_identifier (token_buffer); }
+ | SWITCH { $$ = get_identifier (token_buffer); }
+ | CASE { $$ = get_identifier (token_buffer); }
+ | DEFAULT { $$ = get_identifier (token_buffer); }
+ | BREAK { $$ = get_identifier (token_buffer); }
+ | CONTINUE { $$ = get_identifier (token_buffer); }
+ | RETURN { $$ = get_identifier (token_buffer); }
+ | GOTO { $$ = get_identifier (token_buffer); }
+ | ASM_KEYWORD { $$ = get_identifier (token_buffer); }
+ | SIZEOF { $$ = get_identifier (token_buffer); }
+ | TYPEOF { $$ = get_identifier (token_buffer); }
+ | ALIGNOF { $$ = get_identifier (token_buffer); }
+ | TYPESPEC | TYPE_QUAL
+ ;
+
+keyworddecl:
+ selector ':' '(' typename ')' identifier
+ {
+ $$ = build_keyword_decl ($1, $4, $6);
+ }
+
+ | selector ':' identifier
+ {
+ $$ = build_keyword_decl ($1, NULL_TREE, $3);
+ }
+
+ | ':' '(' typename ')' identifier
+ {
+ $$ = build_keyword_decl (NULL_TREE, $3, $5);
+ }
+
+ | ':' identifier
+ {
+ $$ = build_keyword_decl (NULL_TREE, NULL_TREE, $2);
+ }
+ ;
+
+messageargs:
+ selector
+ | keywordarglist
+ ;
+
+keywordarglist:
+ keywordarg
+ | keywordarglist keywordarg
+ {
+ $$ = chainon ($1, $2);
+ }
+ ;
+
+
+keywordexpr:
+ nonnull_exprlist
+ {
+ if (TREE_CHAIN ($1) == NULL_TREE)
+ /* just return the expr., remove a level of indirection */
+ $$ = TREE_VALUE ($1);
+ else
+ /* we have a comma expr., we will collapse later */
+ $$ = $1;
+ }
+ ;
+
+keywordarg:
+ selector ':' keywordexpr
+ {
+ $$ = build_tree_list ($1, $3);
+ }
+ | ':' keywordexpr
+ {
+ $$ = build_tree_list (NULL_TREE, $2);
+ }
+ ;
+
+receiver:
+ expr
+ | CLASSNAME
+ {
+ $$ = get_class_reference ($1);
+ }
+ ;
+
+objcmessageexpr:
+ '['
+ { objc_receiver_context = 1; }
+ receiver
+ { objc_receiver_context = 0; }
+ messageargs ']'
+ {
+ $$ = build_tree_list ($3, $5);
+ }
+ ;
+
+selectorarg:
+ selector
+ | keywordnamelist
+ ;
+
+keywordnamelist:
+ keywordname
+ | keywordnamelist keywordname
+ {
+ $$ = chainon ($1, $2);
+ }
+ ;
+
+keywordname:
+ selector ':'
+ {
+ $$ = build_tree_list ($1, NULL_TREE);
+ }
+ | ':'
+ {
+ $$ = build_tree_list (NULL_TREE, NULL_TREE);
+ }
+ ;
+
+objcselectorexpr:
+ SELECTOR '(' selectorarg ')'
+ {
+ $$ = $3;
+ }
+ ;
+
+objcprotocolexpr:
+ PROTOCOL '(' identifier ')'
+ {
+ $$ = $3;
+ }
+ ;
+
+/* extension to support C-structures in the archiver */
+
+objcencodeexpr:
+ ENCODE '(' typename ')'
+ {
+ $$ = groktypename ($3);
+ }
+ ;
+
+%%
diff --git a/gnu/usr.bin/gcc/cc1plus/parse.y b/gnu/usr.bin/gcc/cc1plus/parse.y
new file mode 100644
index 00000000000..fd034af418d
--- /dev/null
+++ b/gnu/usr.bin/gcc/cc1plus/parse.y
@@ -0,0 +1,3906 @@
+/* YACC parser for C++ syntax.
+ Copyright (C) 1988, 1989, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Hacked by Michael Tiemann (tiemann@cygnus.com)
+
+This file is part of GNU CC.
+
+GNU CC 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 Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/* This grammar is based on the GNU CC grammar. */
+
+/* Note: Bison automatically applies a default action of "$$ = $1" for
+ all derivations; this is applied before the explicit action, if one
+ is given. Keep this in mind when reading the actions. */
+
+%{
+/* Cause the `yydebug' variable to be defined. */
+#define YYDEBUG 1
+
+#include "config.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "tree.h"
+#include "input.h"
+#include "flags.h"
+#include "lex.h"
+#include "cp-tree.h"
+#include "output.h"
+
+/* Since parsers are distinct for each language, put the language string
+ definition here. (fnf) */
+char *language_string = "GNU C++";
+
+extern tree void_list_node;
+extern struct obstack permanent_obstack;
+
+#ifndef errno
+extern int errno;
+#endif
+
+extern int end_of_file;
+extern int current_class_depth;
+
+/* FSF LOCAL dje prefix attributes */
+extern tree strip_attrs PROTO((tree));
+/* END FSF LOCAL */
+
+void yyerror ();
+
+/* Like YYERROR but do call yyerror. */
+#define YYERROR1 { yyerror ("syntax error"); YYERROR; }
+
+#define OP0(NODE) (TREE_OPERAND (NODE, 0))
+#define OP1(NODE) (TREE_OPERAND (NODE, 1))
+
+/* Contains the statement keyword (if/while/do) to include in an
+ error message if the user supplies an empty conditional expression. */
+static char *cond_stmt_keyword;
+
+/* Nonzero if we have an `extern "C"' acting as an extern specifier. */
+int have_extern_spec;
+int used_extern_spec;
+
+void yyhook ();
+
+/* Cons up an empty parameter list. */
+#ifdef __GNUC__
+__inline
+#endif
+static tree
+empty_parms ()
+{
+ tree parms;
+
+ if (strict_prototype)
+ parms = void_list_node;
+ else
+ parms = NULL_TREE;
+ return parms;
+}
+%}
+
+%start program
+
+%union {long itype; tree ttype; char *strtype; enum tree_code code; }
+
+/* All identifiers that are not reserved words
+ and are not declared typedefs in the current block */
+%token IDENTIFIER
+
+/* All identifiers that are declared typedefs in the current block.
+ In some contexts, they are treated just like IDENTIFIER,
+ but they can also serve as typespecs in declarations. */
+%token TYPENAME
+
+/* Reserved words that specify storage class.
+ yylval contains an IDENTIFIER_NODE which indicates which one. */
+%token SCSPEC
+
+/* Reserved words that specify type.
+ yylval contains an IDENTIFIER_NODE which indicates which one. */
+%token TYPESPEC
+
+/* Reserved words that qualify type: "const" or "volatile".
+ yylval contains an IDENTIFIER_NODE which indicates which one. */
+%token TYPE_QUAL
+
+/* Character or numeric constants.
+ yylval is the node for the constant. */
+%token CONSTANT
+
+/* String constants in raw form.
+ yylval is a STRING_CST node. */
+%token STRING
+
+/* "...", used for functions with variable arglists. */
+%token ELLIPSIS
+
+/* the reserved words */
+/* SCO include files test "ASM", so use something else. */
+%token SIZEOF ENUM /* STRUCT UNION */ IF ELSE WHILE DO FOR SWITCH CASE DEFAULT
+%token BREAK CONTINUE RETURN GOTO ASM_KEYWORD GCC_ASM_KEYWORD TYPEOF ALIGNOF
+%token SIGOF
+%token ATTRIBUTE EXTENSION LABEL
+
+/* the reserved words... C++ extensions */
+%token <ttype> AGGR
+%token <itype> VISSPEC
+%token DELETE NEW OVERLOAD THIS OPERATOR CXX_TRUE CXX_FALSE
+%token NAMESPACE TYPENAME_KEYWORD USING
+%token LEFT_RIGHT TEMPLATE
+%token TYPEID DYNAMIC_CAST STATIC_CAST REINTERPRET_CAST CONST_CAST
+%token <itype> SCOPE
+
+/* Define the operator tokens and their precedences.
+ The value is an integer because, if used, it is the tree code
+ to use in the expression made from the operator. */
+
+%left EMPTY /* used to resolve s/r with epsilon */
+
+%left error
+
+/* Add precedence rules to solve dangling else s/r conflict */
+%nonassoc IF
+%nonassoc ELSE
+
+%left IDENTIFIER TYPENAME PTYPENAME SCSPEC TYPESPEC TYPE_QUAL ENUM AGGR ELLIPSIS TYPEOF SIGOF OPERATOR NSNAME TYPENAME_KEYWORD
+
+%left '{' ',' ';'
+
+%nonassoc THROW
+%right <code> ':'
+%right <code> ASSIGN '='
+%right <code> '?'
+%left <code> OROR
+%left <code> ANDAND
+%left <code> '|'
+%left <code> '^'
+%left <code> '&'
+%left <code> MIN_MAX
+%left <code> EQCOMPARE
+%left <code> ARITHCOMPARE '<' '>'
+%left <code> LSHIFT RSHIFT
+%left <code> '+' '-'
+%left <code> '*' '/' '%'
+%left <code> POINTSAT_STAR DOT_STAR
+%right <code> UNARY PLUSPLUS MINUSMINUS '~'
+%left HYPERUNARY
+%left <ttype> PAREN_STAR_PAREN LEFT_RIGHT
+%left <code> POINTSAT '.' '(' '['
+
+%right SCOPE /* C++ extension */
+%nonassoc NEW DELETE TRY CATCH
+
+%type <code> unop
+
+%type <ttype> identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist
+%type <ttype> paren_expr_or_null nontrivial_exprlist
+%type <ttype> expr_no_commas cast_expr unary_expr primary string STRING
+%type <ttype> typed_declspecs reserved_declspecs boolean.literal
+%type <ttype> typed_typespecs reserved_typespecquals
+%type <ttype> declmods typespec typespecqual_reserved
+%type <ttype> SCSPEC TYPESPEC TYPE_QUAL nonempty_type_quals maybe_type_qual
+%type <itype> initdecls notype_initdecls initdcl /* C++ modification */
+%type <ttype> init initlist maybeasm maybe_init
+%type <ttype> asm_operands nonnull_asm_operands asm_operand asm_clobbers
+%type <ttype> maybe_attribute attributes attribute attribute_list attrib
+%type <ttype> any_word
+
+%type <ttype> compstmt implicitly_scoped_stmt
+
+%type <ttype> declarator notype_declarator after_type_declarator
+%type <ttype> direct_notype_declarator direct_after_type_declarator
+
+%type <ttype> structsp opt.component_decl_list component_decl_list
+%type <ttype> component_decl component_decl_1 components notype_components
+%type <ttype> component_declarator component_declarator0
+%type <ttype> notype_component_declarator notype_component_declarator0
+%type <ttype> after_type_component_declarator after_type_component_declarator0
+%type <ttype> enumlist enumerator
+%type <ttype> type_id absdcl type_quals
+%type <ttype> direct_abstract_declarator conversion_declarator
+%type <ttype> new_type_id new_declarator direct_new_declarator
+%type <ttype> xexpr parmlist parms parm bad_parm full_parm
+%type <ttype> identifiers_or_typenames
+%type <ttype> fcast_or_absdcl regcast_or_absdcl
+%type <ttype> expr_or_declarator complex_notype_declarator
+%type <ttype> notype_unqualified_id unqualified_id qualified_id
+%type <ttype> overqualified_id notype_qualified_id any_id
+%type <ttype> complex_direct_notype_declarator functional_cast
+%type <ttype> named_parm complex_parmlist typed_declspecs1 parms_comma
+
+/* C++ extensions */
+%token <ttype> TYPENAME_ELLIPSIS PTYPENAME
+%token <ttype> PRE_PARSED_FUNCTION_DECL EXTERN_LANG_STRING ALL
+%token <ttype> PRE_PARSED_CLASS_DECL
+%type <ttype> fn.def1 /* Not really! */
+%type <ttype> fn.def2 return_id
+%type <itype> ctor_initializer_opt
+%type <ttype> named_class_head named_class_head_sans_basetype
+%type <ttype> named_complex_class_head_sans_basetype
+%type <ttype> unnamed_class_head
+%type <ttype> class_head base_class_list
+%type <itype> base_class_access_list
+%type <ttype> base_class maybe_base_class_list base_class.1
+%type <ttype> exception_specification_opt ansi_raise_identifier ansi_raise_identifiers
+%type <ttype> operator_name
+%type <ttype> object aggr
+%type <itype> new delete
+/* %type <ttype> primary_no_id */
+%type <ttype> nonmomentary_expr maybe_parmlist
+%type <itype> initdcl0 notype_initdcl0 member_init_list
+%type <ttype> template_header template_parm_list template_parm
+%type <ttype> template_type_parm
+%type <ttype> template_type template_arg_list template_arg
+%type <ttype> template_instantiation template_type_name tmpl.2
+%type <ttype> template_instantiate_once template_instantiate_some
+%type <itype> fn_tmpl_end
+/* %type <itype> try_for_typename */
+%type <ttype> condition xcond paren_cond_or_null
+%type <ttype> type_name nested_name_specifier nested_type ptr_to_mem
+%type <ttype> qualified_type_name complete_type_name notype_identifier
+%type <ttype> complex_type_name nested_name_specifier_1
+%type <itype> nomods_initdecls nomods_initdcl0
+%type <ttype> new_initializer new_placement specialization type_specifier_seq
+%type <ttype> using_decl .poplevel
+
+/* in order to recognize aggr tags as defining and thus shadowing. */
+%token TYPENAME_DEFN IDENTIFIER_DEFN PTYPENAME_DEFN
+%type <ttype> named_class_head_sans_basetype_defn
+%type <ttype> identifier_defn IDENTIFIER_DEFN TYPENAME_DEFN PTYPENAME_DEFN
+
+%token NSNAME
+%type <ttype> NSNAME
+
+/* Used in lex.c for parsing pragmas. */
+%token END_OF_LINE
+
+/* lex.c and pt.c depends on this being the last token. Define
+ any new tokens before this one! */
+%token END_OF_SAVED_INPUT
+
+%{
+/* List of types and structure classes of the current declaration. */
+static tree current_declspecs;
+/* List of prefix attributes in effect.
+ Prefix attributes are parsed by the reserved_declspecs and declmods
+ rules. They create a list that contains *both* declspecs and attrs. */
+/* ??? It is not clear yet that all cases where an attribute can now appear in
+ a declspec list have been updated. */
+static tree prefix_attributes;
+
+/* When defining an aggregate, this is the most recent one being defined. */
+static tree current_aggr;
+
+/* Tell yyparse how to print a token's value, if yydebug is set. */
+
+#define YYPRINT(FILE,YYCHAR,YYLVAL) yyprint(FILE,YYCHAR,YYLVAL)
+extern void yyprint ();
+extern tree combine_strings PROTO((tree));
+%}
+
+%%
+program: /* empty */
+ | extdefs
+ {
+ /* In case there were missing closebraces,
+ get us back to the global binding level. */
+ while (! global_bindings_p ())
+ poplevel (0, 0, 0);
+ finish_file ();
+ }
+ ;
+
+/* 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. */
+
+extdefs:
+ { $<ttype>$ = NULL_TREE; } lang_extdef
+ { $<ttype>$ = NULL_TREE; }
+ | extdefs lang_extdef
+ { $<ttype>$ = NULL_TREE; }
+ ;
+
+extdefs_opt:
+ extdefs
+ | /* empty */
+ ;
+
+.hush_warning:
+ { have_extern_spec = 1;
+ used_extern_spec = 0;
+ $<ttype>$ = NULL_TREE; }
+ ;
+.warning_ok:
+ { have_extern_spec = 0; }
+ ;
+
+asm_keyword:
+ ASM_KEYWORD
+ | GCC_ASM_KEYWORD
+ ;
+
+lang_extdef:
+ { if (pending_lang_change) do_pending_lang_change(); }
+ extdef
+ { if (! toplevel_bindings_p () && ! pseudo_global_level_p())
+ pop_everything (); }
+ ;
+
+extdef:
+ fndef
+ { if (pending_inlines) do_pending_inlines (); }
+ | datadef
+ { if (pending_inlines) do_pending_inlines (); }
+ | template_def
+ { if (pending_inlines) do_pending_inlines (); }
+ | overloaddef
+ | asm_keyword '(' string ')' ';'
+ { if (TREE_CHAIN ($3)) $3 = combine_strings ($3);
+ assemble_asm ($3); }
+ | extern_lang_string '{' extdefs_opt '}'
+ { pop_lang_context (); }
+ | extern_lang_string .hush_warning fndef .warning_ok
+ { if (pending_inlines) do_pending_inlines ();
+ pop_lang_context (); }
+ | extern_lang_string .hush_warning datadef .warning_ok
+ { if (pending_inlines) do_pending_inlines ();
+ pop_lang_context (); }
+ | NAMESPACE identifier '{'
+ { push_namespace ($2); }
+ extdefs_opt '}'
+ { pop_namespace (); }
+ | NAMESPACE '{'
+ { push_namespace (NULL_TREE); }
+ extdefs_opt '}'
+ { pop_namespace (); }
+ | NAMESPACE identifier '=' any_id ';'
+ { do_namespace_alias ($2, $4); }
+ | using_decl ';'
+ { do_toplevel_using_decl ($1); }
+ | USING NAMESPACE any_id ';'
+ { do_using_directive ($3); }
+ ;
+
+using_decl:
+ USING qualified_id
+ { $$ = $2; }
+ | USING global_scope qualified_id
+ { $$ = $3; }
+ | USING global_scope unqualified_id
+ { $$ = $3; }
+ ;
+
+any_id:
+ unqualified_id
+ | qualified_id
+ | global_scope qualified_id
+ { $$ = $2; }
+ | global_scope unqualified_id
+ { $$ = $2; }
+ ;
+
+extern_lang_string:
+ EXTERN_LANG_STRING
+ { push_lang_context ($1); }
+ | extern_lang_string EXTERN_LANG_STRING
+ { if (current_lang_name != $2)
+ cp_error ("use of linkage spec `%D' is different from previous spec `%D'", $2, current_lang_name);
+ pop_lang_context (); push_lang_context ($2); }
+ ;
+
+template_header:
+ TEMPLATE '<'
+ { begin_template_parm_list (); }
+ template_parm_list '>'
+ { $$ = end_template_parm_list ($4); }
+ ;
+
+template_parm_list:
+ template_parm
+ { $$ = process_template_parm (NULL_TREE, $1); }
+ | template_parm_list ',' template_parm
+ { $$ = process_template_parm ($1, $3); }
+ ;
+
+template_type_parm:
+ aggr
+ {
+ $$ = build_tree_list ($1, NULL_TREE);
+ ttpa:
+ if (TREE_PURPOSE ($$) == signature_type_node)
+ sorry ("signature as template type parameter");
+ else if (TREE_PURPOSE ($$) != class_type_node)
+ pedwarn ("template type parameters must use the keyword `class'");
+ }
+ | aggr identifier
+ { $$ = build_tree_list ($1, $2); goto ttpa; }
+ | TYPENAME_KEYWORD
+ { $$ = build_tree_list (class_type_node, NULL_TREE); }
+ | TYPENAME_KEYWORD identifier
+ { $$ = build_tree_list (class_type_node, $2); }
+ ;
+
+template_parm:
+ /* The following rules introduce a new reduce/reduce
+ conflict on the ',' and '>' input tokens: they are valid
+ prefixes for a `structsp', which means they could match a
+ nameless parameter. See 14.6, paragraph 3.
+ By putting them before the `parm' rule, we get
+ their match before considering them nameless parameter
+ declarations. */
+ template_type_parm
+ { $$ = build_tree_list (NULL_TREE, $$); }
+ | template_type_parm '=' typespec
+ { $$ = build_tree_list ($3, $$); }
+ | full_parm
+ ;
+
+overloaddef:
+ OVERLOAD ov_identifiers ';'
+ { warning ("use of `overload' is an anachronism"); }
+ ;
+
+ov_identifiers: IDENTIFIER
+ { declare_overloaded ($1); }
+ | ov_identifiers ',' IDENTIFIER
+ { declare_overloaded ($3); }
+ ;
+
+template_def:
+ /* Class template declarations go here; they aren't normal class
+ declarations, because we can't process the bodies yet. */
+ template_header named_class_head_sans_basetype '{'
+ { yychar = '{'; goto template1; }
+ ';'
+ | template_header named_class_head_sans_basetype_defn '{'
+ { yychar = '{'; goto template1; }
+ ';'
+ | template_header named_class_head_sans_basetype ':'
+ { yychar = ':'; goto template1; }
+ ';'
+ | template_header named_class_head_sans_basetype_defn ':'
+ {
+ yychar = ':';
+ template1:
+ if (current_aggr == signature_type_node)
+ sorry ("template type defining a signature");
+ /* Maybe pedantic warning for union?
+ How about an enum? :-) */
+ end_template_decl ($1, $2, current_aggr, 1);
+ reinit_parse_for_template (yychar, $1, $2);
+ yychar = YYEMPTY;
+ }
+ ';'
+ | template_header named_class_head_sans_basetype ';'
+ {
+ end_template_decl ($1, $2, current_aggr, 0);
+ /* declare $2 as template name with $1 parm list */
+ }
+ | template_header named_class_head_sans_basetype_defn ';'
+ {
+ end_template_decl ($1, $2, current_aggr, 0);
+ /* declare $2 as template name with $1 parm list */
+ }
+ | template_header /* notype_initdcl0 ';' */
+ notype_declarator exception_specification_opt maybeasm maybe_attribute
+ fn_tmpl_end
+ {
+ tree d;
+ int momentary;
+ int def = ($6 != ';');
+ momentary = suspend_momentary ();
+ d = start_decl ($<ttype>2, /*current_declspecs*/NULL_TREE, 0,
+ $3);
+ cplus_decl_attributes (d, $5, /*prefix_attributes*/NULL_TREE);
+ cp_finish_decl (d, NULL_TREE, $4, 0, 0);
+ end_template_decl ($1, d, 0, def);
+ if (def)
+ reinit_parse_for_template ((int) $6, $1, d);
+ resume_momentary (momentary);
+ }
+ | template_header typed_declspecs /*initdcl0*/
+ declarator exception_specification_opt maybeasm maybe_attribute
+ fn_tmpl_end
+ {
+ tree d, specs, attrs;
+ int momentary;
+ int def = ($7 != ';');
+ split_specs_attrs ($2, &specs, &attrs);
+ momentary = suspend_momentary ();
+ d = start_decl ($<ttype>3, specs, 0, $<ttype>4);
+ cplus_decl_attributes (d, $6, attrs);
+ cp_finish_decl (d, NULL_TREE, $5, 0, 0);
+ end_template_decl ($1, d, 0, def);
+ if (def)
+ {
+ reinit_parse_for_template ((int) $7, $1, d);
+ yychar = YYEMPTY;
+ }
+ note_list_got_semicolon ($<ttype>2);
+ resume_momentary (momentary);
+ }
+ | template_header declmods notype_declarator fn_tmpl_end
+ {
+ tree d, specs, attrs;
+ int def = ($4 != ';');
+ split_specs_attrs ($2, &specs, &attrs);
+ d = start_decl ($<ttype>3, specs, 0, NULL_TREE);
+ cplus_decl_attributes (d, NULL_TREE, attrs);
+ cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
+ end_template_decl ($1, d, 0, def);
+ if (def)
+ reinit_parse_for_template ((int) $4, $1, d);
+ }
+ /* Try to recover from syntax errors in templates. */
+ | template_header error '}' { end_template_decl ($1, 0, 0, 0); }
+ | template_header error ';' { end_template_decl ($1, 0, 0, 0); }
+ ;
+
+fn_tmpl_end: '{' { $$ = '{'; }
+ | ':' { $$ = ':'; }
+ | ';' { $$ = ';'; }
+ | '=' { $$ = '='; }
+ | RETURN { $$ = RETURN; }
+ ;
+
+datadef:
+ nomods_initdecls ';'
+ {}
+ | declmods notype_initdecls ';'
+ {}
+ /* Normal case to make fast: "const i;". */
+ | declmods notype_declarator ';'
+ { tree d, specs, attrs;
+ split_specs_attrs ($1, &specs, &attrs);
+ d = start_decl ($<ttype>2, specs, 0, NULL_TREE);
+ cplus_decl_attributes (d, NULL_TREE, attrs);
+ cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
+ }
+ | typed_declspecs initdecls ';'
+ {
+ note_list_got_semicolon ($<ttype>$);
+ }
+ /* Normal case: make this fast. */
+ | typed_declspecs declarator ';'
+ { tree d, specs, attrs;
+ split_specs_attrs ($1, &specs, &attrs);
+ d = start_decl ($<ttype>2, specs, 0, NULL_TREE);
+ cplus_decl_attributes (d, NULL_TREE, attrs);
+ cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
+ note_list_got_semicolon ($<ttype>$);
+ }
+ | declmods ';'
+ { pedwarn ("empty declaration"); }
+ | explicit_instantiation ';'
+ | typed_declspecs ';'
+ {
+ tree t, attrs;
+ split_specs_attrs ($1, &t, &attrs);
+ shadow_tag (t);
+ if (TREE_CODE (t) == TREE_LIST
+ && TREE_PURPOSE (t) == NULL_TREE)
+ {
+ t = TREE_VALUE (t);
+ if (IS_AGGR_TYPE (t)
+ && IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (t)))
+ {
+ if (CLASSTYPE_USE_TEMPLATE (t) == 0)
+ SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (t);
+ else if (CLASSTYPE_TEMPLATE_INSTANTIATION (t))
+ error ("override declaration for already-expanded template");
+ }
+ }
+ note_list_got_semicolon ($<ttype>$);
+ }
+ | error ';'
+ | error '}'
+ | ';'
+ ;
+
+ctor_initializer_opt:
+ nodecls
+ { $$ = 0; }
+ | base_init
+ { $$ = 1; }
+ ;
+
+maybe_return_init:
+ /* empty */
+ | return_init
+ | return_init ';'
+ ;
+
+eat_saved_input:
+ /* empty */
+ | END_OF_SAVED_INPUT
+ ;
+
+fndef:
+ fn.def1 maybe_return_init ctor_initializer_opt compstmt_or_error
+ {
+ finish_function (lineno, (int)$3, 0);
+ if ($<ttype>$) process_next_inline ($<ttype>$);
+ }
+ | fn.def1 maybe_return_init function_try_block
+ {
+ if ($<ttype>$) process_next_inline ($<ttype>$);
+ }
+ eat_saved_input
+ | typed_declspecs declarator error
+ {}
+ | declmods notype_declarator error
+ {}
+ | notype_declarator error
+ {}
+ ;
+
+fn.def1:
+ typed_declspecs declarator exception_specification_opt
+ { tree specs, attrs;
+ split_specs_attrs ($1, &specs, &attrs);
+ if (! start_function (specs, $2, $3, attrs, 0))
+ YYERROR1;
+ reinit_parse_for_function ();
+ $$ = NULL_TREE; }
+ | declmods notype_declarator exception_specification_opt
+ { tree specs = strip_attrs ($1);
+ if (! start_function (specs, $2, $3, NULL_TREE, 0))
+ YYERROR1;
+ reinit_parse_for_function ();
+ $$ = NULL_TREE; }
+ | notype_declarator exception_specification_opt
+ { if (! start_function (NULL_TREE, $$, $2, NULL_TREE, 0))
+ YYERROR1;
+ reinit_parse_for_function ();
+ $$ = NULL_TREE; }
+ | PRE_PARSED_FUNCTION_DECL
+ { start_function (NULL_TREE, TREE_VALUE ($$),
+ NULL_TREE, NULL_TREE, 1);
+ reinit_parse_for_function (); }
+ ;
+
+/* more C++ complexity. See component_decl for a comment on the
+ reduce/reduce conflict introduced by these rules. */
+fn.def2:
+ typed_declspecs '(' parmlist ')' type_quals exception_specification_opt
+ { tree specs = strip_attrs ($1);
+ $$ = build_parse_node (CALL_EXPR, TREE_VALUE (specs), $3, $5);
+ $$ = start_method (TREE_CHAIN (specs), $$, $6);
+ rest_of_mdef:
+ if (! $$)
+ YYERROR1;
+ if (yychar == YYEMPTY)
+ yychar = YYLEX;
+ reinit_parse_for_method (yychar, $$); }
+ | typed_declspecs LEFT_RIGHT type_quals exception_specification_opt
+ { tree specs = strip_attrs ($1);
+ $$ = build_parse_node (CALL_EXPR, TREE_VALUE (specs),
+ empty_parms (), $3);
+ $$ = start_method (TREE_CHAIN (specs), $$, $4);
+ goto rest_of_mdef;
+ }
+ | typed_declspecs declarator exception_specification_opt
+ { tree specs = strip_attrs ($1);
+ $$ = start_method (specs, $2, $3); goto rest_of_mdef; }
+ | declmods notype_declarator exception_specification_opt
+ { tree specs = strip_attrs ($1);
+ $$ = start_method (specs, $2, $3); goto rest_of_mdef; }
+ | notype_declarator exception_specification_opt
+ { $$ = start_method (NULL_TREE, $$, $2); goto rest_of_mdef; }
+ ;
+
+return_id: RETURN IDENTIFIER
+ {
+ if (! current_function_parms_stored)
+ store_parm_decls ();
+ $$ = $2;
+ }
+ ;
+
+return_init: return_id maybe_init
+ { store_return_init ($<ttype>$, $2); }
+ | return_id '(' nonnull_exprlist ')'
+ { store_return_init ($<ttype>$, $3); }
+ | return_id LEFT_RIGHT
+ { store_return_init ($<ttype>$, NULL_TREE); }
+ ;
+
+base_init:
+ ':' .set_base_init member_init_list
+ {
+ if ($3 == 0)
+ error ("no base initializers given following ':'");
+ setup_vtbl_ptr ();
+ /* Always keep the BLOCK node associated with the outermost
+ pair of curley braces of a function. These are needed
+ for correct operation of dwarfout.c. */
+ keep_next_level ();
+ }
+ ;
+
+.set_base_init:
+ /* empty */
+ {
+ if (! current_function_parms_stored)
+ store_parm_decls ();
+
+ if (DECL_CONSTRUCTOR_P (current_function_decl))
+ {
+ /* Make a contour for the initializer list. */
+ pushlevel (0);
+ clear_last_expr ();
+ expand_start_bindings (0);
+ }
+ else if (current_class_type == NULL_TREE)
+ error ("base initializers not allowed for non-member functions");
+ else if (! DECL_CONSTRUCTOR_P (current_function_decl))
+ error ("only constructors take base initializers");
+ }
+ ;
+
+member_init_list:
+ /* empty */
+ { $$ = 0; }
+ | member_init
+ { $$ = 1; }
+ | member_init_list ',' member_init
+ | member_init_list error
+ ;
+
+member_init: '(' nonnull_exprlist ')'
+ {
+ if (current_class_name && !flag_traditional)
+ pedwarn ("anachronistic old style base class initializer");
+ expand_member_init (C_C_D, NULL_TREE, $2);
+ }
+ | LEFT_RIGHT
+ {
+ if (current_class_name && !flag_traditional)
+ pedwarn ("anachronistic old style base class initializer");
+ expand_member_init (C_C_D, NULL_TREE, void_type_node);
+ }
+ | notype_identifier '(' nonnull_exprlist ')'
+ { expand_member_init (C_C_D, $<ttype>$, $3); }
+ | notype_identifier LEFT_RIGHT
+ { expand_member_init (C_C_D, $<ttype>$, void_type_node); }
+ | complete_type_name '(' nonnull_exprlist ')'
+ { expand_member_init (C_C_D, $<ttype>$, $3); }
+ | complete_type_name LEFT_RIGHT
+ { expand_member_init (C_C_D, $<ttype>$, void_type_node); }
+ /* GNU extension */
+ | notype_qualified_id '(' nonnull_exprlist ')'
+ {
+ do_member_init (OP0 ($1), OP1 ($1), $3);
+ }
+ | notype_qualified_id LEFT_RIGHT
+ {
+ do_member_init (OP0 ($1), OP1 ($1), void_type_node);
+ }
+ ;
+
+identifier:
+ IDENTIFIER
+ | TYPENAME
+ | PTYPENAME
+ | NSNAME
+ ;
+
+notype_identifier:
+ IDENTIFIER
+ | PTYPENAME
+ | NSNAME %prec EMPTY
+ ;
+
+identifier_defn:
+ IDENTIFIER_DEFN
+ | TYPENAME_DEFN
+ | PTYPENAME_DEFN
+ ;
+
+explicit_instantiation:
+ TEMPLATE specialization template_instantiation
+ { do_type_instantiation ($3 ? $3 : $2, NULL_TREE); }
+ | TEMPLATE typed_declspecs declarator
+ { tree specs = strip_attrs ($2);
+ do_function_instantiation (specs, $3, NULL_TREE); }
+ | TEMPLATE notype_declarator
+ { do_function_instantiation (NULL_TREE, $2, NULL_TREE); }
+ | SCSPEC TEMPLATE specialization template_instantiation
+ { do_type_instantiation ($4 ? $4 : $3, $1); }
+ | SCSPEC TEMPLATE typed_declspecs declarator
+ { tree specs = strip_attrs ($3);
+ do_function_instantiation (specs, $4, $1); }
+ | SCSPEC TEMPLATE notype_declarator
+ { do_function_instantiation (NULL_TREE, $3, $1); }
+ ;
+
+template_type:
+ template_type_name tmpl.2 template_instantiation
+ { if ($3) $$ = $3; }
+ ;
+
+template_type_name:
+ PTYPENAME '<' template_arg_list '>'
+ { $$ = lookup_template_class ($$, $3, NULL_TREE); }
+ | PTYPENAME '<' '>'
+ { $$ = lookup_template_class ($$, NULL_TREE, NULL_TREE); }
+ | TYPENAME '<' template_arg_list '>'
+ { $$ = lookup_template_class ($$, $3, NULL_TREE); }
+ ;
+
+tmpl.2:
+ /* empty */ %prec EMPTY
+ { $$ = instantiate_class_template ($<ttype>0, 1); }
+ ;
+
+template_arg_list:
+ template_arg
+ { $$ = build_tree_list (NULL_TREE, $$); }
+ | template_arg_list ',' template_arg
+ { $$ = chainon ($$, build_tree_list (NULL_TREE, $3)); }
+ ;
+
+template_arg:
+ type_id
+ { $$ = groktypename ($$); }
+ | expr_no_commas %prec UNARY
+ ;
+
+template_instantiate_once:
+ PRE_PARSED_CLASS_DECL maybe_base_class_list
+ {
+ tree t, decl, tmpl;
+
+ tmpl = TREE_PURPOSE (IDENTIFIER_TEMPLATE ($1));
+ t = xref_tag (DECL_TEMPLATE_INFO (tmpl)->aggr, $1, $2, 0);
+ set_current_level_tags_transparency (1);
+ my_friendly_assert (TREE_CODE (t) == RECORD_TYPE
+ || TREE_CODE (t) == UNION_TYPE, 257);
+ $<ttype>$ = t;
+
+ /* Now, put a copy of the decl in global scope, to avoid
+ recursive expansion. */
+ decl = IDENTIFIER_LOCAL_VALUE ($1);
+ if (!decl)
+ decl = IDENTIFIER_CLASS_VALUE ($1);
+ /* Now, put a copy of the decl in global scope, to avoid
+ recursive expansion. */
+ if (decl)
+ {
+ /* Need to copy it to clear the chain pointer,
+ and need to get it into permanent storage. */
+ my_friendly_assert (TREE_CODE (decl) == TYPE_DECL, 258);
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ decl = copy_node (decl);
+ if (DECL_LANG_SPECIFIC (decl))
+ copy_lang_decl (decl);
+ pop_obstacks ();
+ pushdecl_top_level (decl);
+ }
+ /* Kludge; see instantiate_class_template. */
+ TYPE_BEING_DEFINED (t) = 0;
+ }
+ left_curly opt.component_decl_list '}'
+ {
+ tree t = finish_struct ($<ttype>3, $5, 0);
+
+ pop_obstacks ();
+ end_template_instantiation ($1);
+
+ repo_template_used (t);
+
+ /* Now go after the methods & class data. */
+ instantiate_member_templates ($1);
+
+ pop_tinst_level();
+
+ CLASSTYPE_GOT_SEMICOLON (t) = 1;
+ }
+ ;
+
+template_instantiation:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | template_instantiate_once
+ { $$ = $1; }
+ ;
+
+template_instantiate_some:
+ /* empty */
+ { $$ = NULL_TREE; /* never used from here... */}
+ | template_instantiate_once template_instantiate_some
+ { $$ = $1; /*???*/ }
+ ;
+
+unop: '-'
+ { $$ = NEGATE_EXPR; }
+ | '+'
+ { $$ = CONVERT_EXPR; }
+ | PLUSPLUS
+ { $$ = PREINCREMENT_EXPR; }
+ | MINUSMINUS
+ { $$ = PREDECREMENT_EXPR; }
+ | '!'
+ { $$ = TRUTH_NOT_EXPR; }
+ ;
+
+expr: nontrivial_exprlist
+ { $$ = build_x_compound_expr ($$); }
+ | expr_no_commas
+ ;
+
+paren_expr_or_null:
+ LEFT_RIGHT
+ { error ("ANSI C++ forbids an empty condition for `%s'",
+ cond_stmt_keyword);
+ $$ = integer_zero_node; }
+ | '(' expr ')'
+ { $$ = condition_conversion ($2); }
+ ;
+
+paren_cond_or_null:
+ LEFT_RIGHT
+ { error ("ANSI C++ forbids an empty condition for `%s'",
+ cond_stmt_keyword);
+ $$ = integer_zero_node; }
+ | '(' condition ')'
+ { $$ = condition_conversion ($2); }
+ ;
+
+xcond:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | condition
+ { $$ = condition_conversion ($$); }
+ | error
+ { $$ = NULL_TREE; }
+ ;
+
+condition:
+ type_specifier_seq declarator exception_specification_opt maybeasm maybe_attribute '='
+ { {
+ tree d;
+ for (d = getdecls (); d; d = TREE_CHAIN (d))
+ if (TREE_CODE (d) == TYPE_DECL) {
+ tree s = TREE_TYPE (d);
+ if (TREE_CODE (s) == RECORD_TYPE)
+ cp_error ("definition of class `%T' in condition", s);
+ else if (TREE_CODE (s) == ENUMERAL_TYPE)
+ cp_error ("definition of enum `%T' in condition", s);
+ }
+ }
+ current_declspecs = $1;
+ $<itype>6 = suspend_momentary ();
+ $<ttype>$ = start_decl ($<ttype>2, current_declspecs, 1, $3);
+ cplus_decl_attributes ($<ttype>$, $5,
+ /*prefix_attributes*/ NULL_TREE);
+ }
+ init
+ {
+ cp_finish_decl ($<ttype>7, $8, $5, 0, LOOKUP_ONLYCONVERTING);
+ resume_momentary ($<itype>6);
+ $$ = $<ttype>7;
+ if (TREE_CODE (TREE_TYPE ($$)) == ARRAY_TYPE)
+ cp_error ("definition of array `%#D' in condition", $$);
+ }
+ | expr
+ ;
+
+compstmtend:
+ '}'
+ | maybe_label_decls stmts '}'
+ | maybe_label_decls stmts error '}'
+ | maybe_label_decls error '}'
+ ;
+
+already_scoped_stmt:
+ '{' compstmtend
+ { finish_stmt (); }
+ | simple_stmt
+ ;
+
+
+nontrivial_exprlist:
+ expr_no_commas ',' expr_no_commas
+ { $$ = tree_cons (NULL_TREE, $$,
+ build_tree_list (NULL_TREE, $3)); }
+ | expr_no_commas ',' error
+ { $$ = tree_cons (NULL_TREE, $$,
+ build_tree_list (NULL_TREE, error_mark_node)); }
+ | nontrivial_exprlist ',' expr_no_commas
+ { chainon ($$, build_tree_list (NULL_TREE, $3)); }
+ | nontrivial_exprlist ',' error
+ { chainon ($$, build_tree_list (NULL_TREE, error_mark_node)); }
+ ;
+
+nonnull_exprlist:
+ expr_no_commas
+ { $$ = build_tree_list (NULL_TREE, $$); }
+ | nontrivial_exprlist
+ ;
+
+unary_expr:
+ primary %prec UNARY
+ {
+#if 0
+ if (TREE_CODE ($$) == TYPE_EXPR)
+ $$ = build_component_type_expr (C_C_D, $$, NULL_TREE, 1);
+#endif
+ }
+ /* __extension__ turns off -pedantic for following primary. */
+ | EXTENSION
+ { $<itype>1 = pedantic;
+ pedantic = 0; }
+ cast_expr %prec UNARY
+ { $$ = $3;
+ pedantic = $<itype>1; }
+ | '*' cast_expr %prec UNARY
+ { $$ = build_x_indirect_ref ($2, "unary *"); }
+ | '&' cast_expr %prec UNARY
+ { $$ = build_x_unary_op (ADDR_EXPR, $2); }
+ | '~' cast_expr
+ { $$ = build_x_unary_op (BIT_NOT_EXPR, $2); }
+ | unop cast_expr %prec UNARY
+ { $$ = build_x_unary_op ($1, $2);
+ if ($1 == NEGATE_EXPR && TREE_CODE ($2) == INTEGER_CST)
+ TREE_NEGATED_INT ($$) = 1;
+ overflow_warning ($$);
+ }
+ /* Refer to the address of a label as a pointer. */
+ | ANDAND identifier
+ { tree label = lookup_label ($2);
+ if (label == NULL_TREE)
+ $$ = null_pointer_node;
+ else
+ {
+ TREE_USED (label) = 1;
+ $$ = build1 (ADDR_EXPR, ptr_type_node, label);
+ TREE_CONSTANT ($$) = 1;
+ }
+ }
+ | SIZEOF unary_expr %prec UNARY
+ { if (TREE_CODE ($2) == COMPONENT_REF
+ && DECL_BIT_FIELD (TREE_OPERAND ($2, 1)))
+ error ("sizeof applied to a bit-field");
+ /* ANSI says arrays and functions are converted inside comma.
+ But we can't really convert them in build_compound_expr
+ because that would break commas in lvalues.
+ So do the conversion here if operand was a comma. */
+ if (TREE_CODE ($2) == COMPOUND_EXPR
+ && (TREE_CODE (TREE_TYPE ($2)) == ARRAY_TYPE
+ || TREE_CODE (TREE_TYPE ($2)) == FUNCTION_TYPE))
+ $2 = default_conversion ($2);
+ else if (TREE_CODE ($2) == TREE_LIST)
+ {
+ tree t = TREE_VALUE ($2);
+ if (t != NULL_TREE
+ && ((TREE_TYPE (t)
+ && TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
+ || is_overloaded_fn (t)))
+ pedwarn ("ANSI C++ forbids taking the sizeof a function type");
+ }
+ $$ = c_sizeof (TREE_TYPE ($2)); }
+ | SIZEOF '(' type_id ')' %prec HYPERUNARY
+ { $$ = c_sizeof (groktypename ($3)); }
+ | ALIGNOF unary_expr %prec UNARY
+ { $$ = grok_alignof ($2); }
+ | ALIGNOF '(' type_id ')' %prec HYPERUNARY
+ { $$ = c_alignof (groktypename ($3)); }
+
+ /* The %prec EMPTY's here are required by the = init initializer
+ syntax extension; see below. */
+ | new new_type_id %prec EMPTY
+ { $$ = build_new (NULL_TREE, $2, NULL_TREE, $1); }
+ | new new_type_id new_initializer
+ { $$ = build_new (NULL_TREE, $2, $3, $1); }
+ | new new_placement new_type_id %prec EMPTY
+ { $$ = build_new ($2, $3, NULL_TREE, $1); }
+ | new new_placement new_type_id new_initializer
+ { $$ = build_new ($2, $3, $4, $1); }
+ | new '(' type_id ')' %prec EMPTY
+ { $$ = build_new (NULL_TREE, groktypename($3),
+ NULL_TREE, $1); }
+ | new '(' type_id ')' new_initializer
+ { $$ = build_new (NULL_TREE, groktypename($3), $5, $1); }
+ | new new_placement '(' type_id ')' %prec EMPTY
+ { $$ = build_new ($2, groktypename($4), NULL_TREE, $1); }
+ | new new_placement '(' type_id ')' new_initializer
+ { $$ = build_new ($2, groktypename($4), $6, $1); }
+
+ | delete cast_expr %prec UNARY
+ { $$ = delete_sanity ($2, NULL_TREE, 0, $1); }
+ | delete '[' ']' cast_expr %prec UNARY
+ { $$ = delete_sanity ($4, NULL_TREE, 1, $1);
+ if (yychar == YYEMPTY)
+ yychar = YYLEX; }
+ | delete '[' expr ']' cast_expr %prec UNARY
+ { $$ = delete_sanity ($5, $3, 2, $1);
+ if (yychar == YYEMPTY)
+ yychar = YYLEX; }
+ ;
+
+new_placement:
+ '(' nonnull_exprlist ')'
+ { $$ = $2; }
+ | '{' nonnull_exprlist '}'
+ {
+ $$ = $2;
+ pedwarn ("old style placement syntax, use () instead");
+ }
+ ;
+
+new_initializer:
+ '(' nonnull_exprlist ')'
+ { $$ = $2; }
+ | LEFT_RIGHT
+ { $$ = NULL_TREE; }
+ | '(' typespec ')'
+ {
+ cp_error ("`%T' is not a valid expression", $2);
+ $$ = error_mark_node;
+ }
+ /* GNU extension so people can use initializer lists. Note that
+ this alters the meaning of `new int = 1', which was previously
+ syntactically valid but semantically invalid. */
+ | '=' init
+ {
+ if (pedantic)
+ pedwarn ("ANSI C++ forbids initialization of new expression with `='");
+ $$ = $2;
+ }
+ ;
+
+/* This is necessary to postpone reduction of `int ((int)(int)(int))'. */
+regcast_or_absdcl:
+ '(' type_id ')' %prec EMPTY
+ { $2 = tree_cons (NULL_TREE, $2, void_list_node);
+ TREE_PARMLIST ($2) = 1;
+ $$ = build_parse_node (CALL_EXPR, NULL_TREE, $2,
+ NULL_TREE); }
+ | regcast_or_absdcl '(' type_id ')' %prec EMPTY
+ { $3 = tree_cons (NULL_TREE, $3, void_list_node);
+ TREE_PARMLIST ($3) = 1;
+ $$ = build_parse_node (CALL_EXPR, $$, $3, NULL_TREE); }
+ ;
+
+cast_expr:
+ unary_expr
+ | regcast_or_absdcl unary_expr %prec UNARY
+ { $$ = reparse_absdcl_as_casts ($$, $2); }
+ | regcast_or_absdcl '{' initlist maybecomma '}' %prec UNARY
+ {
+ tree init = build_nt (CONSTRUCTOR, NULL_TREE,
+ nreverse ($3));
+ if (pedantic)
+ pedwarn ("ANSI C++ forbids constructor-expressions");
+ /* Indicate that this was a GNU C constructor expression. */
+ TREE_HAS_CONSTRUCTOR (init) = 1;
+
+ $$ = reparse_absdcl_as_casts ($$, init);
+ }
+ ;
+
+expr_no_commas:
+ cast_expr
+ /* Handle general members. */
+ | expr_no_commas POINTSAT_STAR expr_no_commas
+ { $$ = build_x_binary_op (MEMBER_REF, $$, $3); }
+ | expr_no_commas DOT_STAR expr_no_commas
+ { $$ = build_m_component_ref ($$, $3); }
+ | expr_no_commas '+' expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas '-' expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas '*' expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas '/' expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas '%' expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas LSHIFT expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas RSHIFT expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas ARITHCOMPARE expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas '<' expr_no_commas
+ { $$ = build_x_binary_op (LT_EXPR, $$, $3); }
+ | expr_no_commas '>' expr_no_commas
+ { $$ = build_x_binary_op (GT_EXPR, $$, $3); }
+ | expr_no_commas EQCOMPARE expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas MIN_MAX expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas '&' expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas '|' expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas '^' expr_no_commas
+ { $$ = build_x_binary_op ($2, $$, $3); }
+ | expr_no_commas ANDAND expr_no_commas
+ { $$ = build_x_binary_op (TRUTH_ANDIF_EXPR, $$, $3); }
+ | expr_no_commas OROR expr_no_commas
+ { $$ = build_x_binary_op (TRUTH_ORIF_EXPR, $$, $3); }
+ | expr_no_commas '?' xexpr ':' expr_no_commas
+ { $$ = build_x_conditional_expr ($$, $3, $5); }
+ | expr_no_commas '=' expr_no_commas
+ { $$ = build_modify_expr ($$, NOP_EXPR, $3);
+ C_SET_EXP_ORIGINAL_CODE ($$, MODIFY_EXPR); }
+ | expr_no_commas ASSIGN expr_no_commas
+ { register tree rval;
+ if ((rval = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, $$, $3,
+ make_node ($2))))
+ $$ = rval;
+ else
+ $$ = build_modify_expr ($$, $2, $3); }
+ | THROW
+ { $$ = build_throw (NULL_TREE); }
+ | THROW expr_no_commas
+ { $$ = build_throw ($2); }
+/* These extensions are not defined. The second arg to build_m_component_ref
+ is old, build_m_component_ref now does an implicit
+ build_indirect_ref (x, NULL_PTR) on the second argument.
+ | object '&' expr_no_commas %prec UNARY
+ { $$ = build_m_component_ref ($$, build_x_unary_op (ADDR_EXPR, $3)); }
+ | object unop expr_no_commas %prec UNARY
+ { $$ = build_m_component_ref ($$, build_x_unary_op ($2, $3)); }
+ | object '(' type_id ')' expr_no_commas %prec UNARY
+ { tree type = groktypename ($3);
+ $$ = build_m_component_ref ($$, build_c_cast (type, $5, 0)); }
+ | object primary_no_id %prec UNARY
+ { $$ = build_m_component_ref ($$, $2); }
+*/
+ ;
+
+notype_unqualified_id:
+ '~' see_typename identifier
+ { $$ = build_parse_node (BIT_NOT_EXPR, $3); }
+ | operator_name
+ | IDENTIFIER
+ | PTYPENAME
+ | NSNAME %prec EMPTY
+ ;
+
+unqualified_id:
+ notype_unqualified_id
+ | TYPENAME
+ ;
+
+expr_or_declarator:
+ notype_unqualified_id
+ | '*' expr_or_declarator %prec UNARY
+ { $$ = build_parse_node (INDIRECT_REF, $2); }
+ | '&' expr_or_declarator %prec UNARY
+ { $$ = build_parse_node (ADDR_EXPR, $2); }
+ | '(' expr_or_declarator ')'
+ { $$ = $2; }
+ ;
+
+direct_notype_declarator:
+ complex_direct_notype_declarator
+ | notype_unqualified_id
+ | '(' expr_or_declarator ')'
+ { $$ = finish_decl_parsing ($2); }
+ ;
+
+primary:
+ notype_unqualified_id
+ {
+ if (TREE_CODE ($$) == BIT_NOT_EXPR)
+ $$ = build_x_unary_op (BIT_NOT_EXPR, TREE_OPERAND ($$, 0));
+ else if (IDENTIFIER_OPNAME_P ($$))
+ {
+ tree op = $$;
+ $$ = lookup_name (op, 0);
+ if ($$ == NULL_TREE)
+ {
+ if (op != ansi_opname[ERROR_MARK])
+ error ("operator %s not defined",
+ operator_name_string (op));
+ $$ = error_mark_node;
+ }
+ }
+ else
+ $$ = do_identifier ($$);
+ }
+ | CONSTANT
+ | boolean.literal
+ | string
+ { $$ = combine_strings ($$); }
+ | '(' expr ')'
+ { char class;
+ $$ = $2;
+ class = TREE_CODE_CLASS (TREE_CODE ($$));
+ if (class == 'e' || class == '1'
+ || class == '2' || class == '<')
+ /* This inhibits warnings in truthvalue_conversion. */
+ C_SET_EXP_ORIGINAL_CODE ($$, ERROR_MARK); }
+ | '(' expr_or_declarator ')'
+ { char class;
+ $$ = reparse_decl_as_expr (NULL_TREE, $2);
+ class = TREE_CODE_CLASS (TREE_CODE ($$));
+ if (class == 'e' || class == '1'
+ || class == '2' || class == '<')
+ /* This inhibits warnings in truthvalue_conversion. */
+ C_SET_EXP_ORIGINAL_CODE ($$, ERROR_MARK); }
+ | '(' error ')'
+ { $$ = error_mark_node; }
+ | '('
+ { if (current_function_decl == 0)
+ {
+ error ("braced-group within expression allowed only inside a function");
+ YYERROR;
+ }
+ keep_next_level ();
+ $<ttype>$ = expand_start_stmt_expr (); }
+ compstmt ')'
+ { tree rtl_exp;
+ if (pedantic)
+ pedwarn ("ANSI C++ forbids braced-groups within expressions");
+ rtl_exp = expand_end_stmt_expr ($<ttype>2);
+ /* The statements have side effects, so the group does. */
+ TREE_SIDE_EFFECTS (rtl_exp) = 1;
+
+ if (TREE_CODE ($3) == BLOCK)
+ {
+ /* Make a BIND_EXPR for the BLOCK already made. */
+ $$ = build (BIND_EXPR, TREE_TYPE (rtl_exp),
+ NULL_TREE, rtl_exp, $3);
+ /* Remove the block from the tree at this point.
+ It gets put back at the proper place
+ when the BIND_EXPR is expanded. */
+ delete_block ($3);
+ }
+ else
+ $$ = $3;
+ }
+ | primary '(' nonnull_exprlist ')'
+ { /* [eichin:19911016.1902EST] */
+ $<ttype>$ = build_x_function_call ($1, $3, current_class_decl);
+ /* here we instantiate_class_template as needed... */
+ do_pending_templates ();
+ } template_instantiate_some {
+ if (TREE_CODE ($<ttype>5) == CALL_EXPR
+ && TREE_TYPE ($<ttype>5) != void_type_node)
+ $$ = require_complete_type ($<ttype>5);
+ else
+ $$ = $<ttype>5;
+ }
+ | primary LEFT_RIGHT
+ {
+ $$ = build_x_function_call ($$, NULL_TREE, current_class_decl);
+ if (TREE_CODE ($$) == CALL_EXPR
+ && TREE_TYPE ($$) != void_type_node)
+ $$ = require_complete_type ($$);
+ }
+ | primary '[' expr ']'
+ { $$ = grok_array_decl ($$, $3); }
+ | primary PLUSPLUS
+ { /* If we get an OFFSET_REF, turn it into what it really
+ means (e.g., a COMPONENT_REF). This way if we've got,
+ say, a reference to a static member that's being operated
+ on, we don't end up trying to find a member operator for
+ the class it's in. */
+ if (TREE_CODE ($$) == OFFSET_REF)
+ $$ = resolve_offset_ref ($$);
+ $$ = build_x_unary_op (POSTINCREMENT_EXPR, $$); }
+ | primary MINUSMINUS
+ { if (TREE_CODE ($$) == OFFSET_REF)
+ $$ = resolve_offset_ref ($$);
+ $$ = build_x_unary_op (POSTDECREMENT_EXPR, $$); }
+ /* C++ extensions */
+ | THIS
+ { if (current_class_decl)
+ {
+#ifdef WARNING_ABOUT_CCD
+ TREE_USED (current_class_decl) = 1;
+#endif
+ $$ = current_class_decl;
+ }
+ else if (current_function_decl
+ && DECL_STATIC_FUNCTION_P (current_function_decl))
+ {
+ error ("`this' is unavailable for static member functions");
+ $$ = error_mark_node;
+ }
+ else
+ {
+ if (current_function_decl)
+ error ("invalid use of `this' in non-member function");
+ else
+ error ("invalid use of `this' at top level");
+ $$ = error_mark_node;
+ }
+ }
+ | TYPE_QUAL '(' nonnull_exprlist ')'
+ {
+ tree type;
+ tree id = $$;
+
+ /* This is a C cast in C++'s `functional' notation. */
+ if ($3 == error_mark_node)
+ {
+ $$ = error_mark_node;
+ break;
+ }
+#if 0
+ if ($3 == NULL_TREE)
+ {
+ error ("cannot cast null list to type `%s'",
+ IDENTIFIER_POINTER (TYPE_NAME (id)));
+ $$ = error_mark_node;
+ break;
+ }
+#endif
+#if 0
+ /* type is not set! (mrs) */
+ if (type == error_mark_node)
+ $$ = error_mark_node;
+ else
+#endif
+ {
+ if (id == ridpointers[(int) RID_CONST])
+ type = build_type_variant (integer_type_node, 1, 0);
+ else if (id == ridpointers[(int) RID_VOLATILE])
+ type = build_type_variant (integer_type_node, 0, 1);
+#if 0
+ /* should not be able to get here (mrs) */
+ else if (id == ridpointers[(int) RID_FRIEND])
+ {
+ error ("cannot cast expression to `friend' type");
+ $$ = error_mark_node;
+ break;
+ }
+#endif
+ else my_friendly_abort (79);
+ $$ = build_c_cast (type, build_compound_expr ($3), 1);
+ }
+ }
+ | functional_cast
+ | DYNAMIC_CAST '<'
+ { dont_allow_type_definitions = "inside dynamic_cast"; }
+ type_id '>'
+ { dont_allow_type_definitions = 0; }
+ '(' expr ')'
+ { tree type = groktypename ($4);
+ $$ = build_dynamic_cast (type, $8); }
+ | STATIC_CAST '<'
+ { dont_allow_type_definitions = "inside static_cast"; }
+ type_id '>'
+ { dont_allow_type_definitions = 0; }
+ '(' expr ')'
+ { tree type = groktypename ($4);
+ $$ = build_static_cast (type, $8); }
+ | REINTERPRET_CAST '<'
+ { dont_allow_type_definitions = "inside reinterpret_cast"; }
+ type_id '>'
+ { dont_allow_type_definitions = 0; }
+ '(' expr ')'
+ { tree type = groktypename ($4);
+ $$ = build_reinterpret_cast (type, $8); }
+ | CONST_CAST '<'
+ { dont_allow_type_definitions = "inside const_cast"; }
+ type_id '>'
+ { dont_allow_type_definitions = 0; }
+ '(' expr ')'
+ { tree type = groktypename ($4);
+ $$ = build_const_cast (type, $8); }
+ | TYPEID '(' expr ')'
+ { $$ = build_typeid ($3); }
+ | TYPEID '(' type_id ')'
+ { tree type = groktypename ($3);
+ $$ = get_typeid (TYPE_MAIN_VARIANT (type)); }
+ | global_scope IDENTIFIER
+ {
+ do_scoped_id:
+ $$ = IDENTIFIER_GLOBAL_VALUE ($2);
+ if (yychar == YYEMPTY)
+ yychar = YYLEX;
+ if (! $$)
+ {
+ if (yychar == '(' || yychar == LEFT_RIGHT)
+ $$ = implicitly_declare ($2);
+ else
+ {
+ if (IDENTIFIER_GLOBAL_VALUE ($2) != error_mark_node)
+ error ("undeclared variable `%s' (first use here)",
+ IDENTIFIER_POINTER ($2));
+ $$ = error_mark_node;
+ /* Prevent repeated error messages. */
+ IDENTIFIER_GLOBAL_VALUE ($2) = error_mark_node;
+ }
+ }
+ else
+ {
+ if (TREE_CODE ($$) == ADDR_EXPR)
+ assemble_external (TREE_OPERAND ($$, 0));
+ else
+ assemble_external ($$);
+ TREE_USED ($$) = 1;
+ }
+ if (TREE_CODE ($$) == CONST_DECL)
+ {
+ /* XXX CHS - should we set TREE_USED of the constant? */
+ $$ = DECL_INITIAL ($$);
+ /* This is to prevent an enum whose value is 0
+ from being considered a null pointer constant. */
+ $$ = build1 (NOP_EXPR, TREE_TYPE ($$), $$);
+ TREE_CONSTANT ($$) = 1;
+ }
+
+ }
+ | global_scope operator_name
+ {
+ got_scope = NULL_TREE;
+ if (TREE_CODE ($2) == IDENTIFIER_NODE)
+ goto do_scoped_id;
+ $$ = $2;
+ }
+ | overqualified_id %prec HYPERUNARY
+ { $$ = build_offset_ref (OP0 ($$), OP1 ($$)); }
+ | overqualified_id '(' nonnull_exprlist ')'
+ { $$ = build_member_call (OP0 ($$), OP1 ($$), $3); }
+ | overqualified_id LEFT_RIGHT
+ { $$ = build_member_call (OP0 ($$), OP1 ($$), NULL_TREE); }
+ | object unqualified_id %prec UNARY
+ { got_object = NULL_TREE;
+ $$ = build_component_ref ($$, $2, NULL_TREE, 1); }
+ | object overqualified_id %prec UNARY
+ { got_object = NULL_TREE;
+ $$ = build_object_ref ($$, OP0 ($2), OP1 ($2)); }
+ | object unqualified_id '(' nonnull_exprlist ')'
+ {
+ got_object = NULL_TREE;
+#if 0
+ /* This is a future direction of this code, but because
+ build_x_function_call cannot always undo what is done
+ in build_component_ref entirely yet, we cannot do this. */
+ $$ = build_x_function_call (build_component_ref ($$, $2, NULL_TREE, 1), $4, $$);
+ if (TREE_CODE ($$) == CALL_EXPR
+ && TREE_TYPE ($$) != void_type_node)
+ $$ = require_complete_type ($$);
+#else
+ $$ = build_method_call ($$, $2, $4, NULL_TREE,
+ (LOOKUP_NORMAL|LOOKUP_AGGR));
+#endif
+ }
+ | object unqualified_id LEFT_RIGHT
+ {
+ got_object = NULL_TREE;
+#if 0
+ /* This is a future direction of this code, but because
+ build_x_function_call cannot always undo what is done
+ in build_component_ref entirely yet, we cannot do this. */
+ $$ = build_x_function_call (build_component_ref ($$, $2, NULL_TREE, 1), NULL_TREE, $$);
+ if (TREE_CODE ($$) == CALL_EXPR
+ && TREE_TYPE ($$) != void_type_node)
+ $$ = require_complete_type ($$);
+#else
+ $$ = build_method_call ($$, $2, NULL_TREE, NULL_TREE,
+ (LOOKUP_NORMAL|LOOKUP_AGGR));
+#endif
+ }
+ | object overqualified_id '(' nonnull_exprlist ')'
+ {
+ got_object = NULL_TREE;
+ if (IS_SIGNATURE (IDENTIFIER_TYPE_VALUE (OP0 ($2))))
+ {
+ warning ("signature name in scope resolution ignored");
+ $$ = build_method_call ($$, OP1 ($2), $4, NULL_TREE,
+ (LOOKUP_NORMAL|LOOKUP_AGGR));
+ }
+ else
+ $$ = build_scoped_method_call ($$, OP0 ($2), OP1 ($2), $4);
+ }
+ | object overqualified_id LEFT_RIGHT
+ {
+ got_object = NULL_TREE;
+ if (IS_SIGNATURE (IDENTIFIER_TYPE_VALUE (OP0 ($2))))
+ {
+ warning ("signature name in scope resolution ignored");
+ $$ = build_method_call ($$, OP1 ($2), NULL_TREE, NULL_TREE,
+ (LOOKUP_NORMAL|LOOKUP_AGGR));
+ }
+ else
+ $$ = build_scoped_method_call ($$, OP0 ($2), OP1 ($2), NULL_TREE);
+ }
+ /* p->int::~int() is valid -- 12.4 */
+ | object '~' TYPESPEC LEFT_RIGHT
+ {
+ got_object = NULL_TREE;
+ if (IDENTIFIER_GLOBAL_VALUE ($3)
+ && (TREE_CODE (TREE_TYPE ($1))
+ != TREE_CODE (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE ($3)))))
+ cp_error ("`%E' is not of type `%T'", $1, $3);
+ $$ = convert (void_type_node, $1);
+ }
+ | object TYPESPEC SCOPE '~' TYPESPEC LEFT_RIGHT
+ {
+ got_object = NULL_TREE;
+ if ($2 != $5)
+ cp_error ("destructor specifier `%T::~%T()' must have matching names", $2, $5);
+ if (TREE_CODE (TREE_TYPE ($1))
+ != TREE_CODE (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE ($2))))
+ cp_error ("`%E' is not of type `%T'", $1, $2);
+ $$ = convert (void_type_node, $1);
+ }
+ | object error
+ {
+ got_object = NULL_TREE;
+ $$ = error_mark_node;
+ }
+ ;
+
+/* Not needed for now.
+
+primary_no_id:
+ '(' expr ')'
+ { $$ = $2; }
+ | '(' error ')'
+ { $$ = error_mark_node; }
+ | '('
+ { if (current_function_decl == 0)
+ {
+ error ("braced-group within expression allowed only inside a function");
+ YYERROR;
+ }
+ $<ttype>$ = expand_start_stmt_expr (); }
+ compstmt ')'
+ { if (pedantic)
+ pedwarn ("ANSI C++ forbids braced-groups within expressions");
+ $$ = expand_end_stmt_expr ($<ttype>2); }
+ | primary_no_id '(' nonnull_exprlist ')'
+ { $$ = build_x_function_call ($$, $3, current_class_decl); }
+ | primary_no_id LEFT_RIGHT
+ { $$ = build_x_function_call ($$, NULL_TREE, current_class_decl); }
+ | primary_no_id '[' expr ']'
+ { goto do_array; }
+ | primary_no_id PLUSPLUS
+ { $$ = build_x_unary_op (POSTINCREMENT_EXPR, $$); }
+ | primary_no_id MINUSMINUS
+ { $$ = build_x_unary_op (POSTDECREMENT_EXPR, $$); }
+ | SCOPE IDENTIFIER
+ { goto do_scoped_id; }
+ | SCOPE operator_name
+ { if (TREE_CODE ($2) == IDENTIFIER_NODE)
+ goto do_scoped_id;
+ goto do_scoped_operator;
+ }
+ ;
+*/
+
+new: NEW
+ { $$ = 0; }
+ | global_scope NEW
+ { got_scope = NULL_TREE; $$ = 1; }
+ ;
+
+delete: DELETE
+ { $$ = 0; }
+ | global_scope delete
+ { got_scope = NULL_TREE; $$ = 1; }
+ ;
+
+boolean.literal:
+ CXX_TRUE
+ { $$ = boolean_true_node; }
+ | CXX_FALSE
+ { $$ = boolean_false_node; }
+ ;
+
+/* Produces a STRING_CST with perhaps more STRING_CSTs chained onto it. */
+string:
+ STRING
+ | string STRING
+ { $$ = chainon ($$, $2); }
+ ;
+
+nodecls:
+ /* empty */
+ {
+ if (! current_function_parms_stored)
+ store_parm_decls ();
+ setup_vtbl_ptr ();
+ /* Always keep the BLOCK node associated with the outermost
+ pair of curley braces of a function. These are needed
+ for correct operation of dwarfout.c. */
+ keep_next_level ();
+ }
+ ;
+
+object: primary '.'
+ { got_object = TREE_TYPE ($$); }
+ | primary POINTSAT
+ {
+ $$ = build_x_arrow ($$);
+ got_object = TREE_TYPE ($$);
+ }
+ ;
+
+decl:
+ /* Normal case: make this fast. */
+ typespec declarator ';'
+ { tree d = get_decl_list ($1);
+ int yes = suspend_momentary ();
+ d = start_decl ($2, d, 0, NULL_TREE);
+ cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
+ resume_momentary (yes);
+ if (IS_AGGR_TYPE_CODE (TREE_CODE ($1)))
+ note_got_semicolon ($1);
+ }
+ | typed_declspecs declarator ';'
+ { tree d, specs, attrs;
+ int yes;
+ split_specs_attrs ($1, &specs, &attrs);
+ yes = suspend_momentary ();
+ d = start_decl ($2, specs, 0, NULL_TREE);
+ cplus_decl_attributes (d, NULL_TREE, attrs);
+ cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
+ resume_momentary (yes);
+ note_list_got_semicolon ($1);
+ }
+ | typespec initdecls ';'
+ {
+ resume_momentary ($2);
+ if (IS_AGGR_TYPE_CODE (TREE_CODE ($1)))
+ note_got_semicolon ($1);
+ }
+ | typed_declspecs initdecls ';'
+ {
+ resume_momentary ($2);
+ note_list_got_semicolon ($1);
+ }
+ | declmods notype_initdecls ';'
+ { resume_momentary ($2); }
+ | typed_declspecs ';'
+ {
+ shadow_tag ($1);
+ note_list_got_semicolon ($1);
+ }
+ | declmods ';'
+ { warning ("empty declaration"); }
+ ;
+
+/* Any kind of declarator (thus, all declarators allowed
+ after an explicit typespec). */
+
+declarator:
+ after_type_declarator %prec EMPTY
+ | notype_declarator %prec EMPTY
+ ;
+
+/* This is necessary to postpone reduction of `int()()()()'. */
+fcast_or_absdcl:
+ LEFT_RIGHT %prec EMPTY
+ { $$ = build_parse_node (CALL_EXPR, NULL_TREE, empty_parms (),
+ NULL_TREE); }
+ | fcast_or_absdcl LEFT_RIGHT %prec EMPTY
+ { $$ = build_parse_node (CALL_EXPR, $$, empty_parms (),
+ NULL_TREE); }
+ ;
+
+/* ANSI type-id (8.1) */
+type_id:
+ typed_typespecs absdcl
+ { $$ = build_decl_list ($$, $2); }
+ | nonempty_type_quals absdcl
+ { $$ = build_decl_list ($$, $2); }
+ | typespec absdcl
+ { $$ = build_decl_list (get_decl_list ($$), $2); }
+ | typed_typespecs %prec EMPTY
+ { $$ = build_decl_list ($$, NULL_TREE); }
+ | nonempty_type_quals %prec EMPTY
+ { $$ = build_decl_list ($$, NULL_TREE); }
+ ;
+
+/* 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.
+ In the result, declspecs have a non-NULL TREE_VALUE, attributes do not. */
+
+typed_declspecs:
+ typed_typespecs %prec EMPTY
+ | typed_declspecs1
+ ;
+
+typed_declspecs1:
+ declmods typespec
+ { $$ = decl_tree_cons (NULL_TREE, $2, $$); }
+ | typespec reserved_declspecs %prec HYPERUNARY
+ { $$ = decl_tree_cons (NULL_TREE, $$, $2); }
+ | typespec reserved_typespecquals reserved_declspecs
+ { $$ = decl_tree_cons (NULL_TREE, $$, chainon ($2, $3)); }
+ | declmods typespec reserved_declspecs
+ { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); }
+ | declmods typespec reserved_typespecquals
+ { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); }
+ | declmods typespec reserved_typespecquals reserved_declspecs
+ { $$ = decl_tree_cons (NULL_TREE, $2,
+ chainon ($3, chainon ($4, $$))); }
+ ;
+
+reserved_declspecs:
+ SCSPEC
+ { if (extra_warnings)
+ warning ("`%s' is not at beginning of declaration",
+ IDENTIFIER_POINTER ($$));
+ $$ = build_decl_list (NULL_TREE, $$); }
+ | reserved_declspecs typespecqual_reserved
+ { $$ = decl_tree_cons (NULL_TREE, $2, $$); }
+ | reserved_declspecs SCSPEC
+ { if (extra_warnings)
+ warning ("`%s' is not at beginning of declaration",
+ IDENTIFIER_POINTER ($2));
+ $$ = decl_tree_cons (NULL_TREE, $2, $$); }
+ | reserved_declspecs attributes
+ { $$ = decl_tree_cons ($2, NULL_TREE, $1); }
+ | attributes
+ { $$ = decl_tree_cons ($1, NULL_TREE, NULL_TREE); }
+ ;
+
+/* List of just storage classes and type modifiers.
+ A declaration can start with just this, but then it cannot be used
+ to redeclare a typedef-name.
+ In the result, declspecs have a non-NULL TREE_VALUE, attributes do not. */
+
+declmods:
+ nonempty_type_quals %prec EMPTY
+ { TREE_STATIC ($$) = 1; }
+ | SCSPEC
+ { $$ = IDENTIFIER_AS_LIST ($$); }
+ | declmods TYPE_QUAL
+ { $$ = decl_tree_cons (NULL_TREE, $2, $$);
+ TREE_STATIC ($$) = 1; }
+ | declmods SCSPEC
+ { if (extra_warnings && TREE_STATIC ($$))
+ warning ("`%s' is not at beginning of declaration",
+ IDENTIFIER_POINTER ($2));
+ $$ = decl_tree_cons (NULL_TREE, $2, $$);
+ TREE_STATIC ($$) = TREE_STATIC ($1); }
+ | declmods attributes
+ { $$ = decl_tree_cons ($2, NULL_TREE, $1); }
+ | attributes
+ { $$ = decl_tree_cons ($1, NULL_TREE, NULL_TREE); }
+ ;
+
+/* Used instead of declspecs where storage classes are not allowed
+ (that is, for typenames and structure components).
+
+ C++ can takes storage classes for structure components.
+ Don't accept a typedef-name if anything but a modifier precedes it. */
+
+typed_typespecs:
+ typespec %prec EMPTY
+ { $$ = get_decl_list ($$); }
+ | nonempty_type_quals typespec
+ { $$ = decl_tree_cons (NULL_TREE, $2, $$); }
+ | typespec reserved_typespecquals
+ { $$ = decl_tree_cons (NULL_TREE, $$, $2); }
+ | nonempty_type_quals typespec reserved_typespecquals
+ { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); }
+ ;
+
+reserved_typespecquals:
+ typespecqual_reserved
+ { $$ = build_decl_list (NULL_TREE, $$); }
+ | reserved_typespecquals typespecqual_reserved
+ { $$ = decl_tree_cons (NULL_TREE, $2, $$); }
+ ;
+
+/* A typespec (but not a type qualifier).
+ Once we have seen one of these in a declaration,
+ if a typedef name appears then it is being redeclared. */
+
+typespec: structsp
+ | TYPESPEC %prec EMPTY
+ | complete_type_name
+ | TYPEOF '(' expr ')'
+ { $$ = TREE_TYPE ($3);
+ if (pedantic && !in_system_header)
+ pedwarn ("ANSI C++ forbids `typeof'"); }
+ | TYPEOF '(' type_id ')'
+ { $$ = groktypename ($3);
+ if (pedantic && !in_system_header)
+ pedwarn ("ANSI C++ forbids `typeof'"); }
+ | SIGOF '(' expr ')'
+ { tree type = TREE_TYPE ($3);
+
+ if (IS_AGGR_TYPE (type))
+ {
+ sorry ("sigof type specifier");
+ $$ = type;
+ }
+ else
+ {
+ error ("`sigof' applied to non-aggregate expression");
+ $$ = error_mark_node;
+ }
+ }
+ | SIGOF '(' type_id ')'
+ { tree type = groktypename ($3);
+
+ if (IS_AGGR_TYPE (type))
+ {
+ sorry ("sigof type specifier");
+ $$ = type;
+ }
+ else
+ {
+ error("`sigof' applied to non-aggregate type");
+ $$ = error_mark_node;
+ }
+ }
+ ;
+
+/* A typespec that is a reserved word, or a type qualifier. */
+
+typespecqual_reserved: TYPESPEC
+ | TYPE_QUAL
+ | structsp
+ ;
+
+initdecls:
+ initdcl0
+ | initdecls ',' initdcl
+ ;
+
+notype_initdecls:
+ notype_initdcl0
+ | notype_initdecls ',' initdcl
+ ;
+
+nomods_initdecls:
+ nomods_initdcl0
+ | nomods_initdecls ',' initdcl
+ ;
+
+maybeasm:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | asm_keyword '(' string ')'
+ { if (TREE_CHAIN ($3)) $3 = combine_strings ($3); $$ = $3; }
+ ;
+
+initdcl0:
+ declarator exception_specification_opt maybeasm maybe_attribute '='
+ { split_specs_attrs ($<ttype>0, &current_declspecs,
+ &prefix_attributes);
+ if (TREE_CODE (current_declspecs) != TREE_LIST)
+ current_declspecs = get_decl_list (current_declspecs);
+ if (have_extern_spec && !used_extern_spec)
+ {
+ current_declspecs = decl_tree_cons
+ (NULL_TREE, get_identifier ("extern"),
+ current_declspecs);
+ used_extern_spec = 1;
+ }
+ $<itype>5 = suspend_momentary ();
+ $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 1, $2);
+ cplus_decl_attributes ($<ttype>$, $4, prefix_attributes); }
+ init
+/* Note how the declaration of the variable is in effect while its init is parsed! */
+ { cp_finish_decl ($<ttype>6, $7, $3, 0, LOOKUP_ONLYCONVERTING);
+ $$ = $<itype>5; }
+ | declarator exception_specification_opt maybeasm maybe_attribute
+ { tree d;
+ split_specs_attrs ($<ttype>0, &current_declspecs,
+ &prefix_attributes);
+ if (TREE_CODE (current_declspecs) != TREE_LIST)
+ current_declspecs = get_decl_list (current_declspecs);
+ if (have_extern_spec && !used_extern_spec)
+ {
+ current_declspecs = decl_tree_cons
+ (NULL_TREE, get_identifier ("extern"),
+ current_declspecs);
+ used_extern_spec = 1;
+ }
+ $$ = suspend_momentary ();
+ d = start_decl ($<ttype>1, current_declspecs, 0, $2);
+ cplus_decl_attributes (d, $4, prefix_attributes);
+ cp_finish_decl (d, NULL_TREE, $3, 0, 0); }
+ ;
+
+initdcl:
+ declarator exception_specification_opt maybeasm maybe_attribute '='
+ { $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 1, $2);
+ cplus_decl_attributes ($<ttype>$, $4, prefix_attributes); }
+ init
+/* Note how the declaration of the variable is in effect while its init is parsed! */
+ { cp_finish_decl ($<ttype>6, $7, $3, 0, LOOKUP_ONLYCONVERTING); }
+ | declarator exception_specification_opt maybeasm maybe_attribute
+ { $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 0, $2);
+ cplus_decl_attributes ($<ttype>$, $4, prefix_attributes);
+ cp_finish_decl ($<ttype>$, NULL_TREE, $3, 0, 0); }
+ ;
+
+notype_initdcl0:
+ notype_declarator exception_specification_opt maybeasm maybe_attribute '='
+ { split_specs_attrs ($<ttype>0, &current_declspecs,
+ &prefix_attributes);
+ $<itype>5 = suspend_momentary ();
+ $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 1, $2);
+ cplus_decl_attributes ($<ttype>$, $4, prefix_attributes); }
+ init
+/* Note how the declaration of the variable is in effect while its init is parsed! */
+ { cp_finish_decl ($<ttype>6, $7, $3, 0, LOOKUP_ONLYCONVERTING);
+ $$ = $<itype>5; }
+ | notype_declarator exception_specification_opt maybeasm maybe_attribute
+ { tree d;
+ split_specs_attrs ($<ttype>0, &current_declspecs,
+ &prefix_attributes);
+ $$ = suspend_momentary ();
+ d = start_decl ($<ttype>1, current_declspecs, 0, $2);
+ cplus_decl_attributes (d, $4, prefix_attributes);
+ cp_finish_decl (d, NULL_TREE, $3, 0, 0); }
+ ;
+
+nomods_initdcl0:
+ notype_declarator exception_specification_opt maybeasm maybe_attribute '='
+ { current_declspecs = NULL_TREE;
+ prefix_attributes = NULL_TREE;
+ $<itype>5 = suspend_momentary ();
+ $<ttype>$ = start_decl ($1, current_declspecs, 1, $2);
+ cplus_decl_attributes ($<ttype>$, $4, prefix_attributes); }
+ init
+/* Note how the declaration of the variable is in effect while its init is parsed! */
+ { cp_finish_decl ($<ttype>6, $7, $3, 0, LOOKUP_ONLYCONVERTING);
+ $$ = $<itype>5; }
+ | notype_declarator exception_specification_opt maybeasm maybe_attribute
+ { tree d;
+ current_declspecs = NULL_TREE;
+ prefix_attributes = NULL_TREE;
+ $$ = suspend_momentary ();
+ d = start_decl ($1, current_declspecs, 0, $2);
+ cplus_decl_attributes (d, $4, prefix_attributes);
+ cp_finish_decl (d, NULL_TREE, $3, 0, 0); }
+ ;
+
+/* the * rules are dummies to accept the Apollo extended syntax
+ so that the header files compile. */
+maybe_attribute:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | attributes
+ { $$ = $1; }
+ ;
+
+attributes:
+ attribute
+ { $$ = $1; }
+ | attributes attribute
+ { $$ = chainon ($1, $2); }
+ ;
+
+attribute:
+ ATTRIBUTE '(' '(' attribute_list ')' ')'
+ { $$ = $4; }
+ ;
+
+attribute_list:
+ attrib
+ { $$ = $1; }
+ | attribute_list ',' attrib
+ { $$ = chainon ($1, $3); }
+ ;
+
+attrib:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | any_word
+ { $$ = build_tree_list ($1, NULL_TREE); }
+ | any_word '(' IDENTIFIER ')'
+ { $$ = build_tree_list ($1, build_tree_list (NULL_TREE, $3)); }
+ | any_word '(' IDENTIFIER ',' nonnull_exprlist ')'
+ { $$ = build_tree_list ($1, tree_cons (NULL_TREE, $3, $5)); }
+ | any_word '(' nonnull_exprlist ')'
+ { $$ = build_tree_list ($1, $3); }
+ ;
+
+/* This still leaves out most reserved keywords,
+ shouldn't we include them? */
+
+any_word:
+ identifier
+ | SCSPEC
+ | TYPESPEC
+ | TYPE_QUAL
+ ;
+
+/* A nonempty list of identifiers, including typenames. */
+identifiers_or_typenames:
+ identifier
+ { $$ = build_tree_list (NULL_TREE, $1); }
+ | identifiers_or_typenames ',' identifier
+ { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); }
+ ;
+
+maybe_init:
+ %prec EMPTY /* empty */
+ { $$ = NULL_TREE; }
+ | '=' init
+ { $$ = $2; }
+
+init:
+ expr_no_commas %prec '='
+ | '{' '}'
+ { $$ = build_nt (CONSTRUCTOR, NULL_TREE, NULL_TREE);
+ TREE_HAS_CONSTRUCTOR ($$) = 1; }
+ | '{' initlist '}'
+ { $$ = build_nt (CONSTRUCTOR, NULL_TREE, nreverse ($2));
+ TREE_HAS_CONSTRUCTOR ($$) = 1; }
+ | '{' initlist ',' '}'
+ { $$ = build_nt (CONSTRUCTOR, NULL_TREE, nreverse ($2));
+ TREE_HAS_CONSTRUCTOR ($$) = 1; }
+ | error
+ { $$ = NULL_TREE; }
+ ;
+
+/* This chain is built in reverse order,
+ and put in forward order where initlist is used. */
+initlist:
+ init
+ { $$ = build_tree_list (NULL_TREE, $$); }
+ | initlist ',' init
+ { $$ = tree_cons (NULL_TREE, $3, $$); }
+ /* These are for labeled elements. */
+ | '[' expr_no_commas ']' init
+ { $$ = build_tree_list ($2, $4); }
+ | initlist ',' CASE expr_no_commas ':' init
+ { $$ = tree_cons ($4, $6, $$); }
+ | identifier ':' init
+ { $$ = build_tree_list ($$, $3); }
+ | initlist ',' identifier ':' init
+ { $$ = tree_cons ($3, $5, $$); }
+ ;
+
+structsp:
+ ENUM identifier '{'
+ { $<itype>3 = suspend_momentary ();
+ $$ = start_enum ($2); }
+ enumlist maybecomma_warn '}'
+ { $$ = finish_enum ($<ttype>4, $5);
+ resume_momentary ((int) $<itype>3);
+ check_for_missing_semicolon ($<ttype>4); }
+ | ENUM identifier '{' '}'
+ { $$ = finish_enum (start_enum ($2), NULL_TREE);
+ check_for_missing_semicolon ($$); }
+ | ENUM '{'
+ { $<itype>2 = suspend_momentary ();
+ $$ = start_enum (make_anon_name ()); }
+ enumlist maybecomma_warn '}'
+ { $$ = finish_enum ($<ttype>3, $4);
+ resume_momentary ((int) $<itype>1);
+ check_for_missing_semicolon ($<ttype>3); }
+ | ENUM '{' '}'
+ { $$ = finish_enum (start_enum (make_anon_name()), NULL_TREE);
+ check_for_missing_semicolon ($$); }
+ | ENUM identifier
+ { $$ = xref_tag (enum_type_node, $2, NULL_TREE, 1); }
+ | ENUM complex_type_name
+ { $$ = xref_tag (enum_type_node, $2, NULL_TREE, 1); }
+ | TYPENAME_KEYWORD complex_type_name
+ { $$ = $2; }
+ /* C++ extensions, merged with C to avoid shift/reduce conflicts */
+ | class_head left_curly opt.component_decl_list '}'
+ {
+ int semi;
+ tree id;
+
+#if 0
+ /* Need to rework class nesting in the
+ presence of nested classes, etc. */
+ shadow_tag (CLASSTYPE_AS_LIST ($$)); */
+#endif
+ if (yychar == YYEMPTY)
+ yychar = YYLEX;
+ semi = yychar == ';';
+ /* finish_struct nukes this anyway; if
+ finish_exception does too, then it can go. */
+ if (semi)
+ note_got_semicolon ($$);
+
+ if (TREE_CODE ($$) == ENUMERAL_TYPE)
+ /* $$ = $1 from default rule. */;
+ else
+ {
+ $$ = finish_struct ($$, $3, semi);
+ if (semi) note_got_semicolon ($$);
+ }
+
+ pop_obstacks ();
+
+ id = TYPE_IDENTIFIER ($$);
+ if (id && IDENTIFIER_TEMPLATE (id))
+ {
+ tree decl;
+
+ /* I don't know if the copying of this TYPE_DECL is
+ * really needed. However, it's such a small per-
+ * formance penalty that the extra safety is a bargain.
+ * - niklas@appli.se
+ */
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ decl = copy_node (lookup_name (id, 0));
+ if (DECL_LANG_SPECIFIC (decl))
+ copy_lang_decl (decl);
+ pop_obstacks ();
+ undo_template_name_overload (id, 0);
+ pushdecl_top_level (decl);
+ }
+ if (! semi)
+ check_for_missing_semicolon ($$); }
+ | class_head %prec EMPTY
+ {
+ /* struct B: public A; is not accepted by the WP grammar. */
+ if (TYPE_BINFO_BASETYPES ($$) && !TYPE_SIZE ($$)
+ && ! TYPE_BEING_DEFINED ($$))
+ cp_error ("base clause without member specification for `%#T'",
+ $$);
+ }
+ ;
+
+maybecomma:
+ /* empty */
+ | ','
+ ;
+
+maybecomma_warn:
+ /* empty */
+ | ','
+ { if (pedantic) pedwarn ("comma at end of enumerator list"); }
+ ;
+
+aggr: AGGR
+ | aggr SCSPEC
+ { error ("storage class specifier `%s' not allowed after struct or class", IDENTIFIER_POINTER ($2)); }
+ | aggr TYPESPEC
+ { error ("type specifier `%s' not allowed after struct or class", IDENTIFIER_POINTER ($2)); }
+ | aggr TYPE_QUAL
+ { error ("type qualifier `%s' not allowed after struct or class", IDENTIFIER_POINTER ($2)); }
+ | aggr AGGR
+ { error ("no body nor ';' separates two class, struct or union declarations"); }
+ ;
+
+specialization:
+ aggr template_type_name ';'
+ {
+ yyungetc (';', 1); current_aggr = $$; $$ = $2;
+ if ($<ttype>0 == ridpointers[(int) RID_TEMPLATE])
+ instantiate_class_template ($$, 2);
+ }
+ ;
+
+named_class_head_sans_basetype:
+ aggr identifier
+ { current_aggr = $$; $$ = $2; }
+ | specialization
+ ;
+
+named_class_head_sans_basetype_defn:
+ aggr identifier_defn %prec EMPTY
+ { current_aggr = $$; $$ = $2; }
+ | aggr template_type_name '{'
+ { yyungetc ('{', 1);
+ aggr2:
+ current_aggr = $$;
+ $$ = $2;
+ overload_template_name ($$, 0); }
+ | aggr template_type_name ':'
+ { yyungetc (':', 1); goto aggr2; }
+ ;
+
+named_complex_class_head_sans_basetype:
+ aggr nested_name_specifier identifier
+ { current_aggr = $$; $$ = $3; }
+ | aggr template_type %prec EMPTY
+ { current_aggr = $$; $$ = $2; }
+ ;
+
+do_xref_defn: /* empty */ %prec EMPTY
+ { $<ttype>$ = xref_tag (current_aggr, $<ttype>0, NULL_TREE, 0); }
+ ;
+
+named_class_head:
+ named_class_head_sans_basetype %prec EMPTY
+ { $$ = xref_tag (current_aggr, $1, NULL_TREE, 1); }
+ | named_class_head_sans_basetype_defn do_xref_defn
+ maybe_base_class_list %prec EMPTY
+ {
+ $$ = $<ttype>2;
+ if ($3)
+ xref_basetypes (current_aggr, $1, $<ttype>2, $3);
+ }
+ | named_complex_class_head_sans_basetype maybe_base_class_list
+ {
+ $$ = TREE_TYPE ($1);
+ if ($2)
+ xref_basetypes (current_aggr, $1, TREE_TYPE ($1), $2);
+ }
+ ;
+
+unnamed_class_head: aggr '{'
+ { $$ = xref_tag ($$, make_anon_name (), NULL_TREE, 0);
+ yyungetc ('{', 1); }
+ ;
+
+class_head: unnamed_class_head | named_class_head ;
+
+maybe_base_class_list:
+ %prec EMPTY /* empty */
+ { $$ = NULL_TREE; }
+ | ':' see_typename %prec EMPTY
+ { yyungetc(':', 1); $$ = NULL_TREE; }
+ | ':' see_typename base_class_list %prec EMPTY
+ { $$ = $3; }
+ ;
+
+base_class_list:
+ base_class
+ | base_class_list ',' see_typename base_class
+ { $$ = chainon ($$, $4); }
+ ;
+
+base_class:
+ base_class.1
+ {
+ tree type;
+ type = IDENTIFIER_TYPE_VALUE ($$);
+ if (! is_aggr_typedef ($$, 1))
+ $$ = NULL_TREE;
+ else if (current_aggr == signature_type_node
+ && (! type) && (! IS_SIGNATURE (type)))
+ {
+ error ("class name not allowed as base signature");
+ $$ = NULL_TREE;
+ }
+ else if (current_aggr == signature_type_node)
+ {
+ sorry ("signature inheritance, base type `%s' ignored",
+ IDENTIFIER_POINTER ($$));
+ $$ = build_tree_list ((tree)access_public, $$);
+ }
+ else if (type && IS_SIGNATURE (type))
+ {
+ error ("signature name not allowed as base class");
+ $$ = NULL_TREE;
+ }
+ else
+ $$ = build_tree_list ((tree)access_default, $$);
+ }
+ | base_class_access_list see_typename base_class.1
+ {
+ tree type;
+ type = IDENTIFIER_TYPE_VALUE ($3);
+ if (current_aggr == signature_type_node)
+ error ("access and source specifiers not allowed in signature");
+ if (! is_aggr_typedef ($3, 1))
+ $$ = NULL_TREE;
+ else if (current_aggr == signature_type_node
+ && (! type) && (! IS_SIGNATURE (type)))
+ {
+ error ("class name not allowed as base signature");
+ $$ = NULL_TREE;
+ }
+ else if (current_aggr == signature_type_node)
+ {
+ sorry ("signature inheritance, base type `%s' ignored",
+ IDENTIFIER_POINTER ($$));
+ $$ = build_tree_list ((tree)access_public, $3);
+ }
+ else if (type && IS_SIGNATURE (type))
+ {
+ error ("signature name not allowed as base class");
+ $$ = NULL_TREE;
+ }
+ else
+ $$ = build_tree_list ((tree) $$, $3);
+ }
+ ;
+
+base_class.1:
+ complete_type_name
+ | SIGOF '(' expr ')'
+ {
+ if (current_aggr == signature_type_node)
+ {
+ if (IS_AGGR_TYPE (TREE_TYPE ($3)))
+ {
+ sorry ("`sigof' as base signature specifier");
+ /* need to return some dummy signature identifier */
+ $$ = $3;
+ }
+ else
+ {
+ error ("`sigof' applied to non-aggregate expression");
+ $$ = error_mark_node;
+ }
+ }
+ else
+ {
+ error ("`sigof' in struct or class declaration");
+ $$ = error_mark_node;
+ }
+ }
+ | SIGOF '(' type_id ')'
+ {
+ if (current_aggr == signature_type_node)
+ {
+ if (IS_AGGR_TYPE (groktypename ($3)))
+ {
+ sorry ("`sigof' as base signature specifier");
+ /* need to return some dummy signature identifier */
+ $$ = $3;
+ }
+ else
+ {
+ error ("`sigof' applied to non-aggregate expression");
+ $$ = error_mark_node;
+ }
+ }
+ else
+ {
+ error ("`sigof' in struct or class declaration");
+ $$ = error_mark_node;
+ }
+ }
+ ;
+
+base_class_access_list:
+ VISSPEC see_typename
+ | SCSPEC see_typename
+ { if ($<ttype>$ != ridpointers[(int)RID_VIRTUAL])
+ sorry ("non-virtual access");
+ $$ = access_default_virtual; }
+ | base_class_access_list VISSPEC see_typename
+ { int err = 0;
+ if ($2 == access_protected)
+ {
+ warning ("`protected' access not implemented");
+ $2 = access_public;
+ err++;
+ }
+ else if ($2 == access_public)
+ {
+ if ($1 == access_private)
+ {
+ mixed:
+ error ("base class cannot be public and private");
+ }
+ else if ($1 == access_default_virtual)
+ $$ = access_public_virtual;
+ }
+ else /* $2 == access_private */
+ {
+ if ($1 == access_public)
+ goto mixed;
+ else if ($1 == access_default_virtual)
+ $$ = access_private_virtual;
+ }
+ }
+ | base_class_access_list SCSPEC see_typename
+ { if ($2 != ridpointers[(int)RID_VIRTUAL])
+ sorry ("non-virtual access");
+ if ($$ == access_public)
+ $$ = access_public_virtual;
+ else if ($$ == access_private)
+ $$ = access_private_virtual; }
+ ;
+
+left_curly: '{'
+ { tree t = $<ttype>0;
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ if (! IS_AGGR_TYPE (t))
+ {
+ t = $<ttype>0 = make_lang_type (RECORD_TYPE);
+ TYPE_NAME (t) = get_identifier ("erroneous type");
+ }
+ if (TYPE_SIZE (t))
+ duplicate_tag_error (t);
+ if (TYPE_SIZE (t) || TYPE_BEING_DEFINED (t))
+ {
+ t = make_lang_type (TREE_CODE (t));
+ pushtag (TYPE_IDENTIFIER ($<ttype>0), t, 0);
+ $<ttype>0 = t;
+ }
+ pushclass (t, 0);
+ TYPE_BEING_DEFINED (t) = 1;
+ /* Reset the interface data, at the earliest possible
+ moment, as it might have been set via a class foo;
+ before. */
+ /* Don't change signatures. */
+ if (! IS_SIGNATURE (t))
+ {
+ extern tree pending_vtables;
+ int needs_writing;
+ tree name = TYPE_IDENTIFIER (t);
+
+ if (! ANON_AGGRNAME_P (name))
+ {
+ CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
+ SET_CLASSTYPE_INTERFACE_UNKNOWN_X
+ (t, interface_unknown);
+ }
+
+ /* Record how to set the access of this class's
+ virtual functions. If write_virtuals == 2 or 3, then
+ inline virtuals are ``extern inline''. */
+ switch (write_virtuals)
+ {
+ case 0:
+ case 1:
+ needs_writing = 1;
+ break;
+ case 2:
+ needs_writing = !! value_member (name, pending_vtables);
+ break;
+ case 3:
+ needs_writing = ! CLASSTYPE_INTERFACE_ONLY (t)
+ && CLASSTYPE_INTERFACE_KNOWN (t);
+ break;
+ default:
+ needs_writing = 0;
+ }
+ CLASSTYPE_VTABLE_NEEDS_WRITING (t) = needs_writing;
+ }
+#if 0
+ t = TYPE_IDENTIFIER ($<ttype>0);
+ if (t && IDENTIFIER_TEMPLATE (t))
+ overload_template_name (t, 1);
+#endif
+ }
+ ;
+
+opt.component_decl_list:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | component_decl_list
+ {
+ if (current_aggr == signature_type_node)
+ $$ = build_tree_list ((tree) access_public, $$);
+ else
+ $$ = build_tree_list ((tree) access_default, $$);
+ }
+ | opt.component_decl_list VISSPEC ':' component_decl_list
+ {
+ tree visspec = (tree) $2;
+
+ if (current_aggr == signature_type_node)
+ {
+ error ("access specifier not allowed in signature");
+ visspec = (tree) access_public;
+ }
+ $$ = chainon ($$, build_tree_list (visspec, $4));
+ }
+ | opt.component_decl_list VISSPEC ':'
+ {
+ if (current_aggr == signature_type_node)
+ error ("access specifier not allowed in signature");
+ }
+ ;
+
+/* Note: we no longer warn about the semicolon after a component_decl_list.
+ ARM $9.2 says that the semicolon is optional, and therefore allowed. */
+component_decl_list:
+ component_decl
+ { if ($$ == void_type_node) $$ = NULL_TREE;
+ }
+ | component_decl_list component_decl
+ { /* In pushdecl, we created a reverse list of names
+ in this binding level. Make sure that the chain
+ of what we're trying to add isn't the item itself
+ (which can happen with what pushdecl's doing). */
+ if ($2 != NULL_TREE && $2 != void_type_node)
+ {
+ if (TREE_CHAIN ($2) != $$)
+ $$ = chainon ($$, $2);
+ else
+ $$ = $2;
+ }
+ }
+ ;
+
+component_decl:
+ component_decl_1 ';'
+ { }
+ | component_decl_1 '}'
+ { error ("missing ';' before right brace");
+ yyungetc ('}', 0); }
+ /* C++: handle constructors, destructors and inline functions */
+ /* note that INLINE is like a TYPESPEC */
+ | fn.def2 ':' /* base_init compstmt */
+ { $$ = finish_method ($$); }
+ | fn.def2 TRY /* base_init compstmt */
+ { $$ = finish_method ($$); }
+ | fn.def2 RETURN /* base_init compstmt */
+ { $$ = finish_method ($$); }
+ | fn.def2 '{' /* nodecls compstmt */
+ { $$ = finish_method ($$); }
+ | ';'
+ { $$ = NULL_TREE; }
+ ;
+
+component_decl_1:
+ /* Do not add a "typed_declspecs declarator" rule here for
+ speed; we need to call grok_x_components for enums, so the
+ speedup would be insignificant. */
+ typed_declspecs components
+ { $$ = grok_x_components ($1, $2); }
+ | declmods notype_components
+ { $$ = grok_x_components ($1, $2); }
+ | notype_declarator exception_specification_opt maybeasm maybe_attribute maybe_init
+ { $$ = grokfield ($$, NULL_TREE, $2, $5, $3,
+ build_tree_list ($4, NULL_TREE)); }
+ | ':' expr_no_commas
+ { $$ = grokbitfield (NULL_TREE, NULL_TREE, $2); }
+ | error
+ { $$ = NULL_TREE; }
+
+ /* These rules introduce a reduce/reduce conflict; in
+ typedef int foo, bar;
+ class A {
+ foo (bar);
+ };
+ should "A::foo" be declared as a function or "A::bar" as a data
+ member? In other words, is "bar" an after_type_declarator or a
+ parmlist? */
+ | typed_declspecs '(' parmlist ')' type_quals exception_specification_opt maybeasm maybe_attribute maybe_init
+ { tree specs, attrs;
+ split_specs_attrs ($1, &specs, &attrs);
+ $$ = build_parse_node (CALL_EXPR, TREE_VALUE (specs),
+ $3, $5);
+ $$ = grokfield ($$, TREE_CHAIN (specs), $6, $9, $7,
+ build_tree_list ($8, attrs)); }
+ | typed_declspecs LEFT_RIGHT type_quals exception_specification_opt maybeasm maybe_attribute maybe_init
+ { tree specs, attrs;
+ split_specs_attrs ($1, &specs, &attrs);
+ $$ = build_parse_node (CALL_EXPR, TREE_VALUE (specs),
+ empty_parms (), $3);
+ $$ = grokfield ($$, TREE_CHAIN (specs), $4, $7, $5,
+ build_tree_list ($6, attrs)); }
+ | using_decl
+ { $$ = do_class_using_decl ($1); }
+ ;
+
+/* The case of exactly one component is handled directly by component_decl. */
+/* ??? Huh? ^^^ */
+components:
+ /* empty: possibly anonymous */
+ { $$ = NULL_TREE; }
+ | component_declarator0
+ | components ',' component_declarator
+ {
+ /* In this context, void_type_node encodes
+ friends. They have been recorded elsewhere. */
+ if ($$ == void_type_node)
+ $$ = $3;
+ else
+ $$ = chainon ($$, $3);
+ }
+ ;
+
+notype_components:
+ /* empty: possibly anonymous */
+ { $$ = NULL_TREE; }
+ | notype_component_declarator0
+ | notype_components ',' notype_component_declarator
+ {
+ /* In this context, void_type_node encodes
+ friends. They have been recorded elsewhere. */
+ if ($$ == void_type_node)
+ $$ = $3;
+ else
+ $$ = chainon ($$, $3);
+ }
+ ;
+
+component_declarator0:
+ after_type_component_declarator0
+ | notype_component_declarator0
+ ;
+
+component_declarator:
+ after_type_component_declarator
+ | notype_component_declarator
+ ;
+
+after_type_component_declarator0:
+ after_type_declarator exception_specification_opt maybeasm maybe_attribute maybe_init
+ { split_specs_attrs ($<ttype>0, &current_declspecs,
+ &prefix_attributes);
+ $<ttype>0 = current_declspecs;
+ $$ = grokfield ($$, current_declspecs, $2, $5, $3,
+ build_tree_list ($4, prefix_attributes)); }
+ | TYPENAME ':' expr_no_commas maybe_attribute
+ { split_specs_attrs ($<ttype>0, &current_declspecs,
+ &prefix_attributes);
+ $<ttype>0 = current_declspecs;
+ $$ = grokbitfield ($$, current_declspecs, $3);
+ cplus_decl_attributes ($$, $4, prefix_attributes); }
+ ;
+
+notype_component_declarator0:
+ notype_declarator exception_specification_opt maybeasm maybe_attribute maybe_init
+ { split_specs_attrs ($<ttype>0, &current_declspecs,
+ &prefix_attributes);
+ $<ttype>0 = current_declspecs;
+ $$ = grokfield ($$, current_declspecs, $2, $5, $3,
+ build_tree_list ($4, prefix_attributes)); }
+ | IDENTIFIER ':' expr_no_commas maybe_attribute
+ { split_specs_attrs ($<ttype>0, &current_declspecs,
+ &prefix_attributes);
+ $<ttype>0 = current_declspecs;
+ $$ = grokbitfield ($$, current_declspecs, $3);
+ cplus_decl_attributes ($$, $4, prefix_attributes); }
+ | ':' expr_no_commas maybe_attribute
+ { split_specs_attrs ($<ttype>0, &current_declspecs,
+ &prefix_attributes);
+ $<ttype>0 = current_declspecs;
+ $$ = grokbitfield (NULL_TREE, current_declspecs, $2);
+ cplus_decl_attributes ($$, $3, prefix_attributes); }
+ ;
+
+after_type_component_declarator:
+ after_type_declarator exception_specification_opt maybeasm maybe_attribute maybe_init
+ { $$ = grokfield ($$, current_declspecs, $2, $5, $3,
+ build_tree_list ($4, prefix_attributes)); }
+ | TYPENAME ':' expr_no_commas maybe_attribute
+ { $$ = grokbitfield ($$, current_declspecs, $3);
+ cplus_decl_attributes ($$, $4, prefix_attributes); }
+ ;
+
+notype_component_declarator:
+ notype_declarator exception_specification_opt maybeasm maybe_attribute maybe_init
+ { $$ = grokfield ($$, current_declspecs, $2, $5, $3,
+ build_tree_list ($4, prefix_attributes)); }
+ | IDENTIFIER ':' expr_no_commas maybe_attribute
+ { $$ = grokbitfield ($$, current_declspecs, $3);
+ cplus_decl_attributes ($$, $4, prefix_attributes); }
+ | ':' expr_no_commas maybe_attribute
+ { $$ = grokbitfield (NULL_TREE, current_declspecs, $2);
+ cplus_decl_attributes ($$, $3, prefix_attributes); }
+ ;
+
+/* We chain the enumerators in reverse order.
+ Because of the way enums are built, the order is
+ insignificant. Take advantage of this fact. */
+
+enumlist:
+ enumerator
+ | enumlist ',' enumerator
+ { TREE_CHAIN ($3) = $$; $$ = $3; }
+ ;
+
+enumerator:
+ identifier
+ { $$ = build_enumerator ($$, NULL_TREE); }
+ | identifier '=' expr_no_commas
+ { $$ = build_enumerator ($$, $3); }
+ ;
+
+/* ANSI new-type-id (5.3.4) */
+new_type_id:
+ type_specifier_seq new_declarator
+ { $$ = build_decl_list ($$, $2); }
+ | type_specifier_seq %prec EMPTY
+ { $$ = build_decl_list ($$, NULL_TREE); }
+ /* GNU extension to allow arrays of arbitrary types with
+ non-constant dimension. */
+ | '(' type_id ')' '[' expr ']'
+ {
+ if (pedantic)
+ pedwarn ("ANSI C++ forbids array dimensions with parenthesized type in new");
+ $$ = build_parse_node (ARRAY_REF, TREE_VALUE ($2), $5);
+ $$ = build_decl_list (TREE_PURPOSE ($2), $$);
+ }
+ ;
+
+type_quals:
+ /* empty */ %prec EMPTY
+ { $$ = NULL_TREE; }
+ | type_quals TYPE_QUAL
+ { $$ = decl_tree_cons (NULL_TREE, $2, $$); }
+ ;
+
+nonempty_type_quals:
+ TYPE_QUAL
+ { $$ = IDENTIFIER_AS_LIST ($$); }
+ | nonempty_type_quals TYPE_QUAL
+ { $$ = decl_tree_cons (NULL_TREE, $2, $$); }
+ ;
+
+/* These rules must follow the rules for function declarations
+ and component declarations. That way, longer rules are preferred. */
+
+suspend_mom:
+ { $<itype>$ = suspend_momentary (); }
+
+/* An expression which will not live on the momentary obstack. */
+nonmomentary_expr:
+ suspend_mom expr
+ { resume_momentary ((int) $<itype>1); $$ = $2; }
+ ;
+
+/* An expression which will not live on the momentary obstack. */
+maybe_parmlist:
+ suspend_mom '(' nonnull_exprlist ')'
+ { resume_momentary ((int) $<itype>1); $$ = $3; }
+ | suspend_mom '(' parmlist ')'
+ { resume_momentary ((int) $<itype>1); $$ = $3; }
+ | suspend_mom LEFT_RIGHT
+ { resume_momentary ((int) $<itype>1); $$ = empty_parms (); }
+ | suspend_mom '(' error ')'
+ { resume_momentary ((int) $<itype>1); $$ = NULL_TREE; }
+ ;
+
+/* A declarator that is allowed only after an explicit typespec. */
+/* may all be followed by prec '.' */
+after_type_declarator:
+ '*' nonempty_type_quals after_type_declarator %prec UNARY
+ { $$ = make_pointer_declarator ($2, $3); }
+ | '&' nonempty_type_quals after_type_declarator %prec UNARY
+ { $$ = make_reference_declarator ($2, $3); }
+ | '*' after_type_declarator %prec UNARY
+ { $$ = make_pointer_declarator (NULL_TREE, $2); }
+ | '&' after_type_declarator %prec UNARY
+ { $$ = make_reference_declarator (NULL_TREE, $2); }
+ | ptr_to_mem type_quals after_type_declarator
+ { tree arg = make_pointer_declarator ($2, $3);
+ $$ = build_parse_node (SCOPE_REF, $1, arg);
+ }
+ | direct_after_type_declarator
+ ;
+
+qualified_type_name:
+ type_name %prec EMPTY
+ {
+ /* Remember that this name has been used in the class
+ definition, as per [class.scope0] */
+ if (current_class_type
+ && TYPE_BEING_DEFINED (current_class_type)
+ && ! IDENTIFIER_CLASS_VALUE ($$))
+ {
+ tree t = lookup_name ($$, -2);
+ if (t)
+ pushdecl_class_level (t);
+ }
+ }
+ | nested_type
+ ;
+
+nested_type:
+ nested_name_specifier type_name %prec EMPTY
+ { $$ = $2; }
+ ;
+
+direct_after_type_declarator:
+ direct_after_type_declarator maybe_parmlist type_quals %prec '.'
+ { $$ = build_parse_node (CALL_EXPR, $$, $2, $3); }
+ | direct_after_type_declarator '[' nonmomentary_expr ']'
+ { $$ = build_parse_node (ARRAY_REF, $$, $3); }
+ | direct_after_type_declarator '[' ']'
+ { $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); }
+ | '(' after_type_declarator ')'
+ { $$ = $2; }
+ | nested_name_specifier type_name %prec EMPTY
+ { push_nested_class (TREE_TYPE ($$), 3);
+ $$ = build_parse_node (SCOPE_REF, $$, $2);
+ TREE_COMPLEXITY ($$) = current_class_depth; }
+ | type_name %prec EMPTY
+ ;
+
+/* A declarator allowed whether or not there has been
+ an explicit typespec. These cannot redeclare a typedef-name. */
+
+notype_declarator:
+ '*' nonempty_type_quals notype_declarator %prec UNARY
+ { $$ = make_pointer_declarator ($2, $3); }
+ | '&' nonempty_type_quals notype_declarator %prec UNARY
+ { $$ = make_reference_declarator ($2, $3); }
+ | '*' notype_declarator %prec UNARY
+ { $$ = make_pointer_declarator (NULL_TREE, $2); }
+ | '&' notype_declarator %prec UNARY
+ { $$ = make_reference_declarator (NULL_TREE, $2); }
+ | ptr_to_mem type_quals notype_declarator
+ { tree arg = make_pointer_declarator ($2, $3);
+ $$ = build_parse_node (SCOPE_REF, $1, arg);
+ }
+ | direct_notype_declarator
+ ;
+
+complex_notype_declarator:
+ '*' nonempty_type_quals notype_declarator %prec UNARY
+ { $$ = make_pointer_declarator ($2, $3); }
+ | '&' nonempty_type_quals notype_declarator %prec UNARY
+ { $$ = make_reference_declarator ($2, $3); }
+ | '*' complex_notype_declarator %prec UNARY
+ { $$ = make_pointer_declarator (NULL_TREE, $2); }
+ | '&' complex_notype_declarator %prec UNARY
+ { $$ = make_reference_declarator (NULL_TREE, $2); }
+ | ptr_to_mem type_quals notype_declarator
+ { tree arg = make_pointer_declarator ($2, $3);
+ $$ = build_parse_node (SCOPE_REF, $1, arg);
+ }
+ | complex_direct_notype_declarator
+ ;
+
+complex_direct_notype_declarator:
+ direct_notype_declarator maybe_parmlist type_quals %prec '.'
+ { $$ = build_parse_node (CALL_EXPR, $$, $2, $3); }
+ | '(' complex_notype_declarator ')'
+ { $$ = $2; }
+ | direct_notype_declarator '[' nonmomentary_expr ']'
+ { $$ = build_parse_node (ARRAY_REF, $$, $3); }
+ | direct_notype_declarator '[' ']'
+ { $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); }
+ | notype_qualified_id
+ { if (TREE_TYPE (OP0 ($$)) != current_class_type)
+ {
+ push_nested_class (TREE_TYPE (OP0 ($$)), 3);
+ TREE_COMPLEXITY ($$) = current_class_depth;
+ }
+ }
+ ;
+
+qualified_id:
+ nested_name_specifier unqualified_id
+ { got_scope = NULL_TREE;
+ $$ = build_parse_node (SCOPE_REF, $$, $2); }
+ ;
+
+notype_qualified_id:
+ nested_name_specifier notype_unqualified_id
+ { got_scope = NULL_TREE;
+ $$ = build_parse_node (SCOPE_REF, $$, $2); }
+ ;
+
+overqualified_id:
+ notype_qualified_id
+ | global_scope notype_qualified_id
+ { $$ = $2; }
+ ;
+
+functional_cast:
+ typespec '(' nonnull_exprlist ')'
+ { $$ = build_functional_cast ($$, $3); }
+ | typespec '(' expr_or_declarator ')'
+ { $$ = reparse_decl_as_expr ($$, $3); }
+ | typespec fcast_or_absdcl %prec EMPTY
+ { $$ = reparse_absdcl_as_expr ($$, $2); }
+ ;
+
+type_name:
+ TYPENAME
+ | template_type %prec EMPTY
+ ;
+
+nested_name_specifier:
+ nested_name_specifier_1
+ | nested_name_specifier nested_name_specifier_1
+ { $$ = $2; }
+ ;
+
+/* Why the @#$%^& do type_name and notype_identifier need to be expanded
+ inline here?!? (jason) */
+nested_name_specifier_1:
+ TYPENAME SCOPE
+ { got_scope = TREE_TYPE ($$); }
+ | NSNAME SCOPE
+ { got_scope = $$; }
+ | template_type SCOPE
+ { got_scope = TREE_TYPE ($$); }
+/* These break 'const i;'
+ | IDENTIFIER SCOPE
+ {
+ failed_scope:
+ cp_error ("`%D' is not an aggregate typedef",
+ lastiddecl ? lastiddecl : $$);
+ $$ = error_mark_node;
+ }
+ | PTYPENAME SCOPE
+ { goto failed_scope; } */
+ ;
+
+complete_type_name:
+ qualified_type_name
+ | global_scope qualified_type_name
+ { $$ = $2; }
+ ;
+
+complex_type_name:
+ nested_type
+ | global_scope qualified_type_name
+ { $$ = $2; }
+ ;
+
+ptr_to_mem:
+ nested_name_specifier '*'
+ { got_scope = NULL_TREE; }
+ | global_scope nested_name_specifier '*'
+ { $$ = $2; got_scope = NULL_TREE; }
+ ;
+
+/* All uses of explicit global scope must go through this nonterminal so
+ that got_scope will be set before yylex is called to get the next token. */
+global_scope:
+ SCOPE
+ { got_scope = void_type_node; }
+ ;
+
+/* ANSI new-declarator (5.3.4) */
+new_declarator:
+ '*' type_quals new_declarator
+ { $$ = make_pointer_declarator ($2, $3); }
+ | '*' type_quals %prec EMPTY
+ { $$ = make_pointer_declarator ($2, NULL_TREE); }
+ | '&' type_quals new_declarator %prec EMPTY
+ { $$ = make_reference_declarator ($2, $3); }
+ | '&' type_quals %prec EMPTY
+ { $$ = make_reference_declarator ($2, NULL_TREE); }
+ | ptr_to_mem type_quals %prec EMPTY
+ { tree arg = make_pointer_declarator ($2, NULL_TREE);
+ $$ = build_parse_node (SCOPE_REF, $1, arg);
+ }
+ | ptr_to_mem type_quals new_declarator
+ { tree arg = make_pointer_declarator ($2, $3);
+ $$ = build_parse_node (SCOPE_REF, $1, arg);
+ }
+ | direct_new_declarator %prec EMPTY
+ ;
+
+/* ANSI direct-new-declarator (5.3.4) */
+direct_new_declarator:
+ '[' expr ']'
+ { $$ = build_parse_node (ARRAY_REF, NULL_TREE, $2); }
+ | direct_new_declarator '[' nonmomentary_expr ']'
+ { $$ = build_parse_node (ARRAY_REF, $$, $3); }
+ ;
+
+/* ANSI abstract-declarator (8.1) */
+absdcl:
+ '*' nonempty_type_quals absdcl
+ { $$ = make_pointer_declarator ($2, $3); }
+ | '*' absdcl
+ { $$ = make_pointer_declarator (NULL_TREE, $2); }
+ | '*' nonempty_type_quals %prec EMPTY
+ { $$ = make_pointer_declarator ($2, NULL_TREE); }
+ | '*' %prec EMPTY
+ { $$ = make_pointer_declarator (NULL_TREE, NULL_TREE); }
+ | '&' nonempty_type_quals absdcl
+ { $$ = make_reference_declarator ($2, $3); }
+ | '&' absdcl
+ { $$ = make_reference_declarator (NULL_TREE, $2); }
+ | '&' nonempty_type_quals %prec EMPTY
+ { $$ = make_reference_declarator ($2, NULL_TREE); }
+ | '&' %prec EMPTY
+ { $$ = make_reference_declarator (NULL_TREE, NULL_TREE); }
+ | ptr_to_mem type_quals %prec EMPTY
+ { tree arg = make_pointer_declarator ($2, NULL_TREE);
+ $$ = build_parse_node (SCOPE_REF, $1, arg);
+ }
+ | ptr_to_mem type_quals absdcl
+ { tree arg = make_pointer_declarator ($2, $3);
+ $$ = build_parse_node (SCOPE_REF, $1, arg);
+ }
+ | direct_abstract_declarator %prec EMPTY
+ ;
+
+/* ANSI direct-abstract-declarator (8.1) */
+direct_abstract_declarator:
+ '(' absdcl ')'
+ { $$ = $2; }
+ /* `(typedef)1' is `int'. */
+ | PAREN_STAR_PAREN
+ | direct_abstract_declarator '(' parmlist ')' type_quals %prec '.'
+ { $$ = build_parse_node (CALL_EXPR, $$, $3, $5); }
+ | direct_abstract_declarator LEFT_RIGHT type_quals %prec '.'
+ { $$ = build_parse_node (CALL_EXPR, $$, empty_parms (), $3); }
+ | direct_abstract_declarator '[' nonmomentary_expr ']' %prec '.'
+ { $$ = build_parse_node (ARRAY_REF, $$, $3); }
+ | direct_abstract_declarator '[' ']' %prec '.'
+ { $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); }
+ | '(' complex_parmlist ')' type_quals %prec '.'
+ { $$ = build_parse_node (CALL_EXPR, NULL_TREE, $2, $4); }
+ | regcast_or_absdcl type_quals %prec '.'
+ { TREE_OPERAND ($$, 2) = $2; }
+ | fcast_or_absdcl type_quals %prec '.'
+ { TREE_OPERAND ($$, 2) = $2; }
+ | '[' nonmomentary_expr ']' %prec '.'
+ { $$ = build_parse_node (ARRAY_REF, NULL_TREE, $2); }
+ | '[' ']' %prec '.'
+ { $$ = build_parse_node (ARRAY_REF, NULL_TREE, NULL_TREE); }
+ ;
+
+/* For C++, decls and stmts can be intermixed, so we don't need to
+ have a special rule that won't start parsing the stmt section
+ until we have a stmt that parses without errors. */
+
+stmts:
+ stmt
+ | errstmt
+ | stmts stmt
+ | stmts errstmt
+ ;
+
+errstmt: error ';'
+ ;
+
+/* build the LET_STMT node before parsing its contents,
+ so that any LET_STMTs within the context can have their display pointers
+ set up to point at this one. */
+
+.pushlevel: /* empty */
+ { emit_line_note (input_filename, lineno);
+ pushlevel (0);
+ clear_last_expr ();
+ push_momentary ();
+ expand_start_bindings (0); }
+ ;
+
+.poplevel: /* empty */
+ { expand_end_bindings (getdecls (), kept_level_p (), 1);
+ $$ = poplevel (kept_level_p (), 1, 0);
+ pop_momentary (); }
+ ;
+
+/* Read zero or more forward-declarations for labels
+ that nested functions can jump to. */
+maybe_label_decls:
+ /* empty */
+ | label_decls
+ { if (pedantic)
+ pedwarn ("ANSI C++ forbids label declarations"); }
+ ;
+
+label_decls:
+ label_decl
+ | label_decls label_decl
+ ;
+
+label_decl:
+ LABEL identifiers_or_typenames ';'
+ { tree link;
+ for (link = $2; link; link = TREE_CHAIN (link))
+ {
+ tree label = shadow_label (TREE_VALUE (link));
+ C_DECLARED_LABEL_FLAG (label) = 1;
+ declare_nonlocal_label (label);
+ }
+ }
+ ;
+
+/* This is the body of a function definition.
+ It causes syntax errors to ignore to the next openbrace. */
+compstmt_or_error:
+ compstmt
+ {}
+ | error compstmt
+ ;
+
+compstmt: '{' .pushlevel compstmtend .poplevel
+ { $$ = $4; }
+ ;
+
+simple_if:
+ IF
+ { cond_stmt_keyword = "if"; }
+ .pushlevel paren_cond_or_null
+ { emit_line_note (input_filename, lineno);
+ expand_start_cond ($4, 0); }
+ implicitly_scoped_stmt
+ ;
+
+implicitly_scoped_stmt:
+ compstmt
+ { finish_stmt (); }
+ | .pushlevel simple_stmt .poplevel
+ { $$ = $3; }
+ ;
+
+stmt:
+ compstmt
+ { finish_stmt (); }
+ | simple_stmt
+ ;
+
+simple_stmt:
+ decl
+ { finish_stmt (); }
+ | expr ';'
+ {
+ tree expr = $1;
+ emit_line_note (input_filename, lineno);
+ /* Do default conversion if safe and possibly important,
+ in case within ({...}). */
+ if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
+ && lvalue_p (expr))
+ || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
+ expr = default_conversion (expr);
+ cplus_expand_expr_stmt (expr);
+ clear_momentary ();
+ finish_stmt (); }
+ | simple_if ELSE
+ { expand_start_else (); }
+ implicitly_scoped_stmt
+ { expand_end_cond (); }
+ .poplevel
+ { finish_stmt (); }
+ | simple_if %prec IF
+ { expand_end_cond ();
+ expand_end_bindings (getdecls (), kept_level_p (), 1);
+ poplevel (kept_level_p (), 1, 0);
+ pop_momentary ();
+ finish_stmt (); }
+ | WHILE
+ { emit_nop ();
+ emit_line_note (input_filename, lineno);
+ expand_start_loop (1);
+ cond_stmt_keyword = "while"; }
+ .pushlevel paren_cond_or_null
+ { expand_exit_loop_if_false (0, $4); }
+ already_scoped_stmt .poplevel
+ { expand_end_loop ();
+ finish_stmt (); }
+ | DO
+ { emit_nop ();
+ emit_line_note (input_filename, lineno);
+ expand_start_loop_continue_elsewhere (1); }
+ implicitly_scoped_stmt WHILE
+ { expand_loop_continue_here ();
+ cond_stmt_keyword = "do"; }
+ paren_expr_or_null ';'
+ { emit_line_note (input_filename, lineno);
+ expand_exit_loop_if_false (0, $6);
+ expand_end_loop ();
+ clear_momentary ();
+ finish_stmt (); }
+ | FOR
+ { emit_line_note (input_filename, lineno);
+ if (flag_new_for_scope > 0)
+ {
+ /* Conditionalize .pushlevel */
+ pushlevel (0);
+ note_level_for_for ();
+ clear_last_expr ();
+ push_momentary ();
+ expand_start_bindings (0);
+ }
+ }
+ '(' for.init.statement
+ { emit_nop ();
+ emit_line_note (input_filename, lineno);
+ expand_start_loop_continue_elsewhere (1); }
+ .pushlevel xcond ';'
+ { emit_line_note (input_filename, lineno);
+ if ($7) expand_exit_loop_if_false (0, $7); }
+ xexpr ')'
+ /* Don't let the tree nodes for $10 be discarded
+ by clear_momentary during the parsing of the next stmt. */
+ { push_momentary (); }
+ already_scoped_stmt .poplevel
+ { emit_line_note (input_filename, lineno);
+ expand_loop_continue_here ();
+ if ($10) cplus_expand_expr_stmt ($10);
+ pop_momentary ();
+ expand_end_loop ();
+ if (flag_new_for_scope > 0)
+ {
+ expand_end_bindings (getdecls (), kept_level_p (), 1);
+ poplevel (kept_level_p (), 1, 0);
+ pop_momentary ();
+ }
+ finish_stmt (); }
+ | SWITCH .pushlevel '(' condition ')'
+ { emit_line_note (input_filename, lineno);
+ c_expand_start_case ($4);
+ push_switch ();
+ /* Don't let the tree nodes for $4 be discarded by
+ clear_momentary during the parsing of the next stmt. */
+ push_momentary (); }
+ implicitly_scoped_stmt
+ { expand_end_case ($4);
+ pop_momentary ();
+ pop_switch (); }
+ .poplevel
+ { finish_stmt (); }
+ | CASE expr_no_commas ':'
+ { register tree value = check_cp_case_value ($2);
+ register tree label
+ = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+
+ if (value != error_mark_node)
+ {
+ tree duplicate;
+ int success = pushcase (value, convert_and_check,
+ label, &duplicate);
+ if (success == 1)
+ cp_error ("case label `%E' not within a switch statement", $2);
+ else if (success == 2)
+ {
+ cp_error ("duplicate case value `%E'", $2);
+ cp_error_at ("previously used here", duplicate);
+ }
+ else if (success == 3)
+ warning ("case value out of range");
+ else if (success == 5)
+ cp_error ("case label `%E' within scope of cleanup or variable array", $2);
+ }
+ define_case_label (label);
+ }
+ stmt
+ | CASE expr_no_commas ELLIPSIS expr_no_commas ':'
+ { register tree value1 = check_cp_case_value ($2);
+ register tree value2 = check_cp_case_value ($4);
+ register tree label
+ = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+
+ if (pedantic)
+ pedwarn ("ANSI C++ forbids range expressions in switch statement");
+ if (value1 != error_mark_node
+ && value2 != error_mark_node)
+ {
+ tree duplicate;
+ int success = pushcase_range (value1, value2,
+ convert_and_check, label,
+ &duplicate);
+ if (success == 1)
+ error ("case label not within a switch statement");
+ else if (success == 2)
+ {
+ error ("duplicate (or overlapping) case value");
+ error_with_decl (duplicate, "this is the first entry overlapping that value");
+ }
+ else if (success == 3)
+ warning ("case value out of range");
+ else if (success == 4)
+ warning ("empty range specified");
+ else if (success == 5)
+ error ("case label within scope of cleanup or variable array");
+ }
+ define_case_label (label);
+ }
+ stmt
+ | DEFAULT ':'
+ {
+ tree duplicate;
+ register tree label
+ = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+ int success = pushcase (NULL_TREE, 0, label, &duplicate);
+ if (success == 1)
+ error ("default label not within a switch statement");
+ else if (success == 2)
+ {
+ error ("multiple default labels in one switch");
+ error_with_decl (duplicate, "this is the first default label");
+ }
+ define_case_label (NULL_TREE);
+ }
+ stmt
+ | BREAK ';'
+ { emit_line_note (input_filename, lineno);
+ if ( ! expand_exit_something ())
+ error ("break statement not within loop or switch"); }
+ | CONTINUE ';'
+ { emit_line_note (input_filename, lineno);
+ if (! expand_continue_loop (0))
+ error ("continue statement not within a loop"); }
+ | RETURN ';'
+ { emit_line_note (input_filename, lineno);
+ c_expand_return (NULL_TREE); }
+ | RETURN expr ';'
+ { emit_line_note (input_filename, lineno);
+ c_expand_return ($2);
+ finish_stmt ();
+ }
+ | asm_keyword maybe_type_qual '(' string ')' ';'
+ { if (TREE_CHAIN ($4)) $4 = combine_strings ($4);
+ emit_line_note (input_filename, lineno);
+ expand_asm ($4);
+ finish_stmt ();
+ }
+ /* This is the case with just output operands. */
+ | asm_keyword maybe_type_qual '(' string ':' asm_operands ')' ';'
+ { if (TREE_CHAIN ($4)) $4 = combine_strings ($4);
+ emit_line_note (input_filename, lineno);
+ c_expand_asm_operands ($4, $6, NULL_TREE, NULL_TREE,
+ $2 == ridpointers[(int)RID_VOLATILE],
+ input_filename, lineno);
+ finish_stmt ();
+ }
+ /* This is the case with input operands as well. */
+ | asm_keyword maybe_type_qual '(' string ':' asm_operands ':' asm_operands ')' ';'
+ { if (TREE_CHAIN ($4)) $4 = combine_strings ($4);
+ emit_line_note (input_filename, lineno);
+ c_expand_asm_operands ($4, $6, $8, NULL_TREE,
+ $2 == ridpointers[(int)RID_VOLATILE],
+ input_filename, lineno);
+ finish_stmt ();
+ }
+ /* This is the case with clobbered registers as well. */
+ | asm_keyword maybe_type_qual '(' string ':' asm_operands ':'
+ asm_operands ':' asm_clobbers ')' ';'
+ { if (TREE_CHAIN ($4)) $4 = combine_strings ($4);
+ emit_line_note (input_filename, lineno);
+ c_expand_asm_operands ($4, $6, $8, $10,
+ $2 == ridpointers[(int)RID_VOLATILE],
+ input_filename, lineno);
+ finish_stmt ();
+ }
+ | GOTO '*' expr ';'
+ { emit_line_note (input_filename, lineno);
+ expand_computed_goto ($3); }
+ | GOTO identifier ';'
+ { tree decl;
+ emit_line_note (input_filename, lineno);
+ decl = lookup_label ($2);
+ TREE_USED (decl) = 1;
+ expand_goto (decl); }
+ | label_colon stmt
+ { finish_stmt (); }
+ | label_colon '}'
+ { error ("label must be followed by statement");
+ yyungetc ('}', 0);
+ finish_stmt (); }
+ | ';'
+ { finish_stmt (); }
+ | try_block
+ ;
+
+function_try_block:
+ TRY
+ {
+ if (! current_function_parms_stored)
+ store_parm_decls ();
+ expand_start_early_try_stmts ();
+ }
+ ctor_initializer_opt compstmt_or_error
+ { expand_end_try_stmts ();
+ expand_start_all_catch (); }
+ handler_seq
+ {
+ expand_end_all_catch ();
+ finish_function (lineno, (int)$3, 0);
+ }
+ ;
+
+try_block:
+ TRY
+ { expand_start_try_stmts (); }
+ compstmt
+ { expand_end_try_stmts ();
+ expand_start_all_catch (); }
+ handler_seq
+ { expand_end_all_catch (); }
+ ;
+
+handler_seq:
+ /* empty */
+ | handler_seq CATCH .pushlevel
+ { dont_allow_type_definitions = "inside exception declarations"; }
+ handler_args
+ { dont_allow_type_definitions = 0; }
+ compstmt
+ { expand_end_catch_block (); }
+ .poplevel
+ ;
+
+type_specifier_seq:
+ typed_typespecs %prec EMPTY
+ | nonempty_type_quals %prec EMPTY
+ ;
+
+handler_args:
+ '(' ELLIPSIS ')'
+ { expand_start_catch_block (NULL_TREE, NULL_TREE); }
+ /* This doesn't allow reference parameters, the below does.
+ | '(' type_specifier_seq absdcl ')'
+ { expand_start_catch_block ($2, $3); }
+ | '(' type_specifier_seq ')'
+ { expand_start_catch_block ($2, NULL_TREE); }
+ | '(' type_specifier_seq notype_declarator ')'
+ { expand_start_catch_block ($2, $3); }
+ | '(' typed_typespecs after_type_declarator ')'
+ { expand_start_catch_block ($2, $3); }
+ This allows reference parameters... */
+ | '(' parm ')'
+ { expand_start_catch_block (TREE_PURPOSE ($2),
+ TREE_VALUE ($2)); }
+ ;
+
+label_colon:
+ IDENTIFIER ':'
+ { tree label;
+ do_label:
+ label = define_label (input_filename, lineno, $1);
+ if (label)
+ expand_label (label);
+ }
+ | PTYPENAME ':'
+ { goto do_label; }
+ | TYPENAME ':'
+ { goto do_label; }
+ ;
+
+for.init.statement:
+ xexpr ';'
+ { if ($1) cplus_expand_expr_stmt ($1); }
+ | decl
+ | '{' compstmtend
+ ;
+
+/* Either a type-qualifier or nothing. First thing in an `asm' statement. */
+
+maybe_type_qual:
+ /* empty */
+ { emit_line_note (input_filename, lineno);
+ $$ = NULL_TREE; }
+ | TYPE_QUAL
+ { emit_line_note (input_filename, lineno); }
+ ;
+
+xexpr:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | expr
+ | error
+ { $$ = NULL_TREE; }
+ ;
+
+/* These are the operands other than the first string and colon
+ in asm ("addextend %2,%1": "=dm" (x), "0" (y), "g" (*x)) */
+asm_operands: /* empty */
+ { $$ = NULL_TREE; }
+ | nonnull_asm_operands
+ ;
+
+nonnull_asm_operands:
+ asm_operand
+ | nonnull_asm_operands ',' asm_operand
+ { $$ = chainon ($$, $3); }
+ ;
+
+asm_operand:
+ STRING '(' expr ')'
+ { $$ = build_tree_list ($$, $3); }
+ ;
+
+asm_clobbers:
+ STRING
+ { $$ = tree_cons (NULL_TREE, $$, NULL_TREE); }
+ | asm_clobbers ',' STRING
+ { $$ = tree_cons (NULL_TREE, $3, $$); }
+ ;
+
+/* This is what appears inside the parens in a function declarator.
+ Its value is represented in the format that grokdeclarator expects.
+
+ In C++, declaring a function with no parameters
+ means that that function takes *no* parameters. */
+
+parmlist: /* empty */
+ {
+ if (strict_prototype)
+ $$ = void_list_node;
+ else
+ $$ = NULL_TREE;
+ }
+ | complex_parmlist
+ | type_id
+ { $$ = tree_cons (NULL_TREE, $$, void_list_node);
+ TREE_PARMLIST ($$) = 1; }
+ ;
+
+/* This nonterminal does not include the common sequence '(' type_id ')',
+ as it is ambiguous and must be disambiguated elsewhere. */
+complex_parmlist:
+ parms
+ {
+ $$ = chainon ($$, void_list_node);
+ TREE_PARMLIST ($$) = 1;
+ }
+ | parms_comma ELLIPSIS
+ {
+ TREE_PARMLIST ($$) = 1;
+ }
+ /* C++ allows an ellipsis without a separating ',' */
+ | parms ELLIPSIS
+ {
+ TREE_PARMLIST ($$) = 1;
+ }
+ | type_id ELLIPSIS
+ {
+ $$ = build_tree_list (NULL_TREE, $$);
+ TREE_PARMLIST ($$) = 1;
+ }
+ | ELLIPSIS
+ {
+ /* ARM $8.2.5 has this as a boxed-off comment. */
+ if (pedantic)
+ warning ("use of `...' without a first argument is non-portable");
+ $$ = NULL_TREE;
+ }
+ | TYPENAME_ELLIPSIS
+ {
+ TREE_PARMLIST ($$) = 1;
+ }
+ | parms TYPENAME_ELLIPSIS
+ {
+ TREE_PARMLIST ($$) = 1;
+ }
+ | type_id TYPENAME_ELLIPSIS
+ {
+ $$ = build_tree_list (NULL_TREE, $$);
+ TREE_PARMLIST ($$) = 1;
+ }
+ | parms ':'
+ {
+ /* This helps us recover from really nasty
+ parse errors, for example, a missing right
+ parenthesis. */
+ yyerror ("possibly missing ')'");
+ $$ = chainon ($$, void_list_node);
+ TREE_PARMLIST ($$) = 1;
+ yyungetc (':', 0);
+ yychar = ')';
+ }
+ | type_id ':'
+ {
+ /* This helps us recover from really nasty
+ parse errors, for example, a missing right
+ parenthesis. */
+ yyerror ("possibly missing ')'");
+ $$ = tree_cons (NULL_TREE, $$, void_list_node);
+ TREE_PARMLIST ($$) = 1;
+ yyungetc (':', 0);
+ yychar = ')';
+ }
+ ;
+
+/* A nonempty list of parameter declarations or type names. */
+parms:
+ named_parm
+ { $$ = build_tree_list (NULL_TREE, $$); }
+ | parm '=' init
+ { $$ = build_tree_list ($3, $$); }
+ | parms_comma full_parm
+ { $$ = chainon ($$, $2); }
+ | parms_comma bad_parm
+ { $$ = chainon ($$, build_tree_list (NULL_TREE, $2)); }
+ | parms_comma bad_parm '=' init
+ { $$ = chainon ($$, build_tree_list ($4, $2)); }
+ ;
+
+parms_comma:
+ parms ','
+ | type_id ','
+ { $$ = build_tree_list (NULL_TREE, $$); }
+ ;
+
+/* A single parameter declaration or parameter type name,
+ as found in a parmlist. The first four cases make up for 10%
+ of the time spent parsing C++. We cannot use them because
+ of `int id[]' which won't get parsed properly. */
+named_parm:
+/*
+ typed_declspecs dont_see_typename '*' IDENTIFIER
+ { tree specs = strip_attrs ($1);
+ $$ = build_tree_list (specs, build_parse_node (INDIRECT_REF, $4));
+ see_typename (); }
+ | typed_declspecs dont_see_typename '&' IDENTIFIER
+ { tree specs = strip_attrs ($1);
+ $$ = build_tree_list (specs, build_parse_node (ADDR_EXPR, $4));
+ see_typename (); }
+ | TYPENAME IDENTIFIER
+ { $$ = build_tree_list (get_decl_list ($$), $2); }
+ | TYPESPEC IDENTIFIER
+ { $$ = build_tree_list (get_decl_list ($$), $2); }
+ | */
+ /* Here we expand typed_declspecs inline to avoid mis-parsing of
+ TYPESPEC IDENTIFIER. */
+ typed_declspecs1 declarator
+ { tree specs = strip_attrs ($1);
+ $$ = build_tree_list (specs, $2); }
+ | typed_typespecs declarator
+ { $$ = build_tree_list ($$, $2); }
+ | typespec declarator
+ { $$ = build_tree_list (get_decl_list ($$), $2); }
+ | typed_declspecs1 absdcl
+ { tree specs = strip_attrs ($1);
+ $$ = build_tree_list (specs, $2); }
+ | typed_declspecs1 %prec EMPTY
+ { tree specs = strip_attrs ($1);
+ $$ = build_tree_list (specs, NULL_TREE); }
+ | declmods notype_declarator
+ { tree specs = strip_attrs ($1);
+ $$ = build_tree_list (specs, $2); }
+ ;
+
+full_parm:
+ parm maybe_init
+ { $$ = build_tree_list ($2, $$); }
+ ;
+
+parm:
+ named_parm
+ | type_id
+ ;
+
+see_typename: %prec EMPTY
+ { see_typename (); }
+ ;
+
+/*
+dont_see_typename: %prec EMPTY
+ { dont_see_typename (); }
+ ;
+
+try_for_typename:
+ {
+ if ($<ttype>-1 == error_mark_node)
+ $$ = 0;
+ else
+ {
+ $$ = 1;
+ pushclass ($<ttype>-1, 1);
+ }
+ }
+ ;
+*/
+
+bad_parm:
+ /* empty */ %prec EMPTY
+ {
+ error ("type specifier omitted for parameter");
+ $$ = build_tree_list (integer_type_node, NULL_TREE);
+ }
+ | notype_declarator
+ {
+ error ("type specifier omitted for parameter");
+ $$ = build_tree_list (integer_type_node, $$);
+ }
+ ;
+
+exception_specification_opt:
+ %prec EMPTY /* empty */
+ { $$ = NULL_TREE; }
+ | THROW '(' ansi_raise_identifiers ')' %prec EMPTY
+ { $$ = $3; }
+ | THROW LEFT_RIGHT %prec EMPTY
+ { $$ = build_decl_list (NULL_TREE, NULL_TREE); }
+ ;
+
+ansi_raise_identifier:
+ type_id
+ { $$ = build_decl_list (NULL_TREE, groktypename($$)); }
+ ;
+
+ansi_raise_identifiers:
+ ansi_raise_identifier
+ | ansi_raise_identifiers ',' ansi_raise_identifier
+ {
+ TREE_CHAIN ($3) = $$;
+ $$ = $3;
+ }
+ ;
+
+conversion_declarator:
+ /* empty */ %prec EMPTY
+ { $$ = NULL_TREE; }
+ | '*' type_quals conversion_declarator
+ { $$ = make_pointer_declarator ($2, $3); }
+ | '&' type_quals conversion_declarator
+ { $$ = make_reference_declarator ($2, $3); }
+ | ptr_to_mem type_quals conversion_declarator
+ { tree arg = make_pointer_declarator ($2, $3);
+ $$ = build_parse_node (SCOPE_REF, $1, arg);
+ }
+ ;
+
+operator: OPERATOR
+ { got_scope = NULL_TREE; }
+ ;
+
+operator_name:
+ operator '*'
+ { $$ = ansi_opname[MULT_EXPR]; }
+ | operator '/'
+ { $$ = ansi_opname[TRUNC_DIV_EXPR]; }
+ | operator '%'
+ { $$ = ansi_opname[TRUNC_MOD_EXPR]; }
+ | operator '+'
+ { $$ = ansi_opname[PLUS_EXPR]; }
+ | operator '-'
+ { $$ = ansi_opname[MINUS_EXPR]; }
+ | operator '&'
+ { $$ = ansi_opname[BIT_AND_EXPR]; }
+ | operator '|'
+ { $$ = ansi_opname[BIT_IOR_EXPR]; }
+ | operator '^'
+ { $$ = ansi_opname[BIT_XOR_EXPR]; }
+ | operator '~'
+ { $$ = ansi_opname[BIT_NOT_EXPR]; }
+ | operator ','
+ { $$ = ansi_opname[COMPOUND_EXPR]; }
+ | operator ARITHCOMPARE
+ { $$ = ansi_opname[$2]; }
+ | operator '<'
+ { $$ = ansi_opname[LT_EXPR]; }
+ | operator '>'
+ { $$ = ansi_opname[GT_EXPR]; }
+ | operator EQCOMPARE
+ { $$ = ansi_opname[$2]; }
+ | operator ASSIGN
+ { $$ = ansi_assopname[$2]; }
+ | operator '='
+ { $$ = ansi_opname [MODIFY_EXPR]; }
+ | operator LSHIFT
+ { $$ = ansi_opname[$2]; }
+ | operator RSHIFT
+ { $$ = ansi_opname[$2]; }
+ | operator PLUSPLUS
+ { $$ = ansi_opname[POSTINCREMENT_EXPR]; }
+ | operator MINUSMINUS
+ { $$ = ansi_opname[PREDECREMENT_EXPR]; }
+ | operator ANDAND
+ { $$ = ansi_opname[TRUTH_ANDIF_EXPR]; }
+ | operator OROR
+ { $$ = ansi_opname[TRUTH_ORIF_EXPR]; }
+ | operator '!'
+ { $$ = ansi_opname[TRUTH_NOT_EXPR]; }
+ | operator '?' ':'
+ { $$ = ansi_opname[COND_EXPR]; }
+ | operator MIN_MAX
+ { $$ = ansi_opname[$2]; }
+ | operator POINTSAT %prec EMPTY
+ { $$ = ansi_opname[COMPONENT_REF]; }
+ | operator POINTSAT_STAR %prec EMPTY
+ { $$ = ansi_opname[MEMBER_REF]; }
+ | operator LEFT_RIGHT
+ { $$ = ansi_opname[CALL_EXPR]; }
+ | operator '[' ']'
+ { $$ = ansi_opname[ARRAY_REF]; }
+ | operator NEW %prec EMPTY
+ { $$ = ansi_opname[NEW_EXPR]; }
+ | operator DELETE %prec EMPTY
+ { $$ = ansi_opname[DELETE_EXPR]; }
+ | operator NEW '[' ']'
+ { $$ = ansi_opname[VEC_NEW_EXPR]; }
+ | operator DELETE '[' ']'
+ { $$ = ansi_opname[VEC_DELETE_EXPR]; }
+ /* Names here should be looked up in class scope ALSO. */
+ | operator type_specifier_seq conversion_declarator
+ { $$ = grokoptypename ($2, $3); }
+ | operator error
+ { $$ = ansi_opname[ERROR_MARK]; }
+ ;
+
+%%
+
+#ifdef SPEW_DEBUG
+const char *
+debug_yytranslate (value)
+ int value;
+{
+ return yytname[YYTRANSLATE (value)];
+}
+
+#endif
diff --git a/gnu/usr.bin/gcc/common/bi-parser.y b/gnu/usr.bin/gcc/common/bi-parser.y
new file mode 100644
index 00000000000..0a03d0f05ad
--- /dev/null
+++ b/gnu/usr.bin/gcc/common/bi-parser.y
@@ -0,0 +1,169 @@
+/* Bytecode definition file parser.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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 Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+%{
+
+#include <stdio.h>
+#include "hconfig.h"
+#include "bi-defs.h"
+
+extern char yytext[];
+extern int yyleng;
+
+
+/* Chain of all defs built by the parser. */
+struct def *defs;
+int ndefs;
+
+static struct node *makenode ();
+static struct variation *makevar ();
+static struct def *makedef ();
+
+void yyerror ();
+
+%}
+
+%union
+{
+ char *string;
+ struct def *def;
+ struct variation *variation;
+ struct node *node;
+}
+
+%token <string> DEFOP STRING
+%type <string> opt_string
+%type <def> defs def
+%type <variation> variations variation
+%type <node> list items item
+
+%%
+
+top:
+ defs
+ { defs = $1; }
+ ;
+
+defs:
+ def
+ | defs def
+ { $2->next = $1; $$ = $2; }
+ ;
+
+def:
+ DEFOP '(' STRING ',' opt_string ',' '(' variations ')' ')'
+ { $$ = makedef ($3, $5, $8); }
+ ;
+
+variations:
+ variation
+ | variations ',' variation
+ { $3->next = $1; $$ = $3; }
+ ;
+
+variation:
+ '(' opt_string ')'
+ { $$ = makevar ($2, (struct node *) NULL, (struct node *) NULL, (struct node *) NULL); }
+ | '(' opt_string ',' list ')'
+ { $$ = makevar ($2, $4, (struct node *) NULL, (struct node *) NULL); }
+ | '(' opt_string ',' list ',' list ')'
+ { $$ = makevar ($2, $4, $6, (struct node *) NULL); }
+ | '(' opt_string ',' list ',' list ',' list ')'
+ { $$ = makevar ($2, $4, $6, $8); }
+ ;
+
+opt_string:
+ /* empty */ { $$ = ""; }
+ | STRING { $$ = $1; }
+ ;
+
+list:
+ '(' items ')'
+ { $$ = $2; }
+ | /* empty */
+ { $$ = NULL; }
+ ;
+
+items:
+ item
+ /* Note right recursion. */
+ | item ',' items
+ { $1->next = $3; $$ = $1; }
+ ;
+
+item:
+ STRING
+ { $$ = makenode ($1); }
+ ;
+
+%%
+
+static struct node *
+makenode (s)
+ char *s;
+{
+ struct node *n;
+
+ n = (struct node *) malloc (sizeof (struct node));
+ n->text = s;
+ n->next = NULL;
+ return n;
+}
+
+static struct variation *
+makevar (name, inputs, outputs, literals)
+ char *name;
+ struct node *inputs, *outputs, *literals;
+{
+ struct variation *v;
+
+ v = (struct variation *) malloc (sizeof (struct variation));
+ v->name = name;
+ v->code = ndefs++;
+ v->inputs = inputs;
+ v->outputs = outputs;
+ v->literals = literals;
+ v->next = NULL;
+ return v;
+}
+
+static struct def *
+makedef (name, template, vars)
+ char *name, *template;
+ struct variation *vars;
+{
+ struct def *d;
+
+ d = (struct def *) malloc (sizeof (struct def));
+ d->basename = name;
+ d->template = template;
+ d->variations = vars;
+ d->next = NULL;
+ return d;
+}
+
+void
+yyerror (s)
+ char *s;
+{
+ fprintf (stderr, "syntax error in input\n");
+ exit (FATAL_EXIT_CODE);
+}
diff --git a/gnu/usr.bin/gcc/common/c-parse.y b/gnu/usr.bin/gcc/common/c-parse.y
new file mode 100644
index 00000000000..e7aed2c036c
--- /dev/null
+++ b/gnu/usr.bin/gcc/common/c-parse.y
@@ -0,0 +1,2068 @@
+/* YACC parser for C syntax and for Objective C. -*-c-*-
+ Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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 Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* This file defines the grammar of C and that of Objective C.
+ ifobjc ... end ifobjc conditionals contain code for Objective C only.
+ ifc ... end ifc conditionals contain code for C only.
+ Sed commands in Makefile.in are used to convert this file into
+ c-parse.y and into objc-parse.y. */
+
+/* To whomever it may concern: I have heard that such a thing was once
+ written by AT&T, but I have never seen it. */
+
+%expect 34
+
+/* These are the 23 conflicts you should get in parse.output;
+ the state numbers may vary if minor changes in the grammar are made.
+
+State 42 contains 1 shift/reduce conflict. (Two ways to parse ATTRIBUTE.)
+State 44 contains 1 shift/reduce conflict. (Two ways to recover from error.)
+State 103 contains 1 shift/reduce conflict. (Two ways to recover from error.)
+State 110 contains 1 shift/reduce conflict. (Two ways to parse ATTRIBUTE.)
+State 111 contains 1 shift/reduce conflict. (Two ways to recover from error.)
+State 115 contains 1 shift/reduce conflict. (Two ways to recover from error.)
+State 132 contains 1 shift/reduce conflict. (See comment at component_decl.)
+State 180 contains 1 shift/reduce conflict. (Two ways to parse ATTRIBUTE.)
+State 194 contains 2 shift/reduce conflict. (Four ways to parse this.)
+State 202 contains 1 shift/reduce conflict. (Two ways to recover from error.)
+State 214 contains 1 shift/reduce conflict. (Two ways to recover from error.)
+State 220 contains 1 shift/reduce conflict. (Two ways to recover from error.)
+State 304 contains 2 shift/reduce conflicts. (Four ways to parse this.)
+State 335 contains 2 shift/reduce conflicts. (Four ways to parse this.)
+State 347 contains 1 shift/reduce conflict. (Two ways to parse ATTRIBUTES.)
+State 352 contains 1 shift/reduce conflict. (Two ways to parse ATTRIBUTES.)
+State 383 contains 2 shift/reduce conflicts. (Four ways to parse this.)
+State 434 contains 2 shift/reduce conflicts. (Four ways to parse this.) */
+
+
+%{
+#include <stdio.h>
+#include <errno.h>
+#include <setjmp.h>
+
+#include "config.h"
+#include "tree.h"
+#include "input.h"
+#include "c-lex.h"
+#include "c-tree.h"
+#include "flags.h"
+
+#ifdef MULTIBYTE_CHARS
+#include <stdlib.h>
+#include <locale.h>
+#endif
+
+
+/* Since parsers are distinct for each language, put the language string
+ definition here. */
+char *language_string = "GNU C";
+
+#ifndef errno
+extern int errno;
+#endif
+
+void yyerror ();
+
+/* Like YYERROR but do call yyerror. */
+#define YYERROR1 { yyerror ("syntax error"); YYERROR; }
+
+/* Cause the `yydebug' variable to be defined. */
+#define YYDEBUG 1
+%}
+
+%start program
+
+%union {long itype; tree ttype; enum tree_code code;
+ char *filename; int lineno; int ends_in_label; }
+
+/* All identifiers that are not reserved words
+ and are not declared typedefs in the current block */
+%token IDENTIFIER
+
+/* All identifiers that are declared typedefs in the current block.
+ In some contexts, they are treated just like IDENTIFIER,
+ but they can also serve as typespecs in declarations. */
+%token TYPENAME
+
+/* Reserved words that specify storage class.
+ yylval contains an IDENTIFIER_NODE which indicates which one. */
+%token SCSPEC
+
+/* Reserved words that specify type.
+ yylval contains an IDENTIFIER_NODE which indicates which one. */
+%token TYPESPEC
+
+/* Reserved words that qualify type: "const" or "volatile".
+ yylval contains an IDENTIFIER_NODE which indicates which one. */
+%token TYPE_QUAL
+
+/* Character or numeric constants.
+ yylval is the node for the constant. */
+%token CONSTANT
+
+/* String constants in raw form.
+ yylval is a STRING_CST node. */
+%token STRING
+
+/* "...", used for functions with variable arglists. */
+%token ELLIPSIS
+
+/* the reserved words */
+/* SCO include files test "ASM", so use something else. */
+%token SIZEOF ENUM STRUCT UNION IF ELSE WHILE DO FOR SWITCH CASE DEFAULT
+%token BREAK CONTINUE RETURN GOTO ASM_KEYWORD TYPEOF ALIGNOF
+%token ATTRIBUTE EXTENSION LABEL
+%token REALPART IMAGPART
+
+/* Add precedence rules to solve dangling else s/r conflict */
+%nonassoc IF
+%nonassoc ELSE
+
+/* Define the operator tokens and their precedences.
+ The value is an integer because, if used, it is the tree code
+ to use in the expression made from the operator. */
+
+%right <code> ASSIGN '='
+%right <code> '?' ':'
+%left <code> OROR
+%left <code> ANDAND
+%left <code> '|'
+%left <code> '^'
+%left <code> '&'
+%left <code> EQCOMPARE
+%left <code> ARITHCOMPARE
+%left <code> LSHIFT RSHIFT
+%left <code> '+' '-'
+%left <code> '*' '/' '%'
+%right <code> UNARY PLUSPLUS MINUSMINUS
+%left HYPERUNARY
+%left <code> POINTSAT '.' '(' '['
+
+/* The Objective-C keywords. These are included in C and in
+ Objective C, so that the token codes are the same in both. */
+%token INTERFACE IMPLEMENTATION END SELECTOR DEFS ENCODE
+%token CLASSNAME PUBLIC PRIVATE PROTECTED PROTOCOL OBJECTNAME CLASS ALIAS
+
+/* Objective-C string constants in raw form.
+ yylval is an OBJC_STRING_CST node. */
+%token OBJC_STRING
+
+
+%type <code> unop
+
+%type <ttype> identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist exprlist
+%type <ttype> expr_no_commas cast_expr unary_expr primary string STRING
+%type <ttype> typed_declspecs reserved_declspecs
+%type <ttype> typed_typespecs reserved_typespecquals
+%type <ttype> declmods typespec typespecqual_reserved
+%type <ttype> SCSPEC TYPESPEC TYPE_QUAL nonempty_type_quals maybe_type_qual
+%type <ttype> initdecls notype_initdecls initdcl notype_initdcl
+%type <ttype> init maybeasm
+%type <ttype> asm_operands nonnull_asm_operands asm_operand asm_clobbers
+%type <ttype> maybe_attribute attributes attribute attribute_list attrib
+%type <ttype> any_word
+
+%type <ttype> compstmt
+
+%type <ttype> declarator
+%type <ttype> notype_declarator after_type_declarator
+%type <ttype> parm_declarator
+
+%type <ttype> structsp component_decl_list component_decl_list2
+%type <ttype> component_decl components component_declarator
+%type <ttype> enumlist enumerator
+%type <ttype> typename absdcl absdcl1 type_quals
+%type <ttype> xexpr parms parm identifiers
+
+%type <ttype> parmlist parmlist_1 parmlist_2
+%type <ttype> parmlist_or_identifiers parmlist_or_identifiers_1
+%type <ttype> identifiers_or_typenames
+
+%type <itype> setspecs
+
+%type <ends_in_label> lineno_stmt_or_label lineno_stmt_or_labels stmt_or_label
+
+%type <filename> save_filename
+%type <lineno> save_lineno
+
+
+%{
+/* Number of statements (loosely speaking) seen so far. */
+static int stmt_count;
+
+/* Input file and line number of the end of the body of last simple_if;
+ used by the stmt-rule immediately after simple_if returns. */
+static char *if_stmt_file;
+static int if_stmt_line;
+
+/* List of types and structure classes of the current declaration. */
+static tree current_declspecs;
+static tree prefix_attributes = NULL_TREE;
+
+/* Stack of saved values of current_declspecs and prefix_attributes. */
+static tree declspec_stack;
+
+/* 1 if we explained undeclared var errors. */
+static int undeclared_variable_notice;
+
+
+/* Tell yyparse how to print a token's value, if yydebug is set. */
+
+#define YYPRINT(FILE,YYCHAR,YYLVAL) yyprint(FILE,YYCHAR,YYLVAL)
+extern void yyprint ();
+%}
+
+%%
+program: /* empty */
+ { if (pedantic)
+ pedwarn ("ANSI C forbids an empty source file");
+ finish_file ();
+ }
+ | extdefs
+ {
+ /* In case there were missing closebraces,
+ get us back to the global binding level. */
+ while (! global_bindings_p ())
+ poplevel (0, 0, 0);
+ finish_file ();
+ }
+ ;
+
+/* 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. */
+
+extdefs:
+ {$<ttype>$ = NULL_TREE; } extdef
+ | extdefs {$<ttype>$ = NULL_TREE; } extdef
+ ;
+
+extdef:
+ fndef
+ | datadef
+ | ASM_KEYWORD '(' expr ')' ';'
+ { STRIP_NOPS ($3);
+ if ((TREE_CODE ($3) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND ($3, 0)) == STRING_CST)
+ || TREE_CODE ($3) == STRING_CST)
+ assemble_asm ($3);
+ else
+ error ("argument of `asm' is not a constant string"); }
+ ;
+
+datadef:
+ setspecs notype_initdecls ';'
+ { if (pedantic)
+ error ("ANSI C forbids data definition with no type or storage class");
+ else if (!flag_traditional)
+ warning ("data definition has no type or storage class");
+
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($1); }
+ | declmods setspecs notype_initdecls ';'
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs setspecs initdecls ';'
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods ';'
+ { pedwarn ("empty declaration"); }
+ | typed_declspecs ';'
+ { shadow_tag ($1); }
+ | error ';'
+ | error '}'
+ | ';'
+ { if (pedantic)
+ pedwarn ("ANSI C does not allow extra `;' outside of a function"); }
+ ;
+
+fndef:
+ typed_declspecs setspecs declarator
+ { if (! start_function ($1, $3, prefix_attributes,
+ NULL_TREE, 0))
+ YYERROR1;
+ reinit_parse_for_function (); }
+ xdecls
+ { store_parm_decls (); }
+ compstmt_or_error
+ { finish_function (0);
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs setspecs declarator error
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods setspecs notype_declarator
+ { if (! start_function ($1, $3, prefix_attributes,
+ NULL_TREE, 0))
+ YYERROR1;
+ reinit_parse_for_function (); }
+ xdecls
+ { store_parm_decls (); }
+ compstmt_or_error
+ { finish_function (0);
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods setspecs notype_declarator error
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | setspecs notype_declarator
+ { if (! start_function (NULL_TREE, $2,
+ prefix_attributes, NULL_TREE, 0))
+ YYERROR1;
+ reinit_parse_for_function (); }
+ xdecls
+ { store_parm_decls (); }
+ compstmt_or_error
+ { finish_function (0);
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($1); }
+ | setspecs notype_declarator error
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($1); }
+ ;
+
+identifier:
+ IDENTIFIER
+ | TYPENAME
+ ;
+
+unop: '&'
+ { $$ = ADDR_EXPR; }
+ | '-'
+ { $$ = NEGATE_EXPR; }
+ | '+'
+ { $$ = CONVERT_EXPR; }
+ | PLUSPLUS
+ { $$ = PREINCREMENT_EXPR; }
+ | MINUSMINUS
+ { $$ = PREDECREMENT_EXPR; }
+ | '~'
+ { $$ = BIT_NOT_EXPR; }
+ | '!'
+ { $$ = TRUTH_NOT_EXPR; }
+ ;
+
+expr: nonnull_exprlist
+ { $$ = build_compound_expr ($1); }
+ ;
+
+exprlist:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | nonnull_exprlist
+ ;
+
+nonnull_exprlist:
+ expr_no_commas
+ { $$ = build_tree_list (NULL_TREE, $1); }
+ | nonnull_exprlist ',' expr_no_commas
+ { chainon ($1, build_tree_list (NULL_TREE, $3)); }
+ ;
+
+unary_expr:
+ primary
+ | '*' cast_expr %prec UNARY
+ { $$ = build_indirect_ref ($2, "unary *"); }
+ /* __extension__ turns off -pedantic for following primary. */
+ | EXTENSION
+ { $<itype>1 = pedantic;
+ pedantic = 0; }
+ cast_expr %prec UNARY
+ { $$ = $3;
+ pedantic = $<itype>1; }
+ | unop cast_expr %prec UNARY
+ { $$ = build_unary_op ($1, $2, 0);
+ overflow_warning ($$); }
+ /* Refer to the address of a label as a pointer. */
+ | ANDAND identifier
+ { tree label = lookup_label ($2);
+ if (pedantic)
+ pedwarn ("ANSI C forbids `&&'");
+ if (label == 0)
+ $$ = null_pointer_node;
+ else
+ {
+ TREE_USED (label) = 1;
+ $$ = build1 (ADDR_EXPR, ptr_type_node, label);
+ TREE_CONSTANT ($$) = 1;
+ }
+ }
+/* This seems to be impossible on some machines, so let's turn it off.
+ You can use __builtin_next_arg to find the anonymous stack args.
+ | '&' ELLIPSIS
+ { tree types = TYPE_ARG_TYPES (TREE_TYPE (current_function_decl));
+ $$ = error_mark_node;
+ if (TREE_VALUE (tree_last (types)) == void_type_node)
+ error ("`&...' used in function with fixed number of arguments");
+ else
+ {
+ if (pedantic)
+ pedwarn ("ANSI C forbids `&...'");
+ $$ = tree_last (DECL_ARGUMENTS (current_function_decl));
+ $$ = build_unary_op (ADDR_EXPR, $$, 0);
+ } }
+*/
+ | SIZEOF unary_expr %prec UNARY
+ { if (TREE_CODE ($2) == COMPONENT_REF
+ && DECL_BIT_FIELD (TREE_OPERAND ($2, 1)))
+ error ("`sizeof' applied to a bit-field");
+ $$ = c_sizeof (TREE_TYPE ($2)); }
+ | SIZEOF '(' typename ')' %prec HYPERUNARY
+ { $$ = c_sizeof (groktypename ($3)); }
+ | ALIGNOF unary_expr %prec UNARY
+ { $$ = c_alignof_expr ($2); }
+ | ALIGNOF '(' typename ')' %prec HYPERUNARY
+ { $$ = c_alignof (groktypename ($3)); }
+ | REALPART cast_expr %prec UNARY
+ { $$ = build_unary_op (REALPART_EXPR, $2, 0); }
+ | IMAGPART cast_expr %prec UNARY
+ { $$ = build_unary_op (IMAGPART_EXPR, $2, 0); }
+ ;
+
+cast_expr:
+ unary_expr
+ | '(' typename ')' cast_expr %prec UNARY
+ { tree type = groktypename ($2);
+ $$ = build_c_cast (type, $4); }
+ | '(' typename ')' '{'
+ { start_init (NULL_TREE, NULL, 0);
+ $2 = groktypename ($2);
+ really_start_incremental_init ($2); }
+ initlist_maybe_comma '}' %prec UNARY
+ { char *name;
+ tree result = pop_init_level (0);
+ tree type = $2;
+ finish_init ();
+
+ if (pedantic)
+ pedwarn ("ANSI C forbids constructor expressions");
+ if (TYPE_NAME (type) != 0)
+ {
+ if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
+ name = IDENTIFIER_POINTER (TYPE_NAME (type));
+ else
+ name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
+ }
+ else
+ name = "";
+ $$ = result;
+ if (TREE_CODE (type) == ARRAY_TYPE && TYPE_SIZE (type) == 0)
+ {
+ int failure = complete_array_type (type, $$, 1);
+ if (failure)
+ abort ();
+ }
+ }
+ ;
+
+expr_no_commas:
+ cast_expr
+ | expr_no_commas '+' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '-' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '*' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '/' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '%' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas LSHIFT expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas RSHIFT expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas ARITHCOMPARE expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas EQCOMPARE expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '&' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '|' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas '^' expr_no_commas
+ { $$ = parser_build_binary_op ($2, $1, $3); }
+ | expr_no_commas ANDAND expr_no_commas
+ { $$ = parser_build_binary_op (TRUTH_ANDIF_EXPR, $1, $3); }
+ | expr_no_commas OROR expr_no_commas
+ { $$ = parser_build_binary_op (TRUTH_ORIF_EXPR, $1, $3); }
+ | expr_no_commas '?' xexpr ':' expr_no_commas
+ { $$ = build_conditional_expr ($1, $3, $5); }
+ | expr_no_commas '=' expr_no_commas
+ { $$ = build_modify_expr ($1, NOP_EXPR, $3);
+ C_SET_EXP_ORIGINAL_CODE ($$, MODIFY_EXPR); }
+ | expr_no_commas ASSIGN expr_no_commas
+ { $$ = build_modify_expr ($1, $2, $3);
+ /* This inhibits warnings in truthvalue_conversion. */
+ C_SET_EXP_ORIGINAL_CODE ($$, ERROR_MARK); }
+ ;
+
+primary:
+ IDENTIFIER
+ {
+ $$ = lastiddecl;
+ if (!$$ || $$ == error_mark_node)
+ {
+ if (yychar == YYEMPTY)
+ yychar = YYLEX;
+ if (yychar == '(')
+ {
+ {
+ /* Ordinary implicit function declaration. */
+ $$ = implicitly_declare ($1);
+ assemble_external ($$);
+ TREE_USED ($$) = 1;
+ }
+ }
+ else if (current_function_decl == 0)
+ {
+ error ("`%s' undeclared here (not in a function)",
+ IDENTIFIER_POINTER ($1));
+ $$ = error_mark_node;
+ }
+ else
+ {
+ {
+ if (IDENTIFIER_GLOBAL_VALUE ($1) != error_mark_node
+ || IDENTIFIER_ERROR_LOCUS ($1) != current_function_decl)
+ {
+ error ("`%s' undeclared (first use this function)",
+ IDENTIFIER_POINTER ($1));
+
+ if (! undeclared_variable_notice)
+ {
+ error ("(Each undeclared identifier is reported only once");
+ error ("for each function it appears in.)");
+ undeclared_variable_notice = 1;
+ }
+ }
+ $$ = error_mark_node;
+ /* Prevent repeated error messages. */
+ IDENTIFIER_GLOBAL_VALUE ($1) = error_mark_node;
+ IDENTIFIER_ERROR_LOCUS ($1) = current_function_decl;
+ }
+ }
+ }
+ else if (TREE_TYPE ($$) == error_mark_node)
+ $$ = error_mark_node;
+ else if (C_DECL_ANTICIPATED ($$))
+ {
+ /* The first time we see a build-in function used,
+ if it has not been declared. */
+ C_DECL_ANTICIPATED ($$) = 0;
+ if (yychar == YYEMPTY)
+ yychar = YYLEX;
+ if (yychar == '(')
+ {
+ /* Omit the implicit declaration we
+ would ordinarily do, so we don't lose
+ the actual built in type.
+ But print a diagnostic for the mismatch. */
+ if (TREE_CODE ($$) != FUNCTION_DECL)
+ error ("`%s' implicitly declared as function",
+ IDENTIFIER_POINTER (DECL_NAME ($$)));
+ else if ((TYPE_MODE (TREE_TYPE (TREE_TYPE ($$)))
+ != TYPE_MODE (integer_type_node))
+ && (TREE_TYPE (TREE_TYPE ($$))
+ != void_type_node))
+ pedwarn ("type mismatch in implicit declaration for built-in function `%s'",
+ IDENTIFIER_POINTER (DECL_NAME ($$)));
+ /* If it really returns void, change that to int. */
+ if (TREE_TYPE (TREE_TYPE ($$)) == void_type_node)
+ TREE_TYPE ($$)
+ = build_function_type (integer_type_node,
+ TYPE_ARG_TYPES (TREE_TYPE ($$)));
+ }
+ else
+ pedwarn ("built-in function `%s' used without declaration",
+ IDENTIFIER_POINTER (DECL_NAME ($$)));
+
+ /* Do what we would ordinarily do when a fn is used. */
+ assemble_external ($$);
+ TREE_USED ($$) = 1;
+ }
+ else
+ {
+ assemble_external ($$);
+ TREE_USED ($$) = 1;
+ }
+
+ if (TREE_CODE ($$) == CONST_DECL)
+ {
+ $$ = DECL_INITIAL ($$);
+ /* This is to prevent an enum whose value is 0
+ from being considered a null pointer constant. */
+ $$ = build1 (NOP_EXPR, TREE_TYPE ($$), $$);
+ TREE_CONSTANT ($$) = 1;
+ }
+ }
+ | CONSTANT
+ | string
+ { $$ = combine_strings ($1); }
+ | '(' expr ')'
+ { char class = TREE_CODE_CLASS (TREE_CODE ($2));
+ if (class == 'e' || class == '1'
+ || class == '2' || class == '<')
+ C_SET_EXP_ORIGINAL_CODE ($2, ERROR_MARK);
+ $$ = $2; }
+ | '(' error ')'
+ { $$ = error_mark_node; }
+ | '('
+ { if (current_function_decl == 0)
+ {
+ error ("braced-group within expression allowed only inside a function");
+ YYERROR;
+ }
+ /* We must force a BLOCK for this level
+ so that, if it is not expanded later,
+ there is a way to turn off the entire subtree of blocks
+ that are contained in it. */
+ keep_next_level ();
+ push_iterator_stack ();
+ push_label_level ();
+ $<ttype>$ = expand_start_stmt_expr (); }
+ compstmt ')'
+ { tree rtl_exp;
+ if (pedantic)
+ pedwarn ("ANSI C forbids braced-groups within expressions");
+ pop_iterator_stack ();
+ pop_label_level ();
+ rtl_exp = expand_end_stmt_expr ($<ttype>2);
+ /* The statements have side effects, so the group does. */
+ TREE_SIDE_EFFECTS (rtl_exp) = 1;
+
+ if (TREE_CODE ($3) == BLOCK)
+ {
+ /* Make a BIND_EXPR for the BLOCK already made. */
+ $$ = build (BIND_EXPR, TREE_TYPE (rtl_exp),
+ NULL_TREE, rtl_exp, $3);
+ /* Remove the block from the tree at this point.
+ It gets put back at the proper place
+ when the BIND_EXPR is expanded. */
+ delete_block ($3);
+ }
+ else
+ $$ = $3;
+ }
+ | primary '(' exprlist ')' %prec '.'
+ { $$ = build_function_call ($1, $3); }
+ | primary '[' expr ']' %prec '.'
+ { $$ = build_array_ref ($1, $3); }
+ | primary '.' identifier
+ {
+ $$ = build_component_ref ($1, $3);
+ }
+ | primary POINTSAT identifier
+ {
+ tree expr = build_indirect_ref ($1, "->");
+
+ $$ = build_component_ref (expr, $3);
+ }
+ | primary PLUSPLUS
+ { $$ = build_unary_op (POSTINCREMENT_EXPR, $1, 0); }
+ | primary MINUSMINUS
+ { $$ = build_unary_op (POSTDECREMENT_EXPR, $1, 0); }
+ ;
+
+/* Produces a STRING_CST with perhaps more STRING_CSTs chained onto it. */
+string:
+ STRING
+ | string STRING
+ { $$ = chainon ($1, $2); }
+ ;
+
+
+xdecls:
+ /* empty */
+ | datadecls
+ | datadecls ELLIPSIS
+ /* ... is used here to indicate a varargs function. */
+ { c_mark_varargs ();
+ if (pedantic)
+ pedwarn ("ANSI C does not permit use of `varargs.h'"); }
+ ;
+
+/* The following are analogous to lineno_decl, decls and decl
+ except that they do not allow nested functions.
+ They are used for old-style parm decls. */
+lineno_datadecl:
+ save_filename save_lineno datadecl
+ { }
+ ;
+
+datadecls:
+ lineno_datadecl
+ | errstmt
+ | datadecls lineno_datadecl
+ | lineno_datadecl errstmt
+ ;
+
+datadecl:
+ typed_declspecs setspecs initdecls ';'
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods setspecs notype_initdecls ';'
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs ';'
+ { shadow_tag_warned ($1, 1);
+ pedwarn ("empty declaration"); }
+ | declmods ';'
+ { pedwarn ("empty declaration"); }
+ ;
+
+/* This combination which saves a lineno before a decl
+ is the normal thing to use, rather than decl itself.
+ This is to avoid shift/reduce conflicts in contexts
+ where statement labels are allowed. */
+lineno_decl:
+ save_filename save_lineno decl
+ { }
+ ;
+
+decls:
+ lineno_decl
+ | errstmt
+ | decls lineno_decl
+ | lineno_decl errstmt
+ ;
+
+/* records the type and storage class specs to use for processing
+ the declarators that follow.
+ Maintains a stack of outer-level values of current_declspecs,
+ for the sake of parm declarations nested in function declarators. */
+setspecs: /* empty */
+ { $$ = suspend_momentary ();
+ pending_xref_error ();
+ declspec_stack = tree_cons (prefix_attributes,
+ current_declspecs,
+ declspec_stack);
+ current_declspecs = $<ttype>0;
+ prefix_attributes = NULL_TREE; }
+ ;
+
+setattrs: /* empty */
+ { prefix_attributes = chainon (prefix_attributes, $<ttype>0); }
+ ;
+
+decl:
+ typed_declspecs setspecs initdecls ';'
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods setspecs notype_initdecls ';'
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs setspecs nested_function
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods setspecs notype_nested_function
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs ';'
+ { shadow_tag ($1); }
+ | declmods ';'
+ { pedwarn ("empty declaration"); }
+ ;
+
+/* 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. */
+
+typed_declspecs:
+ typespec reserved_declspecs
+ { $$ = tree_cons (NULL_TREE, $1, $2); }
+ | declmods typespec reserved_declspecs
+ { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); }
+ ;
+
+reserved_declspecs: /* empty */
+ { $$ = NULL_TREE; }
+ | reserved_declspecs typespecqual_reserved
+ { $$ = tree_cons (NULL_TREE, $2, $1); }
+ | reserved_declspecs SCSPEC
+ { if (extra_warnings)
+ warning ("`%s' is not at beginning of declaration",
+ IDENTIFIER_POINTER ($2));
+ $$ = tree_cons (NULL_TREE, $2, $1); }
+ ;
+
+/* List of just storage classes and type modifiers.
+ A declaration can start with just this, but then it cannot be used
+ to redeclare a typedef-name. */
+
+declmods:
+ TYPE_QUAL
+ { $$ = tree_cons (NULL_TREE, $1, NULL_TREE);
+ TREE_STATIC ($$) = 1; }
+ | SCSPEC
+ { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); }
+ | declmods TYPE_QUAL
+ { $$ = tree_cons (NULL_TREE, $2, $1);
+ TREE_STATIC ($$) = 1; }
+ | declmods 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); }
+ ;
+
+
+/* Used instead of declspecs where storage classes are not allowed
+ (that is, for typenames and structure components).
+ Don't accept a typedef-name if anything but a modifier precedes it. */
+
+typed_typespecs:
+ typespec reserved_typespecquals
+ { $$ = tree_cons (NULL_TREE, $1, $2); }
+ | nonempty_type_quals typespec reserved_typespecquals
+ { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); }
+ ;
+
+reserved_typespecquals: /* empty */
+ { $$ = NULL_TREE; }
+ | reserved_typespecquals typespecqual_reserved
+ { $$ = tree_cons (NULL_TREE, $2, $1); }
+ ;
+
+/* A typespec (but not a type qualifier).
+ Once we have seen one of these in a declaration,
+ if a typedef name appears then it is being redeclared. */
+
+typespec: TYPESPEC
+ | structsp
+ | TYPENAME
+ { /* For a typedef name, record the meaning, not the name.
+ In case of `foo foo, bar;'. */
+ $$ = lookup_name ($1); }
+ | TYPEOF '(' expr ')'
+ { $$ = TREE_TYPE ($3); }
+ | TYPEOF '(' typename ')'
+ { $$ = groktypename ($3); }
+ ;
+
+/* A typespec that is a reserved word, or a type qualifier. */
+
+typespecqual_reserved: TYPESPEC
+ | TYPE_QUAL
+ | structsp
+ ;
+
+initdecls:
+ initdcl
+ | initdecls ',' initdcl
+ ;
+
+notype_initdecls:
+ notype_initdcl
+ | notype_initdecls ',' initdcl
+ ;
+
+maybeasm:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | ASM_KEYWORD '(' string ')'
+ { if (TREE_CHAIN ($3)) $3 = combine_strings ($3);
+ $$ = $3;
+ }
+ ;
+
+initdcl:
+ declarator maybeasm maybe_attribute '='
+ { $<ttype>$ = start_decl ($1, current_declspecs, 1,
+ $3, prefix_attributes);
+ start_init ($<ttype>$, $2, global_bindings_p ()); }
+ init
+/* Note how the declaration of the variable is in effect while its init is parsed! */
+ { finish_init ();
+ finish_decl ($<ttype>5, $6, $2); }
+ | declarator maybeasm maybe_attribute
+ { tree d = start_decl ($1, current_declspecs, 0,
+ $3, prefix_attributes);
+ finish_decl (d, NULL_TREE, $2);
+ }
+ ;
+
+notype_initdcl:
+ notype_declarator maybeasm maybe_attribute '='
+ { $<ttype>$ = start_decl ($1, current_declspecs, 1,
+ $3, prefix_attributes);
+ start_init ($<ttype>$, $2, global_bindings_p ()); }
+ init
+/* Note how the declaration of the variable is in effect while its init is parsed! */
+ { finish_init ();
+ decl_attributes ($<ttype>5, $3, prefix_attributes);
+ finish_decl ($<ttype>5, $6, $2); }
+ | notype_declarator maybeasm maybe_attribute
+ { tree d = start_decl ($1, current_declspecs, 0,
+ $3, prefix_attributes);
+ finish_decl (d, NULL_TREE, $2); }
+ ;
+/* the * rules are dummies to accept the Apollo extended syntax
+ so that the header files compile. */
+maybe_attribute:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | attributes
+ { $$ = $1; }
+ ;
+
+attributes:
+ attribute
+ { $$ = $1; }
+ | attributes attribute
+ { $$ = chainon ($1, $2); }
+ ;
+
+attribute:
+ ATTRIBUTE '(' '(' attribute_list ')' ')'
+ { $$ = $4; }
+ ;
+
+attribute_list:
+ attrib
+ { $$ = $1; }
+ | attribute_list ',' attrib
+ { $$ = chainon ($1, $3); }
+ ;
+
+attrib:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | any_word
+ { $$ = build_tree_list ($1, NULL_TREE); }
+ | any_word '(' IDENTIFIER ')'
+ { $$ = build_tree_list ($1, build_tree_list (NULL_TREE, $3)); }
+ | any_word '(' IDENTIFIER ',' nonnull_exprlist ')'
+ { $$ = build_tree_list ($1, tree_cons (NULL_TREE, $3, $5)); }
+ | any_word '(' exprlist ')'
+ { $$ = build_tree_list ($1, $3); }
+ ;
+
+/* This still leaves out most reserved keywords,
+ shouldn't we include them? */
+
+any_word:
+ identifier
+ | SCSPEC
+ | TYPESPEC
+ | TYPE_QUAL
+ ;
+
+/* Initializers. `init' is the entry point. */
+
+init:
+ expr_no_commas
+ | '{'
+ { really_start_incremental_init (NULL_TREE);
+ /* Note that the call to clear_momentary
+ is in process_init_element. */
+ push_momentary (); }
+ initlist_maybe_comma '}'
+ { $$ = pop_init_level (0);
+ if ($$ == error_mark_node
+ && ! (yychar == STRING || yychar == CONSTANT))
+ pop_momentary ();
+ else
+ pop_momentary_nofree (); }
+
+ | error
+ { $$ = error_mark_node; }
+ ;
+
+/* `initlist_maybe_comma' is the guts of an initializer in braces. */
+initlist_maybe_comma:
+ /* empty */
+ { if (pedantic)
+ pedwarn ("ANSI C forbids empty initializer braces"); }
+ | initlist1 maybecomma
+ ;
+
+initlist1:
+ initelt
+ | initlist1 ',' initelt
+ ;
+
+/* `initelt' is a single element of an initializer.
+ It may use braces. */
+initelt:
+ expr_no_commas
+ { process_init_element ($1); }
+ | '{'
+ { push_init_level (0); }
+ initlist_maybe_comma '}'
+ { process_init_element (pop_init_level (0)); }
+ | error
+ /* These are for labeled elements. The syntax for an array element
+ initializer conflicts with the syntax for an Objective-C message,
+ so don't include these productions in the Objective-C grammar. */
+ | '[' expr_no_commas ELLIPSIS expr_no_commas ']' '='
+ { set_init_index ($2, $4); }
+ initelt
+ | '[' expr_no_commas ']' '='
+ { set_init_index ($2, NULL_TREE); }
+ initelt
+ | '[' expr_no_commas ']'
+ { set_init_index ($2, NULL_TREE); }
+ initelt
+ | identifier ':'
+ { set_init_label ($1); }
+ initelt
+ | '.' identifier '='
+ { set_init_label ($2); }
+ initelt
+ ;
+
+nested_function:
+ declarator
+ { push_c_function_context ();
+ if (! start_function (current_declspecs, $1,
+ prefix_attributes, NULL_TREE, 1))
+ {
+ pop_c_function_context ();
+ YYERROR1;
+ }
+ reinit_parse_for_function (); }
+ xdecls
+ { store_parm_decls (); }
+/* This used to use compstmt_or_error.
+ That caused a bug with input `f(g) int g {}',
+ where the use of YYERROR1 above caused an error
+ which then was handled by compstmt_or_error.
+ There followed a repeated execution of that same rule,
+ which called YYERROR1 again, and so on. */
+ compstmt
+ { finish_function (1);
+ pop_c_function_context (); }
+ ;
+
+notype_nested_function:
+ notype_declarator
+ { push_c_function_context ();
+ if (! start_function (current_declspecs, $1,
+ prefix_attributes, NULL_TREE, 1))
+ {
+ pop_c_function_context ();
+ YYERROR1;
+ }
+ reinit_parse_for_function (); }
+ xdecls
+ { store_parm_decls (); }
+/* This used to use compstmt_or_error.
+ That caused a bug with input `f(g) int g {}',
+ where the use of YYERROR1 above caused an error
+ which then was handled by compstmt_or_error.
+ There followed a repeated execution of that same rule,
+ which called YYERROR1 again, and so on. */
+ compstmt
+ { finish_function (1);
+ pop_c_function_context (); }
+ ;
+
+/* Any kind of declarator (thus, all declarators allowed
+ after an explicit typespec). */
+
+declarator:
+ after_type_declarator
+ | notype_declarator
+ ;
+
+/* A declarator that is allowed only after an explicit typespec. */
+
+after_type_declarator:
+ '(' after_type_declarator ')'
+ { $$ = $2; }
+ | after_type_declarator '(' parmlist_or_identifiers %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
+/* | after_type_declarator '(' error ')' %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE);
+ poplevel (0, 0, 0); } */
+ | after_type_declarator '[' expr ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, $3); }
+ | after_type_declarator '[' ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
+ | '*' type_quals after_type_declarator %prec UNARY
+ { $$ = make_pointer_declarator ($2, $3); }
+ | attributes setattrs after_type_declarator
+ { $$ = $3; }
+ | TYPENAME
+ ;
+
+/* Kinds of declarator that can appear in a parameter list
+ in addition to notype_declarator. This is like after_type_declarator
+ but does not allow a typedef name in parentheses as an identifier
+ (because it would conflict with a function with that typedef as arg). */
+
+parm_declarator:
+ parm_declarator '(' parmlist_or_identifiers %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
+/* | parm_declarator '(' error ')' %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE);
+ poplevel (0, 0, 0); } */
+ | parm_declarator '[' expr ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, $3); }
+ | parm_declarator '[' ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
+ | '*' type_quals parm_declarator %prec UNARY
+ { $$ = make_pointer_declarator ($2, $3); }
+ | attributes setattrs parm_declarator
+ { $$ = $3; }
+ | TYPENAME
+ ;
+
+/* A declarator allowed whether or not there has been
+ an explicit typespec. These cannot redeclare a typedef-name. */
+
+notype_declarator:
+ notype_declarator '(' parmlist_or_identifiers %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
+/* | notype_declarator '(' error ')' %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, NULL_TREE, NULL_TREE);
+ poplevel (0, 0, 0); } */
+ | '(' notype_declarator ')'
+ { $$ = $2; }
+ | '*' type_quals notype_declarator %prec UNARY
+ { $$ = make_pointer_declarator ($2, $3); }
+ | notype_declarator '[' expr ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, $3); }
+ | notype_declarator '[' ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
+ | attributes setattrs notype_declarator
+ { $$ = $3; }
+ | IDENTIFIER
+ ;
+
+structsp:
+ STRUCT identifier '{'
+ { $$ = start_struct (RECORD_TYPE, $2);
+ /* Start scope of tag before parsing components. */
+ }
+ component_decl_list '}' maybe_attribute
+ { $$ = finish_struct ($<ttype>4, $5, $7); }
+ | STRUCT '{' component_decl_list '}' maybe_attribute
+ { $$ = finish_struct (start_struct (RECORD_TYPE, NULL_TREE),
+ $3, $5);
+ }
+ | STRUCT identifier
+ { $$ = xref_tag (RECORD_TYPE, $2); }
+ | UNION identifier '{'
+ { $$ = start_struct (UNION_TYPE, $2); }
+ component_decl_list '}' maybe_attribute
+ { $$ = finish_struct ($<ttype>4, $5, $7); }
+ | UNION '{' component_decl_list '}' maybe_attribute
+ { $$ = finish_struct (start_struct (UNION_TYPE, NULL_TREE),
+ $3, $5);
+ }
+ | UNION identifier
+ { $$ = xref_tag (UNION_TYPE, $2); }
+ | ENUM identifier '{'
+ { $<itype>3 = suspend_momentary ();
+ $$ = start_enum ($2); }
+ enumlist maybecomma_warn '}' maybe_attribute
+ { $$ = finish_enum ($<ttype>4, nreverse ($5), $8);
+ resume_momentary ($<itype>3); }
+ | ENUM '{'
+ { $<itype>2 = suspend_momentary ();
+ $$ = start_enum (NULL_TREE); }
+ enumlist maybecomma_warn '}' maybe_attribute
+ { $$ = finish_enum ($<ttype>3, nreverse ($4), $7);
+ resume_momentary ($<itype>2); }
+ | ENUM identifier
+ { $$ = xref_tag (ENUMERAL_TYPE, $2); }
+ ;
+
+maybecomma:
+ /* empty */
+ | ','
+ ;
+
+maybecomma_warn:
+ /* empty */
+ | ','
+ { if (pedantic) pedwarn ("comma at end of enumerator list"); }
+ ;
+
+component_decl_list:
+ component_decl_list2
+ { $$ = $1; }
+ | component_decl_list2 component_decl
+ { $$ = chainon ($1, $2);
+ pedwarn ("no semicolon at end of struct or union"); }
+ ;
+
+component_decl_list2: /* empty */
+ { $$ = NULL_TREE; }
+ | component_decl_list2 component_decl ';'
+ { $$ = chainon ($1, $2); }
+ | component_decl_list2 ';'
+ { 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. */
+
+component_decl:
+ typed_typespecs setspecs components
+ { $$ = $3;
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_typespecs
+ { if (pedantic)
+ pedwarn ("ANSI C forbids member declarations with no members");
+ shadow_tag($1);
+ $$ = NULL_TREE; }
+ | nonempty_type_quals setspecs components
+ { $$ = $3;
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | nonempty_type_quals
+ { if (pedantic)
+ pedwarn ("ANSI C forbids member declarations with no members");
+ shadow_tag($1);
+ $$ = NULL_TREE; }
+ | error
+ { $$ = NULL_TREE; }
+ ;
+
+components:
+ component_declarator
+ | components ',' component_declarator
+ { $$ = chainon ($1, $3); }
+ ;
+
+component_declarator:
+ save_filename save_lineno declarator maybe_attribute
+ { $$ = grokfield ($1, $2, $3, current_declspecs, NULL_TREE);
+ decl_attributes ($$, $4, prefix_attributes); }
+ | save_filename save_lineno
+ declarator ':' expr_no_commas maybe_attribute
+ { $$ = grokfield ($1, $2, $3, current_declspecs, $5);
+ decl_attributes ($$, $6, prefix_attributes); }
+ | save_filename save_lineno ':' expr_no_commas maybe_attribute
+ { $$ = grokfield ($1, $2, NULL_TREE, current_declspecs, $4);
+ decl_attributes ($$, $5, prefix_attributes); }
+ ;
+
+/* We chain the enumerators in reverse order.
+ They are put in forward order where enumlist is used.
+ (The order used to be significant, but no longer is so.
+ However, we still maintain the order, just to be clean.) */
+
+enumlist:
+ enumerator
+ | enumlist ',' enumerator
+ { if ($1 == error_mark_node)
+ $$ = $1;
+ else
+ $$ = chainon ($3, $1); }
+ | error
+ { $$ = error_mark_node; }
+ ;
+
+
+enumerator:
+ identifier
+ { $$ = build_enumerator ($1, NULL_TREE); }
+ | identifier '=' expr_no_commas
+ { $$ = build_enumerator ($1, $3); }
+ ;
+
+typename:
+ typed_typespecs absdcl
+ { $$ = build_tree_list ($1, $2); }
+ | nonempty_type_quals absdcl
+ { $$ = build_tree_list ($1, $2); }
+ ;
+
+absdcl: /* an absolute declarator */
+ /* empty */
+ { $$ = NULL_TREE; }
+ | absdcl1
+ ;
+
+nonempty_type_quals:
+ TYPE_QUAL
+ { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); }
+ | nonempty_type_quals TYPE_QUAL
+ { $$ = tree_cons (NULL_TREE, $2, $1); }
+ ;
+
+type_quals:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | type_quals TYPE_QUAL
+ { $$ = tree_cons (NULL_TREE, $2, $1); }
+ ;
+
+absdcl1: /* a nonempty absolute declarator */
+ '(' absdcl1 ')'
+ { $$ = $2; }
+ /* `(typedef)1' is `int'. */
+ | '*' type_quals absdcl1 %prec UNARY
+ { $$ = make_pointer_declarator ($2, $3); }
+ | '*' type_quals %prec UNARY
+ { $$ = make_pointer_declarator ($2, NULL_TREE); }
+ | absdcl1 '(' parmlist %prec '.'
+ { $$ = build_nt (CALL_EXPR, $1, $3, NULL_TREE); }
+ | absdcl1 '[' expr ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, $3); }
+ | absdcl1 '[' ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
+ | '(' parmlist %prec '.'
+ { $$ = build_nt (CALL_EXPR, NULL_TREE, $2, NULL_TREE); }
+ | '[' expr ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, NULL_TREE, $2); }
+ | '[' ']' %prec '.'
+ { $$ = build_nt (ARRAY_REF, NULL_TREE, NULL_TREE); }
+ | attributes setattrs absdcl1
+ { $$ = $3; }
+ ;
+
+/* at least one statement, the first of which parses without error. */
+/* stmts is used only after decls, so an invalid first statement
+ is actually regarded as an invalid decl and part of the decls. */
+
+stmts:
+ lineno_stmt_or_labels
+ {
+ if (pedantic && $1)
+ pedwarn ("ANSI C forbids label at end of compound statement");
+ }
+ ;
+
+lineno_stmt_or_labels:
+ lineno_stmt_or_label
+ | lineno_stmt_or_labels lineno_stmt_or_label
+ { $$ = $2; }
+ | lineno_stmt_or_labels errstmt
+ { $$ = 0; }
+ ;
+
+xstmts:
+ /* empty */
+ | stmts
+ ;
+
+errstmt: error ';'
+ ;
+
+pushlevel: /* empty */
+ { emit_line_note (input_filename, lineno);
+ pushlevel (0);
+ clear_last_expr ();
+ push_momentary ();
+ expand_start_bindings (0);
+ }
+ ;
+
+/* Read zero or more forward-declarations for labels
+ that nested functions can jump to. */
+maybe_label_decls:
+ /* empty */
+ | label_decls
+ { if (pedantic)
+ pedwarn ("ANSI C forbids label declarations"); }
+ ;
+
+label_decls:
+ label_decl
+ | label_decls label_decl
+ ;
+
+label_decl:
+ LABEL identifiers_or_typenames ';'
+ { tree link;
+ for (link = $2; link; link = TREE_CHAIN (link))
+ {
+ tree label = shadow_label (TREE_VALUE (link));
+ C_DECLARED_LABEL_FLAG (label) = 1;
+ declare_nonlocal_label (label);
+ }
+ }
+ ;
+
+/* This is the body of a function definition.
+ It causes syntax errors to ignore to the next openbrace. */
+compstmt_or_error:
+ compstmt
+ {}
+ | error compstmt
+ ;
+
+compstmt: '{' '}'
+ { $$ = convert (void_type_node, integer_zero_node); }
+ | '{' pushlevel maybe_label_decls decls xstmts '}'
+ { emit_line_note (input_filename, lineno);
+ expand_end_bindings (getdecls (), 1, 0);
+ $$ = poplevel (1, 1, 0);
+ if (yychar == CONSTANT || yychar == STRING)
+ pop_momentary_nofree ();
+ else
+ pop_momentary (); }
+ | '{' pushlevel maybe_label_decls error '}'
+ { emit_line_note (input_filename, lineno);
+ expand_end_bindings (getdecls (), kept_level_p (), 0);
+ $$ = poplevel (kept_level_p (), 0, 0);
+ if (yychar == CONSTANT || yychar == STRING)
+ pop_momentary_nofree ();
+ else
+ pop_momentary (); }
+ | '{' pushlevel maybe_label_decls stmts '}'
+ { emit_line_note (input_filename, lineno);
+ expand_end_bindings (getdecls (), kept_level_p (), 0);
+ $$ = poplevel (kept_level_p (), 0, 0);
+ if (yychar == CONSTANT || yychar == STRING)
+ pop_momentary_nofree ();
+ else
+ pop_momentary (); }
+ ;
+
+/* Value is number of statements counted as of the closeparen. */
+simple_if:
+ if_prefix lineno_labeled_stmt
+/* Make sure expand_end_cond is run once
+ for each call to expand_start_cond.
+ Otherwise a crash is likely. */
+ | if_prefix error
+ ;
+
+if_prefix:
+ IF '(' expr ')'
+ { emit_line_note ($<filename>-1, $<lineno>0);
+ expand_start_cond (truthvalue_conversion ($3), 0);
+ $<itype>$ = stmt_count;
+ if_stmt_file = $<filename>-1;
+ if_stmt_line = $<lineno>0;
+ position_after_white_space (); }
+ ;
+
+/* This is a subroutine of stmt.
+ It is used twice, once for valid DO statements
+ and once for catching errors in parsing the end test. */
+do_stmt_start:
+ DO
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ /* See comment in `while' alternative, above. */
+ emit_nop ();
+ expand_start_loop_continue_elsewhere (1);
+ position_after_white_space (); }
+ lineno_labeled_stmt WHILE
+ { expand_loop_continue_here (); }
+ ;
+
+save_filename:
+ { $$ = input_filename; }
+ ;
+
+save_lineno:
+ { $$ = lineno; }
+ ;
+
+lineno_labeled_stmt:
+ save_filename save_lineno stmt
+ { }
+/* | save_filename save_lineno error
+ { }
+*/
+ | save_filename save_lineno label lineno_labeled_stmt
+ { }
+ ;
+
+lineno_stmt_or_label:
+ save_filename save_lineno stmt_or_label
+ { $$ = $3; }
+ ;
+
+stmt_or_label:
+ stmt
+ { $$ = 0; }
+ | label
+ { $$ = 1; }
+ ;
+
+/* Parse a single real statement, not including any labels. */
+stmt:
+ compstmt
+ { stmt_count++; }
+ | all_iter_stmt
+ | expr ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+/* It appears that this should not be done--that a non-lvalue array
+ shouldn't get an error if the value isn't used.
+ Section 3.2.2.1 says that an array lvalue gets converted to a pointer
+ if it appears as a top-level expression,
+ but says nothing about non-lvalue arrays. */
+#if 0
+ /* Call default_conversion to get an error
+ on referring to a register array if pedantic. */
+ if (TREE_CODE (TREE_TYPE ($1)) == ARRAY_TYPE
+ || TREE_CODE (TREE_TYPE ($1)) == FUNCTION_TYPE)
+ $1 = default_conversion ($1);
+#endif
+ iterator_expand ($1);
+ clear_momentary (); }
+ | simple_if ELSE
+ { expand_start_else ();
+ $<itype>1 = stmt_count;
+ position_after_white_space (); }
+ lineno_labeled_stmt
+ { expand_end_cond ();
+ if (extra_warnings && stmt_count == $<itype>1)
+ warning ("empty body in an else-statement"); }
+ | simple_if %prec IF
+ { expand_end_cond ();
+ /* This warning is here instead of in simple_if, because we
+ do not want a warning if an empty if is followed by an
+ else statement. Increment stmt_count so we don't
+ give a second error if this is a nested `if'. */
+ if (extra_warnings && stmt_count++ == $<itype>1)
+ warning_with_file_and_line (if_stmt_file, if_stmt_line,
+ "empty body in an if-statement"); }
+/* Make sure expand_end_cond is run once
+ for each call to expand_start_cond.
+ Otherwise a crash is likely. */
+ | simple_if ELSE error
+ { expand_end_cond (); }
+ | WHILE
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ /* The emit_nop used to come before emit_line_note,
+ but that made the nop seem like part of the preceding line.
+ And that was confusing when the preceding line was
+ inside of an if statement and was not really executed.
+ I think it ought to work to put the nop after the line number.
+ We will see. --rms, July 15, 1991. */
+ emit_nop (); }
+ '(' expr ')'
+ { /* Don't start the loop till we have succeeded
+ in parsing the end test. This is to make sure
+ that we end every loop we start. */
+ expand_start_loop (1);
+ emit_line_note (input_filename, lineno);
+ expand_exit_loop_if_false (NULL_PTR,
+ truthvalue_conversion ($4));
+ position_after_white_space (); }
+ lineno_labeled_stmt
+ { expand_end_loop (); }
+ | do_stmt_start
+ '(' expr ')' ';'
+ { emit_line_note (input_filename, lineno);
+ expand_exit_loop_if_false (NULL_PTR,
+ truthvalue_conversion ($3));
+ expand_end_loop ();
+ clear_momentary (); }
+/* This rule is needed to make sure we end every loop we start. */
+ | do_stmt_start error
+ { expand_end_loop ();
+ clear_momentary (); }
+ | FOR
+ '(' xexpr ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ /* See comment in `while' alternative, above. */
+ emit_nop ();
+ if ($3) c_expand_expr_stmt ($3);
+ /* Next step is to call expand_start_loop_continue_elsewhere,
+ but wait till after we parse the entire for (...).
+ Otherwise, invalid input might cause us to call that
+ fn without calling expand_end_loop. */
+ }
+ xexpr ';'
+ /* Can't emit now; wait till after expand_start_loop... */
+ { $<lineno>7 = lineno;
+ $<filename>$ = input_filename; }
+ xexpr ')'
+ {
+ /* Start the loop. Doing this after parsing
+ all the expressions ensures we will end the loop. */
+ expand_start_loop_continue_elsewhere (1);
+ /* Emit the end-test, with a line number. */
+ emit_line_note ($<filename>8, $<lineno>7);
+ if ($6)
+ expand_exit_loop_if_false (NULL_PTR,
+ truthvalue_conversion ($6));
+ /* Don't let the tree nodes for $9 be discarded by
+ clear_momentary during the parsing of the next stmt. */
+ push_momentary ();
+ $<lineno>7 = lineno;
+ $<filename>8 = input_filename;
+ position_after_white_space (); }
+ lineno_labeled_stmt
+ { /* Emit the increment expression, with a line number. */
+ emit_line_note ($<filename>8, $<lineno>7);
+ expand_loop_continue_here ();
+ if ($9)
+ c_expand_expr_stmt ($9);
+ if (yychar == CONSTANT || yychar == STRING)
+ pop_momentary_nofree ();
+ else
+ pop_momentary ();
+ expand_end_loop (); }
+ | SWITCH '(' expr ')'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ c_expand_start_case ($3);
+ /* Don't let the tree nodes for $3 be discarded by
+ clear_momentary during the parsing of the next stmt. */
+ push_momentary ();
+ position_after_white_space (); }
+ lineno_labeled_stmt
+ { expand_end_case ($3);
+ if (yychar == CONSTANT || yychar == STRING)
+ pop_momentary_nofree ();
+ else
+ pop_momentary (); }
+ | BREAK ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ if ( ! expand_exit_something ())
+ error ("break statement not within loop or switch"); }
+ | CONTINUE ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ if (! expand_continue_loop (NULL_PTR))
+ error ("continue statement not within a loop"); }
+ | RETURN ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ c_expand_return (NULL_TREE); }
+ | RETURN expr ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ c_expand_return ($2); }
+ | ASM_KEYWORD maybe_type_qual '(' expr ')' ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ STRIP_NOPS ($4);
+ if ((TREE_CODE ($4) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND ($4, 0)) == STRING_CST)
+ || TREE_CODE ($4) == STRING_CST)
+ expand_asm ($4);
+ else
+ error ("argument of `asm' is not a constant string"); }
+ /* This is the case with just output operands. */
+ | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ')' ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ c_expand_asm_operands ($4, $6, NULL_TREE, NULL_TREE,
+ $2 == ridpointers[(int)RID_VOLATILE],
+ input_filename, lineno); }
+ /* This is the case with input operands as well. */
+ | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ':' asm_operands ')' ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ c_expand_asm_operands ($4, $6, $8, NULL_TREE,
+ $2 == ridpointers[(int)RID_VOLATILE],
+ input_filename, lineno); }
+ /* This is the case with clobbered registers as well. */
+ | ASM_KEYWORD maybe_type_qual '(' expr ':' asm_operands ':'
+ asm_operands ':' asm_clobbers ')' ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ c_expand_asm_operands ($4, $6, $8, $10,
+ $2 == ridpointers[(int)RID_VOLATILE],
+ input_filename, lineno); }
+ | GOTO identifier ';'
+ { tree decl;
+ stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ decl = lookup_label ($2);
+ if (decl != 0)
+ {
+ TREE_USED (decl) = 1;
+ expand_goto (decl);
+ }
+ }
+ | GOTO '*' expr ';'
+ { stmt_count++;
+ emit_line_note ($<filename>-1, $<lineno>0);
+ expand_computed_goto (convert (ptr_type_node, $3)); }
+ | ';'
+ ;
+
+all_iter_stmt:
+ all_iter_stmt_simple
+/* | all_iter_stmt_with_decl */
+ ;
+
+all_iter_stmt_simple:
+ FOR '(' primary ')'
+ {
+ /* The value returned by this action is */
+ /* 1 if everything is OK */
+ /* 0 in case of error or already bound iterator */
+
+ $<itype>$ = 0;
+ if (TREE_CODE ($3) != VAR_DECL)
+ error ("invalid `for (ITERATOR)' syntax");
+ else if (! ITERATOR_P ($3))
+ error ("`%s' is not an iterator",
+ IDENTIFIER_POINTER (DECL_NAME ($3)));
+ else if (ITERATOR_BOUND_P ($3))
+ error ("`for (%s)' inside expansion of same iterator",
+ IDENTIFIER_POINTER (DECL_NAME ($3)));
+ else
+ {
+ $<itype>$ = 1;
+ iterator_for_loop_start ($3);
+ }
+ }
+ lineno_labeled_stmt
+ {
+ if ($<itype>5)
+ iterator_for_loop_end ($3);
+ }
+
+/* This really should allow any kind of declaration,
+ for generality. Fix it before turning it back on.
+
+all_iter_stmt_with_decl:
+ FOR '(' ITERATOR pushlevel setspecs iterator_spec ')'
+ {
+*/ /* The value returned by this action is */
+ /* 1 if everything is OK */
+ /* 0 in case of error or already bound iterator */
+/*
+ iterator_for_loop_start ($6);
+ }
+ lineno_labeled_stmt
+ {
+ iterator_for_loop_end ($6);
+ emit_line_note (input_filename, lineno);
+ expand_end_bindings (getdecls (), 1, 0);
+ $<ttype>$ = poplevel (1, 1, 0);
+ if (yychar == CONSTANT || yychar == STRING)
+ pop_momentary_nofree ();
+ else
+ pop_momentary ();
+ }
+*/
+
+/* Any kind of label, including jump labels and case labels.
+ ANSI C accepts labels only before statements, but we allow them
+ also at the end of a compound statement. */
+
+label: CASE expr_no_commas ':'
+ { register tree value = check_case_value ($2);
+ register tree label
+ = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+
+ stmt_count++;
+
+ if (value != error_mark_node)
+ {
+ tree duplicate;
+ int success = pushcase (value, convert_and_check,
+ label, &duplicate);
+ if (success == 1)
+ error ("case label not within a switch statement");
+ else if (success == 2)
+ {
+ error ("duplicate case value");
+ error_with_decl (duplicate, "this is the first entry for that value");
+ }
+ else if (success == 3)
+ warning ("case value out of range");
+ else if (success == 5)
+ error ("case label within scope of cleanup or variable array");
+ }
+ position_after_white_space (); }
+ | CASE expr_no_commas ELLIPSIS expr_no_commas ':'
+ { register tree value1 = check_case_value ($2);
+ register tree value2 = check_case_value ($4);
+ register tree label
+ = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+
+ stmt_count++;
+
+ if (value1 != error_mark_node && value2 != error_mark_node)
+ {
+ tree duplicate;
+ int success = pushcase_range (value1, value2,
+ convert_and_check, label,
+ &duplicate);
+ if (success == 1)
+ error ("case label not within a switch statement");
+ else if (success == 2)
+ {
+ error ("duplicate case value");
+ error_with_decl (duplicate, "this is the first entry for that value");
+ }
+ else if (success == 3)
+ warning ("case value out of range");
+ else if (success == 4)
+ warning ("empty case range");
+ else if (success == 5)
+ error ("case label within scope of cleanup or variable array");
+ }
+ position_after_white_space (); }
+ | DEFAULT ':'
+ {
+ tree duplicate;
+ register tree label
+ = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+ int success = pushcase (NULL_TREE, 0, label, &duplicate);
+ stmt_count++;
+ if (success == 1)
+ error ("default label not within a switch statement");
+ else if (success == 2)
+ {
+ error ("multiple default labels in one switch");
+ error_with_decl (duplicate, "this is the first default label");
+ }
+ position_after_white_space (); }
+ | identifier ':'
+ { tree label = define_label (input_filename, lineno, $1);
+ stmt_count++;
+ emit_nop ();
+ if (label)
+ expand_label (label);
+ position_after_white_space (); }
+ ;
+
+/* Either a type-qualifier or nothing. First thing in an `asm' statement. */
+
+maybe_type_qual:
+ /* empty */
+ { emit_line_note (input_filename, lineno);
+ $$ = NULL_TREE; }
+ | TYPE_QUAL
+ { emit_line_note (input_filename, lineno); }
+ ;
+
+xexpr:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | expr
+ ;
+
+/* These are the operands other than the first string and colon
+ in asm ("addextend %2,%1": "=dm" (x), "0" (y), "g" (*x)) */
+asm_operands: /* empty */
+ { $$ = NULL_TREE; }
+ | nonnull_asm_operands
+ ;
+
+nonnull_asm_operands:
+ asm_operand
+ | nonnull_asm_operands ',' asm_operand
+ { $$ = chainon ($1, $3); }
+ ;
+
+asm_operand:
+ STRING '(' expr ')'
+ { $$ = build_tree_list ($1, $3); }
+ ;
+
+asm_clobbers:
+ string
+ { $$ = tree_cons (NULL_TREE, combine_strings ($1), NULL_TREE); }
+ | asm_clobbers ',' string
+ { $$ = tree_cons (NULL_TREE, combine_strings ($3), $1); }
+ ;
+
+/* This is what appears inside the parens in a function declarator.
+ Its value is a list of ..._TYPE nodes. */
+parmlist:
+ { pushlevel (0);
+ clear_parm_order ();
+ declare_parm_level (0); }
+ parmlist_1
+ { $$ = $2;
+ parmlist_tags_warning ();
+ poplevel (0, 0, 0); }
+ ;
+
+parmlist_1:
+ parmlist_2 ')'
+ | parms ';'
+ { tree parm;
+ if (pedantic)
+ pedwarn ("ANSI C forbids forward parameter declarations");
+ /* Mark the forward decls as such. */
+ for (parm = getdecls (); parm; parm = TREE_CHAIN (parm))
+ TREE_ASM_WRITTEN (parm) = 1;
+ clear_parm_order (); }
+ parmlist_1
+ { $$ = $4; }
+ | error ')'
+ { $$ = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE); }
+ ;
+
+/* This is what appears inside the parens in a function declarator.
+ Is value is represented in the format that grokdeclarator expects. */
+parmlist_2: /* empty */
+ { $$ = get_parm_info (0); }
+ | ELLIPSIS
+ { $$ = get_parm_info (0);
+ /* Gcc used to allow this as an extension. However, it does
+ not work for all targets, and thus has been disabled.
+ Also, since func (...) and func () are indistinguishable,
+ it caused problems with the code in expand_builtin which
+ tries to verify that BUILT_IN_NEXT_ARG is being used
+ correctly. */
+ error ("ANSI C requires a named argument before `...'");
+ }
+ | parms
+ { $$ = get_parm_info (1); }
+ | parms ',' ELLIPSIS
+ { $$ = get_parm_info (0); }
+ ;
+
+parms:
+ parm
+ { push_parm_decl ($1); }
+ | parms ',' parm
+ { push_parm_decl ($3); }
+ ;
+
+/* A single parameter declaration or parameter type name,
+ as found in a parmlist. */
+parm:
+ typed_declspecs setspecs parm_declarator maybe_attribute
+ { $$ = build_tree_list (build_tree_list (current_declspecs,
+ $3),
+ build_tree_list (prefix_attributes,
+ $4));
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs setspecs notype_declarator maybe_attribute
+ { $$ = build_tree_list (build_tree_list (current_declspecs,
+ $3),
+ build_tree_list (prefix_attributes,
+ $4));
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | typed_declspecs setspecs absdcl maybe_attribute
+ { $$ = build_tree_list (build_tree_list (current_declspecs,
+ $3),
+ build_tree_list (prefix_attributes,
+ $4));
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods setspecs notype_declarator maybe_attribute
+ { $$ = build_tree_list (build_tree_list (current_declspecs,
+ $3),
+ build_tree_list (prefix_attributes,
+ $4));
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+
+ | declmods setspecs absdcl maybe_attribute
+ { $$ = build_tree_list (build_tree_list (current_declspecs,
+ $3),
+ build_tree_list (prefix_attributes,
+ $4));
+ current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ ;
+
+/* This is used in a function definition
+ where either a parmlist or an identifier list is ok.
+ Its value is a list of ..._TYPE nodes or a list of identifiers. */
+parmlist_or_identifiers:
+ { pushlevel (0);
+ clear_parm_order ();
+ declare_parm_level (1); }
+ parmlist_or_identifiers_1
+ { $$ = $2;
+ parmlist_tags_warning ();
+ poplevel (0, 0, 0); }
+ ;
+
+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); }
+ ;
+
+/* A nonempty list of identifiers. */
+identifiers:
+ IDENTIFIER
+ { $$ = build_tree_list (NULL_TREE, $1); }
+ | identifiers ',' IDENTIFIER
+ { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); }
+ ;
+
+/* A nonempty list of identifiers, including typenames. */
+identifiers_or_typenames:
+ identifier
+ { $$ = build_tree_list (NULL_TREE, $1); }
+ | identifiers_or_typenames ',' identifier
+ { $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); }
+ ;
+
+%%
diff --git a/gnu/usr.bin/gcc/cpp/cexp.y b/gnu/usr.bin/gcc/cpp/cexp.y
new file mode 100644
index 00000000000..d83de803364
--- /dev/null
+++ b/gnu/usr.bin/gcc/cpp/cexp.y
@@ -0,0 +1,1047 @@
+/* Parse C expressions for CCCP.
+ Copyright (C) 1987, 1992, 1994, 1995 Free Software Foundation.
+
+This program 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 Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding!
+
+ Adapted from expread.y of GDB by Paul Rubin, July 1986. */
+
+/* Parse a C expression from text in a string */
+
+%{
+#include "config.h"
+#include <setjmp.h>
+/* #define YYDEBUG 1 */
+
+#ifdef MULTIBYTE_CHARS
+#include <stdlib.h>
+#include <locale.h>
+#endif
+
+#include <stdio.h>
+
+typedef unsigned char U_CHAR;
+
+/* This is used for communicating lists of keywords with cccp.c. */
+struct arglist {
+ struct arglist *next;
+ U_CHAR *name;
+ int length;
+ int argno;
+};
+
+/* Define a generic NULL if one hasn't already been defined. */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef GENERIC_PTR
+#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
+#define GENERIC_PTR void *
+#else
+#define GENERIC_PTR char *
+#endif
+#endif
+
+/* Find the largest host integer type and set its size and type. */
+
+#ifndef HOST_BITS_PER_WIDE_INT
+
+#if HOST_BITS_PER_LONG > HOST_BITS_PER_INT
+#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_LONG
+#define HOST_WIDE_INT long
+#else
+#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_INT
+#define HOST_WIDE_INT int
+#endif
+
+#endif
+
+#ifndef NULL_PTR
+#define NULL_PTR ((GENERIC_PTR)0)
+#endif
+
+int yylex ();
+void yyerror ();
+HOST_WIDE_INT expression_value;
+
+static jmp_buf parse_return_error;
+
+/* Nonzero means count most punctuation as part of a name. */
+static int keyword_parsing = 0;
+
+/* Nonzero means do not evaluate this expression.
+ This is a count, since unevaluated expressions can nest. */
+static int skip_evaluation;
+
+/* some external tables of character types */
+extern unsigned char is_idstart[], is_idchar[], is_hor_space[];
+
+extern char *xmalloc ();
+
+/* Flag for -pedantic. */
+extern int pedantic;
+
+/* Flag for -traditional. */
+extern int traditional;
+
+#ifndef CHAR_TYPE_SIZE
+#define CHAR_TYPE_SIZE BITS_PER_UNIT
+#endif
+
+#ifndef INT_TYPE_SIZE
+#define INT_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef LONG_TYPE_SIZE
+#define LONG_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE INT_TYPE_SIZE
+#endif
+
+#ifndef MAX_CHAR_TYPE_SIZE
+#define MAX_CHAR_TYPE_SIZE CHAR_TYPE_SIZE
+#endif
+
+#ifndef MAX_INT_TYPE_SIZE
+#define MAX_INT_TYPE_SIZE INT_TYPE_SIZE
+#endif
+
+#ifndef MAX_LONG_TYPE_SIZE
+#define MAX_LONG_TYPE_SIZE LONG_TYPE_SIZE
+#endif
+
+#ifndef MAX_WCHAR_TYPE_SIZE
+#define MAX_WCHAR_TYPE_SIZE WCHAR_TYPE_SIZE
+#endif
+
+/* Yield nonzero if adding two numbers with A's and B's signs can yield a
+ number with SUM's sign, where A, B, and SUM are all C integers. */
+#define possible_sum_sign(a, b, sum) ((((a) ^ (b)) | ~ ((a) ^ (sum))) < 0)
+
+static void integer_overflow ();
+static long left_shift ();
+static long right_shift ();
+%}
+
+%union {
+ struct constant {long value; int unsignedp;} integer;
+ struct name {U_CHAR *address; int length;} name;
+ struct arglist *keywords;
+}
+
+%type <integer> exp exp1 start
+%type <keywords> keywords
+%token <integer> INT CHAR
+%token <name> NAME
+%token <integer> ERROR
+
+%right '?' ':'
+%left ','
+%left OR
+%left AND
+%left '|'
+%left '^'
+%left '&'
+%left EQUAL NOTEQUAL
+%left '<' '>' LEQ GEQ
+%left LSH RSH
+%left '+' '-'
+%left '*' '/' '%'
+%right UNARY
+
+/* %expect 40 */
+
+%%
+
+start : exp1
+ { expression_value = $1.value; }
+ ;
+
+/* Expressions, including the comma operator. */
+exp1 : exp
+ | exp1 ',' exp
+ { if (pedantic)
+ pedwarn ("comma operator in operand of `#if'");
+ $$ = $3; }
+ ;
+
+/* Expressions, not including the comma operator. */
+exp : '-' exp %prec UNARY
+ { $$.value = - $2.value;
+ if (($$.value & $2.value) < 0 && ! $2.unsignedp)
+ integer_overflow ();
+ $$.unsignedp = $2.unsignedp; }
+ | '!' exp %prec UNARY
+ { $$.value = ! $2.value;
+ $$.unsignedp = 0; }
+ | '+' exp %prec UNARY
+ { $$ = $2; }
+ | '~' exp %prec UNARY
+ { $$.value = ~ $2.value;
+ $$.unsignedp = $2.unsignedp; }
+ | '#' NAME
+ { $$.value = check_assertion ($2.address, $2.length,
+ 0, NULL_PTR);
+ $$.unsignedp = 0; }
+ | '#' NAME
+ { keyword_parsing = 1; }
+ '(' keywords ')'
+ { $$.value = check_assertion ($2.address, $2.length,
+ 1, $5);
+ keyword_parsing = 0;
+ $$.unsignedp = 0; }
+ | '(' exp1 ')'
+ { $$ = $2; }
+ ;
+
+/* Binary operators in order of decreasing precedence. */
+exp : exp '*' exp
+ { $$.unsignedp = $1.unsignedp || $3.unsignedp;
+ if ($$.unsignedp)
+ $$.value = (unsigned long) $1.value * $3.value;
+ else
+ {
+ $$.value = $1.value * $3.value;
+ if ($1.value
+ && ($$.value / $1.value != $3.value
+ || ($$.value & $1.value & $3.value) < 0))
+ integer_overflow ();
+ } }
+ | exp '/' exp
+ { if ($3.value == 0)
+ {
+ if (!skip_evaluation)
+ error ("division by zero in #if");
+ $3.value = 1;
+ }
+ $$.unsignedp = $1.unsignedp || $3.unsignedp;
+ if ($$.unsignedp)
+ $$.value = (unsigned long) $1.value / $3.value;
+ else
+ {
+ $$.value = $1.value / $3.value;
+ if (($$.value & $1.value & $3.value) < 0)
+ integer_overflow ();
+ } }
+ | exp '%' exp
+ { if ($3.value == 0)
+ {
+ if (!skip_evaluation)
+ error ("division by zero in #if");
+ $3.value = 1;
+ }
+ $$.unsignedp = $1.unsignedp || $3.unsignedp;
+ if ($$.unsignedp)
+ $$.value = (unsigned long) $1.value % $3.value;
+ else
+ $$.value = $1.value % $3.value; }
+ | exp '+' exp
+ { $$.value = $1.value + $3.value;
+ $$.unsignedp = $1.unsignedp || $3.unsignedp;
+ if (! $$.unsignedp
+ && ! possible_sum_sign ($1.value, $3.value,
+ $$.value))
+ integer_overflow (); }
+ | exp '-' exp
+ { $$.value = $1.value - $3.value;
+ $$.unsignedp = $1.unsignedp || $3.unsignedp;
+ if (! $$.unsignedp
+ && ! possible_sum_sign ($$.value, $3.value,
+ $1.value))
+ integer_overflow (); }
+ | exp LSH exp
+ { $$.unsignedp = $1.unsignedp;
+ if ($3.value < 0 && ! $3.unsignedp)
+ $$.value = right_shift (&$1, -$3.value);
+ else
+ $$.value = left_shift (&$1, $3.value); }
+ | exp RSH exp
+ { $$.unsignedp = $1.unsignedp;
+ if ($3.value < 0 && ! $3.unsignedp)
+ $$.value = left_shift (&$1, -$3.value);
+ else
+ $$.value = right_shift (&$1, $3.value); }
+ | exp EQUAL exp
+ { $$.value = ($1.value == $3.value);
+ $$.unsignedp = 0; }
+ | exp NOTEQUAL exp
+ { $$.value = ($1.value != $3.value);
+ $$.unsignedp = 0; }
+ | exp LEQ exp
+ { $$.unsignedp = 0;
+ if ($1.unsignedp || $3.unsignedp)
+ $$.value = (unsigned long) $1.value <= $3.value;
+ else
+ $$.value = $1.value <= $3.value; }
+ | exp GEQ exp
+ { $$.unsignedp = 0;
+ if ($1.unsignedp || $3.unsignedp)
+ $$.value = (unsigned long) $1.value >= $3.value;
+ else
+ $$.value = $1.value >= $3.value; }
+ | exp '<' exp
+ { $$.unsignedp = 0;
+ if ($1.unsignedp || $3.unsignedp)
+ $$.value = (unsigned long) $1.value < $3.value;
+ else
+ $$.value = $1.value < $3.value; }
+ | exp '>' exp
+ { $$.unsignedp = 0;
+ if ($1.unsignedp || $3.unsignedp)
+ $$.value = (unsigned long) $1.value > $3.value;
+ else
+ $$.value = $1.value > $3.value; }
+ | exp '&' exp
+ { $$.value = $1.value & $3.value;
+ $$.unsignedp = $1.unsignedp || $3.unsignedp; }
+ | exp '^' exp
+ { $$.value = $1.value ^ $3.value;
+ $$.unsignedp = $1.unsignedp || $3.unsignedp; }
+ | exp '|' exp
+ { $$.value = $1.value | $3.value;
+ $$.unsignedp = $1.unsignedp || $3.unsignedp; }
+ | exp AND
+ { skip_evaluation += !$1.value; }
+ exp
+ { skip_evaluation -= !$1.value;
+ $$.value = ($1.value && $4.value);
+ $$.unsignedp = 0; }
+ | exp OR
+ { skip_evaluation += !!$1.value; }
+ exp
+ { skip_evaluation -= !!$1.value;
+ $$.value = ($1.value || $4.value);
+ $$.unsignedp = 0; }
+ | exp '?'
+ { skip_evaluation += !$1.value; }
+ exp ':'
+ { skip_evaluation += !!$1.value - !$1.value; }
+ exp
+ { skip_evaluation -= !!$1.value;
+ $$.value = $1.value ? $4.value : $7.value;
+ $$.unsignedp = $4.unsignedp || $7.unsignedp; }
+ | INT
+ { $$ = yylval.integer; }
+ | CHAR
+ { $$ = yylval.integer; }
+ | NAME
+ { $$.value = 0;
+ $$.unsignedp = 0; }
+ ;
+
+keywords :
+ { $$ = 0; }
+ | '(' keywords ')' keywords
+ { struct arglist *temp;
+ $$ = (struct arglist *) xmalloc (sizeof (struct arglist));
+ $$->next = $2;
+ $$->name = (U_CHAR *) "(";
+ $$->length = 1;
+ temp = $$;
+ while (temp != 0 && temp->next != 0)
+ temp = temp->next;
+ temp->next = (struct arglist *) xmalloc (sizeof (struct arglist));
+ temp->next->next = $4;
+ temp->next->name = (U_CHAR *) ")";
+ temp->next->length = 1; }
+ | NAME keywords
+ { $$ = (struct arglist *) xmalloc (sizeof (struct arglist));
+ $$->name = $1.address;
+ $$->length = $1.length;
+ $$->next = $2; }
+ ;
+%%
+
+/* During parsing of a C expression, the pointer to the next character
+ is in this variable. */
+
+static char *lexptr;
+
+/* Take care of parsing a number (anything that starts with a digit).
+ Set yylval and return the token type; update lexptr.
+ LEN is the number of characters in it. */
+
+/* maybe needs to actually deal with floating point numbers */
+
+int
+parse_number (olen)
+ int olen;
+{
+ register char *p = lexptr;
+ register int c;
+ register unsigned long n = 0, nd, ULONG_MAX_over_base;
+ register int base = 10;
+ register int len = olen;
+ register int overflow = 0;
+ register int digit, largest_digit = 0;
+ int spec_long = 0;
+
+ for (c = 0; c < len; c++)
+ if (p[c] == '.') {
+ /* It's a float since it contains a point. */
+ yyerror ("floating point numbers not allowed in #if expressions");
+ return ERROR;
+ }
+
+ yylval.integer.unsignedp = 0;
+
+ if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) {
+ p += 2;
+ base = 16;
+ len -= 2;
+ }
+ else if (*p == '0')
+ base = 8;
+
+ ULONG_MAX_over_base = (unsigned long) -1 / base;
+
+ for (; len > 0; len--) {
+ c = *p++;
+
+ if (c >= '0' && c <= '9')
+ digit = c - '0';
+ else if (base == 16 && c >= 'a' && c <= 'f')
+ digit = c - 'a' + 10;
+ else if (base == 16 && c >= 'A' && c <= 'F')
+ digit = c - 'A' + 10;
+ else {
+ /* `l' means long, and `u' means unsigned. */
+ while (1) {
+ if (c == 'l' || c == 'L')
+ {
+ if (spec_long)
+ yyerror ("two `l's in integer constant");
+ spec_long = 1;
+ }
+ else if (c == 'u' || c == 'U')
+ {
+ if (yylval.integer.unsignedp)
+ yyerror ("two `u's in integer constant");
+ yylval.integer.unsignedp = 1;
+ }
+ else
+ break;
+
+ if (--len == 0)
+ break;
+ c = *p++;
+ }
+ /* Don't look for any more digits after the suffixes. */
+ break;
+ }
+ if (largest_digit < digit)
+ largest_digit = digit;
+ nd = n * base + digit;
+ overflow |= ULONG_MAX_over_base < n | nd < n;
+ n = nd;
+ }
+
+ if (len != 0) {
+ yyerror ("Invalid number in #if expression");
+ return ERROR;
+ }
+
+ if (base <= largest_digit)
+ warning ("integer constant contains digits beyond the radix");
+
+ if (overflow)
+ warning ("integer constant out of range");
+
+ /* If too big to be signed, consider it unsigned. */
+ if ((long) n < 0 && ! yylval.integer.unsignedp)
+ {
+ if (base == 10)
+ warning ("integer constant is so large that it is unsigned");
+ yylval.integer.unsignedp = 1;
+ }
+
+ lexptr = p;
+ yylval.integer.value = n;
+ return INT;
+}
+
+struct token {
+ char *operator;
+ int token;
+};
+
+static struct token tokentab2[] = {
+ {"&&", AND},
+ {"||", OR},
+ {"<<", LSH},
+ {">>", RSH},
+ {"==", EQUAL},
+ {"!=", NOTEQUAL},
+ {"<=", LEQ},
+ {">=", GEQ},
+ {"++", ERROR},
+ {"--", ERROR},
+ {NULL, ERROR}
+};
+
+/* Read one token, getting characters through lexptr. */
+
+int
+yylex ()
+{
+ register int c;
+ register int namelen;
+ register unsigned char *tokstart;
+ register struct token *toktab;
+ int wide_flag;
+
+ retry:
+
+ tokstart = (unsigned char *) lexptr;
+ c = *tokstart;
+ /* See if it is a special token of length 2. */
+ if (! keyword_parsing)
+ for (toktab = tokentab2; toktab->operator != NULL; toktab++)
+ if (c == *toktab->operator && tokstart[1] == toktab->operator[1]) {
+ lexptr += 2;
+ if (toktab->token == ERROR)
+ {
+ char *buf = (char *) alloca (40);
+ sprintf (buf, "`%s' not allowed in operand of `#if'", toktab->operator);
+ yyerror (buf);
+ }
+ return toktab->token;
+ }
+
+ switch (c) {
+ case 0:
+ return 0;
+
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ lexptr++;
+ goto retry;
+
+ case 'L':
+ /* Capital L may start a wide-string or wide-character constant. */
+ if (lexptr[1] == '\'')
+ {
+ lexptr++;
+ wide_flag = 1;
+ goto char_constant;
+ }
+ if (lexptr[1] == '"')
+ {
+ lexptr++;
+ wide_flag = 1;
+ goto string_constant;
+ }
+ break;
+
+ case '\'':
+ wide_flag = 0;
+ char_constant:
+ lexptr++;
+ if (keyword_parsing) {
+ char *start_ptr = lexptr - 1;
+ while (1) {
+ c = *lexptr++;
+ if (c == '\\')
+ c = parse_escape (&lexptr);
+ else if (c == '\'')
+ break;
+ }
+ yylval.name.address = tokstart;
+ yylval.name.length = lexptr - start_ptr;
+ return NAME;
+ }
+
+ /* This code for reading a character constant
+ handles multicharacter constants and wide characters.
+ It is mostly copied from c-lex.c. */
+ {
+ register int result = 0;
+ register num_chars = 0;
+ unsigned width = MAX_CHAR_TYPE_SIZE;
+ int max_chars;
+ char *token_buffer;
+
+ if (wide_flag)
+ {
+ width = MAX_WCHAR_TYPE_SIZE;
+#ifdef MULTIBYTE_CHARS
+ max_chars = MB_CUR_MAX;
+#else
+ max_chars = 1;
+#endif
+ }
+ else
+ max_chars = MAX_LONG_TYPE_SIZE / width;
+
+ token_buffer = (char *) alloca (max_chars + 1);
+
+ while (1)
+ {
+ c = *lexptr++;
+
+ if (c == '\'' || c == EOF)
+ break;
+
+ if (c == '\\')
+ {
+ c = parse_escape (&lexptr);
+ if (width < HOST_BITS_PER_INT
+ && (unsigned) c >= (1 << width))
+ pedwarn ("escape sequence out of range for character");
+ }
+
+ num_chars++;
+
+ /* Merge character into result; ignore excess chars. */
+ if (num_chars < max_chars + 1)
+ {
+ if (width < HOST_BITS_PER_INT)
+ result = (result << width) | (c & ((1 << width) - 1));
+ else
+ result = c;
+ token_buffer[num_chars - 1] = c;
+ }
+ }
+
+ token_buffer[num_chars] = 0;
+
+ if (c != '\'')
+ error ("malformatted character constant");
+ else if (num_chars == 0)
+ error ("empty character constant");
+ else if (num_chars > max_chars)
+ {
+ num_chars = max_chars;
+ error ("character constant too long");
+ }
+ else if (num_chars != 1 && ! traditional)
+ warning ("multi-character character constant");
+
+ /* If char type is signed, sign-extend the constant. */
+ if (! wide_flag)
+ {
+ int num_bits = num_chars * width;
+
+ if (lookup ("__CHAR_UNSIGNED__", sizeof ("__CHAR_UNSIGNED__")-1, -1)
+ || ((result >> (num_bits - 1)) & 1) == 0)
+ yylval.integer.value
+ = result & ((unsigned long) ~0 >> (HOST_BITS_PER_LONG - num_bits));
+ else
+ yylval.integer.value
+ = result | ~((unsigned long) ~0 >> (HOST_BITS_PER_LONG - num_bits));
+ }
+ else
+ {
+#ifdef MULTIBYTE_CHARS
+ /* Set the initial shift state and convert the next sequence. */
+ result = 0;
+ /* In all locales L'\0' is zero and mbtowc will return zero,
+ so don't use it. */
+ if (num_chars > 1
+ || (num_chars == 1 && token_buffer[0] != '\0'))
+ {
+ wchar_t wc;
+ (void) mbtowc (NULL_PTR, NULL_PTR, 0);
+ if (mbtowc (& wc, token_buffer, num_chars) == num_chars)
+ result = wc;
+ else
+ warning ("Ignoring invalid multibyte character");
+ }
+#endif
+ yylval.integer.value = result;
+ }
+ }
+
+ /* This is always a signed type. */
+ yylval.integer.unsignedp = 0;
+
+ return CHAR;
+
+ /* some of these chars are invalid in constant expressions;
+ maybe do something about them later */
+ case '/':
+ case '+':
+ case '-':
+ case '*':
+ case '%':
+ case '|':
+ case '&':
+ case '^':
+ case '~':
+ case '!':
+ case '@':
+ case '<':
+ case '>':
+ case '[':
+ case ']':
+ case '.':
+ case '?':
+ case ':':
+ case '=':
+ case '{':
+ case '}':
+ case ',':
+ case '#':
+ if (keyword_parsing)
+ break;
+ case '(':
+ case ')':
+ lexptr++;
+ return c;
+
+ case '"':
+ string_constant:
+ if (keyword_parsing) {
+ char *start_ptr = lexptr;
+ lexptr++;
+ while (1) {
+ c = *lexptr++;
+ if (c == '\\')
+ c = parse_escape (&lexptr);
+ else if (c == '"')
+ break;
+ }
+ yylval.name.address = tokstart;
+ yylval.name.length = lexptr - start_ptr;
+ return NAME;
+ }
+ yyerror ("string constants not allowed in #if expressions");
+ return ERROR;
+ }
+
+ if (c >= '0' && c <= '9' && !keyword_parsing) {
+ /* It's a number */
+ for (namelen = 0;
+ c = tokstart[namelen], is_idchar[c] || c == '.';
+ namelen++)
+ ;
+ return parse_number (namelen);
+ }
+
+ /* It is a name. See how long it is. */
+
+ if (keyword_parsing) {
+ for (namelen = 0;; namelen++) {
+ if (is_hor_space[tokstart[namelen]])
+ break;
+ if (tokstart[namelen] == '(' || tokstart[namelen] == ')')
+ break;
+ if (tokstart[namelen] == '"' || tokstart[namelen] == '\'')
+ break;
+ }
+ } else {
+ if (!is_idstart[c]) {
+ yyerror ("Invalid token in expression");
+ return ERROR;
+ }
+
+ for (namelen = 0; is_idchar[tokstart[namelen]]; namelen++)
+ ;
+ }
+
+ lexptr += namelen;
+ yylval.name.address = tokstart;
+ yylval.name.length = namelen;
+ return NAME;
+}
+
+
+/* Parse a C escape sequence. STRING_PTR points to a variable
+ containing a pointer to the string to parse. That pointer
+ is updated past the characters we use. The value of the
+ escape sequence is returned.
+
+ A negative value means the sequence \ newline was seen,
+ which is supposed to be equivalent to nothing at all.
+
+ If \ is followed by a null character, we return a negative
+ value and leave the string pointer pointing at the null character.
+
+ If \ is followed by 000, we return 0 and leave the string pointer
+ after the zeros. A value of 0 does not mean end of string. */
+
+int
+parse_escape (string_ptr)
+ char **string_ptr;
+{
+ register int c = *(*string_ptr)++;
+ switch (c)
+ {
+ case 'a':
+ return TARGET_BELL;
+ case 'b':
+ return TARGET_BS;
+ case 'e':
+ case 'E':
+ if (pedantic)
+ pedwarn ("non-ANSI-standard escape sequence, `\\%c'", c);
+ return 033;
+ case 'f':
+ return TARGET_FF;
+ case 'n':
+ return TARGET_NEWLINE;
+ case 'r':
+ return TARGET_CR;
+ case 't':
+ return TARGET_TAB;
+ case 'v':
+ return TARGET_VT;
+ case '\n':
+ return -2;
+ case 0:
+ (*string_ptr)--;
+ return 0;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ register int i = c - '0';
+ register int count = 0;
+ while (++count < 3)
+ {
+ c = *(*string_ptr)++;
+ if (c >= '0' && c <= '7')
+ i = (i << 3) + c - '0';
+ else
+ {
+ (*string_ptr)--;
+ break;
+ }
+ }
+ if ((i & ~((1 << MAX_CHAR_TYPE_SIZE) - 1)) != 0)
+ {
+ i &= (1 << MAX_CHAR_TYPE_SIZE) - 1;
+ warning ("octal character constant does not fit in a byte");
+ }
+ return i;
+ }
+ case 'x':
+ {
+ register unsigned i = 0, overflow = 0, digits_found = 0, digit;
+ for (;;)
+ {
+ c = *(*string_ptr)++;
+ if (c >= '0' && c <= '9')
+ digit = c - '0';
+ else if (c >= 'a' && c <= 'f')
+ digit = c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ digit = c - 'A' + 10;
+ else
+ {
+ (*string_ptr)--;
+ break;
+ }
+ overflow |= i ^ (i << 4 >> 4);
+ i = (i << 4) + digit;
+ digits_found = 1;
+ }
+ if (!digits_found)
+ yyerror ("\\x used with no following hex digits");
+ if (overflow | (i & ~((1 << BITS_PER_UNIT) - 1)))
+ {
+ i &= (1 << BITS_PER_UNIT) - 1;
+ warning ("hex character constant does not fit in a byte");
+ }
+ return i;
+ }
+ default:
+ return c;
+ }
+}
+
+void
+yyerror (s)
+ char *s;
+{
+ error (s);
+ skip_evaluation = 0;
+ longjmp (parse_return_error, 1);
+}
+
+static void
+integer_overflow ()
+{
+ if (!skip_evaluation && pedantic)
+ pedwarn ("integer overflow in preprocessor expression");
+}
+
+static long
+left_shift (a, b)
+ struct constant *a;
+ unsigned long b;
+{
+ /* It's unclear from the C standard whether shifts can overflow.
+ The following code ignores overflow; perhaps a C standard
+ interpretation ruling is needed. */
+ if (b >= HOST_BITS_PER_LONG)
+ return 0;
+ else if (a->unsignedp)
+ return (unsigned long) a->value << b;
+ else
+ return a->value << b;
+}
+
+static long
+right_shift (a, b)
+ struct constant *a;
+ unsigned long b;
+{
+ if (b >= HOST_BITS_PER_LONG)
+ return a->unsignedp ? 0 : a->value >> (HOST_BITS_PER_LONG - 1);
+ else if (a->unsignedp)
+ return (unsigned long) a->value >> b;
+ else
+ return a->value >> b;
+}
+
+/* This page contains the entry point to this file. */
+
+/* Parse STRING as an expression, and complain if this fails
+ to use up all of the contents of STRING. */
+/* We do not support C comments. They should be removed before
+ this function is called. */
+
+HOST_WIDE_INT
+parse_c_expression (string)
+ char *string;
+{
+ lexptr = string;
+
+ if (lexptr == 0 || *lexptr == 0) {
+ error ("empty #if expression");
+ return 0; /* don't include the #if group */
+ }
+
+ /* if there is some sort of scanning error, just return 0 and assume
+ the parsing routine has printed an error message somewhere.
+ there is surely a better thing to do than this. */
+ if (setjmp (parse_return_error))
+ return 0;
+
+ if (yyparse ())
+ return 0; /* actually this is never reached
+ the way things stand. */
+ if (*lexptr)
+ error ("Junk after end of expression.");
+
+ return expression_value; /* set by yyparse () */
+}
+
+#ifdef TEST_EXP_READER
+extern int yydebug;
+
+/* Main program for testing purposes. */
+int
+main ()
+{
+ int n, c;
+ char buf[1024];
+
+/*
+ yydebug = 1;
+*/
+ initialize_random_junk ();
+
+ for (;;) {
+ printf ("enter expression: ");
+ n = 0;
+ while ((buf[n] = getchar ()) != '\n' && buf[n] != EOF)
+ n++;
+ if (buf[n] == EOF)
+ break;
+ buf[n] = '\0';
+ printf ("parser returned %ld\n", parse_c_expression (buf));
+ }
+
+ return 0;
+}
+
+/* table to tell if char can be part of a C identifier. */
+unsigned char is_idchar[256];
+/* table to tell if char can be first char of a c identifier. */
+unsigned char is_idstart[256];
+/* table to tell if c is horizontal space. isspace () thinks that
+ newline is space; this is not a good idea for this program. */
+char is_hor_space[256];
+
+/*
+ * initialize random junk in the hash table and maybe other places
+ */
+initialize_random_junk ()
+{
+ register int i;
+
+ /*
+ * Set up is_idchar and is_idstart tables. These should be
+ * faster than saying (is_alpha (c) || c == '_'), etc.
+ * Must do set up these things before calling any routines tthat
+ * refer to them.
+ */
+ for (i = 'a'; i <= 'z'; i++) {
+ ++is_idchar[i - 'a' + 'A'];
+ ++is_idchar[i];
+ ++is_idstart[i - 'a' + 'A'];
+ ++is_idstart[i];
+ }
+ for (i = '0'; i <= '9'; i++)
+ ++is_idchar[i];
+ ++is_idchar['_'];
+ ++is_idstart['_'];
+#if DOLLARS_IN_IDENTIFIERS
+ ++is_idchar['$'];
+ ++is_idstart['$'];
+#endif
+
+ /* horizontal space table */
+ ++is_hor_space[' '];
+ ++is_hor_space['\t'];
+}
+
+error (msg)
+{
+ printf ("error: %s\n", msg);
+}
+
+warning (msg)
+{
+ printf ("warning: %s\n", msg);
+}
+
+struct hashnode *
+lookup (name, len, hash)
+ char *name;
+ int len;
+ int hash;
+{
+ return (DEFAULT_SIGNED_CHAR) ? 0 : ((struct hashnode *) -1);
+}
+#endif
diff --git a/gnu/usr.bin/gcc/gcc2netbsd b/gnu/usr.bin/gcc/gcc2netbsd
index 6d254eebe0a..988d0b61ccd 100644
--- a/gnu/usr.bin/gcc/gcc2netbsd
+++ b/gnu/usr.bin/gcc/gcc2netbsd
@@ -1,6 +1,6 @@
#!/usr/gnu/bin/perl
#
-# $NetBSD: gcc2netbsd,v 1.4 1996/01/08 03:51:38 phil Exp $
+# $NetBSD: gcc2netbsd,v 1.5 1996/02/28 21:01:27 phil Exp $
#
# Perl script to convert a standard distribution directory for gcc into
# a NetBSD source tree.
@@ -44,9 +44,11 @@ $version = "2.7.2";
@cc1f = ("c-parse.c", "c-lang.c");
+@cc1of = ("c-parse.y");
+
@cc1objf = ("objc-parse.c", "objc-act.c");
-@cc1objof = ("objc-tree.def", "objc-act.h");
+@cc1objof = ("objc-tree.def", "objc-act.h", "objc-parse.y");
@cc1plusf = ("call.c", "decl.c", "errfn.c", "expr.c", "pt.c", "sig.c",
"typeck2.c", "class.c", "decl2.c", "error.c", "gc.c",
@@ -55,7 +57,7 @@ $version = "2.7.2";
"search.c", "tree.c", "xref.c", "repo.c");
@cc1plusof = ("tree.def", "class.h", "cp-tree.h", "decl.h", "hash.h",
- "lex.h", "parse.h", "input.c");
+ "lex.h", "parse.h", "input.c", "parse.y");
@commonf = ("bc-emit.c", "bc-optab.c", "bi-reverse.c", "c-aux-info.c",
"c-common.c", "c-convert.c", "c-decl.c", "c-iterate.c",
@@ -83,7 +85,7 @@ $version = "2.7.2";
"hard-reg-set.h", "input.h", "integrate.h", "loop.h",
"machmode.h", "obstack.h", "output.h", "real.h",
"recog.h", "regs.h", "reload.h", "rtl.h", "stack.h",
- "tree.h", "typeclass.h", "xcoffout.h");
+ "tree.h", "typeclass.h", "xcoffout.h", "bi-parser.y");
@commonplus = ("lang-specs.h", "lang-options.h");
@@ -95,7 +97,7 @@ $version = "2.7.2";
@cppf = ("cccp.c", "cexp.c");
-@cppof = ("pcp.h");
+@cppof = ("pcp.h", "cexp.y");
@gplusf = ("g++.c");