162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * C global declaration parser for genksyms.
462306a36Sopenharmony_ci * Copyright 1996, 1997 Linux International.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * New implementation contributed by Richard Henderson <rth@tamu.edu>
762306a36Sopenharmony_ci * Based on original work by Bjorn Ekwall <bj0rn@blox.se>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * This file is part of the Linux modutils.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci%{
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <assert.h>
1562306a36Sopenharmony_ci#include <stdlib.h>
1662306a36Sopenharmony_ci#include <string.h>
1762306a36Sopenharmony_ci#include "genksyms.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic int is_typedef;
2062306a36Sopenharmony_cistatic int is_extern;
2162306a36Sopenharmony_cistatic char *current_name;
2262306a36Sopenharmony_cistatic struct string_list *decl_spec;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic void yyerror(const char *);
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic inline void
2762306a36Sopenharmony_ciremove_node(struct string_list **p)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci  struct string_list *node = *p;
3062306a36Sopenharmony_ci  *p = node->next;
3162306a36Sopenharmony_ci  free_node(node);
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic inline void
3562306a36Sopenharmony_ciremove_list(struct string_list **pb, struct string_list **pe)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci  struct string_list *b = *pb, *e = *pe;
3862306a36Sopenharmony_ci  *pb = e;
3962306a36Sopenharmony_ci  free_list(b, e);
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/* Record definition of a struct/union/enum */
4362306a36Sopenharmony_cistatic void record_compound(struct string_list **keyw,
4462306a36Sopenharmony_ci		       struct string_list **ident,
4562306a36Sopenharmony_ci		       struct string_list **body,
4662306a36Sopenharmony_ci		       enum symbol_type type)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	struct string_list *b = *body, *i = *ident, *r;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	if (i->in_source_file) {
5162306a36Sopenharmony_ci		remove_node(keyw);
5262306a36Sopenharmony_ci		(*ident)->tag = type;
5362306a36Sopenharmony_ci		remove_list(body, ident);
5462306a36Sopenharmony_ci		return;
5562306a36Sopenharmony_ci	}
5662306a36Sopenharmony_ci	r = copy_node(i); r->tag = type;
5762306a36Sopenharmony_ci	r->next = (*keyw)->next; *body = r; (*keyw)->next = NULL;
5862306a36Sopenharmony_ci	add_symbol(i->string, type, b, is_extern);
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci%}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci%token ASM_KEYW
6462306a36Sopenharmony_ci%token ATTRIBUTE_KEYW
6562306a36Sopenharmony_ci%token AUTO_KEYW
6662306a36Sopenharmony_ci%token BOOL_KEYW
6762306a36Sopenharmony_ci%token BUILTIN_INT_KEYW
6862306a36Sopenharmony_ci%token CHAR_KEYW
6962306a36Sopenharmony_ci%token CONST_KEYW
7062306a36Sopenharmony_ci%token DOUBLE_KEYW
7162306a36Sopenharmony_ci%token ENUM_KEYW
7262306a36Sopenharmony_ci%token EXTERN_KEYW
7362306a36Sopenharmony_ci%token EXTENSION_KEYW
7462306a36Sopenharmony_ci%token FLOAT_KEYW
7562306a36Sopenharmony_ci%token INLINE_KEYW
7662306a36Sopenharmony_ci%token INT_KEYW
7762306a36Sopenharmony_ci%token LONG_KEYW
7862306a36Sopenharmony_ci%token REGISTER_KEYW
7962306a36Sopenharmony_ci%token RESTRICT_KEYW
8062306a36Sopenharmony_ci%token SHORT_KEYW
8162306a36Sopenharmony_ci%token SIGNED_KEYW
8262306a36Sopenharmony_ci%token STATIC_KEYW
8362306a36Sopenharmony_ci%token STATIC_ASSERT_KEYW
8462306a36Sopenharmony_ci%token STRUCT_KEYW
8562306a36Sopenharmony_ci%token TYPEDEF_KEYW
8662306a36Sopenharmony_ci%token UNION_KEYW
8762306a36Sopenharmony_ci%token UNSIGNED_KEYW
8862306a36Sopenharmony_ci%token VOID_KEYW
8962306a36Sopenharmony_ci%token VOLATILE_KEYW
9062306a36Sopenharmony_ci%token TYPEOF_KEYW
9162306a36Sopenharmony_ci%token VA_LIST_KEYW
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci%token EXPORT_SYMBOL_KEYW
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci%token ASM_PHRASE
9662306a36Sopenharmony_ci%token ATTRIBUTE_PHRASE
9762306a36Sopenharmony_ci%token TYPEOF_PHRASE
9862306a36Sopenharmony_ci%token BRACE_PHRASE
9962306a36Sopenharmony_ci%token BRACKET_PHRASE
10062306a36Sopenharmony_ci%token EXPRESSION_PHRASE
10162306a36Sopenharmony_ci%token STATIC_ASSERT_PHRASE
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci%token CHAR
10462306a36Sopenharmony_ci%token DOTS
10562306a36Sopenharmony_ci%token IDENT
10662306a36Sopenharmony_ci%token INT
10762306a36Sopenharmony_ci%token REAL
10862306a36Sopenharmony_ci%token STRING
10962306a36Sopenharmony_ci%token TYPE
11062306a36Sopenharmony_ci%token OTHER
11162306a36Sopenharmony_ci%token FILENAME
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci%%
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cideclaration_seq:
11662306a36Sopenharmony_ci	declaration
11762306a36Sopenharmony_ci	| declaration_seq declaration
11862306a36Sopenharmony_ci	;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cideclaration:
12162306a36Sopenharmony_ci	{ is_typedef = 0; is_extern = 0; current_name = NULL; decl_spec = NULL; }
12262306a36Sopenharmony_ci	declaration1
12362306a36Sopenharmony_ci	{ free_list(*$2, NULL); *$2 = NULL; }
12462306a36Sopenharmony_ci	;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cideclaration1:
12762306a36Sopenharmony_ci	EXTENSION_KEYW TYPEDEF_KEYW { is_typedef = 1; } simple_declaration
12862306a36Sopenharmony_ci		{ $$ = $4; }
12962306a36Sopenharmony_ci	| TYPEDEF_KEYW { is_typedef = 1; } simple_declaration
13062306a36Sopenharmony_ci		{ $$ = $3; }
13162306a36Sopenharmony_ci	| simple_declaration
13262306a36Sopenharmony_ci	| function_definition
13362306a36Sopenharmony_ci	| asm_definition
13462306a36Sopenharmony_ci	| export_definition
13562306a36Sopenharmony_ci	| static_assert
13662306a36Sopenharmony_ci	| error ';'				{ $$ = $2; }
13762306a36Sopenharmony_ci	| error '}'				{ $$ = $2; }
13862306a36Sopenharmony_ci	;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cisimple_declaration:
14162306a36Sopenharmony_ci	decl_specifier_seq_opt init_declarator_list_opt ';'
14262306a36Sopenharmony_ci		{ if (current_name) {
14362306a36Sopenharmony_ci		    struct string_list *decl = (*$3)->next;
14462306a36Sopenharmony_ci		    (*$3)->next = NULL;
14562306a36Sopenharmony_ci		    add_symbol(current_name,
14662306a36Sopenharmony_ci			       is_typedef ? SYM_TYPEDEF : SYM_NORMAL,
14762306a36Sopenharmony_ci			       decl, is_extern);
14862306a36Sopenharmony_ci		    current_name = NULL;
14962306a36Sopenharmony_ci		  }
15062306a36Sopenharmony_ci		  $$ = $3;
15162306a36Sopenharmony_ci		}
15262306a36Sopenharmony_ci	;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ciinit_declarator_list_opt:
15562306a36Sopenharmony_ci	/* empty */				{ $$ = NULL; }
15662306a36Sopenharmony_ci	| init_declarator_list
15762306a36Sopenharmony_ci	;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ciinit_declarator_list:
16062306a36Sopenharmony_ci	init_declarator
16162306a36Sopenharmony_ci		{ struct string_list *decl = *$1;
16262306a36Sopenharmony_ci		  *$1 = NULL;
16362306a36Sopenharmony_ci		  add_symbol(current_name,
16462306a36Sopenharmony_ci			     is_typedef ? SYM_TYPEDEF : SYM_NORMAL, decl, is_extern);
16562306a36Sopenharmony_ci		  current_name = NULL;
16662306a36Sopenharmony_ci		  $$ = $1;
16762306a36Sopenharmony_ci		}
16862306a36Sopenharmony_ci	| init_declarator_list ',' init_declarator
16962306a36Sopenharmony_ci		{ struct string_list *decl = *$3;
17062306a36Sopenharmony_ci		  *$3 = NULL;
17162306a36Sopenharmony_ci		  free_list(*$2, NULL);
17262306a36Sopenharmony_ci		  *$2 = decl_spec;
17362306a36Sopenharmony_ci		  add_symbol(current_name,
17462306a36Sopenharmony_ci			     is_typedef ? SYM_TYPEDEF : SYM_NORMAL, decl, is_extern);
17562306a36Sopenharmony_ci		  current_name = NULL;
17662306a36Sopenharmony_ci		  $$ = $3;
17762306a36Sopenharmony_ci		}
17862306a36Sopenharmony_ci	;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ciinit_declarator:
18162306a36Sopenharmony_ci	declarator asm_phrase_opt attribute_opt initializer_opt
18262306a36Sopenharmony_ci		{ $$ = $4 ? $4 : $3 ? $3 : $2 ? $2 : $1; }
18362306a36Sopenharmony_ci	;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci/* Hang on to the specifiers so that we can reuse them.  */
18662306a36Sopenharmony_cidecl_specifier_seq_opt:
18762306a36Sopenharmony_ci	/* empty */				{ decl_spec = NULL; }
18862306a36Sopenharmony_ci	| decl_specifier_seq
18962306a36Sopenharmony_ci	;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cidecl_specifier_seq:
19262306a36Sopenharmony_ci	decl_specifier				{ decl_spec = *$1; }
19362306a36Sopenharmony_ci	| decl_specifier_seq decl_specifier	{ decl_spec = *$2; }
19462306a36Sopenharmony_ci	;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cidecl_specifier:
19762306a36Sopenharmony_ci	storage_class_specifier
19862306a36Sopenharmony_ci		{ /* Version 2 checksumming ignores storage class, as that
19962306a36Sopenharmony_ci		     is really irrelevant to the linkage.  */
20062306a36Sopenharmony_ci		  remove_node($1);
20162306a36Sopenharmony_ci		  $$ = $1;
20262306a36Sopenharmony_ci		}
20362306a36Sopenharmony_ci	| type_specifier
20462306a36Sopenharmony_ci	;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistorage_class_specifier:
20762306a36Sopenharmony_ci	AUTO_KEYW
20862306a36Sopenharmony_ci	| REGISTER_KEYW
20962306a36Sopenharmony_ci	| STATIC_KEYW
21062306a36Sopenharmony_ci	| EXTERN_KEYW	{ is_extern = 1; $$ = $1; }
21162306a36Sopenharmony_ci	| INLINE_KEYW	{ is_extern = 0; $$ = $1; }
21262306a36Sopenharmony_ci	;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_citype_specifier:
21562306a36Sopenharmony_ci	simple_type_specifier
21662306a36Sopenharmony_ci	| cvar_qualifier
21762306a36Sopenharmony_ci	| TYPEOF_KEYW '(' parameter_declaration ')'
21862306a36Sopenharmony_ci	| TYPEOF_PHRASE
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	/* References to s/u/e's defined elsewhere.  Rearrange things
22162306a36Sopenharmony_ci	   so that it is easier to expand the definition fully later.  */
22262306a36Sopenharmony_ci	| STRUCT_KEYW IDENT
22362306a36Sopenharmony_ci		{ remove_node($1); (*$2)->tag = SYM_STRUCT; $$ = $2; }
22462306a36Sopenharmony_ci	| UNION_KEYW IDENT
22562306a36Sopenharmony_ci		{ remove_node($1); (*$2)->tag = SYM_UNION; $$ = $2; }
22662306a36Sopenharmony_ci	| ENUM_KEYW IDENT
22762306a36Sopenharmony_ci		{ remove_node($1); (*$2)->tag = SYM_ENUM; $$ = $2; }
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	/* Full definitions of an s/u/e.  Record it.  */
23062306a36Sopenharmony_ci	| STRUCT_KEYW IDENT class_body
23162306a36Sopenharmony_ci		{ record_compound($1, $2, $3, SYM_STRUCT); $$ = $3; }
23262306a36Sopenharmony_ci	| UNION_KEYW IDENT class_body
23362306a36Sopenharmony_ci		{ record_compound($1, $2, $3, SYM_UNION); $$ = $3; }
23462306a36Sopenharmony_ci	| ENUM_KEYW IDENT enum_body
23562306a36Sopenharmony_ci		{ record_compound($1, $2, $3, SYM_ENUM); $$ = $3; }
23662306a36Sopenharmony_ci	/*
23762306a36Sopenharmony_ci	 * Anonymous enum definition. Tell add_symbol() to restart its counter.
23862306a36Sopenharmony_ci	 */
23962306a36Sopenharmony_ci	| ENUM_KEYW enum_body
24062306a36Sopenharmony_ci		{ add_symbol(NULL, SYM_ENUM, NULL, 0); $$ = $2; }
24162306a36Sopenharmony_ci	/* Anonymous s/u definitions.  Nothing needs doing.  */
24262306a36Sopenharmony_ci	| STRUCT_KEYW class_body			{ $$ = $2; }
24362306a36Sopenharmony_ci	| UNION_KEYW class_body				{ $$ = $2; }
24462306a36Sopenharmony_ci	;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cisimple_type_specifier:
24762306a36Sopenharmony_ci	CHAR_KEYW
24862306a36Sopenharmony_ci	| SHORT_KEYW
24962306a36Sopenharmony_ci	| INT_KEYW
25062306a36Sopenharmony_ci	| LONG_KEYW
25162306a36Sopenharmony_ci	| SIGNED_KEYW
25262306a36Sopenharmony_ci	| UNSIGNED_KEYW
25362306a36Sopenharmony_ci	| FLOAT_KEYW
25462306a36Sopenharmony_ci	| DOUBLE_KEYW
25562306a36Sopenharmony_ci	| VOID_KEYW
25662306a36Sopenharmony_ci	| BOOL_KEYW
25762306a36Sopenharmony_ci	| VA_LIST_KEYW
25862306a36Sopenharmony_ci	| BUILTIN_INT_KEYW
25962306a36Sopenharmony_ci	| TYPE			{ (*$1)->tag = SYM_TYPEDEF; $$ = $1; }
26062306a36Sopenharmony_ci	;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ciptr_operator:
26362306a36Sopenharmony_ci	'*' cvar_qualifier_seq_opt
26462306a36Sopenharmony_ci		{ $$ = $2 ? $2 : $1; }
26562306a36Sopenharmony_ci	;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cicvar_qualifier_seq_opt:
26862306a36Sopenharmony_ci	/* empty */					{ $$ = NULL; }
26962306a36Sopenharmony_ci	| cvar_qualifier_seq
27062306a36Sopenharmony_ci	;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cicvar_qualifier_seq:
27362306a36Sopenharmony_ci	cvar_qualifier
27462306a36Sopenharmony_ci	| cvar_qualifier_seq cvar_qualifier		{ $$ = $2; }
27562306a36Sopenharmony_ci	;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cicvar_qualifier:
27862306a36Sopenharmony_ci	CONST_KEYW | VOLATILE_KEYW | ATTRIBUTE_PHRASE
27962306a36Sopenharmony_ci	| RESTRICT_KEYW
28062306a36Sopenharmony_ci		{ /* restrict has no effect in prototypes so ignore it */
28162306a36Sopenharmony_ci		  remove_node($1);
28262306a36Sopenharmony_ci		  $$ = $1;
28362306a36Sopenharmony_ci		}
28462306a36Sopenharmony_ci	;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cideclarator:
28762306a36Sopenharmony_ci	ptr_operator declarator			{ $$ = $2; }
28862306a36Sopenharmony_ci	| direct_declarator
28962306a36Sopenharmony_ci	;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cidirect_declarator:
29262306a36Sopenharmony_ci	IDENT
29362306a36Sopenharmony_ci		{ if (current_name != NULL) {
29462306a36Sopenharmony_ci		    error_with_pos("unexpected second declaration name");
29562306a36Sopenharmony_ci		    YYERROR;
29662306a36Sopenharmony_ci		  } else {
29762306a36Sopenharmony_ci		    current_name = (*$1)->string;
29862306a36Sopenharmony_ci		    $$ = $1;
29962306a36Sopenharmony_ci		  }
30062306a36Sopenharmony_ci		}
30162306a36Sopenharmony_ci	| TYPE
30262306a36Sopenharmony_ci		{ if (current_name != NULL) {
30362306a36Sopenharmony_ci		    error_with_pos("unexpected second declaration name");
30462306a36Sopenharmony_ci		    YYERROR;
30562306a36Sopenharmony_ci		  } else {
30662306a36Sopenharmony_ci		    current_name = (*$1)->string;
30762306a36Sopenharmony_ci		    $$ = $1;
30862306a36Sopenharmony_ci		  }
30962306a36Sopenharmony_ci		}
31062306a36Sopenharmony_ci	| direct_declarator '(' parameter_declaration_clause ')'
31162306a36Sopenharmony_ci		{ $$ = $4; }
31262306a36Sopenharmony_ci	| direct_declarator '(' error ')'
31362306a36Sopenharmony_ci		{ $$ = $4; }
31462306a36Sopenharmony_ci	| direct_declarator BRACKET_PHRASE
31562306a36Sopenharmony_ci		{ $$ = $2; }
31662306a36Sopenharmony_ci	| '(' declarator ')'
31762306a36Sopenharmony_ci		{ $$ = $3; }
31862306a36Sopenharmony_ci	;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci/* Nested declarators differ from regular declarators in that they do
32162306a36Sopenharmony_ci   not record the symbols they find in the global symbol table.  */
32262306a36Sopenharmony_cinested_declarator:
32362306a36Sopenharmony_ci	ptr_operator nested_declarator		{ $$ = $2; }
32462306a36Sopenharmony_ci	| direct_nested_declarator
32562306a36Sopenharmony_ci	;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cidirect_nested_declarator:
32862306a36Sopenharmony_ci	IDENT
32962306a36Sopenharmony_ci	| TYPE
33062306a36Sopenharmony_ci	| direct_nested_declarator '(' parameter_declaration_clause ')'
33162306a36Sopenharmony_ci		{ $$ = $4; }
33262306a36Sopenharmony_ci	| direct_nested_declarator '(' error ')'
33362306a36Sopenharmony_ci		{ $$ = $4; }
33462306a36Sopenharmony_ci	| direct_nested_declarator BRACKET_PHRASE
33562306a36Sopenharmony_ci		{ $$ = $2; }
33662306a36Sopenharmony_ci	| '(' nested_declarator ')'
33762306a36Sopenharmony_ci		{ $$ = $3; }
33862306a36Sopenharmony_ci	| '(' error ')'
33962306a36Sopenharmony_ci		{ $$ = $3; }
34062306a36Sopenharmony_ci	;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ciparameter_declaration_clause:
34362306a36Sopenharmony_ci	parameter_declaration_list_opt DOTS		{ $$ = $2; }
34462306a36Sopenharmony_ci	| parameter_declaration_list_opt
34562306a36Sopenharmony_ci	| parameter_declaration_list ',' DOTS		{ $$ = $3; }
34662306a36Sopenharmony_ci	;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ciparameter_declaration_list_opt:
34962306a36Sopenharmony_ci	/* empty */					{ $$ = NULL; }
35062306a36Sopenharmony_ci	| parameter_declaration_list
35162306a36Sopenharmony_ci	;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ciparameter_declaration_list:
35462306a36Sopenharmony_ci	parameter_declaration
35562306a36Sopenharmony_ci	| parameter_declaration_list ',' parameter_declaration
35662306a36Sopenharmony_ci		{ $$ = $3; }
35762306a36Sopenharmony_ci	;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ciparameter_declaration:
36062306a36Sopenharmony_ci	decl_specifier_seq m_abstract_declarator
36162306a36Sopenharmony_ci		{ $$ = $2 ? $2 : $1; }
36262306a36Sopenharmony_ci	;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cim_abstract_declarator:
36562306a36Sopenharmony_ci	ptr_operator m_abstract_declarator
36662306a36Sopenharmony_ci		{ $$ = $2 ? $2 : $1; }
36762306a36Sopenharmony_ci	| direct_m_abstract_declarator
36862306a36Sopenharmony_ci	;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_cidirect_m_abstract_declarator:
37162306a36Sopenharmony_ci	/* empty */					{ $$ = NULL; }
37262306a36Sopenharmony_ci	| IDENT
37362306a36Sopenharmony_ci		{ /* For version 2 checksums, we don't want to remember
37462306a36Sopenharmony_ci		     private parameter names.  */
37562306a36Sopenharmony_ci		  remove_node($1);
37662306a36Sopenharmony_ci		  $$ = $1;
37762306a36Sopenharmony_ci		}
37862306a36Sopenharmony_ci	/* This wasn't really a typedef name but an identifier that
37962306a36Sopenharmony_ci	   shadows one.  */
38062306a36Sopenharmony_ci	| TYPE
38162306a36Sopenharmony_ci		{ remove_node($1);
38262306a36Sopenharmony_ci		  $$ = $1;
38362306a36Sopenharmony_ci		}
38462306a36Sopenharmony_ci	| direct_m_abstract_declarator '(' parameter_declaration_clause ')'
38562306a36Sopenharmony_ci		{ $$ = $4; }
38662306a36Sopenharmony_ci	| direct_m_abstract_declarator '(' error ')'
38762306a36Sopenharmony_ci		{ $$ = $4; }
38862306a36Sopenharmony_ci	| direct_m_abstract_declarator BRACKET_PHRASE
38962306a36Sopenharmony_ci		{ $$ = $2; }
39062306a36Sopenharmony_ci	| '(' m_abstract_declarator ')'
39162306a36Sopenharmony_ci		{ $$ = $3; }
39262306a36Sopenharmony_ci	| '(' error ')'
39362306a36Sopenharmony_ci		{ $$ = $3; }
39462306a36Sopenharmony_ci	;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cifunction_definition:
39762306a36Sopenharmony_ci	decl_specifier_seq_opt declarator BRACE_PHRASE
39862306a36Sopenharmony_ci		{ struct string_list *decl = *$2;
39962306a36Sopenharmony_ci		  *$2 = NULL;
40062306a36Sopenharmony_ci		  add_symbol(current_name, SYM_NORMAL, decl, is_extern);
40162306a36Sopenharmony_ci		  $$ = $3;
40262306a36Sopenharmony_ci		}
40362306a36Sopenharmony_ci	;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ciinitializer_opt:
40662306a36Sopenharmony_ci	/* empty */					{ $$ = NULL; }
40762306a36Sopenharmony_ci	| initializer
40862306a36Sopenharmony_ci	;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci/* We never care about the contents of an initializer.  */
41162306a36Sopenharmony_ciinitializer:
41262306a36Sopenharmony_ci	'=' EXPRESSION_PHRASE
41362306a36Sopenharmony_ci		{ remove_list($2, &(*$1)->next); $$ = $2; }
41462306a36Sopenharmony_ci	;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ciclass_body:
41762306a36Sopenharmony_ci	'{' member_specification_opt '}'		{ $$ = $3; }
41862306a36Sopenharmony_ci	| '{' error '}'					{ $$ = $3; }
41962306a36Sopenharmony_ci	;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_cimember_specification_opt:
42262306a36Sopenharmony_ci	/* empty */					{ $$ = NULL; }
42362306a36Sopenharmony_ci	| member_specification
42462306a36Sopenharmony_ci	;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cimember_specification:
42762306a36Sopenharmony_ci	member_declaration
42862306a36Sopenharmony_ci	| member_specification member_declaration	{ $$ = $2; }
42962306a36Sopenharmony_ci	;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cimember_declaration:
43262306a36Sopenharmony_ci	decl_specifier_seq_opt member_declarator_list_opt ';'
43362306a36Sopenharmony_ci		{ $$ = $3; }
43462306a36Sopenharmony_ci	| error ';'
43562306a36Sopenharmony_ci		{ $$ = $2; }
43662306a36Sopenharmony_ci	;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cimember_declarator_list_opt:
43962306a36Sopenharmony_ci	/* empty */					{ $$ = NULL; }
44062306a36Sopenharmony_ci	| member_declarator_list
44162306a36Sopenharmony_ci	;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cimember_declarator_list:
44462306a36Sopenharmony_ci	member_declarator
44562306a36Sopenharmony_ci	| member_declarator_list ',' member_declarator	{ $$ = $3; }
44662306a36Sopenharmony_ci	;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cimember_declarator:
44962306a36Sopenharmony_ci	nested_declarator attribute_opt			{ $$ = $2 ? $2 : $1; }
45062306a36Sopenharmony_ci	| IDENT member_bitfield_declarator		{ $$ = $2; }
45162306a36Sopenharmony_ci	| member_bitfield_declarator
45262306a36Sopenharmony_ci	;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_cimember_bitfield_declarator:
45562306a36Sopenharmony_ci	':' EXPRESSION_PHRASE				{ $$ = $2; }
45662306a36Sopenharmony_ci	;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ciattribute_opt:
45962306a36Sopenharmony_ci	/* empty */					{ $$ = NULL; }
46062306a36Sopenharmony_ci	| attribute_opt ATTRIBUTE_PHRASE
46162306a36Sopenharmony_ci	;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_cienum_body:
46462306a36Sopenharmony_ci	'{' enumerator_list '}'				{ $$ = $3; }
46562306a36Sopenharmony_ci	| '{' enumerator_list ',' '}'			{ $$ = $4; }
46662306a36Sopenharmony_ci	 ;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cienumerator_list:
46962306a36Sopenharmony_ci	enumerator
47062306a36Sopenharmony_ci	| enumerator_list ',' enumerator
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_cienumerator:
47362306a36Sopenharmony_ci	IDENT
47462306a36Sopenharmony_ci		{
47562306a36Sopenharmony_ci			const char *name = strdup((*$1)->string);
47662306a36Sopenharmony_ci			add_symbol(name, SYM_ENUM_CONST, NULL, 0);
47762306a36Sopenharmony_ci		}
47862306a36Sopenharmony_ci	| IDENT '=' EXPRESSION_PHRASE
47962306a36Sopenharmony_ci		{
48062306a36Sopenharmony_ci			const char *name = strdup((*$1)->string);
48162306a36Sopenharmony_ci			struct string_list *expr = copy_list_range(*$3, *$2);
48262306a36Sopenharmony_ci			add_symbol(name, SYM_ENUM_CONST, expr, 0);
48362306a36Sopenharmony_ci		}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ciasm_definition:
48662306a36Sopenharmony_ci	ASM_PHRASE ';'					{ $$ = $2; }
48762306a36Sopenharmony_ci	;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ciasm_phrase_opt:
49062306a36Sopenharmony_ci	/* empty */					{ $$ = NULL; }
49162306a36Sopenharmony_ci	| ASM_PHRASE
49262306a36Sopenharmony_ci	;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ciexport_definition:
49562306a36Sopenharmony_ci	EXPORT_SYMBOL_KEYW '(' IDENT ')' ';'
49662306a36Sopenharmony_ci		{ export_symbol((*$3)->string); $$ = $5; }
49762306a36Sopenharmony_ci	;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci/* Ignore any module scoped _Static_assert(...) */
50062306a36Sopenharmony_cistatic_assert:
50162306a36Sopenharmony_ci	STATIC_ASSERT_PHRASE ';'			{ $$ = $2; }
50262306a36Sopenharmony_ci	;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci%%
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_cistatic void
50762306a36Sopenharmony_ciyyerror(const char *e)
50862306a36Sopenharmony_ci{
50962306a36Sopenharmony_ci  error_with_pos("%s", e);
51062306a36Sopenharmony_ci}
511