home *** CD-ROM | disk | FTP | other *** search
- /*
- * Prototypes builder...
- * =====================
- *
- * Copyright (C) Duncan White, 1987 & 1988.
- *
- ****** Restrictions on use
- *
- * Anyone may use, adapt and extend this program in any way they like,
- * subject to the following:
- *
- * 1). my name is not removed.
- * 2). your name is appended if you change it, detailing the changes
- * you made.
- * 3). you don't make any money out of it without consulting me.
- * 4). you don't attempt to alter this 'restrictions on use' section.
- *
- * In other words, share & enjoy...
- *
- ****** Purpose
- *
- * This program attempts to build a file of external declarations
- * [prototypes] for all the functions declared in a given C file.
- * It produces this list in two forms:
- *
- * #ifdef HASPROTOS
- * <nice external prototype declarations>
- * #else
- * <old ikky external declarations for UNIX C compilers>
- * #endif
- *
- * You can then incorporate the file generated into your .h files.
- * Make sure you #define HASPROTOS iff your compiler supports
- * prototypes: otherwise you'll lose all the advantages.
- *
- * Alternatively, if you give the -f [function] option, the program will
- * instead produce a pretty printed text form of the function
- * declarations it parses.
- *
- ****** How does it do it:
- *
- * The program parses EACH LINE of a C source file to see whether it
- * satisfies the grammar shown below. If it does, the appropriate
- * declarations is bunged out onto the output stream.
- *
- * Unfortunately, this implies that an entire function declaration
- * must be on a single line.... sorry to all those who don't use this
- * convention: I didn't feel up to writing a full C parser, or a
- * backtracking parser!
- *
- ****** The Grammar
- *
- * The grammar is restricted; in particular, it omits:
- *
- * 1). function parameters (use typedef!),
- * 2). array parameters (I use pointers instead),
- * 3). and struct parameters not concealed by #define's or typedef's.
- *
- * function_declaration = [ starred_id ] id '(' idlist ')' tslist
- * idlist = empty | id list{ ',' id }
- * tslist = list{ typespec } ( EOL | '{' )
- * typespec = id starred_id list{ ',' starred_id } ';'
- * starred_id = {'*'} id
- *
- ******* History
- *
- * Version Who Date Comments
- * ======= === ==== ========
- * 1.0 dcw 16th Aug 1987 Wrote it
- * 1.1 dcw 30th Aug 1987 Corrected spaces bug &
- * added #ifdef LATTICE #else
- * 1.2 dcw 9th Sep 1987 Used dcwos.h to determine HASPROTOS
- * 1.3 dcw 25th Feb 1988 Added starred id for return type
- * XNX1.4 dcw 5th April 1988 Ported to Xenix
- * made it accept declns eg. thingy() {..
- * altered arg{c,v} interface.
- * BSD1.4 dcw 7th April 1988 Reverse ported to BSD
- * 1.5 dcw 7th April 1988 Made if and while special cases in
- * get_token
- * 2.0 dcw 2nd July 1988 Made ready for releasing to news...
- */
-
-
- #include "dcw.h"
-
-
- /* ----------------------- Data types ------------------------- */
-
-
- #define ID_LEN 50
- #define LINE_LEN 1024
-
-
- #define FDECL struct anon1
- #define EL_IDLIST struct anon2
- #define EL_TSLIST struct anon3
-
- #define IDLIST EL_IDLIST *
- #define TSLIST EL_TSLIST *
-
- FDECL {
- char ftype[ID_LEN];
- char fname[ID_LEN];
- IDLIST formals;
- TSLIST ftypes;
- };
-
- EL_IDLIST {
- char id[ID_LEN];
- IDLIST next;
- };
-
- EL_TSLIST {
- char type[ID_LEN];
- char var[ID_LEN];
- TSLIST next;
- };
-
-
- /* --------------------- Forward declns ----------------------- */
- /* Guess what generated these then ??? */
-
-
- #ifdef HASPROTOS
- extern void main( int , char ** );
- extern void usage( BOOL );
- extern void out_extern( FILE * , FDECL * , BOOL );
- extern void print_fdecl( FILE * , FDECL * );
- extern void prototype( FILE * , FDECL * , char * );
- extern int readline( FILE * , char * );
- extern void get_token( void );
- extern BOOL parse_function_decln( char * , FDECL * );
- extern BOOL parse_list_id( IDLIST * );
- extern BOOL parse_restof_ids( IDLIST * );
- extern BOOL parse_list_ts( TSLIST * );
- extern BOOL parse_typespec( TSLIST * );
- extern BOOL parse_starred_id( char * , char * );
- #else
- extern void main();
- extern void usage();
- extern void out_extern();
- extern void print_fdecl();
- extern void prototype();
- extern int readline();
- extern void get_token();
- extern BOOL parse_function_decln();
- extern BOOL parse_list_id();
- extern BOOL parse_restof_ids();
- extern BOOL parse_list_ts();
- extern BOOL parse_typespec();
- extern BOOL parse_starred_id();
- #endif
-
-
- /* ---------------------- Main program ------------------------ */
-
-
- void main( argc, argv ) int argc; char **argv;
- {
- FILE *in,*out;
- FDECL f;
- char line[LINE_LEN];
- BOOL origonly;
-
- usage( argc>1 && argc<=4 );
-
- origonly = ( strcmp( argv[1], "-f" ) == 0 );
- if( origonly) {
- int i;
-
- for( i=2; i<argc; i++ ) argv[i-1] = argv[i];
- argc--;
- }
-
- usage( argc > 1 ); /* still at least one argument left */
-
- in = fopen( argv[1], "r" );
- ASSERT( in != NULL, ("Can't open '%s'\n",argv[1]) );
-
- if( argc == 2 ) {
- out = stdout;
- } else {
- out = fopen( argv[2], "w" );
- ASSERT( out != NULL, ("Can't create '%s'\n",argv[2]) );
- }
-
- if( origonly ) {
- while( readline( in, line ) != EOF ) {
- if( parse_function_decln( line, &f ) ) {
- print_fdecl( out, &f );
- }
- }
- } else {
- fprintf( out, "#ifdef HASPROTOS\n" );
- while( readline( in, line ) != EOF ) {
- if( parse_function_decln( line, &f ) ) {
- out_extern( out, &f, TRUE );
- }
- }
- fprintf( out, "#else\n" );
- fseek( in, 0L, 0 );
- while( readline( in, line ) != EOF ) {
- if( parse_function_decln( line, &f ) ) {
- out_extern( out, &f, FALSE );
- }
- }
- fprintf( out, "#endif\n" );
- }
- fclose( in );
- fclose( out );
- exit( 0 );
- }
-
-
- void usage(b) BOOL b;
- {
- ASSERT( b, ("Usage: proto [-f] infile [outfile]\n") );
- }
-
-
- void out_extern( out, f, b ) FILE *out; FDECL *f; BOOL b;
- {
- IDLIST i;
-
- fprintf( out, "extern %s %s(", f->ftype, f->fname );
- if( b ) {
- if( f->formals ) {
- prototype( out, f, f->formals->id );
- for( i=f->formals->next; i; i=i->next ) {
- fprintf( out, "," );
- prototype( out, f, i->id );
- }
- } else {
- fprintf( out, " void " );
- }
- }
- fprintf( out, ");\n" );
- }
-
-
- /* print the original form of the function declaration */
-
- void print_fdecl( out, f ) FILE *out; FDECL *f;
- {
- IDLIST i;
- TSLIST t;
-
- fprintf( out, "%s %s(", f->ftype, f->fname );
- if( f->formals ) {
- fprintf( out, "%s", f->formals->id );
- for( i=f->formals->next; i; i=i->next ) {
- fprintf( out, ", %s", i->id );
- }
- }
- fprintf( out, ")" );
- for( t=f->ftypes; t; t=t->next ) {
- fprintf( out, " %s %s;", t->type, t->var );
- }
- fprintf( out, " \n" );
- }
-
-
- void prototype( out, f, name ) FILE *out; FDECL *f; char *name;
- {
- TSLIST t;
-
- for( t=f->ftypes; t; t=t->next ) {
- if( streq( name, t->var ) ) {
- fprintf( out, " %s ", t->type );
- return;
- }
- }
- fprintf( stderr, "warning: %s has undeclared formal '%s' => integer\n",
- f->fname, name );
- fprintf( out, " int" );
- }
-
-
- int readline( f, line ) FILE *f; char *line;
- {
- int c;
- char *p = line;
-
- c=getc(f);
- if( c==EOF ) return c;
- ungetc( c, f );
- while( (c=getc(f)) != '\n' ) *p++ = c;
- *p = '\0';
- return p-line;
- }
-
-
- /* ----------------- Lexer routines ---------------------- */
-
-
- char *lex_line;
- char tokstr[100];
- enum token_type {
- tID, tSTAR, tSEMI, tCOMMA, tOPEN, tCLOSE, tEOL, tBRACE, tERR
- } token;
-
-
- void get_token()
- {
- char *s = tokstr;
- char c;
-
- while( *lex_line == ' ' || *lex_line == '\t' ) lex_line++;
- c = *lex_line++;
- *s++ = c;
- *s = '\0';
-
- switch( c ) {
- case '\0' : token = tEOL ; break;
- case ',' : token = tCOMMA ; break;
- case ';' : token = tSEMI ; break;
- case '*' : token = tSTAR ; break;
- case '(' : token = tOPEN ; break;
- case '{' : token = tBRACE; break;
- case ')' : token = tCLOSE ; break;
- default :
- if( !isalpha( c ) ) {
- token = tERR;
- } else {
- while( (c = *lex_line)=='_'||isalnum(c) ) {
- *s++ = c; lex_line++;
- }
- *s = '\0';
- if( strcmp(tokstr,"if") == 0
- || strcmp(tokstr,"while") == 0
- || strcmp(tokstr,"switch") == 0
- ) {
- token = tERR;
- } else {
- token = tID;
- }
- }
- }
- }
-
-
- /* ------------------- Parser routines ------------------- */
-
-
- BOOL parse_function_decln( line, f ) char *line; FDECL *f;
- {
- char stars [ID_LEN];
- char basetype[ID_LEN];
-
- lex_line = line;
- get_token();
- if( token != tID ) return FALSE;
-
- strcpy( basetype, tokstr );
- get_token();
- if( token == tOPEN ) {
- strcpy( f->fname, basetype );
- strcpy( f->ftype, "int" );
- } else {
- if( ! parse_starred_id( stars, f->fname ) ) return FALSE;
-
- if( *stars == '\0' ) {
- strcpy( f->ftype, basetype );
- } else {
- sprintf( f->ftype, "%s %s", basetype, stars );
- }
- if( token != tOPEN ) return FALSE;
- }
- get_token();
- if( ! parse_list_id( &(f->formals) ) || token != tCLOSE )
- return FALSE;
- get_token();
- return parse_list_ts( &(f->ftypes) );
- }
-
-
- /* attempt to parse an idLIST [possibly empty] */
-
- BOOL parse_list_id( ip ) IDLIST *ip;
- {
- *ip = NULL;
- if( token != tID ) return TRUE;
- *ip = NEW( EL_IDLIST );
- strcpy( (*ip)->id, tokstr );
- get_token();
- return parse_restof_ids( &((*ip)->next) );
- }
-
-
- BOOL parse_restof_ids( ip ) IDLIST *ip;
- {
- *ip = NULL;
- if( token != tCOMMA ) return TRUE;
-
- get_token();
- if( token != tID ) return FALSE;
-
- *ip = NEW( EL_IDLIST );
- strcpy( (*ip)->id, tokstr );
- get_token();
- return parse_restof_ids( &((*ip)->next) );
- }
-
-
- /*
- * attempt to parse a list of typespecs [possibly empty]
- * followed by tEOL or tBRACE
- */
-
- BOOL parse_list_ts( tp ) TSLIST *tp;
- {
- TSLIST t;
-
- for(;;) {
- *tp = NULL;
- if( token==tEOL || token==tBRACE ) return TRUE;
-
- if( ! parse_typespec( tp ) ) return FALSE;
- for( t = *tp; t->next; t=t->next );
- tp = &(t->next);
- }
- /*NOTREACHED*/
- }
-
-
- BOOL parse_typespec( tp ) TSLIST *tp;
- {
- char basetype[ID_LEN];
- char stars [ID_LEN];
-
- if( token != tID ) return FALSE;
- strcpy( basetype, tokstr );
-
- for(;;) {
- get_token();
- *tp = NEW( EL_TSLIST );
- if( ! parse_starred_id( stars, (*tp)->var ) ) return FALSE;
-
- if( *stars == '\0' ) {
- strcpy( (*tp)->type, basetype );
- } else {
- sprintf( (*tp)->type, "%s %s", basetype, stars );
- }
-
- if( token == tSEMI ) {
- get_token();
- return TRUE;
- }
- if( token != tCOMMA ) return FALSE;
- tp = &((*tp)->next);
- }
- /*NOTREACHED*/
- }
-
-
- BOOL parse_starred_id( stars, id ) char *stars, *id;
- {
- BOOL ok;
-
- while( token == tSTAR ) {
- *stars++ = '*';
- get_token();
- }
- *stars = '\0';
- ok = token == tID;
- if( ok ) {
- strcpy( id, tokstr );
- get_token();
- }
- return ok;
- }
-