123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500 |
- /* 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 <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);
- }
- %}
- %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 enum_body
- { 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 enum definition. Tell add_symbol() to restart its counter.
- */
- | ENUM_KEYW enum_body
- { add_symbol(NULL, SYM_ENUM, NULL, 0); $$ = $2; }
- /* Anonymous s/u definitions. Nothing needs doing. */
- | 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
- ;
- enum_body:
- '{' enumerator_list '}' { $$ = $3; }
- | '{' enumerator_list ',' '}' { $$ = $4; }
- ;
- enumerator_list:
- enumerator
- | enumerator_list ',' enumerator
- enumerator:
- IDENT
- {
- const char *name = strdup((*$1)->string);
- add_symbol(name, SYM_ENUM_CONST, NULL, 0);
- }
- | IDENT '=' EXPRESSION_PHRASE
- {
- const char *name = strdup((*$1)->string);
- struct string_list *expr = copy_list_range(*$3, *$2);
- add_symbol(name, SYM_ENUM_CONST, expr, 0);
- }
- 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);
- }
|