Listing 1: The C declaration extractor program


/*  
** makefun.c - C Declaration Extraction Program
** Written October, 1995 and placed in the 
** public domain by Ted Merrill.
**
** The purpose of this program is to
** automatically create a header file containing 
** declarations extracted from function and/or
** data definitions or declarationsin a C or
** C++ source file.  Preparation of the source
** file is required as follows:
**
** To prepare the source file for extraction,
** you must prefix definitions and declarations
** to be extracted with special comments that
** begin at column 1. Please see example at
** bottom of this file.  If the item to be
** extracted must begin with "extern", you must
** place the word "extern" before the special
** comment, since the extractor will prepend an
** "extern" on its own.  To "comment out" the
** special comments, move them right from
** column 1.
**
** Compilation: nothing special.
**
** Execution:
** Redirect stdin to the source file and stdout
** to the output file.  For example, try: 
**
** makefun <makefun.c >makefun.out
**
** and: 
**
** makefun <makefun.out >makefun1.out
**
** Using the results of execution:
** The output file should be #included into
** those C/C++ files using the functions whose
** declarations were extracted.
*/

#include <stdio.h>

enum makefun_state
{
    STATE_NEW_LINE, /* at beginning of line,
                       outside of declaration */
    STATE_SILENT_LINE, /* inside of a line
                          outside a declaration */
    STATE_MATCH,       /* inside a potential beginning of a
                          declaration */
    STATE_IN_C,        /* inside a C comment in a declaration */
    STATE_C_END,       /* at possible end of C comment */
    STATE_IN_CPP,      /* inside a C++ comment in a declaration */
    STATE_IN_DECL,     /* inside a declaration, but not in a comment */
    STATE_C_BEGIN,     /* possible beginning of C comment in a
                          declaration */
};

#define CMATCH "/*-E-"   /* C-style special comment beginning*/
#define CPPMATCH "//-E-" /* C++-style special comment beginning*/

int main()
{
    /* begin at new line */
    enum makefun_state state = STATE_NEW_LINE;
    int imatch;         /* index into matching string */
    int bmatchc;        /* true if we match C comment so far */
    int bmatchcpp;      /* true if we match C++ comment so far */
    int ch;             /* character from stdin */
    printf("\n/*This is automatically generated,");
    printf(" not a source file! */\n");
    while ( (ch = getchar()) != EOF )
    {   /* loop until end of file; all input at top only! */
        switch( state )
        {
            case STATE_NEW_LINE:  /* here at begin of line, 
                                     outside decl. */
                if ( ch == CMATCH[0] )
                {
                    state = STATE_MATCH;
                    bmatchc = 1;    /* match C comment so far */
                    imatch = 1;     /* match index 1 next time */
                }
                else bmatchc = 0;
                if ( ch == CPPMATCH[0] ) 
                {
                    state = STATE_MATCH;
                    bmatchcpp = 1; /* match C++ comment so far */
                    imatch = 1;    /* match index 1 next time */
                }
                else bmatchcpp = 0;
                if      ( bmatchc || bmatchcpp ) ;
                else if ( ch == '\n' ) ;
                else      state = STATE_SILENT_LINE;
            break;

            case STATE_SILENT_LINE:  /* here inside a line, 
                                        outside of decl. */
                if ( ch == '\n' ) state = STATE_NEW_LINE;
            break;
            case STATE_MATCH:   /* here at begin of potential 
                                   declaration */
                if ( bmatchc && ch != CMATCH[imatch] ) 
                    bmatchc = 0;
                if ( bmatchcpp && ch != CPPMATCH[imatch] ) 
                    bmatchcpp = 0;
                imatch++;
                if      ( bmatchc && ! CMATCH[imatch] ) 
                {   /* found a C special comment match */
                    state = STATE_IN_C;
                    printf("\n\nextern\n"); /* make declaration 
                                                         extern!  */
                    printf("%s", CMATCH );  /* start emitting! */
                }
                else if ( bmatchcpp && ! CPPMATCH[imatch] )
                {   /* found a C++ special comment match */
                    state = STATE_IN_CPP;
                    printf("\n\nextern\n"); /* make declaration 
                                                         extern! */
                    printf("%s", CPPMATCH ); /* start emitting! */
                }
                if ( bmatchc || bmatchcpp ) ;
                else if ( ch == '\n' ) state = STATE_NEW_LINE;
                else      state = STATE_SILENT_LINE;
            break;
            case STATE_IN_C:  /* here inside C comment in a 
                                 declaration */
                putchar( ch );
                if ( ch == '*' ) state = STATE_C_END;
            break;
            case STATE_C_END:  /* at possible end of C style 
                                  comment */
                putchar( ch );
                if ( ch == '/' ) state = STATE_IN_DECL;
                else if ( ch == '*' ) ;
                else             state = STATE_IN_C;
            break;
            case STATE_IN_CPP:  /* here inside C++ comment in a  
                                   declaration */
                putchar( ch );
                if ( ch == '\n' ) state = STATE_IN_DECL;
            break;
            case STATE_IN_DECL: /* here inside decl. but not 
                                   inside comment */
                if      ( ch == '/' ) state = STATE_C_BEGIN;
                else if ( ch == '{' || ch == '=' || ch == ';' )
                {
                    ch = ';';  /* replace with terminator 
                                  semicolon */
                    state = STATE_SILENT_LINE;
                }
                putchar(ch);
            break;
            case STATE_C_BEGIN:  /* possible begin of comment in 
                                    declaration */
                if      ( ch == '*' ) state = STATE_IN_C;
                else if ( ch == '/' ) state = STATE_IN_CPP;
                else if ( ch == '{' || ch == '=' || ch == ';' )
                {
                    ch = ';'; /* replace with terminator 
                                 semicolon */
                    state = STATE_SILENT_LINE;
                }
                else      state = STATE_IN_DECL;
                putchar(ch);
            break;
        }
    }
    printf("\n\n/*-------- end ----------*/\n");
    return 0;
}
/* End of File */