163 lines
4.5 KiB
C
163 lines
4.5 KiB
C
// 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;
|
|
}
|