3 /* Id: grammar.y,v 1.1 2004/03/24 21:29:23 tom Exp
5 * yacc grammar for C function prototype generator
6 * This was derived from the grammar in Appendix A of
7 * "The C Programming Language" by Kernighan and Ritchie.
10 %token
<text
> '(' '*' '&'
11 /* identifiers that are not reserved words */
12 T_IDENTIFIER T_TYPEDEF_NAME T_DEFINE_NAME
15 T_AUTO T_EXTERN T_REGISTER T_STATIC T_TYPEDEF
16 /* This keyword included for compatibility with C++. */
18 /* This keyword included for compatibility with GCC */
22 T_CHAR T_DOUBLE T_FLOAT T_INT T_VOID
23 T_LONG T_SHORT T_SIGNED T_UNSIGNED
24 T_ENUM T_STRUCT T_UNION
26 T_Bool T_Complex T_Imaginary
31 /* paired square brackets and everything between them: [ ... ] */
37 /* all input to the matching right brace */
43 /* constant expression or paired braces following an equal sign */
51 /* ( "string literal" ) following asm keyword */
54 /* va_dcl from <varargs.h> */
57 %type
<decl_spec
> decl_specifiers decl_specifier
58 %type
<decl_spec
> storage_class type_specifier type_qualifier
59 %type
<decl_spec
> struct_or_union_specifier enum_specifier
60 %type
<decl_list
> init_declarator_list
61 %type
<declarator
> init_declarator declarator direct_declarator
62 %type
<declarator
> abs_declarator direct_abs_declarator
63 %type
<param_list
> parameter_type_list parameter_list
64 %type
<parameter
> parameter_declaration
65 %type
<param_list
> opt_identifier_list identifier_list
66 %type
<text
> struct_or_union pointer opt_type_qualifiers type_qualifier_list
67 any_id identifier_or_ref
68 %type
<text
> enumeration
77 #define YYMAXDEPTH 150
79 extern
int yylex (void);
81 /* declaration specifier attributes for the typedef statement currently being
84 static int cur_decl_spec_flags
;
86 /* pointer to parameter list for the current function definition */
87 static ParameterList
*func_params
;
89 /* A parser semantic action sets this pointer to the current declarator in
90 * a function parameter declaration in order to catch any comments following
91 * the parameter declaration on the same line. If the lexer scans a comment
92 * and <cur_declarator> is not NULL, then the comment is attached to the
93 * declarator. To ignore subsequent comments, the lexer sets this to NULL
94 * after scanning a comment or end of line.
96 static Declarator
*cur_declarator
;
98 /* temporary string buffer */
99 static char buf
[MAX_TEXT_SIZE
];
101 /* table of typedef names */
102 static SymbolTable
*typedef_names
;
104 /* table of define names */
105 static SymbolTable
*define_names
;
107 /* table of type qualifiers */
108 static SymbolTable
*type_qualifiers
;
110 /* information about the current input file */
112 char *base_name
; /* base input file name */
113 char *file_name
; /* current file name */
114 FILE *file
; /* input file */
115 unsigned line_num
; /* current line number in input file */
116 FILE *tmp_file
; /* temporary file */
117 long begin_comment
; /* tmp file offset after last written ) or ; */
118 long end_comment
; /* tmp file offset after last comment */
119 boolean convert
; /* if TRUE, convert function definitions */
120 boolean changed
; /* TRUE if conversion done in this file */
123 static IncludeStack
*cur_file
; /* current input file */
127 static int haveAnsiParam
(void);
130 /* Flags to enable us to find if a procedure returns a value.
132 static int return_val
, /* nonzero on BRACES iff return-expression found */
133 returned_at
; /* marker for token-number to set 'return_val' */
136 static char *dft_decl_spec
(void);
141 return
(lintLibrary
() && !return_val
) ?
"void" : "int";
145 #define dft_decl_spec() "int"
152 if
(func_params
!= 0) {
153 for
(p
= func_params
->first
; p
!= 0; p
= p
->next
) {
154 if
(p
->declarator
->func_def
== FUNC_ANSI
) {
170 : external_declaration
171 | translation_unit external_declaration
176 | function_definition
178 | linkage_specification
180 |
error T_MATCHRBRACE
191 : T_LBRACE T_MATCHRBRACE
194 linkage_specification
195 : T_EXTERN T_STRING_LITERAL braces
197 /* Provide an empty action here so bison will not complain about
198 * incompatible types in the default action it normally would
202 | T_EXTERN T_STRING_LITERAL declaration
209 : decl_specifiers
';'
212 if
(types_out
&& want_typedef
()) {
213 gen_declarations
(&$1, (DeclaratorList
*)0);
220 | decl_specifiers init_declarator_list
';'
222 if
(func_params
!= NULL
) {
223 set_param_types
(func_params
, &$1, &$2);
225 gen_declarations
(&$1, &$2);
234 | any_typedef decl_specifiers
236 cur_decl_spec_flags
= $2.flags
;
239 opt_declarator_list
';'
246 : T_EXTENSION T_TYPEDEF
264 int flags
= cur_decl_spec_flags
;
266 /* If the typedef is a pointer type, then reset the short type
267 * flags so it does not get promoted.
269 if
(strcmp
($1->text
, $1->name
) != 0)
270 flags
&= ~
(DS_CHAR | DS_SHORT | DS_FLOAT
);
271 new_symbol
(typedef_names
, $1->name
, NULL
, flags
);
274 | declarator_list
',' declarator
276 int flags
= cur_decl_spec_flags
;
278 if
(strcmp
($3->text
, $3->name
) != 0)
279 flags
&= ~
(DS_CHAR | DS_SHORT | DS_FLOAT
);
280 new_symbol
(typedef_names
, $3->name
, NULL
, flags
);
286 : decl_specifiers declarator
289 if
($2->func_def
== FUNC_NONE
) {
290 yyerror("syntax error");
293 func_params
= &($2->head
->params
);
294 func_params
->begin_comment
= cur_file
->begin_comment
;
295 func_params
->end_comment
= cur_file
->end_comment
;
297 opt_declaration_list T_LBRACE
299 /* If we're converting to K&R and we've got a nominally K&R
300 * function which has a parameter which is ANSI (i.e., a prototyped
301 * function pointer), then we must override the deciphered value of
302 * 'func_def' so that the parameter will be converted.
304 if
(func_style
== FUNC_TRADITIONAL
306 && $2->head
->func_def
== func_style
) {
307 $2->head
->func_def
= FUNC_BOTH
;
312 if
(cur_file
->convert
)
313 gen_func_definition
(&$1, $2);
314 gen_prototype
(&$1, $2);
324 if
($1->func_def
== FUNC_NONE
) {
325 yyerror("syntax error");
328 func_params
= &($1->head
->params
);
329 func_params
->begin_comment
= cur_file
->begin_comment
;
330 func_params
->end_comment
= cur_file
->end_comment
;
332 opt_declaration_list T_LBRACE T_MATCHRBRACE
338 new_decl_spec
(&decl_spec
, dft_decl_spec
(), $1->begin
, DS_NONE
);
339 if
(cur_file
->convert
)
340 gen_func_definition
(&decl_spec
, $1);
341 gen_prototype
(&decl_spec
, $1);
345 free_decl_spec
(&decl_spec
);
358 | declaration_list declaration
363 | decl_specifiers decl_specifier
365 join_decl_specs
(&$$
, &$1, &$2);
380 new_decl_spec
(&$$
, $1.text
, $1.begin
, DS_NONE
);
384 new_decl_spec
(&$$
, $1.text
, $1.begin
, DS_EXTERN
);
388 new_decl_spec
(&$$
, $1.text
, $1.begin
, DS_NONE
);
392 new_decl_spec
(&$$
, $1.text
, $1.begin
, DS_STATIC
);
396 new_decl_spec
(&$$
, $1.text
, $1.begin
, DS_INLINE
);
400 new_decl_spec
(&$$
, $1.text
, $1.begin
, DS_JUNK
);
407 new_decl_spec
(&$$
, $1.text
, $1.begin
, DS_CHAR
);
411 new_decl_spec
(&$$
, $1.text
, $1.begin
, DS_NONE
);
415 new_decl_spec
(&$$
, $1.text
, $1.begin
, DS_FLOAT
);
419 new_decl_spec
(&$$
, $1.text
, $1.begin
, DS_NONE
);
423 new_decl_spec
(&$$
, $1.text
, $1.begin
, DS_NONE
);
427 new_decl_spec
(&$$
, $1.text
, $1.begin
, DS_SHORT
);
431 new_decl_spec
(&$$
, $1.text
, $1.begin
, DS_NONE
);
435 new_decl_spec
(&$$
, $1.text
, $1.begin
, DS_NONE
);
439 new_decl_spec
(&$$
, $1.text
, $1.begin
, DS_NONE
);
443 new_decl_spec
(&$$
, $1.text
, $1.begin
, DS_CHAR
);
447 new_decl_spec
(&$$
, $1.text
, $1.begin
, DS_NONE
);
451 new_decl_spec
(&$$
, $1.text
, $1.begin
, DS_NONE
);
456 s
= find_symbol
(typedef_names
, $1.text
);
458 new_decl_spec
(&$$
, $1.text
, $1.begin
, s
->flags
);
460 | struct_or_union_specifier
467 new_decl_spec
(&$$
, $1.text
, $1.begin
, DS_NONE
);
471 /* This rule allows the <pointer> nonterminal to scan #define
472 * names as if they were type modifiers.
475 s
= find_symbol
(define_names
, $1.text
);
477 new_decl_spec
(&$$
, $1.text
, $1.begin
, s
->flags
);
481 struct_or_union_specifier
482 : struct_or_union any_id braces
485 if
((s
= implied_typedef
()) == 0)
486 (void)sprintf
(s
= buf
, "%s %s", $1.text
, $2.text
);
487 new_decl_spec
(&$$
, s
, $1.begin
, DS_NONE
);
489 | struct_or_union braces
492 if
((s
= implied_typedef
()) == 0)
493 (void)sprintf
(s
= buf
, "%s {}", $1.text
);
494 new_decl_spec
(&$$
, s
, $1.begin
, DS_NONE
);
496 | struct_or_union any_id
498 (void)sprintf
(buf
, "%s %s", $1.text
, $2.text
);
499 new_decl_spec
(&$$
, buf
, $1.begin
, DS_NONE
);
506 imply_typedef
($$.text
);
510 imply_typedef
($$.text
);
517 new_decl_list
(&$$
, $1);
519 | init_declarator_list
',' init_declarator
521 add_decl_list
(&$$
, &$1, $3);
528 if
($1->func_def
!= FUNC_NONE
&& func_params
== NULL
&&
529 func_style
== FUNC_TRADITIONAL
&& cur_file
->convert
) {
530 gen_func_declarator
($1);
531 fputs
(cur_text
(), cur_file
->tmp_file
);
537 if
($1->func_def
!= FUNC_NONE
&& func_params
== NULL
&&
538 func_style
== FUNC_TRADITIONAL
&& cur_file
->convert
) {
539 gen_func_declarator
($1);
540 fputs
(" =", cur_file
->tmp_file
);
547 : enumeration any_id braces
550 if
((s
= implied_typedef
()) == 0)
551 (void)sprintf
(s
= buf
, "enum %s", $2.text
);
552 new_decl_spec
(&$$
, s
, $1.begin
, DS_NONE
);
557 if
((s
= implied_typedef
()) == 0)
558 (void)sprintf
(s
= buf
, "%s {}", $1.text
);
559 new_decl_spec
(&$$
, s
, $1.begin
, DS_NONE
);
563 (void)sprintf
(buf
, "enum %s", $2.text
);
564 new_decl_spec
(&$$
, buf
, $1.begin
, DS_NONE
);
571 imply_typedef
("enum");
582 : pointer direct_declarator
585 (void)sprintf
(buf
, "%s%s", $1.text
, $$
->text
);
587 $$
->text
= xstrdup
(buf
);
588 $$
->begin
= $1.begin
;
597 $$
= new_declarator
($1.text
, $1.text
, $1.begin
);
602 (void)sprintf
(buf
, "(%s)", $$
->text
);
604 $$
->text
= xstrdup
(buf
);
605 $$
->begin
= $1.begin
;
607 | direct_declarator T_BRACKETS
610 (void)sprintf
(buf
, "%s%s", $$
->text
, $2.text
);
612 $$
->text
= xstrdup
(buf
);
614 | direct_declarator
'(' parameter_type_list
')'
616 $$
= new_declarator
("%s()", $1->name
, $1->begin
);
619 $$
->head
= ($1->func_stack
== NULL
) ? $$
: $1->head
;
620 $$
->func_def
= FUNC_ANSI
;
622 | direct_declarator
'(' opt_identifier_list
')'
624 $$
= new_declarator
("%s()", $1->name
, $1->begin
);
627 $$
->head
= ($1->func_stack
== NULL
) ? $$
: $1->head
;
628 $$
->func_def
= FUNC_TRADITIONAL
;
633 : '*' opt_type_qualifiers
635 (void)sprintf
($$.text
, "*%s", $2.text
);
638 |
'*' opt_type_qualifiers pointer
640 (void)sprintf
($$.text
, "*%s%s", $2.text
, $3.text
);
651 | type_qualifier_list
657 (void)sprintf
($$.text
, "%s ", $1.text
);
661 | type_qualifier_list type_qualifier
663 (void)sprintf
($$.text
, "%s%s ", $1.text
, $2.text
);
671 | parameter_list
',' T_ELLIPSIS
673 add_ident_list
(&$$
, &$1, "...");
678 : parameter_declaration
680 new_param_list
(&$$
, $1);
682 | parameter_list
',' parameter_declaration
684 add_param_list
(&$$
, &$1, $3);
688 parameter_declaration
689 : decl_specifiers declarator
692 $$
= new_parameter
(&$1, $2);
694 | decl_specifiers abs_declarator
697 $$
= new_parameter
(&$1, $2);
702 $$
= new_parameter
(&$1, (Declarator
*)0);
718 add_ident_list
(&$$
, &$$
, $1.text
);
720 | identifier_list
',' any_id
722 add_ident_list
(&$$
, &$1, $3.text
);
734 if
(lintLibrary
()) { /* Lint doesn't grok C++ ref variables */
738 (void)sprintf
($$.text
, "&%s", $2.text
);
746 $$
= new_declarator
($1.text
, "", $1.begin
);
748 | pointer direct_abs_declarator
751 (void)sprintf
(buf
, "%s%s", $1.text
, $$
->text
);
753 $$
->text
= xstrdup
(buf
);
754 $$
->begin
= $1.begin
;
756 | direct_abs_declarator
759 direct_abs_declarator
760 : '(' abs_declarator
')'
763 (void)sprintf
(buf
, "(%s)", $$
->text
);
765 $$
->text
= xstrdup
(buf
);
766 $$
->begin
= $1.begin
;
768 | direct_abs_declarator T_BRACKETS
771 (void)sprintf
(buf
, "%s%s", $$
->text
, $2.text
);
773 $$
->text
= xstrdup
(buf
);
777 $$
= new_declarator
($1.text
, "", $1.begin
);
779 | direct_abs_declarator
'(' parameter_type_list
')'
781 $$
= new_declarator
("%s()", "", $1->begin
);
784 $$
->head
= ($1->func_stack
== NULL
) ? $$
: $1->head
;
785 $$
->func_def
= FUNC_ANSI
;
787 | direct_abs_declarator
'(' ')'
789 $$
= new_declarator
("%s()", "", $1->begin
);
791 $$
->head
= ($1->func_stack
== NULL
) ? $$
: $1->head
;
792 $$
->func_def
= FUNC_ANSI
;
794 |
'(' parameter_type_list
')'
798 d
= new_declarator
("", "", $1.begin
);
799 $$
= new_declarator
("%s()", "", $1.begin
);
803 $$
->func_def
= FUNC_ANSI
;
809 d
= new_declarator
("", "", $1.begin
);
810 $$
= new_declarator
("%s()", "", $1.begin
);
813 $$
->func_def
= FUNC_ANSI
;
819 #if defined(__EMX__) || defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(vms)
830 yaccError
(char *msg
)
833 put_error
(); /* tell what line we're on, and what file */
834 fprintf
(stderr
, "%s at token '%s'\n", msg
, yytext
);
837 /* Initialize the table of type qualifier keywords recognized by the lexical
843 static char *keywords
[] = {
852 #if defined(MSDOS) || defined(OS2)
910 /* Initialize type qualifier table. */
911 type_qualifiers
= new_symbol_table
();
912 for
(i
= 0; i
< sizeof
(keywords
)/sizeof
(keywords
[0]); ++i
) {
913 new_symbol
(type_qualifiers
, keywords
[i
], NULL
, DS_NONE
);
917 /* Process the C source file. Write function prototypes to the standard
918 * output. Convert function definitions and write the converted source
919 * code to a temporary file.
922 process_file
(FILE *infile
, char *name
)
926 if
(strlen
(name
) > 2) {
927 s
= name
+ strlen
(name
) - 2;
930 if
(*s
== 'l' ||
*s
== 'y')
932 #if defined(MSDOS) || defined(OS2)
933 if
(*s
== 'L' ||
*s
== 'Y')
939 included_files
= new_symbol_table
();
940 typedef_names
= new_symbol_table
();
941 define_names
= new_symbol_table
();
947 include_file
(strcpy
(base_file
, name
), func_style
!= FUNC_NONE
);
951 put_blankline
(stdout
);
955 put_string
(stdout
, "/* ");
956 put_string
(stdout
, cur_file_name
());
957 put_string
(stdout
, " */\n");
960 free_symbol_table
(define_names
);
961 free_symbol_table
(typedef_names
);
962 free_symbol_table
(included_files
);
969 free_symbol_table
(type_qualifiers
);
971 if
(yy_current_buffer
!= 0)
972 yy_delete_buffer
(yy_current_buffer
);