Is there any way to do uppercase to lowercase and vice versa for COMMENTS? For example:
*** input_file.c ***
#include <stdio.h>
/* My FIRST program */
void main(void) {
printf("Hello world!\n"); // PRINT Message
}
*** output_file.c ***
#include <stdio.h>
/* mY first PROGRAM */
void main(void) {
printf("Hello world!\n"); // print mESSAGE
}
I've seen codes that lowercase to uppercase strings or chars and vice versa for example with functions help, but is there any similar or any other code that does this work for comments? :
#include <stdio.h>
#include <string.h>
int main()
{
char s[1000];
printf("Enter the string: ");
gets(s);
strlwr(s);
printf("string in lowercase ='%s'\n",s);
return 0;
}
Thank you in advance
CodePudding user response:
Parsing the C syntax is a non trivial task. Here is a small program that strips comments from a C source file. You can modify it to change comments. Hint: start by changing comments to uppercase, then transpose the case of characters.
This program reads the file contents one byte at a time, via a function getcpp
that handles the infamous line continuation sequence, \
immediately followed by a newline, and maintains the line number for error messages.
The main()
function parses the C syntax including comments, characters constants and string literals. It supports most of the syntax but does not handle trigraphs (an obsolete feature of historical interest only).
As posted, it removes all comments, replacing them with a space or a newline as appropriate. Study the code and see how you can modify it for your purpose. Learning by example is a good method, once you get the program to do what you need, you can try and rewrite one from scratch to hone your skills and make progress.
Here is the code:
/* strip C comments by chqrlie */
#include <errno.h>
#include <stdio.h>
#include <string.h>
/* read the next byte from the C source file, handing escaped newlines */
int getcpp(FILE *fp, int *lineno_p) {
int ch;
while ((ch = getc(fp)) == '\\') {
if ((ch = getc(fp)) != '\n') {
ungetc(ch, fp);
return '\\';
}
*lineno_p = 1;
}
if (ch == '\n')
*lineno_p = 1;
return ch;
}
int main(int argc, char *argv[]) {
FILE *fp = stdin, *ft = stdout;
const char *filename = "<stdin>";
int ch, lineno;
if (argc > 1) {
if ((fp = fopen(filename = argv[1], "r")) == NULL) {
fprintf(stderr, "Cannot open input file %s: %s\n",
filename, strerror(errno));
return 1;
}
}
if (argc > 2) {
if ((ft = fopen(argv[2], "w")) == NULL) {
fprintf(stderr, "Cannot open output file %s: %s\n",
argv[2], strerror(errno));
return 1;
}
}
lineno = 1;
while ((ch = getcpp(fp, &lineno)) != EOF) {
int startline = lineno;
if (ch == '/') {
if ((ch = getcpp(fp, &lineno)) == '/') {
/* single-line comment */
//putc('/', ft);
//putc('/', ft);
while ((ch = getcpp(fp, &lineno)) != EOF && ch != '\n') {
// Do something with the comment character
//putc(ch, ft);
}
if (ch == EOF) {
fprintf(stderr, "%s:%d: unterminated single line comment\n",
filename, startline);
break;
}
putc('\n', ft); /* replace comment with newline */
continue;
}
if (ch == '*') {
/* multi-line comment */
int lastc = 0;
//putc('/', ft);
//putc('*', ft);
while ((ch = getcpp(fp, &lineno)) != EOF) {
// Do something with the comment character
//putc(ch, ft);
if (ch == '/' && lastc == '*') {
break;
}
lastc = ch;
}
if (ch == EOF) {
fprintf(stderr, "%s:%d: unterminated comment\n",
filename, startline);
break;
}
putc(' ', ft); /* replace comment with single space */
continue;
}
putc('/', ft);
/* keep parsing to handle n/"a//"[i] */
}
if (ch == '\'' || ch == '"') {
int sep = ch;
const char *const_type = (ch == '"') ? "string" : "character";
putc(sep, ft);
while ((ch = getcpp(fp, &lineno)) != EOF) {
putc(ch, ft);
if (ch == sep)
break;;
if (ch == '\\') {
if ((ch = getcpp(fp, &lineno)) == EOF)
break;
putc(ch, ft);
}
if (ch == '\n') {
fprintf(stderr, "%s:%d: unescaped newline in %s constant\n",
filename, lineno - 1, const_type);
/* This is a syntax error but keep going as if constant was terminated */
break;
}
}
if (ch == EOF) {
fprintf(stderr, "%s:%d: unterminated %s constant\n",
filename, startline, const_type);
break;
}
continue;
}
putc(ch, ft);
}
if (fp != stdin)
fclose(fp);
if (ft != stdout)
fclose(ft);
return 0;
}
CodePudding user response:
I wrote and tested this program that does what you ask assuming that the only true C-comments either begin with //
and end with '\n'
or begin with /*
and end with */
It's not overly efficient as it only reads and writes one character at a time, but I think the code is pretty easy to understand:
#include <stdio.h>
#include <stdlib.h>
int main(int args, char *argv[]){
if(args != 3){ //Ensure the program was run with the proper number of arguments
fprintf(stderr,"USAGE: %s <input file> <output file>\n",argv[0]);
exit(EXIT_FAILURE);
}
FILE *in = fopen(argv[1],"r");
FILE *out = fopen(argv[2],"w");
if(!in || !out){ //Ensure both files opened successfully
fprintf(stderr,in ? "File %s unopenable for writing\n" : "File %s unopenable for reading\n",in ? argv[2] : argv[1]);
exit(EXIT_FAILURE);
}
int first,second;
second = fgetc(in);
if(second == EOF) //Input file is empty
exit(EXIT_SUCCESS);
first = second;
enum {line_comment,multiline_comment, string_text, non_comment} status = non_comment; //Keeps track of what type of text we're reading right now
while((second = fgetc(in)) != EOF){
switch(status){
case line_comment: //Flip the case of every letter until we find a newline
if(second == '\n' && first != '\\') //Allow escaped newlines
status = non_comment;
else if(second >= 'A' && second <= 'Z')
second = 'a'-'A';
else if(second >= 'a' && second <='z')
second -= 'a'-'A';
break;
case multiline_comment: //Flip the case of every letter until we find "*/"
if(first == '*' && second == '/') //We found the end of the comment
status = non_comment;
else if(second >= 'A' && second <= 'Z')
second = 'a'-'A';
else if(second >= 'a' && second <= 'z')
second -= 'a'-'A';
break;
case string_text:
if(second == '"' && first != '\\') //Look for end of string but ignore '\"' as those are allowed in strings
status = non_comment;
break;
case non_comment: //Look for the two-character comment beginnings "//" and "/*"
if(first == '/'){
if(second == '/')
status = line_comment;
else if(second == '*')
status = multiline_comment;
}
else if(second == '"' && first != '\\') //Also check for the beginning of a string
status = string_text;
break;
}
fputc(first,out); //Write last round's possibly-modified char to the output file
first = second;
}
fputc(first,out); //Output the last character of the file
exit(EXIT_SUCCESS); //Close all open files
}