Exercise 5-20. Expand
dclto handle declarations with function argument types, qualifiers likeconst, and so on.
The basic dcl treats () as “function returning” but ignores argument types. This exercise adds: parameter lists inside (), type qualifiers (const, volatile), storage classes (static, extern), and the void type. The approach: when ( is encountered and the next token is not ), read a comma-separated parameter list and include it in the output.
Solution
/* K&R Exercise 5-20 — dcl with argument types, const, qualifiers
* Compile: gcc -ansi -Wall ex5-20.c -o dcl20
* Examples:
* int *f(char *, int)
* const char *strcpy(char *, const char *)
* void (*signal(int, void (*)(int)))(int) */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAXTOKEN 200
static char token[MAXTOKEN];
static char name[MAXTOKEN];
static char datatype[MAXTOKEN]; /* includes qualifiers */
static char out[2000];
static int tokentype;
static int errf;
static const char *qualifiers[] = {
"const", "volatile", "unsigned", "signed",
"short", "long", "static", "extern", "register", NULL
};
static int is_qualifier(const char *s)
{
const char **q;
for (q = qualifiers; *q; q++)
if (strcmp(s, *q) == 0) return 1;
return 0;
}
int gettoken(void)
{
int c;
char *p = token;
while ((c = getchar()) == ' ' || c == '\t')
;
if (c == '(') {
if ((c = getchar()) == ')') {
strcpy(token, "()");
return tokentype = '0'; /* PARENS_EMPTY */
}
ungetc(c, stdin);
return tokentype = '(';
}
if (c == '[') {
*p++ = c;
while ((*p++ = getchar()) != ']')
;
*p = '\0';
return tokentype = '[';
}
if (isalpha(c) || c == '_') {
*p++ = c;
while (isalnum(c = getchar()) || c == '_') *p++ = c;
*p = '\0';
ungetc(c, stdin);
return tokentype = 'a'; /* NAME_OR_QUAL */
}
return tokentype = c;
}
/* Read a parameter list up to the matching ')' — simple, one level */
static void read_params(char *buf)
{
int c, depth = 1;
char *p = buf;
*p++ = '(';
while (depth > 0 && (c = getchar()) != EOF) {
if (c == '(') depth++;
if (c == ')') { depth--; if (depth == 0) break; }
*p++ = c;
}
*p++ = ')';
*p = '\0';
}
void dcl(void);
void dirdcl(void)
{
int type;
if (tokentype == '(') {
dcl();
if (tokentype != ')') {
printf("error: missing )\n"); errf = 1; return;
}
} else if (tokentype == 'a') {
strcpy(name, token);
} else {
printf("error: expected name or (dcl)\n"); errf = 1; return;
}
while ((type = gettoken()) == '0' || type == '(' || type == '[') {
if (type == '0') {
strcat(out, " function returning");
} else if (type == '(') {
char params[500];
read_params(params);
strcat(out, " function");
strcat(out, params);
strcat(out, " returning");
gettoken(); /* consume next for outer loop */
} else {
strcat(out, " array");
strcat(out, token);
strcat(out, " of");
}
}
}
void dcl(void)
{
int ns = 0;
while (gettoken() == '*') ns++;
dirdcl();
if (errf) return;
while (ns-- > 0)
strcat(out, " pointer to");
}
int main(void)
{
int c;
while (gettoken() != EOF) {
errf = 0;
/* Collect qualifier(s) + base type into datatype */
datatype[0] = '\0';
while (tokentype == 'a' && is_qualifier(token)) {
if (datatype[0]) strcat(datatype, " ");
strcat(datatype, token);
gettoken();
}
if (datatype[0]) strcat(datatype, " ");
strcat(datatype, token); /* base type */
out[0] = '\0';
dcl();
if (errf) {
while ((c = getchar()) != '\n' && c != EOF)
;
} else {
printf("%s: %s %s\n", name, out, datatype);
}
}
return 0;
}
Test It
printf "int *p\nconst char *s\nint (*fp)(char *, int)\n" | ./dcl20
Sample Output
p: pointer to int s: pointer to const char fp: function(char *, int) returning pointer to int
What This Exercise Teaches
- Extending a grammar — adding qualifiers means recognising them before the base type; storing them in
datatypekeeps the recursive structure unchanged - Nested parameter lists —
read_paramsdoes brace-matching to handle function-pointer parameters likevoid (*)(int) - Real C declaration complexity — the full C declaration grammar is complex; this exercise shows why tools like
cdeclexist and why C99’stypedefis so commonly used to tame complex types
Set Up Your C Environment
← Exercise 5-19 |
Chapter 5 Solutions |
Chapter 6 Solutions →
Book: The C Programming Language, 2nd Ed — Kernighan & Ritchie