#include <stdio.h>
#include <string.h> //for strcpy(), strcat()
#include <ctype.h> //for isalpha(), isalnum()
//compile with: gcc -Wall -Wextra cc-c.c -o cc-c
//run with: printf 'x () * [] * () char\n' | ./cc-c # char (*(*x())[])()
// or: printf 'daytab * [13] int\n' | ./cc-c # int (*daytab)[13]
// or: printf 'comp * () void\n' | ./cc-c # void (*comp)()
// or: printf 'argv * * char\n' | ./cc-c # char (*(*argv)) correct, but with redundant ()
// or: printf 'daytab [13] * int\n' | ./cc-c # int (*daytab[13]) correct, but with redundant ()
//K&R2 section 5.12: undcl, the reverse of dcl (archived just below).
//It reads a declaration written as words -- in a short form, one token
//per word -- and turns it back into C:
//
// x () * [] * () char -> char (*(*x())[])()
//
//The words are the same order dcl prints them in, shortened:
// x () * [] * () char
// x: function returning pointer to array[] of pointer to function
// returning char
//
//How it works: out holds the declaration built so far, and each token
//WRAPS it from the inside out:
//
// token rule out
// x start x
// () append x()
// * wrap as (*...) (*x())
// [] append (*x())[]
// * wrap as (*...) (*(*x())[])
// () append (*(*x())[])()
// char put type in front char (*(*x())[])()
//
//Every * gets parentheses around it, needed or not, because undcl
//doesn't look ahead to see whether a () or [] follows. So "argv * *
//char" gives char (*(*argv)) -- correct C, but char **argv is what a
//person would write. Exercise 5-19 asks you to remove the redundant
//parentheses.
//
//sprintf is printf into a string instead of onto the screen:
//sprintf(temp, "(*%s)", out) writes "(*" + out + ")" into temp. It
//can't write into out directly -- out is also the input being read --
//hence temp, then strcpy back into out.
//
//Fixed from the book's text:
//1. main() -> int main(void), as in dcl (gcc 15 / C23).
//2. Added printf("%s\n", out) after the inner loop -- without it the
// declaration is built and never printed.
//3. temp was char temp[MAXTOKEN] -- 100 bytes -- but sprintf copies
// all of out (up to 1000) into it. gcc -Wall caught it:
// warning: '%s' directive writing up to 999 bytes into a
// region of size 98 [-Wformat-overflow=]
// A declaration over ~97 characters would overflow temp and
// overwrite whatever memory follows. temp is now MAXTOKEN + MAXOUT,
// big enough for token + ' ' + out.
//
//gettoken, getch and ungetch are unchanged from dcl.
#define MAXTOKEN 100
#define MAXOUT 1000
enum { NAME, PARENS, BRACKETS };
int gettoken(void);
int tokentype; //type of last token
char token[MAXTOKEN]; //last token string
char out[MAXOUT];
//undcl: convert word descriptions to declarations
int main(void)
{
int type;
char temp[MAXTOKEN + MAXOUT]; //room for token, a blank and out
while (gettoken() != EOF) {
strcpy(out, token);
while ((type = gettoken()) != '\n')
if (type == PARENS || type == BRACKETS)
strcat(out, token);
else if (type == '*') {
sprintf(temp, "(*%s)", out);
strcpy(out, temp);
} else if (type == NAME) {
sprintf(temp, "%s %s", token, out);
strcpy(out, temp);
} else
printf("invalid input at %s\n", token);
printf("%s\n", out);
}
return 0;
}
//gettoken: return next token
int gettoken(void)
{
int c, getch(void);
void ungetch(int);
char *p = token;
while ((c = getch()) == ' ' || c == '\t')
;
if (c == '(') {
if ((c = getch()) == ')') {
strcpy(token, "()");
return tokentype = PARENS;
} else {
ungetch(c);
return tokentype = '(';
}
} else if (c == '[') {
for (*p++ = c; (*p++ = getch()) != ']'; )
;
*p = '\0';
return tokentype = BRACKETS;
} else if (isalpha(c)) {
for (*p++ = c; isalnum(c = getch()); )
*p++ = c;
*p = '\0';
ungetch(c);
return tokentype = NAME;
} else
return tokentype = c;
}
//--- from section 4.3 ---
#define BUFSIZE 100
char buf[BUFSIZE]; //buffer for ungetch
int bufp = 0; //next free position in buf
//getch: get a (possibly pushed back) character
int getch(void)
{
return (bufp > 0) ? buf[--bufp] : getchar();
}
//ungetch: push character back on input
void ungetch(int c)
{
if (bufp >= BUFSIZE)
printf("ungetch: too many characters\n");
else
buf[bufp++] = c;
}
win@DESKTOP-MEIH88T:~/webdev-projects$ gcc -Wall -Wextra cc-c.c -o cc-c
win@DESKTOP-MEIH88T:~/webdev-projects$ printf 'x () * [] * () char\n' | ./cc-c
char (*(*x())[])()
win@DESKTOP-MEIH88T:~/webdev-projects$ printf 'daytab * [13] int\n' | ./cc-c
int (*daytab)[13]
win@DESKTOP-MEIH88T:~/webdev-projects$ printf 'comp * () void\n' | ./cc-c
void (*comp)()
win@DESKTOP-MEIH88T:~/webdev-projects$ printf 'argv * * char\n' | ./cc-c
char (*(*argv))
win@DESKTOP-MEIH88T:~/webdev-projects$ printf 'daytab [13] * int\n' | ./cc-c
int (*daytab[13])
win@DESKTOP-MEIH88T:~/webdev-projects$ a combination of symbols : code interesting