
% cat newado.mail
From seismo!umcp-cs!elsie!ado Sun Sep 23 20:43:29 1984
Received: by decvax.UUCP (4.12/1.0)
        id AA04152; Sun, 23 Sep 84 20:43:24 edt
From: seismo!umcp-cs!elsie!ado
Received: from umcp-cs.UUCP by seismo.ARPA with UUCP; Sun, 23 Sep 84 19:01:23 EDT
Received: by maryland.ARPA (4.12/4.7)
        id AA11780; Sun, 23 Sep 84 18:52:09 edt
Date: Sun, 23 Sep 84 18:52:09 edt
Message-Id: <8409232252.AA11780@maryland.ARPA>
To: minow@decvax
Subject: A truly pathological bug...and (less kludgy?) line numbering fixes
Status: R

1.      The truly pathological bug is the treatment of lines like:
        
                #include "a /* comment */ b"

        which tell you about being unable to open file "a  b".
        (I suppose SOME pervert could name a file "a/**/b".)
        The "fix" to "doinclude":

        #ifdef OLDVERSION
                while ((c = get()) != EOF_CHAR && c != '\n' && c != delim) {
        #if COMMENT_INVISIBLE
                    if (c != COM_SPACE)
                        save(c);
        #else
                    save(c);
        #endif
                }
                save(EOS);
                if (c != delim)
                    goto incerr;
        #else
                instring = TRUE;
                while ((c = get()) != delim)
                        if (c == EOF_CHAR || c == '\n')
                                goto incerr;
                        else    save(c);
                save(EOS);
                instring = FALSE;
        #endif

2.  Here's my latest combination of changes to the last "cpp1.c" you sent
    that's designed to deal with line numbering.  It seems a bit better than
    my last set to me.

    First, eliminate newline faking in "addfile":
> #ifdef OLDVERSION
>       file->buffer[0] = '\n';         /* Fake initial newline to      */
>       file->buffer[1] = EOS;          /* initialize for first read    */
>       line = 0;                       /* Note correct line number     */
> #else
>       file->buffer[0] = EOS;
>       line = 1;
> #endif

    Since we no longer put in the phony new line, we avoid diddling "line"
    in "cppmain":

>               /*
>                * Explicitly output a #line at the start of cpp output so
>                * that lint (etc.) knows the name of the original source
>                * file.  If we don't do this explicitly, we may get
>                * the name of the first #include file instead.
>                */
>       #ifdef OLDVERSION
>               line = 1;
>               sharp();
>               line = 0;
>       #else
>               sharp();
>       #endif

    We also need not worry about the count being off the first time we do a
    "sharp" call, so the

X #ifdef OLDVERSION
X               if (counter > 4)                /* pending newlines.    */
X #else
X                                               /* pending newlines.    */
X               if (line == counter)
X                       --counter;              /* Forget addfile's fake '\n' */
X               if (counter > 4)
X #endif

    business of my last letter reverts to
>               if (counter > 4)                /* pending newlines.    */

    Double counting of lines is STILL a problem;
    the line skipping loop is still:
        
> #ifdef OLDVERSION
>           for (counter = 0;; counter++) {
> #else
>           counter = 0;
>           for ( ; ; ) {
> #endif
>               while (type[(c = get())] == SPA) /* Skip leading blanks */
>                   ;                           /* in this line.        */
>               if (c == '\n')                  /* If line's all blank, */
> #ifdef OLDVERSION
>                   ;                           /* Do nothing now       */
> #else
>                   ++counter;                  /* just count it        */
> #endif
>               else if (c == '#')              /* Is 1st non-space '#' */
>                   counter = control(counter); /* Yes, do a #command   */
>               else if (c == EOF_CHAR)         /* At end of file?      */
>                   break;
> #ifdef OLDVERSION
>               else if (flevel > 0)            /* #ifdef false?        */
>                   skipnl();                   /* Skip to newline      */
> #else
>               else if (flevel > 0) {          /* #ifdef false?        */
>                   skipnl();                   /* Skip to newline      */
>                   ++counter;
>               }
> #endif
>               else {
>                   break;                      /* Actual token         */
>               }
>           }

    We also STILL toss in the extra newline in "sharp" when appropriate:

> FILE_LOCAL
> sharp()
> /*
>  * Output a line number line.
>  */
> {
>       register char           *name;
> 
> #ifndef OLDVERSION
>       if (keepcomments)
>               putchar('\n');
> #endif

    We still fix the typo in "control":
> #ifdef OLDVERSION
>       if (control > 0 && (hash == L_line || hash == L_option)) {
> #else
>       if (counter > 0 && (hash == L_line || hash == L_option)) {
> #endif

    And finally, we get to make this change in "control", to ensure that
    the first line of an included file does not disappear:

> #if 1
> #ifdef OLDVERSION
>       skipnl();                       /* Dump rest of control line    */
>       counter++;                      /* Count it, too.               */
> #else
>       if (hash != L_include) {        /* If haven't already eaten line */
>               skipnl();               /* Dump rest of control line    */
>               counter++;              /* Count it, too.               */
>       }
> #endif
> #else

                                --ado


From tektronix!tomk@orca Sun Sep 23 21:54:48 1984
Received: by decvax.UUCP (4.12/1.0)
        id AA04987; Sun, 23 Sep 84 21:54:43 edt
From: tektronix!tomk@orca
To: tektronix!decvax!minow
Fcc: outbox
Return-Path: <tomk@orca>
Received: from orca.TEK by tektronix ; 23 Sep 84 13:33:23 PDT
Received: by orca.TEK (1.138/Tek) ,     id AA03938; Sun, 23 Sep 84 13:33:49 pdt
Message-Id: <8409232033.AA03938@orca.TEK>
Date: Sun, 23 Sep 84 13:33:41 PDT
Subject: DECUS C bugs, etc.
Status: R

Hi!  I just grabbed your cpp submission off the net.  Looks like
an interesting addition to DECUS C.  I totally forgot that you
offered to send me a test copy earlier.

I discovered a bug in "t" running under RT11 a few months ago.
If there's a null character stuck in a line, "t" refuses to print
everything after the null.  DIR.SAV seems to stick a null at the
first of a line when there's only one file in the directory.
DIR probably shouldn't stick the null there, but I developed a
quick and sleazy fix to "t" to eliminate the bug.  Here's the
change to "t.h" (Nov'83 version):
        [input to SLP]
        -3
         * Kloos version of 09-Jun-84
        -35
        #ifndef rt11
        -36
        #else
        #define FWILDMODE       "ru"
        -37
        #endif
        /

Do you know of any problems with "sortc" as distributed in the
Nov'83 release?  When I have less than about 43K of user memory
and a big file to sort, it munches the output.  Extra characters
appear in some places and a few are missing from others.  I haven't
had the time to dissect the code yet and am hoping that someone
else may have fixed it already.  Any hints?

Are there any updates to the RT-11 version of DECUS C since the last
care package I received from you (late May)?

Regards,
-Tom Kloos, Tektronix, Wilsonville, Oregon
                                Ignore paths in header.  Use this:
uucp:   ..{ucbvax,decvax,uw-beaver,hplabs,allegra}!tektronix!orca!tomk


From seismo!umcp-cs!elsie!ado Mon Sep 24 12:26:31 1984
Received: by decvax.UUCP (4.12/1.0)
        id AA17918; Mon, 24 Sep 84 12:26:24 edt
From: seismo!umcp-cs!elsie!ado
Received: from umcp-cs.UUCP by seismo.ARPA with UUCP; Mon, 24 Sep 84 12:04:14 EDT
Received: by maryland.ARPA (4.12/4.7)
        id AA26652; Mon, 24 Sep 84 11:37:58 edt
Date: Mon, 24 Sep 84 11:37:58 edt
Message-Id: <8409241537.AA26652@maryland.ARPA>
To: minow@decvax
Subject: Re: re: cpp1.c
Status: R

Got your letter--thanks.

Here's a notion--submitted for your approval.
It's the code to squelch output of comments that are either
        1.  on preprocessor directive lines or
        2.  in conditionally-compiled code that's not being emitted.

Fairly straightforward changes, actually:

        a.  Add this at the top of cpp1.c:

> int           keepcomments = FALSE;   /* Write out comments flag      */
> #ifndef OLDVERSION
> static int    cflag = FALSE;          /* as per command line */
> #endif

        b.  Add this to "dooptions":

>               case 'C':                       /* Keep comments        */
> #ifndef OLDVERSION
>                   cflag = TRUE;
> #endif
>                   keepcomments = TRUE;
>                   break;
> 

        c.  And finally, change the call to "docontrol":

>               else if (c == '#')              /* Is 1st non-space '#' */
> #ifdef OLDVERSION
>                   counter = control(counter); /* Yes, do a #command   */
> #else
>                       {
>                       keepcomments = FALSE;
>                       counter = control(counter);
>                       keepcomments = cflag && (flevel == 0);
>                       }
> #endif

Should cut down the computer usage bills of lint users.
                                --ado


From seismo!umcp-cs!elsie!ado Mon Sep 24 12:26:51 1984
Received: by decvax.UUCP (4.12/1.0)
        id AA17925; Mon, 24 Sep 84 12:26:44 edt
From: seismo!umcp-cs!elsie!ado
Received: from umcp-cs.UUCP by seismo.ARPA with UUCP; Mon, 24 Sep 84 12:04:23 EDT
Received: by maryland.ARPA (4.12/4.7)
        id AA26659; Mon, 24 Sep 84 11:38:08 edt
Date: Mon, 24 Sep 84 11:38:08 edt
Message-Id: <8409241538.AA26659@maryland.ARPA>
To: minow@decvax
Subject: Perfect hashing and a warped human mind
Status: R

Here's a possible replacement for "perfect hashing" in cpp1.c.
It makes for both a smaller cpp1.c source file and (at least on our system)
a smaller executable cpp.  It may also be easier for folks to understand.
                                --ado
#ifdef OLDVERSION
/*
 * The following is generated by a "perfect hash" routine.
 */
#define L_else                  4
#define L_line                  5
#define L_define                6
#define L_elif                  7
#define L_endif                 8
#define L_if                    9
#define L_undef                 10
#define L_include               11
#define L_ifdef                 12
#define L_ifndef                13
#define L_assert                14
#define L_option                15
#define FIRST   'a'
#define LAST    'u'
static int px_assoc[] = {
        0,      /* 'a' */
        -1,     /* 'b' */
        -1,     /* 'c' */
        0,      /* 'd' */
        0,      /* 'e' */
        3,      /* 'f' */
        -1,     /* 'g' */
        -1,     /* 'h' */
        4,      /* 'i' */
        -1,     /* 'j' */
        -1,     /* 'k' */
        1,      /* 'l' */
        -1,     /* 'm' */
        9,      /* 'n' */
        0,      /* 'o' */
        -1,     /* 'p' */
        -1,     /* 'q' */
        -1,     /* 'r' */
        -1,     /* 's' */
        8,      /* 't' */
        2,      /* 'u' */
};
static char *px_table[] = {
        NULL,                   /*  0   */
        NULL,                   /*  1   */
        NULL,                   /*  2   */
        NULL,                   /*  3   */
        "else",                 /*  4   */
        "line",                 /*  5   */
        "define",               /*  6   */
        "elif",                 /*  7   */
        "endif",                /*  8   */
        "if",                   /*  9   */
        "undef",                /* 10   */
        "include",              /* 11   */
        "ifdef",                /* 12   */
        "ifndef",               /* 13   */
        "assert",               /* 14   */
        "option",               /* 15   */
};

FILE_LOCAL int
control(counter)
int             counter;        /* Pending newline counter              */
/*
 * Process #control lines.  Simple commands are processed inline,
 * while complex commands have their own subroutines.
 *
 * The counter is used to force out a newline before #line, and
 * #option commands.  This prevents these commands from ending up at
 * the end of the previous line if cpp is invoked with the -C option.
 */
{
        register int            c;
        register char           *tp;
        register int            hash;
        char                    *ep;

        c = skipws();
        if (c == '\n' || c == EOF_CHAR)
            return (counter + 1);
        if (!isdigit(c))
            scanid(c);                  /* Get #word to token[]         */
        else {
            unget();                    /* Hack -- allow #123 as a      */
            strcpy(token, "line");      /* synonym for #line 123        */
        }
        /*
         * Look for keyword (string of alpha) in the perfect hash table.
         * Set hash to the index (L_xxx value) or 0 if not found
         */
        if (token[0] < FIRST || token[0] > LAST)
            hash = 0;
        else {
            for (tp = token; isalpha(*tp); tp++)
                ;
            hash = (tp - token);
            if (*--tp < FIRST || *tp > LAST)
                hash = 0;
            else {
                hash += px_assoc[*token - FIRST] + px_assoc[*tp - FIRST];
                if (px_table[hash] == NULL
                 || !streq(token, px_table[hash]))
                    hash = 0;
            }
        }
        /*
         * hash is now set to a unique value corresponding to the
         * control keyword (or zero if it's not in the table).
         */
#else
/*
 * The following is generated by human perverseness.
 */

#define L_else          ('e' + ('s' << 1))
#define L_line          ('l' + ('n' << 1))
#define L_define        ('d' + ('f' << 1))
#define L_elif          ('e' + ('i' << 1))
#define L_endif         ('e' + ('d' << 1))
#define L_if            ('i' + (EOS << 1))
#define L_undef         ('u' + ('d' << 1))
#define L_include       ('i' + ('c' << 1))
#define L_ifdef         ('i' + ('d' << 1))
#define L_ifndef        ('i' + ('n' << 1))
#define L_assert        ('a' + ('s' << 1))
#define L_option        ('o' + ('t' << 1))

FILE_LOCAL int
control(counter)
int             counter;        /* Pending newline counter              */
/*
 * Process #control lines.  Simple commands are processed inline,
 * while complex commands have their own subroutines.
 *
 * The counter is used to force out a newline before #line, and
 * #option commands.  This prevents these commands from ending up at
 * the end of the previous line if cpp is invoked with the -C option.
 */
{
        register int            c;
        register char           *tp;
        register int            hash;
        char                    *ep;

        c = skipws();
        if (c == '\n' || c == EOF_CHAR)
            return (counter + 1);
        if (!isdigit(c))
            scanid(c);                  /* Get #word to token[]         */
        else {
            unget();                    /* Hack -- allow #123 as a      */
            strcpy(token, "line");      /* synonym for #line 123        */
        }
        switch (hash = token[0] + (token[2] << 1)) {
                case L_else:    tp = "else";            break;
                case L_line:    tp = "line";            break;
                case L_define:  tp = "define";          break;
                case L_elif:    tp = "elif";            break;
                case L_endif:   tp = "endif";           break;
                case L_if:      tp = "if";              break;
                case L_undef:   tp = "undef";           break;
                case L_include: tp = "include";         break;
                case L_ifdef:   tp = "ifdef";           break;
                case L_ifndef:  tp = "ifndef";          break;
                case L_assert:  tp = "assert";          break;
                case L_option:  tp = "option";          break;
                default:        tp = ""; hash = 0;      break;
        }
        if (!streq(tp, token))
                hash = 0;
        /*
         * hash is now set to a unique value corresponding to the
         * control keyword (or zero if we think it's nonsense).
         */
#endif
                                --ado


From seismo!umcp-cs!elsie!ado Tue Sep 25 14:27:42 1984
Received: by decvax.UUCP (4.12/1.0)
        id AA13453; Tue, 25 Sep 84 14:27:38 edt
From: seismo!umcp-cs!elsie!ado
Received: from umcp-cs.UUCP by seismo.ARPA with UUCP; Tue, 25 Sep 84 13:03:08 EDT
Received: by maryland.ARPA (4.12/4.7)
        id AA13754; Tue, 25 Sep 84 12:27:47 edt
Date: Tue, 25 Sep 84 12:27:47 edt
Message-Id: <8409251627.AA13754@maryland.ARPA>
To: minow@decvax
Subject: cpp.h addition
Status: R

Appending a
        extern char     *sprintf();
lint to "cpp.h" saves a bit of "lint" grief.
                                --ado


From seismo!cmcl2!hipl!tony Fri Sep 28 03:19:55 1984
Received: by decvax.UUCP (4.12/1.0)
        id AA15286; Fri, 28 Sep 84 03:19:30 edt
Received: from cmcl2.UUCP by seismo.ARPA with UUCP; Thu, 27 Sep 84 20:51:40 EDT
Received: by NYU-CMCL2.ARPA; Thu, 27 Sep 84 19:06:13 edt
Received: by hipl.UUCP (4.12/4.7)
        id AA01328; Thu, 27 Sep 84 18:28:22 edt
Date: Thu, 27 Sep 84 18:28:22 edt
From: seismo!cmcl2!hipl!tony (Tony Movshon)
Message-Id: <8409272228.AA01328@hipl.UUCP>
To: minow@decvax
Subject: cpp
Status: R

I retrieved cpp from net.sources and have installed it under RT11. I have not
tested it exhaustively, but it appears to work fine. One minor point: in
cppdef.h, you have it define HOST as SYS_RSX even if the compiler predefines
"rt11" (this was presumably for testing). It would be more humane to have it
define HOST as SYS_RT11.
You mentioned some bug-fixes affecting RT11 that you installed since the last
DECUS release: could you send them to me for my planned RT11 resubmission?

% 
