Guest User

Untitled

a guest
May 23rd, 2017
635
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.96 KB | None | 0 0
  1. /* K&R version, 1388 tokens excluding whitespace */
  2. /****************************************************************************/
  3. /*                                                                          */
  4. /*       Program: tokount.c                                                 */
  5. /*                                                                          */
  6. /*       Author:  Barry Gorman ([email protected])                    */
  7. /*                                                                          */
  8. /*       Date:    April 15th 1993.                                          */
  9. /*                                                                          */
  10. /*       Purpose: Counts tokens in C programs, based on ANSI C Standard     */
  11. /*                                                                          */
  12. /*       Note:    This program is to be used only on correct program texts  */
  13. /*                                                                          */
  14. /****************************************************************************/
  15. #include <ctype.h>                      /* isalnum isdigit isspace          */
  16. /* #include <errno.h>                   /* errno                            */
  17. extern int errno;
  18. #include <stdio.h>                      /* EOF ferror FILE fopen fputs getc */
  19.                                         /* perror printf stderr ungetc      */
  20. /* #include <stdlib.h>                  /* EXIT_FAILURE EXIT_SUCCESS        */
  21. #include <string.h>                     /* strchr strcmp                    */
  22. /****************************************************************************/
  23. #define TOKEN_MAX  512
  24. typedef int E_CHAR;                                       /* all chars +EOF */
  25. typedef enum {FALSE=0, TRUE=1} bool;                      /* suits my debug */
  26. typedef enum
  27. {HEADER, IDENTIFIER, NUMBER, CHARACTER, STRING, OPERATOR, PUNCTUATOR,
  28.     OTHER, UNKNOWN, END_OF_FILE, WHITE_VERTICAL, WHITE_HORIZONTAL}
  29. TOKEN_CLASS;
  30. E_CHAR current_char, look_ahead='\n';                     /* start with new */
  31. FILE *program_file;
  32. char token_chars[TOKEN_MAX+1];
  33. int token_count, token_length;
  34. bool header_flag, echo_tokens;                            /* handle <....h> */
  35. TOKEN_CLASS current_token;
  36. /****************************************************************************/
  37. E_CHAR next_char(/*void*/)  /* a function for ANSI C Translation Phases 1+2 */
  38. /****************************************************************************/
  39. {static E_CHAR next_one='\n';                /* internal character cache */
  40.     current_char=look_ahead;                    /* copy external lookaheads */
  41.     if(token_length<TOKEN_MAX)
  42.       {token_chars[token_length++]=current_char;           /* assemble val */
  43.         token_chars[token_length]='\0';}
  44.     do {look_ahead=next_one; next_one=getc(program_file);   /* get next raw */
  45.         if(look_ahead=='?' && next_one=='?')    /* ANSI trigraph 2.1.1.2(1) */
  46.       {int next_two=getc(program_file);    /* look ahead one more char */
  47.             char *translated=strchr("#[\\]^{|}~=(/)'<!>-"+9, next_two);
  48.             if(translated)                      /* test trigraph recognised */
  49.           {look_ahead=*(translated-9);     /* copy char to replace ??x */
  50.                 next_one=getc(program_file);}   /* read following character */
  51.             else ungetc(next_two, program_file);}  /* otherwise put ch back */
  52.         if(look_ahead!='\\' || next_one!='\n') return(current_char);  /* OK */
  53.         next_one=getc(program_file);}           /* ANSI splicing 2.1.1.2(2) */
  54.     while(1);}  /* I don't like infinite loops; this one makes code clearer */
  55. /****************************************************************************/
  56. TOKEN_CLASS next_token(/*void*/) /* function for ANSI C Translation Phase 3 */
  57. /****************************************************************************/
  58. #define Digits     '0': case '1': case '2': case '3': case '4': case '5':\
  59.    case '6': case '7': case '8': case '9'
  60. #define Double     '#': case '+': case '&': case '|'
  61. #define Letter     'A': case 'B': case 'C': case 'D': case 'E': case 'F':\
  62.  case 'G': case 'H': case 'I': case 'J': case 'K': case 'M': case 'N':\
  63.  case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':\
  64.  case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b':\
  65.  case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i':\
  66.  case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p':\
  67.  case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w':\
  68.  case 'x': case 'y': case 'z': case '_'
  69. #define Others     '$': case '@': case '`': case '\\'
  70. #define Puncts     '(': case ')': case ',': case ';': case '[': case ']':\
  71.  case '{': case '}'
  72. #define Quotes     '"': case'\''
  73. #define Simple     ':': case '?': case '~'
  74. #define Single     '!': case '%': case '*': case'=' : case'^'
  75. #define WhiteH     ' ': case'\t'
  76. #define WhiteV    '\n': case'\v': case'\f'
  77. {token_length=0; switch(next_char())
  78.  case '.':   {if(!isdigit(look_ahead))                    /* period/ellipsis */
  79.                 {while(look_ahead=='.') next_char();     /* grab any number */
  80.            case Puncts:     return(PUNCTUATOR);}                    /* arbitrary class */
  81.         case Digits: while(isalnum(look_ahead) || look_ahead=='.' || look_ahead=='_')
  82.                  if((next_char()=='e' || current_char=='E') /* opt exponent */
  83.                  && ( look_ahead=='+' || look_ahead=='-')) next_char();
  84.              return(NUMBER);                             /* unusual syntax! */
  85.         case 'L':    if(look_ahead=='"' || look_ahead=='\'') next_char();  /* L"... */
  86.              else                                        /* reserved words, */
  87.          case Letter:    {while(isalnum(look_ahead) || look_ahead=='_') next_char();
  88.                  return(IDENTIFIER);                     /* all identifiers */
  89.                 case '<':        if(header_flag) current_char='>';       /* flag set in Ph4 */
  90.                  else
  91.          case '>':           {if(look_ahead==current_char) next_char(); /* >> and << */
  92.                      if(look_ahead=='=') next_char();    /*  >= >>= <= <<=  */
  93.                      return(OPERATOR);}}                 /* compare & shift */
  94.         case Quotes:{E_CHAR quote_char=current_char;             /* "_" '_' and <_> */
  95.              do if(look_ahead=='\\') {next_char(); next_char();}  /* \n etc */
  96.              while(next_char()!=quote_char && current_char!=EOF); /* match? */
  97.              return(header_flag? HEADER: quote_char=='"'? STRING: CHARACTER);}
  98.         case '/':    if(look_ahead=='*')                         /* start a comment */
  99.           {next_char();                            /* kill current /, */
  100.                  while(next_char()!='*' || look_ahead!='/')  /* and first * */
  101.                      if(current_char==EOF) break;        /* don't lock loop */
  102.                  next_char();    token_chars[0]=' ';     /* replace comment */
  103.                  token_length=1; token_chars[1]='\0';    /* by single space */
  104.          case WhiteH:     return(WHITE_HORIZONTAL);               /* may consolidate */
  105.          case WhiteV:     return(WHITE_VERTICAL);                 /* in later phases */
  106.          case '-':        if(look_ahead=='>') {next_char(); return(OPERATOR);} /* -> */
  107.          case Double:     if(look_ahead==current_char){next_char(); return(OPERATOR);}}
  108.         case Single: if(look_ahead=='=') next_char();            /* finds op= forms */
  109.         case Simple: return(OPERATOR);                           /* deal with ++ += */
  110.         case Others: return(OTHER);                              /* few unused char */
  111.         case EOF:    return(END_OF_FILE);                        /* want EOF repeat */
  112.         default:     return(UNKNOWN);}}                          /* is non printing */
  113. /****************************************************************************/
  114. TOKEN_CLASS print_token(/*void*/)          /* application specific function */
  115. /****************************************************************************/
  116. {current_token=next_token();    /* alter function to print selected info */
  117.     if(current_token<END_OF_FILE)
  118.       {switch (current_token)
  119.      {
  120.      case HEADER:
  121.             token_count-=2;
  122.         if (echo_tokens)
  123.               printf("    #include %s shouldn't have counted; subtracting\n",
  124.                    token_chars);
  125.             break;
  126.       case STRING:  
  127.             if (echo_tokens)
  128.                 printf("%5d-%d: %d [%s]\n", token_count+1, token_count+token_length,
  129.                     current_token, token_chars);
  130.             token_count += token_length;
  131.             break;
  132.       default:
  133.             token_count++;
  134.             if (echo_tokens)
  135.                 printf("%5d: %d [%s]\n", token_count, current_token, token_chars);
  136.       }
  137.      }
  138.     return(current_token);}
  139. /****************************************************************************/
  140. /* int main(int argc, char *argv[])/* program expects file-name as argument */
  141. main(argc, argv) int argc; char *argv[];
  142. /****************************************************************************/
  143. {
  144.     if((argc<2)||(argc>3)||((argc==3)&&(strcmp(argv[1],"-p"))))
  145.    {fputs("Usage: tokount [-p] file.c\n",stderr); return(/*EXIT_FAILURE*/1);}
  146.     echo_tokens=(argc==3);                     /* Print tokens if -p option */
  147.     if(!(program_file=fopen(argv[argc-1], "r"))) {perror(argv[argc-1]); return(errno);}
  148.         /*** do not alter this loop, put changes in print_token ***/
  149.     do {while(print_token()==WHITE_VERTICAL||current_token==WHITE_HORIZONTAL);
  150.         if(strcmp(token_chars, "#"))       continue;
  151.         while(print_token()==WHITE_HORIZONTAL);
  152.         if(strcmp(token_chars, "include")) continue;   /* double negative!! */
  153.         header_flag=TRUE;
  154.         while(print_token()==WHITE_HORIZONTAL);
  155.         header_flag=FALSE;}
  156.     while(current_token!=END_OF_FILE);
  157.     if(ferror(program_file)) {perror(argv[argc-1]); return(errno);}
  158.     printf("%d\n", token_count);
  159.     return(/*EXIT_SUCCESS*/0);}
  160. /********************************* the end **********************************/
Advertisement
Add Comment
Please, Sign In to add comment