Exercise 6-1 (getword)
Chapter_6 words | wordp Exercise_6-2 |
Exercise 6-1 K&R, p. 136
Exercise 6-1. Our version of getword() does not properly handle underscores, string constants, comments, or preprocessor control lines. Write a better version.
Notes:
We use a modified version of the program
nocomment from
Exercise_1-23,
Chapter_1.
We remove comments, character and string literals and, optionally, preprocessor control lines.
We considered include and
define to be C keywords,
so we added them to keytab[] and kept
the preprocessor lines (commented out a part of the program).
Then we can use the
words
program above to count the C keywords in the generated file(s).
nocomment.c download
#include <stdio.h> // for getchar(), putchar(), printf(), EOF
// test multiline preprocessor command:
#define FALSE \
0
#define TRUE 1
// testing a \
multiline \
C++ style \
comment
int main()
{
int c1, c2;
int insideComment = FALSE; // for C style comments
while ((c1 = getchar()) != EOF)
{
if (c1 == '\\') // escape character or sequence
{ /* skip \', \", \\ */ // \ continues a C++ style comment on the next line
c2 = getchar();
if (c2 == EOF)
{ // \ newline is part of a multiline preprocessor command or C++ comment
printf("\nEscape character not ended properly\n"); // Error message
return 1; // return from main(), end program with an error message
}
if (c2 == '\n') // not an escape, but a multiline command or comment
{
putchar(c1); // '\\'
putchar(c2); // '\n'
}
// else remove escape (print nothing)
}
else if (c1 == '\'') // character literal
{ // skip '\\', '"', '\"', '*', '#'
// remove character literal (print nothing)
while ((c1 = getchar()) != '\'')
{
if (c1 == EOF || c1 == '\n')
{
printf("\nCharacter literal not ended properly\n"); // Error message
return 1; // end program with an error message
}
// else
if (c1 == '\\') // escape char or sequence
{
// print nothing
c1 = getchar();
if (c1 == EOF)
{ // \ newline is part of a multiline preprocessor command or C++ comment
printf("\nEscape character not ended properly\n"); // Error message
return 1; // end program with an error message
}
// else skip char
}
// else skip char
} // here c1 == '\''
}
else if (c1 == '\"') // strings are on a single line
{ // Skip strings: "/*", "*/", "//", "'", "\"", "\'", "\\", "#"
// skip char (print nothing)
while ((c1 = getchar()) != '\"')
{
if (c1 == EOF || c1 == '\n')
{
printf("\nQuoted string not ended properly\n"); // Error message
return 1; // end program with an error message
}
else if (c1 == '\\') // escape char or sequence
{
// skip char (print nothing)
c1 = getchar();
if (c1 == EOF || c1 == '\n')
{
printf("\nEscape character not ended properly\n"); // Error message
return 1; // end program with an error message
}
// else skip char
}
// else skip char
} // here c1 == '\"'
} // continue with getchar() in outer while() to skip last '\"'
else if (c1 == '/')
{
c2 = /* testing */ getchar();
if (c2 == '/') // beginning of a C++ style comment
{
while ((c2 = getchar()) != EOF)
{ // \ continues a C++ style comment on the next line
if (c1 != '\\' && c2 == '\n')
{break;} // out of inner while()
c1 = c2; // c1 holds the penultimate char read
} // here c2 == '\n' or EOF, end of C++ style comment
if (c2 == EOF)
{return 0;} // end program normally, exit main()
putchar(c2); // putchar('\n'); // C++ style comment ends with '\n'
}
else if (c2 == '*') // beginning of a C style comment
{
insideComment = TRUE;
while (insideComment) // insideComment == 1 (insideComment != 0)
{
while ((c1 = getchar()) != '*')
{
if (c1 == EOF)
{
printf("\nC style comment not closed properly\n"); // Error message
return 1; // end program with an error message
}
// else skip chars till '*'
}
c2 = getchar();
if (c2 == EOF)
{
printf("\nC style comment not closed properly\n"); // Error message
return 1; // end program with an error message
}
else if (c2 == '/') // end of C style comment
{
insideComment = FALSE; // reset
break; // out of while(insideComment)
}
// else continue; // C style comment continues
} // end of while (insideComment)
}
else // no comment, false alarm
{
putchar(c1);
if (c2 != EOF) {putchar(c2);}
else {return 0;} // end program normally, exit main()
}
}
/*
else if (c1 == '#') // skip preprocessor control lines
{
while ((c2 = getchar()) != EOF)
{ // \ continues a preprocessor command on the next line
if (c1 != '\\' && c2 == '\n')
{break;} // out of inner while()
c1 = c2; // c1 holds the penultimate char read
} // here c2 == '\n' or EOF, end of preprocessor command
if (c2 == EOF)
{return 0;} // end program normally
// else skip line (don't print newline)
}
*/
else {putchar(c1);} // no comment
} // end of outer while()
return 0;
}
/*
gcc nocomment.c -o nocomment
./nocomment < nocomment.c > copy.c
// We cannot compile copy.c, it misses (preprocessor commands,)
// character and string literals
gcc words.c -o words
./words < copy.c
(2, break), (2, define), (9, else), (20, if), (1, include),
(3, int), (10, return), (6, while),
./nocomment < words.c > copy.c
./words < copy.c
(1, break), (7, char), (2, define), (2, else), (2, for),
(11, if), (3, include), (20, int), (7, return), (2, sizeof),
(3, struct), (4, void), (3, while),
rm copy.c // clean
*/
Chapter_6 words | BACK_TO_TOP | wordp Exercise_6-2 |
Comments
Post a Comment