home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume3
/
proto
/
proto.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-02-03
|
10KB
|
472 lines
/*
* 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;
}