[funini.com] -> [kei@sodan] -> Kernel Reading

root/scripts/genksyms/parse.y

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. remove_node
  2. remove_list
  3. yyerror

/* 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.

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2 of the License, or (at your
   option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software Foundation,
   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */


%{

#include <assert.h>
#include <malloc.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);
}

%}

%token ASM_KEYW
%token ATTRIBUTE_KEYW
%token AUTO_KEYW
%token BOOL_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 STRUCT_KEYW
%token TYPEDEF_KEYW
%token UNION_KEYW
%token UNSIGNED_KEYW
%token VOID_KEYW
%token VOLATILE_KEYW
%token TYPEOF_KEYW

%token EXPORT_SYMBOL_KEYW

%token ASM_PHRASE
%token ATTRIBUTE_PHRASE
%token BRACE_PHRASE
%token BRACKET_PHRASE
%token EXPRESSION_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
        | 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_specifier     { decl_spec = *$2; }
        ;

decl_specifier:
        storage_class_specifier
                { /* Version 2 checksumming ignores storage class, as that
                     is really irrelevant to the linkage.  */
                  remove_node($1);
                  $$ = $1;
                }
        | type_specifier
        ;

storage_class_specifier:
        AUTO_KEYW
        | REGISTER_KEYW
        | STATIC_KEYW
        | EXTERN_KEYW   { is_extern = 1; $$ = $1; }
        | INLINE_KEYW   { is_extern = 0; $$ = $1; }
        ;

type_specifier:
        simple_type_specifier
        | cvar_qualifier
        | TYPEOF_KEYW '(' decl_specifier_seq '*' ')'
        | TYPEOF_KEYW '(' decl_specifier_seq ')'

        /* References to s/u/e's defined elsewhere.  Rearrange things
           so that it is easier to expand the definition fully later.  */
        | STRUCT_KEYW IDENT
                { remove_node($1); (*$2)->tag = SYM_STRUCT; $$ = $2; }
        | UNION_KEYW IDENT
                { remove_node($1); (*$2)->tag = SYM_UNION; $$ = $2; }
        | ENUM_KEYW IDENT
                { remove_node($1); (*$2)->tag = SYM_ENUM; $$ = $2; }

        /* Full definitions of an s/u/e.  Record it.  */
        | STRUCT_KEYW IDENT class_body
                { struct string_list *s = *$3, *i = *$2, *r;
                  r = copy_node(i); r->tag = SYM_STRUCT;
                  r->next = (*$1)->next; *$3 = r; (*$1)->next = NULL;
                  add_symbol(i->string, SYM_STRUCT, s, is_extern);
                  $$ = $3;
                }
        | UNION_KEYW IDENT class_body
                { struct string_list *s = *$3, *i = *$2, *r;
                  r = copy_node(i); r->tag = SYM_UNION;
                  r->next = (*$1)->next; *$3 = r; (*$1)->next = NULL;
                  add_symbol(i->string, SYM_UNION, s, is_extern);
                  $$ = $3;
                }
        | ENUM_KEYW IDENT BRACE_PHRASE
                { struct string_list *s = *$3, *i = *$2, *r;
                  r = copy_node(i); r->tag = SYM_ENUM;
                  r->next = (*$1)->next; *$3 = r; (*$1)->next = NULL;
                  add_symbol(i->string, SYM_ENUM, s, is_extern);
                  $$ = $3;
                }

        /* Anonymous s/u/e definitions.  Nothing needs doing.  */
        | ENUM_KEYW BRACE_PHRASE                        { $$ = $2; }
        | STRUCT_KEYW class_body                        { $$ = $2; }
        | UNION_KEYW class_body                         { $$ = $2; }
        ;

simple_type_specifier:
        CHAR_KEYW
        | SHORT_KEYW
        | INT_KEYW
        | LONG_KEYW
        | SIGNED_KEYW
        | UNSIGNED_KEYW
        | FLOAT_KEYW
        | DOUBLE_KEYW
        | VOID_KEYW
        | BOOL_KEYW
        | TYPE                  { (*$1)->tag = SYM_TYPEDEF; $$ = $1; }
        ;

ptr_operator:
        '*' cvar_qualifier_seq_opt
                { $$ = $2 ? $2 : $1; }
        ;

cvar_qualifier_seq_opt:
        /* empty */                                     { $$ = NULL; }
        | cvar_qualifier_seq
        ;

cvar_qualifier_seq:
        cvar_qualifier
        | cvar_qualifier_seq cvar_qualifier             { $$ = $2; }
        ;

cvar_qualifier:
        CONST_KEYW | VOLATILE_KEYW | ATTRIBUTE_PHRASE
        | RESTRICT_KEYW
                { /* restrict has no effect in prototypes so ignore it */
                  remove_node($1);
                  $$ = $1;
                }
        ;

declarator:
        ptr_operator declarator                 { $$ = $2; }
        | direct_declarator
        ;

direct_declarator:
        IDENT
                { if (current_name != NULL) {
                    error_with_pos("unexpected second declaration name");
                    YYERROR;
                  } else {
                    current_name = (*$1)->string;
                    $$ = $1;
                  }
                }
        | direct_declarator '(' parameter_declaration_clause ')'
                { $$ = $4; }
        | direct_declarator '(' error ')'
                { $$ = $4; }
        | direct_declarator BRACKET_PHRASE
                { $$ = $2; }
        | '(' declarator ')'
                { $$ = $3; }
        | '(' error ')'
                { $$ = $3; }
        ;

/* Nested declarators differ from regular declarators in that they do
   not record the symbols they find in the global symbol table.  */
nested_declarator:
        ptr_operator nested_declarator          { $$ = $2; }
        | direct_nested_declarator
        ;

direct_nested_declarator:
        IDENT
        | TYPE
        | direct_nested_declarator '(' parameter_declaration_clause ')'
                { $$ = $4; }
        | direct_nested_declarator '(' error ')'
                { $$ = $4; }
        | direct_nested_declarator BRACKET_PHRASE
                { $$ = $2; }
        | '(' nested_declarator ')'
                { $$ = $3; }
        | '(' error ')'
                { $$ = $3; }
        ;

parameter_declaration_clause:
        parameter_declaration_list_opt DOTS             { $$ = $2; }
        | parameter_declaration_list_opt
        | parameter_declaration_list ',' DOTS           { $$ = $3; }
        ;

parameter_declaration_list_opt:
        /* empty */                                     { $$ = NULL; }
        | parameter_declaration_list
        ;

parameter_declaration_list:
        parameter_declaration
        | parameter_declaration_list ',' parameter_declaration
                { $$ = $3; }
        ;

parameter_declaration:
        decl_specifier_seq m_abstract_declarator
                { $$ = $2 ? $2 : $1; }
        ;

m_abstract_declarator:
        ptr_operator m_abstract_declarator
                { $$ = $2 ? $2 : $1; }
        | direct_m_abstract_declarator
        ;

direct_m_abstract_declarator:
        /* empty */                                     { $$ = NULL; }
        | IDENT
                { /* For version 2 checksums, we don't want to remember
                     private parameter names.  */
                  remove_node($1);
                  $$ = $1;
                }
        /* This wasn't really a typedef name but an identifier that
           shadows one.  */
        | TYPE
                { remove_node($1);
                  $$ = $1;
                }
        | direct_m_abstract_declarator '(' parameter_declaration_clause ')'
                { $$ = $4; }
        | direct_m_abstract_declarator '(' error ')'
                { $$ = $4; }
        | direct_m_abstract_declarator BRACKET_PHRASE
                { $$ = $2; }
        | '(' m_abstract_declarator ')'
                { $$ = $3; }
        | '(' error ')'
                { $$ = $3; }
        ;

function_definition:
        decl_specifier_seq_opt declarator BRACE_PHRASE
                { struct string_list *decl = *$2;
                  *$2 = NULL;
                  add_symbol(current_name, SYM_NORMAL, decl, is_extern);
                  $$ = $3;
                }
        ;

initializer_opt:
        /* empty */                                     { $$ = NULL; }
        | initializer
        ;

/* We never care about the contents of an initializer.  */
initializer:
        '=' EXPRESSION_PHRASE
                { remove_list($2, &(*$1)->next); $$ = $2; }
        ;

class_body:
        '{' member_specification_opt '}'                { $$ = $3; }
        | '{' error '}'                                 { $$ = $3; }
        ;

member_specification_opt:
        /* empty */                                     { $$ = NULL; }
        | member_specification
        ;

member_specification:
        member_declaration
        | member_specification member_declaration       { $$ = $2; }
        ;

member_declaration:
        decl_specifier_seq_opt member_declarator_list_opt ';'
                { $$ = $3; }
        | error ';'
                { $$ = $2; }
        ;

member_declarator_list_opt:
        /* empty */                                     { $$ = NULL; }
        | member_declarator_list
        ;

member_declarator_list:
        member_declarator
        | member_declarator_list ',' member_declarator  { $$ = $3; }
        ;

member_declarator:
        nested_declarator attribute_opt                 { $$ = $2 ? $2 : $1; }
        | IDENT member_bitfield_declarator              { $$ = $2; }
        | member_bitfield_declarator
        ;

member_bitfield_declarator:
        ':' EXPRESSION_PHRASE                           { $$ = $2; }
        ;

attribute_opt:
        /* empty */                                     { $$ = NULL; }
        | attribute_opt ATTRIBUTE_PHRASE
        ;

asm_definition:
        ASM_PHRASE ';'                                  { $$ = $2; }
        ;

asm_phrase_opt:
        /* empty */                                     { $$ = NULL; }
        | ASM_PHRASE
        ;

export_definition:
        EXPORT_SYMBOL_KEYW '(' IDENT ')' ';'
                { export_symbol((*$3)->string); $$ = $5; }
        ;


%%

static void
yyerror(const char *e)
{
  error_with_pos("%s", e);
}

/* [<][>][^][v][top][bottom][index][help] */

[funini.com] -> [kei@sodan] -> Kernel Reading