Exercise 5-20-2 (Expanded undeclare - Encode declarations)
Chapter_5 Exercise_5-20-1 | ch5-Exercises Chapter_6 |
Exercise 5-20 K&R, p. 126
Exercise 5-20. Expand dcl to handle declarations with function argument types, qualifiers like const, and so on.
Note: See Expanded_declarations for the text files.
unedcl.c download
#include <stdio.h> // for printf(), sprintf(), getchar(), EOF, NULL
#include <string.h> // for strcat(), strcpy(), strcmp()
#include <ctype.h> // for isalpha(), isalnum()
/*
dcl: datatype optional modifiers optional *s direct-dcl
direct-dcl: name
(dcl)
direct-dcl(optional arguments)
direct-dcl[optional size]
arguments: argument
argument, arguments
arguments, ...
argument: dcl with optional name
size: integral type
*/
#define FALSE 0
#define TRUE 1
#define MAXTOKEN 100 // max token length
#define MAXOUTPUT 5000 // max length of output string
#define ARGSEP ',' // argument separator
// static const short unsigned int (5 strings or words)
#define MAXNODTMODQ 10 // max no of data type words plus modifiers, qualifiers
#define MAXNOPQS 10 // max no of pointer qualifiers
enum {STRING, PARENS, BRACKETS, ELLIPSIS};
char *DTMODQ[] = // data types, modifiers, and qualifiers
{"char", "signed", "unsigned", "short", "int", "long", "float", "double",
"const", "static", "volatile", "register", "void", "" // empty string marks the end
}; // reserved words cannot be used as names
int gettoken(void);
int tokentype; // type of last token
char token[MAXTOKEN]; // last token string
char name[MAXTOKEN]; // identifier name
char datatype[MAXTOKEN*MAXNODTMODQ]; // data type, modifiers, qualifiers
char pointqs[MAXTOKEN*MAXNOPQS]; // pointer qualifiers
// read variable, array, function, or argument declaration
char *readDeclaration(void); // return pointer to the output string
// we assume the input file has no errors, so we don't have to do much
// error checking in this program
int main() // convert word description to declaration
{
tokentype = 0; // initialize
char *out;
while(tokentype != EOF) // process a file
{
out = readDeclaration(); // process a line
if (out != NULL)
{printf("%s\n", out);}
}
return 0;
}
// return pointer to the output string
char *readDeclaration(void) // read variable,
{ // array, function, or argument declaration
gettoken();
if (tokentype == EOF)
{return NULL;} // return to caller, readDeclaration() or main()
if (tokentype == '\n' || tokentype == ARGSEP ||
tokentype == ELLIPSIS || tokentype == ')')
{return "";} // the empty string, not NULL
char *p;
char line[MAXOUTPUT]; // read current line
char temp[MAXOUTPUT+MAXTOKEN*MAXNODTMODQ];
// to avoid warnings (temp not big enough)
// sprintf(), string printf(), writes into string temp,
// holding datatype[MAXTOKEN*MAXNODTMODQ] and line[MAXOUTPUT]
int i, match = FALSE;
line[0] = '\0'; // initialize; line[] is now the empty string; ""[0] == '\0'
// first token is normally the name, however, arguments have optional name
if (tokentype == STRING) // name, modifier, or qualifier
{ // modifiers, qualifiers are reserved words, name is not
for (i = 0; DTMODQ[i][0] != '\0'; i++)
{
if (strcmp(token, DTMODQ[i]) == 0)
{
match = TRUE;
break; // out of for()
}
}
if (!match) // found name
{ // if we find no name, line[] remains empty; in both cases
strcat(line, token); // we can append to line[] with strcat()
gettoken();
}
}
// process one line or argument
while (tokentype != '\n' && tokentype != EOF)
{ // line may end with EOF, not '\n' or other separator
if (tokentype == PARENS || tokentype == BRACKETS)
{strcat(line, token);} // f(), a[], a[10]
else if (tokentype == '(') // function with arguments
{ // arguments have optional names
strcat(line, "(");
p = readDeclaration();
if (p == NULL) {return NULL;}
strcat(line, p);
while (tokentype == ARGSEP)
{
strcat(line, ", ");
p = readDeclaration();
if (p == NULL) {return NULL;}
strcat(line, p);
}
if (tokentype == ELLIPSIS)
{
strcat(line, "..."); // strcat(line, token);
gettoken();
if (tokentype != ')')
{
printf("Missing ')'\n");
return NULL; // signal error
}
}
strcat(line, ")");
}
else if (tokentype == ARGSEP || tokentype == ELLIPSIS || tokentype == ')')
{ // for function arguments
p = line;
return p; // return to the caller, which handles the arguments
}
else if (tokentype == '*')
{ // read extra token:
if (gettoken() == '(' || tokentype == PARENS || tokentype == BRACKETS)
{ // pointer to function (with or without arguments) or to array
sprintf(temp, "(*%s)", line);
strcpy(line, temp); // (*pf), (*pa)
if (tokentype == '(') // process extra token in the next inner while() iteration
{continue;} // by skipping gettoken() at the end of inner while()
// else
strcat(line, token); // process extra token, () or []:
} // (*pf)(), (*pa)[], (*pa)[10]
else // pointer to data type
{
sprintf(temp, "*%s", line); // no extra parentheses added
strcpy(line, temp); // like int *p (data type is read at the end of line)
if (tokentype == EOF)
{ // break here would only exit inner while()
return NULL; // 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 (tokentype == STRING) // data type, modifier, qualifier
{ // name is not read here, it was read at the beginning of outer while()
strcpy(datatype, token);
while (gettoken() == STRING) // read extra token
{ // static const signed short int, const volatile *
strcat(datatype, " ");
strcat(datatype, token);
}
if (line[0] != '\0')
{ // add datatype at the beginning
sprintf(temp, "%s%s%s", datatype, (line[0] == '[') ? "" : " ", line);
strcpy(line, temp); // array[], not array []
}
else {strcpy(line, datatype);} // strcat(line, datatype);
// process extra token in the next inner while() iteration
continue; // by skipping gettoken() at the end of inner while()
}
else {printf("Invalid token at \"%s\"\n", token);}
gettoken();
}
p = line;
return p;
}
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 == ',') // argument separator
{
return tokentype = ARGSEP;
}
else if (c == '.')
{
if ((c = getch()) != '.' || (c = getch()) != '.')
{
printf("Expected ellipsis, ...\n");
return tokentype = c;
}
else
{
strcpy(token, "...");
return tokentype = ELLIPSIS;
}
}
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 = STRING;
}
else {return tokentype = c;} // could be ')' 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 unedcl.c -o unedcl
./unedcl // 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())[])()
f * * () int // Enter
int (**f)()
f const * const volatile const * () int // Enter
int (*const volatile const *const f)()
f (() int, ...) int // Enter
int f(int (), ...)
f ((() * int, ...) int, ...) int // Enter
int f(int (int *(), ...), ...)
// Ctrl^D in Linux, Ctrl^Z+Enter in Windows (EOF)
./unedcl < unedcl.txt > "edcl(copy).txt"
diff -s edcl.txt "edcl(copy).txt"
// Files edcl.txt and edcl(copy).txt are identical
meld edcl.txt "edcl(copy).txt"
// Files are identical
*/
Note: File name "edcl(copy).txt" is within quotes because the shell interprets parentheses (subshell).
Chapter_5 Exercise_5-20-1 | BACK_TO_TOP | ch5-Exercises Chapter_6 |
Comments
Post a Comment