27.8 Program Files

I l @ ve RuBoard

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_COMMENTCF_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, ' 
 /******************************************************** * 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_COMMENTCF_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); } 
', 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


Practical C++ Programming
Practical C Programming, 3rd Edition
ISBN: 1565923065
EAN: 2147483647
Year: 2003
Pages: 364

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net