#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 'argv * * char\n' | ./cc-c # char **argv (5.12's undcl: char (*(*argv)))
// or: printf 'daytab [13] * int\n' | ./cc-c # int *daytab[13] (5.12's undcl: int (*daytab[13]))
// or: printf 'daytab * [13] int\n' | ./cc-c # int (*daytab)[13] (parentheses needed: kept)
// or: printf 'x () * [] * () char\n' | ./cc-c # char (*(*x())[])()
// or: printf 'x * * [] char\n' | ./cc-c # char (**x)[]
//K&R2 exercise 5-19: modify undcl so that it does not add redundant
//parentheses to declarations.
//
//Builds on section 5.12's undcl (archived just below 5-18). undcl
//wrapped EVERY * as (*...), giving char (*(*argv)) for char **argv.
//
//When are the parentheses needed? Only when the NEXT token is () or
//[]. Those bind tighter than *, so without parentheses they'd attach
//to the name instead of to the pointer:
//
// *daytab[13] daytab is an array of pointers
// (*daytab)[13] daytab is a pointer to an array
//
//Anything else after the * -- another *, the type name, or the end of
//the line -- can't steal it, so "*" alone is enough.
//
//So at each *, undcl must LOOK AHEAD one token before deciding. It
//reads the next token, then marks it to be handed out again: a flag,
//prevtoken, makes the next gettoken() call return the same token
//instead of reading new input. That's "peek": see a token without
//using it up.
//
// x * * [] char
// * next is * -> no ( ) *x
// * next is [] -> ( ) (**x)
// [] (**x)[]
// char char (**x)[]
//
//Also fixed: the inner loop now stops at EOF as well as '\n'. undcl's
//loop waited only for '\n', so a last line without one made it loop
//forever printing "invalid input" (gettoken returns EOF every time).
#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];
int prevtoken = 0; //1: next gettoken() repeats the last token
//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' && type != EOF)
if (type == PARENS || type == BRACKETS)
strcat(out, token);
else if (type == '*') {
type = gettoken(); //peek at the next token...
prevtoken = 1; //...and hand it out again
if (type == PARENS || type == BRACKETS)
sprintf(temp, "(*%s)", out);
else
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;
if (prevtoken) { //a peeked-at token: repeat it
prevtoken = 0;
return tokentype;
}
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;
}
win@DESKTOP-MEIH88T:~/webdev-projects$ gcc -Wall -Wextra cc-c.c -o cc-c
win@DESKTOP-MEIH88T:~/webdev-projects$ printf 'int x)\nchar **argv\n' | ./cc-c
error: syntax error
argv: pointer to pointer to char
win@DESKTOP-MEIH88T:~/webdev-projects$ printf 'int (*pf\nint *daytab[13]\n' | ./cc-c
error: missing )
daytab: array[13] of pointer to int
win@DESKTOP-MEIH88T:~/webdev-projects$ printf 'int *\nvoid (*comp)()\n' | ./cc-c
error: expected name or (dcl)
comp: pointer to function returning void
win@DESKTOP-MEIH88T:~/webdev-projects$ printf 'int x[5\nint (*daytab)[13]\n' | ./cc-c
error: missing ]
daytab: pointer to array[13] of int
win@DESKTOP-MEIH88T:~/webdev-projects$ printf '*x\n\nchar c' | ./cc-c
error: expected a data type
c: char