I l@ve RuBoard Previous Section Next Section

27.8 Program Files

The following examples contain the complete listing of our program, by file. They are listed here for reference:

Example

File

Example 27-3

The ch_type.h file

Example 27-4

The ch_type.cpp file

Example 27-5

The token.h file

Example 27-6

The token.cpp file

Example 27-7

The stat.cpp file

Example 27-8

Unix Makefile for CC (Generic Unix)

Example 27-9

Unix Makefile for g++

Example 27-10

Borland-C++ Makefile

Example 27-11

Microsoft Visual C++ Makefile

Example 27-3. stat/ch_type.h
/********************************************************
 * char_type -- Character type class                    *
 *                                                      *
 * Member functions:                                    *
 *      type -- returns the type of a character.        *
 *              (Limited to simple types)               *
 *      is(ch, char_type) -- check to see if ch is      *
 *              a member of the given type.             *
 *              (Works for derrived types as well.)     *
 ********************************************************/
class char_type {
    public:
        enum CHAR_TYPE {
            C_EOF,              // End of file character
            C_WHITE,    // Whitespace or control character
            C_NEWLINE,  // A newline character
            C_ALPHA,    // A Letter (includes _)
            C_DIGIT,    // A Number
            C_OPERATOR, // Random operator
            C_SLASH,    // The character '/'
            C_L_PAREN,  // The character '('
            C_R_PAREN,  // The character ')'
            C_L_CURLY,  // The character '{'
            C_R_CURLY,  // The character '}'
            C_SINGLE,   // The character '\''
            C_DOUBLE,   // The character '"'
            // End of simple types, more complex, derrived types follow
            C_HEX_DIGIT,// Hexidecimal digit
            C_ALPHA_NUMERIC     // Alpha numeric
        };
    private:
        static enum CHAR_TYPE type_info[256];   // Information on each character
        
        // Fill in a range of type info stuff
        void fill_range(int start, int end, CHAR_TYPE type);
    public:
        char_type(  );    // Initialize the data
        // ~char_type   -- default destructor

        // Returns true if character is a given type
        int is(int ch, CHAR_TYPE kind);

        CHAR_TYPE type(int ch);
};
Example 27-4. stat/ch_type.cpp
/********************************************************
 * ch_type package                                      *
 *                                                      *
 * The class ch_type is used to tell the type of        *
 * various characters.                                  *
 *                                                      *
 * The main member functions are:                       *
 *      is -- True if the character is the indicated    *
 *              type.                                   *
 *      type -- Return type of character.               *
 ********************************************************/
#include <iostream>
#include <assert.h>

#include "ch_type.h"

// Define the type information array
char_type::CHAR_TYPE char_type::type_info[256]; 
/********************************************************
 * fill_range -- fill in a range of types for the       *
 *      character type class                            *
 *                                                      *
 * Parameters                                           *
 *      start, end -- range of items to fill in         *
 *      type -- type to use for filling                 *
 ********************************************************/
void char_type::fill_range(int start, int end, CHAR_TYPE type)
{
    int cur_ch;

    for (cur_ch = start; cur_ch <= end; ++cur_ch) {
        assert(cur_ch >= 0);
        assert(cur_ch < sizeof(type_info)/sizeof(type_info[0]));
        type_info[cur_ch] = type;
    }
}

/*********************************************************
 * char_type::char_type -- initialize the char type table*
 *********************************************************/
char_type::char_type(  )
{
    fill_range(0, 255, C_WHITE);

    fill_range('A', 'Z', C_ALPHA);
    fill_range('a', 'z', C_ALPHA);
    type_info['_'] = C_ALPHA;

    fill_range('0', '9', C_DIGIT);

    type_info['!'] = C_OPERATOR;
    type_info['#'] = C_OPERATOR;
    type_info['$'] = C_OPERATOR;
    type_info['%'] = C_OPERATOR;
    type_info['^'] = C_OPERATOR;
    type_info['&'] = C_OPERATOR;
    type_info['*'] = C_OPERATOR;
    type_info['-'] = C_OPERATOR;
    type_info['+'] = C_OPERATOR;
    type_info['='] = C_OPERATOR;
    type_info['|'] = C_OPERATOR;
    type_info['~'] = C_OPERATOR;
    type_info[','] = C_OPERATOR;
    type_info[':'] = C_OPERATOR;
    type_info['?'] = C_OPERATOR;
    type_info['.'] = C_OPERATOR;
    type_info['<'] = C_OPERATOR;
    type_info['>'] = C_OPERATOR;

    type_info['/'] = C_SLASH;
    type_info['\n'] = C_NEWLINE;

    type_info['('] = C_L_PAREN;
    type_info[')'] = C_R_PAREN;

    type_info['{'] = C_L_CURLY;
    type_info['}'] = C_R_CURLY;

    type_info['"'] = C_DOUBLE;
    type_info['\''] = C_SINGLE;
}

int char_type::is(int ch, CHAR_TYPE kind)
{
    if (ch == EOF) return (kind == C_EOF);

    switch (kind) {
        case C_HEX_DIGIT:

            assert(ch >= 0);
            assert(ch < sizeof(type_info)/sizeof(type_info[0]));

            if (type_info[ch] == C_DIGIT)
                return (1);
            if ((ch >= 'A') && (ch <= 'F')) 
                return (1);
            if ((ch >= 'a') && (ch <= 'f')) 
                return (1);
            return (0);
        case C_ALPHA_NUMERIC:
            assert(ch >= 0);
            assert(ch < sizeof(type_info)/sizeof(type_info[0]));

            return ((type_info[ch] == C_ALPHA) ||
                    (type_info[ch] == C_DIGIT));
        default:
            assert(ch >= 0);
            assert(ch < sizeof(type_info)/sizeof(type_info[0]));

            return (type_info[ch] == kind);
    }
};

char_type::CHAR_TYPE char_type::type(const int ch) {
    if (ch == EOF) return (C_EOF);

    assert(ch >= 0);
    assert(ch < sizeof(type_info)/sizeof(type_info[0]));

    return (type_info[ch]);
}
Example 27-5. stat/token.h
#include <string>
#include <iostream>
/********************************************************
 * token -- token handling module                       *
 *                                                      *
 * Functions:                                           *
 *      next_token -- get the next token from the input *
 ********************************************************/

/*
 * A list of tokens
 *      Note, how this list is used depends on defining the macro T.
 *      This macro is used for defining the tokens types themselves
 *      as well as the string version of the tokens.
 */
#define TOKEN_LIST \
   T(T_NUMBER),         /* Simple number (floating point or integer) */ \
   T(T_STRING),         /* String or character constant */              \
   T(T_COMMENT),        /* Comment */                                   \
   T(T_NEWLINE),        /* Newline character */                         \
   T(T_OPERATOR),       /* Arithmetic operator */                       \
   T(T_L_PAREN),        /* Character "(" */                             \
   T(T_R_PAREN),        /* Character ")" */                             \
   T(T_L_CURLY),        /* Character "{" */                             \
   T(T_R_CURLY),        /* Character "}" */                             \
   T(T_ID),             /* Identifier */                                \
   T(T_EOF)             /* End of File */

/*
 * Define the enumerated list of tokens.  
 *      This makes use of a trick using the T macro
 *      and our TOKEN_LIST
 */
#define T(x) x          // Define T(  ) as the name
enum TOKEN_TYPE {
   TOKEN_LIST
};
#undef T                // Remove old temporary macro

// A list of the names of the tokens
extern const char *const TOKEN_NAMES[];

/********************************************************
 * input_file -- data from the input file               *
 *                                                      *
 * The current two characters are store in              *
 *      cur_char and next_char                          *
 *                                                      *
 * The member function read_char moves eveyone up       *
 * one character.                                       *
 *                                                      *
 * The line is buffered and output everytime a newline  *
 * is passed.                                           *
 ********************************************************/
class input_file: public std::ifstream {
    private:
        std::string line;       // Current line
    public:
        int cur_char;   // Current character (can be EOF)
        int next_char;  // Next character (can be EOF)

        /*
         * Initialize the input file and read the first 2 
         * characters.
         */
        input_file(const char *const name) : 
            std::ifstream(name),
            line("")
        {
            if (bad(  ))
                return;
            cur_char = get(  );
            next_char = get(  );
        }

        /*
         * Write the line to the screen
         */
        void flush_line(  ) {
            std::cout << line;
            std::cout.flush(  );
            line = "";
        }
        /*
         * Advance one character
         */
        void read_char(  ) {
            line += cur_char;

            cur_char = next_char;
            next_char = get(  );
        }
};

/********************************************************
 * token class                                          *
 *                                                      *
 *      Reads the next token in the input stream        *
 *      and returns its type.                           *
 ********************************************************/
class token {
    private:
        // True if we are in the middle of a comment
        int in_comment; 

        // True if we need to read a character
        // (This hack is designed to get the new lines right)
        int need_to_read_one;

        // Read a /* */ style comment
        TOKEN_TYPE read_comment(input_file& in_file);
    public:
        token(  ) { 
            in_comment = false;
            need_to_read_one = 0;
        }

        // Return the next token in the stream
        TOKEN_TYPE next_token(input_file& in_file);
};
Example 27-6. stat/token.cpp
/********************************************************
 * token -- token handling module                       *
 *                                                      *
 * Functions:                                           *
 *      next_token -- get the next token from the input *
 ********************************************************/
#include <fstream>
#include <cstdlib>

#include "ch_type.h"
#include "token.h"

/*
 * Define the token name list
 *      This makes use of a trick using the T macro
 *      and our TOKEN_LIST
 */
#define T(x) #x         // Define x as a string
const char *const TOKEN_NAMES[] = {
   TOKEN_LIST
};
#undef T                // Remove old temporary macro

static char_type char_type;     // Character type information
/********************************************************
 * read_comment -- read in a comment                    *
 *                                                      *
 * Parameters                                           *
 *      in_file -- file to read                         *
 *                                                      *
 * Returns                                              *
 *      Token read.  Can be a T_COMMENT or T_NEW_LINE   *
 *      depending on what we read.                      *
 *                                                      *
 *      Multi-line comments are split into multiple     *
 *      tokens.                                         *
 ********************************************************/
TOKEN_TYPE token::read_comment(input_file& in_file)
{
    if (in_file.cur_char == '\n') {
        in_file.read_char(  );
        return (T_NEWLINE);
    }
    while (true) {
        in_comment = true;
        if (in_file.cur_char == EOF) {
            std::cerr << "Error: EOF inside comment\n";
            return (T_EOF);
        }
        if (in_file.cur_char == '\n')
            return (T_COMMENT);
        if ((in_file.cur_char == '*') && 
            (in_file.next_char == '/')) {
            in_comment = false;
            // Skip past the ending */
            in_file.read_char(  );
            in_file.read_char(  );
            return (T_COMMENT);
        }
        in_file.read_char(  );
    }
}
/********************************************************
 * next_token -- read the next token in an input stream *
 *                                                      *
 * Parameters                                           *
 *      in_file -- file to read                         *
 *                                                      *
 * Returns                                              *
 *      next token                                      *
 ********************************************************/
TOKEN_TYPE token::next_token(input_file& in_file)
{

    if (need_to_read_one)
        in_file.read_char(  );
    
    need_to_read_one = 0;

    if (in_comment)
        return (read_comment(in_file));

    while (char_type.is(in_file.cur_char, char_type::C_WHITE)) {
        in_file.read_char(  );
    }
    if (in_file.cur_char == EOF)
        return (T_EOF);

    switch (char_type.type(in_file.cur_char)) {
        case char_type::C_NEWLINE:
            in_file.read_char(  );
            return (T_NEWLINE);
        case char_type::C_ALPHA:
            while (char_type.is(in_file.cur_char, 
                                char_type::C_ALPHA_NUMERIC))
                in_file.read_char(  );
            return (T_ID);
        case char_type::C_DIGIT:
            in_file.read_char(  );
            if ((in_file.cur_char == 'X') || (in_file.cur_char == 'x')) {
                in_file.read_char(  );
                while (char_type.is(in_file.cur_char, 
                                        char_type::C_HEX_DIGIT)) {

                    in_file.read_char(  );
                }
                return (T_NUMBER);
            }
            while (char_type.is(in_file.cur_char, char_type::C_DIGIT))
                in_file.read_char(  );
            return (T_NUMBER);
        case char_type::C_SLASH:
            // Check for  /* characters 
            if (in_file.next_char == '*') {
                return (read_comment(in_file));
            }
            // Now check for double slash comments
            if (in_file.next_char == '/') {
                while (true) {
                    // Comment starting with // and ending with EOF is legal
                    if (in_file.cur_char == EOF)
                        return (T_COMMENT);
                    if (in_file.cur_char == '\n')
                        return (T_COMMENT);
                    in_file.read_char(  );
                }
            }
            // Fall through
        case char_type::C_OPERATOR:
            in_file.read_char(  );
            return (T_OPERATOR);
        case char_type::C_L_PAREN:
            in_file.read_char(  );
            return (T_L_PAREN);
        case char_type::C_R_PAREN:
            in_file.read_char(  );
            return (T_R_PAREN);
        case char_type::C_L_CURLY:
            in_file.read_char(  );
            return (T_L_CURLY);
        case char_type::C_R_CURLY:
            in_file.read_char(  );
            return (T_R_CURLY);
        case char_type::C_DOUBLE:
            while (true) {
                in_file.read_char(  );
                // Check for end of string
                if (in_file.cur_char == '"')
                    break;

                // Escape character, then skip the next character
                if (in_file.cur_char == '\\')
                    in_file.read_char(  );
            }
            in_file.read_char(  );
            return (T_STRING);
        case char_type::C_SINGLE:
            while (true) {
                in_file.read_char(  );
                // Check for end of character
                if (in_file.cur_char == '\'')
                    break;

                // Escape character, then skip the next character
                if (in_file.cur_char == '\\')
                    in_file.read_char(  );
            }
            in_file.read_char(  );
            return (T_STRING);
        default:
            assert("Internal error: Very strange character" != 0);
    }
    assert("Internal error: We should never get here" != 0);
    return (T_EOF);     // Should never get here either
}
Example 27-7. stat/stat.cpp
/********************************************************
 * stat                                                 *
 *      Produce statistics about a program              *
 *                                                      *
 * Usage:                                               *
 *      stat [options] <file-list>                      *
 *                                                      *
 ********************************************************/
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <cstring>
#include <assert.h>

#include "ch_type.h"
#include "token.h"

/********************************************************
 * stat -- general purpose statistic                    *
 *                                                      *
 * Member functions:                                    *
 *      take_token -- receives token and uses it to     *
 *                      compute statistic               *
 *      line_start -- output stat at the beginning of   *
 *                      a line.                         *
 *      eof     -- output stat at the end of the file   *
 ********************************************************/
class a_stat {
    public:
        virtual void take_token(TOKEN_TYPE token) = 0;
        virtual void line_start(  ) {};
        virtual void eof(  ) {};
        // Default constructor
        // Default destructor
        // Copy constructor defaults as well (probably not used)
};

/********************************************************
 * line_counter -- handle line number / line count      *
 *              stat.                                   *
 *                                                      *
 * Counts the number of T_NEW_LINE tokens seen and      *
 * output the current line number at the beginning      *
 * of the line.                                         *
 *                                                      *
 * At EOF it will output the total number of lines      *
 ********************************************************/
class line_counter: public a_stat {
    private:
        int cur_line;   // Line number for the current line
    public:
        // Initialize the line counter -- to zero
        line_counter(  ) { 
            cur_line = 0; 
        };
        // Default destrctor
        // Default copy constructor (probably never called)

        // Consume tokens,  count the number of new line tokens
        void take_token(TOKEN_TYPE token) {
            if (token == T_NEWLINE) 
                ++cur_line;
        }

        // Output start of line statistics 
        // namely the current line number
        void line_start(  ) {
            std::cout << std::setw(4) << cur_line << ' ' << std::setw(0);
        }

        // Output eof statistics
        // namely the total number of lines
        void eof(  ) {
            std::cout << "Total number of lines: " << cur_line << '\n';
        }
};

/********************************************************
 * paren_count -- count the nesting level of (  )         *
 *                                                      *
 * Counts the number of T_L_PAREN vs T_R_PAREN tokens   *
 * and writes the current nesting level at the beginning*
 * of each line.                                        *
 *                                                      *
 * Also keeps track of the maximum nesting level.       *
 ********************************************************/
class paren_counter: public a_stat {
    private:
        int cur_level;          // Current nesting level
        int max_level;          // Maximum nesting level
    public:
        // Initialize the counter
        paren_counter(  ) { 
            cur_level = 0; 
            max_level = 0;
        };
        // Default destructor
        // Default copy constructor (probably never called)

        // Consume tokens,  count the nesting of (  ) 
        void take_token(TOKEN_TYPE token) {
            switch (token) {
                case T_L_PAREN:
                    ++cur_level;
                    if (cur_level > max_level)
                        max_level = cur_level;
                    break;
                case T_R_PAREN:
                    --cur_level;
                    break;
                default:
                    // Ignore
                    break;
            }
        }

        // Output start of line statistics 
        // namely the current line number
        void line_start(  ) {
            std::cout.setf(std::ios::left);
            std::cout.width(2);

            std::cout << '(' <<  cur_level << ' ';

            std::cout.unsetf(std::ios::left);
            std::cout.width(  );
        }

        // Output eof statistics
        // namely the total number of lines
        void eof(  ) {
            std::cout << "Maximum nesting of (  ) : " << max_level << '\n';
        }
};

/********************************************************
 * brace_counter -- count the nesting level of {}       *
 *                                                      *
 * Counts the number of T_L_CURLY vs T_R_CURLY tokens   *
 * and writes the current nesting level at the beginning*
 * of each line.                                        *
 *                                                      *
 * Also keeps track of the maximum nesting level.       *
 *                                                      *
 * Note: brace_counter and paren_counter should         *
 * probably be combined.                                *
 ********************************************************/
class brace_counter: public a_stat {
    private:
        int cur_level;          // Current nesting level
        int max_level;          // Maximum nesting level
    public:
        // Initialize the counter
        brace_counter(  ) { 
            cur_level = 0; 
            max_level = 0;
        };
        // Default destructor
        // Default copy constructor (probably never called)

        // Consume tokens,  count the nesting of (  ) 
        void take_token(TOKEN_TYPE token) {
            switch (token) {
                case T_L_CURLY:
                    ++cur_level;
                    if (cur_level > max_level)
                        max_level = cur_level;
                    break;
                case T_R_CURLY:
                    --cur_level;
                    break;
                default:
                    // Ignore
                    break;
            }
        }

        // Output start of line statistics 
        // namely the current line number
        void line_start(  ) {
            std::cout.setf(std::ios::left);
            std::cout.width(2);

            std::cout << '{' <<  cur_level << ' ';

            std::cout.unsetf(std::ios::left);
            std::cout.width(  );
        }

        // Output eof statistics
        // namely the total number of lines
        void eof(  ) {
            std::cout << "Maximum nesting of {} : " << max_level << '\n';
        }
};

/********************************************************
 * comment_counter -- count the number of lines         *
 *      with and without comments.                      *
 *                                                      *
 * Outputs nothing at the beginning of each line, but   *
 * will output a ratio at the end of file               *
 *                                                      *
 * Note: This class makes use of two bits:              *
 *      CF_COMMENT  -- a comment was seen               *
 *      CF_CODE     -- code was seen                    *
 * to collect statistics.                               *
 *                                                      *
 * These are combined to form an index into the counter *
 * array so the value of these two bits is very         *
 * important.                                           *
 ********************************************************/
static const int CF_COMMENT = (1<<0);   // Line contains comment
static const int CF_CODE    = (1<<1);   // Line contains code
// These bits are combined to form the statistics
//
//      0                  -- [0] Blank line
//      CF_COMMENT         -- [1] Comment only line
//      CF_CODE            -- [2] Code only line
//      CF_COMMENT|CF_CODE -- [3] Comments and code on this line

class comment_counter: public a_stat {
    private:
        int counters[4];        // Count of various types of stats.
        int flags;              // Flags for the current line
    public:
        // Initialize the counters
        comment_counter(  ) { 
            memset(counters, '\0', sizeof(counters));
            flags = 0;
        };
        // Default destructor
        // Default copy constructor (probably never called)

        // Consume tokens,  count the nesting of (  ) 
        void take_token(TOKEN_TYPE token) {
            switch (token) {
                case T_COMMENT:
                    flags |= CF_COMMENT;
                    break;
                default:
                    flags |= CF_CODE;
                    break;
                case T_NEWLINE:
                    assert(flags >= 0);
                    assert(flags < sizeof(counters)/sizeof(counters[0]));
                    ++counters[flags];
                    flags = 0;
                    break;
            }
        }

        // void line_start(  ) -- defaults to base

        // Output eof statistics
        // namely the total number of lines
        void eof(  ) {
            std::cout << "Number of blank lines ................." <<   
                    counters[0] << '\n';
            std::cout << "Number of comment only lines .........." << 
                    counters[1] << '\n';
            std::cout << "Number of code only lines ............." << 
                    counters[2] << '\n';
            std::cout << "Number of lines with code and comments " << 
                    counters[3] << '\n';
            std::cout.setf(std::ios::fixed);
            std::cout.precision(1);
            std::cout << "Comment to code ratio " <<
               float(counters[1] + counters[3]) /
               float(counters[2] + counters[3]) * 100.0 << "%\n";
        }
};


static line_counter line_count;         // Counter of lines
static paren_counter paren_count;       // Counter of (  ) levels
static brace_counter brace_count;       // Counter of {} levels
static comment_counter comment_count;   // Counter of comment info

// A list of the statistics we are collecting
static a_stat *stat_list[] = {
    &line_count,
    &paren_count,
    &brace_count,
    &comment_count,
    NULL
};


/********************************************************
 * do_file -- process a single file                     *
 *                                                      *
 * Parameters                                           *
 *      name -- the name of the file to process         *
 ********************************************************/
static void do_file(const char *const name)
{
    input_file in_file(name);   // File to read
    token token;                // Token reader/parser
    TOKEN_TYPE cur_token;       // Current token type
    class a_stat **cur_stat;    // Pointer to stat for collection/writing

    if (in_file.bad(  )) {
        std::cerr << "Error: Could not open file " << 
                name << " for reading\n";
        return;
    }
    while (true) {
        cur_token = token.next_token(in_file);
        for (cur_stat = stat_list; *cur_stat != NULL; ++cur_stat)
           (*cur_stat)->take_token(cur_token);
#ifdef DEBUG
        assert(cur_token >= 0);
        assert(cur_token < sizeof(TOKEN_NAMES)/sizeof(TOKEN_NAMES[0]));
        std::cout << "   " << TOKEN_NAMES[cur_token] << '\n';
#endif /* DEBUG */

        switch (cur_token) {
            case T_NEWLINE:
                for (cur_stat = stat_list; *cur_stat != NULL; ++cur_stat)
                    (*cur_stat)->line_start(  );
                in_file.flush_line(  );
                break;
            case T_EOF:
                for (cur_stat = stat_list; *cur_stat != NULL; ++cur_stat)
                   (*cur_stat)->eof(  );
                return;
            default:
                // Do nothing
                break;
        }
    }
}

int main(int argc, char *argv[])
{
    char *prog_name = argv[0];  // Name of the program

    if (argc == 1) {
        std::cerr << "Usage is " << prog_name << "[options] <file-list>\n";
        exit (8);
    }

    for (/* argc set */; argc > 1; --argc) {
       do_file(argv[1]);
       ++argv;
    }
    return (0);
}
Example 27-8. stat/makefile.unx
#
# Makefile for many Unix compilers using the
# "standard" command name CC
#
CC=CC
CFLAGS=-g
OBJS= stat.o ch_type.o token.o

all: stat.out stat

stat.out: stat
        stat ../calc3/calc3.cpp >stat.out

stat: $(OBJS)
        $(CC) $(CCFLAGS) -o stat $(OBJS)

stat.o: stat.cpp token.h
        $(CC) $(CCFLAGS) -c stat.cpp

ch_type.o: ch_type.cpp ch_type.h
        $(CC) $(CCFLAGS) -c ch_type.cpp

token.o: token.cpp token.h ch_type.h
        $(CC) $(CCFLAGS) -c token.cpp


clean:
        rm stat stat.o ch_type.o token.o
Example 27-9. stat/makefile.gnu
#
# Makefile for the Free Software Foundations g++ compiler
#
CC=g++
CCFLAGS=-g -Wall
OBJS= stat.o ch_type.o token.o

all: stat.out stat 

stat.out: stat
        stat ../calc3/calc3.cpp >stat.out

stat: $(OBJS)
        $(CC) $(CCFLAGS) -o stat $(OBJS)

stat.o: stat.cpp token.h
        $(CC) $(CCFLAGS) -c stat.cpp

ch_type.o: ch_type.cpp ch_type.h
        $(CC) $(CCFLAGS) -c ch_type.cpp

token.o: token.cpp token.h ch_type.h
        $(CC) $(CCFLAGS) -c token.cpp

clean:
        rm stat stat.o ch_type.o token.o
Example 27-10. stat/makefile.bcc
#
# Makefile for Borland's Borland-C++ compiler
#
CC=bcc32
#
# Flags 
#       -N  -- Check for stack overflow
#       -v  -- Enable debugging
#       -w  -- Turn on all warnings
#       -tWC -- Console application
#
CFLAGS=-N -v -w -tWC
OBJS= stat.obj ch_type.obj token.obj

all: stat.out stat.exe

stat.out: stat.exe
        stat ..\calc3\calc3.cpp >stat.out

stat.exe: $(OBJS)
        $(CC) $(CCFLAGS) -estat $(OBJS)

stat.obj: stat.cpp token.h
        $(CC) $(CCFLAGS) -c stat.cpp

ch_type.obj: ch_type.cpp ch_type.h
        $(CC) $(CCFLAGS) -c ch_type.cpp

token.obj: token.cpp token.h ch_type.h
        $(CC) $(CCFLAGS) -c token.cpp


clean:
        erase stat.exe stat.obj ch_type.obj token.obj
Example 27-11. stat/makefile.msc
#
# Makefile for Microsoft Visual C++
#
CC=cl
#
# Flags 
#       AL -- Compile for large model
#       Zi -- Enable debugging
#       W1 -- Turn on warnings
#
CFLAGS=/AL /Zi /W1
OBJS= stat.obj ch_type.obj token.obj

all: stat.out stat.exe

stat.out: stat.exe
        stat ..\calc3\calc3.cpp >stat.out

stat.exe: $(OBJS)
        $(CC) $(CCFLAGS)  $(OBJS)

stat.obj: stat.cpp token.h
        $(CC) $(CCFLAGS) -c stat.cpp

ch_type.obj: ch_type.cpp ch_type.h
        $(CC) $(CCFLAGS) -c ch_type.cpp

token.obj: token.cpp token.h ch_type.h
        $(CC) $(CCFLAGS) -c token.cpp


clean:
        erase stat.exe stat.obj ch_type.obj token.obj
    I l@ve RuBoard Previous Section Next Section