From K&R exercise 1-23,
Write a program to remove all comments from a C program. Don't forget to handle quoted strings and character constants properly. C comments don't nest.
My solution,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 10000 // max input length
int get_input(char input[], int maxlen);
char * no_comments(char input[], int len);
_Bool comment_start(char input[], int idx);
_Bool comment_end(char input[], int idx, char *comments, int cdx);
_Bool quote_start(char input[], int idx);
_Bool quote_end(char input[], int idx);
int main(void)
{
char input[MAXLEN];
int len = get_input(input, MAXLEN);
char *scrubbed = no_comments(input, len);
printf("%s", scrubbed);
free(scrubbed);
}
int get_input(char input[], int maxlen)
{
int i;
char c;
for (i = 0; i < maxlen-1 && (c = getchar()) != EOF; i++) {
input[i] = c;
}
input[++i] = '\0';
return i;
}
char * no_comments(char input[], int len)
{
char *scrubbed = (char *) malloc((len+1) * sizeof(char));
int sdx = 0; // index
char *comments = (char *) malloc((len+1) * sizeof(char));
comments[0] = '\0';
int cdx = 0; // index
_Bool quoted = 0;
for (int idx = 0; idx <= len; idx++) {
if (strlen(comments) == 0) { // outside comment
if (!quoted && comment_start(input, idx)) {
comments[cdx++] = input[idx];
} else {
scrubbed[sdx++] = input[idx];
}
if (quoted && quote_end(input, idx)) {
quoted = 0;
} else if (!quoted && quote_start(input, idx)) {
quoted = 1;
}
} else { // inside comment
if (comment_end(input, idx, comments, cdx)) {
comments[0] = '\0'; // exit comment
cdx = 0;
} else {
comments[cdx++] = input[idx];
}
}
}
free(comments);
return scrubbed;
}
_Bool comment_start(char input[], int idx)
{
char nxt = input[idx+1];
return input[idx] == '/' && (nxt == '*' || nxt == '/');
}
_Bool comment_end(char input[], int idx, char *comments, int cdx)
{
char prev = comments[cdx-1];
char cur = input[idx];
char nxt = input[idx+1];
_Bool new_style = (cdx == 1 && cur == '/') || (cdx > 1 && comments[1] == '/');
_Bool old_style = (cdx == 1 && cur == '*') || (cdx > 1 && comments[1] == '*');
return (new_style && nxt == '\n') || (old_style && cdx > 2 && prev == '*' && cur == '/');
}
_Bool quote_start(char input[], int idx)
{
return input[idx] == '"' && input[idx-1] != '\'';
}
_Bool quote_end(char input[], int idx)
{
return input[idx] == '"' && input[idx-1] != '\\';
}