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

  1. /*
  2.  *            Prototypes builder...
  3.  *            =====================
  4.  *
  5.  *        Copyright (C) Duncan White, 1987 & 1988.
  6.  *
  7.  ****** Restrictions on use
  8.  *
  9.  *    Anyone may use, adapt and extend this program in any way they like,
  10.  *    subject to the following:
  11.  *
  12.  *    1).    my name is not removed.
  13.  *    2).    your name is appended if you change it, detailing the changes
  14.  *        you made.
  15.  *    3).    you don't make any money out of it without consulting me.
  16.  *    4).    you don't attempt to alter this 'restrictions on use' section.
  17.  *
  18.  *    In other words, share & enjoy...
  19.  *
  20.  ****** Purpose
  21.  *
  22.  *    This program attempts to build a file of external declarations
  23.  *    [prototypes] for all the functions declared in a given C file.
  24.  *    It produces this list in two forms:
  25.  *
  26.  *    #ifdef HASPROTOS
  27.  *    <nice external prototype declarations>
  28.  *    #else
  29.  *    <old ikky external declarations for UNIX C compilers>
  30.  *    #endif
  31.  *
  32.  *    You can then incorporate the file generated into your .h files.
  33.  *    Make sure you #define HASPROTOS iff your compiler supports
  34.  *    prototypes: otherwise you'll lose all the advantages.
  35.  *
  36.  *    Alternatively, if you give the -f [function] option, the program will
  37.  *    instead produce a pretty printed text form of the function
  38.  *    declarations it parses.
  39.  *
  40.  ****** How does it do it:
  41.  *
  42.  *    The program parses EACH LINE of a C source file to see whether it
  43.  *    satisfies the grammar shown below. If it does, the appropriate
  44.  *    declarations is bunged out onto the output stream.
  45.  *
  46.  *    Unfortunately, this implies that an entire function declaration
  47.  *    must be on a single line.... sorry to all those who don't use this
  48.  *    convention: I didn't feel up to writing a full C parser, or a
  49.  *    backtracking parser!
  50.  *
  51.  ****** The Grammar
  52.  *
  53.  *    The grammar is restricted; in particular, it omits:
  54.  *
  55.  *    1).    function parameters (use typedef!),
  56.  *    2).    array parameters (I use pointers instead),
  57.  *    3).    and struct parameters not concealed by #define's or typedef's.
  58.  *
  59.  *    function_declaration    = [ starred_id ] id '(' idlist ')' tslist
  60.  *    idlist            = empty | id list{ ',' id }
  61.  *    tslist            = list{ typespec } ( EOL | '{' )
  62.  *    typespec        = id starred_id list{ ',' starred_id } ';'
  63.  *    starred_id        = {'*'} id
  64.  *
  65.  ******* History
  66.  *
  67.  *    Version    Who    Date        Comments
  68.  *    =======    ===    ====        ========
  69.  *    1.0    dcw    16th Aug 1987    Wrote it
  70.  *    1.1    dcw    30th Aug 1987    Corrected spaces bug &
  71.  *                    added #ifdef LATTICE #else
  72.  *    1.2    dcw    9th Sep 1987    Used dcwos.h to determine HASPROTOS
  73.  *    1.3    dcw    25th Feb 1988    Added starred id for return type
  74.  *    XNX1.4    dcw    5th April 1988    Ported to Xenix
  75.  *                    made it accept declns eg. thingy() {..
  76.  *                    altered arg{c,v} interface.
  77.  *    BSD1.4    dcw    7th April 1988    Reverse ported to BSD
  78.  *    1.5    dcw    7th April 1988    Made if and while special cases in
  79.  *                    get_token
  80.  *    2.0    dcw    2nd July 1988    Made ready for releasing to news...
  81.  */
  82.  
  83.  
  84. #include "dcw.h"
  85.  
  86.  
  87. /* ----------------------- Data types ------------------------- */
  88.  
  89.  
  90. #define ID_LEN        50
  91. #define LINE_LEN    1024
  92.  
  93.  
  94. #define FDECL        struct anon1
  95. #define EL_IDLIST    struct anon2
  96. #define EL_TSLIST    struct anon3
  97.  
  98. #define IDLIST    EL_IDLIST *
  99. #define TSLIST    EL_TSLIST *
  100.  
  101. FDECL {
  102.     char    ftype[ID_LEN];
  103.     char    fname[ID_LEN];
  104.     IDLIST    formals;
  105.     TSLIST    ftypes;
  106. };
  107.  
  108. EL_IDLIST {
  109.     char    id[ID_LEN];
  110.     IDLIST    next;
  111. };
  112.  
  113. EL_TSLIST {
  114.     char    type[ID_LEN];
  115.     char    var[ID_LEN];
  116.     TSLIST    next;
  117. };
  118.  
  119.  
  120. /* --------------------- Forward declns ----------------------- */
  121. /*             Guess what generated these then ???              */
  122.  
  123.  
  124. #ifdef HASPROTOS
  125. extern void main( int , char ** );
  126. extern void usage( BOOL );
  127. extern void out_extern( FILE * , FDECL * , BOOL );
  128. extern void print_fdecl( FILE * , FDECL * );
  129. extern void prototype( FILE * , FDECL * , char * );
  130. extern int readline( FILE * , char * );
  131. extern void get_token( void );
  132. extern BOOL parse_function_decln( char * , FDECL * );
  133. extern BOOL parse_list_id( IDLIST * );
  134. extern BOOL parse_restof_ids( IDLIST * );
  135. extern BOOL parse_list_ts( TSLIST * );
  136. extern BOOL parse_typespec( TSLIST * );
  137. extern BOOL parse_starred_id( char * , char * );
  138. #else
  139. extern void main();
  140. extern void usage();
  141. extern void out_extern();
  142. extern void print_fdecl();
  143. extern void prototype();
  144. extern int readline();
  145. extern void get_token();
  146. extern BOOL parse_function_decln();
  147. extern BOOL parse_list_id();
  148. extern BOOL parse_restof_ids();
  149. extern BOOL parse_list_ts();
  150. extern BOOL parse_typespec();
  151. extern BOOL parse_starred_id();
  152. #endif
  153.  
  154.  
  155. /* ---------------------- Main program ------------------------ */
  156.  
  157.  
  158. void main( argc, argv ) int argc; char **argv;
  159. {
  160.     FILE    *in,*out;
  161.     FDECL    f;
  162.     char    line[LINE_LEN];
  163.     BOOL    origonly;
  164.  
  165.     usage( argc>1 && argc<=4 );
  166.  
  167.     origonly = ( strcmp( argv[1], "-f" ) == 0 );
  168.     if( origonly) {
  169.         int i;
  170.  
  171.         for( i=2; i<argc; i++ ) argv[i-1] = argv[i];
  172.         argc--;
  173.     }
  174.  
  175.     usage( argc > 1 );    /* still at least one argument left */
  176.  
  177.     in = fopen( argv[1], "r" );
  178.     ASSERT( in != NULL, ("Can't open '%s'\n",argv[1]) );
  179.  
  180.     if( argc == 2 ) {
  181.         out = stdout;
  182.     } else {
  183.         out = fopen( argv[2], "w" );
  184.         ASSERT( out != NULL, ("Can't create '%s'\n",argv[2]) );
  185.     }
  186.  
  187.     if( origonly ) {
  188.         while( readline( in, line ) != EOF ) {
  189.             if( parse_function_decln( line, &f ) ) {
  190.                 print_fdecl( out, &f );
  191.             }
  192.         }
  193.     } else {
  194.         fprintf( out, "#ifdef HASPROTOS\n" );
  195.         while( readline( in, line ) != EOF ) {
  196.             if( parse_function_decln( line, &f ) ) {
  197.                 out_extern( out, &f, TRUE );
  198.             }
  199.         }
  200.         fprintf( out, "#else\n" );
  201.         fseek( in, 0L, 0 );
  202.         while( readline( in, line ) != EOF ) {
  203.             if( parse_function_decln( line, &f ) ) {
  204.                 out_extern( out, &f, FALSE );
  205.             }
  206.         }
  207.         fprintf( out, "#endif\n" );
  208.     }
  209.     fclose( in );
  210.     fclose( out );
  211.     exit( 0 );
  212. }
  213.  
  214.  
  215. void usage(b) BOOL b;
  216. {
  217.     ASSERT( b, ("Usage: proto [-f] infile [outfile]\n") );
  218. }
  219.  
  220.  
  221. void out_extern( out, f, b ) FILE *out; FDECL *f; BOOL b;
  222. {
  223.     IDLIST  i;
  224.  
  225.     fprintf( out, "extern %s %s(", f->ftype, f->fname );
  226.     if( b ) {
  227.         if( f->formals ) {
  228.             prototype( out, f, f->formals->id );
  229.             for( i=f->formals->next; i; i=i->next ) {
  230.                 fprintf( out, "," );
  231.                 prototype( out, f, i->id );
  232.             }
  233.         } else {
  234.             fprintf( out, " void " );
  235.         }
  236.     }
  237.     fprintf( out, ");\n" );
  238. }
  239.  
  240.  
  241. /* print the original form of the function declaration */
  242.  
  243. void print_fdecl( out, f ) FILE *out; FDECL *f;
  244. {
  245.     IDLIST i;
  246.     TSLIST t;
  247.  
  248.     fprintf( out, "%s %s(", f->ftype, f->fname );
  249.     if( f->formals ) {
  250.         fprintf( out, "%s", f->formals->id );
  251.         for( i=f->formals->next; i; i=i->next ) {
  252.             fprintf( out, ", %s", i->id );
  253.         }
  254.     }
  255.     fprintf( out, ")" );
  256.     for( t=f->ftypes; t; t=t->next ) {
  257.         fprintf( out, " %s %s;", t->type, t->var );
  258.     }
  259.     fprintf( out, " \n" );
  260. }
  261.  
  262.  
  263. void prototype( out, f, name ) FILE *out; FDECL *f; char *name;
  264. {
  265.     TSLIST t;
  266.  
  267.     for( t=f->ftypes; t; t=t->next ) {
  268.         if( streq( name, t->var ) ) {
  269.             fprintf( out, " %s ", t->type );
  270.             return;
  271.         }
  272.     }
  273.     fprintf( stderr, "warning: %s has undeclared formal '%s' => integer\n",
  274.         f->fname, name );
  275. fprintf( out, " int" );
  276. }
  277.  
  278.  
  279. int readline( f, line ) FILE *f; char *line;
  280. {
  281.     int c;
  282.     char *p = line;
  283.  
  284.     c=getc(f);
  285.     if( c==EOF ) return c;
  286.     ungetc( c, f );
  287.     while( (c=getc(f)) != '\n' ) *p++ = c;
  288.     *p = '\0';
  289.     return p-line;
  290. }
  291.  
  292.  
  293. /* ----------------- Lexer routines ---------------------- */
  294.  
  295.  
  296. char *lex_line;
  297. char tokstr[100];
  298. enum token_type {
  299.     tID, tSTAR, tSEMI, tCOMMA, tOPEN, tCLOSE, tEOL, tBRACE, tERR
  300. } token;
  301.  
  302.  
  303. void get_token()
  304. {
  305.     char *s = tokstr;
  306.     char c;
  307.  
  308.     while( *lex_line == ' ' || *lex_line == '\t' ) lex_line++;
  309.     c = *lex_line++;
  310.     *s++ = c;
  311.     *s = '\0';
  312.  
  313.     switch( c ) {
  314.     case '\0' : token = tEOL      ; break;
  315.     case ','  : token = tCOMMA    ; break;
  316.     case ';'  : token = tSEMI     ; break;
  317.     case '*'  : token = tSTAR     ; break;
  318.     case '('  : token = tOPEN     ; break;
  319.     case '{'  : token = tBRACE; break;
  320.     case ')'  : token = tCLOSE    ; break;
  321.     default   :
  322.         if( !isalpha( c ) ) {
  323.             token = tERR;
  324.         } else {
  325.             while( (c = *lex_line)=='_'||isalnum(c) ) {
  326.                 *s++ = c; lex_line++;
  327.             }
  328.             *s = '\0';
  329.             if( strcmp(tokstr,"if") == 0
  330.             ||  strcmp(tokstr,"while") == 0
  331.             ||  strcmp(tokstr,"switch") == 0
  332.             ) {
  333.                 token = tERR;
  334.             } else {
  335.                 token = tID;
  336.             }
  337.         }
  338.     }
  339. }
  340.  
  341.  
  342. /* ------------------- Parser routines ------------------- */
  343.  
  344.  
  345. BOOL parse_function_decln( line, f ) char *line; FDECL *f;
  346. {
  347.     char stars   [ID_LEN];
  348.     char basetype[ID_LEN];
  349.  
  350.     lex_line = line;
  351.     get_token();
  352.     if( token != tID ) return FALSE;
  353.  
  354.     strcpy( basetype, tokstr );
  355.     get_token();
  356.     if( token == tOPEN ) {
  357.         strcpy( f->fname, basetype );
  358.         strcpy( f->ftype, "int" );
  359.     } else {
  360.         if( ! parse_starred_id( stars, f->fname ) ) return FALSE;
  361.  
  362.         if( *stars == '\0' ) {
  363.             strcpy( f->ftype, basetype );
  364.         } else {
  365.             sprintf( f->ftype, "%s %s", basetype, stars );
  366.         }
  367.         if( token != tOPEN ) return FALSE;
  368.     }
  369.     get_token();
  370.     if( ! parse_list_id( &(f->formals) ) || token != tCLOSE )
  371.         return FALSE;
  372.     get_token();
  373.     return parse_list_ts( &(f->ftypes) );
  374. }
  375.  
  376.  
  377. /* attempt to parse an idLIST [possibly empty] */
  378.  
  379. BOOL parse_list_id( ip ) IDLIST *ip;
  380. {
  381.     *ip = NULL;
  382.     if( token != tID ) return TRUE;
  383.     *ip = NEW( EL_IDLIST );
  384.     strcpy( (*ip)->id, tokstr );
  385.     get_token();
  386.     return parse_restof_ids( &((*ip)->next) );
  387. }
  388.  
  389.  
  390. BOOL parse_restof_ids( ip ) IDLIST *ip;
  391. {
  392.     *ip = NULL;
  393.     if( token != tCOMMA ) return TRUE;
  394.  
  395.     get_token();
  396.     if( token != tID ) return FALSE;
  397.  
  398.     *ip = NEW( EL_IDLIST );
  399.     strcpy( (*ip)->id, tokstr );
  400.     get_token();
  401.     return parse_restof_ids( &((*ip)->next) );
  402. }
  403.  
  404.  
  405. /*
  406.  * attempt to parse a list of typespecs [possibly empty]
  407.  * followed by tEOL or tBRACE
  408.  */
  409.  
  410. BOOL parse_list_ts( tp ) TSLIST *tp;
  411. {
  412.     TSLIST t;
  413.  
  414.     for(;;) {
  415.         *tp = NULL;
  416.         if( token==tEOL || token==tBRACE ) return TRUE;
  417.  
  418.         if( ! parse_typespec( tp ) ) return FALSE;
  419.         for( t = *tp; t->next; t=t->next );
  420.         tp = &(t->next);
  421.     }
  422.     /*NOTREACHED*/
  423. }
  424.  
  425.  
  426. BOOL parse_typespec( tp ) TSLIST *tp;
  427. {
  428.     char basetype[ID_LEN];
  429.     char stars   [ID_LEN];
  430.  
  431.     if( token != tID ) return FALSE;
  432.     strcpy( basetype, tokstr );
  433.  
  434.     for(;;) {
  435.         get_token();
  436.         *tp = NEW( EL_TSLIST );
  437.         if( ! parse_starred_id( stars, (*tp)->var ) ) return FALSE;
  438.  
  439.         if( *stars == '\0' ) {
  440.             strcpy( (*tp)->type, basetype );
  441.         } else {
  442.             sprintf( (*tp)->type, "%s %s", basetype, stars );
  443.         }
  444.  
  445.         if( token == tSEMI ) {
  446.             get_token();
  447.             return TRUE;
  448.         }
  449.         if( token != tCOMMA ) return FALSE;
  450.         tp = &((*tp)->next);
  451.     }
  452.     /*NOTREACHED*/
  453. }
  454.  
  455.  
  456. BOOL parse_starred_id( stars, id ) char *stars, *id;
  457. {
  458.     BOOL ok;
  459.  
  460.     while( token == tSTAR ) {
  461.         *stars++ = '*';
  462.         get_token();
  463.     }
  464.     *stars = '\0';
  465.     ok = token == tID;
  466.     if( ok ) {
  467.         strcpy( id, tokstr );
  468.         get_token();
  469.     }
  470.     return ok;
  471. }
  472.