aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-parse.y
diff options
context:
space:
mode:
authorlaw <law@138bc75d-0d04-0410-961f-82ee72b054a4>1997-08-11 15:56:58 +0000
committerlaw <law@138bc75d-0d04-0410-961f-82ee72b054a4>1997-08-11 15:56:58 +0000
commit071cd279a6ac9efccecd8171777a9fc99ac4796a (patch)
treeb2e1ea43e0bdba8cca9bb02ed01f5e3da5a955a6 /gcc/c-parse.y
parent5b48acd0eb694e43d357e6ad8f2daa604ad8d2ff (diff)
Initial revision
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@14764 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/c-parse.y')
-rw-r--r--gcc/c-parse.y2176
1 files changed, 2176 insertions, 0 deletions
diff --git a/gcc/c-parse.y b/gcc/c-parse.y
new file mode 100644
index 00000000000..fd2b0f94a08
--- /dev/null
+++ b/gcc/c-parse.y
@@ -0,0 +1,2176 @@
+/*WARNING: This file is automatically generated!*/
+/* YACC parser for C syntax and for Objective C. -*-c-*-
+ Copyright (C) 1987, 88, 89, 92-6, 1997 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 46
+
+/* 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> typed_declspecs_no_prefix_attr reserved_declspecs_no_prefix_attr
+%type <ttype> declmods_no_prefix_attr
+%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 = NULL_TREE;
+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"); }
+ | extension extdef
+ { pedantic = $<itype>1; }
+ ;
+
+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 (current_declspecs, $3,
+ prefix_attributes, NULL_TREE, 0))
+ YYERROR1;
+ reinit_parse_for_function (); }
+ old_style_parm_decls
+ { 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 (current_declspecs, $3,
+ prefix_attributes, NULL_TREE, 0))
+ YYERROR1;
+ reinit_parse_for_function (); }
+ old_style_parm_decls
+ { 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 (); }
+ old_style_parm_decls
+ { 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 cast_expr %prec UNARY
+ { $$ = $2;
+ 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
+ { skip_evaluation--;
+ 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
+ { skip_evaluation--;
+ $$ = c_sizeof (groktypename ($3)); }
+ | alignof unary_expr %prec UNARY
+ { skip_evaluation--;
+ $$ = c_alignof_expr ($2); }
+ | alignof '(' typename ')' %prec HYPERUNARY
+ { skip_evaluation--;
+ $$ = 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); }
+ ;
+
+sizeof:
+ SIZEOF { skip_evaluation++; }
+ ;
+
+alignof:
+ ALIGNOF { skip_evaluation++; }
+ ;
+
+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
+ { $1 = truthvalue_conversion (default_conversion ($1));
+ skip_evaluation += $1 == boolean_false_node; }
+ expr_no_commas
+ { skip_evaluation -= $1 == boolean_false_node;
+ $$ = parser_build_binary_op (TRUTH_ANDIF_EXPR, $1, $4); }
+ | expr_no_commas OROR
+ { $1 = truthvalue_conversion (default_conversion ($1));
+ skip_evaluation += $1 == boolean_true_node; }
+ expr_no_commas
+ { skip_evaluation -= $1 == boolean_true_node;
+ $$ = parser_build_binary_op (TRUTH_ORIF_EXPR, $1, $4); }
+ | expr_no_commas '?'
+ { $1 = truthvalue_conversion (default_conversion ($1));
+ skip_evaluation += $1 == boolean_false_node; }
+ expr ':'
+ { skip_evaluation += (($1 == boolean_true_node)
+ - ($1 == boolean_false_node)); }
+ expr_no_commas
+ { skip_evaluation -= $1 == boolean_true_node;
+ $$ = build_conditional_expr ($1, $4, $7); }
+ | expr_no_commas '?'
+ { if (pedantic)
+ pedwarn ("ANSI C forbids omitting the middle term of a ?: expression");
+ /* Make sure first operand is calculated only once. */
+ $<ttype>2 = save_expr ($1);
+ $1 = truthvalue_conversion (default_conversion ($<ttype>2));
+ skip_evaluation += $1 == boolean_true_node; }
+ ':' expr_no_commas
+ { skip_evaluation -= $1 == boolean_true_node;
+ $$ = build_conditional_expr ($1, $<ttype>2, $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); }
+ ;
+
+
+old_style_parm_decls:
+ /* 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
+ ;
+
+/* We don't allow prefix attributes here because they cause reduce/reduce
+ conflicts: we can't know whether we're parsing a function decl with
+ attribute suffix, or function defn with attribute prefix on first old
+ style parm. */
+datadecl:
+ typed_declspecs_no_prefix_attr setspecs initdecls ';'
+ { current_declspecs = TREE_VALUE (declspec_stack);
+ prefix_attributes = TREE_PURPOSE (declspec_stack);
+ declspec_stack = TREE_CHAIN (declspec_stack);
+ resume_momentary ($2); }
+ | declmods_no_prefix_attr 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_no_prefix_attr ';'
+ { shadow_tag_warned ($1, 1);
+ pedwarn ("empty declaration"); }
+ | declmods_no_prefix_attr ';'
+ { 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);
+ split_specs_attrs ($<ttype>0,
+ &current_declspecs, &prefix_attributes); }
+ ;
+
+/* ??? Yuck. See after_type_declarator. */
+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"); }
+ | extension decl
+ { pedantic = $<itype>1; }
+ ;
+
+/* Declspecs which contain at least one type specifier or typedef name.
+ (Just `const' or `volatile' is not enough.)
+ A typedef'd name following these is taken as a name to be declared.
+ Declspecs have a non-NULL TREE_VALUE, attributes do not. */
+
+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); }
+ | reserved_declspecs attributes
+ { $$ = tree_cons ($2, NULL_TREE, $1); }
+ ;
+
+typed_declspecs_no_prefix_attr:
+ typespec reserved_declspecs_no_prefix_attr
+ { $$ = tree_cons (NULL_TREE, $1, $2); }
+ | declmods_no_prefix_attr typespec reserved_declspecs_no_prefix_attr
+ { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); }
+ ;
+
+reserved_declspecs_no_prefix_attr:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | reserved_declspecs_no_prefix_attr typespecqual_reserved
+ { $$ = tree_cons (NULL_TREE, $2, $1); }
+ | reserved_declspecs_no_prefix_attr 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, type modifiers, and prefix attributes.
+ A declaration can start with just this, but then it cannot be used
+ to redeclare a typedef-name.
+ Declspecs have a non-NULL TREE_VALUE, attributes do not. */
+
+declmods:
+ declmods_no_prefix_attr
+ { $$ = $1; }
+ | attributes
+ { $$ = tree_cons ($1, NULL_TREE, NULL_TREE); }
+ | declmods declmods_no_prefix_attr
+ { $$ = chainon ($2, $1); }
+ | declmods attributes
+ { $$ = tree_cons ($2, NULL_TREE, $1); }
+ ;
+
+declmods_no_prefix_attr:
+ TYPE_QUAL
+ { $$ = tree_cons (NULL_TREE, $1, NULL_TREE);
+ TREE_STATIC ($$) = 1; }
+ | SCSPEC
+ { $$ = tree_cons (NULL_TREE, $1, NULL_TREE); }
+ | declmods_no_prefix_attr TYPE_QUAL
+ { $$ = tree_cons (NULL_TREE, $2, $1);
+ TREE_STATIC ($$) = 1; }
+ | declmods_no_prefix_attr 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 (); }
+ old_style_parm_decls
+ { 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 (); }
+ old_style_parm_decls
+ { 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); }
+ /* ??? Yuck. setattrs is a quick hack. We can't use
+ prefix_attributes because $1 only applies to this
+ declarator. We assume setspecs has already been done.
+ setattrs also avoids 5 reduce/reduce conflicts (otherwise multiple
+ attributes could be recognized here or in `attributes'). */
+ | 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); }
+ /* ??? Yuck. setattrs is a quick hack. We can't use
+ prefix_attributes because $1 only applies to this
+ declarator. We assume setspecs has already been done.
+ setattrs also avoids 5 reduce/reduce conflicts (otherwise multiple
+ attributes could be recognized here or in `attributes'). */
+ | 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); }
+ /* ??? Yuck. setattrs is a quick hack. We can't use
+ prefix_attributes because $1 only applies to this
+ declarator. We assume setspecs has already been done.
+ setattrs also avoids 5 reduce/reduce conflicts (otherwise multiple
+ attributes could be recognized here or in `attributes'). */
+ | 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; }
+ | extension component_decl
+ { $$ = $2;
+ pedantic = $<itype>1; }
+ ;
+
+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); }
+ /* ??? It appears we have to support attributes here, however
+ using prefix_attributes is wrong. */
+ ;
+
+/* 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 ';'
+ { if (pedantic)
+ pedwarn ("ANSI C forbids `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);
+
+ if (pedantic)
+ pedwarn ("ANSI C forbids case ranges");
+ 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)); }
+ ;
+
+extension:
+ EXTENSION
+ { $<itype>$ = pedantic;
+ pedantic = 0; }
+ ;
+
+%%