Eliminar todos los comentarios de un progtwig en C: ¿Alguna posible mejora de este código?

Estoy aprendiendo C del libro K&R y para el ejercicio 1.23 en el primer capítulo, tengo que escribir un progtwig que elimine todos los comentarios dado el código C que el usuario ingresa. Este es mi progtwig completo hasta ahora. ¿Hay alguna mejora que pueda hacer?

/** Tuesday, 10/07/2013 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. **/ #include  #define MAX_LENGTH 65536 #define NOT_IN_COMMENT 0 #define SINGLE_COMMENT 1 #define MULTI_COMMENT 2 main() { char code[MAX_LENGTH]; /* Buffer that stores the inputted code */ int size = 0; /* Length of the inputted code */ int loop; /* Integer used for the for loop */ char c; /* Character to input into */ int status = NOT_IN_COMMENT; /* Are we in a comment? What type? */ int in_string = 0; /* Are we inside of a string constant? */ char last_character; /* Value of the last character */ /* Input all code into the buffer until escape sequence pressed */ while ((c = getchar()) != EOF) code[size++] = c; code[size] = '\0'; /* Remove all comments from the code and display results to user */ for (loop = 0; loop < size; loop++) { char current = code[loop]; if (in_string) { if (current == '"') in_string = 0; putchar(current); } else { if (status == NOT_IN_COMMENT) { if (current == '"') { putchar(current); in_string = 1; continue; } if (current == '/' && last_character == '/') status = SINGLE_COMMENT; else if (current == '*' && last_character == '/') status = MULTI_COMMENT; else if (current != '/' || (current == '/' && loop < size-1 && !(code[loop+1] == '/' || code[loop+1] == '*'))) putchar(current); } else if (status == SINGLE_COMMENT) { if (current == '\n') { status = NOT_IN_COMMENT; putchar('\n'); } } else if (status == MULTI_COMMENT) { if (current == '/' && last_character == '*') status = NOT_IN_COMMENT; } } last_character = current; } } 

Mueva su eliminación de comentarios a una función (más útil), y lea una línea a la vez con fgets (), last_character es ambiguo (¿significa último o anterior?), Esto usa muchas menos llamadas a putchar (), solo Un printf (se podría usar pone) por línea, preserva la mayor parte de lo que estaba haciendo,

 #include  #include  #define MAX_LENGTH 65536 #define NOT_IN_COMMENT 0 #define SINGLE_COMMENT 1 #define MULTI_COMMENT 2 int status = NOT_IN_COMMENT; /* Are we in a comment? What type? */ int in_string = 0; /* Are we inside of a string constant? */ char* stripcomments(char* stripped,char* code) { int ndx; /* index for code[] */ int ondx; /* index for output[] */ char prevch; /* Value of the previous character */ char ch; /* Character to input into */ /* Remove all comments from the code and display results to user */ for (ndx=ondx=0; ndx < strlen(code); ndx++) { char current = code[ndx]; if (in_string) { if (current == '"') in_string = 0; stripped[ondx++] = current; } else { if (status == NOT_IN_COMMENT) { if (current == '"') { stripped[ondx++] = current; in_string = 1; continue; } if (current == '/' && prevch == '/') status = SINGLE_COMMENT; else if (current == '*' && prevch == '/') status = MULTI_COMMENT; else if (current != '/' || (current == '/' && ndx < strlen(code)-1 && !(code[ndx+1] == '/' || code[ndx+1] == '*'))) stripped[ondx++] = current; } else if (status == SINGLE_COMMENT) { if (current == '\n') { status = NOT_IN_COMMENT; stripped[ondx++] = '\n'; } } else if (status == MULTI_COMMENT) { if (current == '/' && prevch == '*') status = NOT_IN_COMMENT; } } prevch = current; } stripped[ondx] = '\0'; return(stripped); } int main(void) { char code[MAX_LENGTH]; /* Buffer that stores the inputted code */ char stripped[MAX_LENGTH]; while( fgets(code,sizeof(code),stdin) ) { //printf("%s\n",code); //strip comments... stripcomments(stripped,code); if( strlen(stripped) > 0 ) printf("%s",stripped); } } 

Te lo dejo a ti para eliminar las líneas en blanco adicionales.

Cuando manejes cadenas entre comillas, deberías detectar comillas escapadas ( \" ). Por ejemplo, "\"/* not a comment */\"" es una cadena válida, pero creo que tu código eliminará el comentario falso del medio de eso

Si desea ser realmente correcto, también debe manejar las continuaciones de línea (una línea que termina con a \ continúa en la línea siguiente). Para una mayor sensación de vello, también debes manejar los trigrafos. ??/" es una cita escapada, y ??/ al final de una línea es una continuación.

El estilo del código se ve bastante bien, aunque main debe declararse más adecuadamente como int main(void) .

Me queda bien, ¡bien hecho!

Tal vez podría mejorarse agregando algunos comentarios 🙂 Como guía general, agregue uno para cada condicional. Estaba comentando pero se detuvo justo en la parte jugosa, dentro del bucle. Pero el código parece bastante legible como está.

¿Funciona? ¿Lo has probado?

Parece que podría fallar si tengo una cadena que contiene una comilla doble escapada … por ejemplo, "He said, \"Hello, World!\"" .

 //GH PATEL COLLEGE OF ENGINEERING & TECHNOLOGY. //c program to remove comments from given src.txt file, and write back to dest.txt file. #include  int main() { FILE *src,*dest; char ch,pre,line[100]; int nflag,qflag,index; src=fopen("src.txt","r+"); dest=fopen("dest.txt","w+"); nflag=1; while(!feof(src)) { index=0; for(ch=fgetc(src);ch!=EOF && ch!='\n';) { if(ch=='"'&&pre!='\\') { qflag=0; for(;ch!='\n' && qflag==0;) { line[index++]=ch; pre=ch; ch=fgetc(src); if(ch=='"'&&pre!='\\') { qflag=1; line[index++]=ch; pre=ch; ch=fgetc(src); break; } } } else if(ch=='/') { pre=ch; ch=fgetc(src); if(ch=='/') { for(;fgetc(src)!='\n';); break; } if(ch=='*') { nflag=1; for(ch=fgetc(src);nflag==1;) { if(ch=='*') { pre=ch; ch=fgetc(src); if(ch=='/') { nflag=0; } } else { pre=ch; ch=fgetc(src); } } } } else { line[index++]=ch; pre=ch; ch=fgetc(src); } } line[index]='\0'; if(index>0) { line[index] = '\0'; fprintf(dest,"%s\n",line); fflush(stdin); } } getch(); fclose(src); fclose(dest); return 0; } 

Me gusta este hilo para incluir un “stripper de comentarios” en mi proyecto antes de entregarlo al analizador JSON. Sólo me gusta más un enfoque FSM. Espero que mi implementación sea comprensible y útil para cualquiera:

 #include  #include  void strip(int ch, FILE *stream) { static enum strip_states { STRIP_STATE_PUTC = 0, STRIP_STATE_SINGLE, STRIP_STATE_MULTI, STRIP_STATE_STRING, } state = STRIP_STATE_PUTC; static char _ch = 0; static unsigned char _nestlevel = 0; /* String */ if (state == STRIP_STATE_PUTC && ch == '"') { state = STRIP_STATE_STRING; } else if (state == STRIP_STATE_STRING && ch == '"') { state = STRIP_STATE_PUTC; /* Multiline */ } else if (_ch == '/' && ch == '*') { if (state == STRIP_STATE_PUTC) state = STRIP_STATE_MULTI; else if (state == STRIP_STATE_MULTI) _nestlevel++; } else if (_ch == '*' && ch == '/') { if (state == STRIP_STATE_MULTI && _nestlevel > 0) _nestlevel--; else if (state == STRIP_STATE_MULTI && _nestlevel == 0) state = STRIP_STATE_PUTC; /* Singleline */ } else if (state == STRIP_STATE_PUTC && _ch == '/' && ch == '/') { state = STRIP_STATE_SINGLE; } else if (state == STRIP_STATE_SINGLE && ch == '\n') { state = STRIP_STATE_PUTC; } /* Put character */ if ((state == STRIP_STATE_PUTC && ch != '/') || state == STRIP_STATE_STRING) fputc(ch, stream); _ch = ch; } int main(void) { int ch; while ((ch = fgetc(stdin)) != EOF) strip(ch, stdout); return 0; } 

Que funciona:

  • Comentarios de una sola línea "xxx // comment"
  • Comentarios multilínea normales "xxx /* comment\n another comment */ yyy"
  • Comentarios nesteds "xxx /* comment /* nested comment */ end of comment */ yyy

Actualmente no implementado y probado:

  • Comentario multilínea detrás de comentario de una sola línea
  • Continuacion de linea
  • Personajes escapados

Un cordial saludo, Jerry

Puede consultar el código simple a continuación:

 #include  int main(int argc, char **argv) { char code[1000]; char output[1000]; char ch; int i = 0; //store code in array while ((ch = getchar()) != EOF) { code[i++] = ch; } code[i] = '\0'; int index = 0; i = 0; //store removed comment code in output while (code[i] != EOF) { if (code[i] == '/' && code[i + 1] == '/') { //to remove single line comments while (code[i] != '\n') i++; } else if (code[i] == '/' && code[i + 1] == '*') { //to remove multi line comments i = i + 2; while (code[i] != '*' && code[i + 1] != '/') { i++; } i = i + 3; } else { //store the rest of the code in output array output[index++] = code[i++]; } } output[index] = '\0'; printf("%s", output); } 

ENTRADA:

 #include void main() { printf("Hello"); /*-------------------------------------------- ------------------Ignored by compiler------- -------------------------------------------- */ printf("By"); } 

SALIDA:

 #include void main() { printf("Hello"); printf("By"); }