K&R C Programs Exercise 5-18

Exercise 5-18. Make the basic dcl program recover from input errors.

K&R’s dcl program (Section 5.12) parses C declarations into English. It calls error() which prints a message and then exits — making it useless for batch input. The fix: on error, skip to the next newline and try to continue. This requires turning dcl‘s recursive calls into error-aware calls that propagate an error flag upward, and resetting state before retrying.

Solution

/* K&R Exercise 5-18 — dcl with error recovery
 * Compile: gcc -ansi -Wall ex5-18.c -o dcl18
 * Input:   C declaration strings, one per line
 * Example: int (*fp)(char *)
 *          char **argv */
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define MAXTOKEN 100

enum { NAME, PARENS, BRACKETS };

static char token[MAXTOKEN];
static char name[MAXTOKEN];
static char datatype[MAXTOKEN];
static char out[1000];
static int  tokentype;
static int  errf;          /* error flag */

int gettoken(void)
{
    int c;
    char *p = token;
    while ((c = getchar()) == ' ' || c == '\t')
        ;
    if (c == '(') {
        if ((c = getchar()) == ')') {
            strcpy(token, "()"); return tokentype = PARENS;
        } else {
            ungetc(c, stdin); return tokentype = '(';
        }
    } else if (c == '[') {
        *p++ = c;
        while ((*p++ = getchar()) != ']')
            ;
        *p = '\0';
        return tokentype = BRACKETS;
    } else if (isalpha(c)) {
        *p++ = c;
        while (isalnum(c = getchar()) || c == '_')
            *p++ = c;
        *p = '\0';
        ungetc(c, stdin);
        return tokentype = NAME;
    }
    return tokentype = c;
}

void dcl(void);

void dirdcl(void)
{
    int type;
    if (tokentype == '(') {
        dcl();
        if (tokentype != ')') {
            printf("error: missing )\n");
            errf = 1; return;
        }
    } else if (tokentype == NAME) {
        strcpy(name, token);
    } else {
        printf("error: expected name or (dcl)\n");
        errf = 1; return;
    }
    while ((type = gettoken()) == PARENS || type == BRACKETS) {
        if (type == PARENS)
            strcat(out, " function returning");
        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;
        strcpy(datatype, token);
        out[0] = '\0';
        dcl();
        if (errf) {
            /* skip rest of line and retry */
            while ((c = getchar()) != '\n' && c != EOF)
                ;
            printf("  (skipped malformed declaration)\n");
        } else if (tokentype != '\n') {
            printf("error: syntax error at '%s'\n", token);
        } else {
            printf("%s: %s %s\n", name, out, datatype);
        }
    }
    return 0;
}

Test It

printf "int (*fp)()\nchar **argv\nbad *** input\ndouble *x\n" | ./dcl18

Sample Output

fp:  function returning pointer to int
argv:  pointer to pointer to char
error: expected name or (dcl)
  (skipped malformed declaration)
x:  pointer to double

What This Exercise Teaches

  • Error recovery in recursive descent parsers — the standard approach is “panic mode”: on error, discard input until a synchronisation point (here, the next newline), reset state, and retry
  • Error flag propagation — setting errf = 1 and checking it at each recursive level avoids printing partial results for malformed input
  • Exit vs continue — a library function should recover; a standalone program might exit; the choice depends on whether the caller can meaningfully continue

Set Up Your C Environment

← Exercise 5-17  | 
Chapter 5 Solutions  | 
Exercise 5-19 →

Book: The C Programming Language, 2nd Ed — Kernighan & Ritchie

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>