/*-----------------------------------------------------------* | File: comcon.c - Last rev. MLO 1995-11-30 | | comcon copies from to , substituting | | C-style comments for C++-style comments (//...) . | | | | NOTE: this toy has been written before the release of the | | C++ standard that does not allow C++-style comments to be | | continued. The handling of "// ... \" lines therefore is | | NOT standard. See for details ISO-IEC 14882:1998 2.7.1 . | +------------------------------------------------------+----* | Author: Maurizio Loreti, aka MLO or (HAM) I3NOO | | Work: University of Padova - Department of Physics | | Via F. Marzolo, 8 - 35131 PADOVA - Italy | | Phone: +39 (049) 827-7216 FAX: +39 (049) 827-7102 | | EMail: loreti@padova.infn.it | | WWW: http://wwwcdf.pd.infn.it/~loreti/mlo.html | *------------------------------------------------------*/ #include #include int process(FILE*, FILE*); int main( int argc, char *argv[] ){ FILE *fpin, *fpout; int status = EXIT_FAILURE; const char filerr[] = "%s: couldn't open file \"%s\" for %sput\n"; if (argc != 3) { fprintf(stderr, "Usage:\t%s \n", argv[0]); fputs("\tCopy, with conversion of C++ comments to C comments.\n", stderr); } else { if ((fpin = fopen(argv[1], "r")) == 0) { fprintf(stderr, filerr, argv[0], argv[1], "in"); } else { if ((fpout = fopen(argv[2], "w")) == 0) { fprintf(stderr, filerr, argv[0], argv[2], "out"); fclose(fpin); } else { status = process(fpin, fpout); fclose(fpin); fclose(fpout); } } } return status; } int process( FILE *fpin, /* Input file */ FILE *fpout /* Output file */ ){ int c; /* Next character */ int lastc; /* Previous character */ unsigned int state = 0; unsigned long ln = 0; /* Line number */ /** | process() is implemented as a finite state machine. | The fgetc() loop is exited at EOF; the standard guarantees that every | input line has a trailing '\n', so I don't check e.g. for state == 4 | at the end (a C++ comment in the last line, without a newline and ended | by EOF). I don't care for errors like e.g. an EOF inside a string; these | situations are flagged by the compiler both in the input and in the | output file. **/ while ((c = fgetc(fpin)) != EOF) { switch (state) { /** | state 0: normal input **/ case 0: switch (c) { case '\"': /* String */ state = 1; break; case '\'': /* Character constant */ state = 2; break; case '/': /* To be investigated */ state = 3; break; } break; /** | state 1: inside a string (found a ") **/ case 1: switch (c) { case '\"': /* End of the string */ state = 0; break; case '\\': /* Escaped character */ state = 7; break; } break; /** | state 2: inside a character constant (found a ') **/ case 2: switch (c) { case '\'': /* End of the character constant */ state = 0; break; case '\\': /* Escaped character */ state = 8; break; } break; /** | state 3: we have found a /, maybe this is a comment... **/ case 3: switch (c) { case '/': /* C++ comment; change to C-style */ state = 4; c = '*'; break; case '*': /* C-style comment */ state = 5; break; default: /* Just a slash... */ state = 0; break; } break; /** | state 4: we are inside a C++ comment (found a sequence //). | When a newline is found, check for comment continuation on | the next line. **/ case 4: switch (c) { case '\n': /* End of comment; change to C-style */ if (lastc != '\\') { fputs(" */", fpout); if (ferror(fpout)) { perror("Write error"); return EXIT_FAILURE; } state = 0; } break; case '*': state = 9; break; } break; /** | state 5: we are inside a C comment **/ case 5: if (c == '*') state = 6; break; /** | state 6: we are inside a C comment, and there is an additional *; maybe | this is the end of the comment... **/ case 6: if (c == '/') state = 0; else state = 5; break; /** | state 7: an escaped character inside a string, like "...\"..." **/ case 7: state = 1; break; /** | state 8: an escaped character inside a character constant, like '\"' **/ case 8: state = 2; break; /** | state 9: after a star in a C++ comment - maybe a trouble... **/ case 9: if (c == '/') { fprintf(stdout, "Please, check line %lu for troubles...\n", ln+1); state = 4; } break; } /** | Output 'c' to file, and save it in 'lastc' **/ fputc((lastc = c), fpout); if (ferror(fpout)) { perror("Write error"); return EXIT_FAILURE; } if (c == '\n') ln++; } if (ferror(fpin)) { perror("Read error"); return EXIT_FAILURE; } fprintf(stdout, "%lu lines written\n", ln); return EXIT_SUCCESS; }