rsalz@uunet.uu.net (Rich Salz) (10/20/89)
Submitted-by: Chin Huang <cthuang@watdragon.waterloo.edu> Posting-number: Volume 20, Issue 39 Archive-name: cproto [ Not to be confused with Ron Guilmette's protoize, which will also appear here. This takes a neat way out in that it avoids doing any parsing of function bodies, which I think is really clever. As Chin says, you will need FLEX which is available from your nearest archive site and is also distributed on most GNU sites. /r$ ] This is program automatically generates C function prototypes and variable declarations from C language source code. You don't need the source to 4.2BSD lint to compile this program but you do need flex since the lexical analyzer specified in lex.l makes use of mutually exclusive start conditions. Chin Huang cthuang@watdragon.waterloo.edu # # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Contents: README Makefile cproto.1 cproto.sh grammar.y lex.l cproto.h # patchlevel.h semantics.h symbol.h cproto1.c semantics.c string.c # symbol.c echo x - README sed 's/^@//' > "README" <<'@//E*O*F README//' This is program automatically generates C function prototypes and variable declarations from C language source code. You don't need the source to 4.2BSD lint to compile this program but you do need flex since the lexical analyzer specified in lex.l makes use of mutually exclusive start conditions. Chin Huang cthuang@watdragon.waterloo.edu @//E*O*F README// chmod u=rw,g=r,o=r README echo x - Makefile sed 's/^@//' > "Makefile" <<'@//E*O*F Makefile//' # # $Header: Makefile,v 1.1 89/03/14 20:58:56 cthuang Exp $ # # Makefile for C prototype generator LEX = flex YACC = yacc CFLAGS = -O SOURCES = README Makefile cproto.1 cproto.sh \ grammar.y lex.l \ cproto.h patchlevel.h semantics.h symbol.h \ cproto1.c semantics.c string.c symbol.c CSOURCES = cproto1.c semantics.c string.c symbol.c y.tab.c OBJECTS = cproto1.o semantics.o string.o symbol.o y.tab.o all: cproto1 cproto1: $(OBJECTS) $(CC) $(CFLAGS) -o $@ $(OBJECTS) y.tab.o: y.tab.c lex.yy.c $(CC) $(CFLAGS) -c $*.c y.tab.c: grammar.y $(YACC) grammar.y lex.yy.c: lex.l grammar.y $(LEX) lex.l lint: lint -B $(CSOURCES) shar: shar -c $(SOURCES) >shar.out ci: ci -u $(SOURCES) main.o: symbol.h cproto.h semantics.o: symbol.h cproto.h semantics.h symbol.o: symbol.h y.tab.o: symbol.h cproto.h semantics.h @//E*O*F Makefile// chmod u=rw,g=r,o=r Makefile echo x - cproto.1 sed 's/^@//' > "cproto.1" <<'@//E*O*F cproto.1//' @.\" $Header: cproto.1,v 1.1 89/03/14 21:30:01 cthuang Exp $ @.\" @.de EX \"Begin example @.ne 5 @.if n .sp 1 @.if t .sp .5 @.nf @.in +.5i @.. @.de EE \"End example @.fi @.in -.5i @.if n .sp 1 @.if t .sp .5 @.. @.TH CPROTO 1 "March 14, 1989" @.SH NAME cproto \- generate C function prototypes from C source code @.SH SYNOPSIS @.B cproto [ @.I option \fP...\fI ] [ @.I file ] @.SH DESCRIPTION @.B Cproto generates C function prototypes from a C language source file. For each function defined in the file, @.B cproto outputs to the standard output a line consisting of the prototype for that function. Optionally, @.B cproto also outputs declarations for any variables defined in the file. If no @.I file argument is given, @.B cproto takes its input from the standard input. @.SH OPTIONS @.TP @.B \-e On the output, prepend the keyword @.B extern to declarations that have global scope. @.TP @.B \-g Output only "global" declarations. Only declarations of functions and variables that can be accessed outside of the source file will be printed. @.TP @.BI \-p n Set the style of function prototype where @.I n is a number from 0 to 2. For example, consider the function definition @.EX main (argc, argv) int argc; char *argv[]; { ... } @.EE A value of 2 produces the full function prototype: @.EX int main(int argc, char *argv[]); @.EE For a value of 1, the output has the form: @.EX int main(int /*argc*/, char */*argv*/[]); @.EE When set to 0, the output is: @.EX int main(/*int argc, char *argv[]*/); @.EE The default value is 2. @.TP @.B \-v Also output declarations of variables defined in the file. @.TP @.BI \-D name\[=value\] This option is passed through to the preprocessor and is used to define symbols for use with conditionals such as @.I #ifdef. @.TP @.BI \-U name This option is passed through to the preprocessor and is used to remove any definitions of this symbol. @.TP @.BI \-I directory This option is passed through to the preprocessor and is used to specify a directory to search for files that are referenced with @.I #include. @.SH AUTHOR Chin Huang (cthuang@watdragon.waterloo.edu) @.SH CAVEATS Any error messages produced are minimal. If the C source code is accepted by the C compiler, then @.B cproto will probably accept it as well. @.SH "SEE ALSO" cc(1), cpp(1) @//E*O*F cproto.1// chmod u=r,g=r,o=r cproto.1 echo x - cproto.sh sed 's/^@//' > "cproto.sh" <<'@//E*O*F cproto.sh//' #!/bin/sh # $Header$ # cpp_opt="-I." cproto_opt="" source="" for opt do case $opt in -D*|-U*|-I*) cpp_opt="$cpp_opt $opt" ;; -*) cproto_opt="$cproto_opt $opt" ;; *) source=$opt ;; esac done /lib/cpp $cpp_opt $source | cproto1 $cproto_opt @//E*O*F cproto.sh// chmod u=rwx,g=r,o=r cproto.sh echo x - grammar.y sed 's/^@//' > "grammar.y" <<'@//E*O*F grammar.y//' /* * $Header: grammar.y,v 1.1 89/03/14 20:59:01 cthuang Exp $ * * yacc grammar for C prototype generator * This was derived from the grammar given in Appendix A of * "The C Programming Language" by the Kernighan and Ritchie. */ /* identifiers that are not reserved words */ %token IDENTIFIER TYPEDEF_NAME /* storage class */ %token AUTO EXTERN REGISTER STATIC TYPEDEF /* type specifiers */ %token CHAR DOUBLE FLOAT INT VOID %token LONG SHORT SIGNED UNSIGNED %token ENUM STRUCT UNION /* type qualifiers */ %token CONST VOLATILE /* paired braces and everything between them: { ... } */ %token BRACES /* paired square brackets and everything between them: [ ... ]*/ %token BRACKETS /* three periods */ %token ELLIPSIS /* equal sign followed by constant expression or stuff between braces */ %token INITIALIZER %type <decl_spec> decl_specs decl_spec_item %type <decl_spec> storage_class type_spec type_qualifier %type <decl_spec> struct_union_spec enum_spec %type <decl_list> init_decl_list %type <declarator> init_declarator declarator direct_decl %type <param_list> param_type_list param_list %type <parameter> param_decl %type <param_list> identifier_list ident_list %type <text> struct_or_union %type <text> pointer type_qual_list %type <text> IDENTIFIER TYPEDEF_NAME %type <text> BRACKETS %{ #include <stdio.h> #include "cproto.h" #include "semantics.h" /* This variable is TRUE when the parameter declaration part of a function * definition is currently being parsed. * For example: * int * main (argc, argv) * int argc; | TRUE when these lines * char **argv; | are being scanned. * { * ... * } */ static boolean func_decl = FALSE; /* This points to the list of parameters for the current function definition. */ static ParameterList *cur_params; /* temporary string buffer */ static char buf[MAX_TEXT_LENGTH]; /* Table of typedef names */ SymbolTable *typedef_names; %} %% program : /* empty */ | translation_unit ; translation_unit : external_decl | translation_unit external_decl ; external_decl : declaration | function_def | error ; declaration : decl_specs ';' | decl_specs init_decl_list ';' { if (func_decl) { set_param_types(cur_params, &$1, &$2); } else { output_declarations(&$1, &$2); } free_decl_spec(&$1); free_decl_list(&$2); } | TYPEDEF decl_specs declarator ';' { (void)new_symbol(typedef_names, $3.name); free_decl_spec(&$2); free_declarator(&$3); } ; function_def : decl_specs declarator { if ($2.func_def == FUNC_DEF_NONE) { yyerror("syntax error"); YYERROR; } func_decl = TRUE; cur_params = &($2.params); } opt_decl_list BRACES { func_decl = FALSE; output_prototype(&$1, &$2); free_decl_spec(&$1); free_declarator(&$2); } | declarator { if ($1.func_def == FUNC_DEF_NONE) { yyerror("syntax error"); YYERROR; } func_decl = TRUE; cur_params = &($1.params); } opt_decl_list BRACES { DeclSpec decl_spec; func_decl = FALSE; new_decl_spec(&decl_spec, "int", DE_EXTERN); output_prototype(&decl_spec, &$1); free_decl_spec(&decl_spec); free_declarator(&$1); } ; decl_list : declaration | decl_list declaration ; decl_specs : decl_spec_item | decl_specs decl_spec_item { join_decl_specs(&$$, &$1, &$2); } ; decl_spec_item : storage_class | type_spec | type_qualifier ; opt_decl_list : decl_list | /* empty */ ; storage_class : AUTO { new_decl_spec(&$$, "auto", DE_JUNK); } | EXTERN { new_decl_spec(&$$, "extern", DE_EXTERN); } | REGISTER { new_decl_spec(&$$, "register", DE_JUNK); } | STATIC { new_decl_spec(&$$, "static", DE_STATIC); } ; type_spec : CHAR { new_decl_spec(&$$, "char", DE_EXTERN); } | DOUBLE { new_decl_spec(&$$, "double", DE_EXTERN); } | FLOAT { new_decl_spec(&$$, "float", DE_EXTERN); } | INT { new_decl_spec(&$$, "int", DE_EXTERN); } | LONG { new_decl_spec(&$$, "long", DE_EXTERN); } | SHORT { new_decl_spec(&$$, "short", DE_EXTERN); } | SIGNED { new_decl_spec(&$$, "signed", DE_EXTERN); } | UNSIGNED { new_decl_spec(&$$, "unsigned", DE_EXTERN); } | VOID { new_decl_spec(&$$, "void", DE_EXTERN); } | struct_union_spec | enum_spec | TYPEDEF_NAME { new_decl_spec(&$$, $1, DE_EXTERN); } ; type_qualifier : CONST { new_decl_spec(&$$, "const", DE_EXTERN); } | VOLATILE { new_decl_spec(&$$, "volatile", DE_EXTERN); } ; struct_union_spec : struct_or_union IDENTIFIER BRACES { sprintf(buf, "%s %s {}", $1, $2); new_decl_spec(&$$, buf, DE_EXTERN); } | struct_or_union BRACES { sprintf(buf, "%s {}", $1); new_decl_spec(&$$, buf, DE_EXTERN); } | struct_or_union IDENTIFIER { sprintf(buf, "%s %s", $1, $2); new_decl_spec(&$$, buf, DE_EXTERN); } ; struct_or_union : STRUCT { strcpy($$, "struct"); } | UNION { strcpy($$, "union"); } ; init_decl_list : init_declarator { new_decl_list(&$$, &$1); } | init_decl_list ',' init_declarator { add_decl_list(&$$, &$1, &$3); } ; init_declarator : declarator | declarator INITIALIZER ; enum_spec : ENUM IDENTIFIER BRACES { sprintf(buf, "enum %s {}", $2); new_decl_spec(&$$, buf, DE_EXTERN); } | ENUM BRACES { new_decl_spec(&$$, "enum {}", DE_EXTERN); } | ENUM IDENTIFIER { sprintf(buf, "enum %s", $2); new_decl_spec(&$$, buf, DE_EXTERN); } ; declarator : pointer direct_decl { sprintf(buf, "%s%s", $1, $2.text); $$ = $2; $$.text = strdup(buf); free($2.text); } | direct_decl ; direct_decl : IDENTIFIER { new_declarator(&$$, $1, $1); } | '(' declarator ')' { sprintf(buf, "(%s)", $2.text); $$ = $2; $$.text = strdup(buf); free($2.text); } | direct_decl BRACKETS { sprintf(buf, "%s%s", $1.text, $2); $$ = $1; $$.text = strdup(buf); free($1.text); } | direct_decl '(' param_type_list ')' { sprintf(buf, "%s(%%s)", $1.text); $$ = $1; $$.func_def = FUNC_DEF_NEW; $$.params = $3; $$.text = strdup(buf); free($1.text); } | direct_decl '(' identifier_list ')' { sprintf(buf, "%s(%%s)", $1.text); $$ = $1; $$.func_def = FUNC_DEF_OLD; $$.params = $3; $$.text = strdup(buf); free($1.text); } ; pointer : '*' type_qual_list { sprintf($$, "*%s", $2); } | '*' type_qual_list pointer { sprintf($$, "*%s%s", $2, $3); } ; type_qual_list : /* empty */ { strcpy($$, ""); } | type_qual_list type_qualifier { sprintf($$, "%s %s ", $1, $2.text); free($2.text); } ; param_type_list : VOID { Parameter p; new_parameter(&p, "void", " ", " "); new_param_list(&$$, &p); } | param_list | param_list ',' ELLIPSIS { Parameter p; new_parameter(&p, "...", " ", " "); add_param_list(&$$, &$1, &p); } ; param_list : param_decl { new_param_list(&$$, &$1); } | param_list ',' param_decl { add_param_list(&$$, &$1, &$3); } ; param_decl : decl_specs declarator { new_parameter(&$$, $1.text, $2.text, $2.name); } ; identifier_list : /* empty */ { new_ident_list(&$$); } | ident_list ; ident_list : IDENTIFIER { new_ident_list(&$$); add_ident_list(&$$, &$$, $1); } | ident_list ',' IDENTIFIER { add_ident_list(&$$, &$1, $3); } ; %% #include "lex.yy.c" yyerror (msg) char *msg; { print_error(msg); } void parse_file () { typedef_names = create_symbol_table(); (void)yyparse(); } @//E*O*F grammar.y// chmod u=rw,g=r,o=r grammar.y echo x - lex.l sed 's/^@//' > "lex.l" <<'@//E*O*F lex.l//' /* * $Header: lex.l,v 1.1 89/03/14 20:59:10 cthuang Exp $ * * C function prototype generator * Lexical analyzer specification for flex */ WLF ([ \t\n\f]*) LETTER [a-zA-Z_] DIGIT [0-9] ID {LETTER}({LETTER}|{DIGIT})* SKIPQUOTED (\"([^"\n]|\\\")*\"|\'.\'|\\.) %{ static int curly = 0; /* number of curly brace nesting levels */ int line_num = 1; %} %x INIT1 INIT2 CURLY COMMENT %% \n { ++line_num; } #[ \t]*[0-9]+.*$ { sscanf(yytext, "# %d ", &line_num); --line_num; } #.*$ ; "(" return '('; ")" return ')'; "*" return '*'; "," return ','; ";" return ';'; "..." return ELLIPSIS; auto return AUTO; extern return EXTERN; register return REGISTER; static return STATIC; typedef return TYPEDEF; char return CHAR; double return DOUBLE; float return FLOAT; int return INT; void return VOID; long return LONG; short return SHORT; signed return SIGNED; unsigned return UNSIGNED; enum return ENUM; struct return STRUCT; union return UNION; const return CONST; volatile return VOLATILE; \[[^\]]*\] { strcpy(yylval.text, yytext); return BRACKETS; } {ID} { strcpy(yylval.text, yytext); if (is_typedef_name(yytext)) return TYPEDEF_NAME; else return IDENTIFIER; } "="{WLF}"{" { curly = 1; BEGIN INIT1; } <INIT1>\n { ++line_num; } <INIT1>"{" ++curly; <INIT1>"}" { if (--curly == 0) { BEGIN 0; return INITIALIZER; } } <INIT1>{SKIPQUOTED}|. ; "=" { BEGIN INIT2; } <INIT2>\n { ++line_num; } <INIT2>({SKIPQUOTED}|[^,;])+[,;] { yyless(yyleng-1); BEGIN 0; return INITIALIZER; } "{" { curly=1; BEGIN CURLY; } <CURLY>\n { ++line_num; } <CURLY>"{" { ++curly; } <CURLY>"}" { --curly; if (curly == 0) { BEGIN 0; return BRACES; } } <CURLY>{SKIPQUOTED}|. ; "/*" BEGIN COMMENT; <COMMENT>\n { ++line_num; } <COMMENT>"*/" BEGIN 0; <COMMENT>. ; [ \t]+ ; @. print_error("syntax error"); @//E*O*F lex.l// chmod u=rw,g=r,o=r lex.l echo x - cproto.h sed 's/^@//' > "cproto.h" <<'@//E*O*F cproto.h//' /* * $Header: cproto.h,v 1.1 89/03/14 20:59:12 cthuang Exp $ * * Definitions for C language prototype generator */ #include "symbol.h" /* Boolean type */ typedef char boolean; #define FALSE 0 #define TRUE 1 /* maximum number of characters in a text buffer */ #define MAX_TEXT_LENGTH 512 /* Declaration specifier flags */ #define DE_EXTERN 0 /* default: declaration has global scope */ #define DE_STATIC 1 /* visible only in current file */ #define DE_JUNK 2 /* we're not interested in this declaration */ /* This structure stores information about a declaration specifier. */ typedef struct _decl_spec { unsigned short flags; /* flags defined above */ char *text; /* source text */ } DeclSpec; /* Types of function definitions * * FUNC_DEF_OLD traditional style function definition * FUNC_DEF_NEW ANSI style */ typedef enum { FUNC_DEF_NONE, FUNC_DEF_OLD, FUNC_DEF_NEW } FuncDefType; /* This structure stores information about a function parameter. */ typedef struct _parameter { char *decl_spec; /* declaration specifier text */ char *declarator; /* declarator text */ char *name; /* parameter name */ struct _parameter *next; /* next parameter in list */ } Parameter; /* This is a list of function parameters. */ typedef struct _parameter_list { Parameter *first; /* pointer to first parameter in list */ Parameter *last; /* pointer to last parameter in list */ } ParameterList; /* This structure stores information about a declarator. */ typedef struct _declarator { char *name; /* name of declared variable or function */ char *text; /* source text */ FuncDefType func_def; /* style of function definition */ ParameterList params; /* list of parameters if this is a function */ struct _declarator *next; /* next declarator in list */ } Declarator; /* This is a list of declarators. */ typedef struct _declarator_list { Declarator *first; /* pointer to first declarator in list */ Declarator *last; /* pointer to last declarator in list */ } DeclaratorList; /* parser stack entry type */ typedef union { char text[MAX_TEXT_LENGTH]; DeclSpec decl_spec; Parameter parameter; ParameterList param_list; Declarator declarator; DeclaratorList decl_list; } YYSTYPE; /* Program options */ extern boolean extern_out; extern boolean globals_only; extern int proto_style; extern boolean variables_out; /* Global declarations */ extern int line_num; extern SymbolTable *typedef_names; extern void print_error(); extern void parse_file(); extern char *strdup(), *strstr(); extern char *malloc(); @//E*O*F cproto.h// chmod u=rw,g=r,o=r cproto.h echo x - patchlevel.h sed 's/^@//' > "patchlevel.h" <<'@//E*O*F patchlevel.h//' #define PATCHLEVEL 0 @//E*O*F patchlevel.h// chmod u=rw,g=r,o=r patchlevel.h echo x - semantics.h sed 's/^@//' > "semantics.h" <<'@//E*O*F semantics.h//' /* * $Header: semantics.h,v 1.1 89/03/14 20:59:16 cthuang Exp $ * * Declarations for semantics action routines */ extern boolean is_typedef_name(); extern void new_decl_spec(); extern void join_decl_specs(); extern void free_decl_spec(); extern void new_parameter(); extern void free_parameter(); extern void new_param_list(); extern void add_param_list(); extern void free_param_list(); extern void new_ident_list(); extern void add_ident_list(); extern void new_declarator(); extern void free_declarator(); extern void new_decl_list(); extern void add_decl_list(); extern void free_decl_list(); extern void set_param_types(); extern void output_declarations(); extern void output_prototype(); @//E*O*F semantics.h// chmod u=rw,g=r,o=r semantics.h echo x - symbol.h sed 's/^@//' > "symbol.h" <<'@//E*O*F symbol.h//' /* * $Header: symbol.h,v 1.1 89/03/14 20:59:18 cthuang Exp $ * * Definitions for a symbol table */ #ifndef _SYMBOL_H #define _SYMBOL_H /* maximum length of symbols */ #define SYM_MAX_LENGTH 64 typedef struct _symbol { struct _symbol *next; /* next symbol in list */ char name[SYM_MAX_LENGTH]; /* name of symbol */ } Symbol; /* hash table length */ #define SYM_MAX_HASH 256 typedef struct _symbol_table { Symbol *bucket[SYM_MAX_HASH]; /* hash buckets */ } SymbolTable; extern SymbolTable *create_symbol_table(); /* Create symbol table */ extern Symbol *find_symbol(); /* Lookup symbol name */ extern Symbol *new_symbol(); /* Define new symbol */ #endif @//E*O*F symbol.h// chmod u=rw,g=r,o=r symbol.h echo x - cproto1.c sed 's/^@//' > "cproto1.c" <<'@//E*O*F cproto1.c//' /* * $Header: cproto1.c,v 1.1 89/03/14 20:59:21 cthuang Exp $ * * C prototype generator * This filter reads C source code and outputs ANSI C function prototypes. */ #ifndef lint static char *rcsid = "$Header: cproto1.c,v 1.1 89/03/14 20:59:21 cthuang Exp $"; #endif #include <stdio.h> #include "cproto.h" /* getopt declarations */ extern int getopt(); extern char *optarg; extern int optind; /* Name of the program */ static char *progname = "cproto"; /* Program options */ /* TRUE when "extern" should appear to external declarations. */ boolean extern_out = FALSE; /* TRUE when only external declarations will be generated. */ boolean globals_only = FALSE; /* This variable controls the style of function prototype. */ int proto_style = 2; /* TRUE when variable declarations are printed also. */ boolean variables_out = FALSE; /* Output an error message along with the line number where it was found. */ void print_error (msg) char *msg; { fprintf(stderr, "%s: line %d: %s\n", progname, line_num, msg); } main (argc, argv) int argc; char **argv; { int c; boolean error_flag; error_flag = FALSE; while ((c = getopt(argc, argv, "egp:v")) != EOF) { switch (c) { case 'e': extern_out = TRUE; break; case 'g': globals_only = TRUE; break; case 'p': proto_style = atoi(optarg); break; case 'v': variables_out = TRUE; break; case '?': default: error_flag = TRUE; } } if (optind == argc-1) { if (freopen(argv[optind], "r", stdin) == NULL) { fprintf(stderr, "%s: cannot open file %s\n", progname, argv[optind]); exit(1); } } else { error_flag = (boolean)(optind < argc-1); } if (error_flag) { fprintf(stderr, "usage: %s [ -egv ] [ -p n ] [ file ]\n", progname); exit(1); } parse_file(); } @//E*O*F cproto1.c// chmod u=rw,g=r,o=r cproto1.c echo x - semantics.c sed 's/^@//' > "semantics.c" <<'@//E*O*F semantics.c//' /* * $Header: semantics.c,v 1.1 89/03/14 20:59:22 cthuang Exp $ * * C prototype generator * These routines implement the semantic actions executed by the yacc parser. * */ #include <stdio.h> #include <strings.h> #include "cproto.h" #include "semantics.h" /* Create a new string by joining two strings with a space between them. * Return a pointer to the resultant string or NULL if an error occurred. */ static char * concat_string (a, b) char *a, *b; { char *result; if ((result = malloc((unsigned)(strlen(a) + strlen(b) + 2))) != NULL) { strcpy(result, a); strcat(result, " "); strcat(result, b); } return result; } /* Delete the first occurence of a substring from a string. * Return a pointer to a static buffer containing the result. * If the substring is not found, then return the entire string. */ static char * delete_string (src, key) char *src, *key; { static char buf[MAX_TEXT_LENGTH]; char *s; int n; if ((s = strstr(src, key)) == NULL) { strcpy(buf, src); } else { strcpy(buf, ""); n = s - src; if (n > 0) strncat(buf, src, n); n = strlen(src) - n - strlen(key); if (n > 0) strncat(buf, s+strlen(key), n); } return buf; } /* Check if the given identifier is really a typedef name by searching the * symbol table. * Return TRUE if it is a typedef name. */ boolean is_typedef_name (name) char *name; { return (boolean)(find_symbol(typedef_names, name) != NULL); } /* Initialize a new declaration specifier part. */ void new_decl_spec (decl_spec, text, flags) DeclSpec *decl_spec; char *text; unsigned short flags; { decl_spec->text = strdup(text); decl_spec->flags = flags; } /* Append two declaration specifier parts together. */ void join_decl_specs (result, a, b) DeclSpec *result, *a, *b; { result->text = concat_string(a->text, b->text); result->flags = a->flags | b->flags; free(a->text); free(b->text); } /* Free storage used by a declaration specifier part. */ void free_decl_spec (decl_spec) DeclSpec *decl_spec; { if (decl_spec->text != NULL) free(decl_spec->text); } /* Initialize the parameter structure. */ void new_parameter (param, decl_spec, declarator, name) Parameter *param; char *decl_spec, *declarator, *name; { param->decl_spec = strdup(decl_spec); param->declarator = strdup(delete_string(declarator, "%s")); param->name = strdup(name); } /* Free the storage used by the parameter. */ void free_parameter (param) Parameter *param; { if (param->decl_spec != NULL) free(param->decl_spec); if (param->declarator != NULL) free(param->declarator); free(param->name); } /* Initialize an empty list of function parameters. */ void new_param_list (param_list, param) ParameterList *param_list; Parameter *param; { Parameter *p; p = (Parameter *)malloc(sizeof(Parameter)); *p = *param; param_list->first = param_list->last = p; p->next = NULL; } /* Add the function parameter declaration to the list. */ void add_param_list (to, from, param) ParameterList *to, *from; Parameter *param; { Parameter *p; p = (Parameter *)malloc(sizeof(Parameter)); *p = *param; to->first = from->first; from->last->next = p; to->last = p; p->next = NULL; } /* Free storage used by the elements in the function parameter list. */ void free_param_list (param_list) ParameterList *param_list; { Parameter *p, *next; p = param_list->first; while (p != NULL) { next = p->next; free_parameter(p); free((char *)p); p = next; } } /* Initialize an empty list of function parameter names. * This is just a list of function parameter declarations with * only the name field set. */ void new_ident_list (param_list) ParameterList *param_list; { param_list->first = param_list->last = NULL; } /* Add an item to the list of function parameter declarations but set only * the parameter name field. */ void add_ident_list (to, from, name) ParameterList *to, *from; char *name; { Parameter *p; p = (Parameter *)malloc(sizeof(Parameter)); p->decl_spec = NULL; p->declarator = NULL; p->name = strdup(name); to->first = from->first; if (to->first == NULL) { to->first = p; } else { from->last->next = p; } to->last = p; p->next = NULL; } /* Initialize a declarator. */ void new_declarator (d, name, text) Declarator *d; char *name, *text; { d->name = strdup(name); d->text = strdup(text); d->func_def = FUNC_DEF_NONE; d->params.first = d->params.last = NULL; } /* Free storage used by a declarator. */ void free_declarator (d) Declarator *d; { if (d->name != NULL) free(d->name); if (d->text != NULL) free(d->text); free_param_list(&(d->params)); } /* Initialize a declarator list and add the given declarator to it. */ void new_decl_list (decl_list, declarator) DeclaratorList *decl_list; Declarator *declarator; { Declarator *d; d = (Declarator *)malloc(sizeof(Declarator)); *d = *declarator; decl_list->first = decl_list->last = d; d->next = NULL; } /* Add the declarator to the declarator list. */ void add_decl_list (to, from, declarator) DeclaratorList *to, *from; Declarator *declarator; { Declarator *d; d = (Declarator *)malloc(sizeof(Declarator)); *d = *declarator; to->first = from->first; from->last->next = d; to->last = d; to->last->next = NULL; } /* Free storage used by the declarators in the declarator list. */ void free_decl_list (decl_list) DeclaratorList *decl_list; { Declarator *d, *next; d = decl_list->first; while (d != NULL) { next = d->next; free_declarator(d); free((char *)d); d = next; } } /* Search the list of parameters for a matching parameter name. * Return a pointer to the matching parameter or NULL if not found. */ static Parameter * search_parameter_list (params, name) ParameterList *params; char *name; { Parameter *p; for (p = params->first; p != NULL; p = p->next) { if (strcmp(p->name, name) == 0) return p; } return (Parameter *)NULL; } /* For each declared variable name in the declarator list, * set the declaration specifier and declarator for the parameter * with the same name. */ void set_param_types (params, decl_spec, declarators) ParameterList *params; DeclSpec *decl_spec; DeclaratorList *declarators; { Declarator *d; Parameter *p; char buf[MAX_TEXT_LENGTH]; for (d = declarators->first; d != NULL; d = d->next) { /* Search the parameter list for a matching name. */ p = search_parameter_list(params, d->name); if (p == NULL) { sprintf(buf, "declared argument \"%s\" is missing", d->name); print_error(buf); } else { p->decl_spec = strdup(decl_spec->text); p->declarator = strdup(delete_string(d->text, "%s")); } } } /* Output a declaration specifier for an external declaration. */ static void output_decl_spec (decl_spec) DeclSpec *decl_spec; { if (extern_out && (decl_spec->flags & DE_STATIC) == 0) { if (strstr(decl_spec->text, "extern") == NULL) { printf("extern "); } } printf("%s ", decl_spec->text); } /* Output a function parameter type and variable declaration. */ static void output_parameter (p) Parameter *p; { char *s; if (proto_style == 1) { s = strstr(p->declarator, p->name); *s = '\0'; printf("%s %s/*%s*/%s", p->decl_spec, p->declarator, p->name, s+strlen(p->name)); *s = *(p->name); } else { printf("%s %s", p->decl_spec, p->declarator); } } /* Output the list of function parameters. */ static void output_parameters (params) ParameterList *params; { Parameter *p; if (proto_style == 0) printf("/*"); p = params->first; if (p == NULL) { printf("void"); } else { output_parameter(p); p = p->next; while (p != NULL) { printf(", "); output_parameter(p); p = p->next; } } if (proto_style == 0) printf("*/"); } /* Output a declarator. */ static void output_declarator (d) Declarator *d; { char *s; if (d->func_def == FUNC_DEF_NONE) { printf("%s", d->text); } else { if ((s = strstr(d->text, "%s")) != NULL) { *s = '\0'; printf("%s", d->text); output_parameters(&(d->params)); printf("%s", s+2); *s = '%'; } } } /* Output variable declarations. */ void output_declarations (decl_spec, decl_list) DeclSpec *decl_spec; /* declaration specifier */ DeclaratorList *decl_list; /* list of declared variables */ { Declarator *d; if (variables_out == FALSE) return; if (globals_only && (decl_spec->flags & DE_STATIC)) return; for (d = decl_list->first; d != NULL; d = d->next) { if (d->func_def == FUNC_DEF_NONE) { if (strstr(decl_spec->text, "extern") == NULL) { output_decl_spec(decl_spec); output_declarator(d); printf(";\n"); } } } } /* Output the prototype for the function definition. */ void output_prototype (decl_spec, declarator) DeclSpec *decl_spec; Declarator *declarator; { Parameter *p; if (globals_only && (decl_spec->flags & DE_STATIC)) return; /* Check for function parameters for which no type has been specified. * This happens when a parameter name appears in the function * declaration but does not appear in the parameter declaration part. * The default type in this cause is "int". */ for (p = declarator->params.first; p != NULL; p = p->next) { if (p->decl_spec == NULL) { p->decl_spec = strdup("int"); p->declarator = strdup(p->name); } } output_decl_spec(decl_spec); output_declarator(declarator); printf(";\n"); } @//E*O*F semantics.c// chmod u=rw,g=r,o=r semantics.c echo x - string.c sed 's/^@//' > "string.c" <<'@//E*O*F string.c//' /* * $Header: string.c,v 1.1 89/03/14 20:59:24 cthuang Exp $ * * Some are string handling routines */ #include <stdio.h> #include <strings.h> extern char *malloc(); /* Copy the string into an allocated memory block. * Return a pointer to the copy. */ char * strdup (s) char *s; { char *dest; if ((dest = malloc((unsigned)(strlen(s)+1))) != NULL) strcpy(dest, s); return dest; } /* Return a pointer to the first occurence of the substring * within the string, or NULL if not found. */ char * strstr (src, key) char *src, *key; { char *s; int keylen; keylen = strlen(key); s = index(src, *key); while (s != NULL) { if (strncmp(s, key, keylen) == 0) return s; s = index(s+1, *key); } return NULL; } @//E*O*F string.c// chmod u=rw,g=r,o=r string.c echo x - symbol.c sed 's/^@//' > "symbol.c" <<'@//E*O*F symbol.c//' /* * $Header: symbol.c,v 1.1 89/03/14 20:59:26 cthuang Exp $ * * Symbol table maintenance. Implements an abstract data type called * the symbol table. */ #include <stdio.h> #include <strings.h> #include "symbol.h" extern char *malloc(); /* Create a symbol table. * Return a pointer to the symbol table or NULL if an error occurs. */ SymbolTable * create_symbol_table () { SymbolTable *symtab; int i; if ((symtab = (SymbolTable *)malloc(sizeof(SymbolTable))) != NULL) { for (i = 0; i < SYM_MAX_HASH; ++i) symtab->bucket[i] = NULL; } return symtab; } /* This is a simple hash function mapping a symbol name to a hash bucket. */ static int hash (name) char *name; { return (name[0] + name[1] + strlen(name)) % SYM_MAX_HASH; } /* Search the list of symbols <list> for the symbol <name>. * Return a pointer to the symbol or NULL if not found. */ static Symbol * search_symbol_list (list, name) Symbol *list; char *name; { Symbol *sym; for (sym = list; sym != NULL; sym = sym->next) { if (strncmp(sym->name, name, SYM_MAX_LENGTH-1) == 0) return sym; } return NULL; } /* Look for symbol <name> in symbol table <symtab>. * Return a pointer to the symbol or NULL if not found. */ Symbol * find_symbol (symtab, name) SymbolTable *symtab; char *name; { return search_symbol_list(symtab->bucket[hash(name)], name); } /* If the symbol <name> does not already exist in symbol table <symtab>, * then add the symbol to the symbol table. * Return a pointer to the symbol or NULL on an error. */ Symbol * new_symbol (symtab, name) SymbolTable *symtab; /* symbol table */ char *name; /* symbol name */ { Symbol *sym; int i; if ((sym = find_symbol(symtab, name)) == NULL) { if ((sym = (Symbol *)malloc(sizeof(Symbol))) != NULL) { strncpy(sym->name, name, SYM_MAX_LENGTH-1); sym->name[SYM_MAX_LENGTH-1] = '\0'; i = hash(name); sym->next = symtab->bucket[i]; symtab->bucket[i] = sym; } } return sym; } @//E*O*F symbol.c// chmod u=rw,g=r,o= symbol.c echo Inspecting for damage in transit... temp=/tmp/shar$$; dtemp=/tmp/.shar$$ trap "rm -f $temp $dtemp; exit" 0 1 2 3 15 cat > $temp <<\!!! 9 50 344 README 43 110 826 Makefile 105 402 2247 cproto.1 20 32 264 cproto.sh 432 939 7877 grammar.y 103 263 1946 lex.l 86 373 2616 cproto.h 1 3 21 patchlevel.h 32 75 707 semantics.h 28 98 673 symbol.h 88 272 1827 cproto1.c 466 1296 9642 semantics.c 43 124 759 string.c 93 308 2014 symbol.c 1549 4345 31763 total !!! wc README Makefile cproto.1 cproto.sh grammar.y lex.l cproto.h patchlevel.h semantics.h symbol.h cproto1.c semantics.c string.c symbol.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp if [ -s $dtemp ] then echo "Ouch [diff of wc output]:" ; cat $dtemp else echo "No problems found." fi exit 0 -- cthuang@watdragon.uwaterloo.ca cthuang@watdragon.waterloo.edu cthuang@watdragon.waterloo.cdn {uunet,utzoo}!watmath!watdragon!cthuang -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.