/* $Id: parser.y,v 1.27 2001/07/13 19:09:55 sandro Exp $ */ /* * Copyright (c) 1995-2001 Sandro Sigala. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This grammar should be full ANSI C compilant. */ %{ #include #include #include #include #include #include "config.h" extern int lineno; #ifdef YYTEXT_POINTER extern char *yytext; #else extern char yytext[]; #endif extern FILE *output_file; static void yyerror(char *); static char *cat(char *, ...); static int cast; static char *ident; #define dup(s) xstrdup(s) %} %union { char *string; } %token TYPEDEF EXTERN STATIC AUTO REGISTER %token VOID CHAR SHORT INT LONG FLOAT DOUBLE SIGNED UNSIGNED %token CONST VOLATILE STRUCT UNION ENUM %token ELLIPSIS IDENTIFIER NUMBER %type declaration_specifiers storage_class_specifier type_specifier %type tag_specifier struct_or_union_or_enum specifier_qualifier_list %type type_qualifier identifier declarator direct_declarator %type pointer type_qualifier_list parameter_type_list parameter_list %type parameter_declaration identifier_list type_name %type abstract_declarator direct_abstract_declarator %type constant_expression storage_class_specifier_opt %% file: /* empty */ | declaration_or_cast_list ; declaration_or_cast_list: declaration_or_cast | declaration_or_cast_list declaration_or_cast ; declaration_or_cast: no_cast declaration | init_cast cast ; init_cast: { cast = 1; } ; no_cast: { cast = 0; } ; cast: '(' type_name ')' identifier ';' { char *s = cat(dup("cast"), $4, dup(" into"), $2, NULL); fprintf(output_file, "%s;\n", s); free(s); } ; declaration: storage_class_specifier_opt declaration_specifiers declarator ';' { char *s = cat(dup("declare"), ident, dup(" as"), $1, $3, $2, NULL); fprintf(output_file, "%s;\n", s); free(s); ident = NULL; } ; storage_class_specifier_opt: /* empty */ { $$ = dup(""); } | storage_class_specifier { $$ = $1; } ; declaration_specifiers: type_specifier { $$ = $1; } | type_specifier declaration_specifiers { $$ = cat($1, $2, NULL); } | type_qualifier { $$ = $1; } | type_qualifier declaration_specifiers { $$ = cat($1, $2, NULL); } ; storage_class_specifier: TYPEDEF { $$ = dup(" typedef"); } | EXTERN { $$ = dup(" extern"); } | STATIC { $$ = dup(" static"); } | AUTO { $$ = dup(" auto"); } | REGISTER { $$ = dup(" register"); } ; type_specifier: VOID { $$ = dup(" void"); } | CHAR { $$ = dup(" char"); } | SHORT { $$ = dup(" short"); } | INT { $$ = dup(" int"); } | LONG { $$ = dup(" long"); } | FLOAT { $$ = dup(" float"); } | DOUBLE { $$ = dup(" double"); } | SIGNED { $$ = dup(" signed"); } | UNSIGNED { $$ = dup(" unsigned"); } | tag_specifier { $$ = $1; } ; tag_specifier: struct_or_union_or_enum identifier { $$ = cat($1, $2, NULL); } ; struct_or_union_or_enum: STRUCT { $$ = dup(" struct"); } | UNION { $$ = dup(" union"); } | ENUM { $$ = dup(" enum"); } ; specifier_qualifier_list: type_specifier specifier_qualifier_list { $$ = cat($1, $2, NULL); } | type_specifier { $$ = $1; } | type_qualifier specifier_qualifier_list { $$ = cat($1, $2, NULL); } | type_qualifier { $$ = $1; } ; type_qualifier: CONST { $$ = dup(" const"); } | VOLATILE { $$ = dup(" volatile"); } ; identifier: IDENTIFIER { $$ = cat(dup(" "), dup(yytext), NULL); } ; declarator: pointer direct_declarator { $$ = cat($2, $1, NULL); } | direct_declarator { $$ = $1; } ; direct_declarator: identifier { if (ident == NULL && !cast) { ident = $1; $$ = dup(""); } else $$ = cat($1, dup(" as"), NULL); } | '(' declarator ')' { $$ = $2; } | direct_declarator '[' constant_expression ']' { $$ = cat($1, dup(" array["), $3, dup("] of"), NULL); } | direct_declarator '[' ']' { $$ = cat($1, dup(" array of"), NULL); } | direct_declarator '(' parameter_type_list ')' { $$ = cat($1, dup(" function that expects ("), dup($3+1), dup(") returning"), NULL); free($3); } | direct_declarator '(' identifier_list ')' { $$ = cat($1, dup(" function that expects ("), dup($3+1), dup(") returning"), NULL); free($3); } | direct_declarator '(' ')' { $$ = cat($1, dup(" function returning"), NULL); } ; pointer: '*' { $$ = dup(" pointer to"); } | '*' type_qualifier_list { $$ = cat($2, dup(" pointer to"), NULL); } | '*' pointer { $$ = cat($2, dup(" pointer to"), NULL); } | '*' type_qualifier_list pointer { $$ = cat($3, $2, dup(" pointer to"), NULL); } ; type_qualifier_list: type_qualifier { $$ = $1; } | type_qualifier_list type_qualifier { $$ = cat($1, $2, NULL); } ; parameter_type_list: parameter_list { $$ = $1; } | parameter_list ',' ELLIPSIS { $$ = cat($1, dup(", ..."), NULL); } ; parameter_list: parameter_declaration { $$ = $1; } | parameter_list ',' parameter_declaration { $$ = cat($1, dup(","), $3, NULL); } ; parameter_declaration: declaration_specifiers declarator { $$ = cat($2, $1, NULL); } | declaration_specifiers abstract_declarator { $$ = cat($2, $1, NULL); } | declaration_specifiers { $$ = $1; } ; identifier_list: identifier { $$ = $1; } | identifier_list ',' identifier { $$ = cat($1, dup(","), $3, NULL); } ; type_name: specifier_qualifier_list { $$ = $1; } | specifier_qualifier_list abstract_declarator { $$ = cat($2, $1, NULL); } ; abstract_declarator: pointer { $$ = $1; } | direct_abstract_declarator { $$ = $1; } | pointer direct_abstract_declarator { $$ = cat($2, $1, NULL); } ; direct_abstract_declarator: '(' abstract_declarator ')' { $$ = $2; } | '[' ']' { $$ = dup(" array of"); } | '[' constant_expression ']' { $$ = cat(dup(" array["), $2, dup("] of"), NULL); } | direct_abstract_declarator '[' ']' { $$ = cat($1, dup(" array of"), NULL); } | direct_abstract_declarator '[' constant_expression ']' { $$ = cat($1, dup(" array["), $3, dup("] of"), NULL); } | '(' ')' { $$ = dup(" function returning"); } | '(' parameter_type_list ')' { $$ = cat(dup(" function that expectes ("), dup($2+1), dup(") returning"), NULL); free($2); } | direct_abstract_declarator '(' ')' { $$ = cat($1, dup(" function returning"), NULL); } | direct_abstract_declarator '(' parameter_type_list ')' { $$ = cat($1, dup(" function that expects ("), dup($3+1), dup(") returning"), NULL); free($3); } ; constant_expression: NUMBER { $$ = dup(yytext); } ; %% static void yyerror(char *s) { errx(1, "%d: %s", lineno, s); } /* * Catenate the null-terminated strings into a newly allocated string. * The parameter list is terminated by a NULL pointer. * The parameters are deallocated after copy. */ static char *cat(char *s, ...) { va_list ap; int size; char *p, *newstr; size = strlen(s) + 1; va_start(ap, s); while ((p = va_arg(ap, char *)) != NULL) size += strlen(p) + 1; va_end(ap); newstr = (char *)xmalloc(size); va_start(ap, s); strcpy(newstr, s); free(s); while ((p = va_arg(ap, char *)) != NULL) { strcat(newstr, p); free(p); } va_end(ap); return newstr; }