// no-comment.c
// Řešení IJC-DU1, příklad b), 22.3.2024
// Autor: Roman Nečas, FIT
// Přeloženo: gcc 13.2.1


#include <stdio.h>
#include "error.h"

int main(int argc, char *argv[])
{
    FILE *fp;
    int state = 0;
    int c;
    int lastChar = 0; // To keep track of the last character to handle line continuation in comments

    if (argc > 2)
    {
        error_exit("Too many arguments");
    }

    if(argc == 2)
    {
        fp = fopen(argv[1], "r");
        if (!fp) {
            error_exit("Cannot open file: %s", argv[1]);
        }
    }
    else
    {
        fp = stdin;
    }

    while ((c = fgetc(fp)) != EOF)
    {
        switch (state)
        {
            case 0: // Normal code
                if (c == '/')
                {
                    state = 1; // Possible comment start
                }
                else if (c == '"')
                {
                    putchar(c);
                    state = 4; // String literal start
                }
                else if (c == '\'') // Handle single quotes
                {
                    putchar(c);
                    state = 7; // Character literal start
                }
                else
                {
                    putchar(c);
                }
                break;

            case 1: // After first '/'
                if (c == '*')
                {
                    state = 2; // Multi-line comment start
                }
                else if (c == '/')
                {
                    // Transition to single-line comment state but do not output '/'
                    state = 6; // Single-line comment start
                }
                else
                {
                    putchar('/'); // Not a comment, print '/' and current char
                    putchar(c);
                    state = 0;
                }
                break;

            case 2: // Inside multi-line comment
                if (c == '*')
                {
                    state = 3; // Possible end of comment
                }
                break;

            case 3: // Possible end of multi-line comment
                if (c == '/')
                {
                    state = 0; // End of comment
                }
                else if (c != '*')
                {
                    state = 2; // Still inside comment
                }
                break;

            case 4: // Inside string literal
                if (c == '\\')
                {
                    putchar(c);
                    c = fgetc(fp); // Read next character
                    putchar(c); // Print escaped character
                    // Do not change state, stay in string literal
                }
                else if (c == '"')
                {
                    putchar(c); // End of string literal
                    state = 0;
                }
                else
                {
                    putchar(c); // Part of string literal
                }
                break;

            case 5: // After escape character in string literal
                putchar(c); // Print escaped character
                state = 4;
                break;

            case 6: // Inside single-line comment
                if (c == '\n')
                {
                    if (lastChar != '\\') // If not a continuation
                    {
                        putchar(c); // Ensure newline is outputted to maintain original structure
                        state = 0; // End of single-line comment
                    }
                    // If it was a continuation, simply ignore and continue in state 6
                }
                break;

            case 7: // Inside character literal
                putchar(c);
                if (c == '\\')
                {
                    state = 8; // Escape sequence within character literal
                }
                else if (c == '\'')
                {
                    state = 0; // End of character literal
                }
                break;

            case 8: // After escape character in character literal
                putchar(c); // Print escaped character
                state = 7; // Return to character literal state
                break;
        }
        lastChar = c; // Update lastChar at the end of the loop
    }

    if (ferror(fp))
    {
        error_exit("Read error\n");
    }

    if (state != 0)
    {
        error_exit("Unterminated comment or string\n");
    }

    fclose(fp);
    return 0;
}
