Exercise 5-19 (undcl - Encode declarations, redundant parentheses)

Chapter_5     Exercise_5-18 Expanded_declarations     Exercise_5-20-1







Exercise 5-19     K&R, p. 126


Exercise 5-19. Modify undcl so that it does not add redundant parentheses to declarations.




undcl.c         download


#include <stdio.h> // for printf(), sprintf(), getchar(), EOF
#include <string.h> // for strcat(), strcpy()
#include <ctype.h> // for isalpha(), isalnum()

/*
dcl: optional *s direct-dcl
direct-dcl: name
(dcl)
direct-dcl()
direct-dcl[optional size]
*/
// char (*(*x())[])()
// x () * [] * () char
#define MAXTOKEN 100 // max token length
#define MAXOUTPUT 1000 // max length of output string

enum {NAME, PARENS, BRACKETS};

int gettoken(void);

int tokentype; // type of last token
char token[MAXTOKEN]; // last token string
char name[MAXTOKEN]; // identifier name
char datatype[MAXTOKEN]; // data type: char, int, etc.
char out[MAXOUTPUT]; // output string

int main() // convert word description to declaration
{
int type;
char temp[MAXOUTPUT+MAXTOKEN]; // to avoid warnings (temp not big enough)
// sprintf(), string printf(), writes into string temp,
// holding name[MAXTOKEN] and out[MAXOUTPUT]
while(gettoken() != EOF) // process a file
{ // first token is the name:
strcpy(out, token); // reset at the beginning of each line
type = gettoken(); // within the inner while(), move gettoken() to the end
if (type == EOF) {break;} // out of outer while(), end program
while (type != '\n' && type != EOF) // process one line
{ // line may end with EOF, not '\n'
if (type == PARENS || type == BRACKETS)
{strcat(out, token);} // f(), a[], a[10]
else if (type == '*')
{
if ((type = gettoken()) == PARENS || type == BRACKETS) // read extra token
{ // pointer to function or to array
sprintf(temp, "(*%s)", out);
strcpy(out, temp); // (*pf), (*pa)
strcat(out, token); // process extra token, () or []:
} // (*pf)(), (*pa)[], (*pa)[10]
else // pointer to data type
{
sprintf(temp, "*%s", out); // no extra parentheses added
strcpy(out, temp); // like int *p (data type is read at the end of line)
if (type == EOF)
{ // break here would only exit inner while()
return 1; // end program, signalling error
}
// else // process extra token in the next inner while() iteration
continue; // by skipping gettoken() at the end of inner while()
}
}
else if (type == NAME) // or STRING
{ // data type
sprintf(temp, "%s %s", token, out); // add data type at the beginning
strcpy(out, temp);
}
else {printf("Invalid token at \"%s\"\n", token);}

type = gettoken();
}

printf("%s\n", out);
}

return 0;
}

int getch(void);
void ungetch(int);

int gettoken(void)
{
int c;
char *p = token;

while((c = getch()) == ' ' || c == '\t')
{} // skip beginning whitespace

if (c == '(')
{
if ((c = getch()) == ')')
{
strcpy(token, "()");
return tokentype = PARENS;
}
else
{
ungetch(c);
return tokentype = '(';
}
}
else if (c == '[')
{
for (*p++ = c; isalnum(c = getch()); ) // isdigit() or 0x, then isxdigit()
{ // token holds [...]
*p++ = c;
}

if (c != ']')
{
printf("Expected ']'\n");
*p = '\0'; // end token string
return tokentype = c;
}
// else
*p++ = c; // ']'
*p = '\0'; // end token string

return tokentype = BRACKETS;
}
else if (isalpha(c))
{
for (*p++ = c; isalnum(c = getch()); )
{*p++ = c;}
*p = '\0'; // end string
ungetch(c);
return tokentype = NAME;
}
else {return tokentype = c;} // could be '*' or ')' or '\n' or EOF
}

// buffer for ungetch():
int buf = EOF-1; // not a real character, not even EOF

int getch(void) // get a (possibly pushed-back) character
{
if (buf < EOF)
{
return getchar();
}

int temp = buf; // buf >= EOF
buf = EOF-1; // reset buf

return temp;
}
// push character back on input (make it available for the next getch()):
void ungetch(int c)
{
buf = c;
}
/*
gcc undcl.c -o undcl
./undcl // Enter (input from keyboard)
apf [] * () char // Enter
char (*apf[])()
argv * * char // Enter
char **argv
comp () * void // Enter
void *comp()
comp * () void // Enter
void (*comp)()
x () * [] * () char // Enter
char (*(*x())[])()
// Ctrl^D in Linux, Ctrl^Z+Enter in Windows (EOF)

./undcl < undcl.txt > "dcl(copy).txt"
diff -s dcl.txt "dcl(copy).txt"
// Files dcl.txt and dcl(copy).txt are identical
meld dcl.txt "dcl(copy).txt"
// Files are identical
*/





Notes:  See undeclare for the text files. This time, the files dcl.txt and dcl(copy).txt are identical (no more redundant parentheses).
File name "dcl(copy).txt" is within quotes because the shell interprets parentheses (subshell).









Chapter_5     Exercise_5-18 BACK_TO_TOP Expanded_declarations     Exercise_5-20-1



Comments

Popular posts from this blog

Contents

Blogger Page Margins in Contempo