Quote:
>>>// ...your program \
>>> does not handle \
>>> multiline \
>>> C++ comments!!
>>Sorry, these beasts do not exist. From Stroustrup, The C++
>>programming language 2nd ed, page 478 (my ARM is at work):
>>"The characters // start a comment, which terminates at the end of the
>>line on which they occur."
>That is insufficient. Read 'Phases of Preprocessing' on page 607 -
>backslash-newline pairs are removed before comments are dealt with, so
>the 4 lines above comprise a single line for comment processing. This is
>the same general rule that C uses (with the specific difference that //
>does not introduce a comment in C).
OK, I tought that that was not legal C++. So, here comes the updated
version of comcon.c --- followed by a sample file. Enjoy...
---------------------------------Begin file: comcon.c
/*-----------------------------------------------------------*
| File: comcon.c - Last rev. MLO 1995-11-30 |
| comcon <in> <out> copies from <in> to <out>, substituting |
| C-style comments for C++-style comments (//...) . |
*------------------------------------------------------+----*
| Author: Maurizio Loreti, aka MLO or (HAM) I3NOO |
| Work: University of Padova - Department of Physics |
| Via F. Marzolo, 8 - 35131 PADOVA - Italy |
| Phone: ++39 (49) 827-7216 FAX: ++39 (49) 827-7102 |
| WWW: http://mvxpd5.pd.infn.it/wwwcdf/mlo.html |
*------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
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";
if (argc != 3) {
fprintf(stderr, "Usage:\t%s <input file> <output file>\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;
Quote:
}
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;
Quote:
}
---------------------------------Begin file: comcon.txt
This is a sample file for comcon.c :
/* This is a C style comment */
// This is a C++ style comment
" This is a string with embedded /* and */ "
" This is a string with embedded // "
" This is a string with an escaped quote \" , /* and */ "
" This is a string with an escaped quote \" and // "
// This is a C++ \
comment on \
several lines.
'\"' and an escaped character too
/* * // ... and more complicated things */
// The following line must be signalled:
// /* Trouble in line no. 15 */
---------------------------------End included files.
Maurizio Loreti http://mvxpd5.pd.infn.it/wwwcdf/mlo.html