Jeroen Jacobs
Jeroen Jacobs

Reputation: 1525

Condition is always true. Bug in my code, or bug in my IDE?

I've been doing some exercises from the "The C Programming language" (second edition), and I'm at 1-23, where you need to develop a program that strips out the comments.

This what I have so far:

#include <stdio.h>

#define CODE 0
#define START_COMMENT 1
#define END_COMMENT 2
#define COMMENT 3
#define INQUOTE 4

/* this is a test */

/* this is a *** comment maybe / but still testing */

main() {
    char c;
    char state=CODE;
    while ((c = getchar()) != EOF) {

        if(state == CODE) {
            if (c == '/') {
                state = START_COMMENT; /* this works? */
            }
            else if (c == '"' || c == '\'') {
                state = INQUOTE;
                putchar(c);
            }
            else {
                putchar(c);
            }
        }
        else if(state == INQUOTE) {
            if (c == '"' || c == '\'') {
                state = CODE;
                putchar(c);
            }
            else {
                putchar(c);
            }
        }
        else if(state == START_COMMENT) {
            if (c == '*') {
                state = COMMENT;
            }
            else {
                putchar('/');
                putchar(c);
                state = CODE;
            }
        }
        else if(state == COMMENT) {
            if (c == '*') {
                state = END_COMMENT;
            }
        }
        else if(state == END_COMMENT) {
            if (c == '/') {
                state = CODE;
            }
            else
                state = COMMENT;
        }
    }
}

I'm using CLion on Mac, and it complains that line 54 always evaluates to "true". Which is this line at the bottom:

else if(state == END_COMMENT) {

Despite this remark, the program seems to work so far...

Does that line always evaluates to true, and if so, why? Because I don't see anything wrong with it.

Upvotes: 0

Views: 165

Answers (1)

Gardener
Gardener

Reputation: 2660

As stated in the comments, this is much easier to debug as a switch statement. I converted it to a switch and the issues with the final if/else conditions went away.

I also am using CLion on a mac and saw the warnings that you were seeing.

Despite the comments above, your code handles the c style '/* .... */ comments correctly.

I think it is helpful to let people know that this a preprocessor that simply strips old-style c comments /*..*/ not //... from code and then puts out the stripped code.

The state machine is MUCH easier to read as a switch statement, and easier to debug as well.

Note that in one place, you were checking for one of two characters, which allowed the fallthrough style in one of the switch statements.

Sometimes, when it is easier to write the code more 'simply' rather than to figure out why the compiler feels that a condition will always be true, it is best to follow best practices and simplify.

#include <stdio.h>

const char CODE = 0;
const char START_COMMENT = 1;
const char END_COMMENT = 2;
const char COMMENT = 3;
const char INQUOTE = 4;

// Preprocessor which discards comments
int main() {
    int c;
    char state = CODE;
    while (EOF != (c = getchar())) {

        switch (state) {
            case CODE:

                switch (c) {
                    case '/':  // If we are in a comment, we will strip this section of the code
                        // check if this is the start of a comment:
                        state = POTENTIAL_COMMENT;
                        break;
                    case '"':
                    case '\'':
                        state = INQUOTE;
                        putchar(c);
                        break;
                    default:
                        putchar(c);
                }
                break;
            case INQUOTE:
                if (c == '"' || c == '\'') {
                    state = CODE;
                }
                putchar(c);
                break;
            case POTENTIAL_COMMENT:
                switch (c) {
                    case '*':   // We saw the '/', so now we se the '*' and we are in a comment, just eat the char
                        state = COMMENT;
                        break;
                    case '/':
                        state = LINE_COMMENT;
                        break;
                    default:
                        putchar('/');  // we saw a '/' before, but it wasn't really the start of a comment, so put the '/' back and the current char
                        putchar(c);
                        state = CODE;
                }
            case COMMENT:
                if (c == '*') {
                    state = END_COMMENT;
                }
                break;
            case LINE_COMMENT:
                if (c == '\n')
                    state = CODE;
                break;
            case END_COMMENT:
                if (c == '/') {
                    state = CODE;
                } else
                    state = COMMENT;
        }
    }
}

Upvotes: 1

Related Questions