ttyS0 tty1
     	ˆÁÀ„ ?ÃÂ *”    	/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * C global declaration parser for genksyms.
 * Copyright 1996, 1997 Linux International.
 *
 * New implementation contributed by Richard Henderson <rth@tamu.edu>
 * Based on original work by Bjorn Ekwall <bj0rn@blox.se>
 *
 * This file is part of the Linux modutils.
 */

%{

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "genksyms.h"

static int is_typedef;
static int is_extern;
static char *current_name;
static struct string_list *decl_spec;

static void yyerror(const char *);

static inline void
remove_node(struct string_list **p)
{
  struct string_list *node = *p;
  *p = node->next;
  free_node(node);
}

static inline void
remove_list(struct string_list **pb, struct string_list **pe)
{
  struct string_list *b = *pb, *e = *pe;
  *pb = e;
  free_list(b, e);
}

/* Record definition of a struct/union/enum */
static void record_compound(struct string_list **keyw,
		       struct string_list **ident,
		       struct string_list **body,
		       enum symbol_type type)
{
	struct string_list *b = *body, *i = *ident, *r;

	if (i->in_source_file) {
		remove_node(keyw);
		(*ident)->tag = type;
		remove_list(body, ident);
		return;
	}
	r = copy_node(i); r->tag = type;
	r->next = (*keyw)->next; *body = r; (*keyw)->next = NULL;
	add_symbol(i->string, type, b, is_extern);
}

%}

%token ASM_KEYW
%token ATTRIBUTE_KEYW
%token AUTO_KEYW
%token BOOL_KEYW
%token BUILTIN_INT_KEYW
%token CHAR_KEYW
%token CONST_KEYW
%token DOUBLE_KEYW
%token ENUM_KEYW
%token EXTERN_KEYW
%token EXTENSION_KEYW
%token FLOAT_KEYW
%token INLINE_KEYW
%token INT_KEYW
%token LONG_KEYW
%token REGISTER_KEYW
%token RESTRICT_KEYW
%token SHORT_KEYW
%token SIGNED_KEYW
%token STATIC_KEYW
%token STATIC_ASSERT_KEYW
%token STRUCT_KEYW
%token TYPEDEF_KEYW
%token UNION_KEYW
%token UNSIGNED_KEYW
%token VOID_KEYW
%token VOLATILE_KEYW
%token TYPEOF_KEYW
%token VA_LIST_KEYW

%token EXPORT_SYMBOL_KEYW

%token ASM_PHRASE
%token ATTRIBUTE_PHRASE
%token TYPEOF_PHRASE
%token BRACE_PHRASE
%token BRACKET_PHRASE
%token EXPRESSION_PHRASE
%token STATIC_ASSERT_PHRASE

%token CHAR
%token DOTS
%token IDENT
%token INT
%token REAL
%token STRING
%token TYPE
%token OTHER
%token FILENAME

%%

declaration_seq:
	declaration
	| declaration_seq declaration
	;

declaration:
	{ is_typedef = 0; is_extern = 0; current_name = NULL; decl_spec = NULL; }
	declaration1
	{ free_list(*$2, NULL); *$2 = NULL; }
	;

declaration1:
	EXTENSION_KEYW TYPEDEF_KEYW { is_typedef = 1; } simple_declaration
		{ $$ = $4; }
	| TYPEDEF_KEYW { is_typedef = 1; } simple_declaration
		{ $$ = $3; }
	| simple_declaration
	| function_definition
	| asm_definition
	| export_definition
	| static_assert
	| error ';'				{ $$ = $2; }
	| error '}'				{ $$ = $2; }
	;

simple_declaration:
	decl_specifier_seq_opt init_declarator_list_opt ';'
		{ if (current_name) {
		    struct string_list *decl = (*$3)->next;
		    (*$3)->next = NULL;
		    add_symbol(current_name,
			       is_typedef ? SYM_TYPEDEF : SYM_NORMAL,
			       decl, is_extern);
		    current_name = NULL;
		  }
		  $$ = $3;
		}
	;

init_declarator_list_opt:
	/* empty */				{ $$ = NULL; }
	| init_declarator_list
	;

init_declarator_list:
	init_declarator
		{ struct string_list *decl = *$1;
		  *$1 = NULL;
		  add_symbol(current_name,
			     is_typedef ? SYM_TYPEDEF : SYM_NORMAL, decl, is_extern);
		  current_name = NULL;
		  $$ = $1;
		}
	| init_declarator_list ',' init_declarator
		{ struct string_list *decl = *$3;
		  *$3 = NULL;
		  free_list(*$2, NULL);
		  *$2 = decl_spec;
		  add_symbol(current_name,
			     is_typedef ? SYM_TYPEDEF : SYM_NORMAL, decl, is_extern);
		  current_name = NULL;
		  $$ = $3;
		}
	;

init_declarator:
	declarator asm_phrase_opt attribute_opt initializer_opt
		{ $$ = $4 ? $4 : $3 ? $3 : $2 ? $2 : $1; }
	;

/* Hang on to the specifiers so that we can reuse them.  */
decl_specifier_seq_opt:
	/* empty */				{ decl_spec = NULL; }
	| decl_specifier_seq
	;

decl_specifier_seq:
	decl_specifier				{ decl_spec = *$1; }
	| decl_specifier_seq decl_specif