0

I've started studying C in the university. The professor gave us a task - to write a program that counts the number of comments in an another C program. We still haven't talked about operating with files. I found a similar solution - C Program to count comment lines (// and /* */) . Modified it a bit and it actually works but I can't understand the enum stuff. Tried to rewrite it without enumerations but with no success (cuz we have to explain how to program works). My question is - is there a way to solve it without enumerations?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv) {

FILE *fp;
int c, i=0;
char ch;
char path[150];

unsigned int chars  = 0;
unsigned int multi  = 0;
unsigned int single = 0;

enum states { TEXT, 
    SAW_SLASH, 
    SAW_STAR, 
    SINGLE_COMMENT, 
    MULTI_COMMENT } state = TEXT;

printf("Write file's path. Separate the folders with TWO back slashes (\\)\n");
scanf("%s", &path);

fp = fopen(path, "r");
if ( !fp )
{
    fprintf(stderr, "Cannot open file %s\n", argv[1] );
}
else {
    while((c=fgetc(fp)) != EOF){

    switch( state ) {
        case TEXT :
        switch( c )
        {
            case '/'  : state = SAW_SLASH; break;
            default   : break;
        }
        break;
        case SAW_SLASH :
            switch( c )
            {
              case '/'  : 
                  printf("case SLASH case / \n");
                  state = SINGLE_COMMENT; 
                  break;
              case '*'  : 
                  printf("case SLASH case * \n");
                  state = MULTI_COMMENT; 
                  break;
              default   : 
                  state = TEXT; 
                  break;
            }
            break;
        case SAW_STAR :
            switch( c )
            {
                case '/'  : 
                    printf("case STAR case / \n");
                    state = TEXT; 
                    multi++; 
                    break;
                case '*'  : 
                    break;
                case '\n' : 
                    printf("case SLASH case 'NEW LINE' \n");
                    multi++; // fall through
                default   : 
                    state = MULTI_COMMENT; 
                    break;
            }
            break;
        case SINGLE_COMMENT :
            switch( c )
            {
              case '\n' : 
                  printf("case SINGLE case NEW LINE \n");
                  state = TEXT; 
                  single++; // fall through
              default   : 
                  break;
            }
            break;
        case MULTI_COMMENT :
            switch( c )
            {
              case '*'  : 
                  printf("case MULTI case * \n");
                  state = SAW_STAR; 
                  break;
              case '\n' : 
                break;
              default   : 
                  break;
            }
            break;

        default: // NOT REACHABLE
            break;
        }
    }
    fclose(fp);
    printf( "File                 : %s\n", argv[1] );
    printf( "Single-comment: %8u\n", single );
    printf( "Multi-comment: %8u\n", multi );

}
return 0;
}
Community
  • 1
  • 1
Alex
  • 485
  • 6
  • 18
  • 2
    I haven't read it carefully but enums really have nothing to do with it. I don't necessarily think you're properly doing the assignment, but using #define for the states should work just the same. Also, are you sure you don't have to make it not comments in strings? (It looks like this would count "// not a comment" as a comment). – Lupe Nov 25 '16 at 20:29
  • @Lupe Tested the code and works fine. But i'm trying to find an alternative way to do it. – Alex Nov 25 '16 at 20:31
  • @Lupe PS: Actually you are write. "// not a comment" is considered a comment. Anyway, still gotta find an alternative. – Alex Nov 25 '16 at 20:34
  • It is not trivial: the string literal may contain an escaped `\"` which does *not* mark the end of the string. Just as a comment may contain `"`. – Weather Vane Nov 25 '16 at 20:35
  • This is written using a pattern called "State machine". The "enum stuff" is just a symbolic names for the states. – Eugene Sh. Nov 25 '16 at 20:36
  • @Alex Like I said, the enums don't matter. Use #defines or C-style constants if you prefer, but they'd just be a somewhat more confusing version of the enums. Do you have to exclude comments in strings? I doubt you'd get an assignment with that sort of requirement before learning how to use enums, but I may be wrong. – Lupe Nov 25 '16 at 20:38
  • Your code includes `"… Separate the folders with TWO back slashes (\\)…"`. Note that when you read a string from the terminal, you do not need to double up the backslashes; that is only a problem in C source code. Note that your message prints just one backslash; that may have been what you intended, but if you intended to print two, you need to write ``\\\\`` to embed two adjacent backslashes in the output string. – Jonathan Leffler Nov 25 '16 at 20:41
  • @Lupe The file which is going to be read shouldn't compulsory work. Actually just for the test i'm reading a PHP file. The assignment says: "Write a C program which reads another C program and counts the number of the comments in it." So the program which is going to be read doesn't have to me executable or something – Alex Nov 25 '16 at 20:44
  • But surely it's useless trying to count the comments in a source code of a different language, or a C source which contains syntax errors?? – Weather Vane Nov 25 '16 at 20:46
  • As I said - it doesn't matter if the source is executable or not. Just have to count the comments if there are such. – Alex Nov 25 '16 at 20:50
  • Note that a compiler-level comprehension of comments requires you to understand strings and character constants and backslash-newline combinations (and nominally trigraphs too). The code shown handles none of those. Mostly that doesn't matter; when did you last see 'real' C code that had a slash, backslash, newline, star sequence to start a comment? Backslash-newline after a `//` comment start continues the 'single line' comment onto the next line, though. – Jonathan Leffler Nov 25 '16 at 20:51
  • @Alex it matters if you find an unmatched comment termination `*/`. How many comments does that make? 0 or 1? And how many preceding `//` style comments was it supposed to "comment-out"? – Weather Vane Nov 25 '16 at 20:59
  • Well 0 but we are newbies here. It's not expected from us to handle these situations. Let's say we are expected to read a simple file with a couple of comments in it. Nothing else. There won't be "// blah blah" or unclosed multi-line comments. – Alex Nov 25 '16 at 21:04
  • In that case you should have written it yourself instead of whipping another's work. "I found it on the internet but I can't make it answer my homework". – Weather Vane Nov 25 '16 at 21:07
  • The problem is that the professor will talk about manipulating files next month and we have to finish the task by the end of next week. I made it to fit my task but don't actually understand how the enums work here. So I wanted a help to make an alternative solution – Alex Nov 25 '16 at 21:12

1 Answers1

0

Since enum is equivalent to a bunch of #define 's, you can replace this part of the code:

enum states {
    TEXT, 
    SAW_SLASH, 
    SAW_STAR, 
    SINGLE_COMMENT, 
    MULTI_COMMENT
} state = TEXT;

with:

#define TEXT           0
#define SAW_SLASH      1
#define SAW_STAR       2
#define SINGLE_COMMENT 3
#define MULTI_COMMENT  4

int state = TEXT;
Zhigang An
  • 296
  • 2
  • 13