1 /* $Id: grammar.y,v 1.1 2004/03/24 21:29:23 tom Exp $
3 * yacc grammar for C function prototype generator
4 * This was derived from the grammar in Appendix A of
5 * "The C Programming Language" by Kernighan and Ritchie.
8 %token <text> '(' '*' '&'
9 /* identifiers that are not reserved words */
10 T_IDENTIFIER T_TYPEDEF_NAME T_DEFINE_NAME
13 T_AUTO T_EXTERN T_REGISTER T_STATIC T_TYPEDEF
14 /* This keyword included for compatibility with C++. */
16 /* This keyword included for compatibility with GCC */
20 T_CHAR T_DOUBLE T_FLOAT T_INT T_VOID
21 T_LONG T_SHORT T_SIGNED T_UNSIGNED
22 T_ENUM T_STRUCT T_UNION
24 T_Bool T_Complex T_Imaginary
29 /* paired square brackets and everything between them: [ ... ] */
35 /* all input to the matching right brace */
41 /* constant expression or paired braces following an equal sign */
49 /* ( "string literal" ) following asm keyword */
52 /* va_dcl from <varargs.h> */
55 %type <decl_spec> decl_specifiers decl_specifier
56 %type <decl_spec> storage_class type_specifier type_qualifier
57 %type <decl_spec> struct_or_union_specifier enum_specifier
58 %type <decl_list> init_declarator_list
59 %type <declarator> init_declarator declarator direct_declarator
60 %type <declarator> abs_declarator direct_abs_declarator
61 %type <param_list> parameter_type_list parameter_list
62 %type <parameter> parameter_declaration
63 %type <param_list> opt_identifier_list identifier_list
64 %type <text> struct_or_union pointer opt_type_qualifiers type_qualifier_list
65 any_id identifier_or_ref
66 %type <text> enumeration
75 #define YYMAXDEPTH 150
77 extern int yylex (void);
79 /* declaration specifier attributes for the typedef statement currently being
82 static int cur_decl_spec_flags;
84 /* pointer to parameter list for the current function definition */
85 static ParameterList *func_params;
87 /* A parser semantic action sets this pointer to the current declarator in
88 * a function parameter declaration in order to catch any comments following
89 * the parameter declaration on the same line. If the lexer scans a comment
90 * and <cur_declarator> is not NULL, then the comment is attached to the
91 * declarator. To ignore subsequent comments, the lexer sets this to NULL
92 * after scanning a comment or end of line.
94 static Declarator *cur_declarator;
96 /* temporary string buffer */
97 static char buf[MAX_TEXT_SIZE];
99 /* table of typedef names */
100 static SymbolTable *typedef_names;
102 /* table of define names */
103 static SymbolTable *define_names;
105 /* table of type qualifiers */
106 static SymbolTable *type_qualifiers;
108 /* information about the current input file */
110 char *base_name; /* base input file name */
111 char *file_name; /* current file name */
112 FILE *file; /* input file */
113 unsigned line_num; /* current line number in input file */
114 FILE *tmp_file; /* temporary file */
115 long begin_comment; /* tmp file offset after last written ) or ; */
116 long end_comment; /* tmp file offset after last comment */
117 boolean convert; /* if TRUE, convert function definitions */
118 boolean changed; /* TRUE if conversion done in this file */
121 static IncludeStack *cur_file; /* current input file */
125 static int haveAnsiParam (void);
128 /* Flags to enable us to find if a procedure returns a value.
130 static int return_val, /* nonzero on BRACES iff return-expression found */
131 returned_at; /* marker for token-number to set 'return_val' */
134 static char *dft_decl_spec (void);
139 return (lintLibrary() && !return_val) ? "void" : "int";
143 #define dft_decl_spec() "int"
150 if (func_params != 0) {
151 for (p = func_params->first; p != 0; p = p->next) {
152 if (p->declarator->func_def == FUNC_ANSI) {
168 : external_declaration
169 | translation_unit external_declaration
174 | function_definition
176 | linkage_specification
178 | error T_MATCHRBRACE
189 : T_LBRACE T_MATCHRBRACE
192 linkage_specification
193 : T_EXTERN T_STRING_LITERAL braces
195 /* Provide an empty action here so bison will not complain about
196 * incompatible types in the default action it normally would
200 | T_EXTERN T_STRING_LITERAL declaration
207 : decl_specifiers ';'
210 if (types_out && want_typedef()) {
211 gen_declarations(&$1, (DeclaratorList *)0);
218 | decl_specifiers init_declarator_list ';'
220 if (func_params != NULL) {
221 set_param_types(func_params, &$1, &$2);
223 gen_declarations(&$1, &$2);
232 | any_typedef decl_specifiers
234 cur_decl_spec_flags = $2.flags;
237 opt_declarator_list ';'
244 : T_EXTENSION T_TYPEDEF
262 int flags = cur_decl_spec_flags;
264 /* If the typedef is a pointer type, then reset the short type
265 * flags so it does not get promoted.
267 if (strcmp($1->text, $1->name) != 0)
268 flags &= ~(DS_CHAR | DS_SHORT | DS_FLOAT);
269 new_symbol(typedef_names, $1->name, NULL, flags);
272 | declarator_list ',' declarator
274 int flags = cur_decl_spec_flags;
276 if (strcmp($3->text, $3->name) != 0)
277 flags &= ~(DS_CHAR | DS_SHORT | DS_FLOAT);
278 new_symbol(typedef_names, $3->name, NULL, flags);
284 : decl_specifiers declarator
287 if ($2->func_def == FUNC_NONE) {
288 yyerror("syntax error");
291 func_params = &($2->head->params);
292 func_params->begin_comment = cur_file->begin_comment;
293 func_params->end_comment = cur_file->end_comment;
295 opt_declaration_list T_LBRACE
297 /* If we're converting to K&R and we've got a nominally K&R
298 * function which has a parameter which is ANSI (i.e., a prototyped
299 * function pointer), then we must override the deciphered value of
300 * 'func_def' so that the parameter will be converted.
302 if (func_style == FUNC_TRADITIONAL
304 && $2->head->func_def == func_style) {
305 $2->head->func_def = FUNC_BOTH;
310 if (cur_file->convert)
311 gen_func_definition(&$1, $2);
312 gen_prototype(&$1, $2);
322 if ($1->func_def == FUNC_NONE) {
323 yyerror("syntax error");
326 func_params = &($1->head->params);
327 func_params->begin_comment = cur_file->begin_comment;
328 func_params->end_comment = cur_file->end_comment;
330 opt_declaration_list T_LBRACE T_MATCHRBRACE
336 new_decl_spec(&decl_spec, dft_decl_spec(), $1->begin, DS_NONE);
337 if (cur_file->convert)
338 gen_func_definition(&decl_spec, $1);
339 gen_prototype(&decl_spec, $1);
343 free_decl_spec(&decl_spec);
356 | declaration_list declaration
361 | decl_specifiers decl_specifier
363 join_decl_specs(&$$, &$1, &$2);
378 new_decl_spec(&$$, $1.text, $1.begin, DS_NONE);
382 new_decl_spec(&$$, $1.text, $1.begin, DS_EXTERN);
386 new_decl_spec(&$$, $1.text, $1.begin, DS_NONE);
390 new_decl_spec(&$$, $1.text, $1.begin, DS_STATIC);
394 new_decl_spec(&$$, $1.text, $1.begin, DS_INLINE);
398 new_decl_spec(&$$, $1.text, $1.begin, DS_JUNK);
405 new_decl_spec(&$$, $1.text, $1.begin, DS_CHAR);
409 new_decl_spec(&$$, $1.text, $1.begin, DS_NONE);
413 new_decl_spec(&$$, $1.text, $1.begin, DS_FLOAT);
417 new_decl_spec(&$$, $1.text, $1.begin, DS_NONE);
421 new_decl_spec(&$$, $1.text, $1.begin, DS_NONE);
425 new_decl_spec(&$$, $1.text, $1.begin, DS_SHORT);
429 new_decl_spec(&$$, $1.text, $1.begin, DS_NONE);
433 new_decl_spec(&$$, $1.text, $1.begin, DS_NONE);
437 new_decl_spec(&$$, $1.text, $1.begin, DS_NONE);
441 new_decl_spec(&$$, $1.text, $1.begin, DS_CHAR);
445 new_decl_spec(&$$, $1.text, $1.begin, DS_NONE);
449 new_decl_spec(&$$, $1.text, $1.begin, DS_NONE);
454 s = find_symbol(typedef_names, $1.text);
456 new_decl_spec(&$$, $1.text, $1.begin, s->flags);
458 | struct_or_union_specifier
465 new_decl_spec(&$$, $1.text, $1.begin, DS_NONE);
469 /* This rule allows the <pointer> nonterminal to scan #define
470 * names as if they were type modifiers.
473 s = find_symbol(define_names, $1.text);
475 new_decl_spec(&$$, $1.text, $1.begin, s->flags);
479 struct_or_union_specifier
480 : struct_or_union any_id braces
483 if ((s = implied_typedef()) == 0)
484 (void)sprintf(s = buf, "%s %s", $1.text, $2.text);
485 new_decl_spec(&$$, s, $1.begin, DS_NONE);
487 | struct_or_union braces
490 if ((s = implied_typedef()) == 0)
491 (void)sprintf(s = buf, "%s {}", $1.text);
492 new_decl_spec(&$$, s, $1.begin, DS_NONE);
494 | struct_or_union any_id
496 (void)sprintf(buf, "%s %s", $1.text, $2.text);
497 new_decl_spec(&$$, buf, $1.begin, DS_NONE);
504 imply_typedef($$.text);
508 imply_typedef($$.text);
515 new_decl_list(&$$, $1);
517 | init_declarator_list ',' init_declarator
519 add_decl_list(&$$, &$1, $3);
526 if ($1->func_def != FUNC_NONE && func_params == NULL &&
527 func_style == FUNC_TRADITIONAL && cur_file->convert) {
528 gen_func_declarator($1);
529 fputs(cur_text(), cur_file->tmp_file);
535 if ($1->func_def != FUNC_NONE && func_params == NULL &&
536 func_style == FUNC_TRADITIONAL && cur_file->convert) {
537 gen_func_declarator($1);
538 fputs(" =", cur_file->tmp_file);
545 : enumeration any_id braces
548 if ((s = implied_typedef()) == 0)
549 (void)sprintf(s = buf, "enum %s", $2.text);
550 new_decl_spec(&$$, s, $1.begin, DS_NONE);
555 if ((s = implied_typedef()) == 0)
556 (void)sprintf(s = buf, "%s {}", $1.text);
557 new_decl_spec(&$$, s, $1.begin, DS_NONE);
561 (void)sprintf(buf, "enum %s", $2.text);
562 new_decl_spec(&$$, buf, $1.begin, DS_NONE);
569 imply_typedef("enum");
580 : pointer direct_declarator
583 (void)sprintf(buf, "%s%s", $1.text, $$->text);
585 $$->text = xstrdup(buf);
586 $$->begin = $1.begin;
595 $$ = new_declarator($1.text, $1.text, $1.begin);
600 (void)sprintf(buf, "(%s)", $$->text);
602 $$->text = xstrdup(buf);
603 $$->begin = $1.begin;
605 | direct_declarator T_BRACKETS
608 (void)sprintf(buf, "%s%s", $$->text, $2.text);
610 $$->text = xstrdup(buf);
612 | direct_declarator '(' parameter_type_list ')'
614 $$ = new_declarator("%s()", $1->name, $1->begin);
617 $$->head = ($1->func_stack == NULL) ? $$ : $1->head;
618 $$->func_def = FUNC_ANSI;
620 | direct_declarator '(' opt_identifier_list ')'
622 $$ = new_declarator("%s()", $1->name, $1->begin);
625 $$->head = ($1->func_stack == NULL) ? $$ : $1->head;
626 $$->func_def = FUNC_TRADITIONAL;
631 : '*' opt_type_qualifiers
633 (void)sprintf($$.text, "*%s", $2.text);
636 | '*' opt_type_qualifiers pointer
638 (void)sprintf($$.text, "*%s%s", $2.text, $3.text);
649 | type_qualifier_list
655 (void)sprintf($$.text, "%s ", $1.text);
659 | type_qualifier_list type_qualifier
661 (void)sprintf($$.text, "%s%s ", $1.text, $2.text);
669 | parameter_list ',' T_ELLIPSIS
671 add_ident_list(&$$, &$1, "...");
676 : parameter_declaration
678 new_param_list(&$$, $1);
680 | parameter_list ',' parameter_declaration
682 add_param_list(&$$, &$1, $3);
686 parameter_declaration
687 : decl_specifiers declarator
690 $$ = new_parameter(&$1, $2);
692 | decl_specifiers abs_declarator
695 $$ = new_parameter(&$1, $2);
700 $$ = new_parameter(&$1, (Declarator *)0);
716 add_ident_list(&$$, &$$, $1.text);
718 | identifier_list ',' any_id
720 add_ident_list(&$$, &$1, $3.text);
732 if (lintLibrary()) { /* Lint doesn't grok C++ ref variables */
736 (void)sprintf($$.text, "&%s", $2.text);
744 $$ = new_declarator($1.text, "", $1.begin);
746 | pointer direct_abs_declarator
749 (void)sprintf(buf, "%s%s", $1.text, $$->text);
751 $$->text = xstrdup(buf);
752 $$->begin = $1.begin;
754 | direct_abs_declarator
757 direct_abs_declarator
758 : '(' abs_declarator ')'
761 (void)sprintf(buf, "(%s)", $$->text);
763 $$->text = xstrdup(buf);
764 $$->begin = $1.begin;
766 | direct_abs_declarator T_BRACKETS
769 (void)sprintf(buf, "%s%s", $$->text, $2.text);
771 $$->text = xstrdup(buf);
775 $$ = new_declarator($1.text, "", $1.begin);
777 | direct_abs_declarator '(' parameter_type_list ')'
779 $$ = new_declarator("%s()", "", $1->begin);
782 $$->head = ($1->func_stack == NULL) ? $$ : $1->head;
783 $$->func_def = FUNC_ANSI;
785 | direct_abs_declarator '(' ')'
787 $$ = new_declarator("%s()", "", $1->begin);
789 $$->head = ($1->func_stack == NULL) ? $$ : $1->head;
790 $$->func_def = FUNC_ANSI;
792 | '(' parameter_type_list ')'
796 d = new_declarator("", "", $1.begin);
797 $$ = new_declarator("%s()", "", $1.begin);
801 $$->func_def = FUNC_ANSI;
807 d = new_declarator("", "", $1.begin);
808 $$ = new_declarator("%s()", "", $1.begin);
811 $$->func_def = FUNC_ANSI;
817 #if defined(__EMX__) || defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(vms)
828 yaccError (char *msg)
831 put_error(); /* tell what line we're on, and what file */
832 fprintf(stderr, "%s at token '%s'\n", msg, yytext);
835 /* Initialize the table of type qualifier keywords recognized by the lexical
841 static char *keywords[] = {
850 #if defined(MSDOS) || defined(OS2)
908 /* Initialize type qualifier table. */
909 type_qualifiers = new_symbol_table();
910 for (i = 0; i < sizeof(keywords)/sizeof(keywords[0]); ++i) {
911 new_symbol(type_qualifiers, keywords[i], NULL, DS_NONE);
915 /* Process the C source file. Write function prototypes to the standard
916 * output. Convert function definitions and write the converted source
917 * code to a temporary file.
920 process_file (FILE *infile, char *name)
924 if (strlen(name) > 2) {
925 s = name + strlen(name) - 2;
928 if (*s == 'l' || *s == 'y')
930 #if defined(MSDOS) || defined(OS2)
931 if (*s == 'L' || *s == 'Y')
937 included_files = new_symbol_table();
938 typedef_names = new_symbol_table();
939 define_names = new_symbol_table();
945 include_file(strcpy(base_file, name), func_style != FUNC_NONE);
949 put_blankline(stdout);
953 put_string(stdout, "/* ");
954 put_string(stdout, cur_file_name());
955 put_string(stdout, " */\n");
958 free_symbol_table(define_names);
959 free_symbol_table(typedef_names);
960 free_symbol_table(included_files);
967 free_symbol_table (type_qualifiers);
969 if (yy_current_buffer != 0)
970 yy_delete_buffer(yy_current_buffer);