Search code examples
cobsolete

Identifying outdated C code in dragon book


I'm currently reading this edition of Compiler: Principles, Techniques & Tools.

I've never coded in C before (Although I've dabbled in C++) but from other programming knowledge most of the code makes sense, however I noticed a quirk which is that the functions are defined as such:

emit(t, tval)
    int t, tval
{
}

Figuring something was amiss, I looked it up and sure enough, that method of defining functions seems to be obsolete. I was hoping that someone could perhaps read the bits of code which I retyped below and warn me of any bad practices or obsolete techniques which I otherwise might not notice and pick up on. Also, any heads up on newer features of C which may help me write the code neater would be greatly appreciated. I am primarily looking for code which takes advantage of semantics, features, functions, etc that are no longer on the standard C specification, rather than from a stylistic point of view.

Also, if you have a copy of the book, and wouldn't mind flicking through it and seeing (or even from memory) if you can spot some other obsolete or redundant methods of doing things, that'd be fantastic too!

I wasn't sure whether this would fit better in CodeReview, if so, please comment and I'll delete and repost there, but I think since it's from a popular programming text, it might be more fitting here. Apologies if I'm incorrect.

global.h

#include <stdio.h>
#include <ctype.h>

#define BSIZE   128
#define NONE    -1
#define EOS     '\0'

#define NUM     256
#define DIV     257
#define MOD     258
#define ID      259
#define DONE    260

int tokenval;
int lineno;

struct entry {
    char *lexptr;
    int token;
};

struct entry symtable[];

lexer.c

#include "global.h"

char lexbuf[BSIZE];
int lineno = 1;
int tokenval = NONE;

int lexan()
{
    int t;

    while (1) {
        t = getchar();

        if (t == ' ' || t == '\t')
            ;
        else if (t == '\n')
            lineno++;
        else if (isdigit(t)) {
            ungetc(t, stdin);
            scanf("%d", &tokenval);
            return NUM;
        }
        else if (isalpha(t)) {
            int p, b = 0;
            while (isalnum(t)) {
                lexbuf[b] = t;
                b++;
                if (b >= BSIZE)
                    error("compiler error");
            }
            lexbuf[b] = EOS;
            if (t != EOF)
                ungetc(t, stdin);
            p = lookup(lexbuf);
            if (p == 0)
                p = insert(lexbuf, ID);
            tokenval = p;
            return symtable[p].token
        }
        else if (t == EOF)
            return DONE;
    }
}

parser.c

#include "global.h"

int lookahead;

parse()
{
    lookahead = lexan();
    while (lookahead != DONE) {
        expr(); match(';');
    }
}

expr()
{
    int t;
    term();
    while (1)
        switch (lookahead) {
            case '+': case '-':
                t = lookahead;
                match(lookahead); term(); emit(t, NONE);
                continue;
            default:
                return;
        }
}

term()
{
    int t;
    factor();
    while (1)
        switch (lookahead) {
            case '*': case '/':
                t = lookahead;
                match(lookahead); factor(); emit(t, NONE);
                continue;
            default:
                return;
        }
}

factor()
{
    switch (lookahead) {
        case '(':
            match('('); expr(); match(')'); break;
        case NUM:
            emit(NUM, tokenval); match(NUM); break;
        case ID:
            emit(ID, tokenval); match(ID); break;
        default:
            error("Syntax error");
    }
}

match (t)
    int t;
{
    if (lookahead == t)
        lookahead = lexan();
    else error("Syntax error");
}

Solution

  • From just skimming over the code, other than the old-style function argument declarations you've already brought up, the only other outdated feature I see is the lack of return type on functions that don't return anything. For example, the parse function returns nothing, which this old code denotes by declaring it as just parse(), yet modern code would require void parse(). There's also the issue that functions that don't take any arguments should have void between their parentheses (e.g., void parse(void)), but I don't think this is strictly required.