linux/scripts/genksyms/parse.y
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0-or-later */
   2/*
   3 * C global declaration parser for genksyms.
   4 * Copyright 1996, 1997 Linux International.
   5 *
   6 * New implementation contributed by Richard Henderson <rth@tamu.edu>
   7 * Based on original work by Bjorn Ekwall <bj0rn@blox.se>
   8 *
   9 * This file is part of the Linux modutils.
  10 */
  11
  12%{
  13
  14#include <assert.h>
  15#include <stdlib.h>
  16#include <string.h>
  17#include "genksyms.h"
  18
  19static int is_typedef;
  20static int is_extern;
  21static char *current_name;
  22static struct string_list *decl_spec;
  23
  24static void yyerror(const char *);
  25
  26static inline void
  27remove_node(struct string_list **p)
  28{
  29  struct string_list *node = *p;
  30  *p = node->next;
  31  free_node(node);
  32}
  33
  34static inline void
  35remove_list(struct string_list **pb, struct string_list **pe)
  36{
  37  struct string_list *b = *pb, *e = *pe;
  38  *pb = e;
  39  free_list(b, e);
  40}
  41
  42/* Record definition of a struct/union/enum */
  43static void record_compound(struct string_list **keyw,
  44                       struct string_list **ident,
  45                       struct string_list **body,
  46                       enum symbol_type type)
  47{
  48        struct string_list *b = *body, *i = *ident, *r;
  49
  50        if (i->in_source_file) {
  51                remove_node(keyw);
  52                (*ident)->tag = type;
  53                remove_list(body, ident);
  54                return;
  55        }
  56        r = copy_node(i); r->tag = type;
  57        r->next = (*keyw)->next; *body = r; (*keyw)->next = NULL;
  58        add_symbol(i->string, type, b, is_extern);
  59}
  60
  61%}
  62
  63%token ASM_KEYW
  64%token ATTRIBUTE_KEYW
  65%token AUTO_KEYW
  66%token BOOL_KEYW
  67%token BUILTIN_INT_KEYW
  68%token CHAR_KEYW
  69%token CONST_KEYW
  70%token DOUBLE_KEYW
  71%token ENUM_KEYW
  72%token EXTERN_KEYW
  73%token EXTENSION_KEYW
  74%token FLOAT_KEYW
  75%token INLINE_KEYW
  76%token INT_KEYW
  77%token LONG_KEYW
  78%token REGISTER_KEYW
  79%token RESTRICT_KEYW
  80%token SHORT_KEYW
  81%token SIGNED_KEYW
  82%token STATIC_KEYW
  83%token STATIC_ASSERT_KEYW
  84%token STRUCT_KEYW
  85%token TYPEDEF_KEYW
  86%token UNION_KEYW
  87%token UNSIGNED_KEYW
  88%token VOID_KEYW
  89%token VOLATILE_KEYW
  90%token TYPEOF_KEYW
  91%token VA_LIST_KEYW
  92
  93%token EXPORT_SYMBOL_KEYW
  94
  95%token ASM_PHRASE
  96%token ATTRIBUTE_PHRASE
  97%token TYPEOF_PHRASE
  98%token BRACE_PHRASE
  99%token BRACKET_PHRASE
 100%token EXPRESSION_PHRASE
 101%token STATIC_ASSERT_PHRASE
 102
 103%token CHAR
 104%token DOTS
 105%token IDENT
 106%token INT
 107%token REAL
 108%token STRING
 109%token TYPE
 110%token OTHER
 111%token FILENAME
 112
 113%%
 114
 115declaration_seq:
 116        declaration
 117        | declaration_seq declaration
 118        ;
 119
 120declaration:
 121        { is_typedef = 0; is_extern = 0; current_name = NULL; decl_spec = NULL; }
 122        declaration1
 123        { free_list(*$2, NULL); *$2 = NULL; }
 124        ;
 125
 126declaration1:
 127        EXTENSION_KEYW TYPEDEF_KEYW { is_typedef = 1; } simple_declaration
 128                { $$ = $4; }
 129        | TYPEDEF_KEYW { is_typedef = 1; } simple_declaration
 130                { $$ = $3; }
 131        | simple_declaration
 132        | function_definition
 133        | asm_definition
 134        | export_definition
 135        | static_assert
 136        | error ';'                             { $$ = $2; }
 137        | error '}'                             { $$ = $2; }
 138        ;
 139
 140simple_declaration:
 141        decl_specifier_seq_opt init_declarator_list_opt ';'
 142                { if (current_name) {
 143                    struct string_list *decl = (*$3)->next;
 144                    (*$3)->next = NULL;
 145                    add_symbol(current_name,
 146                               is_typedef ? SYM_TYPEDEF : SYM_NORMAL,
 147                               decl, is_extern);
 148                    current_name = NULL;
 149                  }
 150                  $$ = $3;
 151                }
 152        ;
 153
 154init_declarator_list_opt:
 155        /* empty */                             { $$ = NULL; }
 156        | init_declarator_list
 157        ;
 158
 159init_declarator_list:
 160        init_declarator
 161                { struct string_list *decl = *$1;
 162                  *$1 = NULL;
 163                  add_symbol(current_name,
 164                             is_typedef ? SYM_TYPEDEF : SYM_NORMAL, decl, is_extern);
 165                  current_name = NULL;
 166                  $$ = $1;
 167                }
 168        | init_declarator_list ',' init_declarator
 169                { struct string_list *decl = *$3;
 170                  *$3 = NULL;
 171                  free_list(*$2, NULL);
 172                  *$2 = decl_spec;
 173                  add_symbol(current_name,
 174                             is_typedef ? SYM_TYPEDEF : SYM_NORMAL, decl, is_extern);
 175                  current_name = NULL;
 176                  $$ = $3;
 177                }
 178        ;
 179
 180init_declarator:
 181        declarator asm_phrase_opt attribute_opt initializer_opt
 182                { $$ = $4 ? $4 : $3 ? $3 : $2 ? $2 : $1; }
 183        ;
 184
 185/* Hang on to the specifiers so that we can reuse them.  */
 186decl_specifier_seq_opt:
 187        /* empty */                             { decl_spec = NULL; }
 188        | decl_specifier_seq
 189        ;
 190
 191decl_specifier_seq:
 192        decl_specifier                          { decl_spec = *$1; }
 193        | decl_specifier_seq decl_specifier     { decl_spec = *$2; }
 194        ;
 195
 196decl_specifier:
 197        storage_class_specifier
 198                { /* Version 2 checksumming ignores storage class, as that
 199                     is really irrelevant to the linkage.  */
 200                  remove_node($1);
 201                  $$ = $1;
 202                }
 203        | type_specifier
 204        ;
 205
 206storage_class_specifier:
 207        AUTO_KEYW
 208        | REGISTER_KEYW
 209        | STATIC_KEYW
 210        | EXTERN_KEYW   { is_extern = 1; $$ = $1; }
 211        | INLINE_KEYW   { is_extern = 0; $$ = $1; }
 212        ;
 213
 214type_specifier:
 215        simple_type_specifier
 216        | cvar_qualifier
 217        | TYPEOF_KEYW '(' parameter_declaration ')'
 218        | TYPEOF_PHRASE
 219
 220        /* References to s/u/e's defined elsewhere.  Rearrange things
 221           so that it is easier to expand the definition fully later.  */
 222        | STRUCT_KEYW IDENT
 223                { remove_node($1); (*$2)->tag = SYM_STRUCT; $$ = $2; }
 224        | UNION_KEYW IDENT
 225                { remove_node($1); (*$2)->tag = SYM_UNION; $$ = $2; }
 226        | ENUM_KEYW IDENT
 227                { remove_node($1); (*$2)->tag = SYM_ENUM; $$ = $2; }
 228
 229        /* Full definitions of an s/u/e.  Record it.  */
 230        | STRUCT_KEYW IDENT class_body
 231                { record_compound($1, $2, $3, SYM_STRUCT); $$ = $3; }
 232        | UNION_KEYW IDENT class_body
 233                { record_compound($1, $2, $3, SYM_UNION); $$ = $3; }
 234        | ENUM_KEYW IDENT enum_body
 235                { record_compound($1, $2, $3, SYM_ENUM); $$ = $3; }
 236        /*
 237         * Anonymous enum definition. Tell add_symbol() to restart its counter.
 238         */
 239        | ENUM_KEYW enum_body
 240                { add_symbol(NULL, SYM_ENUM, NULL, 0); $$ = $2; }
 241        /* Anonymous s/u definitions.  Nothing needs doing.  */
 242        | STRUCT_KEYW class_body                        { $$ = $2; }
 243        | UNION_KEYW class_body                         { $$ = $2; }
 244        ;
 245
 246simple_type_specifier:
 247        CHAR_KEYW
 248        | SHORT_KEYW
 249        | INT_KEYW
 250        | LONG_KEYW
 251        | SIGNED_KEYW
 252        | UNSIGNED_KEYW
 253        | FLOAT_KEYW
 254        | DOUBLE_KEYW
 255        | VOID_KEYW
 256        | BOOL_KEYW
 257        | VA_LIST_KEYW
 258        | BUILTIN_INT_KEYW
 259        | TYPE                  { (*$1)->tag = SYM_TYPEDEF; $$ = $1; }
 260        ;
 261
 262ptr_operator:
 263        '*' cvar_qualifier_seq_opt
 264                { $$ = $2 ? $2 : $1; }
 265        ;
 266
 267cvar_qualifier_seq_opt:
 268        /* empty */                                     { $$ = NULL; }
 269        | cvar_qualifier_seq
 270        ;
 271
 272cvar_qualifier_seq:
 273        cvar_qualifier
 274        | cvar_qualifier_seq cvar_qualifier             { $$ = $2; }
 275        ;
 276
 277cvar_qualifier:
 278        CONST_KEYW | VOLATILE_KEYW | ATTRIBUTE_PHRASE
 279        | RESTRICT_KEYW
 280                { /* restrict has no effect in prototypes so ignore it */
 281                  remove_node($1);
 282                  $$ = $1;
 283                }
 284        ;
 285
 286declarator:
 287        ptr_operator declarator                 { $$ = $2; }
 288        | direct_declarator
 289        ;
 290
 291direct_declarator:
 292        IDENT
 293                { if (current_name != NULL) {
 294                    error_with_pos("unexpected second declaration name");
 295                    YYERROR;
 296                  } else {
 297                    current_name = (*$1)->string;
 298                    $$ = $1;
 299                  }
 300                }
 301        | TYPE
 302                { if (current_name != NULL) {
 303                    error_with_pos("unexpected second declaration name");
 304                    YYERROR;
 305                  } else {
 306                    current_name = (*$1)->string;
 307                    $$ = $1;
 308                  }
 309                }
 310        | direct_declarator '(' parameter_declaration_clause ')'
 311                { $$ = $4; }
 312        | direct_declarator '(' error ')'
 313                { $$ = $4; }
 314        | direct_declarator BRACKET_PHRASE
 315                { $$ = $2; }
 316        | '(' declarator ')'
 317                { $$ = $3; }
 318        ;
 319
 320/* Nested declarators differ from regular declarators in that they do
 321   not record the symbols they find in the global symbol table.  */
 322nested_declarator:
 323        ptr_operator nested_declarator          { $$ = $2; }
 324        | direct_nested_declarator
 325        ;
 326
 327direct_nested_declarator:
 328        IDENT
 329        | TYPE
 330        | direct_nested_declarator '(' parameter_declaration_clause ')'
 331                { $$ = $4; }
 332        | direct_nested_declarator '(' error ')'
 333                { $$ = $4; }
 334        | direct_nested_declarator BRACKET_PHRASE
 335                { $$ = $2; }
 336        | '(' nested_declarator ')'
 337                { $$ = $3; }
 338        | '(' error ')'
 339                { $$ = $3; }
 340        ;
 341
 342parameter_declaration_clause:
 343        parameter_declaration_list_opt DOTS             { $$ = $2; }
 344        | parameter_declaration_list_opt
 345        | parameter_declaration_list ',' DOTS           { $$ = $3; }
 346        ;
 347
 348parameter_declaration_list_opt:
 349        /* empty */                                     { $$ = NULL; }
 350        | parameter_declaration_list
 351        ;
 352
 353parameter_declaration_list:
 354        parameter_declaration
 355        | parameter_declaration_list ',' parameter_declaration
 356                { $$ = $3; }
 357        ;
 358
 359parameter_declaration:
 360        decl_specifier_seq m_abstract_declarator
 361                { $$ = $2 ? $2 : $1; }
 362        ;
 363
 364m_abstract_declarator:
 365        ptr_operator m_abstract_declarator
 366                { $$ = $2 ? $2 : $1; }
 367        | direct_m_abstract_declarator
 368        ;
 369
 370direct_m_abstract_declarator:
 371        /* empty */                                     { $$ = NULL; }
 372        | IDENT
 373                { /* For version 2 checksums, we don't want to remember
 374                     private parameter names.  */
 375                  remove_node($1);
 376                  $$ = $1;
 377                }
 378        /* This wasn't really a typedef name but an identifier that
 379           shadows one.  */
 380        | TYPE
 381                { remove_node($1);
 382                  $$ = $1;
 383                }
 384        | direct_m_abstract_declarator '(' parameter_declaration_clause ')'
 385                { $$ = $4; }
 386        | direct_m_abstract_declarator '(' error ')'
 387                { $$ = $4; }
 388        | direct_m_abstract_declarator BRACKET_PHRASE
 389                { $$ = $2; }
 390        | '(' m_abstract_declarator ')'
 391                { $$ = $3; }
 392        | '(' error ')'
 393                { $$ = $3; }
 394        ;
 395
 396function_definition:
 397        decl_specifier_seq_opt declarator BRACE_PHRASE
 398                { struct string_list *decl = *$2;
 399                  *$2 = NULL;
 400                  add_symbol(current_name, SYM_NORMAL, decl, is_extern);
 401                  $$ = $3;
 402                }
 403        ;
 404
 405initializer_opt:
 406        /* empty */                                     { $$ = NULL; }
 407        | initializer
 408        ;
 409
 410/* We never care about the contents of an initializer.  */
 411initializer:
 412        '=' EXPRESSION_PHRASE
 413                { remove_list($2, &(*$1)->next); $$ = $2; }
 414        ;
 415
 416class_body:
 417        '{' member_specification_opt '}'                { $$ = $3; }
 418        | '{' error '}'                                 { $$ = $3; }
 419        ;
 420
 421member_specification_opt:
 422        /* empty */                                     { $$ = NULL; }
 423        | member_specification
 424        ;
 425
 426member_specification:
 427        member_declaration
 428        | member_specification member_declaration       { $$ = $2; }
 429        ;
 430
 431member_declaration:
 432        decl_specifier_seq_opt member_declarator_list_opt ';'
 433                { $$ = $3; }
 434        | error ';'
 435                { $$ = $2; }
 436        ;
 437
 438member_declarator_list_opt:
 439        /* empty */                                     { $$ = NULL; }
 440        | member_declarator_list
 441        ;
 442
 443member_declarator_list:
 444        member_declarator
 445        | member_declarator_list ',' member_declarator  { $$ = $3; }
 446        ;
 447
 448member_declarator:
 449        nested_declarator attribute_opt                 { $$ = $2 ? $2 : $1; }
 450        | IDENT member_bitfield_declarator              { $$ = $2; }
 451        | member_bitfield_declarator
 452        ;
 453
 454member_bitfield_declarator:
 455        ':' EXPRESSION_PHRASE                           { $$ = $2; }
 456        ;
 457
 458attribute_opt:
 459        /* empty */                                     { $$ = NULL; }
 460        | attribute_opt ATTRIBUTE_PHRASE
 461        ;
 462
 463enum_body:
 464        '{' enumerator_list '}'                         { $$ = $3; }
 465        | '{' enumerator_list ',' '}'                   { $$ = $4; }
 466         ;
 467
 468enumerator_list:
 469        enumerator
 470        | enumerator_list ',' enumerator
 471
 472enumerator:
 473        IDENT
 474                {
 475                        const char *name = strdup((*$1)->string);
 476                        add_symbol(name, SYM_ENUM_CONST, NULL, 0);
 477                }
 478        | IDENT '=' EXPRESSION_PHRASE
 479                {
 480                        const char *name = strdup((*$1)->string);
 481                        struct string_list *expr = copy_list_range(*$3, *$2);
 482                        add_symbol(name, SYM_ENUM_CONST, expr, 0);
 483                }
 484
 485asm_definition:
 486        ASM_PHRASE ';'                                  { $$ = $2; }
 487        ;
 488
 489asm_phrase_opt:
 490        /* empty */                                     { $$ = NULL; }
 491        | ASM_PHRASE
 492        ;
 493
 494export_definition:
 495        EXPORT_SYMBOL_KEYW '(' IDENT ')' ';'
 496                { export_symbol((*$3)->string); $$ = $5; }
 497        ;
 498
 499/* Ignore any module scoped _Static_assert(...) */
 500static_assert:
 501        STATIC_ASSERT_PHRASE ';'                        { $$ = $2; }
 502        ;
 503
 504%%
 505
 506static void
 507yyerror(const char *e)
 508{
 509  error_with_pos("%s", e);
 510}
 511