C compiler from 211bsd.git commit 98921db
authorNick Downing <downing.nick@gmail.com>
Tue, 7 Feb 2017 11:41:49 +0000 (22:41 +1100)
committerNick Downing <downing.nick@gmail.com>
Tue, 7 Feb 2017 11:41:49 +0000 (22:41 +1100)
35 files changed:
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
TEST/Makefile [new file with mode: 0644]
TEST/README [new file with mode: 0644]
TEST/ctest [new file with mode: 0644]
TEST/old-assn.l [new file with mode: 0644]
TEST/tpr.c [new file with mode: 0644]
TEST/tprint.c [new file with mode: 0644]
TEST/tst_adec.c [new file with mode: 0644]
TEST/tst_asm.c [new file with mode: 0644]
TEST/tst_assign.c [new file with mode: 0644]
TEST/tst_lgm-g.c [new file with mode: 0644]
TEST/tst_lgm.c [new file with mode: 0644]
TEST/tst_longsym.c [new file with mode: 0644]
TEST/tst_pntint.c [new file with mode: 0644]
TEST/tst_rhh-g.c [new file with mode: 0644]
TEST/tst_rhh.c [new file with mode: 0644]
TEST/tst_sgncmp.c [new file with mode: 0644]
c0.h [new file with mode: 0644]
c00.c [new file with mode: 0644]
c01.c [new file with mode: 0644]
c02.c [new file with mode: 0644]
c03.c [new file with mode: 0644]
c04.c [new file with mode: 0644]
c05.c [new file with mode: 0644]
c1.h [new file with mode: 0644]
c10.c [new file with mode: 0644]
c11.c [new file with mode: 0644]
c12.c [new file with mode: 0644]
c13.c [new file with mode: 0644]
cvopt.c [new file with mode: 0644]
fp.c [new file with mode: 0644]
fp_atof.c [new file with mode: 0644]
n.sh [new file with mode: 0755]
optable [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..4fc5c53
--- /dev/null
@@ -0,0 +1,5 @@
+*.bak
+*.o
+c0
+c1
+cvopt
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..a96c743
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,45 @@
+HOSTCC=cc
+INSTALL=install
+CFLAGS = -O
+LDC0FLAGS= -i
+LDC1FLAGS= -n
+DESTDIR =
+LIB=/lib
+
+all: c0 c1 cvopt
+c0: c00.o c01.o c02.o c03.o c04.o c05.o
+       ${CC} ${LDC0FLAGS} ${CFLAGS} -o c0 c00.o c01.o c02.o c03.o c04.o c05.o
+
+c00.o c01.o c02.o c03.o c04.o c05.o: c0.h
+
+c1: c10.o c11.o c12.o c13.o fp.o fp_atof.o table.o
+       ${CC} ${LDC1FLAGS} ${CFLAGS} -o c1 c10.o c11.o c12.o c13.o fp.o fp_atof.o table.o
+
+c10.o c11.o c12.o c13.o: c1.h
+
+table.o: optable cvopt
+       ./cvopt < optable > junk.c
+       ${CC} -S junk.c
+       sed 's/\.data/\.text/' < junk.s > junk.i
+       ${AS} -o table.o junk.i
+       rm -f junk.i junk.c junk.s
+
+cvopt: cvopt.c
+       ${HOSTCC} -o cvopt cvopt.c
+
+install: c0 c1
+       -mv ${DESTDIR}${LIB}/c0 ${DESTDIR}${LIB}/oc0
+       -mv ${DESTDIR}${LIB}/c1 ${DESTDIR}${LIB}/oc1
+       ${INSTALL} -s c0 ${DESTDIR}${LIB}/c0
+       ${INSTALL} -s c1 ${DESTDIR}${LIB}/c1
+
+restore:
+       mv ${DESTDIR}${LIB}/oc0 ${DESTDIR}${LIB}/c0
+       mv ${DESTDIR}${LIB}/oc1 ${DESTDIR}${LIB}/c1
+
+lint:
+       lint -haxc -I. c0?.c > lint.c0
+       lint -haxc -I. c1?.c > lint.c1
+
+clean:
+       rm -f *.o c0 c1 cvopt lint.c?
diff --git a/TEST/Makefile b/TEST/Makefile
new file mode 100644 (file)
index 0000000..97bbc97
--- /dev/null
@@ -0,0 +1,54 @@
+LEX=lex
+CFLAGS=        -O
+SEPFLAG= -i
+LIB=   /lib
+ALL=   tst_adec tst_rhh-g tst_pntint tst_asm tst_lgm-g \
+       tst_sgncmp tst_assign old-assn
+
+all: ${ALL}
+
+tst_adec: tst_adec.o
+       ${CC} -o $@ tst_adec.o
+
+# This will fail... see README
+#tst_rhh: tst_rhh.o
+#      ${CC} -o $@ tst_rhh.o
+
+tst_rhh-g: tst_rhh-g.o
+       ${CC} -o $@ tst_rhh-g.o
+
+tst_pntint: tst_pntint.o
+       ${CC} -o $@ tst_pntint.o
+
+tst_asm: tst_asm.o
+       ${CC} -o $@ tst_asm.o
+
+# This requires changes to the compiler to run, see README
+#tst_longsym: tst_longsym.o
+#      ${CC} -o $@ tst_longsym.o
+
+tst_longsym: tst_longsym.o
+       ${CC} -o $@ tst_longsym.o
+
+tst_lgm: tst_lgm.o
+       ${CC} -o $@ tst_lgm.o
+
+# This will fail... see README
+#tst_lgmgood: tst_lgmgood.o
+#      ${CC} -o $@ tst_lgmgood.o
+
+tst_assign: tst_assign.o
+       ${CC} -o $@ tst_assign.o
+
+tst_sgncmp: tst_sgncmp.o
+       ${CC} -o $@ tst_sgncmp.o
+
+old-assn: old-assn.l
+       ${LEX} old-assn.l
+       ${CC} ${SEPFLAG} ${CFLAGS} -o old-assn lex.yy.c -lln
+       rm lex.yy.c
+
+clean:
+       rm -f lex.yy.c *.o core ${ALL}
+
+install:
diff --git a/TEST/README b/TEST/README
new file mode 100644 (file)
index 0000000..5113854
--- /dev/null
@@ -0,0 +1,197 @@
+       This compiler is obviously based on a Ritchie compiler, roughly dated
+1982, that was slipped under the door by an unnamed benefactor.  It came here
+with void, u_char, many cosmetic changes (use of += vs =+), table.s replaced
+by "optable", and cvopt.c writing a ".c" file, rather than an ".s" file.
+There are also many changes to the way code is generated.
+       Various files begining with "tst" test various bugs/enhancements that
+have been seen in some versions of the Ritchie compiler.  You can see some
+of the bugs that have been fixed by running these test programs.  These test
+programs are far from being complete test suites.  Just because you can get
+one in particular to run doesn't necessarily mean that every case of that
+feature will work.  Other shakedown measures should be taken, for example,
+recompiling & testing every program you can get your hands on.
+
+       Stephen Uitti, Casey Leedom & Keith Bostic
+
+tst_adec.c
+       This bug is where a long is used as an index for an array, that gets
+       decremented.  The bug is that only half of the long gets decremented,
+       corrupting its value.  0 goes to 65535 rather than -1.  The stock
+       2.9 BSD compiler had this bug.  The bug was reported on USENET, with
+       no fix.  This compiler fixes this bug, but 'causes' another - see
+       tstlgm.c, tstlgmgood.c.
+
+tst_pntint.c
+       The new compiler didn't allow assignment of pointers to integers
+       and vice-versa under any circumstances.  This was changed to allow
+       the assignment, but warn the user, a la 4.3.
+
+tst_assign.c
+       The new compiler doesn't handle the old assignment operators at all.
+       It will object to *some* of the old operators, but since "foo =- 8"
+       can be translated "foo = (-8)", a lot of them slip by.  Use the
+       program old-assn and a find to remove all instances of the old
+       operators from your source code.  For example...
+
+       find /usr/src -type f -name '*.[cl]' \
+               -exec /usr/src/lib/ccom/TEST/old-assn {} \; >& old_list&
+
+tst_rhh.c and tst_rhh-g.c
+       This compiler fixes the "tstadec.c" bug, but in doing so creates this
+       other bug.  The symptom is that the compiler runs out of registers
+       while trying to compile this code.  The stock 2.9 BSD compiler
+       compiles this code correctly, but uses a "div" rather than an "ashc"
+       instruction at one point.  "movreg" in c10.c gets called to move
+       values to an appropriate even/odd place, but there aren't enough
+       registers left to do this.  It's unclear why r0 isn't used early on in
+       the developed code, since the stock 2.9 BSD compiler does, and thus
+       doesn't get into trouble.  "tst_rhh-g.c" declares one less register,
+       and thus allows a compiler with the bug to compile the code.
+
+tst_asm.c
+       This tests (and shows how to use) the "asm" feature.  These mods
+       were taken from in a version of the Ritchie compiler found on a
+       VAX at Purdue CS that had been converted into a cross C compiler.
+       These mods were done in c0.h, c1.h, c00.c, c02.c, c11.c, c0.h and
+       c1.h.
+
+tst_longsym.c
+       Mods (mostly to error messages) to allow the parameter NCPS (in both
+       c0.h and c1.h) to be changed to (for example) larger values.  Normally,
+       a standard compiler will give you a message something like:
+
+               tstlongsym.c:3: foobarby redeclared
+
+       So, change NCPS to 16, try again, and it should actually run.  It turns
+       out that "auto" symbol names never get used by the assembler, so it's
+       still happy.  For globals, though, you need an assembler, linker, new
+       a.out format (for the symbol table), ar etc. that can deal with longer
+       names.  These changes took place in c00.c, c01.c c02.c, c03.c, and
+       c11.c.
+
+tst_lgm.c and tst_lgm-g.c
+       These show a bug in union initialization.  Both the stock 2.9 compiler
+       and this compiler allowed the initializations, but compiled incorrect
+       code.  The bugfix allows them and does them correctly but warns that
+       they are non-portable.  This bugfix still won't compile tstlgm.c,
+       since it is not syntactically correct.  tstlgmgood.c is, and this fix
+       allows this code to be compiled.  Note, this compiler will not allow
+       initialization of a union unless the type of the value is the type
+       of the first entry in the union; the stock 2.9 compiler didn't have
+       that limitation.  This fix was applied to c02.c, and is attributed
+       to Doug Gwyn.
+
+tst_sgncmp.c
+       Both the stock 2.9 compiler & this compiler compare large (almost
+       negative) signed int's incorrectly.  The bugfix allows this program
+       to say "true" always.  These changes were made in c10.c, c11.c, c13.c,
+       c2.h, and c20.c.  The bugfix is attributed to George Rosenberg,
+       whose "README" was as follows:
+
+               There seems to be an anomaly in the code generation of
+       some pdp-11 C compilers.  In certain contexts the wrong type of
+       conditional branch instruction is generated.  Instructions such
+       as "jge" may occur rather than instructions such as "jpl".  I
+       have observed the problem with a Whitesmith compiler and both
+       of the compilers distributed with UNIX version 7, Dennis M.
+       Ritchie's compiler and Stephen C. Johnson's compiler.  The
+       expression,
+               "(j-i < 0) == (j-i < zero)",
+
+       evaluates to zero (i.e. false) in the accompanying program,
+       "bug.c", as compiled with the UNIX compilers.  The expression
+       evaluates as one (i.e. true), in the Whitesmith compiler, only
+       because it also incorrectly evaluates a previous expression in
+       the program.  I suggest trying this program with your compiler
+       even if it isn't one of the above.
+
+       In making the changes, the original sources were examined only
+       superficially (e.g. grep jlt), to find the offending code.
+       This code was then patched up.  Programs compiled with the
+       modified compiler seem to work.  By "seem to work", I mean that
+       as far as I know the coding anomalies described here are fixed
+       and no new bugs are introduced.  Due to my ignorance of the
+       global workings of the compiler, there may be a possibility of
+       some unknown global effect coming back to haunt you.  Here is a
+       summary of coding changes applicable in certain contexts.
+
+                       Old Coding              New Coding
+       1.              jlt L001                jmi L001
+       2.              jge L002                jpl L002
+       3.              jle L003                jmi L003
+                                               jeq L003
+       4.              jgt L004                jmi L005
+                                               jne L004
+                                       L005:
+
+c11.c (stock 2.9 BSD compiler only)
+       An improvement to the optimizer, c21.c, does a little better at using
+       values which have been put into registers.  To test the diff the
+       assembly output "cc -O -S c11.c".  Of course c11.c is also useful as
+       part of the compiler.
+
+Other bugs (but no test files):
+
+====   An assignment bug fix - the code is in c01.c.  The bugfix code claims
+       that t = (t, t) + 1; code was broken, now fixed.  It didn't seem
+       broken to me, but I installed the fix anyway.
+
+====   A new type clash error is trapped for in c03.c.  This fix attributed
+       to "IIASA (from MIT)" (whoever/whatever that is).
+
+====   A bug fix for "when there are unitialized static variables in the
+       middle of a routine".  This fix is also attributed to "IIASA (from
+       MIT)", and is applied to c20.c.
+
+====   A bug fix for a typo in c10.c, attributed to ken@ukma.  Search
+       for "typo".
+
+====   The pdp-11 compiler clears a little too much information when
+       it leaves certain scopes.  The place you find this is in the
+       code:
+               f1() { extern int foo; }
+
+               f2() { foo = 1; }
+
+       According to sections 10 & 11.1 of K&R, this is legal, and, in fact,
+       the 4.3 compiler allows this.  2.10's doesn't.  Because of the way
+       that 2.10's compiler handles its stack, this one will be *very* tough.
+
+====   Forward references are a bit paranoid in the 2.10 compiler, for
+       instance, the following code produces an error message that
+
+               struct A {
+                       struct B        *bp;
+               } a = 0;
+
+               struct B {
+                       struct A        *ap;
+               };
+
+       the line "a = 0" causes a reference to an "Undefined structure."
+       This isn't really a bug, and it can be easily worked around, but
+       it's certainly unreasonable.
+
+====   Also, something which isn't a bug in our compiler, but is in the
+       4.3BSD compiler may cause you some problems when porting programs
+       from 4.3.  The 4.3 compiler compares unsigned and signed ints
+       incorrectly (K&R, p. 184, 6.5 and p. 189, 7.6).  Instead of
+       performing an unsigned comparison, it performs a signed comparison.
+       To get a feel for the degree of subtlety that this can lead to in
+       the way of bugs consider the following line from the original source
+       to the 4.3 ndbm standard library source:
+
+       if (i1 <= (i2+3) * sizeof(short))
+
+       I1 and i2 are integers, but because sizeof has type unsigned the
+       entire right hand side of the comparison is converted to unsigned.
+       At this point our compiler and the 4.3 compiler diverge in their
+       treatment of the comparison: ours converts the left hand side of the
+       comparison to unsigned and performs an unsigned comparison.  The
+       4.3 compiler converts the right hand side to signed and performs a
+       signed comparison.  In the particular case above, since i1 had been
+       (essentially) computed as i2 - <exp> with the possibility of a
+       negative result, this caused a problem ...  The corrected code for
+       the above is:
+
+       if (i1 <= (int)((i2+3) * sizeof(short)))
diff --git a/TEST/ctest b/TEST/ctest
new file mode 100644 (file)
index 0000000..bec19e3
--- /dev/null
@@ -0,0 +1,21 @@
+x=`basename $1 .c`
+if test "$2" != s -a "$3" != s
+then
+       echo compiling with old
+       cc -S $x.c
+       echo finished compiling old
+       mv $x.s $x.so
+fi
+if test $2x = 0x
+then
+       cc -t0 -S $x.c
+fi
+if test $2 = 1
+then
+       cc -t1 -S $x.c
+fi
+if test $2 != 0 -a $2 != 1
+then
+       cc -t01 -S $x.c
+fi
+diff $x.so $x.s
diff --git a/TEST/old-assn.l b/TEST/old-assn.l
new file mode 100644 (file)
index 0000000..5b81de0
--- /dev/null
@@ -0,0 +1,172 @@
+%{
+/*
+ * old-assn.l - find old C assignment operators
+ *
+ * Quick little lex program to find occurances of old form assignment
+ * operators in C source programs: =-, =+, etc.
+ *
+ * usage: old-assn [file] ...
+ *
+ * NOTES:
+ *     Won't work on files with lines longer than MAXLINE
+ *     File names should be less than MAXPATHLEN in length ...
+ *     The standard lex environment already includes <stdio.h>
+ *     "yyin" is where lex reads its input from
+ *     lex keeps the current input line number in "yylineno"
+ */
+
+#include <sys/param.h>
+#define        MAXLINE         1024
+
+static char    *ourname,               /* guess */
+               **filelist;             /* list of files we're checking */
+static int     errors = 0,             /* number of errors of course! */
+               printnames = 0;         /* if more than one file to scan */
+
+main(argc, argv)
+       int     argc;
+       char    **argv;
+{
+       char    *C,
+               *rindex();
+
+       ourname = (C = rindex(*argv,'/')) ? ++C : *argv;
+       if (argc == 1)
+       {
+               static char     *siv[] = { "stdin", (char *)0 };
+               filelist = siv;
+       }
+       else
+       {
+               filelist = argv+1;
+               printnames = 1;
+               if (yyopen() == 1)
+                       exit(errors);
+       }
+       yylex();
+       exit(errors);
+}
+
+/*
+ * Open next file when end of file reached on current input.
+ */
+yywrap()
+{
+       filelist++;
+       return(yyopen());
+}
+
+/*
+ * Open next file from filelist and set it up as lex's input.  Return 1
+ * when no more files can be opened, 0 on success.
+ */
+yyopen()
+{
+       fclose(yyin);
+       yylineno = 1;
+       for (;;)
+       {
+               if (!*filelist)
+                       return(1);
+               if (yyin = fopen(*filelist, "r"))
+                       return(0);
+               else
+               {
+                       perror(*filelist);
+                       errors++;
+                       filelist++;
+               }
+       }
+}
+
+/*
+ * Catch cpp "# lineno file" controls and use them to set our current idea of
+ * what file we're reading and what line number we're on.
+ */
+yypunt(yytext)
+       char    *yytext;
+{
+       static char     curfile[MAXPATHLEN];
+       register char   *cp     = curfile,
+                       *yp     = yytext;
+
+       while (*yp < '0' || '9' < *yp)
+               yp++;
+       yylineno = *yp++ - '0';
+       while ('0' <= *yp && *yp <= '9')
+               yylineno = 10*yylineno + *yp++ - '0';
+
+       while (*yp++ != '\"')
+               continue;
+       while (*yp != '\"')
+               *cp++ = *yp++;
+       *cp = '\0';
+       *filelist = curfile;
+}
+%}
+
+%%
+
+%{
+       /*
+        * The following definitions will appear within the function yylex.
+        * Note that yylex must *not* return except at an end of line or at
+        * end of file or the line buffer variable will be trashed (and *no*,
+        * you can't have a "static register ..."  The use of register
+        * variables for "linep", "bufend" and "cp" below in the macro
+        * catenate speeds this program up by about 10%).
+        */
+
+#define        CATENATE(s) \
+       { \
+               for (cp = s;linep < bufend && *cp;*linep++ = *cp++); \
+               *linep = '\0'; \
+       }
+
+       static char     linebuf[MAXLINE+1];     /* current input line */
+       register char   *linep  = linebuf,      /* linebuf input pointer */
+                       *bufend = linebuf+MAXLINE+1,
+                       *cp;
+       static short    oldassn = 0,            /* old assignment in line */
+                       string  = 0;            /* if in a string */
+
+%}
+
+^\#(line)?\ [0-9]+\ \".*\"\n   yypunt(yytext);
+
+[^<>!=]=[-+*&] |
+=[/%^|]                |
+=>>            |
+=<<            {
+                       if (!string)
+                               oldassn = 1;
+                       CATENATE(yytext);
+               }
+
+\\\"           CATENATE(yytext);
+
+\"             {
+                       string = !string;
+                       CATENATE(yytext);
+               }
+
+\n             {
+                       /*
+                        * If an old assignment occured on this line,
+                        * then print the file name, line number and
+                        * and line ala grep.
+                        */
+                       if (oldassn) {
+                               if (printnames)
+                                       printf("%s: %d: %s\n",
+                                               *filelist, yylineno-1, linebuf);
+                               else
+                                       printf("%d: %s\N",
+                                               yylineno-1, linebuf);
+                               oldassn = 0;
+                       }
+                       string = 0;
+                       *(linep = linebuf) = '\0';
+               }
+
+.              CATENATE(yytext);
diff --git a/TEST/tpr.c b/TEST/tpr.c
new file mode 100644 (file)
index 0000000..90bdb83
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Interpret a C intermediate file.
+ */
+#include <stdio.h>
+#include "c1.h"
+
+extern opdope[1];
+extern char    *opntab[1];
+
+struct table cctab[1], efftab[1], regtab[1], sptab[1];
+char   maprel[1], notrel[1];
+char   *outname();
+
+main()
+{
+       register t, op;
+       static char s[9];
+       register char *tp;
+       double atof();
+       char numbuf[64];
+       int lbl, cond;
+       int sdep;
+
+       sdep = 0;
+       for (;;) {
+               op = getw(stdin);
+               if ((op&0177400) != 0177000) {
+                       error("Intermediate file error");
+                       exit(1);
+               }
+               lbl = 0;
+               switch(op &= 0377) {
+
+       case SINIT:
+               printf("init %d\n", getw(stdin));
+               break;
+
+       case EOFC:
+               printf("eof\n");
+               exit(0);
+
+       case BDATA:
+               if (getw(stdin) == 1) {
+                       printf(".byte ");
+                       for (;;)  {
+                               printf("%d", getw(stdin));
+                               if (getw(stdin) != 1)
+                                       break;
+                               printf(",");
+                       }
+                       printf("\n");
+               }
+               break;
+
+       case PROG:
+               printf("prog\n");
+               break;
+
+       case DATA:
+               printf("data\n");
+               break;
+
+       case BSS:
+               printf("bss\n");
+               break;
+
+       case SYMDEF:
+               printf("symdef ");
+               outname(s);
+               printf("%s\n", s);
+               break;
+
+       case RETRN:
+               printf("return\n");
+               break;
+
+       case CSPACE:
+               tp = outname(s);
+               printf("comm %s,%d\n", tp, getw(stdin));
+               break;
+
+       case SSPACE:
+               printf("space %d\n", getw(stdin));
+               break;
+
+       case EVEN:
+               printf("even\n");
+               break;
+
+       case SAVE:
+               printf("save\n");
+               break;
+
+       case SETSTK:
+               t = getw(stdin)-6;
+               printf("setstack %d\n", t);
+               break;
+
+       case PROFIL:
+               t = getw(stdin);
+               printf("profil %d\n", t);
+               break;
+
+       case SNAME:
+               tp = outname(s);
+               printf("sname %s s%d\n", tp, getw(stdin));
+               break;
+
+       case ANAME:
+               tp = outname(s);
+               printf("aname %s a%d\n", tp, getw(stdin));
+               break;
+
+       case RNAME:
+               tp = outname(s);
+               printf("rname %s r%d\n", tp, getw(stdin));
+               break;
+
+       case SWIT:
+               t = getw(stdin);
+               line = getw(stdin);
+               printf("switch line %d def %d\n", line, t);
+               while (t = getw(stdin)) {
+                       printf("   %d %d\n", t, getw(stdin));
+               }
+               break;
+
+       case CBRANCH:
+               lbl = getw(stdin);
+               cond = getw(stdin);
+       case EXPR:
+               line = getw(stdin);
+               if (sdep != 1) {
+                       error("Expression input botch");
+                       exit(1);
+               }
+               sdep = 0;
+               if (lbl)
+                       printf("cbranch %d line %d\n", lbl, line);
+               else
+                       printf("expr line %d\n", line);
+               break;
+
+       case NAME:
+               t = getw(stdin);
+               if (t==EXTERN) {
+                       t = getw(stdin);
+                       printf("name %o, %s\n", t, outname(s));
+               } else if (t==AUTO) {
+                       t = getw(stdin);
+                       printf("name %o a%d\n", t, getw(stdin));
+               } else if (t==STATIC) {
+                       t = getw(stdin);
+                       printf("name %o s%d\n", t, getw(stdin));
+               } else if (t==REG) {
+                       t = getw(stdin);
+                       printf("name %o r%d\n", t, getw(stdin));
+               } else
+                       printf("name botch\n");
+               sdep++;
+               break;
+
+       case CON:
+               t = getw(stdin);
+               printf("const %d %d\n", t, getw(stdin));
+               sdep++;
+               break;
+
+       case LCON:
+               getw(stdin);    /* ignore type, assume long */
+               t = getw(stdin);
+               op = getw(stdin);
+               printf("lconst %D\n", (((long)t<<16) | (unsigned)op));
+               sdep++;
+               break;
+
+       case FCON:
+               t = getw(stdin);
+               printf("fcon %s\n", outname(numbuf));
+               sdep++;
+               break;
+
+       case FSEL:
+               printf("fsel %o ", getw(stdin));
+               printf("%d ", getw(stdin));
+               printf("%d\n", getw(stdin));
+               break;
+
+       case STRASG:
+               t = getw(stdin);
+               printf("strasg %o ", getw(stdin));
+               printf("%d\n", getw(stdin));
+               break;
+
+       case NULLOP:
+               printf("null\n");
+               sdep++;
+               break;
+
+       case LABEL:
+               printf("label %d\n", getw(stdin));
+               break;
+
+       case NLABEL:
+               tp = outname(s);
+               printf("nlabel %s\n", tp);
+               break;
+
+       case RLABEL:
+               tp = outname(s);
+               printf("rlabel %s\n", tp);
+               break;
+
+       case BRANCH:
+               printf("branch %d\n", getw(stdin));
+               break;
+
+       case SETREG:
+               printf("nreg %d\n", getw(stdin));
+               break;
+
+       default:
+               t = getw(stdin);
+               if (op <=0 || op >=120) {
+                       printf("Unknown op %d\n", op);
+                       exit(1);
+               }
+               if (opdope[op]&BINARY)
+                       sdep--;
+               if (sdep<=0)
+                       printf("Binary expression botch\n");
+               if (opntab[op] == 0)
+                       printf("op %d %o\n", op, t);
+               else
+                       printf("%s %o\n", opntab[op], t);
+               break;
+       }
+       }
+}
+
+char *
+outname(s)
+char *s;
+{
+       register char *p, c;
+       register n;
+
+       p = s;
+       n = 0;
+       while (c = getc(stdin)) {
+               *p++ = c;
+               n++;
+       }
+       do {
+               *p++ = 0;
+       } while (n++ < 8);
+       return(s);
+}
+
+error(s)
+char *s;
+{
+       printf("%s\n", s);
+       exit(1);
+}
diff --git a/TEST/tprint.c b/TEST/tprint.c
new file mode 100644 (file)
index 0000000..3b1f0df
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * tree printer routine for C
+ */
+
+#include "c1.h"
+
+char *strop[] {
+"0",
+";",
+"{",
+"}",
+"[",
+"]",
+"(",
+")",
+":",
+",",
+"10",
+"11",
+"12",
+"13",
+"14",
+"15",
+"16",
+"17",
+"18",
+"19",
+"",
+"",
+"string",
+"fcon",
+"sfcon",
+"25",
+"26",
+"",
+"",
+"sizeof",
+"++pre",
+"--pre",
+"++post",
+"--post",
+"!un",
+"&un",
+"*un",
+"-un",
+"~un",
+".",
+"+",
+"-",
+"*",
+"/",
+"%",
+">>",
+"<<",
+"&",
+"|",
+"^",
+"->",
+"itof",
+"ftoi",
+"&&",
+"||",
+"&~",
+"ftol",
+"ltof",
+"itol",
+"ltoi",
+"==",
+"!=",
+"<=",
+"<",
+">=",
+">",
+"<p",
+"<=p",
+">p",
+">=p",
+"=+",
+"=-",
+"=*",
+"=/",
+"=%",
+"=>>",
+"=<<",
+"=&",
+"=|",
+"=^",
+"=",
+"&(test)",
+"82",
+"83",
+"84",
+"=&~",
+"86",
+"87",
+"88",
+"89",
+"?",
+"91",
+"92",
+"93",
+"94",
+"95",
+"96",
+"97",
+"98",
+"99",
+"call",
+"mcall",
+"jump",
+"cbranch",
+"init",
+"setreg",
+"106",
+"107",
+"108",
+"109",
+"forcereg",
+};
+
+treeprint(tp)
+struct tnode *tp;
+{
+       register f;
+       extern fout;
+       static tout;
+
+       if (tout==0)
+               tout = dup(1);
+       flush();
+       f = fout;
+       fout = tout;
+       printf("\n");
+       tprt(tp, 0);
+       flush();
+       fout = f;
+}
+
+tprt(at, al)
+struct tnode *at;
+{
+       register struct tnode *t;
+       register i, l;
+
+       t = at;
+       l = al;
+       if (i=l)
+               do
+                       printf(". ");
+               while (--i);
+       if (t<treebase || t>=spacemax) {
+               printf("%o: bad tree ptr\n", t);
+               return;
+       }
+       if (t->op<0 || t->op>RFORCE) {
+               printf("%d\n", t->op);
+               return;
+       }
+       printf("%s", strop[t->op]);
+       switch (t->op) {
+
+       case SETREG:
+               printf("%d\n", t->type);
+               return;
+
+       case PLUS:
+       case MINUS:
+       case TIMES:
+       case DIVIDE:
+       case MOD:
+       case LSHIFT:
+       case RSHIFT:
+       case AND:
+       case OR:
+       case EXOR:
+       case NAND:
+       case LOGAND:
+       case LOGOR:
+       case EQUAL:
+       case NEQUAL:
+       case LESSEQ:
+       case LESS:
+       case GREATEQ:
+       case GREAT:
+       case LESSEQP:
+       case LESSP:
+       case GREATQP:
+       case GREATP:
+       case ASPLUS:
+       case ASMINUS:
+       case ASTIMES:
+       case ASDIV:
+       case ASMOD:
+       case ASRSH:
+       case ASLSH:
+       case ASSAND:
+       case ASSNAND:
+       case ASOR:
+       case ASXOR:
+       case ASSIGN:
+       case QUEST:
+       case CALL:
+       case MCALL:
+       case CALL1:
+       case CALL2:
+       case TAND:
+               prtype(t);
+
+       case COLON:
+       case COMMA:
+               printf("\n");
+               tprt(t->tr1, l+1);
+               tprt(t->tr2, l+1);
+               return;
+
+       case INCBEF:
+       case INCAFT:
+       case DECBEF:
+       case DECAFT:
+               printf(" (%d)", t->tr2);
+
+       case EXCLA:
+       case AMPER:
+       case STAR:
+       case NEG:
+       case COMPL:
+       case INIT:
+       case JUMP:
+       case LOAD:
+       case RFORCE:
+       case ITOF:
+       case FTOI:
+       case FTOL:
+       case LTOF:
+       case LTOI:
+       case ITOL:
+               prtype(t);
+               printf("\n");
+               tprt(t->tr1, l+1);
+               return;
+
+       case NAME:
+       case CON:
+       case SFCON:
+       case FCON:
+       case AUTOI:
+       case AUTOD:
+               pname(t, 0);
+               prtype(t);
+               printf("\n");
+               return;
+
+       case CBRANCH:
+               printf(" (L%d)\n", t->lbl);
+               tprt(t->btree, l+1);
+               return;
+
+       default:
+               printf(" unknown\n");
+               return;
+       }
+}
+
+char *typetab[] {
+       "int",
+       "char",
+       "float",
+       "double",
+       "struct",
+       "(?5)",
+       "long",
+       "(?7)",
+};
+
+char   *modtab[] {
+       0,
+       "*",
+       "()",
+       "[]",
+};
+
+prtype(atp)
+struct tnode *atp;
+{
+       register struct tnode *tp;
+       register t;
+
+       tp = atp;
+       printf(" %s", typetab[tp->type&07]);
+       t = (tp->type>>3) & 017777;
+       while (t&03) {
+               printf(modtab[t&03]);
+               t =>> 2;
+       }
+       printf(" (%d)", tp->degree);
+}
diff --git a/TEST/tst_adec.c b/TEST/tst_adec.c
new file mode 100644 (file)
index 0000000..078526c
--- /dev/null
@@ -0,0 +1,10 @@
+int    arr[100], x;
+long   p_end;
+main()
+{
+       puts("test autodecrement inside array reference:");
+       p_end = 0;
+       printf("before %ld (should be 0)\n", p_end);
+       x = arr[p_end--];
+       printf("after %ld (should be -1)\n", p_end);
+}
diff --git a/TEST/tst_asm.c b/TEST/tst_asm.c
new file mode 100644 (file)
index 0000000..f79d6e4
--- /dev/null
@@ -0,0 +1,10 @@
+main()
+{
+       register foo;
+       int bar;
+       foo = 4;
+       bar = 6;
+       asm("dec r4");
+       asm("inc 177766(r5)");
+       printf("4-1=%d, 6+1=%d\n", foo, bar);
+}
diff --git a/TEST/tst_assign.c b/TEST/tst_assign.c
new file mode 100644 (file)
index 0000000..c1a1317
--- /dev/null
@@ -0,0 +1,10 @@
+main()
+{
+       int     a = 15,
+               b = 20;
+
+       b =& a;
+       printf("20 & 15 = %d\n",b);
+       a =- 8;
+       printf("15 - 8 = %d\n",a);
+}
diff --git a/TEST/tst_lgm-g.c b/TEST/tst_lgm-g.c
new file mode 100644 (file)
index 0000000..7547fd9
--- /dev/null
@@ -0,0 +1,48 @@
+#include <stdio.h>
+
+/*
+ *     Initilization of structure containing a union:
+ * "tstlgm.c" actually is illegal anyway, since the structure
+ * only has four entries.  This file is more legal.  One set of
+ * compiler fixes allow this to compile (even correctly).
+ */
+
+struct TEST {
+       int first;
+       int second;
+       union UTEST {
+               int u_int;
+               char *u_cptr;
+               int *u_iptr;
+       } third;
+       int fourth;
+};
+
+struct TEST test[] = {
+       {0},
+       {1},
+       {1},
+       {1},
+       {1,2,3,4}, /* was "{1,2,(char *)3,4}," but '82 Ritchie complains */
+       {0},
+       {1,2,0,0},
+       {1,2,0,0},
+       {0,0,0,0},
+       {1}
+};
+
+main()
+{
+       int i;
+
+       printf("Size of TEST structure = %d\n",sizeof(struct TEST));
+       printf("Size of structure test = %d\n",sizeof(test));
+
+       for (i = 0; i < 10; ++i){
+               printf("Cycle %d ",i);
+               printf("First = %d\tSecond = %d\t",
+                       test[i].first, test[i].second);
+               printf("Union third = %d\t", test[i].third.u_int);
+               printf("Fourth = %d\n", test[i].fourth);
+       }
+}
diff --git a/TEST/tst_lgm.c b/TEST/tst_lgm.c
new file mode 100644 (file)
index 0000000..548e021
--- /dev/null
@@ -0,0 +1,47 @@
+#include <stdio.h>
+
+/*     Initilization of structure containing a union:
+ * "tstlgm.c" actually is illegal anyway, since the structure
+ * only has four entries.  This file is more legal.  One set of
+ * compiler fixes allow this to compile (even correctly).
+ */
+
+struct TEST {
+       int first;
+       int second;
+       union UTEST {
+               int u_int;
+               char *u_cptr;
+               int *u_iptr;
+       } third;
+       int fourth;
+};
+
+struct TEST test[] = {
+       {0},
+       {1},
+       {1},
+       {1},
+       {1,2,3,4,5,6},  /* this is what makes it actually illegal */
+       {0},
+       {1,2,0,0},
+       {1,2,0,0},
+       {0,0,0,0},
+       {1}
+};
+
+main()
+{
+       int i;
+
+       printf("Size of TEST structure = %d\n",sizeof(struct TEST));
+       printf("Size of structure test = %d\n",sizeof(test));
+
+       for (i = 0; i < 10; ++i){
+               printf("Cycle %d ",i);
+               printf("First = %d\tSecond = %d\t",
+                       test[i].first, test[i].second);
+               printf("Union third = %d\t", test[i].third.u_int);
+               printf("Fourth = %d\n", test[i].fourth);
+       }
+}
diff --git a/TEST/tst_longsym.c b/TEST/tst_longsym.c
new file mode 100644 (file)
index 0000000..a639bbd
--- /dev/null
@@ -0,0 +1,9 @@
+main()
+{
+       int foobarbyfar, foobarbyfar2;
+
+       foobarbyfar = 6;
+       foobarbyfar2 = 12;
+       printf("foobarbyfar=%d, foobarbyfar=%d, should be 6, 12\n",
+               foobarbyfar, foobarbyfar2);
+}
diff --git a/TEST/tst_pntint.c b/TEST/tst_pntint.c
new file mode 100644 (file)
index 0000000..aff635b
--- /dev/null
@@ -0,0 +1,46 @@
+main()
+{
+       short   s;
+       int     i;
+       long    l;
+       float   f;
+       char    *p;
+
+       s = "s = ...";          /* $L4 assigned to s            */
+       i = "i = ...";          /* $L5 assigned to i            */
+
+       l = "l = ...";          /* $L6 assigned to low word of l,
+                                * upper word cleared
+                                */
+
+/*     f = "f = ...";          /* totally illegal              */
+
+       s = p;                  /* p assigned to s              */
+       i = p;                  /* p assigned to i              */
+
+       l = p;                  /* p assigned to low word of l,
+                                * upper word cleared.
+                                */
+
+/*     f = p;                  /* totally illegal              */
+
+       p = 'a';
+       p = 5;
+       p = 15L;
+       p = 100000L;            /* -74540(8) is assigned to p, with no
+                                * truncation warning, but then the same
+                                * thing happens with the next statement,
+                                * so this is a global error
+                                */
+
+       i = 100000L;            /* -74540(8) assigned to i      */
+
+       p = s;                  /* s assigned to p              */
+       p = i;                  /* i assigned to p              */
+       p = l;                  /* low word of l assigned to p  */
+/*     p = f;                  /* totally illegal              */
+
+       l = i;                  /* i assigned to low word of l,
+                                * upper word sign extended
+                                */
+}
diff --git a/TEST/tst_rhh-g.c b/TEST/tst_rhh-g.c
new file mode 100644 (file)
index 0000000..d29a991
--- /dev/null
@@ -0,0 +1,7 @@
+long   *pl;
+main()
+{
+       register i;
+
+       (pl-pl)+(long)i;
+}
diff --git a/TEST/tst_rhh.c b/TEST/tst_rhh.c
new file mode 100644 (file)
index 0000000..0674e35
--- /dev/null
@@ -0,0 +1,7 @@
+long   *pl;
+main()
+{
+       register i, j;
+
+       (pl-pl)+(long)i;
+}
diff --git a/TEST/tst_sgncmp.c b/TEST/tst_sgncmp.c
new file mode 100644 (file)
index 0000000..cca8276
--- /dev/null
@@ -0,0 +1,39 @@
+int zero = 0;
+int selfinv;
+int i;
+int j;
+int k;
+
+main()
+{
+       selfinv = ~(((unsigned)~0) >> 1);
+       i = selfinv + 0101;     /* neg */
+       j = selfinv - 0100;     /* pos */
+       printf("everything should be true\n");
+       printf("selfinv = 0%o\n", selfinv);
+       printf("zero = %d\n", zero);
+       printf("i = 0%o = %d.\n", i, i);
+       printf("j = 0%o = %d.\n", j, j);
+       printf("j-i = 0%o = %d.\n", j - i);
+       printf("j - i < 0\t");
+       if ((j-i) < 0)
+               printf("true\n");
+       else
+               printf("false\n");
+       k = j - i;
+       printf("k=j-i; (k < 0)\t");
+       if (k < 0)
+               printf("true\n");
+       else
+               printf("false\n");
+       printf("j - i < zero\t");
+       if (j - i < zero)
+               printf("true\n");
+       else
+               printf("false\n");
+       printf("(j-i < 0) == (j - i < zero)\t");
+       if ((j-i < 0) == (j - i < zero))
+               printf("true\n");
+       else
+               printf("false\n");
+}
diff --git a/c0.h b/c0.h
new file mode 100644 (file)
index 0000000..4f86a65
--- /dev/null
+++ b/c0.h
@@ -0,0 +1,592 @@
+/*
+ *     C compiler-- first pass header
+ */
+
+#ifndef _C0_H
+#define _C0_H 1
+
+#include <stdio.h>
+
+#ifdef pdp11
+typedef int _INT;
+typedef long _LONG;
+typedef unsigned int _UNSIGNED_INT;
+typedef unsigned long _UNSIGNED_LONG;
+typedef float _FLOAT;
+typedef double _DOUBLE;
+#else
+#include <stdint.h>
+typedef int16_t _INT;
+typedef int32_t _LONG;
+typedef uint16_t _UNSIGNED_INT;
+typedef uint32_t _UNSIGNED_LONG;
+typedef struct { uint32_t h; } _FLOAT;
+typedef struct { uint32_t l; uint32_t h; } _DOUBLE;
+#endif
+
+/*
+ * This parameter is the _only_ one which affects the recognized length
+ * of symbols.  Symbol names are dynamically allocated and null terminated
+ * now, the define below is the 'cutoff' or maximum length to permit.
+ *
+ * NOTE: there are _exactly_ 4 references to this in all of c0.  There are
+ * _NO_ references to it in c1.  Just make sure that the value is less than
+ * 79 and c1 will be oblivious to the length of a symbol name.
+ *
+ * NOTE: The optimizer (c2) needs to be updated if the size of a symbol
+ * changes.  See the file c2.h
+*/
+
+#define        MAXCPS  32      /* # chars per symbol */
+
+#define        MAXINT  077777  /* Largest positive short integer */
+#define        MAXUINT 0177777 /* largest unsigned integer */
+#define        HSHSIZ  300     /* # entries in hash table for names */
+#define        CMSIZ   40      /* size of expression stack */
+#define        SSIZE   40      /* size of other expression stack */
+#define        SWSIZ   300     /* size of switch table */
+#define        NMEMS   128     /* Number of members in a structure */
+#define        NBPW    16      /* bits per word, object machine */
+#define        NBPC    8       /* bits per character, object machine */
+#define        NCPW    2       /* chars per word, object machine */
+#define        LNCPW   2       /* chars per word, compiler's machine */
+#define        LNBPW   16      /* bits per word, compiler's machine */
+/* dlf change
+#define        STAUTO  (-6)     offset of first auto variable */
+int    STAUTO;
+#define        STARG   4       /* offset of first argument */
+#define        DCLSLOP 512     /* Amount trees lie above declaration stuff */
+
+/* Nick */
+#ifdef pdp11
+#define MAXPATHLEN 64
+#else
+#define MAXPATHLEN 1024
+#endif
+
+
+/*
+ * # bytes in primitive types
+ */
+#define        SZCHAR  1
+#define        SZINT   2
+#define        SZPTR   2
+#define        SZFLOAT 4
+#define        SZLONG  4
+#define        SZDOUB  8
+
+/*
+ * Structure of namelist
+ */
+struct nmlist {
+       char    hclass;         /* storage class */
+       char    hflag;          /* various flags */
+       int     htype;          /* type */
+       int     *hsubsp;        /* subscript list */
+       union   str *hstrp;     /* structure description */
+       int     hoffset;        /* post-allocation location */
+       struct  nmlist *nextnm; /* next name in chain */
+       union   str *sparent;   /* Structure of which this is member */
+       char    hblklev;        /* Block level of definition */
+       char    *name;          /* ASCII name */
+};
+
+/*
+ * format of a structure description
+ *  Same gadget is also used for fields,
+ *  which can't be structures also.
+ * Finally, it is used for parameter collection.
+ */
+union str {
+       struct SS {
+               int     ssize;                  /* structure size */
+               struct nmlist **memlist;        /* member list */
+       } S;
+       struct FS {
+               int     flen;                   /* field width in bits */
+               int     bitoffs;                /* shift count */
+       } F;
+       struct nmlist P;
+};
+
+/*
+ * Structure of tree nodes for operators
+ */
+struct tnode {
+       int     op;             /* operator */
+       int     type;           /* data type */
+       int     *subsp;         /* subscript list (for arrays) */
+       union   str *strp;      /* structure description for structs */
+       union   tree *tr1;      /* left operand */
+       union   tree *tr2;      /* right operand */
+};
+
+/*
+ * Tree node for constants
+ */
+struct cnode {
+       int     op;
+       int     type;
+       int     *subsp;
+       union   str *strp;
+       int     value;
+};
+
+/*
+ * Tree node for long constants
+ */
+struct lnode {
+       int     op;
+       int     type;
+       int     *subsp;
+       union   str *strp;
+       long    lvalue;
+};
+
+/*
+ * tree node for floating
+ * constants
+ */
+struct fnode {
+       int     op;
+       int     type;
+       int     *subsp;
+       union   str *strp;
+       char    *cstr;
+};
+
+/*
+ * All possibilities for tree nodes
+ */
+union tree {
+       struct  tnode t;
+       struct  cnode c;
+       struct  lnode l;
+       struct  fnode f;
+       struct  nmlist n;
+       struct  FS fld;
+};
+
+
+/*
+ * Place used to keep dimensions
+ * during declarations
+ */
+struct tdim {
+       int     rank;
+       int     dimens[5];
+};
+
+/*
+ * Table for recording switches.
+ */
+struct swtab {
+       int     swlab;
+       int     swval;
+};
+
+#define        TNULL   (union tree *)NULL
+
+extern char cvtab[4][4];
+extern char filename[MAXPATHLEN]; /* Nick */
+extern int opdope[];
+extern char ctab[];
+extern char symbuf[MAXCPS+2];
+extern struct nmlist   *hshtab[HSHSIZ];
+extern int kwhash[(HSHSIZ+LNBPW-1)/LNBPW];
+extern union tree **cp;
+extern int isn;
+extern struct swtab swtab[SWSIZ];
+extern int unscflg;
+extern struct swtab *swp;
+extern int contlab;
+extern int brklab;
+extern int retlab;
+extern int deflab;
+extern unsigned autolen;       /* make these int if necessary */
+extern unsigned maxauto;       /* ... will only cause trouble rarely */
+extern int peeksym;
+extern int peekc;
+extern int eof;
+extern int line;
+extern char *locbase;
+extern char *treebase;
+extern char *treebot;
+extern char *coremax;
+extern struct nmlist *defsym;
+extern struct nmlist *funcsym;
+extern int proflg;
+extern struct nmlist *csym;
+extern int cval;
+extern _LONG lcval;
+extern int nchstr;
+extern int nerror;
+extern struct nmlist *paraml;
+extern struct nmlist *parame;
+extern int strflg;
+extern int mosflg;
+extern int initflg;
+extern char sbuf[BUFSIZ];
+extern FILE *sbufp;
+extern int regvar;
+extern int bitoffs;
+extern struct tnode funcblk;
+extern char cvntab[];
+extern char numbuf[64];
+extern struct nmlist **memlist;
+extern union str *sparent;
+extern int nmems;
+extern struct nmlist structhole;
+extern int blklev;
+extern int mossym;
+
+/*
+  operators
+*/
+#define        EOFC    0
+#define        SEMI    1
+#define        LBRACE  2
+#define        RBRACE  3
+#define        LBRACK  4
+#define        RBRACK  5
+#define        LPARN   6
+#define        RPARN   7
+#define        COLON   8
+#define        COMMA   9
+#define        FSEL    10
+#define        CAST    11
+#define        ETYPE   12
+
+#define        KEYW    19
+#define        NAME    20
+#define        CON     21
+#define        STRING  22
+#define        FCON    23
+#define        SFCON   24
+#define        LCON    25
+#define        SLCON   26
+#define        NULLOP  29
+#define        XNULLOP 218     /* interface version */
+
+#define        SIZEOF  91
+#define        INCBEF  30
+#define        DECBEF  31
+#define        INCAFT  32
+#define        DECAFT  33
+#define        EXCLA   34
+#define        AMPER   35
+#define        STAR    36
+#define        NEG     37
+#define        COMPL   38
+
+#define        DOT     39
+#define        PLUS    40
+#define        MINUS   41
+#define        TIMES   42
+#define        DIVIDE  43
+#define        MOD     44
+#define        RSHIFT  45
+#define        LSHIFT  46
+#define        AND     47
+#define        OR      48
+#define        EXOR    49
+#define        ARROW   50
+#define        ITOF    51
+#define        FTOI    52
+#define        LOGAND  53
+#define        LOGOR   54
+#define        FTOL    56
+#define        LTOF    57
+#define        ITOL    58
+#define        LTOI    59
+#define        ITOP    13
+#define        PTOI    14
+#define        LTOP    15
+
+#define        EQUAL   60
+#define        NEQUAL  61
+#define        LESSEQ  62
+#define        LESS    63
+#define        GREATEQ 64
+#define        GREAT   65
+#define        LESSEQP 66
+#define        LESSP   67
+#define        GREATQP 68
+#define        GREATP  69
+
+#define        ASPLUS  70
+#define        ASMINUS 71
+#define        ASTIMES 72
+#define        ASDIV   73
+#define        ASMOD   74
+#define        ASRSH   75
+#define        ASLSH   76
+#define        ASSAND  77
+#define        ASOR    78
+#define        ASXOR   79
+#define        ASSIGN  80
+
+#define        QUEST   90
+#define        MAX     93
+#define        MAXP    94
+#define        MIN     95
+#define        MINP    96
+#define        SEQNC   97
+#define        CALL    100
+#define        MCALL   101
+#define        JUMP    102
+#define        CBRANCH 103
+#define        INIT    104
+#define        SETREG  105
+#define        RFORCE  110
+#define        BRANCH  111
+#define        LABEL   112
+#define        NLABEL  113
+#define        RLABEL  114
+#define        STRASG  115
+#define        ITOC    109
+#define        SEOF    200     /* stack EOF marker in expr compilation */
+
+/*
+  types
+*/
+#define        INT     0
+#define        CHAR    1
+#define        FLOAT   2
+#define        DOUBLE  3
+#define        STRUCT  4
+#define        LONG    6
+#define        UNSIGN  7
+#define        UNCHAR  8
+#define        UNLONG  9
+#define        VOID    10
+#define        UNION   8               /* adjusted later to struct */
+
+#define        ALIGN   01
+#define        TYPE    017
+#define        BIGTYPE 060000
+#define        TYLEN   2
+#define        XTYPE   (03<<4)
+#define        PTR     020
+#define        FUNC    040
+#define        ARRAY   060
+
+/*
+  storage classes
+*/
+#define        KEYWC   1
+#define        TYPEDEF 9
+#define        MOS     10
+#define        AUTO    11
+#define        EXTERN  12
+#define        STATIC  13
+#define        REG     14
+#define        STRTAG  15
+#define ARG    16
+#define        ARG1    17
+#define        AREG    18
+#define        DEFXTRN 20
+#define        MOU     21
+#define        ENUMTAG 22
+#define        ENUMCON 24
+
+/*
+  keywords
+*/
+#define        GOTO    20
+#define        RETURN  21
+#define        IF      22
+#define        WHILE   23
+#define        ELSE    24
+#define        SWITCH  25
+#define        CASE    26
+#define        BREAK   27
+#define        CONTIN  28
+#define        DO      29
+#define        DEFAULT 30
+#define        FOR     31
+#define        ENUM    32
+#define        ASM     33
+
+/*
+  characters
+*/
+#define        BSLASH  117
+#define        SHARP   118
+#define        INSERT  119
+#define        PERIOD  120
+#define        SQUOTE  121
+#define        DQUOTE  122
+#define        LETTER  123
+#define        DIGIT   124
+#define        NEWLN   125
+#define        SPACE   126
+#define        UNKN    127
+
+/*
+ * Special operators in intermediate code
+ */
+#define        BDATA   200
+#define        WDATA   201
+#define        PROG    202
+#define        DATA    203
+#define        BSS     204
+#define        CSPACE  205
+#define        SSPACE  206
+#define        SYMDEF  207
+#define        SAVE    208
+#define        RETRN   209
+#define        EVEN    210
+#define        PROFIL  212
+#define        SWIT    213
+#define        EXPR    214
+#define        SNAME   215
+#define        RNAME   216
+#define        ANAME   217
+#define        SETSTK  219
+#define        SINIT   220
+#define        ASSEM   223
+
+/*
+  Flag bits
+*/
+
+#define        BINARY  01
+#define        LVALUE  02
+#define        RELAT   04
+#define        ASSGOP  010
+#define        LWORD   020
+#define        RWORD   040
+#define        COMMUTE 0100
+#define        RASSOC  0200
+#define        LEAF    0400
+#define        PCVOK   040000
+
+/*
+ * Conversion codes
+ */
+#define        ITF     1
+#define        ITL     2
+#define        LTF     3
+#define        ITP     4
+#define        PTI     5
+#define        FTI     6
+#define        LTI     7
+#define        FTL     8
+#define        LTP     9
+#define        ITC     10
+#define        XX      15
+
+/*
+ * symbol table flags
+ */
+
+#define        FMOS    01
+#define        FTAG    02
+#define        FENUM   03
+#define        FUNION  04
+#define        FKIND   07
+#define        FFIELD  020
+#define        FINIT   040
+#define        FLABL   0100
+
+#ifndef __P
+#ifdef __STDC__
+#define __P(args) args
+#else
+#define __P(args) ()
+#endif
+#endif
+
+/* c00.c */
+int main __P((int argc, char *argv[]));
+int lookup __P((void));
+int findkw __P((void));
+int symbol __P((void));
+int getnum __P((void));
+int subseq __P((int c, int a, int b));
+void putstr __P((int lab, register int max));
+void cntstr __P((void));
+int getcc __P((void));
+int mapch __P((int ac));
+union tree *tree __P((int eflag));
+union tree *xprtype __P((void));
+char *copnum __P((int len));
+
+/* c01.c */
+void build __P((int op));
+union tree *structident __P((register union tree *p1, register union tree *p2));
+union tree *convert __P((union tree *p, int t, int cvn, int len));
+void setype __P((register union tree *p, register int t, register union tree *newp));
+union tree *chkfun __P((register union tree *p));
+union tree *disarray __P((register union tree *p));
+void chkw __P((union tree *p, int okt));
+int lintyp __P((int t));
+void werror __P((char *s, ...));
+void error __P((char *s, ...));
+union tree *block __P((int op, int t, int *subs, union str *str, union tree *p1, union tree *p2));
+union tree *nblock __P((register struct nmlist *ds));
+union tree *cblock __P((int v));
+union tree *fblock __P((int t, char *string));
+char *Tblock __P((int n));
+char *starttree __P((void));
+void endtree __P((char *tp));
+char *Dblock __P((int n));
+void chklval __P((register union tree *p));
+int fold __P((int op, register union tree *p1, union tree *p2));
+int conexp __P((void));
+void assignop __P((int op, register union tree *p1, register union tree *p2));
+struct nmlist *gentemp __P((int type));
+
+/* c02.c */
+void extdef __P((void));
+void cfunc __P((void));
+int cinit __P((struct nmlist *anp, int flex, int sclass));
+void strinit __P((struct nmlist *np, int sclass));
+void setinit __P((register struct nmlist *np));
+void statement __P((void));
+int forstmt __P((void));
+union tree *pexpr __P((int eflag));
+void pswitch __P((void));
+void funchead __P((void));
+void blockhead __P((void));
+void blkend __P((void));
+void nameconflict __P((register struct nmlist *ocs, register struct nmlist *cs));
+void prste __P((struct nmlist *cs));
+void errflush __P((int ao));
+
+/* c03.c */
+int declist __P((int sclass));
+int getkeywords __P((int *scptr, struct nmlist *tptr));
+union str *strdec __P((int mosf, int kind));
+int declare __P((int askw, struct nmlist *tptr, int offset));
+int decl1 __P((int askw, struct nmlist *atptr, int offset, struct nmlist *absname));
+struct nmlist *pushdecl __P((register struct nmlist *sp));
+int getype __P((register struct tdim *dimp, struct nmlist *absname));
+void typov __P((void));
+int align __P((int type, int offset, int aflen));
+void decsyn __P((int o));
+void redec __P((void));
+int goodreg __P((struct nmlist *hp));
+
+/* c04.c */
+int decref __P((register int t));
+int incref __P((register int t));
+void cbranch __P((union tree *t, int lbl, int cond));
+void rcexpr __P((register union tree *tp));
+void treeout __P((register union tree *tp, int isstruct));
+void branch __P((int lab));
+void label __P((int l));
+int plength __P((register union tree *p));
+int length __P((union tree *cs));
+int rlength __P((union tree *cs));
+int simplegoto __P((void));
+int nextchar __P((void));
+int spnextchar __P((void));
+void chconbrk __P((int l));
+void dogoto __P((void));
+void doret __P((void));
+void outcode __P((char *s, ...));
+unsigned int hash __P((register char *sp));
+
+#endif
diff --git a/c00.c b/c00.c
new file mode 100644 (file)
index 0000000..240d482
--- /dev/null
+++ b/c00.c
@@ -0,0 +1,903 @@
+/* C compiler
+ *
+ *     2.1     (2.11BSD)       1996/01/04
+ *
+ * Called from cc:
+ *   c0 source temp1 temp2 [ profileflag ]
+ * temp1 gets most of the intermediate code;
+ * strings are put on temp2, which c1 reads after temp1.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "c0.h"
+
+int    isn     = 1;
+int    peeksym = -1;
+int    line    = 1;
+struct tnode   funcblk = { NAME };
+
+struct kwtab {
+       char    *kwname;
+       int     kwval;
+} kwtab[] = {
+       {"int",         INT},
+       {"char",        CHAR},
+       {"float",       FLOAT},
+       {"double",      DOUBLE},
+       {"struct",      STRUCT},
+       {"long",        LONG},
+       {"unsigned",    UNSIGN},
+       {"union",       UNION},
+       {"short",       INT},
+       {"void",        VOID},
+       {"auto",        AUTO},
+       {"extern",      EXTERN},
+       {"static",      STATIC},
+       {"register",    REG},
+       {"goto",        GOTO},
+       {"return",      RETURN},
+       {"if",          IF},
+       {"while",       WHILE},
+       {"else",        ELSE},
+       {"switch",      SWITCH},
+       {"case",        CASE},
+       {"break",       BREAK},
+       {"continue",    CONTIN},
+       {"do",          DO},
+       {"default",     DEFAULT},
+       {"for",         FOR},
+       {"sizeof",      SIZEOF},
+       {"typedef",     TYPEDEF},
+       {"enum",        ENUM},
+       {"asm",         ASM},
+       {0,             0}
+};
+
+union  tree *cmst[CMSIZ];
+union  tree **cp = cmst;
+int    Wflag;                  /* print warning messages */
+
+int main(argc, argv) int argc; char *argv[]; {
+       register unsigned i;
+       register struct kwtab *ip;
+       char    buf1[BUFSIZ],
+               buf2[BUFSIZ];
+
+       if (argc>1 && strcmp(argv[1], "-u")==0) {
+               argc--;
+               argv++;
+               unscflg++;
+       }
+       if(argc<4) {
+               error("Arg count");
+               exit(1);
+       }
+       if (freopen(argv[1], "r", stdin)==NULL) {
+               error("Can't find %s", argv[1]);
+               exit(1);
+       }
+       setbuf(stdin,buf1);     /* stdio sbrk problems */
+       if (freopen(argv[2], "w", stdout)==NULL || (sbufp=fopen(argv[3],"w"))==NULL) {
+               error("Can't create temp");
+               exit(1);
+       }
+       setbuf(stdout,buf2);    /* stdio sbrk problems */
+       setbuf(sbufp, sbuf);
+       /*
+        * Overlays: allow an extra word on the stack for
+        * each stack from to store the overlay number.
+        */
+       STAUTO = -8;
+       while (argc>4) {
+               switch (argv[4][1]) {
+               case 'P':
+                       proflg++;
+                       break;
+               case 'V':               /* overlays; default, now */
+                       break;
+               case 'w':
+               case 'W':               /* don't print warning messages */
+                       Wflag++;
+                       break;
+               }
+               argc--; argv++;
+       }
+       /*
+        * The hash table locations of the keywords
+        * are marked; if an identifier hashes to one of
+        * these locations, it is looked up in in the keyword
+        * table first.
+        */
+       for (ip=kwtab; ip->kwname; ip++) {
+               i = hash(ip->kwname);
+               kwhash[i/LNBPW] |= 1 << (i%LNBPW);
+       }
+       coremax = locbase = sbrk(0);
+       while(!eof)
+               extdef();
+       outcode("B", EOFC);
+       strflg++;
+       outcode("B", EOFC);
+       blkend();
+       exit(nerror!=0);
+}
+
+/*
+ * Look up the identifier in symbuf in the symbol table.
+ * If it hashes to the same spot as a keyword, try the keyword table
+ * first.
+ * Return is a ptr to the symbol table entry.
+ */
+int lookup() {
+       unsigned ihash;
+       register struct nmlist *rp;
+
+       ihash = hash(symbuf);
+       if (kwhash[ihash/LNBPW] & (1 << (ihash%LNBPW)))
+               if (findkw())
+                       return(KEYW);
+       rp = hshtab[ihash];
+       while (rp) {
+               if (strcmp(symbuf, rp->name) != 0)
+                       goto no;
+               if (mossym != (rp->hflag&FKIND))
+                       goto no;
+               csym = rp;
+               return(NAME);
+       no:
+               rp = rp->nextnm;
+       }
+       rp = (struct nmlist *)Dblock(sizeof(struct nmlist));
+       rp->nextnm = hshtab[ihash];
+       hshtab[ihash] = rp;
+       rp->hclass = 0;
+       rp->htype = 0;
+       rp->hoffset = 0;
+       rp->hsubsp = NULL;
+       rp->hstrp = NULL;
+       rp->sparent = NULL;
+       rp->hblklev = blklev;
+       rp->hflag = mossym;
+       rp->name = Dblock((strlen(symbuf) + 1 + LNCPW - 1) & ~(LNCPW - 1));
+       strcpy(rp->name, symbuf);
+       csym = rp;
+       return(NAME);
+}
+
+/*
+ * Search the keyword table.
+ */
+int findkw() {
+       register struct kwtab *kp;
+
+       for (kp=kwtab; kp->kwname; kp++) {
+               if (strcmp(symbuf, kp->kwname) == 0) {
+                       cval = kp->kwval;
+                       return(1);
+               }
+       }
+       return(0);
+}
+
+
+/*
+ * Return the next symbol from the input.
+ * peeksym is a pushed-back symbol, peekc is a pushed-back
+ * character (after peeksym).
+ * mosflg means that the next symbol, if an identifier,
+ * is a member of structure or a structure tag or an enum tag
+ */
+int symbol() {
+       register int c;
+       register char *sp;
+       register int tline;
+
+       if (peeksym>=0) {
+               c = peeksym;
+               peeksym = -1;
+               if (c==NAME)
+                       mosflg = 0;
+               return(c);
+       }
+       if (peekc) {
+               c = peekc;
+               peekc = 0;
+       } else
+               if (eof)
+                       return(EOFC);
+               else
+                       c = getchar();
+loop:
+       if (c==EOF) {
+               eof++;
+               return(EOFC);
+       }
+       switch(ctab[c]) {
+
+       case SHARP:
+               if ((c=symbol())!=CON) {
+                       error("Illegal #");
+                       return(c);
+               }
+               tline = cval;
+               while (ctab[peekc]==SPACE)
+                       peekc = getchar();
+               if (peekc=='"') {
+                       sp = filename;
+                       while (sp < filename + MAXPATHLEN - 1 && (c = mapch('"')) >= 0) /* Nick */
+                               *sp++ = c;
+                       *sp++ = 0;
+                       peekc = getchar();
+               }
+               if (peekc != '\n') {
+                       error("Illegal #");
+                       while (getchar()!='\n' && eof==0)
+                               ;
+               }
+               peekc = 0;
+               line = tline;
+               return(symbol());
+
+       case NEWLN:
+               line++;
+
+       case SPACE:
+               c = getchar();
+               goto loop;
+
+       case PLUS:
+               return(subseq(c,PLUS,INCBEF));
+
+       case MINUS:
+               if (subseq(c, 0, 1))
+                       return(DECBEF);
+               return(subseq('>', MINUS, ARROW));
+
+       case ASSIGN:
+               return(subseq(c, ASSIGN, EQUAL));
+
+       case LESS:
+               if (subseq(c,0,1))
+                       return(LSHIFT);
+               return(subseq('=',LESS,LESSEQ));
+
+       case GREAT:
+               if (subseq(c,0,1))
+                       return(RSHIFT);
+               return(subseq('=',GREAT,GREATEQ));
+
+       case EXCLA:
+               return(subseq('=',EXCLA,NEQUAL));
+
+       case BSLASH:
+               if (subseq('/', 0, 1))
+                       return(MAX);
+               goto unkn;
+
+       case DIVIDE:
+               if (subseq('\\', 0, 1))
+                       return(MIN);
+               if (subseq('*',1,0))
+                       return(DIVIDE);
+               while ((c = spnextchar()) != EOFC) {
+                       peekc = 0;
+                       if (c=='*') {
+                               if (spnextchar() == '/') {
+                                       peekc = 0;
+                                       c = getchar();
+                                       goto loop;
+                               }
+                       }
+               }
+               eof++;
+               error("Nonterminated comment");
+               return(0);
+
+       case PERIOD:
+       case DIGIT:
+               peekc = c;
+               return(getnum());
+
+       case DQUOTE:
+               cval = isn++;
+               return(STRING);
+
+       case SQUOTE:
+               return(getcc());
+
+       case LETTER:
+               sp = symbuf;
+               while (ctab[c]==LETTER || ctab[c]==DIGIT) {
+                       if (sp < symbuf + MAXCPS)
+                               *sp++ = c;
+                       c = getchar();
+               }
+               *sp++ = '\0';
+               mossym = mosflg;
+               mosflg = 0;
+               peekc = c;
+               if ((c=lookup())==KEYW && cval==SIZEOF)
+                       c = SIZEOF;
+               return(c);
+
+       case AND:
+               return(subseq('&', AND, LOGAND));
+
+       case OR:
+               return(subseq('|', OR, LOGOR));
+
+       case UNKN:
+       unkn:
+               error("Unknown character");
+               c = getchar();
+               goto loop;
+
+       }
+       return(ctab[c]);
+}
+
+/*
+ * Read a number.  Return kind.
+ */
+int getnum() {
+       register char *np;
+       register int c, base;
+       int expseen, sym, ndigit;
+       char *nsyn;
+       int maxdigit;
+
+       nsyn = "Number syntax";
+       lcval = 0;
+       base = 10;
+       maxdigit = 0;
+       np = numbuf;
+       ndigit = 0;
+       sym = CON;
+       expseen = 0;
+       if ((c=spnextchar()) == '0')
+               base = 8;
+       for (;; c = getchar()) {
+               *np++ = c;
+               if (ctab[c]==DIGIT || (base==16) && ('a'<=c&&c<='f'||'A'<=c&&c<='F')) {
+                       if (base==8)
+                               lcval <<= 3;
+                       else if (base==10)
+                               lcval = ((lcval<<2) + lcval)<<1;
+                       else
+                               lcval <<= 4;
+                       if (ctab[c]==DIGIT)
+                               c -= '0';
+                       else if (c>='a')
+                               c -= 'a'-10;
+                       else
+                               c -= 'A'-10;
+                       lcval += c;
+                       ndigit++;
+                       if (c>maxdigit)
+                               maxdigit = c;
+                       continue;
+               }
+               if (c=='.') {
+                       if (base==16 || sym==FCON)
+                               error(nsyn);
+                       sym = FCON;
+                       base = 10;
+                       continue;
+               }
+               if (ndigit==0) {
+                       sym = DOT;
+                       break;
+               }
+               if ((c=='e'||c=='E') && expseen==0) {
+                       expseen++;
+                       sym = FCON;
+                       if (base==16 || maxdigit>=10)
+                               error(nsyn);
+                       base = 10;
+                       *np++ = c = getchar();
+                       if (c!='+' && c!='-' && ctab[c]!=DIGIT)
+                               break;
+               } else if (c=='x' || c=='X') {
+                       if (base!=8 || lcval!=0 || sym!=CON)
+                               error(nsyn);
+                       base = 16;
+               } else if ((c=='l' || c=='L') && sym==CON) {
+                       c = getchar();
+                       sym = LCON;
+                       break;
+               } else
+                       break;
+       }
+       peekc = c;
+       if (maxdigit >= base)
+               error(nsyn);
+       if (sym==FCON) {
+               np[-1] = 0;
+               cval = np-numbuf;
+               return(FCON);
+       }
+       if (sym==CON && (lcval<0 || lcval>MAXINT&&base==10 || (lcval>>1)>MAXINT)) {
+               sym = LCON;
+       }
+       cval = lcval;
+       return(sym);
+}
+
+/*
+ * If the next input character is c, return b and advance.
+ * Otherwise push back the character and return a.
+ */
+int subseq(c, a, b) int c; int a; int b; {
+       if (spnextchar() != c)
+               return(a);
+       peekc = 0;
+       return(b);
+}
+
+/*
+ * Write out a string, either in-line
+ * or in the string temp file labelled by
+ * lab.
+ */
+void putstr(lab, max) int lab; register int max; {
+       register int c;
+
+       nchstr = 0;
+       if (lab) {
+               strflg++;
+               outcode("BNB", LABEL, lab, BDATA);
+               max = 10000;
+       } else
+               outcode("B", BDATA);
+       while ((c = mapch('"')) >= 0) {
+               if (nchstr < max) {
+                       nchstr++;
+                       if (nchstr%15 == 0)
+                               outcode("0B", BDATA);
+                       outcode("1N", c & 0377);
+               }
+       }
+       if (nchstr < max) {
+               nchstr++;
+               outcode("10");
+       }
+       outcode("0");
+       strflg = 0;
+}
+
+void cntstr() {
+       register int c;
+
+       nchstr = 1;
+       while ((c = mapch('"')) >= 0) {
+               nchstr++;
+       }
+}
+
+/*
+ * read a single-quoted character constant.
+ * The routine is sensitive to the layout of
+ * characters in a word.
+ */
+int getcc() {
+       register int c, cc;
+#ifdef pdp11
+       register char *ccp;
+       char realc;
+#else
+       register int shift;
+#endif
+
+       cval = 0;
+#ifdef pdp11
+       ccp = (char *)&cval;
+#else
+       shift = 0;
+#endif
+       cc = 0;
+       while((c=mapch('\'')) >= 0)
+               if(cc++ < LNCPW) {
+#ifdef pdp11
+                       *ccp++ = c;
+#else
+                       cval |= (c & 0377) << shift;
+                       shift += 8;
+#endif
+               }
+       if (cc>LNCPW)
+               error("Long character constant");
+       if (cc==1) {
+#ifdef pdp11
+               realc = cval;
+               cval = realc;
+#else
+               /* we default to signed char */
+               if (cval & 0200)
+                       cval |= ~0377;
+#endif
+       }
+       return(CON);
+}
+
+/*
+ * Read a character in a string or character constant,
+ * detecting the end of the string.
+ * It implements the escape sequences.
+ */
+int mapch(ac) int ac; {
+       register int a, c, n;
+       static int mpeek;
+
+       c = ac;
+       if (a = mpeek)
+               mpeek = 0;
+       else
+               a = getchar();
+loop:
+       if (a==c)
+               return(-1);
+       switch(a) {
+
+       case '\n':
+       case '\0':
+               error("Nonterminated string");
+               peekc = a;
+               return(-1);
+
+       case '\\':
+               switch (a=getchar()) {
+
+               case 't':
+                       return('\t');
+
+               case 'n':
+                       return('\n');
+
+               case 'b':
+                       return('\b');
+
+               case 'f':
+                       return('\014');
+
+               case 'v':
+                       return('\013');
+
+               case '0': case '1': case '2': case '3':
+               case '4': case '5': case '6': case '7':
+                       n = 0;
+                       c = 0;
+                       while (++c<=3 && '0'<=a && a<='7') {
+                               n <<= 3;
+                               n += a-'0';
+                               a = getchar();
+                       }
+                       mpeek = a;
+                       return(n);
+
+               case 'r':
+                       return('\r');
+
+               case '\n':
+                       line++;
+                       a = getchar();
+                       goto loop;
+               }
+       }
+       return(a);
+}
+
+/*
+ * Read an expression and return a pointer to its tree.
+ * It's the classical bottom-up, priority-driven scheme.
+ * The initflg prevents the parse from going past
+ * "," or ":" because those delimiters are special
+ * in initializer (and some other) expressions.
+ */
+union tree *tree(eflag) int eflag; {
+       int *op, opst[SSIZE], *pp, prst[SSIZE];
+       register int andflg, o;
+       register struct nmlist *cs;
+       int p, ps, os, xo = 0, *xop;
+       char *svtree;
+       static struct cnode garbage = { CON, INT, (int *)NULL, (union str *)NULL, 0 };
+
+       svtree = starttree();
+       op = opst;
+       pp = prst;
+       *op = SEOF;
+       *pp = 06;
+       andflg = 0;
+
+advanc:
+       switch (o=symbol()) {
+
+       case NAME:
+               cs = csym;
+               if (cs->hclass==TYPEDEF)
+                       goto atype;
+               if (cs->hclass==ENUMCON) {
+                       *cp++ = cblock(cs->hoffset);
+                       goto tand;
+               }
+               if (cs->hclass==0 && cs->htype==0)
+                       if(nextchar()=='(') {
+                               /* set function */
+                               cs->hclass = EXTERN;
+                               cs->htype = FUNC;
+                       } else {
+                               cs->hclass = STATIC;
+                               error("%s undefined; func. %s", cs->name,
+                                       funcsym ? funcsym->name : "(none)");
+                       }
+               *cp++ = nblock(cs);
+               goto tand;
+
+       case FCON:
+               *cp++ = fblock(DOUBLE, copnum(cval));
+               goto tand;
+
+       case LCON:
+               *cp = (union tree *)Tblock(sizeof(struct lnode));
+               (*cp)->l.op = LCON;
+               (*cp)->l.type = LONG;
+               (*cp)->l.lvalue = lcval;
+               cp++;
+               goto tand;
+
+       case CON:
+               *cp++ = cblock(cval);
+               goto tand;
+
+       /* fake a static char array */
+       case STRING:
+/*
+ * This hack is to compensate for a bit of simplemindedness I'm not sure how
+ * else to fix.  
+ *
+ *     i = sizeof ("foobar");
+ *
+ * or
+ *     i = sizeof "foobar";
+ *
+ * would generate ".byte 'f,'o','o,'b,'a,'r,0" into the data segment!
+ *
+ * What I did here was to scan to "operator" stack looking for left parens
+ * "(" preceeded by a "sizeof".  If both are seen and in that order or only
+ * a SIZEOF is sedn then the string is inside a 'sizeof' and should not 
+ * generate any data to the object file.
+*/
+               xop = op;
+               while   (xop > opst)
+                       {
+                       xo = *xop--;
+                       if      (xo != LPARN)
+                               break;
+                       }
+               if      (xo == SIZEOF)
+                       cntstr();
+               else
+                       putstr(cval, 0);
+               cs = (struct nmlist *)Tblock(sizeof(struct nmlist));
+               cs->hclass = STATIC;
+               cs->hoffset = cval;
+               *cp++ = block(NAME, unscflg? ARRAY+UNCHAR:ARRAY+CHAR, &nchstr,
+                 (union str *)NULL, (union tree *)cs, TNULL);
+
+       tand:
+               if(cp>=cmst+CMSIZ) {
+                       error("Expression overflow");
+                       exit(1);
+               }
+               if (andflg)
+                       goto syntax;
+               andflg = 1;
+               goto advanc;
+
+       case KEYW:
+       atype:
+               if (*op != LPARN || andflg)
+                       goto syntax;
+               peeksym = o;
+               *cp++ = xprtype();
+               if ((o=symbol()) != RPARN)
+                       goto syntax;
+               o = CAST;
+               --op;
+               --pp;
+               if (*op == SIZEOF) {
+                       andflg = 1;
+                       *pp = 100;
+                       goto advanc;
+               }
+               goto oponst;
+
+       case INCBEF:
+       case DECBEF:
+               if (andflg)
+                       o += 2;
+               goto oponst;
+
+       case COMPL:
+       case EXCLA:
+       case SIZEOF:
+               if (andflg)
+                       goto syntax;
+               goto oponst;
+
+       case MINUS:
+               if (!andflg)
+                       o = NEG;
+               andflg = 0;
+               goto oponst;
+
+       case AND:
+       case TIMES:
+               if (andflg)
+                       andflg = 0;
+               else if (o==AND)
+                       o = AMPER;
+               else
+                       o = STAR;
+               goto oponst;
+
+       case LPARN:
+               if (andflg) {
+                       o = symbol();
+                       if (o==RPARN)
+                               o = MCALL;
+                       else {
+                               peeksym = o;
+                               o = CALL;
+                               andflg = 0;
+                       }
+               }
+               goto oponst;
+
+       case RBRACK:
+       case RPARN:
+               if (!andflg)
+                       goto syntax;
+               goto oponst;
+
+       case DOT:
+       case ARROW:
+               mosflg = FMOS;
+               break;
+
+       case ASSIGN:
+               if (andflg==0 && PLUS<=*op && *op<=EXOR) {
+                       o = *op-- + ASPLUS - PLUS;
+                       pp--;
+                       goto oponst;
+               }
+               break;
+
+       }
+       /* binaries */
+       if (andflg==0)
+               goto syntax;
+       andflg = 0;
+
+oponst:
+       p = (opdope[o]>>9) & 037;
+opon1:
+       if (o==COLON && op[0]==COLON && op[-1]==QUEST) {
+               build(*op--);
+               build(*op--);
+               pp -= 2;
+       }
+       ps = *pp;
+       if (p>ps || p==ps && (opdope[o]&RASSOC)!=0) {
+               switch (o) {
+
+               case INCAFT:
+               case DECAFT:
+                       p = 37;
+                       break;
+               case LPARN:
+               case LBRACK:
+               case CALL:
+                       p = 04;
+               }
+               if (initflg) {
+                       if ((o==COMMA && *op!=LPARN && *op!=CALL)
+                        || (o==COLON && *op!=QUEST)) {
+                               p = 00;
+                               goto opon1;
+                       }
+               }
+               if (op >= &opst[SSIZE-1]) {
+                       error("expression overflow");
+                       exit(1);
+               }
+               *++op = o;
+               *++pp = p;
+               goto advanc;
+       }
+       --pp;
+       os = *op--;
+       if (andflg==0 && p>5 && ((opdope[o]&BINARY)==0 || o>=INCBEF&&o<=DECAFT) && opdope[os]&BINARY)
+               goto syntax;
+       switch (os) {
+
+       case SEOF:
+               peeksym = o;
+               build(0);               /* flush conversions */
+               if (eflag)
+                       endtree(svtree);
+               return(*--cp);
+
+       case COMMA:
+               if (*op != CALL)
+                       os = SEQNC;
+               break;
+
+       case CALL:
+               if (o!=RPARN)
+                       goto syntax;
+               build(os);
+               goto advanc;
+
+       case MCALL:
+               *cp++ = block(NULLOP, INT, (int *)NULL,
+                 (union str *)NULL, TNULL, TNULL);
+               os = CALL;
+               break;
+
+       case INCBEF:
+       case INCAFT:
+       case DECBEF:
+       case DECAFT:
+               *cp++ = cblock(1);
+               break;
+
+       case LPARN:
+               if (o!=RPARN)
+                       goto syntax;
+               goto advanc;
+
+       case LBRACK:
+               if (o!=RBRACK)
+                       goto syntax;
+               build(LBRACK);
+               goto advanc;
+       }
+       build(os);
+       goto opon1;
+
+syntax:
+       error("Expression syntax");
+       errflush(o);
+       if (eflag)
+               endtree(svtree);
+       return((union tree *) &garbage);
+}
+
+union tree *xprtype() {
+       struct nmlist typer, absname;
+       int sc;
+       register union tree **scp;
+
+       scp = cp;
+       sc = DEFXTRN;           /* will cause error if class mentioned */
+       getkeywords(&sc, &typer);
+       absname.hclass = 0;
+       absname.hblklev = blklev;
+       absname.hsubsp = NULL;
+       absname.hstrp = NULL;
+       absname.htype = 0;
+       decl1(sc, &typer, 0, &absname);
+       cp = scp;
+       return(block(ETYPE, absname.htype, absname.hsubsp,
+          absname.hstrp, TNULL, TNULL));
+}
+
+char *copnum(len) int len; {
+       register char *s1;
+
+       s1 = Tblock((len+LNCPW-1) & ~(LNCPW-1));
+       strcpy(s1, numbuf);
+       return(s1);
+}
diff --git a/c01.c b/c01.c
new file mode 100644 (file)
index 0000000..6c01650
--- /dev/null
+++ b/c01.c
@@ -0,0 +1,954 @@
+/*
+ * C compiler
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#define _va_start(ap, arg) va_start(ap, arg)
+#else
+#include <varargs.h>
+#define _va_start(ap, arg) va_start(ap)
+#endif
+#include "c0.h"
+
+/*
+ * Called from tree, this routine takes the top 1, 2, or 3
+ * operands on the expression stack, makes a new node with
+ * the operator op, and puts it on the stack.
+ * Essentially all the work is in inserting
+ * appropriate conversions.
+ */
+void build(op) int op; {
+       register int t1;
+       int t2, t;
+       register union tree *p1, *p2, *p3;
+       int dope, leftc, cvn, pcvn;
+
+       /*
+        * a[i] => *(a+i)
+        */
+       if (op==LBRACK) {
+               build(PLUS);
+               op = STAR;
+       }
+       dope = opdope[op];
+       t2 = INT;
+       if ((dope&BINARY)!=0) {
+               p2 = chkfun(disarray(*--cp));
+               if (p2)
+                       t2 = p2->t.type;
+       }
+       p1 = *--cp;
+       /*
+        * sizeof gets turned into a number here.
+        */
+       if (op==SIZEOF) {
+               p1 = cblock(length(p1));
+               p1->c.type = UNSIGN;
+               *cp++ = p1;
+               return;
+       }
+       if (op!=AMPER) {
+               p1 = disarray(p1);
+               if (op!=CALL)
+                       p1 = chkfun(p1);
+       }
+       t1 = p1->t.type;
+       if (t1==CHAR)
+               t1 = INT;
+       else if (t1==UNCHAR)
+               t1 = UNSIGN;
+       if (t2==CHAR)
+               t2 = INT;
+       else if (t2==UNCHAR)
+               t2 = UNSIGN;
+       pcvn = 0;
+       t = INT;
+       switch (op) {
+
+       case CAST:
+               if ((t1&XTYPE)==FUNC || (t1&XTYPE)==ARRAY)
+                       error("Disallowed conversion");
+               if (p1->t.type==UNCHAR) {
+                       *cp++ = block(ETYPE, UNSIGN, (int *)NULL, (union str *)NULL,
+                          TNULL, TNULL);
+                       *cp++ = p2;
+                       build(CAST);
+                       *cp++ = cblock(0377);
+                       build(AND);
+                       return;
+               }
+               if (p2->t.type==CHAR || p2->t.type==UNCHAR)
+                       p2 = block(PLUS, t2, (int *)NULL, (union str *)NULL,
+                          p2, cblock(0));
+               break;
+
+       /* end of expression */
+       case 0:
+               *cp++ = p1;
+               return;
+
+       /* no-conversion operators */
+       case QUEST:
+               if (p2->t.op!=COLON)
+                       error("Illegal conditional");
+               else
+                       if (fold(QUEST, p1, p2))
+                               return;
+
+       /*
+        * Bug fix, because copying type is not enough,
+        * i.e. t = (t, t) + 1;
+        * Original code was:
+        *      case SEQNC:
+        *              t = t2;
+        *      case COMMA:
+        */
+       case SEQNC:
+               *cp++ = block(op, t2, p2->t.subsp, p2->t.strp, p1, p2);
+               return;
+
+       case COMMA:
+       case LOGAND:
+       case LOGOR:
+               *cp++ = block(op, t, p2->t.subsp, p2->t.strp, p1, p2);
+               return;
+
+       case EXCLA:
+               t1 = INT;
+               break;
+
+       case CALL:
+               if ((t1&XTYPE) == PTR && (decref(t1)&XTYPE) == FUNC) {
+                       /*
+                        * Modification to allow calling a function via a
+                        * pointer to a function ("f") without explicitly
+                        * dereferencing the pointer.  That is: f(...) is now
+                        * legal as well as (*f)(...).  The insistence that
+                        * decref(t1) be FUNC prevents pointers to pointers to
+                        * functions and so on from being automatically
+                        * dereferenced which would be incorrect and introduce
+                        * porting problems.  Note that for purity FUNC's
+                        * should really always be referenced (as in pcc) and
+                        * that the new notation is actually more consistent
+                        * with the rest of C ...
+                        */
+                       *cp++ = p1;
+                       build(STAR);
+                       *cp++ = p2;
+                       build(CALL);
+                       return;
+               }
+               if ((t1&XTYPE) != FUNC)
+                       error("Call of non-function");
+               *cp++ = block(CALL,decref(t1),p1->t.subsp,p1->t.strp,p1,p2);
+               return;
+
+       case STAR:
+               if ((t1&XTYPE) == FUNC)
+                       error("Illegal indirection");
+               *cp++ = block(STAR, decref(t1), p1->t.subsp, p1->t.strp, p1, TNULL);
+               return;
+
+       case AMPER:
+               if (p1->t.op==NAME || p1->t.op==STAR) {
+                       *cp++ = block(op,incref(p1->t.type),p1->t.subsp,p1->t.strp,p1,TNULL);
+                       return;
+               }
+               error("Illegal lvalue");
+               break;
+
+       /*
+        * a.b goes to (&a)->b
+        */
+       case DOT:
+               if (p1->t.op==CALL && t1==STRUCT) {
+                       t1 = incref(t1);
+                       setype(p1, t1, p1);
+               } else {
+                       *cp++ = p1;
+                       build(AMPER);
+                       p1 = *--cp;
+               }
+
+       /*
+        * In a->b, a is given the type ptr-to-structure element;
+        * then the offset is added in without conversion;
+        * then * is tacked on to access the member.
+        */
+       case ARROW:
+               if (p2->t.op!=NAME || p2->t.tr1->n.hclass!=MOS) {
+                       error("Illegal structure ref");
+                       *cp++ = p1;
+                       return;
+               }
+               p2 = structident(p1, p2);
+               t2 = p2->n.htype;
+               if (t2==INT && p2->t.tr1->n.hflag&FFIELD)
+                       t2 = UNSIGN;
+               t = incref(t2);
+               chkw(p1, -1);
+               setype(p1, t, p2);
+               *cp++ = block(PLUS, t, p2->t.subsp, p2->t.strp,
+                  p1, cblock(p2->t.tr1->n.hoffset));
+               build(STAR);
+               if (p2->t.tr1->n.hflag&FFIELD)
+#if 1
+                       cp[-1] = block(FSEL, UNSIGN, (int *)NULL, (union str *)NULL, 
+                           cp[-1], (union tree *)p2->t.tr1->n.hstrp);
+#else
+                       *cp++ = block(FSEL, UNSIGN, (int *)NULL, (union str *)NULL, 
+                           *--cp, (union tree *)p2->t.tr1->n.hstrp);
+#endif
+               return;
+       }
+       if ((dope&LVALUE)!=0)
+               chklval(p1);
+       if ((dope&LWORD)!=0)
+               chkw(p1, LONG);
+       if ((dope&RWORD)!=0)
+               chkw(p2, LONG);
+       if ((t1==VOID && op!=CAST) || (t2==VOID && (op!=CAST || t1!=VOID))) {
+               error("Illegal use of void object");
+               t = t1 = t2 = INT;
+       }
+       if ((dope&BINARY)==0) {
+               if (op==ITOF)
+                       t1 = DOUBLE;
+               else if (op==FTOI)
+                       t1 = INT;
+               if (!fold(op, p1, (union tree *)NULL))
+                       *cp++ = block(op, t1, p1->t.subsp, p1->t.strp, p1,TNULL);
+               return;
+       }
+       cvn = 0;
+       if (t1==STRUCT || t2==STRUCT) {
+               if (t1!=t2 || p1->t.strp != p2->t.strp)
+                       error("Incompatible structures");
+               cvn = 0;
+       } else
+               cvn = cvtab[lintyp(t1)][lintyp(t2)];
+       leftc = (cvn>>4)&017;
+       cvn &= 017;
+       t = leftc? t2:t1;
+       if ((t==INT||t==CHAR) && (t1==UNSIGN||t2==UNSIGN))
+               t = UNSIGN;
+       if (dope&ASSGOP || op==CAST) {
+               /*
+                * Weird "lhs op= rhs" requiring a temporary to evaluate as
+                * "lhs = lhs op rhs" so lhs can be converted up for the
+                * operation and then the result converted back down for
+                * the assignment.  As a special sub case, "(int) op= (long)"
+                * doesn't require a temporary except for /= and %= ...
+                */
+               if (leftc && op>=ASPLUS && op<=ASXOR
+                   && (leftc!=LTI || op==ASDIV || op==ASMOD)) {
+                       assignop(op, p1, p2);
+                       return;
+               }
+               t = t1;
+               if (op==ASSIGN) {
+                       if (cvn==PTI) {
+                               if (t1!=t2 || ((t1&TYPE)==STRUCT && p1->t.strp!=p2->t.strp))
+                                       werror("mixed pointer assignment");
+                               cvn = leftc = 0;
+                       } if ((cvn==ITP || cvn==LTP)
+                          && (p2->t.op!=CON || p2->c.value!=0)
+                          && (p2->t.op!=LCON || p2->l.lvalue!=0)) {
+                       /*
+                        * Allow "i = p" and "p = i" with a warning, where
+                        * i is some form of integer (not 0) and p is a
+                        * pointer.  Note that in both this patch and the
+                        * similar one for "?:" below, code from the CAST
+                        * immediately below and the illegal conversion
+                        * check farther below is simply stolen.  It would
+                        * require either a recursive call to build or a
+                        * fairly large rewrite to eliminate the
+                        * duplication.
+                        */
+                               werror("illegal combination of pointer and integer, op =");
+                               if (cvn==ITP)
+                                       cvn = leftc = 0;
+                               else
+                                       if (leftc==0)
+                                               cvn = LTI;
+                                       else {
+                                               cvn = ITL;
+                                               leftc = 0;
+                                       }
+                       }
+               } else if (op==CAST) {
+                       if (cvn==ITP||cvn==PTI)
+                               cvn = leftc = 0;
+                       else if (cvn==LTP) {
+                               if (leftc==0)
+                                       cvn = LTI;
+                               else {
+                                       cvn = ITL;
+                                       leftc = 0;
+                               }
+                       }
+               }
+               if (leftc)
+                       cvn = leftc;
+               leftc = 0;
+       } else if (op==COLON || op==MAX || op==MIN) {
+               if (t1>=PTR && t1==t2)
+                       cvn = 0;
+               if (op!=COLON && (t1>=PTR || t2>=PTR))
+                       op += MAXP-MAX;
+               /*
+                * Allow "e ? i : p" and "e ? p : i" with warning.
+                */
+               if (op==COLON && (cvn==ITP || cvn==LTP)) {
+                       p3 = leftc? p1: p2;
+                       if ((p3->t.op!=CON || p3->c.value!=0)
+                        && (p3->t.op!=LCON || p3->l.lvalue!=0)) {
+                               werror("illegal combination of pointer and integer, op :");
+                               if (cvn==ITP)
+                                       cvn = leftc = 0;
+                               else
+                                       if (leftc==0)
+                                               cvn = LTI;
+                                       else {
+                                               cvn = ITL;
+                                               leftc = 0;
+                                       }
+                       }
+               }
+       } else if (dope&RELAT) {
+               if (op>=LESSEQ && (t1>=PTR||t2>=PTR||(t1==UNSIGN||t1==UNLONG||t2==UNSIGN||t2==UNLONG)
+                && (t==INT||t==CHAR||t==UNSIGN||t==UNLONG)))
+                       op += LESSEQP-LESSEQ;
+               if (cvn==ITP || cvn==PTI)
+                       cvn = 0;
+       }
+       if (cvn==PTI) {
+               cvn = 0;
+               if (op==MINUS) {
+                       pcvn++;
+                       p1 = block(ITOL, LONG, (int *)NULL, (union str *)NULL, p1, TNULL);
+                       p2 = block(ITOL, LONG, (int *)NULL, (union str *)NULL, p2, TNULL);
+                       t = LONG;
+               } else {
+                       if (t1!=t2 || (t1!=(PTR+CHAR) && t1!=(PTR+UNCHAR)))
+                               cvn = XX;
+               }
+       }
+       if (cvn) {
+               if ((cvn==ITP || cvn==LTP) && (opdope[op]&PCVOK)==0) {
+                       p3 = leftc? p1: p2;
+                       if ((p3->t.op!=CON || p3->c.value!=0)
+                        && (p3->t.op!=LCON || p3->l.lvalue!=0))
+                               cvn = XX;
+                       else
+                               cvn = 0;
+               }
+               t1 = plength(p1);
+               t2 = plength(p2);
+               if (cvn==XX || (cvn==PTI&&t1!=t2))
+                       error("Illegal conversion");
+               else if (leftc)
+                       p1 = convert(p1, t, cvn, t2);
+               else
+                       p2 = convert(p2, t, cvn, t1);
+       }
+       if (dope&RELAT)
+               t = INT;
+       if (t==FLOAT)
+               t = DOUBLE;
+       if (t==CHAR)
+               t = INT;
+       if (op==CAST) {
+               /* could the below be an oversight? gcc notes rhs always true */
+               if (t!=DOUBLE /*&& (t!=INT || p2->t.type!=CHAR || p2->t.type!=UNCHAR)*/) {
+                       p2->t.type = t;
+                       p2->t.subsp = p1->t.subsp;
+                       p2->t.strp = p1->t.strp;
+               }
+               if (t==INT && p1->t.type==CHAR)
+                       p2 = block(ITOC, INT, (int *)NULL, (union str *)NULL, p2, TNULL);
+               *cp++ = p2;
+               return;
+       }
+       if (pcvn)
+               t2 = plength(p1->t.tr1);
+       if (fold(op, p1, p2)==0) {
+               p3 = leftc?p2:p1;
+               *cp++ = block(op, t, p3->t.subsp, p3->t.strp, p1, p2);
+       }
+       if (pcvn) {
+               p1 = *--cp;
+               *cp++ = convert(p1, 0, PTI, t2);
+       }
+}
+
+union tree *structident(p1, p2) register union tree *p1; register union tree *p2; {
+       register struct nmlist *np;
+       int vartypes = 0, namesame = 1;
+
+       np = (struct nmlist *)p2->t.tr1;
+       for (;;) {
+               if (namesame && p1->t.type==STRUCT+PTR && p1->t.strp == np->sparent) {
+                       p2->t.type = np->htype;
+                       p2->t.strp = np->hstrp;
+                       p2->t.subsp = np->hsubsp;
+                       p2->t.tr1 = (union tree *)np;
+                       return(p2);
+               }
+               np = np->nextnm;
+               if (np==NULL)
+                       break;
+               namesame = 0;
+               if (strcmp(p2->t.tr1->n.name, np->name) != 0)
+                       continue;
+               if ((p2->t.tr1->n.hflag&FKIND) != (np->hflag&FMOS))
+                       continue;
+               namesame = 1;
+               if (p2->t.tr1->n.htype==np->htype && p2->t.tr1->n.hoffset==np->hoffset)
+                       continue;
+               vartypes++;
+       }
+       if (vartypes)
+               error("Ambiguous structure reference for %s",p2->t.tr1->n.name);
+       else
+               werror("%s not member of cited struct/union",p2->t.tr1->n.name);
+       return(p2);
+}
+
+/*
+ * Generate the appropriate conversion operator.
+ */
+union tree *convert(p, t, cvn, len) union tree *p; int t; int cvn; int len; {
+       register int op;
+
+       if (cvn==0)
+               return(p);
+       op = cvntab[cvn];
+       if (opdope[op]&BINARY) {
+               if (len==0)
+                       error("Illegal conversion");
+               return(block(op, t, (int *)NULL, (union str *)NULL, p, cblock(len)));
+       }
+       return(block(op, t, (int *)NULL, (union str *)NULL, p, TNULL));
+}
+
+/*
+ * Traverse an expression tree, adjust things
+ * so the types of things in it are consistent
+ * with the view that its top node has
+ * type at.
+ * Used with structure references.
+ */
+void setype(p, t, newp) register union tree *p; register int t; register union tree *newp; {
+       for (;; p = p->t.tr1) {
+               p->t.subsp = newp->t.subsp;
+               p->t.strp = newp->t.strp;
+               p->t.type = t;
+               if (p->t.op==AMPER)
+                       t = decref(t);
+               else if (p->t.op==STAR)
+                       t = incref(t);
+               else if (p->t.op!=PLUS)
+                       break;
+       }
+}
+
+/*
+ * A mention of a function name is turned into
+ * a pointer to that function.
+ */
+union tree *chkfun(p) register union tree *p; {
+       register int t;
+
+       if (((t = p->t.type)&XTYPE)==FUNC && p->t.op!=ETYPE)
+               return(block(AMPER,incref(t),p->t.subsp,p->t.strp,p,TNULL));
+       return(p);
+}
+
+/*
+ * A mention of an array is turned into
+ * a pointer to the base of the array.
+ */
+union tree *disarray(p) register union tree *p; {
+       register int t;
+
+       if (p==NULL)
+               return(p);
+       /* check array & not MOS and not typer */
+       if (((t = p->t.type)&XTYPE)!=ARRAY
+        || p->t.op==NAME && p->t.tr1->n.hclass==MOS
+        || p->t.op==ETYPE)
+               return(p);
+       p->t.subsp++;
+       *cp++ = p;
+       setype(p, decref(t), p);
+       build(AMPER);
+       return(*--cp);
+}
+
+/*
+ * make sure that p is a ptr to a node
+ * with type int or char or 'okt.'
+ * okt might be nonexistent or 'long'
+ * (e.g. for <<).
+ */
+void chkw(p, okt) union tree *p; int okt; {
+       register int t = p->t.type;
+
+       if (t == UNLONG)
+               t = LONG;
+       if (t!=INT && t<PTR && t!=CHAR && t!=UNCHAR && t!=UNSIGN && t!=okt)
+               error("Illegal type of operand");
+       return;
+}
+
+/*
+ *'linearize' a type for looking up in the
+ * conversion table
+ */
+int lintyp(t) int t; {
+       switch(t) {
+
+       case INT:
+       case CHAR:
+       case UNSIGN:
+       case UNCHAR:
+               return(0);
+
+       case FLOAT:
+       case DOUBLE:
+               return(1);
+
+       case UNLONG:
+       case LONG:
+               return(2);
+
+       default:
+               return(3);
+       }
+}
+
+/*
+ * Report an error.
+ */
+
+extern int Wflag;      /* Non-zero means do not print warnings */
+
+#ifdef __STDC__
+void werror(char *s, ...)
+#else
+void werror(s, va_alist) char *s; va_dcl
+#endif
+{
+       va_list ap;
+
+       if (Wflag)
+               return;
+       if (filename[0])
+               fprintf(stderr, "%s:", filename);
+       fprintf(stderr, "%d: warning: ", line);
+       _va_start(ap, s);
+       vfprintf(stderr, s, ap);
+       va_end(ap);
+       fprintf(stderr, "\n");
+}
+
+#ifdef __STDC__
+void error(char *s, ...)
+#else
+void error(s, va_alist) char *s; va_dcl
+#endif
+{
+       va_list ap;
+
+       nerror++;
+       if (filename[0])
+               fprintf(stderr, "%s:", filename);
+       fprintf(stderr, "%d: ", line);
+       _va_start(ap, s);
+       vfprintf(stderr, s, ap);
+       va_end(ap);
+       fprintf(stderr, "\n");
+}
+
+/*
+ * Generate a node in an expression tree,
+ * setting the operator, type, dimen/struct table ptrs,
+ * and the operands.
+ */
+union tree *block(op, t, subs, str, p1,p2) int op; int t; int *subs; union str *str; union tree *p1; union tree *p2; {
+       register union tree *p;
+
+ /*fprintf(stderr, "block(%d, %d, {%d, %d}, {%d, %d})\n", op, t,
+   (op == NAME) ? -2 : (p1 ? (int)(_INT)p1->t.op : -1),
+   (op == NAME) ? -2 : (p1 ? (int)(_INT)p1->t.type : -1),
+   (op == FSEL) ? -3 : (p2 ? (int)(_INT)p2->t.op : -1),
+   (op == FSEL) ? -3 : (p2 ? (int)(_INT)p2->t.type : -1));*/
+       p = (union tree *)Tblock(sizeof(struct tnode));
+       p->t.op = op;
+       p->t.type = t;
+       p->t.subsp = subs;
+       p->t.strp = str;
+       p->t.tr1 = p1;
+       if (opdope[op]&BINARY)
+               p->t.tr2 = p2;
+       else
+               p->t.tr2 = NULL;
+       return(p);
+}
+
+union tree *nblock(ds) register struct nmlist *ds; {
+       return(block(NAME, ds->htype, ds->hsubsp, ds->hstrp, (union tree *)ds, TNULL));
+}
+
+/*
+ * Generate a block for a constant
+ */
+union tree *cblock(v) int v; {
+       register union tree *p;
+
+ /*fprintf(stderr, "cblock(0%06o)\n", v & 0177777);*/
+       p = (union tree *)Tblock(sizeof(struct cnode));
+       p->c.op = CON;
+       p->c.type = INT;
+       p->c.subsp = NULL;
+       p->c.strp = NULL;
+       p->c.value = v;
+       return(p);
+}
+
+/*
+ * A block for a float constant
+ */
+union tree *fblock(t, string) int t; char *string; {
+       register union tree *p;
+
+ /*fprintf(stderr, "fblock(%d, \"%s\")\n", t, string);*/
+       p = (union tree *)Tblock(sizeof(struct fnode));
+       p->f.op = FCON;
+       p->f.type = t;
+       p->f.subsp = NULL;
+       p->f.strp = NULL;
+       p->f.cstr = string;
+       return(p);
+}
+
+/*
+ * Assign a block for use in the
+ * expression tree.
+ */
+char *Tblock(n) int n; {
+       register char *p;
+
+ /*fprintf(stderr, "treebase=%p n=%p coremax=%p\n", treebase, n, coremax);*/
+       p = treebase;
+       if (p==NULL) {
+               error("c0 internal error: Tblock");
+               exit(1);
+       }
+       if ((treebase += n) >= coremax) {
+#ifdef pdp11
+               if (sbrk(1024) == (char *)-1) {
+#else
+ /*fprintf(stderr, "sbrk\n");*/
+               if (sbrk(1024) != coremax) {
+#endif
+                       error("Out of space");
+                       exit(1);
+               }
+               coremax += 1024;
+       }
+       return(p);
+}
+
+char *starttree() {
+       register char *st;
+
+ /*fprintf(stderr, "starttree() locbase=%p coremax=%p\n", locbase, coremax);*/
+       st = treebase;
+       if (st==NULL)
+               treebot = treebase = locbase+DCLSLOP;
+ /*fprintf(stderr, "starttree() treebase=%p treebot=%p\n", treebase, treebot);*/
+       return(st);
+}
+
+void endtree(tp) char *tp; {
+       treebase = tp;
+       if (tp==NULL)
+               treebot = NULL;
+ /*fprintf(stderr, "endtree() treebase=%p treebot=%p\n", treebase, treebot);*/
+}
+
+/*
+ * Assign a block for use in a declaration
+ */
+char *Dblock(n) int n; {
+       register char *p;
+
+ /*fprintf(stderr, "locbase=%p n=%d treebot=%p coremax=%p\n", locbase, n, treebot, coremax);*/
+       p = locbase;
+       locbase += n;
+       if (treebot && locbase > treebot) {
+               error("Too much declaring in an expression");
+               exit(1);
+       }
+       if (locbase > coremax) {
+#ifdef pdp11
+               if (sbrk(1024) == (char *)-1) {
+#else
+ /*fprintf(stderr, "sbrk\n");*/
+               if (sbrk(1024) != coremax) {
+#endif
+                       error("out of space");
+                       exit(1);
+               }
+               coremax += 1024;
+       }
+       return(p);
+}
+
+/*
+ * Check that a tree can be used as an lvalue.
+ */
+void chklval(p) register union tree *p; {
+       if (p->t.op==FSEL)
+               p = p->t.tr1;
+       if (p->t.op!=NAME && p->t.op!=STAR)
+               error("Lvalue required");
+}
+
+/*
+ * reduce some forms of `constant op constant'
+ * to a constant.  More of this is done in the next pass
+ * but this is used to allow constant expressions
+ * to be used in switches and array bounds.
+ */
+int fold(op, p1, p2) int op; register union tree *p1; union tree *p2; {
+       register int v1, v2;
+       int unsignf;
+
+       if (p1->t.op!=CON)
+               return(0);
+       unsignf = p1->c.type==UNSIGN;
+       unsignf |= p1->c.type==UNLONG;
+       if (op==QUEST) {
+               if (p2->t.tr1->t.op==CON && p2->t.tr2->t.op==CON) {
+                       p1->c.value = p1->c.value? p2->t.tr1->c.value: p2->t.tr2->c.value;
+                       *cp++ = p1;
+                       p1->t.type = p2->t.type;
+                       return(1);
+               }
+               return(0);
+       }
+       if (p2) {
+               if (p2->t.op!=CON)
+                       return(0);
+               v2 = p2->c.value;
+               unsignf |= p2->c.type==UNSIGN;
+               unsignf |= p2->c.type==UNLONG;
+       }
+       v1 = p1->c.value;
+       switch (op) {
+
+       case PLUS:
+               v1 += v2;
+               break;
+
+       case MINUS:
+               v1 -= v2;
+               break;
+
+       case TIMES:
+               v1 *= v2;
+               break;
+
+       case DIVIDE:
+               if (v2==0)
+                       goto divchk;
+               if (unsignf) {
+                       if (v2==1)
+                               break;
+                       if (v2<0) {
+                               v1 = (_UNSIGNED_INT)v1 >= (_UNSIGNED_INT)v2;
+                               break;
+                       }
+                       v1 = (_UNSIGNED_INT)v1 / v2;
+                       break;
+               }
+               v1 /= v2;
+               break;
+
+       case MOD:
+               if (v2==0)
+                       goto divchk;
+               if (unsignf) {
+                       if (v2==1) {
+                               v1 = 0;
+                               break;
+                       }
+                       if (v2<0) {
+                               if ((_UNSIGNED_INT)v1 >= (_UNSIGNED_INT)v2)
+                                       v1 -= v2;
+                               break;
+                       }
+                       v1 = (_UNSIGNED_INT)v1 % v2;
+                       break;
+               }
+               v1 %= v2;
+               break;
+
+       case AND:
+               v1 &= v2;
+               break;
+
+       case OR:
+               v1 |= v2;
+               break;
+
+       case EXOR:
+               v1 ^= v2;
+               break;
+
+       case NEG:
+               v1 = - v1;
+               break;
+
+       case COMPL:
+               v1 = ~ v1;
+               break;
+
+       case LSHIFT:
+               v1 <<= v2;
+               break;
+
+       case RSHIFT:
+               if (unsignf) {
+                       v1 = (_UNSIGNED_INT)v1 >> v2;
+                       break;
+               }
+               v1 >>= v2;
+               break;
+
+       case EQUAL:
+               v1 = v1==v2;
+               break;
+
+       case NEQUAL:
+               v1 = v1!=v2;
+               break;
+
+       case LESS:
+               v1 = v1<v2;
+               break;
+
+       case GREAT:
+               v1 = v1>v2;
+               break;
+
+       case LESSEQ:
+               v1 = v1<=v2;
+               break;
+
+       case GREATEQ:
+               v1 = v1>=v2;
+               break;
+
+       case LESSP:
+               v1 = (_UNSIGNED_INT)v1<v2;
+               break;
+
+       case GREATP:
+               v1 = (_UNSIGNED_INT)v1>v2;
+               break;
+
+       case LESSEQP:
+               v1 = (_UNSIGNED_INT)v1<=v2;
+               break;
+
+       case GREATQP:
+               v1 = (_UNSIGNED_INT)v1>=v2;
+               break;
+
+       divchk:
+               error("Divide check");
+               nerror--;
+       default:
+               return(0);
+       }
+       p1->c.value = v1;
+       *cp++ = p1;
+       if (unsignf)
+               p1->t.type = UNSIGN;
+       return(1);
+}
+
+/*
+ * Compile an expression expected to have constant value,
+ * for example an array bound or a case value.
+ */
+int conexp() {
+       register union tree *t;
+
+       initflg++;
+       if (t = tree(1))
+               if (t->t.op != CON)
+                       error("Constant required");
+       initflg--;
+ /*fprintf(stderr, "conexp() %d\n", t->c.value);*/
+       return(t->c.value);
+}
+
+/*
+ * Handle peculiar assignment ops that need a temporary.
+ */
+void assignop(op, p1, p2) int op; register union tree *p1; register union tree *p2; {
+       register struct nmlist *np;
+
+       op += PLUS - ASPLUS;
+       if (p1->t.op==NAME) {
+               *cp++ = p1;
+               *cp++ = p1;
+               *cp++ = p2;
+               build(op);
+               build(ASSIGN);
+               return;
+       }
+       np = gentemp(incref(p1->t.type));
+       *cp++ = nblock(np);
+       *cp++ = p1;
+       build(AMPER);
+       build(ASSIGN);
+       *cp++ = nblock(np);
+       build(STAR);
+       *cp++ = nblock(np);
+       build(STAR);
+       *cp++ = p2;
+       build(op);
+       build(ASSIGN);
+       build(SEQNC);
+}
+
+/*
+ * Generate an automatic temporary for
+ * use in certain assignment ops
+ */
+struct nmlist *gentemp(type) int type; {
+       register struct nmlist *tp;
+
+       tp = (struct nmlist *)Tblock(sizeof(struct nmlist));
+       tp->hclass = AUTO;
+       tp->htype = type;
+       tp->hflag = 0;
+       tp->hsubsp = NULL;
+       tp->hstrp = NULL;
+       tp->hblklev = blklev;
+       autolen -= rlength((union tree *)tp);
+       tp->hoffset = autolen;
+       if (autolen < maxauto)
+               maxauto = autolen;
+       return(tp);
+}
diff --git a/c02.c b/c02.c
new file mode 100644 (file)
index 0000000..d361fb4
--- /dev/null
+++ b/c02.c
@@ -0,0 +1,803 @@
+/*
+ * C compiler
+ */
+
+#include <string.h>
+#include "c0.h"
+
+/*
+ * Process a single external definition
+ */
+void extdef() {
+       register int o;
+       int sclass, scflag;
+       struct nmlist typer;
+       register struct nmlist *ds;
+
+       if(((o=symbol())==EOFC) || o==SEMI)
+               return;
+       peeksym = o;
+       sclass = 0;
+       blklev = 0;
+       if (getkeywords(&sclass, &typer)==0) {
+               sclass = EXTERN;
+               if (peeksym!=NAME)
+                       goto syntax;
+       }
+       scflag = 0;
+       if (sclass==DEFXTRN) {
+               scflag++;
+               sclass = EXTERN;
+       }
+       if (sclass!=EXTERN && sclass!=STATIC && sclass!=TYPEDEF)
+               error("Illegal storage class");
+       do {
+               defsym = 0;
+               paraml = NULL;
+               parame = NULL;
+               if (sclass==TYPEDEF) {
+                       decl1(TYPEDEF, &typer, 0, (struct nmlist *)NULL);
+                       continue;
+               }
+               decl1(EXTERN, &typer, 0, (struct nmlist *)NULL);
+               if ((ds=defsym)==0)
+                       return;
+               funcsym = ds;
+               if ((ds->htype&XTYPE)==FUNC) {
+                       if ((peeksym=symbol())==LBRACE || peeksym==KEYW
+                        || (peeksym==NAME && csym->hclass==TYPEDEF)) {
+                               funcblk.type = decref(ds->htype);
+                               funcblk.strp = ds->hstrp;
+                               setinit(ds);
+                               outcode("BS", SYMDEF, sclass==EXTERN?ds->name:"");
+                               cfunc();
+                               return;
+                       }
+                       if (paraml)
+                               error("Inappropriate parameters");
+               } else if ((o=symbol())==COMMA || o==SEMI) {
+                       peeksym = o;
+                       o = (length((union tree *)ds)+ALIGN) & ~ALIGN;
+                       if (sclass==STATIC) {
+                               setinit(ds);
+                               outcode("BSBBSBN", SYMDEF, "", BSS, NLABEL, ds->name, SSPACE, o);
+                       } else if (scflag)
+                               outcode("BSN", CSPACE, ds->name, o);
+               } else {
+                       if (o!=ASSIGN) {
+                               error("Declaration syntax");
+                               peeksym = o;
+                       }
+                       setinit(ds);
+                       if (sclass==EXTERN)
+                               outcode("BS", SYMDEF, ds->name);
+                       outcode("BBS", DATA, NLABEL, ds->name);
+                       if (cinit(ds, 1, sclass) & ALIGN)
+                               outcode("B", EVEN);
+               }
+       } while ((o=symbol())==COMMA);
+       if (o==SEMI)
+               return;
+syntax:
+       if (o==RBRACE) {
+               error("Too many }'s");
+               peeksym = 0;
+               return;
+       }
+       error("External definition syntax");
+       errflush(o);
+       statement();
+}
+
+/*
+ * Process a function definition.
+ */
+void cfunc() {
+       register char *cb;
+       register int sloc;
+
+       sloc = isn;
+       isn += 2;
+       outcode("BBS", PROG, RLABEL, funcsym->name);
+       regvar = 5;
+       autolen = STAUTO;
+       maxauto = STAUTO;
+       blklev = 1;
+       cb = locbase;
+       declist(ARG);
+       outcode("B", SAVE);
+       if (proflg)
+               outcode("BNS", PROFIL, isn++, funcsym->name);
+       funchead();
+       branch(sloc);
+       label(sloc+1);
+       retlab = isn++;
+       blklev = 0;
+       if ((peeksym = symbol()) != LBRACE)
+               error("Compound statement required");
+       statement();
+       outcode("BNB", LABEL, retlab, RETRN);
+       label(sloc);
+/* add STAUTO; overlay bug fix, coupled with section in c11.c */
+       outcode("BN", SETSTK, -maxauto+STAUTO);
+       branch(sloc+1);
+ /*fprintf(stderr, "cb=%p\n", cp);*/
+       locbase = cb;
+}
+
+/*
+ * Process the initializers for an external definition.
+ */
+int cinit(anp, flex, sclass) struct nmlist *anp; int flex; int sclass; {
+       struct nmlist np;
+       register int nel, ninit;
+       int width, isarray, o, brace, realtype;
+       union tree *s;
+
+       np = *anp;
+       realtype = np.htype;
+       isarray = 0;
+       if ((realtype&XTYPE) == ARRAY)
+               isarray++;
+       else
+               flex = 0;
+       width = length((union tree *)&np);
+       nel = 1;
+       /*
+        * If it's an array, find the number of elements.
+        * temporarily modify to look like kind of thing it's
+        * an array of.
+        */
+       if (sclass==AUTO)
+               if (isarray || realtype==STRUCT)
+                       error("No auto. aggregate initialization");
+       if (isarray) {
+               np.htype = decref(realtype);
+               np.hsubsp++;
+               if (width==0 && flex==0)
+                       error("0-length row: %s", anp->name);
+               o = length((union tree *)&np);
+               nel = (unsigned)width/o;
+               width = o;
+       }
+       brace = 0;
+       if ((peeksym=symbol())==LBRACE && (isarray || np.htype!=STRUCT)) {
+               peeksym = -1;
+               brace++;
+       }
+       ninit = 0;
+       do {
+               if ((o=symbol())==RBRACE)
+                       break;
+               peeksym = o;
+               if (o==STRING && (realtype==ARRAY+CHAR || realtype==ARRAY+UNCHAR)) {
+                       if (sclass==AUTO)
+                               error("No strings in automatic");
+                       peeksym = -1;
+                       putstr(0, flex?10000:nel);
+                       ninit += nchstr;
+                       o = symbol();
+                       break;
+               } else if (np.htype==STRUCT) {
+                       strinit(&np, sclass);
+               } else if ((np.htype&ARRAY)==ARRAY || peeksym==LBRACE)
+                       cinit(&np, 0, sclass);
+               else {
+                       char *st;
+                       initflg++;
+                       st = starttree();
+                       s = tree(0);
+                       initflg = 0;
+                       if (np.hflag&FFIELD)
+                               error("No field initialization");
+                       *cp++ = nblock(&np);
+                       *cp++ = s;
+                       build(ASSIGN);
+                       if (sclass==AUTO||sclass==REG)
+                               rcexpr(*--cp);
+                       else if (sclass==ENUMCON) {
+                               if (s->t.op!=CON)
+                                       error("Illegal enum constant for %s", anp->name);
+                               anp->hoffset = s->c.value;
+                       } else
+                               rcexpr(block(INIT,np.htype,(int *)NULL,
+                                 (union str *)NULL, (*--cp)->t.tr2, TNULL));
+                       endtree(st);
+               }
+               ninit++;
+               if ((ninit&077)==0 && sclass==EXTERN)
+                       outcode("BS", SYMDEF, "");
+       } while ((o=symbol())==COMMA && (ninit<nel || brace || flex));
+       if (brace==0 || o!=RBRACE)
+               peeksym = o;
+       /*
+        * If there are too few initializers, allocate
+        * more storage.
+        * If there are too many initializers, extend
+        * the declared size for benefit of "sizeof"
+        */
+       if (ninit<nel && sclass!=AUTO)
+               outcode("BN", SSPACE, (nel-ninit)*width);
+       else if (ninit>nel) {
+               if (flex && nel==0) {
+                       np.hsubsp[-1] = ninit;
+               } else
+                       error("Too many initializers: %s", anp->name);
+               nel = ninit;
+       }
+       return(nel*width);
+}
+
+/*
+ * Initialize a structure
+ */
+void strinit(np, sclass) struct nmlist *np; int sclass; {
+       static struct nmlist junk;
+       register struct nmlist **mlp;
+       static struct nmlist *zerloc = NULL;
+       register int o, brace;
+
+       if ((mlp = np->hstrp->S.memlist)==NULL) {
+               mlp = &zerloc;
+               error("Undefined structure initialization");
+       }
+       brace = 0;
+       if ((o = symbol()) == LBRACE)
+               brace++;
+       else
+               peeksym = o;
+       do {
+               if ((o=symbol()) == RBRACE)
+                       break;
+               peeksym = o;
+               if (*mlp==0) {
+                       error("Too many structure initializers");
+                       cinit(&junk, 0, sclass);
+               } else
+                       cinit(*mlp++, 0, sclass);
+               if (*mlp ==  &structhole) {
+                       outcode("B", EVEN);
+                       mlp++;
+               }
+                               /* DAG -- union initialization bug fix */
+               if (*mlp && mlp[-1]->hoffset == (*mlp)->hoffset) {
+                       werror("union initialization non-portable");
+                       while (*mlp)    /* will NOT be &structhole */
+                               mlp++;  /* skip other members of union */
+               }
+       } while ((o=symbol())==COMMA && (*mlp || brace));
+       if (sclass!=AUTO && sclass!=REG) {
+               if (*mlp)
+                       outcode("BN", SSPACE, np->hstrp->S.ssize - (*mlp)->hoffset);
+               outcode("B", EVEN);
+       }
+       if (o!=RBRACE || brace==0)
+               peeksym = o;
+}
+
+/*
+ * Mark already initialized
+ */
+void setinit(np) register struct nmlist *np; {
+
+       if (np->hflag&FINIT)
+               error("%s multiply defined", np->name);
+       np->hflag |= FINIT;
+}
+
+/*
+ * Process one statement in a function.
+ */
+void statement() {
+       register int o, o1;
+       int sauto, sreg;
+
+stmt:
+       switch(o=symbol()) {
+
+       case EOFC:
+               error("Unexpected EOF");
+       case SEMI:
+               return;
+
+       case LBRACE:
+               sauto = autolen;
+               sreg = regvar;
+               blockhead();
+               while (!eof) {
+                       if ((o=symbol())==RBRACE) {
+                               autolen = sauto;
+                               if (sreg!=regvar)
+                                       outcode("BN", SETREG, sreg);
+                               regvar = sreg;
+                               blkend();
+                               return;
+                       }
+                       peeksym = o;
+                       statement();
+               }
+               error("Missing '}'");
+               return;
+
+       case KEYW:
+               switch(cval) {
+
+               case GOTO:
+                       if (o1 = simplegoto())
+                               branch(o1);
+                       else 
+                               dogoto();
+                       goto semi;
+
+               case RETURN:
+                       doret();
+                       goto semi;
+
+               case ASM:
+               {
+                       char    tmp[80],        /* tmp for line buffer */
+                               *p;
+
+                       if (symbol() != LPARN || (o1 = symbol()) != STRING)
+                               goto syntax;
+                       for (p = tmp; (o1 = mapch('"')) >= 0; )
+                               *p++ = o1&0177;
+                       *p = '\0';
+                       if (symbol() != RPARN)
+                               goto syntax;
+                       outcode("BF", ASSEM, tmp);
+                       goto semi;
+               }
+
+               case IF: {
+                       register int o2;
+                       register union tree *np;
+
+                       np = pexpr(1);
+                       o2 = 0;
+                       if ((o1=symbol())==KEYW) switch (cval) {
+                       case GOTO:
+                               if (o2=simplegoto())
+                                       goto simpif;
+                               cbranch(np, o2=isn++, 0);
+                               dogoto();
+                               label(o2);
+                               goto hardif;
+
+                       case RETURN:
+                               if (nextchar()==';') {
+                                       o2 = retlab;
+                                       goto simpif;
+                               }
+                               cbranch(np, o1=isn++, 0);
+                               doret();
+                               label(o1);
+                               o2++;
+                               goto hardif;
+
+                       case BREAK:
+                               o2 = brklab;
+                               goto simpif;
+
+                       case CONTIN:
+                               o2 = contlab;
+                       simpif:
+                               chconbrk(o2);
+                               cbranch(np, o2, 1);
+                       hardif:
+                               if ((o=symbol())!=SEMI)
+                                       goto syntax;
+                               if ((o1=symbol())==KEYW && cval==ELSE) 
+                                       goto stmt;
+                               peeksym = o1;
+                               return;
+                       }
+                       peeksym = o1;
+                       cbranch(np, o1=isn++, 0);
+                       statement();
+                       if ((o=symbol())==KEYW && cval==ELSE) {
+                               o2 = isn++;
+                               branch(o2);
+                               label(o1);
+                               statement();
+                               label(o2);
+                               return;
+                       }
+                       peeksym = o;
+                       label(o1);
+                       return;
+               }
+
+               case WHILE: {
+                       register int o2;
+                       o1 = contlab;
+                       o2 = brklab;
+                       label(contlab = isn++);
+                       cbranch(pexpr(1), brklab=isn++, 0);
+                       statement();
+                       branch(contlab);
+                       label(brklab);
+                       contlab = o1;
+                       brklab = o2;
+                       return;
+               }
+
+               case BREAK:
+                       chconbrk(brklab);
+                       branch(brklab);
+                       goto semi;
+
+               case CONTIN:
+                       chconbrk(contlab);
+                       branch(contlab);
+                       goto semi;
+
+               case DO: {
+                       register int o2, o3;
+                       o1 = contlab;
+                       o2 = brklab;
+                       contlab = isn++;
+                       brklab = isn++;
+                       label(o3 = isn++);
+                       statement();
+                       label(contlab);
+                       contlab = o1;
+                       if ((o=symbol())==KEYW && cval==WHILE) {
+                               cbranch(tree(1), o3, 1);
+                               label(brklab);
+                               brklab = o2;
+                               goto semi;
+                       }
+                       goto syntax;
+               }
+
+               case CASE:
+                       o1 = conexp();
+                       if ((o=symbol())!=COLON)
+                               goto syntax;
+                       if (swp==0) {
+                               error("Case not in switch");
+                               goto stmt;
+                       }
+                       if(swp>=swtab+SWSIZ) {
+                               error("Switch table overflow");
+                       } else {
+                               swp->swlab = isn;
+                               (swp++)->swval = o1;
+                               label(isn++);
+                       }
+                       goto stmt;
+
+               case SWITCH: {
+                       register union tree *np;
+                       register char *st;
+
+                       o1 = brklab;
+                       brklab = isn++;
+                       st = starttree();
+                       np = pexpr(0);
+                       chkw(np, -1);
+                       rcexpr(block(RFORCE,0,(int *)NULL,(union str *)NULL,np,TNULL));
+                       endtree(st);
+                       pswitch();
+                       brklab = o1;
+                       return;
+               }
+
+               case DEFAULT:
+                       if (swp==0)
+                               error("Default not in switch");
+                       if (deflab)
+                               error("More than 1 'default'");
+                       if ((o=symbol())!=COLON)
+                               goto syntax;
+                       label(deflab = isn++);
+                       goto stmt;
+
+               case FOR: {
+                       register int o2;
+                       o1 = contlab;
+                       o2 = brklab;
+                       contlab = isn++;
+                       brklab = isn++;
+                       if (o=forstmt())
+                               goto syntax;
+                       contlab = o1;
+                       brklab = o2;
+                       return;
+               }
+
+               case ELSE:
+                       error("Inappropriate 'else'");
+                       statement();
+                       return;
+               }
+               error("Unknown keyword");
+               goto syntax;
+
+       case NAME: {
+               register struct nmlist *np;
+               if (nextchar()==':') {
+                       peekc = 0;
+                       np = csym;
+                       if (np->hclass>0) {
+                               if (np->hblklev==0) {
+                                       np = pushdecl(np);
+                                       np->hoffset = 0;
+                               } else {
+                                       defsym = np;
+                                       redec();
+                                       goto stmt;
+                               }
+                       }
+                       np->hclass = STATIC;
+                       np->htype = ARRAY;
+                       np->hflag |= FLABL;
+                       if (np->hoffset==0)
+                               np->hoffset = isn++;
+                       label(np->hoffset);
+                       goto stmt;
+               }
+       }
+       }
+       peeksym = o;
+       rcexpr(tree(1));
+
+semi:
+       if ((o=symbol())==SEMI)
+               return;
+syntax:
+       error("Statement syntax");
+       errflush(o);
+}
+
+/*
+ * Process a for statement.
+ */
+int forstmt() {
+       register int o;
+       register union tree *st;
+       register int l;
+       char *ss;
+
+       if ((o=symbol()) != LPARN)
+               return(o);
+       if ((o=symbol()) != SEMI) {             /* init part */
+               peeksym = o;
+               rcexpr(tree(1));
+               if ((o=symbol()) != SEMI)
+                       return(o);
+       }
+       l = isn;
+       isn += 3;
+       branch(l+0);
+       label(l+1);
+       branch(l+2);
+       label(contlab);
+       st = NULL;
+       if ((o=symbol()) != SEMI) {             /* test part */
+               peeksym = o;
+               ss = starttree();
+               st = tree(0);
+               if ((o=symbol()) != SEMI) {
+                       endtree(ss);
+                       return(o);
+               }
+       }
+       if ((o=symbol()) != RPARN) {    /* incr part */
+               peeksym = o;
+               rcexpr(tree(1));
+               if ((o=symbol()) != RPARN) {
+                       if (st)
+                               endtree(ss);
+                       return(o);
+               }
+       }
+       label(l+0);
+       if (st) {
+               cbranch(st, l+1, 1);
+               endtree(ss);
+       } else
+               branch(l+1);
+       branch(brklab);
+       label(l+2);
+       statement();
+       branch(contlab);
+       label(brklab);
+       return(0);
+}
+
+/*
+ * A parenthesized expression,
+ * as after "if".
+ */
+union tree *pexpr(eflag) int eflag; {
+       register int o;
+       register union tree *t;
+
+       if ((o=symbol())!=LPARN)
+               goto syntax;
+       t = tree(eflag);
+       if ((o=symbol())!=RPARN)
+               goto syntax;
+       if (t->t.type==VOID)
+               error("Illegal use of void");
+       return(t);
+syntax:
+       error("Statement syntax");
+       errflush(o);
+       return(0);
+}
+
+/*
+ * The switch statement, which involves collecting the
+ * constants and labels for the cases.
+ */
+void pswitch() {
+       register struct swtab *cswp, *sswp;
+       int dl, swlab;
+
+       cswp = sswp = swp;
+       if (swp==0)
+               cswp = swp = swtab;
+       branch(swlab=isn++);
+       dl = deflab;
+       deflab = 0;
+       statement();
+       branch(brklab);
+       label(swlab);
+       if (deflab==0)
+               deflab = brklab;
+       outcode("BNN", SWIT, deflab, line);
+       for (; cswp < swp; cswp++)
+               outcode("NN", cswp->swlab, cswp->swval);
+       outcode("0");
+       label(brklab);
+       deflab = dl;
+       swp = sswp;
+}
+
+/*
+ * funchead is called at the start of each function
+ * to process the arguments, which have been linked in a list.
+ * This list is necessary because in
+ * f(a, b) float b; int a; ...
+ * the names are seen before the types.
+ */
+/*
+ * Structure resembling a block for a register variable.
+ */
+struct nmlist  hreg    = { REG, 0, 0, NULL, NULL, 0 };
+struct tnode   areg    = { NAME, 0, NULL, NULL, (union tree *)&hreg};
+void funchead() {
+       register int pl;
+       register struct nmlist *cs;
+       register char *st;
+
+       pl = STARG;
+       while(paraml) {
+               parame->sparent = NULL;
+               cs = paraml;
+               paraml = &paraml->sparent->P;
+               if (cs->htype==FLOAT)
+                       cs->htype = DOUBLE;
+               cs->hoffset = pl;
+               if ((cs->htype&XTYPE) == ARRAY) {
+                       cs->htype -= (ARRAY-PTR);       /* set ptr */
+                       cs->hsubsp++;           /* pop dims */
+               }
+               pl += rlength((union tree *)cs);
+               if (cs->hclass==AREG && (hreg.hoffset=goodreg(cs))>=0) {
+                       st = starttree();
+                       *cp++ = (union tree *)&areg;
+                       *cp++ = nblock(cs);
+                       areg.type = cs->htype;
+                       areg.strp = cs->hstrp;
+                       cs->hclass = AUTO;
+                       build(ASSIGN);
+                       rcexpr(*--cp);
+                       cs->hoffset = hreg.hoffset;
+                       cs->hclass = REG;
+                       endtree(st);
+               } else
+                       cs->hclass = AUTO;
+               prste(cs);
+       }
+       for (pl=0; pl<HSHSIZ; pl++) {
+               for (cs = hshtab[pl]; cs!=NULL; cs = cs->nextnm) {
+                       if (cs->hclass == ARG || cs->hclass==AREG)
+                               error("Not an argument: %s", cs->name);
+               }
+       }
+       outcode("BN", SETREG, regvar);
+}
+
+void blockhead() {
+       register int r;
+
+       r = regvar;
+       blklev++;
+       declist(0);
+       if (r != regvar)
+               outcode("BN", SETREG, regvar);
+}
+
+/*
+ * After the end of a block, delete local
+ * symbols;
+ * Also complain about undefined labels.
+ */
+void blkend() {
+       register struct nmlist *cs, **lcs;
+       register int i;
+
+       blklev--;
+       for (i = 0; i < HSHSIZ; i++) {
+               lcs = &hshtab[i];
+               cs = *lcs;
+               while (cs) {
+                       if (cs->hblklev > blklev
+                        && (((cs->hflag&FLABL)==0 && cs->hclass!=EXTERN) || blklev<=0)) {
+                               if (cs->hclass==0)
+                                       error("%s undefined", cs->name);
+                               if (cs->hclass==EXTERN)
+                                       nameconflict(hshtab[i], cs);
+                               *lcs = cs->nextnm;
+                       } else
+                               lcs = &cs->nextnm;
+                       cs = cs->nextnm;
+               }
+       }
+}
+
+void nameconflict(ocs, cs) register struct nmlist *ocs; register struct nmlist *cs; {
+
+       for (; ocs!=NULL; ocs = ocs->nextnm) 
+               if (ocs!=cs && ocs->hclass==EXTERN && 
+                   strncmp(cs->name, ocs->name, MAXCPS-1) == 0)
+                       error("names %s and %s conflict", cs->name, ocs->name);
+}
+
+/*
+ * write out special definitions of local symbols for
+ * benefit of the debugger.  None of these are used
+ * by the assembler except to save them.
+ */
+void prste(cs) struct nmlist *cs; {
+       register int nkind;
+
+       switch (cs->hclass) {
+       case REG:
+               nkind = RNAME;
+               break;
+
+       case AUTO:
+               nkind = ANAME;
+               break;
+
+       case STATIC:
+               nkind = SNAME;
+               break;
+
+       default:
+               return;
+
+       }
+       outcode("BSN", nkind, cs->name, cs->hoffset);
+}
+
+/*
+ * In case of error, skip to the next
+ * statement delimiter.
+ */
+void errflush(ao) int ao; {
+       register int o;
+
+       o = ao;
+       while(o>RBRACE) {       /* ; { } */
+               if (o==STRING)
+                       putstr(0, 0);
+               o = symbol();
+       }
+       peeksym  = o;
+}
diff --git a/c03.c b/c03.c
new file mode 100644 (file)
index 0000000..bfa3a16
--- /dev/null
+++ b/c03.c
@@ -0,0 +1,727 @@
+/*
+ * C compiler, phase 1
+ * Handles processing of declarations,
+ * except for top-level processing of
+ * externals.
+ */
+
+#include <string.h>
+#include "c0.h"
+
+/*
+ * Process a sequence of declaration statements
+ */
+int declist(sclass) int sclass; {
+       register int sc, offset;
+       struct nmlist typer;
+
+       offset = 0;
+       sc = sclass;
+       while (getkeywords(&sclass, &typer)) {
+               offset = declare(sclass, &typer, offset);
+               sclass = sc;
+       }
+       return(offset+align(INT, offset, 0));
+}
+
+/*
+ * Read the keywords introducing a declaration statement
+ * Store back the storage class, and fill in the type
+ * entry, which looks like a hash table entry.
+ */
+int getkeywords(scptr, tptr) int *scptr; struct nmlist *tptr; {
+       register int skw, tkw, longf;
+       int o, isadecl, ismos, unsignf;
+
+       isadecl = 0;
+       longf = 0;
+       unsignf = 0;
+       tptr->htype = INT;
+       tptr->hstrp = NULL;
+       tptr->hsubsp = NULL;
+       tkw = -1;
+       skw = *scptr;
+       ismos = skw==MOS||skw==MOU? FMOS: 0;
+       for (;;) {
+               mosflg = isadecl? ismos: 0;
+               o = symbol();
+               if (o==NAME && csym->hclass==TYPEDEF) {
+                       if (tkw >= 0)
+                               error("type clash");
+                       tkw = csym->htype;
+                       tptr->hsubsp = csym->hsubsp;
+                       tptr->hstrp = csym->hstrp;
+                       isadecl++;
+                       continue;
+               }
+               switch (o==KEYW? cval: -1) {
+               case AUTO:
+               case STATIC:
+               case EXTERN:
+               case REG:
+               case TYPEDEF:
+                       if (skw && skw!=cval) {
+                               if (skw==ARG && cval==REG)
+                                       cval = AREG;
+                               else
+                                       error("Conflict in storage class");
+                       }
+                       skw = cval;
+                       break;
+
+               case UNSIGN:
+                       unsignf++;
+                       break;
+
+               case LONG:
+                       longf++;
+                       break;
+
+               case ENUM:
+                       if (longf || unsignf)
+                               error("Perverse modifier on 'enum'");
+                       strdec(ismos, cval);
+                       cval = INT;
+                       goto types;
+
+               case UNION:
+               case STRUCT:
+                       tptr->hstrp = strdec(ismos, cval);
+                       cval = STRUCT;
+               case INT:
+               case CHAR:
+               case FLOAT:
+               case DOUBLE:
+               case VOID:
+               types:
+                       if (tkw>=0 && (tkw!=INT || cval!=INT))
+                               error("Type clash");
+                       tkw = cval;
+                       if (unscflg && cval==CHAR)
+                               unsignf++;
+                       break;
+
+               default:
+                       peeksym = o;
+                       if (isadecl==0)
+                               return(0);
+                       if (tkw<0)
+                               tkw = INT;
+                       if (skw==0)
+                               skw = blklev==0? DEFXTRN: AUTO;
+                       if (unsignf) {
+                               if (tkw==INT)
+                                       tkw = UNSIGN;
+                               else if (tkw==CHAR)
+                                       tkw = UNCHAR;
+                               else if (tkw==LONG)
+                                       tkw = UNLONG;
+                               else
+                                       error("Misplaced 'unsigned'");
+                       }
+                       if (longf) {
+                               if (tkw==FLOAT)
+                                       tkw = DOUBLE;
+                               else if (tkw==INT)
+                                       tkw = LONG;
+                               else if (tkw==UNSIGN)
+                                       tkw = UNLONG;
+                               else
+                                       error("Misplaced 'long'");
+                       }
+                       *scptr = skw;
+                       tptr->htype = tkw;
+                       return(1);
+               }
+               isadecl++;
+       }
+}
+
+/*
+ * Process a structure, union, or enum declaration; a subroutine
+ * of getkeywords.
+ */
+union str *strdec(mosf, kind) int mosf; int kind; {
+       register int elsize, o;
+       register struct nmlist *ssym;
+       int savebits;
+       struct nmlist **savememlist;
+       union str *savesparent;
+       int savenmems;
+       union str *strp;
+       struct nmlist *ds;
+       struct nmlist *mems[NMEMS];
+       struct nmlist typer;
+       int tagkind;
+
+       if (kind!=ENUM) {
+               tagkind = STRTAG;
+               mosflg = FTAG;
+               if (kind==UNION)
+                       mosflg = FUNION;
+       } else {
+               tagkind = ENUMTAG;
+               mosflg = FENUM;
+       }
+       ssym = 0;
+       if ((o=symbol())==NAME) {
+               ssym = csym;
+               mosflg = mosf;
+               o = symbol();
+               if (o==LBRACE && ssym->hblklev<blklev)
+                       ssym = pushdecl(ssym);
+               if (ssym->hclass && ssym->hclass!=tagkind) {
+                       defsym = ssym;
+                       redec();
+                       ssym = pushdecl(ssym);
+               }
+               if (ssym->hclass==0) {
+                       ssym->hclass = tagkind;
+                       ssym->hstrp = (union str *)Dblock(sizeof(struct SS));
+                       ssym->hstrp->S.ssize = 0;
+                       ssym->hstrp->S.memlist = NULL;
+               }
+               strp = ssym->hstrp;
+       } else {
+               strp = (union str *)Dblock(sizeof(struct SS));
+               strp->S.ssize = 0;
+               strp->S.memlist = NULL;
+       }
+       mosflg = 0;
+       if (o != LBRACE) {
+               if (ssym==0)
+                       goto syntax;
+               if (ssym->hclass!=tagkind)
+                       error("Bad structure/union/enum name");
+               peeksym = o;
+       } else {
+               ds = defsym;
+               mosflg = 0;
+               savebits = bitoffs;
+               savememlist = memlist;
+               savesparent = sparent;
+               savenmems = nmems;
+               memlist = mems;
+               sparent = strp;
+               nmems = 2;
+               bitoffs = 0;
+               if (kind==ENUM) {
+                       typer.htype = INT;
+                       typer.hstrp = strp;
+                       declare(ENUM, &typer, 0);
+               } else
+                       elsize = declist(kind==UNION?MOU:MOS);
+               bitoffs = savebits;
+#if 1 /* just save a bit of string space */
+               if (strp->S.ssize) {
+                       defsym = ssym;
+                       redec();
+               }
+               defsym = ds;
+#else
+               defsym = ds;
+               if (strp->S.ssize)
+                       error("%s redeclared", ssym->name);
+#endif
+               strp->S.ssize = elsize;
+               *memlist++ = NULL;
+               strp->S.memlist = (struct nmlist **)Dblock((memlist-mems)*sizeof(*memlist));
+               for (o=0; &mems[o] != memlist; o++)
+                       strp->S.memlist[o] = mems[o];
+               memlist = savememlist;
+               sparent = savesparent;
+               nmems = savenmems;
+               if ((o = symbol()) != RBRACE)
+                       goto syntax;
+       }
+       return(strp);
+   syntax:
+       decsyn(o);
+       return(0);
+}
+
+/*
+ * Process a comma-separated list of declarators
+ */
+int declare(askw, tptr, offset) int askw; struct nmlist *tptr; int offset; {
+       register unsigned o;
+       register int skw, isunion;
+       struct nmlist abs, *aptr;
+
+       skw = askw;
+       isunion = 0;
+       if (skw==MOU) {
+               skw = MOS;
+               isunion++;
+               mosflg = FMOS;
+               if ((peeksym=symbol()) == SEMI) {
+                       o = length((union tree *)tptr);
+                       if (o>offset)
+                               offset = o;
+               }
+       }
+       do {
+               if (skw==ENUM && (peeksym=symbol())==RBRACE) {
+                       o = peeksym;
+                       peeksym = -1;
+                       break;
+               }
+               if (skw == MOS) {
+                       abs.hclass = 0;
+                       abs.hflag = 0;
+                       abs.htype = 0;
+                       abs.hsubsp = 0;
+                       abs.hstrp = 0;
+                       abs.nextnm = 0;
+                       abs.sparent = 0;
+                       abs.hblklev = blklev;
+                       abs.name = "<none>";
+                       aptr = &abs;
+               } else
+                       aptr = NULL;
+               o = decl1(skw, tptr, isunion?0:offset, aptr);
+               if (isunion) {
+                       o += align(CHAR, o, 0);
+                       if (o>offset)
+                               offset = o;
+               } else
+                       offset += o;
+       } while ((o=symbol()) == COMMA);
+       if (o==RBRACE) {
+               peeksym = o;
+               o = SEMI;
+       }
+       if (o!=SEMI && (o!=RPARN || skw!=ARG1))
+               decsyn(o);
+       return(offset);
+}
+
+/*
+ * Process a single declarator
+ */
+int decl1(askw, atptr, offset, absname) int askw; struct nmlist *atptr; int offset; struct nmlist *absname; {
+       int t1, a, elsize;
+       register int skw;
+       int type;
+       register struct nmlist *dsym;
+       register struct nmlist *tptr;
+       struct tdim dim;
+       int *dp;
+       int isinit;
+
+       skw = askw;
+       tptr = atptr;
+       mosflg = skw==MOS? FMOS: 0;
+       dim.rank = 0;
+       if (((peeksym=symbol())==SEMI || peeksym==RPARN) && absname==NULL)
+               return(0);
+       /*
+        * Filler field
+        */
+       if (peeksym==COLON && skw==MOS) {
+               peeksym = -1;
+               t1 = conexp();
+               if (t1<0) {
+                       error("Negative field width");
+                       t1 = 0;
+               }
+               elsize = align(tptr->htype, offset, t1);
+               bitoffs += t1;
+               return(elsize);
+       }
+       t1 = getype(&dim, absname);
+       if (t1 == -1)
+               return(0);
+       if (defsym)
+               absname = NULL;
+       if (tptr->hsubsp) {
+               type = tptr->htype;
+               for (a=0; type&XTYPE;) {
+                       if ((type&XTYPE)==ARRAY)
+                               dim.dimens[dim.rank++] = tptr->hsubsp[a++];
+                       type >>= TYLEN;
+               }
+       }
+       type = tptr->htype & ~TYPE;
+       while (t1&XTYPE) {
+               if (type&BIGTYPE) {
+                       typov();
+                       type = t1 = 0;
+               }
+               type = type<<TYLEN | (t1 & XTYPE);
+               t1 >>= TYLEN;
+       }
+       type |= tptr->htype&TYPE;
+       if ((type&XTYPE) == FUNC) {
+               if (skw==AUTO)
+                       skw = EXTERN;
+               if ((skw!=EXTERN && skw!=TYPEDEF) && absname==NULL)
+                       error("Bad func. storage class");
+       }
+       if (defsym)
+               dsym = defsym;
+       else if (absname)
+               dsym = absname;
+       else {
+               error("Name required in declaration");
+               return(0);
+       }
+       if (defsym)
+       if (dsym->hblklev<blklev || dsym->hclass==MOS && skw==MOS) {
+               if (skw==MOS && dsym->sparent==sparent)
+                       redec();
+               defsym = dsym;
+               if (skw==EXTERN) {
+                       for (; dsym!=NULL; dsym = dsym->nextnm) {
+                               if (dsym->hclass==EXTERN
+                                && strcmp(dsym->name, defsym->name)==0) {
+                                       defsym = dsym;
+                                       break;
+                               }
+                       }
+                       dsym = defsym;
+               } else
+                       defsym = dsym = pushdecl(dsym);
+       }
+       if (dim.rank == 0)
+               dsym->hsubsp = NULL;
+       else {
+               /*
+                * If an array is declared twice, make sure the declarations
+                * agree in dimension.  This happens typically when a .h
+                * and .c file both declare a variable.
+                */
+               if (dsym->hsubsp) {
+                       for (a=0, t1 = dsym->htype;
+                           a<dim.rank && (t1&XTYPE)==ARRAY;
+                           a++, t1 >>= TYLEN)
+                               /*
+                                * If we haven't seen a declaration for this
+                                * dimension yet, take what's been given now.
+                                */
+                               if (!dsym->hsubsp[a])
+                                       dsym->hsubsp[a] = dim.dimens[a];
+                               else if (dim.dimens[a]
+                                   && dim.dimens[a] != dsym->hsubsp[a])
+                                       redec();
+                       if (a<dim.rank || (t1&XTYPE)==ARRAY)
+                               redec();
+               } else {
+                       dp = (int *)Dblock(dim.rank*sizeof(dim.rank));
+                       for (a=0; a<dim.rank; a++)
+                               dp[a] = dim.dimens[a];
+                       dsym->hsubsp = dp;
+               }
+       }
+       if (!(dsym->hclass==0
+          || ((skw==ARG||skw==AREG) && dsym->hclass==ARG1)
+          || (skw==EXTERN && dsym->hclass==EXTERN && dsym->htype==type))) {
+               redec();
+               goto syntax;
+       }
+       if (dsym->hclass && (dsym->htype&TYPE)==STRUCT && (type&TYPE)==STRUCT)
+               if (dsym->hstrp != tptr->hstrp) {
+                       error("structure redeclaration");
+               }
+       dsym->htype = type;
+       if (tptr->hstrp)
+               dsym->hstrp = tptr->hstrp;
+       if (skw==TYPEDEF) {
+               dsym->hclass = TYPEDEF;
+               return(0);
+       }
+       if (skw==ARG1) {
+               if (paraml==NULL)
+                       paraml = dsym;
+               else
+                       parame->sparent = (union str *)dsym;
+               parame = dsym;
+               dsym->hclass = skw;
+               return(0);
+       }
+       elsize = 0;
+       if (skw==MOS) {
+               elsize = length((union tree *)dsym);
+               if ((peeksym = symbol())==COLON) {
+                       elsize = 0;
+                       peeksym = -1;
+                       t1 = conexp();
+                       a = align(type, offset, t1);
+                       if (dsym->hflag&FFIELD) {
+                               if (dsym->hstrp->F.bitoffs!=bitoffs
+                                || dsym->hstrp->F.flen!=t1)
+                                       redec();
+                       } else {
+                               dsym->hstrp = (union str *)Dblock(sizeof(struct FS));
+                       }
+                       dsym->hflag |= FFIELD;
+                       dsym->hstrp->F.bitoffs = bitoffs;
+                       dsym->hstrp->F.flen = t1;
+                       bitoffs += t1;
+               } else
+                       a = align(type, offset, 0);
+               elsize += a;
+               offset += a;
+               if (++nmems >= NMEMS) {
+                       error("Too many structure members");
+                       nmems -= NMEMS/2;
+                       memlist -= NMEMS/2;
+               }
+               if (a)
+                       *memlist++ = &structhole;
+               dsym->hoffset = offset;
+               *memlist++ = dsym;
+               dsym->sparent = sparent;
+       }
+       if (skw==REG)
+               if ((dsym->hoffset = goodreg(dsym)) < 0)
+                       skw = AUTO;
+       dsym->hclass = skw;
+       isinit = 0;
+       if ((a=symbol()) == ASSIGN)
+               isinit++;
+       else
+               peeksym = a;
+       if (skw==AUTO) {
+       /*      if (STAUTO < 0) {       */
+                       autolen -= rlength((union tree *)dsym);
+                       dsym->hoffset = autolen;
+                       if (autolen < maxauto)
+                               maxauto = autolen;
+       /*      } else {                        */
+       /*              dsym->hoffset = autolen;        */
+       /*              autolen += rlength(dsym);       */
+       /*              if (autolen > maxauto)          */
+       /*                      maxauto = autolen;      */
+       /*      }                       */
+               if (isinit)
+                       cinit(dsym, 0, AUTO);
+               isinit = 0;
+       } else if (skw==STATIC) {
+               dsym->hoffset = isn;
+               if (isinit) {
+                       outcode("BBN", DATA, LABEL, isn++);
+                       if (cinit(dsym, 1, STATIC) & ALIGN)
+                               outcode("B", EVEN);
+               } else
+                       outcode("BBNBN", BSS, LABEL, isn++, SSPACE,
+                         rlength((union tree *)dsym));
+               outcode("B", PROG);
+               isinit = 0;
+       } else if (skw==REG && isinit) {
+               cinit(dsym, 0, REG);
+               isinit = 0;
+       } else if (skw==ENUM) {
+               if (type!=INT)
+                       error("Illegal enumeration %s", dsym->name);
+               dsym->hclass = ENUMCON;
+               dsym->hoffset = offset;
+               if (isinit)
+                       cinit(dsym, 0, ENUMCON);
+               elsize = dsym->hoffset-offset+1;
+               isinit = 0;
+       }
+       if (absname==0)
+               prste(dsym);
+       if (isinit)
+               peeksym = ASSIGN;
+syntax:
+       return(elsize);
+}
+
+/*
+ * Push down an outer-block declaration
+ * after redeclaration in an inner block.
+ */
+struct nmlist *pushdecl(sp) register struct nmlist *sp; {
+       register struct nmlist *nsp, **hsp;
+
+       nsp = (struct nmlist *)Dblock(sizeof(struct nmlist));
+       *nsp = *sp;
+       nsp->hclass = 0;
+       nsp->hflag &= FKIND;
+       nsp->htype = 0;
+       nsp->hoffset = 0;
+       nsp->hblklev = blklev;
+       nsp->hstrp = NULL;
+       nsp->hsubsp = NULL;
+       nsp->sparent = NULL;
+       hsp = &hshtab[hash(sp->name)];
+       nsp->nextnm = *hsp;
+       *hsp = nsp;
+       return(nsp);
+}
+
+/*
+ * Read a declarator and get the implied type
+ */
+int getype(dimp, absname) register struct tdim *dimp; struct nmlist *absname; {
+       static struct nmlist argtype;
+       int type;
+       register int o;
+       register struct nmlist *ds;
+
+       defsym = 0;
+       type = 0;
+       switch(o=symbol()) {
+
+       case TIMES:
+               type = getype(dimp, absname);
+               if (type==-1)
+                       return(type);
+               if (type&BIGTYPE) {
+                       typov();
+                       type = 0;
+               }
+               return(type<<TYLEN | PTR);
+
+       case LPARN:
+               if (absname==NULL || nextchar()!=')') {
+                       type = getype(dimp, absname);
+                       if (type==-1)
+                               return(type);
+                       if ((o=symbol()) != RPARN)
+                               goto syntax;
+                       goto getf;
+               }
+
+       default:
+               peeksym = o;
+               if (absname)
+                       goto getf;
+               break;
+
+       case NAME:
+               defsym = ds = csym;
+       getf:
+               switch(o=symbol()) {
+
+               case LPARN:
+                       if (blklev==0) {
+                               blklev++;
+                               ds = defsym;
+                               declare(ARG1, &argtype, 0);
+                               defsym = ds;
+                               blklev--;
+                       } else
+                               if ((o=symbol()) != RPARN)
+                                       goto syntax;
+                       if (type&BIGTYPE) {
+                               typov();
+                               type = 0;
+                       }
+                       type = type<<TYLEN | FUNC;
+                       goto getf;
+
+               case LBRACK:
+                       if (dimp->rank>=5) {
+                               error("Rank too large");
+                               dimp->rank = 4;
+                       }
+                       if ((o=symbol()) != RBRACK) {
+                               peeksym = o;
+                               ds = defsym;
+                               cval = conexp();
+                               defsym = ds;
+                               if ((o=symbol())!=RBRACK)
+                                       goto syntax;
+                       } else {
+                               if (dimp->rank!=0)
+                                       error("Null dimension");
+                               cval = 0;
+                       }
+                       dimp->dimens[dimp->rank++] = cval;
+                       if (type&BIGTYPE) {
+                               typov();
+                               type = 0;
+                       }
+                       type = type<<TYLEN | ARRAY;
+                       goto getf;
+               }
+               peeksym = o;
+               return(type);
+       }
+syntax:
+       decsyn(o);
+       return(-1);
+}
+
+/*
+ * More bits required for type than allowed.
+ */
+void typov() {
+       error("Type is too complicated");
+}
+
+/*
+ * Enforce alignment restrictions in structures,
+ * including bit-field considerations.
+ */
+int align(type, offset, aflen) int type; int offset; int aflen; {
+       register int a, t, flen;
+       char *ftl;
+
+       flen = aflen;
+       a = offset;
+       t = type;
+       ftl = "Field too long";
+       if (flen==0) {
+               a += (NBPC+bitoffs-1) / NBPC;
+               bitoffs = 0;
+       }
+       while ((t&XTYPE)==ARRAY)
+               t = decref(t);
+       if (t!=CHAR && t!=UNCHAR) {
+               a = (a+ALIGN) & ~ALIGN;
+               if (a>offset)
+                       bitoffs = 0;
+       }
+       if (flen) {
+               if (type==INT || type==UNSIGN) {
+                       if (flen > NBPW)
+                               error(ftl);
+                       if (flen+bitoffs > NBPW) {
+                               bitoffs = 0;
+                               a += NCPW;
+                       }
+               } else if (type==CHAR || type==UNCHAR) {
+                       if (flen > NBPC)
+                               error(ftl);
+                       if (flen+bitoffs > NBPC) {
+                               bitoffs = 0;
+                               a += 1;
+                       }
+               } else
+                       error("Bad type for field");
+       }
+       return(a-offset);
+}
+
+/*
+ * Complain about syntax error in declaration
+ */
+void decsyn(o) int o; {
+       error("Declaration syntax");
+       errflush(o);
+}
+
+/*
+ * Complain about a redeclaration
+ */
+void redec() {
+       error("%s redeclared", defsym->name);
+}
+
+/*
+ * Determine if a variable is suitable for storage in
+ * a register; if so return the register number
+ */
+int goodreg(hp) struct nmlist *hp; {
+       int type;
+
+       type = hp->htype;
+       if ((type!=INT && type!=UNSIGN && (type&XTYPE)==0)
+        || (type&XTYPE)>PTR || regvar<3)
+               return(-1);
+       return(--regvar);
+}
diff --git a/c04.c b/c04.c
new file mode 100644 (file)
index 0000000..7f8699f
--- /dev/null
+++ b/c04.c
@@ -0,0 +1,422 @@
+/*
+ * C compiler
+ */
+
+#include <stdlib.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#define _va_start(ap, arg) va_start(ap, arg)
+#else
+#include <varargs.h>
+#define _va_start(ap, arg) va_start(ap)
+#endif
+#include "c0.h"
+
+/*
+ * Reduce the degree-of-reference by one.
+ * e.g. turn "ptr-to-int" into "int".
+ */
+int decref(t) register int t; {
+       if ((t & ~TYPE) == 0) {
+               error("Illegal indirection");
+               return(t);
+       }
+       return((t>>TYLEN) & ~TYPE | t&TYPE);
+}
+
+/*
+ * Increase the degree of reference by
+ * one; e.g. turn "int" to "ptr-to-int".
+ */
+int incref(t) register int t; {
+       return(((t&~TYPE)<<TYLEN) | (t&TYPE) | PTR);
+}
+
+/*
+ * Make a tree that causes a branch to lbl
+ * if the tree's value is non-zero together with the cond.
+ */
+void cbranch(t, lbl, cond) union tree *t; int lbl; int cond; {
+       treeout(t, 0);
+       outcode("BNNN", CBRANCH, lbl, cond, line);
+}
+
+/*
+ * Write out a tree.
+ */
+void rcexpr(tp) register union tree *tp; {
+       /*
+        * Special optimization
+        */
+       if (tp->t.op==INIT && tp->t.tr1->t.op==CON) {
+               if (tp->t.type==CHAR || tp->t.type==UNCHAR) {
+                       outcode("B1N0", BDATA, tp->t.tr1->c.value);
+                       return;
+               } else if (tp->t.type==INT || tp->t.type==UNSIGN) {
+                       outcode("BN", SINIT, tp->t.tr1->c.value);
+                       return;
+               }
+       }
+       treeout(tp, 0);
+       outcode("BN", EXPR, line);
+}
+
+void treeout(tp, isstruct) register union tree *tp; int isstruct; {
+       register struct nmlist *hp;
+       register int nextisstruct;
+
+       if (tp == NULL || tp->t.op==NULLOP) {
+               outcode("B", XNULLOP);
+               return;
+       }
+       nextisstruct = tp->t.type==STRUCT;
+       switch(tp->t.op) {
+
+       case NAME:
+               hp = &tp->t.tr1->n;
+               if (hp->hclass==TYPEDEF)
+                       error("Illegal use of type name");
+               outcode("BNN", NAME, hp->hclass==0?STATIC:hp->hclass, tp->t.type);
+               if (hp->hclass==EXTERN)
+                       outcode("S", hp->name);
+               else
+                       outcode("N", hp->hoffset);
+               break;
+
+       case LCON:
+               outcode("BNNN", tp->l.op, tp->l.type, (_UNSIGNED_INT)(tp->l.lvalue>>16),
+                  (_UNSIGNED_INT)tp->l.lvalue);
+               break;
+
+       case CON:
+               outcode("BNN", tp->c.op, tp->c.type, tp->c.value);
+               break;
+
+       case FCON:
+               outcode("BNF", tp->f.op, tp->f.type, tp->f.cstr);
+               break;
+
+       case STRING:
+               outcode("BNNN", NAME, STATIC, tp->t.type, tp->t.tr1);
+               break;
+
+       case FSEL:
+               treeout(tp->t.tr1, nextisstruct);
+               outcode("BNNN", tp->t.op, tp->t.type,
+                  tp->t.tr2->fld.bitoffs, tp->t.tr2->fld.flen);
+               break;
+
+       case ETYPE:
+               error("Illegal use of type");
+               break;
+
+       case AMPER:
+               treeout(tp->t.tr1, 1);
+               outcode("BN", tp->t.op, tp->t.type);
+               break;
+
+
+       case CALL:
+               treeout(tp->t.tr1, 1);
+               treeout(tp->t.tr2, 0);
+               outcode("BN", CALL, tp->t.type);
+               break;
+
+       default:
+               treeout(tp->t.tr1, nextisstruct);
+               if (opdope[tp->t.op]&BINARY)
+                       treeout(tp->t.tr2, nextisstruct);
+               outcode("BN", tp->t.op, tp->t.type);
+               break;
+       }
+       if (nextisstruct && isstruct==0)
+               outcode("BNN", STRASG, STRUCT, tp->t.strp->S.ssize);
+}
+
+/*
+ * Generate a branch
+ */
+void branch(lab) int lab; {
+       outcode("BN", BRANCH, lab);
+}
+
+/*
+ * Generate a label
+ */
+void label(l) int l; {
+       outcode("BN", LABEL, l);
+}
+
+/*
+ * ap is a tree node whose type
+ * is some kind of pointer; return the size of the object
+ * to which the pointer points.
+ */
+int plength(p) register union tree *p; {
+       register int t, l;
+
+       if (p==0 || ((t=p->t.type)&~TYPE) == 0)         /* not a reference */
+               return(1);
+       p->t.type = decref(t);
+       l = length(p);
+       p->t.type = t;
+       return(l);
+}
+
+/*
+ * return the number of bytes in the object
+ * whose tree node is acs.
+ */
+int length(cs) union tree *cs; {
+       register int t, elsz;
+       long n;
+       int nd;
+
+       t = cs->t.type;
+       n = 1;
+       nd = 0;
+       while ((t&XTYPE) == ARRAY) {
+               t = decref(t);
+               n *= cs->t.subsp[nd++];
+       }
+       if ((t&~TYPE)==FUNC)
+               return(0);
+       if (t>=PTR)
+               elsz = SZPTR;
+       else switch(t&TYPE) {
+
+       case VOID:
+               error("Illegal use of void object");
+               return(2);
+
+       case INT:
+       case UNSIGN:
+               elsz = SZINT;
+               break;
+
+       case CHAR:
+       case UNCHAR:
+               elsz = 1;
+               break;
+
+       case FLOAT:
+               elsz = SZFLOAT;
+               break;
+
+       case UNLONG:
+       case LONG:
+               elsz = SZLONG;
+               break;
+
+       case DOUBLE:
+               elsz = SZDOUB;
+               break;
+
+       case STRUCT:
+               if ((elsz = cs->t.strp->S.ssize) == 0)
+                       error("Undefined structure");
+               break;
+       default:
+               error("Compiler error (length)");
+               return(0);
+       }
+       n *= elsz;
+       if (n >= (_UNSIGNED_INT)50000)
+               werror("very large data structure");
+       return(n);
+}
+
+/*
+ * The number of bytes in an object, rounded up to a word.
+ */
+int rlength(cs) union tree *cs; {
+       return((length(cs)+ALIGN) & ~ALIGN);
+}
+
+/*
+ * After an "if (...) goto", look to see if the transfer
+ * is to a simple label.
+ */
+int simplegoto() {
+       register struct nmlist *csp;
+
+       if ((peeksym=symbol())==NAME && nextchar()==';') {
+               csp = csym;
+               if (csp->hblklev == 0)
+                       csp = pushdecl(csp);
+               if (csp->hclass==0 && csp->htype==0) {
+                       csp->htype = ARRAY;
+                       csp->hflag |= FLABL;
+                       if (csp->hoffset==0)
+                               csp->hoffset = isn++;
+               }
+               if ((csp->hclass==0||csp->hclass==STATIC)
+                &&  csp->htype==ARRAY) {
+                       peeksym = -1;
+                       return(csp->hoffset);
+               }
+       }
+       return(0);
+}
+
+/*
+ * Return the next non-white-space character
+ */
+int nextchar() {
+       while (spnextchar()==' ')
+               peekc = 0;
+       return(peekc);
+}
+
+/*
+ * Return the next character, translating all white space
+ * to blank and handling line-ends.
+ */
+int spnextchar() {
+       register int c;
+
+       if ((c = peekc)==0)
+               c = getchar();
+       if (c=='\t' || c=='\014')       /* FF */
+               c = ' ';
+       else if (c=='\n') {
+               c = ' ';
+               line++;
+       }
+       peekc = c;
+       return(c);
+}
+
+/*
+ * is a break or continue legal?
+ */
+void chconbrk(l) int l; {
+       if (l==0)
+               error("Break/continue error");
+}
+
+/*
+ * The goto statement.
+ */
+void dogoto() {
+       register union tree *np;
+       register char *st;
+
+       st = starttree();
+       *cp++ = tree(0);
+       build(STAR);
+       chkw(np = *--cp, -1);
+       rcexpr(block(JUMP, 0, (int *)NULL, (union str *)NULL, np, TNULL));
+       endtree(st);
+}
+
+/*
+ * The return statement, which has to convert
+ * the returned object to the function's type.
+ */
+void doret() {
+       if (nextchar() != ';') {
+               register char *st;
+
+               st = starttree();
+               *cp++ = (union tree *)&funcblk;
+               *cp++ = tree(0);
+               build(ASSIGN);
+               cp[-1] = cp[-1]->t.tr2;
+               build(RFORCE);
+               rcexpr(*--cp);
+               endtree(st);
+       }
+       branch(retlab);
+}
+
+/*
+ * Write a character on the error output.
+ */
+/*
+ * Coded output:
+ *   B: beginning of line; an operator
+ *   N: a number
+ *   S: a symbol (external)
+ *   1: number 1
+ *   0: number 0
+ */
+#ifdef __STDC__
+void outcode(char *s, ...)
+#else
+void outcode(s, va_alist) char *s; va_dcl
+#endif
+{
+       va_list ap;
+       register FILE *bufp;
+       register int ni;
+       register char *np;
+       int n;
+
+       bufp = stdout;
+       if (strflg)
+               bufp = sbufp;
+       _va_start(ap, s);
+       for (;;) switch(*s++) {
+       case 'B':
+               ni = va_arg(ap, int);
+               fputc(ni, bufp);
+               fputc(0376, bufp);
+               continue;
+
+       case 'N':
+               ni = va_arg(ap, int);
+               fputc(ni, bufp);
+               fputc(ni>>8, bufp);
+               continue;
+
+       case 'F':
+               np = va_arg(ap, char *);
+               n = 1000;
+               goto str;
+
+       case 'S':
+               np = va_arg(ap, char *);
+               n = MAXCPS-1;
+               if (*np)
+                       fputc('_', bufp);
+       str:
+               while(n-- && *np) {
+                       fputc(*np++ & 0177, bufp);
+               }
+               fputc(0, bufp);
+               continue;
+
+       case '1':
+               fputc(1, bufp);
+               fputc(0, bufp);
+               continue;
+
+       case '0':
+               fputc(0, bufp);
+               fputc(0, bufp);
+               continue;
+
+       case '\0':
+               va_end(ap);
+               if (ferror(bufp)) {
+                       error("Write error on temp");
+                       exit(1);
+               }
+               return;
+
+       default:
+               error("Botch in outcode");
+       }
+}
+
+unsigned int hash(sp) register char *sp; {
+       register unsigned int h;
+
+       h = 0;
+       for (; *sp; sp++) {
+               h += h;
+               h += *sp;
+       }
+       return(h%HSHSIZ);
+}
diff --git a/c05.c b/c05.c
new file mode 100644 (file)
index 0000000..5cf663b
--- /dev/null
+++ b/c05.c
@@ -0,0 +1,250 @@
+#include "c0.h"
+/*
+ *  info on operators:
+ *   01-- is binary operator
+ *   02-- left (or only) operand must be lvalue
+ *   04-- is relational operator
+ *  010-- is assignment-type operator
+ *  020-- non-float req. on left
+ *  040-- non-float req. on right
+ * 0100-- is commutative
+ * 0200-- is right, not left-associative
+ * 0400-- is leaf of tree
+ * *0XX000-- XX is priority of operator
+ */
+int opdope[] = {
+       000000, /* EOFC */
+       000000, /* ; */
+       000000, /* { */
+       000000, /* } */
+       036001, /* [ */
+       002000, /* ] */
+       037000, /* ( */
+       002000, /* ) */
+       014201, /* : */
+       007001, /* , */
+       000001, /* field selection */
+       034201, /* CAST */
+       000000, /* ETYPE */
+       000001, /* integer->ptr */
+       000001, /* ptr->integer */
+       000001, /* long->ptr */
+       000000, /* 16 */
+       000000, /* 17 */
+       000000, /* 18 */
+       000000, /* 19 */
+       000400, /* name */
+       000400, /* short constant */
+       000400, /* string */
+       000400, /* float */
+       000400, /* double */
+       000400, /* long constant */
+       000400, /* long constant <= 16 bits */
+       000000, /* 27 */
+       000000, /* 28 */
+       000400, /* () empty arglist */
+       074203, /* ++pre */
+       074203, /* --pre */
+       074203, /* ++post */
+       074203, /* --post */
+       034200, /* !un */
+       034202, /* &un */
+       034220, /* *un */
+       034200, /* -un */
+       034220, /* ~un */
+       036001, /* . (structure reference) */
+       070101, /* + */
+       070001, /* - */
+       032101, /* * */
+       032001, /* / */
+       032001, /* % */
+       026061, /* >> */
+       026061, /* << */
+       020161, /* & */
+       017161, /* | */
+       017161, /* ^ */
+       036001, /* -> */
+       000000, /* int -> double */
+       000000, /* double -> int */
+       016001, /* && */
+       015001, /* || */
+       030001, /* &~ */
+       000000, /* 56 */
+       000000, /* 57 */
+       000000, /* 58 */
+       000000, /* 59 */
+       022005, /* == */
+       022005, /* != */
+       024005, /* <= */
+       024005, /* < */
+       024005, /* >= */
+       024005, /* > */
+       024005, /* <p */
+       024005, /* <=p */
+       024005, /* >p */
+       024005, /* >=p */
+       052213, /* += */
+       052213, /* -= */
+       012213, /* *= */
+       012213, /* /= */
+       012213, /* %= */
+       012253, /* >>= */
+       012253, /* <<= */
+       012253, /* &= */
+       012253, /* |= */
+       012253, /* ^= */
+       012213, /* = */
+       000000, /* 81 */
+       000000, /* 82 */
+       000000, /* 83 */
+       000000, /* 84 */
+       000000, /* 85 */
+       000000, /* 86 */
+       000000, /* 87 */
+       000000, /* 88 */
+       000000, /* 89 */
+       014201, /* ? */
+       034200, /* sizeof */
+       000000, /* 92 */
+       021101, /* min */
+       021101, /* minp */
+       021101, /* max */
+       021101, /* maxp */
+       007001, /* , */
+       000000, /* 98 */
+       000000, /* 99 */
+       036001, /* call */
+       036001, /* mcall */
+       000000, /* goto */
+       000000, /* jump cond */
+       000000, /* branch cond */
+       000000, /* 105 */
+       000000, /* 106 */
+       000000, /* 107 */
+       000000, /* 108 */
+       000000, /* char->int */
+       000000, /* 109 - force r0 */
+       000000, /* 110 */
+       000000, /* 111 */
+       000000, /* 112 */
+       000000, /* 113 */
+       000000, /* 114 */
+       000000, /* 115 */
+       000000, /* 116 */
+       000000, /* 117 */
+       000000, /* 118 */
+       000000, /* 119 */
+       000000, /* 120 */
+       000000, /* 121 */
+       000000, /* 122 */
+       000000, /* 123 */
+       000000, /* 124 */
+       000000, /* 125 */
+       000000, /* 126 */
+       000000, /* 127 */
+       026061, /* 128 - << unsigned long */
+       012253  /* 129 - <<= unsigned long */
+};
+
+/*
+ * conversion table:
+ * FTI: float (or double) to integer
+ * ITF: integer to float
+ * ITP: integer to pointer
+ * ITL: integer to long
+ * LTI: long to integer
+ * LTF: long to float
+ * FTL: float to long
+ * PTI: pointer to integer
+ * LTP: long to ptr (ptr[long])
+ * XX: usually illegal
+ * When FTI, LTI, FTL are added in they specify
+ * that it is the left operand that should be converted.
+ * For + this is done and the conversion is turned back into
+ * ITF, ITL, LTF.
+ * For = however the left operand can't be converted
+ * and the specified conversion is applied to the rhs.
+ */
+char cvtab[4][4] = {
+/*             int     double          long            ptr */
+/* int */      {0,     (FTI<<4)+ITF,   (LTI<<4)+ITL,   (ITP<<4)+ITP},
+/* double */   {ITF,   0,              LTF,            XX},
+/* long */     {ITL,   (FTL<<4)+LTF,   0,              (LTP<<4)+LTP},
+/* ptr */      {ITP,   XX,             LTP,            PTI}
+};
+
+/*
+ * relate conversion numbers to operators
+ */
+char   cvntab[] = {
+       0, ITOF, ITOL, LTOF, ITOP, PTOI, FTOI, LTOI, FTOL, LTOP,
+};
+
+/*
+ * character type table
+ */
+char ctab[] = {
+       EOFC,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,
+       UNKN,   SPACE,  NEWLN,  SPACE,  SPACE,  UNKN,   UNKN,   UNKN,
+       UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,
+       UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,   UNKN,
+       SPACE,  EXCLA,  DQUOTE, SHARP,  UNKN,   MOD,    AND,    SQUOTE,
+       LPARN,  RPARN,  TIMES,  PLUS,   COMMA,  MINUS,  PERIOD, DIVIDE,
+       DIGIT,  DIGIT,  DIGIT,  DIGIT,  DIGIT,  DIGIT,  DIGIT,  DIGIT,
+       DIGIT,  DIGIT,  COLON,  SEMI,   LESS,   ASSIGN, GREAT,  QUEST,
+       UNKN,   LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
+       LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
+       LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
+       LETTER, LETTER, LETTER, LBRACK, BSLASH, RBRACK, EXOR,   LETTER,
+       UNKN,   LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
+       LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
+       LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
+       LETTER, LETTER, LETTER, LBRACE, OR,     RBRACE, COMPL,  UNKN
+};
+
+int    STAUTO;
+char   cvtab[4][4];
+char   filename[MAXPATHLEN];
+char   symbuf[MAXCPS+2];
+struct nmlist  *hshtab[HSHSIZ];
+int    kwhash[(HSHSIZ+LNBPW-1)/LNBPW];
+struct swtab   swtab[SWSIZ];
+int    unscflg;
+struct swtab   *swp;
+int    contlab;
+int    brklab;
+int    retlab;
+int    deflab;
+unsigned autolen;              /* make these int if necessary */
+unsigned maxauto;              /* ... will only cause trouble rarely */
+int    peekc;
+int    eof;
+char   *locbase;
+char   *treebase;
+char   *treebot;
+char   *coremax;
+struct nmlist  *defsym;
+struct nmlist  *funcsym;
+int    proflg;
+struct nmlist  *csym;
+int    cval;
+_LONG  lcval;
+int    nchstr;
+int    nerror;
+struct nmlist *paraml;
+struct nmlist *parame;
+int    strflg;
+int    mosflg;
+int    initflg;
+char   sbuf[BUFSIZ];
+FILE   *sbufp;
+int    regvar;
+int    bitoffs;
+char   cvntab[];
+char   numbuf[64];
+struct nmlist **memlist;
+union  str *sparent;
+int    nmems;
+struct nmlist  structhole;
+int    blklev;
+int    mossym;
diff --git a/c1.h b/c1.h
new file mode 100644 (file)
index 0000000..d6be7e7
--- /dev/null
+++ b/c1.h
@@ -0,0 +1,576 @@
+/*
+ * C code generator header
+ */
+
+#ifndef _C1_H
+#define _C1_H 1
+
+#include <stdio.h>
+#include <setjmp.h>
+
+#ifdef pdp11
+typedef int _INT;
+typedef long _LONG;
+typedef unsigned int _UNSIGNED_INT;
+typedef unsigned long _UNSIGNED_LONG;
+typedef float _FLOAT;
+typedef double _DOUBLE;
+#else
+#include <stdint.h>
+typedef int16_t _INT;
+typedef int32_t _LONG;
+typedef uint16_t _UNSIGNED_INT;
+typedef uint32_t _UNSIGNED_LONG;
+typedef struct { uint32_t h; } _FLOAT;
+typedef struct { uint32_t l; uint32_t h; } _DOUBLE;
+#endif
+
+#ifndef NULL
+#define        NULL    0
+#endif
+#define        TNULL   (union tree *)NULL
+#define        UNS(x)  ((unsigned short)(x))
+
+/*
+ *  Tree node for unary and binary
+ */
+struct tnode {
+       int     op;
+       int     type;
+       int     degree;
+       union   tree *tr1;
+       union   tree *tr2;
+};
+
+/*
+ * tree names for locals
+ */
+struct tname {
+       int     op;
+       int     type;
+       char    class;
+       char    regno;
+       int     offset;
+       int     nloc;
+};
+
+/*
+ * tree names for externals
+ */
+struct xtname {
+       int     op;
+       int     type;
+       char    class;
+       char    regno;
+       int     offset;
+       char    *name;
+};
+
+/*
+ * short constants
+ */
+struct tconst {
+       int     op;
+       int     type;
+       _INT    value;
+};
+
+/*
+ * long constants
+ */
+struct lconst {
+       int     op;
+       int     type;
+       _LONG   lvalue;
+};
+
+/*
+ * Floating constants
+ */
+struct ftconst {
+       int     op;
+       int     type;
+       int     value;
+       _DOUBLE fvalue;
+};
+
+/*
+ * Node used for field assignments
+ */
+struct fasgn {
+       int     op;
+       int     type;
+       int     degree;
+       union   tree *tr1;
+       union   tree *tr2;
+       int     mask;
+};
+
+union  tree {
+       struct  tnode t;
+       struct tname n;
+       struct  xtname x;
+       struct  tconst c;
+       struct  lconst l;
+       struct  ftconst f;
+       struct  fasgn F;
+};
+
+struct optab {
+       char    tabdeg1;
+       char    tabtyp1;
+       char    tabdeg2;
+       char    tabtyp2;
+       char    *tabstring;
+};
+
+struct table {
+       int     tabop;
+       struct  optab *tabp;
+};
+
+struct instab {
+       int     iop;
+       char    *str1;
+       char    *str2;
+};
+
+struct swtab {
+       int     swlab;
+       int     swval;
+};
+
+extern char maprel[];
+extern char notrel[];
+extern int nreg;
+extern int isn;
+extern int line;
+extern int nerror;                     /* number of hard errors */
+extern struct table cctab[];
+extern struct table efftab[];
+extern struct table regtab[];
+extern struct table sptab[];
+extern struct table lsptab[1];
+extern char mov[];
+extern char clr[];
+extern char cmp[];
+extern char tst[];
+extern char add[];
+extern char sub[];
+extern char inc[];
+extern char dec[];
+extern char mul[];
+extern char _div[];
+extern char asr[];
+extern char ash[];
+extern char asl[];
+extern char bic[];
+extern char bic1[];
+extern char bit[];
+extern char bit1[];
+extern char bis[];
+extern char bis1[];
+extern char xor[];
+extern char neg[];
+extern char com[];
+extern char stdol[];
+extern char ashc[];
+extern char slmul[];
+extern char sldiv[];
+extern char slrem[];
+extern char uldiv[];
+extern char ulrem[];
+extern char ualdiv[];
+extern char ualrem[];
+extern char ultof[];
+extern char ulsh[];
+extern char ualsh[];
+extern char almul[];
+extern char aldiv[];
+extern char alrem[];
+extern char udiv[];
+extern char urem[];
+extern char jeq[];
+extern char jne[];
+extern char jle[];
+extern char jgt[];
+extern char jlt[];
+extern char jge[];
+extern char jlos[];
+extern char jhi[];
+extern char jlo[];
+extern char jhis[];
+extern char nop[];
+extern char jbr[];
+extern char jpl[];
+extern char jmi[];
+extern char jmijne[];
+extern char jmijeq[];
+extern struct instab instab[];
+extern struct instab branchtab[];
+extern int opdope[];
+extern char *opntab[];
+extern int nstack;
+extern int nfloat;
+extern struct tname sfuncr;
+extern char *funcbase;
+extern char *curbase;
+extern char *coremax;
+extern struct tconst czero, cone;
+extern long totspace;
+extern int regpanic;           /* set when SU register alg. fails */
+extern int panicposs;          /* set when there might be need for regpanic */
+extern jmp_buf jmpbuf;
+extern long ftell();
+extern char *sbrk();
+extern struct optab *match();
+extern union tree *optim();
+extern union tree *unoptim();
+extern union tree *pow2();
+extern union tree *tnode();
+extern union tree *sdelay();
+extern union tree *ncopy();
+extern union tree *getblk();
+extern union tree *strfunc();
+extern union tree *isconstant();
+extern union tree *tconst();
+extern union tree *hardlongs();
+extern union tree *lconst();
+extern union tree *acommute();
+extern union tree *lvfield();
+extern union tree *paint();
+extern long ftell();
+
+/*
+ * Some special stuff for long comparisons
+ */
+extern int xlab1, xlab2, xop, xzero;
+
+/*
+       operators
+*/
+#define        EOFC    0
+#define        SEMI    1
+#define        LBRACE  2
+#define        RBRACE  3
+#define        LBRACK  4
+#define        RBRACK  5
+#define        LPARN   6
+#define        RPARN   7
+#define        COLON   8
+#define        COMMA   9
+#define        FSEL    10
+#define        FSELR   11
+#define        FSELT   12
+#define        FSELA   16
+#define        ULSH    17
+#define        ASULSH  18
+
+#define        KEYW    19
+#define        NAME    20
+#define        CON     21
+#define        STRING  22
+#define        FCON    23
+#define        SFCON   24
+#define        LCON    25
+#define        SLCON   26
+
+#define        AUTOI   27
+#define        AUTOD   28
+#define        NULLOP  218
+#define        INCBEF  30
+#define        DECBEF  31
+#define        INCAFT  32
+#define        DECAFT  33
+#define        EXCLA   34
+#define        AMPER   35
+#define        STAR    36
+#define        NEG     37
+#define        COMPL   38
+
+#define        DOT     39
+#define        PLUS    40
+#define        MINUS   41
+#define        TIMES   42
+#define        DIVIDE  43
+#define        MOD     44
+#define        RSHIFT  45
+#define        LSHIFT  46
+#define        AND     47
+#define        ANDN    55
+#define        OR      48
+#define        EXOR    49
+#define        ARROW   50
+#define        ITOF    51
+#define        FTOI    52
+#define        LOGAND  53
+#define        LOGOR   54
+#define        FTOL    56
+#define        LTOF    57
+#define        ITOL    58
+#define        LTOI    59
+#define        ITOP    13
+#define        PTOI    14
+#define        LTOP    15
+
+#define        EQUAL   60
+#define        NEQUAL  61
+#define        LESSEQ  62
+#define        LESS    63
+#define        GREATEQ 64
+#define        GREAT   65
+#define        LESSEQP 66
+#define        LESSP   67
+#define        GREATQP 68
+#define        GREATP  69
+
+#define        ASPLUS  70
+#define        ASMINUS 71
+#define        ASTIMES 72
+#define        ASDIV   73
+#define        ASMOD   74
+#define        ASRSH   75
+#define        ASLSH   76
+#define        ASAND   77
+#define        ASOR    78
+#define        ASXOR   79
+#define        ASSIGN  80
+#define        TAND    81
+#define        LTIMES  82
+#define        LDIV    83
+#define        LMOD    84
+#define        ASANDN  85
+#define        LASTIMES 86
+#define        LASDIV  87
+#define        LASMOD  88
+
+#define        QUEST   90
+/* #define     MAX     93      not used; wanted macros in param.h */
+#define        MAXP    94
+/* #define     MIN     95      not used; wanted macros in param.h */
+#define        MINP    96
+#define        LLSHIFT 91
+#define        ASLSHL  92
+#define        SEQNC   97
+#define        CALL1   98
+#define        CALL2   99
+#define        CALL    100
+#define        MCALL   101
+#define        JUMP    102
+#define        CBRANCH 103
+#define        INIT    104
+#define        SETREG  105
+#define        LOAD    106
+#define        PTOI1   107
+#define        ITOC    109
+#define        RFORCE  110
+
+/*
+ * Intermediate code operators
+ */
+#define        BRANCH  111
+#define        LABEL   112
+#define        NLABEL  113
+#define        RLABEL  114
+#define        STRASG  115
+#define        STRSET  116
+#define        UDIV    117
+#define        UMOD    118
+#define        ASUDIV  119
+#define        ASUMOD  120
+#define        ULTIMES 121     /* present for symmetry */
+#define        ULDIV   122
+#define        ULMOD   123
+#define        ULASTIMES 124   /* present for symmetry */
+#define        ULASDIV 125
+#define        ULASMOD 126
+#define        ULTOF   127
+#define        ULLSHIFT 128    /* << for unsigned long */
+#define        UASLSHL 129     /* <<= for unsigned long */
+
+#define        BDATA   200
+#define        PROG    202
+#define        DATA    203
+#define        BSS     204
+#define        CSPACE  205
+#define        SSPACE  206
+#define        SYMDEF  207
+#define        SAVE    208
+#define        RETRN   209
+#define        EVEN    210
+#define        PROFIL  212
+#define        SWIT    213
+#define        EXPR    214
+#define        SNAME   215
+#define        RNAME   216
+#define        ANAME   217
+#define        SETSTK  219
+#define        SINIT   220
+#define        GLOBAL  221
+#define        C3BRANCH        222
+#define        ASSEM   223
+
+/*
+ *     types
+ */
+#define        INT     0
+#define        CHAR    1
+#define        FLOAT   2
+#define        DOUBLE  3
+#define        STRUCT  4
+#define        RSTRUCT 5
+#define        LONG    6
+#define        UNSIGN  7
+#define        UNCHAR  8
+#define        UNLONG  9
+#define        VOID    10
+
+#define        TYLEN   2
+#define        TYPE    017
+#define        XTYPE   (03<<4)
+#define        PTR     020
+#define        FUNC    040
+#define        ARRAY   060
+
+/*
+       storage classes
+*/
+#define        KEYWC   1
+#define        MOS     10
+#define        AUTO    11
+#define        EXTERN  12
+#define        STATIC  13
+#define        REG     14
+#define        STRTAG  15
+#define        ARG     16
+#define        OFFS    20
+#define        XOFFS   21
+#define        SOFFS   22
+
+/*
+       Flag    bits
+*/
+
+#define        BINARY  01
+#define        LVALUE  02
+#define        RELAT   04
+#define        ASSGOP  010
+#define        LWORD   020
+#define        RWORD   040
+#define        COMMUTE 0100
+#define        RASSOC  0200
+#define        LEAF    0400
+#define        CNVRT   01000
+
+#if 1 /* moved here from c12.c */
+#define        LSTSIZ  20
+struct acl {
+       int nextl;
+       int nextn;
+       union tree *nlist[LSTSIZ];
+       union tree *llist[LSTSIZ+1];
+};
+#endif
+
+#ifndef __P
+#ifdef __STDC__
+#define __P(args) args
+#else
+#define __P(args) ()
+#endif
+#endif
+
+/* c10.c */
+int main __P((int argc, char *argv[]));
+struct optab *match __P((union tree *tree, struct table *table, int nrleft, int nocvt));
+int rcexpr __P((union tree *atree, struct table *atable, int reg));
+int cexpr __P((register union tree *tree, struct table *table, int areg));
+int reorder __P((union tree **treep, struct table *table, int reg));
+int sreorder __P((union tree **treep, struct table *table, int reg, int recurf));
+int delay __P((union tree **treep, struct table *table, int reg));
+union tree *sdelay __P((union tree **ap));
+union tree *paint __P((register union tree *tp, register int type));
+union tree *ncopy __P((register union tree *p));
+int chkleaf __P((register union tree *tree, struct table *table, int reg));
+int comarg __P((register union tree *tree, int *flagp));
+union tree *strfunc __P((register union tree *tp));
+void doinit __P((register int type, register union tree *tree));
+void movreg __P((int r0, int r1, union tree *tree));
+
+/* c11.c */
+int degree __P((register union tree *t));
+void pname __P((register union tree *p, int flag));
+void pbase __P((register union tree *p));
+int xdcalc __P((register union tree *p, int nrleft));
+int dcalc __P((register union tree *p, int nrleft));
+int notcompat __P((register union tree *p, int ast, int deg, int op));
+int prins __P((int op, int c, struct instab *itable, int lbl));
+int collcon __P((register union tree *p));
+int isfloat __P((register union tree *t));
+int oddreg __P((register union tree *t, register int reg));
+int arlength __P((int t));
+void pswitch __P((struct swtab *afp, struct swtab *alp, int deflab));
+void breq __P((int v, int l));
+int sort __P((struct swtab *afp, struct swtab *alp));
+int ispow2 __P((register union tree *tree));
+union tree *pow2 __P((register union tree *tree));
+void cbranch __P((union tree *atree, register int lbl, int cond, register int reg));
+void branch __P((int lbl, int aop, int c));
+void longrel __P((union tree *atree, int lbl, int cond, int reg));
+int xlongrel __P((int f));
+void label __P((int l));
+void popstk __P((int a));
+void werror __P((char *s));
+void error __P((char *s, ...));
+void psoct __P((int an));
+void getree __P((void));
+int geti __P((void));
+void strasg __P((union tree *atp));
+int decref __P((register int t));
+int incref __P((register int t));
+
+/* c12.c */
+union tree *optim __P((register union tree *tree));
+union tree *unoptim __P((register union tree *tree));
+union tree *lvfield __P((register union tree *t));
+union tree *acommute __P((register union tree *tree));
+int sideeffects __P((register union tree *tp));
+void distrib __P((struct acl *list));
+void squash __P((union tree **p, union tree **maxp));
+void _const __P((int op, register _INT *vp, _INT v, int type));
+union tree *lconst __P((int op, register union tree *lp, register union tree *rp));
+void insert __P((int op, register union tree *tree, register struct acl *list));
+union tree *tnode __P((int op, int type, union tree *tr1, union tree *tr2));
+union tree *tconst __P((int val, int type));
+union tree *getblk __P((int size));
+int islong __P((int t));
+union tree *isconstant __P((register union tree *t));
+union tree *hardlongs __P((register union tree *t));
+int uns __P((union tree *tp));
+
+#ifndef pdp11
+/* fp.c */
+int fp_tst __P((_DOUBLE val));
+_DOUBLE fp_abs __P((_DOUBLE val));
+_DOUBLE fp_neg __P((_DOUBLE val));
+int fp_le __P((_DOUBLE val0, _DOUBLE val1));
+int fp_ge __P((_DOUBLE val0, _DOUBLE val1));
+int fp_gt __P((_DOUBLE val0, _DOUBLE val1));
+int fp_lt __P((_DOUBLE val0, _DOUBLE val1));
+_INT fp_double_to_int __P((_DOUBLE val));
+_LONG fp_double_to_long __P((_DOUBLE val));
+_FLOAT fp_double_to_float __P((_DOUBLE val));
+_DOUBLE fp_int_to_double __P((_INT val));
+_DOUBLE fp_long_to_double __P((_LONG val));
+_DOUBLE fp_float_to_double __P((_FLOAT val));
+_DOUBLE fp_add __P((_DOUBLE val0, _DOUBLE val1));
+_DOUBLE fp_sub __P((_DOUBLE val0, _DOUBLE val1));
+_DOUBLE fp_mul __P((_DOUBLE val0, _DOUBLE val1));
+_DOUBLE fp_div __P((_DOUBLE val0, _DOUBLE val1));
+_DOUBLE fp_ldexp __P((_DOUBLE val, _INT exp));
+
+/* fp_atof.c */
+_DOUBLE fp_atof __P((register char *p));
+#endif
+
+#endif
diff --git a/c10.c b/c10.c
new file mode 100644 (file)
index 0000000..8120924
--- /dev/null
+++ b/c10.c
@@ -0,0 +1,1382 @@
+/*
+ *             C compiler, part 2
+ * 
+ * (long)btodb(l) produced 'no code table error for op: >>(17) type: 6'
+ * allow both long and ulong at line ~341.  1996/6/19
+*/
+
+#if    !defined(lint) && defined(DOSCCS)
+static char    sccsid[] = "@(#)c10.c   2.1 (2.11BSD GTE) 10/4/94";
+#endif
+
+#include <stdlib.h>
+#include "c1.h"
+
+#ifdef DEBUG
+#define        dbprint(op)     printf("        / %s", opntab[op])
+#else
+#define        dbprint(op)     /* */
+#endif
+
+char   maprel[] = {    EQUAL, NEQUAL, GREATEQ, GREAT, LESSEQ,
+                       LESS, GREATQP, GREATP, LESSEQP, LESSP
+};
+
+char   notrel[] = {    NEQUAL, EQUAL, GREAT, GREATEQ, LESS,
+                       LESSEQ, GREATP, GREATQP, LESSP, LESSEQP
+};
+
+struct tconst czero = { CON, INT, 0};
+struct tconst cone  = { CON, INT, 1};
+
+struct tname sfuncr = { NAME, STRUCT, STATIC, 0, 0, 0 };
+
+struct table   *cregtab;
+
+int    nreg    = 3;
+int    isn     = 10000;
+
+int main(argc, argv) int argc; char *argv[]; {
+       char    buf1[BUFSIZ],
+               buf2[BUFSIZ];
+
+       if (argc<4) {
+               error("Arg count");
+               exit(1);
+       }
+       if (freopen(argv[1], "r", stdin)==NULL) {
+               error("Missing temp file");
+               exit(1);
+       }
+       setbuf(stdin,buf1);     /* sbrk problems */
+       if ((freopen(argv[3], "w", stdout)) == NULL) {
+               error("Can't create %s", argv[3]);
+               exit(1);
+       }
+       setbuf(stdout,buf2);    /* sbrk problems */
+       funcbase = curbase = coremax = sbrk(0);
+       getree();
+       /*
+        * If any floating-point instructions
+        * were used, generate a reference that
+        * pulls in the floating-point part of printf.
+        */
+       if (nfloat)
+               printf(".globl  fltused\n");
+       /*
+        * tack on the string file.
+        */
+       printf(".globl\n.data\n");
+       if (*argv[2] != '-') {
+               if (freopen(argv[2], "r", stdin)==NULL) {
+                       error("Missing temp file");
+                       exit(1);
+               }
+               setbuf(stdin,buf1);     /* sbrk problems */
+               getree();
+       }
+       if (totspace >= (_UNSIGNED_INT)56000)
+               werror("possibly too much data");
+       exit(nerror!=0);
+}
+
+/*
+ * Given a tree, a code table, and a
+ * count of available registers, find the code table
+ * for the appropriate operator such that the operands
+ * are of the right type and the number of registers
+ * required is not too large.
+ * Return a ptr to the table entry or 0 if none found.
+ */
+struct optab *match(tree, table, nrleft, nocvt) union tree *tree; struct table *table; int nrleft; int nocvt; {
+#define        NOCVL   1
+#define        NOCVR   2
+       int op, d1, d2, dope;
+       union tree *p2;
+       register union tree *p1;
+       register struct optab *opt;
+
+       if (tree==NULL)
+               return(NULL);
+       if (table==lsptab)
+               table = sptab;
+       if ((op = tree->t.op)==0)
+               return(0);
+       dope = opdope[op];
+       if ((dope&LEAF) == 0)
+               p1 = tree->t.tr1;
+       else
+               p1 = tree;
+       d1 = dcalc(p1, nrleft);
+       if ((dope&BINARY)!=0) {
+               p2 = tree->t.tr2;
+               /*
+                * If a subtree starts off with a conversion operator,
+                * try for a match with the conversion eliminated.
+                * E.g. int = double can be done without generating
+                * the converted int in a register by
+                * movf double,fr0; movfi fr0,int .
+                */
+               if (opdope[p2->t.op]&CNVRT && (nocvt&NOCVR)==0
+                        && (opdope[p2->t.tr1->t.op]&CNVRT)==0) {
+                       tree->t.tr2 = p2->t.tr1;
+                       if (opt = match(tree, table, nrleft, NOCVL))
+                               return(opt);
+                       tree->t.tr2 = p2;
+               } else if (opdope[p1->t.op]&CNVRT && (nocvt&NOCVL)==0
+                && (opdope[p1->t.tr1->t.op]&CNVRT)==0) {
+                       tree->t.tr1 = p1->t.tr1;
+                       if (opt = match(tree, table, nrleft, NOCVR))
+                               return(opt);
+                       tree->t.tr1 = p1;
+               }
+               d2 = dcalc(p2, nrleft);
+       }
+       for (; table->tabop!=op; table++)
+               if (table->tabop==0)
+                       return(0);
+       for (opt = table->tabp; opt->tabdeg1!=0; opt++) {
+               if (d1 > (opt->tabdeg1&077)
+                || (opt->tabdeg1 >= 0100 && (p1->t.op != STAR)))
+                       continue;
+               if (notcompat(p1, opt->tabtyp1, opt->tabdeg1, op))
+                       continue;
+               if ((opdope[op]&BINARY)!=0 && p2!=0) {
+                       if (d2 > (opt->tabdeg2&077)
+                        || (opt->tabdeg2 >= 0100) && (p2->t.op != STAR) )
+                               continue;
+                       if (notcompat(p2,opt->tabtyp2, opt->tabdeg2, 0))
+                               continue;
+                       if ((opt->tabdeg2&077)==20 && xdcalc(p2,nrleft)>20)
+                               continue;
+               }
+               return(opt);
+       }
+       return(0);
+}
+
+/*
+ * Given a tree, a code table, and a register,
+ * produce code to evaluate the tree with the appropriate table.
+ * Registers reg and upcan be used.
+ * If there is a value, it is desired that it appear in reg.
+ * The routine returns the register in which the value actually appears.
+ * This routine must work or there is an error.
+ * If the table called for is cctab, sptab, or efftab,
+ * and tree can't be done using the called-for table,
+ * another try is made.
+ * If the tree can't be compiled using cctab, regtab is
+ * used and a "tst" instruction is produced.
+ * If the tree can't be compiled using sptab,
+ * regtab is used and the register is pushed on the stack.
+ * If the tree can't be compiled using efftab,
+ * just use regtab.
+ * Regtab must succeed or an "op not found" error results.
+ *
+ * A number of special cases are recognized, and
+ * there is an interaction with the optimizer routines.
+ */
+int rcexpr(atree, atable, reg) union tree *atree; struct table *atable; int reg; {
+       register int r;
+       int modf, nargs, recurf;
+       register union tree *tree;
+       register struct table *table;
+
+ /*fprintf(stderr, "rcexpr(0x%08x, 0x%08x, 0x%08x)\n", atree, atable, reg);*/
+       table = atable;
+       recurf = 0;
+       if (reg<0) {
+               recurf++;
+               reg = ~reg;
+               if (reg>=020) {
+                       reg -= 020;
+                       recurf++;
+               }
+       }
+again:
+       if((tree=atree)==0)
+               return(0);
+       if (tree->t.type==VOID) {
+               if (table!=efftab)
+                       error("Illegal use of void");
+               tree->t.type = INT;
+       }
+       if (opdope[tree->t.op]&RELAT && tree->t.tr2->t.op==CON
+           && tree->t.tr2->c.value==0
+           && table==cctab)
+               tree = atree = tree->t.tr1;
+       /*
+        * fieldselect(...) : in efftab mode,
+        * ignore the select, otherwise
+        * do the shift and mask.
+        */
+       if (tree->t.op == FSELT) {
+               if (table==efftab)
+                       atree = tree = tree->t.tr1;
+               else {
+                       tree->t.op = FSEL;
+                       atree = tree = optim(tree);
+               }
+       }
+       switch (tree->t.op)  {
+
+       /*
+        * Structure assignments
+        */
+       case STRASG:
+               strasg(tree);
+               return(0);
+
+       /*
+        * An initializing expression
+        */
+       case INIT:
+               tree = optim(tree);
+               doinit(tree->t.type, tree->t.tr1);
+               return(0);
+
+       /*
+        * Put the value of an expression in r0,
+        * for a switch or a return
+        */
+       case RFORCE:
+               tree = tree->t.tr1;
+               if((r=rcexpr(tree, regtab, reg)) != 0)
+                       movreg(r, 0, tree);
+               return(0);
+
+       /*
+        * sequential execution
+        */
+       case SEQNC:
+               r = nstack;
+               rcexpr(tree->t.tr1, efftab, reg);
+               nstack = r;
+               atree = tree = tree->t.tr2;
+               goto again;
+
+       /*
+        * In the generated &~ operator,
+        * fiddle things so a PDP-11 "bit"
+        * instruction will be produced when cctab is used.
+        */
+       case ANDN:
+               if (table==cctab) {
+                       tree->t.op = TAND;
+                       tree->t.tr2 = optim(tnode(COMPL, tree->t.type, tree->t.tr2, TNULL));
+               }
+               break;
+
+       /*
+        * Handle a subroutine call. It has to be done
+        * here because if cexpr got called twice, the
+        * arguments might be compiled twice.
+        * There is also some fiddling so the
+        * first argument, in favorable circumstances,
+        * goes to (sp) instead of -(sp), reducing
+        * the amount of stack-popping.
+        */
+       case CALL:
+               r = 0;
+               nargs = 0;
+               modf = 0;
+#ifdef notdef
+               /*
+                * The following code would catch instances of foo(...) where
+                * "foo" was anything other than a simple name.  In particular
+                * f(...), (fp(...))(...) and (ffp(...))(...) where "f" is a
+                * pointer to a function, "fp" is a function returning a
+                * pointer to a function and "ffp" is a pointer to a function
+                * returning a pointer to a function.  The catch would among
+                * other things cause the (sp)/-(sp) stack optimization to
+                * stop working.  The compiler has been tested in all these
+                * different cases with the catch commented out and all the
+                * code generated was correct.  So what was it here for?
+                * If a strange error crops up, uncommenting the catch might
+                * be tried ...
+                */
+               if (tree->t.tr1->t.op!=NAME || tree->t.tr1->n.class!=EXTERN) {
+                       nargs++;
+                       nstack++;
+               }
+#endif
+               tree = tree->t.tr2;
+               if(tree->t.op) {
+                       while (tree->t.op==COMMA) {
+                               r += comarg(tree->t.tr2, &modf);
+                               tree = tree->t.tr1;
+                               nargs++;
+                       }
+                       r += comarg(tree, &modf);
+                       nargs++;
+               }
+               tree = atree;
+               tree->t.op = CALL2;
+               if (modf && tree->t.tr1->t.op==NAME
+                  && tree->t.tr1->n.class==EXTERN)
+                       tree->t.op = CALL1;
+               if (cexpr(tree, regtab, reg)<0)
+                       error("compiler botch: call");
+               popstk(r);
+               nstack -= nargs;
+               if (table==efftab || table==regtab)
+                       return(0);
+               r = 0;
+               goto fixup;
+
+       /*
+        * Longs need special treatment.
+        */
+       case ASULSH:    /* 18 */
+       case ULSH:      /* 17 */
+               if (tree->t.type != LONG && tree->t.type != UNLONG)
+                       break;
+               if (tree->t.tr2->t.op==ITOL)
+                       tree->t.tr2 = tree->t.tr2->t.tr1;
+               else
+                       tree->t.tr2 = optim(tnode(LTOI,INT,tree->t.tr2,TNULL));
+               if (tree->t.op==ASULSH)
+                       {
+                       tree->t.op = UASLSHL;
+                       tree->t.tr1 = tnode(AMPER, LONG+PTR, tree->t.tr1, TNULL);
+                       }
+               else
+                       tree->t.op = ULLSHIFT;
+               break;
+
+       case ASLSH:
+       case LSHIFT:
+               if (tree->t.type==LONG || tree->t.type==UNLONG) {
+                       if (tree->t.tr2->t.op==ITOL)
+                               tree->t.tr2 = tree->t.tr2->t.tr1;
+                       else
+                               tree->t.tr2 = optim(tnode(LTOI,INT,tree->t.tr2,TNULL));
+                       if (tree->t.op==ASLSH)
+                               tree->t.op = ASLSHL;
+                       else
+                               tree->t.op = LLSHIFT;
+               }
+               break;
+
+       /*
+        * Try to change * to shift.
+        */
+       case TIMES:
+       case ASTIMES:
+               tree = pow2(tree);
+       }
+       /*
+        * Try to find postfix ++ and -- operators that can be
+        * pulled out and done after the rest of the expression
+        */
+       if (table!=cctab && table!=cregtab && recurf<2
+        && (opdope[tree->t.op]&LEAF)==0) {
+               if (r=delay(&atree, table, reg)) {
+                       tree = atree;
+                       table = efftab;
+                       reg = r-1;
+               }
+       }
+       /*
+        * Basically, try to reorder the computation
+        * so  reg = x+y  is done as  reg = x; reg += y
+        */
+       if (recurf==0 && reorder(&atree, table, reg)) {
+               if (table==cctab && atree->t.op==NAME)
+                       return(reg);
+       }
+       tree = atree;
+       if (table==efftab && tree->t.op==NAME)
+               return(reg);
+       if ((r=cexpr(tree, table, reg))>=0) {
+               if (table==cregtab && (tree->t.op==INCAFT
+                   || tree->t.op==DECAFT || tree->t.op==TIMES))
+                       goto fixup;
+               return(r);
+       }
+       if (table!=regtab && (table!=cctab||(opdope[tree->t.op]&RELAT)==0)) {
+               if((r=cexpr(tree, regtab, reg))>=0) {
+       fixup:
+                       modf = isfloat(tree);
+                       dbprint(tree->t.op);
+                       if (table==sptab || table==lsptab) {
+                               if (tree->t.type==LONG || tree->t.type==UNLONG){
+                                       printf("mov\tr%d,-(sp)\n",r+1);
+                                       nstack++;
+                               }
+                               printf("mov%s   r%d,%s(sp)\n", modf=='f'?"f":"", r,
+                                       table==sptab? "-":"");
+                               nstack++;
+                       }
+                       if (table==cctab || table==cregtab)
+                               printf("tst%s   r%d\n", modf=='f'?"f":"", r);
+                       return(r);
+               }
+       }
+       /*
+        * Special grace for unsigned chars as right operands
+        */
+       if (opdope[tree->t.op]&BINARY && tree->t.tr2->t.type==UNCHAR) {
+               tree->t.tr2 = tnode(LOAD, UNSIGN, tree->t.tr2, TNULL);
+               return(rcexpr(tree, table, reg));
+       }
+       /*
+        * There's a last chance for this operator
+        */
+       if (tree->t.op==LTOI) {
+               r = rcexpr(tree->t.tr1, regtab, reg);
+               if (r >= 0) {
+                       r++;
+                       goto fixup;
+               }
+       }
+
+       r = tree->t.op;
+       if (tree->t.type == STRUCT)
+               error("Illegal operation on structure");
+       else if (r > 0 && r < UASLSHL && opntab[r])
+               error("No code table for op: %s(%d) type: %d", opntab[r], r,
+                       tree->t.type);
+       else
+               error("No code table for op %d", r);
+       return(reg);
+}
+
+/*
+ * Try to compile the tree with the code table using
+ * registers areg and up.  If successful,
+ * return the register where the value actually ended up.
+ * If unsuccessful, return -1.
+ *
+ * Most of the work is the macro-expansion of the
+ * code table.
+ */
+int cexpr(tree, table, areg) register union tree *tree; struct table *table; int areg; {
+       int c, r;
+       register union tree *p, *p1;
+       struct table *ctable;
+       union tree *p2;
+       char *string;
+       int reg, reg1, rreg, flag, opd;
+       struct optab *opt;
+
+       reg = areg;
+       p1 = tree->t.tr2;
+       c = tree->t.op;
+       opd = opdope[c];
+       /*
+        * When the value of a relational or a logical expression is
+        * desired, more work must be done.
+        */
+       if ((opd&RELAT||c==LOGAND||c==LOGOR||c==EXCLA) && table!=cctab) {
+               cbranch(tree, c=isn++, 1, reg);
+               rcexpr((union tree *)&czero, table, reg);
+               branch(isn, 0, 0);
+               label(c);
+               rcexpr((union tree *)&cone, table, reg);
+               label(isn++);
+               return(reg);
+       }
+       if(c==QUEST) {
+               if (table==cctab)
+                       return(-1);
+               cbranch(tree->t.tr1, c=isn++, 0, reg);
+               flag = nstack;
+               rreg = rcexpr(p1->t.tr1, table, reg);
+               nstack = flag;
+               branch(r=isn++, 0, 0);
+               label(c);
+               reg = rcexpr(p1->t.tr2, table, rreg);
+               if (rreg!=reg)
+                       movreg(reg, rreg, tree->t.tr2);
+               label(r);
+               return(rreg);
+       }
+       reg = oddreg(tree, reg);
+       reg1 = reg+1;
+       /*
+        * long values take 2 registers.
+        */
+       if ((tree->t.type==LONG||tree->t.type==UNLONG||opd&RELAT&&(tree->t.tr1->t.type==LONG||tree->t.tr1->t.type==UNLONG))
+          && tree->t.op!=ITOL)
+               reg1++;
+       /*
+        * Leaves of the expression tree
+        */
+       if ((r = chkleaf(tree, table, reg)) >= 0)
+               return(r);
+       /*
+        * x + (-1) is better done as x-1.
+        */
+       if (tree->t.op==PLUS||tree->t.op==ASPLUS) {
+               if ((p1=tree->t.tr2)->t.op==CON && p1->c.value==-1) {
+                       p1->c.value = -p1->c.value;
+                       tree->t.op += (MINUS-PLUS);
+               }
+       }
+       /*
+        * Because of a peculiarity of the PDP11 table
+        * char = *intreg++ and *--intreg cannot go through.
+        */
+       if (tree->t.tr2 && (tree->t.tr2->t.op==AUTOI||tree->t.tr2->t.op==AUTOD)
+        && (tree->t.tr1->t.type==CHAR || tree->t.tr1->t.type==UNCHAR)
+        && tree->t.tr2->t.type!=CHAR && tree->t.tr2->t.type!=UNCHAR)
+               tree->t.tr2 = tnode(LOAD, tree->t.tr2->t.type, tree->t.tr2, TNULL);
+       /*
+        * Another peculiarity of the PDP11 table manifested itself when
+        * amplifying the move3: table.  The same case which optimizes
+        * u_char to char moves is used to move a u_char to a register. This
+        * is wrong, leading to sign extension.  Rather than lose the ability
+        * to generate better code when moving a u_char to a char, a check 
+        * is made here to prevent sign extension.
+        *
+        * If the opcode is assign, the destination is a register and the
+        * source is u_char then do a conversion.
+        *
+        * u_char handling in the compiler is a bit awkward, it would be nice
+        * if %aub in the tables had a more unique meaning.
+       */
+       if (tree->t.tr2 && tree->t.tr1->t.op == NAME
+        && tree->t.tr1->n.class == REG && tree->t.op == ASSIGN
+        && tree->t.tr2->t.type == UNCHAR)
+               tree->t.tr2 = tnode(LOAD, UNSIGN, tree->t.tr2, TNULL);
+       if (table==cregtab)
+               table = regtab;
+       /*
+        * The following peculiar code depends on the fact that
+        * if you just want the codition codes set, efftab
+        * will generate the right code unless the operator is
+        * a shift or
+        * postfix ++ or --. Unravelled, if the table is
+        * cctab and the operator is not special, try first
+        * for efftab;  if the table isn't, if the operator is,
+        * or the first match fails, try to match
+        * with the table actually asked for.
+        */
+       /*
+        * Account for longs and oddregs; below is really
+        * r = nreg - reg - (reg-areg) - (reg1-reg-1);
+        */
+       r = nreg - reg + areg - reg1 + 1;
+       if (table!=cctab || c==INCAFT || c==DECAFT || tree->t.type==LONG || tree->t.type==UNLONG
+/*      || c==ASRSH || c==ASLSH || c==ASULSH || tree->t.tr1->t.type==UNCHAR */
+        || c==ASRSH || c==ASLSH || c==ASULSH
+        || (opt = match(tree, efftab, r, 0)) == 0)
+               if ((opt=match(tree, table, r, 0))==0)
+                       return(-1);
+       string = opt->tabstring;
+       p1 = tree->t.tr1;
+       if (p1->t.op==FCON && p1->f.value>0) {
+#ifdef pdp11
+/* nonportable */
+               printf(".data\nL%d:%o;%o;%o;%o\n.text\n", p1->f.value,
+                       ((_UNSIGNED_INT *)&(p1->f.fvalue))[0],
+                       ((_UNSIGNED_INT *)&(p1->f.fvalue))[1],
+                       ((_UNSIGNED_INT *)&(p1->f.fvalue))[2],
+                       ((_UNSIGNED_INT *)&(p1->f.fvalue))[3] );
+#else
+               printf(".data\nL%d:%o;%o;%o;%o\n.text\n", p1->f.value,
+                       (int)(p1->f.fvalue.h >> 16) & 0xffff,
+                       (int)p1->f.fvalue.h & 0xffff,
+                       (int)(p1->f.fvalue.l >> 16) & 0xffff,
+                       (int)p1->f.fvalue.l & 0xffff );
+#endif
+               p1->f/*c*/.value = -p1->f/*c*/.value;
+       }
+       p2 = 0;
+       if (opdope[tree->t.op]&BINARY) {
+               p2 = tree->t.tr2;
+               if (p2->t.op==FCON && p2->f.value>0) {
+#ifdef pdp11
+/* nonportable */
+                       printf(".data\nL%d:%o;%o;%o;%o\n.text\n", p2->f.value,
+                               ((_UNSIGNED_INT *)&(p2->f.fvalue))[0],
+                               ((_UNSIGNED_INT *)&(p2->f.fvalue))[1],
+                               ((_UNSIGNED_INT *)&(p2->f.fvalue))[2],
+                               ((_UNSIGNED_INT *)&(p2->f.fvalue))[3] );
+#else
+                       printf(".data\nL%d:%o;%o;%o;%o\n.text\n", p2->f.value,
+                               (int)(p2->f.fvalue.h >> 16) & 0xffff,
+                               (int)p2->f.fvalue.h & 0xffff,
+                               (int)(p2->f.fvalue.l >> 16) & 0xffff,
+                               (int)p2->f.fvalue.l & 0xffff );
+#endif
+                       p2->f.value = -p2->f.value;
+               }
+       }
+loop:
+       /*
+        * The 0200 bit asks for a tab.
+        */
+       if ((c = *string++) & 0200) {
+               c &= 0177;
+               putchar('\t');
+       }
+       switch (c) {
+
+       case '\n':
+               dbprint(tree->t.op);
+               break;
+
+       case '\0':
+               if (!isfloat(tree))
+                       if (tree->t.op==DIVIDE||tree->t.op==ASDIV)
+                               reg--;
+               if (table==regtab && (opdope[tree->t.op]&ASSGOP)) {
+                       if (tree->t.tr1->t.type==CHAR)
+                               printf("movb    r%d,r%d\n", reg, reg);
+               }
+               return(reg);
+
+       /* A1 */
+       case 'A':
+               p = p1;
+               goto adr;
+
+       /* A2 */
+       case 'B':
+               p = p2;
+               goto adr;
+
+       adr:
+               c = 0;
+               while (*string=='\'') {
+                       c++;
+                       string++;
+               }
+               if (*string=='+') {
+                       c = 100;
+                       string++;
+               }
+               pname(p, c);
+               goto loop;
+
+       /* I */
+       case 'M':
+               if ((c = *string)=='\'')
+                       string++;
+               else
+                       c = 0;
+               prins(tree->t.op, c, instab, 0);
+               goto loop;
+
+       /* B1 */
+       case 'C':
+               if ((opd&LEAF) != 0)
+                       p = tree;
+               else
+                       p = p1;
+               goto pbyte;
+
+       /* BF */
+       case 'P':
+               p = tree;
+               goto pb1;
+
+       /* B2 */
+       case 'D':
+               p = p2;
+       pbyte:
+               if (p->t.type==CHAR || p->t.type==UNCHAR)
+                       putchar('b');
+       pb1:
+               if (isfloat(p))
+                       putchar('f');
+               goto loop;
+
+       /* BE */
+       case 'L':
+               if (p1->t.type==CHAR || p2->t.type==CHAR
+                || p1->t.type==UNCHAR || p2->t.type==UNCHAR)
+                       putchar('b');
+               p = tree;
+               goto pb1;
+
+       /* F */
+       case 'G':
+               p = p1;
+               flag = 01;
+               goto subtre;
+
+       /* S */
+       case 'K':
+               p = p2;
+               flag = 02;
+               goto subtre;
+
+       /* H */
+       case 'H':
+               p = tree;
+               flag = 04;
+
+       subtre:
+               ctable = regtab;
+               if (flag&04)
+                       ctable = cregtab;
+               c = *string++ - 'A';
+               if (*string=='!') {
+                       string++;
+                       c |= 020;       /* force right register */
+               }
+               if (*string=='?') {
+                       string++;
+                       c |= 040;       /* force condition codes */
+               }
+               if ((c&02)!=0)
+                       ctable = sptab;
+               if ((c&04)!=0)
+                       ctable = cctab;
+               if ((flag&01) && ctable==regtab && (c&01)==0
+                 && ((c&040)||tree->t.op==DIVIDE||tree->t.op==MOD
+                  || tree->t.op==ASDIV||tree->t.op==ASMOD||tree->t.op==ITOL))
+                       ctable = cregtab;
+               if ((c&01)!=0) {
+                       p = p->t.tr1;
+                       if(collcon(p) && ctable!=sptab) {
+                               if (p->t.op==STAR)
+                                       p = p->t.tr1;
+                               p = p->t.tr1;
+                       }
+               }
+               if (table==lsptab && ctable==sptab)
+                       ctable = lsptab;
+               if (c&010)
+                       r = reg1;
+               else
+                       if (opdope[p->t.op]&LEAF || p->t.degree < 2)
+                               r = reg;
+                       else
+                               r = areg;
+               rreg = rcexpr(p, ctable, r);
+               if (ctable!=regtab && ctable!=cregtab)
+                       goto loop;
+               if (c&010) {
+                       if (c&020 && rreg!=reg1)
+                               movreg(rreg, reg1, p);
+                       else
+                               reg1 = rreg;
+               } else if (rreg!=reg)
+                       if ((c&020)==0 && oddreg(tree, 0)==0 && tree->t.type!=LONG
+                       && tree->t.type!=UNLONG
+                       && (flag&04
+                         || flag&01&&xdcalc(p2,nreg-rreg-1)<=(opt->tabdeg2&077)
+                         || flag&02&&xdcalc(p1,nreg-rreg-1)<=(opt->tabdeg1&077))) {
+                               reg = rreg;
+                               reg1 = rreg+1;
+                       } else
+                               movreg(rreg, reg, p);
+               goto loop;
+
+       /* R */
+       case 'I':
+               r = reg;
+               if (*string=='-') {
+                       string++;
+                       r--;
+               }
+               goto preg;
+
+       /* R1 */
+       case 'J':
+               r = reg1;
+       preg:
+               if (*string=='+') {
+                       string++;
+                       r++;
+               }
+               if (r>nreg || r>=4 && tree->t.type==DOUBLE) {
+                       if (regpanic)
+                               error("Register overflow: simplify expression");
+                       else
+                               longjmp(jmpbuf, 1);
+               }
+               printf("r%d", r);
+               goto loop;
+
+       case '-':               /* check -(sp) */
+               if (*string=='(') {
+                       nstack++;
+                       if (table!=lsptab)
+                               putchar('-');
+                       goto loop;
+               }
+               break;
+
+       case ')':               /* check (sp)+ */
+               putchar(')');
+               if (*string=='+')
+                       nstack--;
+               goto loop;
+
+       /* #1 */
+       case '#':
+               p = p1->t.tr1;
+               goto nmbr;
+
+       /* #2 */
+       case '"':
+               p = p2->t.tr1;
+
+       nmbr:
+               if(collcon(p)) {
+                       if (p->t.op==STAR) {
+                               printf("*");
+                               p = p->t.tr1;
+                       }
+                       if ((p = p->t.tr2)->t.op == CON) {
+                               if (p->c.value)
+                                       psoct(p->c.value);
+                       } else if (p->t.op==AMPER)
+                               pname(p->t.tr1, 0);
+               }
+               goto loop;
+
+       /*
+        * Certain adjustments for / %
+        */
+       case 'T':
+               c = reg-1;
+               if (uns(p1) || uns(p2)) {
+                       printf("clr     r%d\n", c);
+                       goto loop;
+               }
+               if (dcalc(p1, 5)>12 && !match(p1, cctab, 10, 0))
+                       printf("tst     r%d\n", reg);
+               printf("sxt     r%d\n", c);
+               goto loop;
+
+       case 'V':       /* adc sbc, clr, or sxt as required for longs */
+               switch(tree->t.op) {
+               case PLUS:
+               case ASPLUS:
+               case INCBEF:
+               case INCAFT:
+                       printf("adc");
+                       break;
+
+               case MINUS:
+               case ASMINUS:
+               case NEG:
+               case DECBEF:
+               case DECAFT:
+                       printf("sbc");
+                       break;
+
+               case ASSIGN:
+                       p = tree->t.tr2;
+                       goto lcasev;
+
+               case ASDIV:
+               case ASMOD:
+               case ASULSH:
+                       p = tree->t.tr1;
+               lcasev:
+                       if (p->t.type!=LONG && p->t.type!=UNLONG) {
+                               if (uns(p) || uns(tree->t.tr2))
+                                       printf("clr");
+                               else
+                                       printf("sxt");
+                               goto loop;
+                       }
+               default:
+                       while ((c = *string++)!='\n' && c!='\0');
+                       break;
+               }
+               goto loop;
+
+       /*
+        * Mask used in field assignments
+        */
+       case 'Z':
+               printf("$%o", UNS(tree->F.mask));
+               goto loop;
+
+       /*
+        * Relational on long values.
+        * Might bug out early. E.g.,
+        * (long<0) can be determined with only 1 test.
+        */
+       case 'X':
+               if (xlongrel(*string++ - '0'))
+                       return(reg);
+               goto loop;
+       }
+       putchar(c);
+       goto loop;
+}
+
+/*
+ * This routine just calls sreorder (below)
+ * on the subtrees and then on the tree itself.
+ * It returns non-zero if anything changed.
+ */
+int reorder(treep, table, reg) union tree **treep; struct table *table; int reg; {
+       register int r, o;
+       register union tree *p;
+
+       p = *treep;
+       o = p->t.op;
+       if (opdope[o]&LEAF||o==LOGOR||o==LOGAND||o==SEQNC||o==QUEST||o==COLON)
+               return(0);
+       while(sreorder(&p->t.tr1, regtab, reg, 1))
+               ;
+       if (opdope[o]&BINARY) 
+               while(sreorder(&p->t.tr2, regtab, reg, 1))
+                       ;
+       r = 0;
+       if (table!=cctab)
+       while (sreorder(treep, table, reg, 0))
+               r++;
+       *treep = optim(*treep);
+       return(r);
+}
+
+/*
+ * Basically this routine carries out two kinds of optimization.
+ * First, it observes that "x + (reg = y)" where actually
+ * the = is any assignment op is better done as "reg=y; x+reg".
+ * In this case rcexpr is called to do the first part and the
+ * tree is modified so the name of the register
+ * replaces the assignment.
+ * Moreover, expressions like "reg = x+y" are best done as
+ * "reg = x; reg += y" (so long as "reg" and "y" are not the same!).
+ */
+int sreorder(treep, table, reg, recurf) union tree **treep; struct table *table; int reg; int recurf; {
+       register union tree *p, *p1;
+
+       p = *treep;
+       if (opdope[p->t.op]&LEAF)
+               return(0);
+       if (p->t.op==PLUS && recurf)
+               if (reorder(&p->t.tr2, table, reg))
+                       *treep = p = optim(p);
+       if ((p1 = p->t.tr1)==TNULL)
+               return(0);
+       if (p->t.op==STAR || p->t.op==PLUS) {
+               if (recurf && reorder(&p->t.tr1, table, reg)) {
+                       *treep = p = optim(p);
+                       if (opdope[p->t.op]&LEAF)
+                               return(0);
+               }
+               p1 = p->t.tr1;
+       }
+       if (p1->t.op==NAME) switch(p->t.op) {
+               case ASLSH:
+               case ASRSH:
+               case ASSIGN:
+                       if (p1->n.class != REG || p1->n.type==CHAR
+                         || isfloat(p->t.tr2))
+                               return(0);
+                       if (p->t.op==ASSIGN) switch (p->t.tr2->t.op) {
+                       case RSHIFT:
+                               if (p->t.type==UNSIGN)
+                                       return(0);
+                               goto caseGEN;
+                       case TIMES:
+                               if (!ispow2(p->t.tr2))
+                                       break;
+                               p->t.tr2 = pow2(p->t.tr2);
+                       case PLUS:
+                       case MINUS:
+                       case AND:
+                       case ANDN:
+                       case OR:
+                       case EXOR:
+                       case LSHIFT:
+                       caseGEN:
+                               p1 = p->t.tr2->t.tr2;
+                               if (xdcalc(p1, 16) > 12
+                                || p1->t.op==NAME
+                                &&(p1->n.nloc==p->t.tr1->n.nloc
+                                 || p1->n.regno==p->t.tr1->n.nloc))
+                                       return(0);
+                               p1 = p->t.tr2;
+                               p->t.tr2 = p1->t.tr1;
+                               if (p1->t.tr1->t.op!=NAME
+                                || p1->t.tr1->n.class!=REG
+                                || p1->t.tr1->n.nloc!=p->t.tr1->n.nloc)
+                                       rcexpr(p, efftab, reg);
+                               p->t.tr2 = p1->t.tr2;
+                               p->t.op = p1->t.op + ASPLUS - PLUS;
+                               *treep = p;
+                               return(1);
+                       }
+                       goto OK;
+
+               case ASTIMES:
+                       if (!ispow2(p))
+                               return(0);
+               case ASPLUS:
+               case ASMINUS:
+               case ASAND:
+               case ASANDN:
+               case ASOR:
+               case ASXOR:
+               case INCBEF:
+               case DECBEF:
+               OK:
+                       if (table==cctab||table==cregtab)
+                               reg += 020;
+                       rcexpr(optim(p), efftab, ~reg);
+                       *treep = p1;
+                       return(1);
+       }
+       return(0);
+}
+
+/*
+ * Delay handles postfix ++ and -- 
+ * It observes that "x + y++" is better
+ * treated as "x + y; y++".
+ * If the operator is ++ or -- itself,
+ * it calls rcexpr to load the operand, letting
+ * the calling instance of rcexpr to do the
+ * ++ using efftab.
+ * Otherwise it uses sdelay to search for inc/dec
+ * among the operands.
+ */
+int delay(treep, table, reg) union tree **treep; struct table *table; int reg; {
+       register union tree *p, *p1;
+       register int r;
+
+       p = *treep;
+       if ((p->t.op==INCAFT||p->t.op==DECAFT)
+        && p->t.tr1->t.op==NAME) {
+               r = p->t.tr1->n.class;
+               if (r == EXTERN || r == OFFS || r == STATIC &&
+                               p->t.tr1->t.type == UNCHAR)
+                       return(1+rcexpr(p->t.tr1, table, reg));
+               else
+                       return(1+rcexpr(paint(p->t.tr1, p->t.type), table,reg));
+       }
+       p1 = 0;
+/*
+ * typo fix, original code.
+ *     if (opdope[p->t.op]&BINARY) {
+ *             if (p->t.op==LOGAND || p->t.op==LOGOR
+ *              || p->t.op==QUEST || p->t.op==COLON || p->t.op==SEQNC)
+ *                     return(0);
+ *             }
+ *             p1 = sdelay(&p->t.tr2);
+ *     if (p1==0)
+ *             p1 = sdelay(&p->t.tr1);
+ */
+       if (opdope[p->t.op]&BINARY) {
+               if (p->t.op==LOGAND || p->t.op==LOGOR
+                || p->t.op==QUEST || p->t.op==COLON || p->t.op==SEQNC)
+                       return(0);
+               p1 = sdelay(&p->t.tr2);
+       }
+       if (p1==0)
+               p1 = sdelay(&p->t.tr1);
+       if (p1) {
+               r = rcexpr(optim(p), table, reg);
+               *treep = p1;
+               return(r+1);
+       }
+       return(0);
+}
+
+union tree *sdelay(ap) union tree **ap; {
+       register union tree *p, *p1;
+
+       if ((p = *ap)==TNULL)
+               return(TNULL);
+       if ((p->t.op==INCAFT||p->t.op==DECAFT) && p->t.tr1->t.op==NAME) {
+               *ap = paint(ncopy(p->t.tr1), p->t.type);
+               return(p);
+       }
+       if (p->t.op==STAR || p->t.op==PLUS)
+               if (p1=sdelay(&p->t.tr1))
+                       return(p1);
+       if (p->t.op==PLUS)
+               return(sdelay(&p->t.tr2));
+       return(0);
+}
+
+/*
+ * Propagate possible implicit type-changing operation
+ */
+union tree *paint(tp, type) register union tree *tp; register int type; {
+
+       if (tp->t.type==type)
+               return(tp);
+       if (tp->t.type==CHAR && type==INT)
+               return(tp);
+       if (tp->t.type==CHAR || tp->t.type==UNCHAR)
+               return(optim(tnode(LOAD, type, tp, TNULL)));
+       tp->t.type = type;
+       if (tp->t.op==AMPER && type&XTYPE)
+               tp->t.tr1 = paint(tp->t.tr1, decref(type));
+       else if (tp->t.op==STAR)
+               tp->t.tr1 = paint(tp->t.tr1, incref(type));
+       else if (tp->t.op==ASSIGN) {
+               paint(tp->t.tr1, type);
+               paint(tp->t.tr2, type);
+       }
+       return(tp);
+}
+
+/*
+ * Copy a tree node for a register variable.
+ * Used by sdelay because if *reg-- is turned
+ * into *reg; reg-- the *reg will in turn
+ * be changed to some offset class, accidentally
+ * modifying the reg--.
+ */
+union tree *ncopy(p) register union tree *p; {
+       register union tree *q;
+
+       q = getblk(sizeof(struct xtname));
+       q->n.op = p->n.op;
+       q->n.type = p->n.type;
+       q->n.class = p->n.class;
+       q->n.regno = p->n.regno;
+       q->n.offset = p->n.offset;
+       if (q->n.class==EXTERN || q->n.class==XOFFS)
+               q->x.name = p->x.name;
+       else
+               q->n.nloc = p->n.nloc;
+       return(q);
+}
+
+/*
+ * If the tree can be immediately loaded into a register,
+ * produce code to do so and return success.
+ */
+int chkleaf(tree, table, reg) register union tree *tree; struct table *table; int reg; {
+       struct tnode lbuf;
+
+ /*fprintf(stderr, "chkleaf(0x%08x, 0x%08x, 0x%08x)\n", tree, table, reg);*/
+       if (tree->t.op!=STAR && dcalc(tree, nreg-reg) > 12)
+               return(-1);
+       lbuf.op = LOAD;
+       lbuf.type = tree->t.type;
+       lbuf.degree = tree->t.degree;
+       lbuf.tr1 = tree;
+#if 1 /* can't have garbage in lbuf.tr2, cexpr() will deref it if non-NULL */
+       lbuf.tr2 = NULL;
+#endif
+       return(rcexpr((union tree *)&lbuf, table, reg));
+}
+
+/*
+ * Compile a function argument.
+ * If the stack is currently empty, put it in (sp)
+ * rather than -(sp); this will save a pop.
+ * Return the number of bytes pushed,
+ * for future popping.
+ */
+int comarg(tree, flagp) register union tree *tree; int *flagp; {
+       register int retval;
+       int i;
+       int size;
+
+       if (tree->t.op==STRASG) {
+               size = tree->F.mask;
+               tree = tree->t.tr1;
+               tree = strfunc(tree);
+               if (size <= sizeof(_INT)) {
+                       paint(tree, INT);
+                       goto normal;
+               }
+               if (size <= sizeof(_LONG)) {
+                       paint(tree, LONG);
+                       goto normal;
+               }
+               if (tree->t.op!=NAME && tree->t.op!=STAR) {
+                       error("Unimplemented structure assignment");
+                       return(0);
+               }
+               tree = tnode(AMPER, STRUCT+PTR, tree, TNULL);
+               tree = tnode(PLUS, STRUCT+PTR, tree, tconst(size, INT));
+               tree = optim(tree);
+               retval = rcexpr(tree, regtab, 0);
+               size >>= 1;
+               if (size <= 5) {
+                       for (i=0; i<size; i++)
+                               printf("mov     -(r%d),-(sp)\n", retval);
+               } else {
+                       if (retval!=0)
+                               printf("mov     r%d,r0\n", retval);
+                       printf("mov     $%o,r1\n", UNS(size));
+                       printf("L%d:mov -(r0),-(sp)\ndec\tr1\njne\tL%d\n", isn, isn);
+                       isn++;
+               }
+               nstack++;
+               return(size*2);
+       }
+normal:
+       if (nstack || isfloat(tree) || tree->t.type==LONG || tree->t.type==UNLONG) {
+               rcexpr(tree, sptab, 0);
+               retval = arlength(tree->t.type);
+       } else {
+               (*flagp)++;
+               rcexpr(tree, lsptab, 0);
+               retval = 0;
+       }
+       return(retval);
+}
+
+union tree *strfunc(tp) register union tree *tp; {
+       if (tp->t.op != CALL)
+               return(tp);
+       paint(tp, STRUCT+PTR);
+       return(tnode(STAR, STRUCT, tp, TNULL));
+}
+
+/*
+ * Compile an initializing expression
+ */
+void doinit(type, tree) register int type; register union tree *tree; {
+       _FLOAT sfval;
+       _DOUBLE fval;
+       _LONG lval;
+
+       if (type==CHAR || type==UNCHAR) {
+               printf(".byte ");
+               if (tree->t.type&XTYPE)
+                       goto illinit;
+               type = INT;
+       }
+       if (type&XTYPE)
+               type = INT;
+       switch (type) {
+       case INT:
+       case UNSIGN:
+               if (tree->t.op==FTOI) {
+                       if (tree->t.tr1->t.op!=FCON && tree->t.tr1->t.op!=SFCON)
+                               goto illinit;
+                       tree = tree->t.tr1;
+#ifdef pdp11
+                       tree->c.value = tree->f.fvalue;
+#else
+                       tree->c.value = fp_double_to_int(tree->f.fvalue);
+#endif
+                       tree->t.op = CON;
+               } else if (tree->t.op==LTOI) {
+                       if (tree->t.tr1->t.op!=LCON)
+                               goto illinit;
+                       tree = tree->t.tr1;
+                       lval = tree->l.lvalue;
+                       tree->t.op = CON;
+                       tree->c.value = lval;
+               }
+               if (tree->t.op == CON)
+                       printf("%o\n", UNS(tree->c.value));
+               else if (tree->t.op==AMPER) {
+                       pname(tree->t.tr1, 0);
+                       putchar('\n');
+               } else
+                       goto illinit;
+               return;
+
+       case DOUBLE:
+       case FLOAT:
+               if (tree->t.op==ITOF) {
+                       if (tree->t.tr1->t.op==CON) {
+/* note: this should be changed to respect the signedness of the int */
+#ifdef pdp11
+                               fval = tree->t.tr1->c.value;
+#else
+                               fval = fp_int_to_double(tree->t.tr1->c.value);
+#endif
+                       } else
+                               goto illinit;
+               } else if (tree->t.op==FCON || tree->t.op==SFCON) {
+                       fval = tree->f.fvalue;
+               } else if (tree->t.op==LTOF) {
+                       if (tree->t.tr1->t.op!=LCON)
+                               goto illinit;
+/* note: this should be changed to respect the signedness of the long */
+#ifdef pdp11
+                       fval = tree->t.tr1->l.lvalue;
+#else
+                       fval = fp_long_to_double(tree->t.tr1->l.lvalue);
+#endif
+               } else
+                       goto illinit;
+               /* note: value is still in emulated r0 and used again below */
+               if (type==FLOAT) {
+#ifdef pdp11
+                       sfval = fval;
+/*nonportable*/
+                       printf("%o; %o\n",
+                               ((_UNSIGNED_INT *)&sfval)[0],
+                               ((_UNSIGNED_INT *)&sfval)[1]);
+#else
+                       sfval = fp_double_to_float(fval);
+                       printf("%o; %o\n",
+                               (int)(sfval.h >> 16) & 0xffff,
+                               (int)sfval.h & 0xffff);
+#endif
+               } else {
+#ifdef pdp11
+/* nonportable */
+                       printf("%o; %o; %o; %o\n",
+                               ((_UNSIGNED_INT *)&fval)[0],
+                               ((_UNSIGNED_INT *)&fval)[1],
+                               ((_UNSIGNED_INT *)&fval)[2],
+                               ((_UNSIGNED_INT *)&fval)[3]);
+#else
+                       printf("%o; %o; %o; %o\n",
+                               (int)(fval.h >> 16) & 0xffff,
+                               (int)fval.h & 0xffff,
+                               (int)(fval.l >> 16) & 0xffff,
+                               (int)fval.l & 0xffff);
+#endif
+               }
+               return;
+
+       case UNLONG:
+       case LONG:
+               if (tree->t.op==FTOL) {
+                       tree = tree->t.tr1;
+                       if (tree->t.op==SFCON)
+                               tree->t.op = FCON;
+                       if (tree->t.op!= FCON)
+                               goto illinit;
+#ifdef pdp11
+                       lval = tree->f.fvalue;
+#else
+                       lval = fp_double_to_long(tree->f.fvalue);
+#endif
+               } else if (tree->t.op==ITOL) {
+                       if (tree->t.tr1->t.op != CON)
+                               goto illinit;
+                       if (uns(tree->t.tr1))
+                               lval = (_UNSIGNED_INT)tree->t.tr1->c.value;
+                       else
+                               lval = tree->t.tr1->c.value;
+               } else if (tree->t.op==LCON) {
+                       lval = tree->l.lvalue;
+               } else
+                       goto illinit;
+/* nonportable */
+               printf("%o; %o\n", UNS((lval>>16)), UNS(lval));
+               return;
+       }
+illinit:
+       error("Illegal initialization");
+}
+
+void movreg(r0, r1, tree) int r0; int r1; union tree *tree; {
+       register char *s;
+       char c;
+
+       if (r0==r1)
+               return;
+       if (tree->t.type==LONG || tree->t.type == UNLONG) {
+               if (r0>=nreg || r1>=nreg) {
+                       error("register overflow: compiler error");
+               }
+               s = "mov        r%d,r%d\nmov    r%d,r%d\n";
+               if (r0 < r1)
+                       printf(s, r0+1,r1+1,r0,r1);
+               else
+                       printf(s, r0,r1,r0+1,r1+1);
+               return;
+       }
+       c = isfloat(tree);
+       printf("mov%.1s r%d,r%d\n", &c, r0, r1);
+}
diff --git a/c11.c b/c11.c
new file mode 100644 (file)
index 0000000..cf903af
--- /dev/null
+++ b/c11.c
@@ -0,0 +1,1190 @@
+/*
+ *  C compiler
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#define _va_start(ap, arg) va_start(ap, arg)
+#else
+#include <varargs.h>
+#define _va_start(ap, arg) va_start(ap)
+#endif
+#include "c1.h"
+
+static void outname __P((char *s));
+
+int degree(t) register union tree *t; {
+       register union tree *t1;
+
+       if (t==NULL || t->t.op==0)
+               return(0);
+       if (t->t.op == CON)
+               return(-3);
+       if (t->t.op == AMPER)
+               return(-2);
+       if (t->t.op==ITOL) {
+               if ((t1 = isconstant(t)) && (t1->c.value>=0 || uns(t1)))
+                       return(-2);
+               if (uns(t1 = t->t.tr1) && opdope[t1->t.op]&LEAF)
+                       return(-1);
+       }
+       if ((opdope[t->t.op] & LEAF) != 0) {
+               if (t->t.type==CHAR || t->t.type==UNCHAR || t->t.type==FLOAT)
+                       return(1);
+               return(0);
+       }
+       return(t->t.degree);
+}
+
+void pname(p, flag) register union tree *p; int flag; {
+       register int i;
+
+loop:
+       switch(p->t.op) {
+
+       case LCON:
+               printf("$%o", flag<=10? UNS(p->l.lvalue>>16):
+                  UNS(p->l.lvalue));
+               return;
+
+       case SFCON:
+       case CON:
+               printf("$");
+               psoct(p->c.value);
+               return;
+
+       case FCON:
+               printf("L%d", (p->c.value>0? p->c.value: -p->c.value));
+               return;
+
+       case NAME:
+               i = p->n.offset;
+               if (flag>10)
+                       i += 2;
+               if (i) {
+                       psoct(i);
+                       if (p->n.class!=OFFS)
+                               putchar('+');
+                       if (p->n.class==REG)
+                               error("Illegal use of register");
+               }
+               switch(p->n.class) {
+
+               case SOFFS:
+               case XOFFS:
+                       pbase(p);
+
+               case OFFS:
+                       printf("(r%d)", p->n.regno);
+                       return;
+
+               case EXTERN:
+               case STATIC:
+                       pbase(p);
+                       return;
+
+               case REG:
+                       printf("r%d", p->n.nloc);
+                       return;
+
+               }
+               error("Compiler error: pname");
+               return;
+
+       case AMPER:
+               putchar('$');
+               p = p->t.tr1;
+               if (p->t.op==NAME && p->n.class==REG)
+                       error("Illegal use of register");
+               goto loop;
+
+       case AUTOI:
+               printf("(r%d)%s", p->n.nloc, flag==1?"":"+");
+               return;
+
+       case AUTOD:
+               printf("%s(r%d)", flag==2?"":"-", p->n.nloc);
+               return;
+
+       case STAR:
+               p = p->t.tr1;
+               putchar('*');
+               goto loop;
+
+       }
+       error("compiler error: bad pname");
+}
+
+void pbase(p) register union tree *p; {
+
+       if (p->n.class==SOFFS || p->n.class==STATIC)
+               printf("L%d", p->n.nloc);
+       else
+               printf("%s", p->x.name);
+}
+
+int xdcalc(p, nrleft) register union tree *p; int nrleft; {
+       register int d;
+
+       if (p==NULL)
+               return(0);
+       d = dcalc(p, nrleft);
+       if (d<20 && (p->t.type==CHAR || p->t.type==UNCHAR)) {
+               if (nrleft>=1)
+                       d = 20;
+               else
+                       d = 24;
+       }
+       return(d);
+}
+
+int dcalc(p, nrleft) register union tree *p; int nrleft; {
+       register union tree *p1;
+
+       if (p==NULL)
+               return(0);
+       switch (p->t.op) {
+
+       case NAME:
+               if (p->n.class==REG && p->n.type!=CHAR && p->n.type!=UNCHAR)
+                       return(9);
+
+       case AMPER:
+       case FCON:
+       case LCON:
+       case AUTOI:
+       case AUTOD:
+               return(12);
+
+       case CON:
+       case SFCON:
+               if (p->c.value==0)
+                       return(4);
+               if (p->c.value==1)
+                       return(5);
+               if (p->c.value > 0)
+                       return(8);
+               return(12);
+
+       case STAR:
+               p1 = p->t.tr1;
+               if (p1->t.op==NAME||p1->t.op==CON||p1->t.op==AUTOI||p1->t.op==AUTOD)
+                       if (p->t.type!=LONG && p->t.type!=UNLONG)
+                               return(12);
+       }
+       if (p->t.type==LONG || p->t.type==UNLONG)
+               nrleft--;
+       return(p->t.degree <= nrleft? 20: 24);
+}
+
+int notcompat(p, ast, deg, op) register union tree *p; int ast; int deg; int op; {
+       unsigned register at, st;
+
+       at = p->t.type;
+       /*
+        * an e or n UNCHAR is to be considered an UNSIGNED,
+        * as long as it is not pointed to.
+        */
+       if (at==UNCHAR && deg<0100 && deg>=20)
+               at = UNSIGN;
+       st = ast;
+       if (st==0)              /* word, byte */
+               return(at!=CHAR && at!=INT && at!=UNSIGN && at<PTR);
+       if (st==1)              /* word */
+               return(at!=INT && at!=UNSIGN && at<PTR);
+       if (st==9 && (at&XTYPE))
+               return(0);
+       st -= 2;
+       if ((at&(~(TYPE+XTYPE))) != 0)
+               at = 020;
+       if ((at&(~TYPE)) != 0)
+               at = at&TYPE | 020;
+       if (st==FLOAT && at==DOUBLE)
+               at = FLOAT;
+       if (p->t.op==NAME && p->n.class==REG && op==ASSIGN && st==CHAR)
+               return(0);
+       return(st != at);
+}
+
+int prins(op, c, itable, lbl) int op; int c; struct instab *itable; int lbl; {
+       register struct instab  *insp;
+       register char   *ip;
+       register int    skip;
+
+       skip = 0;
+       for (insp = itable; insp->iop != 0; insp++) {
+               if (insp->iop == op) {
+                       ip = c ? insp->str2: insp->str1;
+                       if (!ip)
+                               break;
+                       if (ip != jmijne) {
+                               printf(ip, lbl);
+                       }
+                       else {
+                               skip = isn++;
+                               printf(ip, skip);
+                       }
+                       return(skip);
+               }
+       }
+       error("No match' for op %d", op);
+       return(skip);
+}
+
+int collcon(p) register union tree *p; {
+       register int op;
+
+       if (p==NULL)
+               return(0);
+       if (p->t.op==STAR) {
+               if (p->t.type==LONG+PTR || p->t.type==UNLONG+PTR) /* avoid *x(r); *x+2(r) */
+                       return(0);
+               p = p->t.tr1;
+       }
+       if (p->t.op==PLUS) {
+               op = p->t.tr2->t.op;
+               if (op==CON || op==AMPER)
+                       return(1);
+       }
+       return(0);
+}
+
+int isfloat(t) register union tree *t; {
+
+       if ((opdope[t->t.op]&RELAT)!=0)
+               t = t->t.tr1;
+       if (t->t.type==FLOAT || t->t.type==DOUBLE) {
+               nfloat = 1;
+               return('f');
+       }
+       return(0);
+}
+
+int oddreg(t, reg) register union tree *t; register int reg; {
+
+       if (!isfloat(t)) {
+               if (opdope[t->t.op]&RELAT) {
+                       if (t->t.tr1->t.type==LONG || t->t.tr1->t.type==UNLONG)
+                               return((reg+1) & ~01);
+                       return(reg);
+               }
+               switch(t->t.op) {
+               case ULLSHIFT:
+               case UASLSHL:
+               case LLSHIFT:
+               case ASLSHL:
+               case PTOI:
+                       return((reg+1)&~01);
+
+               case DIVIDE:
+               case MOD:
+               case ASDIV:
+               case ASMOD:
+               case ULSH:
+               case ASULSH:
+                       reg++;
+
+               case TIMES:
+               case ASTIMES:
+                       return(reg|1);
+               }
+       }
+       return(reg);
+}
+
+int arlength(t) int t; {
+       if (t>=PTR)
+               return(2);
+       switch(t) {
+
+       case INT:
+       case CHAR:
+       case UNSIGN:
+       case UNCHAR:
+               return(2);
+
+       case UNLONG:
+       case LONG:
+               return(4);
+
+       case FLOAT:
+       case DOUBLE:
+               return(8);
+       }
+       error("botch: peculiar type %d", t);
+       return(1024);
+}
+
+/*
+ * Strings for switch code.
+ */
+
+/*
+ * Modified Memorial day May 80 to uniquely identify switch tables
+ * (as on Vax) so a shell script can optionally include them in RO code.
+ * This is useful in overlays to reduce the size of data space load.
+ * wfj 5/80 
+ */
+char   dirsw[] = {"\
+cmp    r0,$%o\n\
+jhi    L%d\n\
+asl    r0\n\
+jmp    *L%d(r0)\n\
+\t.data\n\
+L%d:\
+" };
+
+char   hashsw[] = {"\
+mov    r0,r1\n\
+clr    r0\n\
+div    $%o,r0\n\
+asl    r1\n\
+jmp    *L%d(r1)\n\
+\t.data\n\
+L%d:\
+"};
+
+/*
+ * If the unsigned casts below won't compile,
+ * try using the calls to lrem and ldiv.
+ */
+
+void pswitch(afp, alp, deflab) struct swtab *afp; struct swtab *alp; int deflab; {
+       int ncase, i, j, tabs, worst, best, range;
+       register struct swtab *swp, *fp, *lp;
+       int *poctab;
+
+       fp = afp;
+       lp = alp;
+       if (fp==lp) {
+               printf("jbr     L%d\n", deflab);
+               return;
+       }
+       isn++;
+       if (sort(fp, lp))
+               return;
+       ncase = lp-fp;
+       lp--;
+       range = lp->swval - fp->swval;
+       /* direct switch */
+       if (range>0 && range <= 3*ncase) {
+               if (fp->swval)
+                       printf("sub     $%o,r0\n", UNS(fp->swval));
+               printf(dirsw, UNS(range), deflab, isn, isn);
+               isn++;
+               for (i=fp->swval; ; i++) {
+                       if (i==fp->swval) {
+                               printf("L%d\n", fp->swlab);
+                               if (fp==lp)
+                                       break;
+                               fp++;
+                       } else
+                               printf("L%d\n", deflab);
+               }
+               printf(".text\n");
+               return;
+       }
+       /* simple switch */
+       if (ncase<10) {
+               for (fp = afp; fp<=lp; fp++)
+                       breq(fp->swval, fp->swlab);
+               printf("jbr     L%d\n", deflab);
+               return;
+       }
+       /* hash switch */
+       best = 077777;
+       poctab = (int *)getblk(((ncase+2)/2) * sizeof(*poctab));
+       for (i=ncase/4; i<=ncase/2; i++) {
+               for (j=0; j<i; j++)
+                       poctab[j] = 0;
+               for (swp=fp; swp<=lp; swp++)
+                       /* lrem(0, swp->swval, i) */
+                       poctab[(_UNSIGNED_INT)swp->swval%i]++;
+               worst = 0;
+               for (j=0; j<i; j++)
+                       if (poctab[j]>worst)
+                               worst = poctab[j];
+               if (i*worst < best) {
+                       tabs = i;
+                       best = i*worst;
+               }
+       }
+       i = isn++;
+       printf(hashsw, UNS(tabs), i, i);
+       isn++;
+       for (i=0; i<tabs; i++)
+               printf("L%d\n", isn+i);
+       printf(".text\n");
+       for (i=0; i<tabs; i++) {
+               printf("L%d:", isn++);
+               for (swp=fp; swp<=lp; swp++) {
+                       /* lrem(0, swp->swval, tabs) */
+                       if ((_UNSIGNED_INT)swp->swval%tabs == i) {
+                               /* ldiv(0, swp->swval, tabs) */
+                               breq((int)((_UNSIGNED_INT)swp->swval/tabs), swp->swlab);
+                       }
+               }
+               printf("jbr     L%d\n", deflab);
+       }
+}
+
+void breq(v, l) int v; int l; {
+       if (v==0)
+               printf("tst     r0\n");
+       else
+               printf("cmp     r0,$%o\n", UNS(v));
+       printf("jeq     L%d\n", l);
+}
+
+int sort(afp, alp) struct swtab *afp; struct swtab *alp; {
+       register struct swtab *cp, *fp, *lp;
+       int intch, t;
+
+       fp = afp;
+       lp = alp;
+       while (fp < --lp) {
+               intch = 0;
+               for (cp=fp; cp<lp; cp++) {
+                       if (cp->swval == cp[1].swval) {
+                               error("Duplicate case (%d)", cp->swval);
+                               return(1);
+                       }
+                       if (cp->swval > cp[1].swval) {
+                               intch++;
+                               t = cp->swval;
+                               cp->swval = cp[1].swval;
+                               cp[1].swval = t;
+                               t = cp->swlab;
+                               cp->swlab = cp[1].swlab;
+                               cp[1].swlab = t;
+                       }
+               }
+               if (intch==0)
+                       break;
+       }
+       return(0);
+}
+
+int ispow2(tree) register union tree *tree; {
+       register int d;
+
+       if (!isfloat(tree) && tree->t.tr2->t.op==CON) {
+               d = tree->t.tr2->c.value;
+               if (d>1 && (d&(d-1))==0)
+                       return(d);
+       }
+       return(0);
+}
+
+union tree *pow2(tree) register union tree *tree; {
+       register int d, i;
+
+       if (d = ispow2(tree)) {
+               for (i=0; (d>>=1)!=0; i++);
+               tree->t.tr2->c.value = i;
+               switch (tree->t.op) {
+
+               case TIMES:
+                       tree->t.op = LSHIFT;
+                       break;
+
+               case ASTIMES:
+                       tree->t.op = ASLSH;
+                       break;
+
+               case PTOI:
+                       if (i==1 && tree->t.tr1->t.op==MINUS && !isconstant(tree->t.tr1->t.tr2)) {
+                               tree->t.op = PTOI1;
+                               tree->t.tr1 = tnode(LTOI, INT, tree->t.tr1, TNULL);
+                               return(optim(tree));
+                       }
+                       tree->t.op = LLSHIFT;
+                       tree->t.tr2->c.value = -i;
+                       i = tree->t.type;
+                       tree->t.type = LONG;
+                       tree = tnode(LTOI, i, tree, TNULL);
+                       break;
+
+               case DIVIDE:
+                       tree->t.op = ULSH;
+                       tree->t.tr2->c.value = -i;
+                       break;
+
+               case ASDIV:
+                       tree->t.op = ASULSH;
+                       tree->t.tr2->c.value = -i;
+                       break;
+
+               case MOD:
+                       tree->t.op = AND;
+                       tree->t.tr2->c.value = (1<<i)-1;
+                       break;
+
+               case ASMOD:
+                       tree->t.op = ASAND;
+                       tree->t.tr2->c.value = (1<<i)-1;
+                       break;
+
+               default:
+                       error("pow2 botch");
+               }
+               tree = optim(tree);
+       }
+       return(tree);
+}
+
+void cbranch(atree, lbl, cond, reg) union tree *atree; register int lbl; int cond; register int reg; {
+       int l1, op;
+       register union tree *tree;
+
+again:
+       if ((tree=atree)==NULL)
+               return;
+       switch(tree->t.op) {
+
+       case LOGAND:
+               if (cond) {
+                       cbranch(tree->t.tr1, l1=isn++, 0, reg);
+                       cbranch(tree->t.tr2, lbl, 1, reg);
+                       label(l1);
+               } else {
+                       cbranch(tree->t.tr1, lbl, 0, reg);
+                       cbranch(tree->t.tr2, lbl, 0, reg);
+               }
+               return;
+
+       case LOGOR:
+               if (cond) {
+                       cbranch(tree->t.tr1, lbl, 1, reg);
+                       cbranch(tree->t.tr2, lbl, 1, reg);
+               } else {
+                       cbranch(tree->t.tr1, l1=isn++, 1, reg);
+                       cbranch(tree->t.tr2, lbl, 0, reg);
+                       label(l1);
+               }
+               return;
+
+       case EXCLA:
+               cbranch(tree->t.tr1, lbl, !cond, reg);
+               return;
+
+       case SEQNC:
+               rcexpr(tree->t.tr1, efftab, reg);
+               atree = tree->t.tr2;
+               goto again;
+
+       case ITOL:
+               tree = tree->t.tr1;
+               break;
+
+       case QUEST:
+               l1 = isn;
+               isn += 2;
+               cbranch(tree->t.tr1, l1, 0, reg);
+               cbranch(tree->t.tr2->t.tr1, lbl, cond, reg);
+               branch(l1+1, 0, 0);
+               label(l1);
+               cbranch(tree->t.tr2->t.tr2, lbl, cond, reg);
+               label(l1+1);
+               return;
+
+       }
+       op = tree->t.op;
+       if (opdope[op]&RELAT
+        && tree->t.tr1->t.op==ITOL && tree->t.tr2->t.op==ITOL
+        && uns(tree->t.tr1->t.tr1) == uns(tree->t.tr2->t.tr1)) {
+               tree->t.tr1 = tree->t.tr1->t.tr1;
+               tree->t.tr2 = tree->t.tr2->t.tr1;
+               if (op>=LESSEQ && op<=GREAT
+                && uns(tree->t.tr1))
+                       tree->t.op = op = op+LESSEQP-LESSEQ;
+       }
+       if (tree->t.type==LONG || tree->t.type==UNLONG
+         || opdope[op]&RELAT&&(tree->t.tr1->t.type==LONG || tree->t.tr1->t.type==UNLONG)) {
+               longrel(tree, lbl, cond, reg);
+               return;
+       }
+       rcexpr(tree, cctab, reg);
+       op = tree->t.op;
+       if ((opdope[op]&RELAT)==0)
+               op = NEQUAL;
+       else {
+               l1 = tree->t.tr2->t.op;
+               if ((l1==CON || l1==SFCON) && tree->t.tr2->c.value==0)
+                       op += 200;              /* special for ptr tests */
+               else
+                       op = maprel[op-EQUAL];
+       }
+       if (isfloat(tree))
+               printf("cfcc\n");
+       branch(lbl, op, !cond);
+}
+
+void branch(lbl, aop, c) int lbl; int aop; int c; {
+       register int    op,
+                       skip;
+
+       if(op = aop) {
+               skip = prins(op, c, branchtab, lbl);
+       } else {
+               printf("jbr");
+               skip = 0;
+       }
+       if (skip)
+               printf("\tL%d\nL%d:", lbl, skip);
+       else
+               printf("\tL%d\n", lbl);
+}
+
+void longrel(atree, lbl, cond, reg) union tree *atree; int lbl; int cond; int reg; {
+       int xl1, xl2, xo, xz;
+       register int op, isrel;
+       register union tree *tree;
+
+       if (reg&01)
+               reg++;
+       reorder(&atree, cctab, reg);
+       tree = atree;
+       isrel = 0;
+       if (opdope[tree->t.op]&RELAT) {
+               isrel++;
+               op = tree->t.op;
+       } else
+               op = NEQUAL;
+       if (!cond)
+               op = notrel[op-EQUAL];
+       xl1 = xlab1;
+       xl2 = xlab2;
+       xo = xop;
+       xlab1 = lbl;
+       xlab2 = 0;
+       xop = op;
+       xz = xzero;
+       xzero = !isrel || (tree->t.tr2->t.op==ITOL && tree->t.tr2->t.tr1->t.op==CON
+               && tree->t.tr2->t.tr1->c.value==0);
+       if (tree->t.op==ANDN) {
+               tree->t.op = TAND;
+               tree->t.tr2 = optim(tnode(COMPL, LONG, tree->t.tr2, TNULL));
+       }
+       if (cexpr(tree, cctab, reg) < 0) {
+               reg = rcexpr(tree, regtab, reg);
+               printf("ashc    $0,r%d\n", reg);
+               branch(xlab1, op, 0);
+       }
+       xlab1 = xl1;
+       xlab2 = xl2;
+       xop = xo;
+       xzero = xz;
+}
+
+/*
+ * Tables for finding out how best to do long comparisons.
+ * First dimen is whether or not the comparison is with 0.
+ * Second is which test: e.g. a>b->
+ *     cmp     a,b
+ *     bgt     YES             (first)
+ *     blt     NO              (second)
+ *     cmp     a+2,b+2
+ *     bhi     YES             (third)
+ *  NO:        ...
+ * Note some tests may not be needed.
+ *
+ * EQUAL = 60
+ * NEQUAL= 61
+ * LESSEQ= 62
+ * LESS  = 63
+ * GREATEQ=64
+ * GREAT  =65
+ * LESSEQP=66
+ * LESSP  =67
+ * GREATQP=68
+ * GREATP =69
+ *
+ * Third dimension (lrtab[][][x]) indexed by "x - EQUAL".
+ */
+char   lrtab[2][3][10] = {
+       {
+               {0, NEQUAL, LESS, LESS, GREAT, GREAT, LESSP, LESSP, GREATP, GREATP},
+               {NEQUAL,        0, GREAT, GREAT, LESS, LESS, GREATP, GREATP, LESSP, LESSP},
+               {EQUAL,NEQUAL,LESSEQP,LESSP, GREATQP,GREATP,LESSEQP,LESSP,GREATQP,GREATP}
+       },
+       {
+               {0, NEQUAL, LESS, LESS, GREATEQ,GREAT, LESSP, LESSP, GREATQP, GREATP},
+               {NEQUAL,        0, GREAT, 0, 0, LESS, GREATP, 0, 0, LESSP},
+               {EQUAL, NEQUAL, EQUAL,  0, 0, NEQUAL, EQUAL, 0, 0, NEQUAL}
+       }
+};
+
+int xlongrel(f) int f; {
+       register int op, bno;
+
+       op = xop;
+       if (f==0) {
+               if (bno = lrtab[xzero][0][op-EQUAL])
+                       branch(xlab1, bno, 0);
+               if (bno = lrtab[xzero][1][op-EQUAL]) {
+                       xlab2 = isn++;
+                       branch(xlab2, bno, 0);
+               }
+               if (lrtab[xzero][2][op-EQUAL]==0)
+                       return(1);
+       } else {
+               branch(xlab1, lrtab[xzero][2][op-EQUAL], 0);
+               if (xlab2)
+                       label(xlab2);
+       }
+       return(0);
+}
+
+void label(l) int l; {
+       printf("L%d:", l);
+}
+
+void popstk(a) int a; {
+       switch(a) {
+
+       case 0:
+               return;
+
+       case 2:
+               printf("tst     (sp)+\n");
+               return;
+
+       case 4:
+               printf("cmp     (sp)+,(sp)+\n");
+               return;
+       }
+       printf("add     $%o,sp\n", UNS(a));
+}
+
+void werror(s) char *s; {
+
+       fprintf(stderr, "%d: %s\n",line,s);
+}
+
+#ifdef __STDC__
+void error(char *s, ...)
+#else
+void error(s, va_alist) char *s; va_dcl
+#endif
+{
+       va_list ap;
+
+       nerror++;
+       fprintf(stderr, "%d: ", line);
+       _va_start(ap, s);
+       vfprintf(stderr, s, ap);
+       va_end(ap);
+       putc('\n', stderr);
+}      
+
+void psoct(an) int an; {
+       register int n;
+       register char *sign;
+
+       sign = "";
+       if ((n = an) < 0) {
+               n = -n;
+               sign = "-";
+       }
+       printf("%s%o", sign, n);
+}
+
+/*
+ * Read in an intermediate file.
+ */
+#define        STKS    100
+void getree() {
+       union tree *expstack[STKS], **sp;
+       register union tree *tp;
+       register int t, op;
+       char s[80];             /* big for asm() stuff & long variable names */
+       struct swtab *swp;
+       long outloc;
+       int lbl, cond, lbl2, lbl3;
+
+       curbase = funcbase;
+       sp = expstack;
+       for (;;) {
+               if (sp >= &expstack[STKS])
+                       error("Stack overflow botch");
+               op = geti();
+               if ((op&0177400) != 0177000) {
+                       error("Intermediate file error");
+                       exit(1);
+               }
+               lbl = 0;
+               switch(op &= 0377) {
+
+       case SINIT:
+               printf("%o\n", UNS(geti()));
+               break;
+
+       case EOFC:
+               return;
+
+       case BDATA:
+               if (geti() == 1) {
+                       printf(".byte ");
+                       for (;;)  {
+                               printf("%o", UNS(geti()));
+                               if (geti() != 1)
+                                       break;
+                               printf(",");
+                       }
+                       printf("\n");
+               }
+               break;
+
+       case PROG:
+               printf(".text\n");
+               break;
+
+       case DATA:
+               printf(".data\n");
+               break;
+
+       case BSS:
+               printf(".bss\n");
+               break;
+
+       case SYMDEF:
+               outname(s);
+               printf(".globl\t%s\n", s);
+               sfuncr.nloc = 0;
+               break;
+
+       case RETRN:
+               printf("jmp\tcret\n");
+               break;
+
+       case CSPACE:
+               outname(s);
+               printf(".comm\t%s,%o\n", s, UNS(geti()));
+               break;
+
+       case SSPACE:
+               printf(".=.+%o\n", UNS(t=geti()));
+               totspace += (_UNSIGNED_INT)t;
+               break;
+
+       case EVEN:
+               printf(".even\n");
+               break;
+
+       case SAVE:
+               printf("jsr     r5,csv\n");
+               break;
+
+       case SETSTK:
+               t = geti();
+               if (t==2)
+                       printf("tst     -(sp)\n");
+               else if (t != 0)
+                       printf("sub     $%o,sp\n", UNS(t));
+               break;
+
+       case PROFIL:
+               t = geti();
+               outname(s);
+               printf("mov     $L%d,r0\njsr    pc,mcount\n", t);
+               printf(".data\nL%d:%s+1\n.text\n", t, s);
+               break;
+
+       case ASSEM:
+               outname(s);
+               printf("%s\n", s);
+               break;
+
+       case SNAME:
+               outname(s);
+               printf("~%s=L%d\n", s+1, geti());
+               break;
+
+       case ANAME:
+               outname(s);
+               printf("~%s=%o\n", s+1, UNS(geti()));
+               break;
+
+       case RNAME:
+               outname(s);
+               printf("~%s=r%d\n", s+1, geti());
+               break;
+
+       case SWIT:
+               t = geti();
+               line = geti();
+               curbase = funcbase;
+               while(swp=(struct swtab *)getblk(sizeof(*swp)), swp->swlab = geti())
+                       swp->swval = geti();
+               pswitch((struct swtab *)funcbase, swp, t);
+               break;
+
+       case C3BRANCH:          /* for fortran [sic] */
+               lbl = geti();
+               lbl2 = geti();
+               lbl3 = geti();
+               goto xpr;
+
+       case CBRANCH:
+               lbl = geti();
+               cond = geti();
+
+       case EXPR:
+       xpr:
+               line = geti();
+               if (sp != &expstack[1]) {
+                       error("Expression input botch");
+                       exit(1);
+               }
+               --sp;
+               regpanic = 0;
+               if (setjmp(jmpbuf)) {
+                       regpanic = 10;
+                       fseek(stdout, outloc, 0);
+               }
+               nstack = 0;
+               panicposs = 0;
+               *sp = tp = optim(*sp);
+               if (regpanic==0 && panicposs)
+                       outloc = ftell(stdout);
+               if (op==CBRANCH)
+                       cbranch(tp, lbl, cond, 0);
+               else if (op==EXPR)
+                       rcexpr(tp, efftab, 0);
+               else {
+                       if (tp->t.type==LONG || tp->t.type==UNLONG) {
+                               rcexpr(tnode(RFORCE, tp->t.type, tp, TNULL), efftab, 0);
+                               printf("ashc    $0,r0\n");
+                       } else {
+                               rcexpr(tp, cctab, 0);
+                               if (isfloat(tp))
+                                       printf("cfcc\n");
+                       }
+                       printf("jgt     L%d\n", lbl3);
+                       printf("jlt     L%d\njbr        L%d\n", lbl, lbl2);
+               }
+               curbase = funcbase;
+               break;
+
+       case NAME:
+               t = geti();
+               if (t==EXTERN) {
+                       tp = getblk(sizeof(struct xtname));
+                       tp->t.type = geti();
+                       outname(s);
+                       tp->x.name = (char *)getblk(strlen(s) + 1);
+                       strcpy(tp->x.name, s);
+               } else {
+                       tp = getblk(sizeof(struct tname));
+                       tp->t.type = geti();
+                       tp->n.nloc = geti();
+               }
+               tp->t.op = NAME;
+               tp->n.class = t;
+               tp->n.regno = 0;
+               tp->n.offset = 0;
+               *sp++ = tp;
+               break;
+
+       case CON:
+               t = geti();
+               *sp++ = tconst(geti(), t);
+               break;
+
+       case LCON:
+               geti(); /* ignore type, assume long */
+               t = geti();
+               op = geti();
+               if (t==0 && op>=0 || t == -1 && op<0) {
+                       *sp++ = tnode(ITOL, LONG, tconst(op, INT), TNULL);
+                       break;
+               }
+               tp = getblk(sizeof(struct lconst));
+               tp->t.op = LCON;
+               tp->t.type = LONG;
+               tp->l.lvalue = ((_LONG)t<<16) + UNS(op); /* nonportable */
+               *sp++ = tp;
+               break;
+
+       case FCON:
+               t = geti();
+               outname(s);
+               tp = getblk(sizeof(struct ftconst));
+               tp->t.op = FCON;
+               tp->t.type = t;
+               tp->f.value = isn++;
+#ifdef pdp11
+               tp->f.fvalue = atof(s);
+#else
+ fprintf(stderr, "%s\n", s);
+               tp->f.fvalue = fp_atof(s);
+#endif
+               *sp++ = tp;
+               break;
+
+       case FSEL:
+               tp = tnode(FSEL, geti(), *--sp, TNULL);
+               t = geti();
+               tp->t.tr2 = tnode(COMMA, INT, tconst(geti(), INT), tconst(t, INT));
+               if (tp->t.tr2->t.tr1->c.value==16)
+                       tp = paint(tp->t.tr1, tp->t.type);
+               *sp++ = tp;
+               break;
+
+       case STRASG:
+               tp = getblk(sizeof(struct fasgn));
+               tp->t.op = STRASG;
+               tp->t.type = geti();
+               tp->F.mask = geti();
+               tp->t.tr1 = *--sp;
+               tp->t.tr2 = NULL;
+               *sp++ = tp;
+               break;
+
+       case NULLOP:
+               *sp++ = tnode(0, 0, TNULL, TNULL);
+               break;
+
+       case LABEL:
+               label(geti());
+               break;
+
+       case NLABEL:
+               outname(s);
+               printf("%s:\n", s);
+               break;
+
+       case RLABEL:
+               outname(s);
+               printf("%s:\n~~%s:\n", s, s+1);
+               break;
+
+       case BRANCH:
+               branch(geti(), 0, 0);
+               break;
+
+       case SETREG:
+               nreg = geti()-1;
+               break;
+
+       default:
+               if (opdope[op]&BINARY) {
+                       if (sp < &expstack[1]) {
+                               error("Binary expression botch");
+                               exit(1);
+                       }
+                       tp = *--sp;
+#if 1
+                       sp[-1] = tnode(op, geti(), sp[-1], tp);
+#else
+                       *sp++ = tnode(op, geti(), *--sp, tp);
+#endif
+               } else
+                       sp[-1] = tnode(op, geti(), sp[-1], TNULL);
+               break;
+       }
+       }
+}
+
+int geti() {
+       register int i;
+
+       i = getchar() & 0xff;
+       i |= (getchar() & 0xff) << 8;
+       return(i);
+}
+
+static void outname(s) register char *s; {
+       register int c;
+
+       while (c = getchar())
+               *s++ = c;
+       *s++ = '\0';
+}
+
+void strasg(atp) union tree *atp; {
+       register union tree *tp;
+       register int nwords, i;
+
+       nwords = atp->F.mask/sizeof(_INT);
+       tp = atp->t.tr1;
+       while (tp->t.op == SEQNC) {
+               rcexpr(tp->t.tr1, efftab, 0);
+               tp = tp->t.tr2;
+       }
+       if (tp->t.op != ASSIGN) {
+               if (tp->t.op==RFORCE) { /* function return */
+                       if (sfuncr.nloc==0) {
+                               sfuncr.nloc = isn++;
+                               printf(".bss\nL%d:.=.+%o\n.text\n", sfuncr.nloc,
+                                       UNS(nwords*sizeof(_INT)));
+                       }
+                       atp->t.tr1 = tnode(ASSIGN, STRUCT, (union tree *)&sfuncr, tp->t.tr1);
+                       strasg(atp);
+                       printf("mov     $L%d,r0\n", sfuncr.nloc);
+                       return;
+               }
+               if (tp->t.op==CALL) {
+                       rcexpr(tp, efftab, 0);
+                       return;
+               }
+               error("Illegal structure operation");
+               return;
+       }
+       tp->t.tr2 = strfunc(tp->t.tr2);
+       if (nwords==1)
+               paint(tp, INT);
+       else if (nwords==sizeof(_INT))
+               paint(tp, LONG);
+       else {
+               if (tp->t.tr1->t.op!=NAME && tp->t.tr1->t.op!=STAR
+                || tp->t.tr2->t.op!=NAME && tp->t.tr2->t.op!=STAR) {
+                       error("unimplemented structure assignment");
+                       return;
+               }
+               tp->t.tr1 = tnode(AMPER, STRUCT+PTR, tp->t.tr1, TNULL);
+               tp->t.tr2 = tnode(AMPER, STRUCT+PTR, tp->t.tr2, TNULL);
+               tp->t.op = STRSET;
+               tp->t.type = STRUCT+PTR;
+               tp = optim(tp);
+               rcexpr(tp, efftab, 0);
+               if (nwords < 7) {
+                       for (i=0; i<nwords; i++)
+                               printf("mov     (r1)+,(r0)+\n");
+                       return;
+               }
+               if (nreg<=1)
+                       printf("mov     r2,-(sp)\n");
+               printf("mov     $%o,r2\n", UNS(nwords));
+               printf("L%d:mov (r1)+,(r0)+\ndec\tr2\njne\tL%d\n", isn, isn);
+               isn++;
+               if (nreg<=1)
+                       printf("mov     (sp)+,r2\n");
+               return;
+       }
+       rcexpr(tp, efftab, 0);
+}
+
+/*
+ * Reduce the degree-of-reference by one.
+ * e.g. turn "ptr-to-int" into "int".
+ */
+int decref(t) register int t; {
+       if ((t & ~TYPE) == 0) {
+               error("Illegal indirection");
+               return(t);
+       }
+       return(((_UNSIGNED_INT)t>>TYLEN) & ~TYPE | t&TYPE);
+}
+
+/*
+ * Increase the degree of reference by
+ * one; e.g. turn "int" to "ptr-to-int".
+ */
+int incref(t) register int t; {
+       return(((t&~TYPE)<<TYLEN) | (t&TYPE) | PTR);
+}
diff --git a/c12.c b/c12.c
new file mode 100644 (file)
index 0000000..cbab7b6
--- /dev/null
+++ b/c12.c
@@ -0,0 +1,1221 @@
+/*
+ *             C compiler part 2 -- expression optimizer
+ */
+
+#include <stdlib.h>
+#include "c1.h"
+#include <sys/param.h>         /* for MAX */
+
+union tree *optim(tree) register union tree *tree; {
+       register int op, dope;
+       int d1, d2;
+       union tree *t;
+#ifdef pdp11
+       union { double dv; _INT iv[4];} fp11;
+#endif
+
+       if (tree==NULL)
+               return(NULL);
+       if ((op = tree->t.op)==0)
+               return(tree);
+       if (op==NAME && tree->n.class==AUTO) {
+               tree->n.class = OFFS;
+               tree->n.regno = 5;
+               tree->n.offset = tree->n.nloc;
+       }
+       dope = opdope[op];
+       if ((dope&LEAF) != 0) {
+               if (op==FCON) {
+#ifdef pdp11
+                       fp11.dv = tree->f.fvalue;
+                       if (fp11.iv[1]==0
+                        && fp11.iv[2]==0
+                        && fp11.iv[3]==0) {
+                               tree->t.op = SFCON;
+                               tree->f.value = fp11.iv[0];
+                       }
+#else
+                       if (tree->f.fvalue.l==0
+                        && (tree->f.fvalue.h & 0xffff)==0) {
+                               tree->t.op = SFCON;
+                               tree->f.value = (int)(tree->f.fvalue.h >> 16) & 0xffff;
+                       }
+#endif
+               }
+               return(tree);
+       }
+       if ((dope&BINARY) == 0)
+               return(unoptim(tree));
+       /* is known to be binary */
+       if (tree->t.type==CHAR)
+               tree->t.type = INT;
+       switch(op) {
+       /*
+        * PDP-11 special:
+        * generate new &=~ operator out of &=
+        * by complementing the RHS.
+        */
+       case ASAND:
+               tree->t.op = ASANDN;
+               tree->t.tr2 = tnode(COMPL, tree->t.tr2->t.type, tree->t.tr2, TNULL);
+               break;
+
+       /*
+        * On the PDP-11, int->ptr via multiplication
+        * Longs are just truncated.
+        */
+       case LTOP:
+               tree->t.op = ITOP;
+               tree->t.tr1 = unoptim(tnode(LTOI,INT,tree->t.tr1, TNULL));
+       case ITOP:
+               tree->t.op = TIMES;
+               break;
+
+       case MINUS:
+               if ((t = isconstant(tree->t.tr2)) && (!uns(t) || tree->t.type!=LONG)
+                && (t->t.type!=INT || t->c.value!=(_INT)0100000)) {
+                       tree->t.op = PLUS;
+                       if (t->t.type==DOUBLE) {
+                               /* PDP-11 FP representation */
+                               t->f/*c*/.value ^= 0100000;
+                       } else
+                               t->c.value = -t->c.value;
+               }
+               break;
+       }
+       op = tree->t.op;
+       dope = opdope[op];
+       if (dope&LVALUE && tree->t.tr1->t.op==FSEL)
+               return(lvfield(tree));
+       if ((dope&COMMUTE)!=0) {
+               d1 = tree->t.type;
+               tree = acommute(tree);
+               if (tree->t.op == op)
+                       tree->t.type = d1;
+               /*
+                * PDP-11 special:
+                * replace a&b by a ANDN ~ b.
+                * This will be undone when in
+                * truth-value context.
+                */
+               if (tree->t.op!=AND)
+                       return(tree);
+               /*
+                * long & pos-int is simpler
+                */
+               if ((tree->t.type==LONG || tree->t.type==UNLONG) && tree->t.tr2->t.op==ITOL
+                && (tree->t.tr2->t.tr1->t.op==CON && tree->t.tr2->t.tr1->c.value>=0
+                  || uns(tree->t.tr2->t.tr1))) {
+                       tree->t.type = UNSIGN;
+                       t = tree->t.tr2;
+                       tree->t.tr2 = tree->t.tr2->t.tr1;
+                       t->t.tr1 = tree;
+                       tree->t.tr1 = tnode(LTOI, UNSIGN, tree->t.tr1, TNULL);
+                       return(optim(t));
+               }
+               /*
+                * Keep constants to the right
+                */
+               if ((tree->t.tr1->t.op==ITOL && tree->t.tr1->t.tr1->t.op==CON)
+                 || tree->t.tr1->t.op==LCON) {
+                       t = tree->t.tr1;
+                       tree->t.tr1 = tree->t.tr2;
+                       tree->t.tr2 = t;
+               }
+               tree->t.op = ANDN;
+               op = ANDN;
+               tree->t.tr2 = tnode(COMPL, tree->t.tr2->t.type, tree->t.tr2, TNULL);
+       }
+    again:
+       tree->t.tr1 = optim(tree->t.tr1);
+       tree->t.tr2 = optim(tree->t.tr2);
+       if (tree->t.type == LONG || tree->t.type==UNLONG) {
+               t = lconst(tree->t.op, tree->t.tr1, tree->t.tr2);
+               if (t)
+                       return(t);
+       }
+       if ((dope&RELAT) != 0) {
+               if ((d1=degree(tree->t.tr1)) < (d2=degree(tree->t.tr2))
+                || d1==d2 && tree->t.tr1->t.op==NAME && tree->t.tr2->t.op!=NAME) {
+                       t = tree->t.tr1;
+                       tree->t.tr1 = tree->t.tr2;
+                       tree->t.tr2 = t;
+                       tree->t.op = maprel[op-EQUAL];
+               }
+               if (tree->t.tr1->t.type==CHAR && tree->t.tr2->t.op==CON
+                && (dcalc(tree->t.tr1, 0) <= 12 || tree->t.tr1->t.op==STAR)
+                && tree->t.tr2->c.value <= 127 && tree->t.tr2->c.value >= 0)
+                       tree->t.tr2->t.type = CHAR;
+       }
+       d1 = MAX(degree(tree->t.tr1), islong(tree->t.type));
+       d2 = MAX(degree(tree->t.tr2), 0);
+       switch (op) {
+
+       /*
+        * In assignment to fields, treat all-zero and all-1 specially.
+        */
+       case FSELA:
+               if (tree->t.tr2->t.op==CON && tree->t.tr2->c.value==0) {
+                       tree->t.op = ASAND;
+                       tree->t.tr2->c.value = ~tree->F.mask;
+                       return(optim(tree));
+               }
+               if (tree->t.tr2->t.op==CON && tree->F.mask==tree->t.tr2->c.value) {
+                       tree->t.op = ASOR;
+                       return(optim(tree));
+               }
+
+       case LTIMES:
+       case LDIV:
+       case LMOD:
+       case LASTIMES:
+       case LASDIV:
+       case LASMOD:
+       case UDIV:
+       case UMOD:
+       case ASUDIV:
+       case ASUMOD:
+       case ULASMOD:
+       case ULTIMES:
+       case ULDIV:
+       case ULMOD:
+       case ULASTIMES:
+       case ULASDIV:
+               tree->t.degree = 10;
+               break;
+
+       case ANDN:
+               if (isconstant(tree->t.tr2) && tree->t.tr2->c.value==0) {
+                       return(tree->t.tr1);
+               }
+               goto def;
+
+       case CALL:
+               tree->t.degree = 10;
+               break;
+
+       case QUEST:
+       case COLON:
+               tree->t.degree = MAX(d1, d2);
+               break;
+
+       case PTOI:
+       case DIVIDE:
+       case ASDIV:
+       case ASTIMES:
+               if (tree->t.tr2->t.op==CON && tree->t.tr2->c.value==1) {
+                       if (op==PTOI)
+                               return(optim(tnode(LTOI,INT,paint(tree->t.tr1,LONG), TNULL)));
+                       return(paint(tree->t.tr1, tree->t.type));
+               }
+       case MOD:
+       case ASMOD:
+               if ((uns(tree->t.tr1) || tree->t.op==PTOI) && ispow2(tree))
+                       return(pow2(tree));
+               if ((op==MOD||op==ASMOD) && tree->t.type==DOUBLE) {
+                       error("Floating %% not defined");
+                       tree->t.type = INT;
+               }
+       case ULSH:
+       case ASULSH:
+               d1 += 2 + regpanic;
+               d2 += 2 + regpanic;
+               panicposs++;
+               if (tree->t.type==LONG || tree->t.type==UNLONG)
+                       return(hardlongs(tree));
+               if ((op==MOD || op==DIVIDE || op==ASMOD || op==ASDIV)
+                && (uns(tree->t.tr1) || uns(tree->t.tr2))
+                && (tree->t.tr2->t.op!=CON || tree->t.tr2->c.value<=1)) {
+                       if (op>=ASDIV) {
+                               tree->t.op += ASUDIV - ASDIV;
+                       } else
+                               tree->t.op += UDIV - DIVIDE;
+                       d1 = d2 = 10;
+               }
+               goto constant;
+
+       case ASPLUS:
+       case ASMINUS:
+               if (tree->t.tr2->t.op==CON && tree->t.tr2->c.value==0)
+                       return(tree->t.tr1);
+               goto def;
+
+       case LSHIFT:
+       case RSHIFT:
+       case ASRSH:
+       case ASLSH:
+               if (tree->t.tr2->t.op==CON && tree->t.tr2->c.value==0)
+                       return(paint(tree->t.tr1, tree->t.type));
+               /*
+                * PDP-11 special: turn right shifts into negative
+                * left shifts
+                */
+               if (tree->t.type == LONG || tree->t.type==UNLONG) {
+                       d1++;
+                       d2++;
+               }
+               if (op==LSHIFT||op==ASLSH)
+                       goto constant;
+               if (tree->t.tr2->t.op==CON && tree->t.tr2->c.value==1
+                && !uns(tree->t.tr1) && !uns(tree->t.tr2))
+                       goto constant;
+               op += (LSHIFT-RSHIFT);
+               tree->t.op = op;
+               tree->t.tr2 = tnode(NEG, tree->t.tr2->t.type, tree->t.tr2, TNULL);
+               if (uns(tree->t.tr1) || uns(tree->t.tr2)) {
+                       if (tree->t.op==LSHIFT)
+                               tree->t.op = ULSH;
+                       else if (tree->t.op==ASLSH)
+                               tree->t.op = ASULSH;
+               }
+               goto again;
+
+       constant:
+               if (tree->t.tr1->t.op==CON && tree->t.tr2->t.op==CON) {
+                       _const(op, &tree->t.tr1->c.value, tree->t.tr2->c.value, tree->t.type);
+                       return(tree->t.tr1);
+               }
+
+
+       def:
+       default:
+               if (dope&RELAT) {
+                       if (tree->t.tr1->t.type==LONG || tree->t.tr1->t.type==UNLONG)   /* long relations are a mess */
+                               d1 = 10;
+                       if (opdope[tree->t.tr1->t.op]&RELAT && tree->t.tr2->t.op==CON
+                        && tree->t.tr2->c.value==0) {
+                               tree = tree->t.tr1;
+                               switch(op) {
+                               case GREATEQ:
+                                       return((union tree *)&cone);
+                               case LESS:
+                                       return((union tree *)&czero);
+                               case LESSEQ:
+                               case EQUAL:
+                                       tree->t.op = notrel[tree->t.op-EQUAL];
+                               }
+                               return(tree);
+                       }
+               }
+               tree->t.degree = d1==d2? d1+islong(tree->t.type): MAX(d1, d2);
+               break;
+       }
+       return(tree);
+}
+
+union tree *unoptim(tree) register union tree *tree; {
+       register union tree *subtre, *p;
+#ifndef pdp11
+       _LONG temp_long;
+       uint16_t temp[2];
+#endif
+
+       if (tree==NULL)
+               return(NULL);
+    again:
+       if (tree->t.op==AMPER && tree->t.tr1->t.op==STAR) {
+               subtre = tree->t.tr1->t.tr1;
+               subtre->t.type = tree->t.type;
+               return(optim(subtre));
+       }
+       subtre = tree->t.tr1 = optim(tree->t.tr1);
+       switch (tree->t.op) {
+
+       case INCAFT:
+       case DECAFT:
+               if (tree->t.type!=subtre->t.type) 
+                       paint(subtre, tree->t.type);
+               break;
+
+       case ITOL:
+               if (subtre->t.op==CON && subtre->t.type==INT && subtre->c.value<0) {
+                       subtre = getblk(sizeof(struct lconst));
+                       subtre->t.op = LCON;
+                       subtre->t.type = LONG;
+                       subtre->l.lvalue = tree->t.tr1->c.value;
+                       return(subtre);
+               }
+               break;
+
+       case FTOI:
+               if (uns(tree)) {
+                       tree->t.op = FTOL;
+                       tree->t.type = LONG;
+                       tree = tnode(LTOI, UNSIGN, tree, TNULL);
+               }
+               break;
+
+       case LTOF:
+               if (subtre->t.op==LCON) {
+                       tree = getblk(sizeof(struct ftconst));
+                       tree->t.op = FCON;
+                       tree->t.type = DOUBLE;
+                       tree->f/*c*/.value = isn++;
+#ifdef pdp11
+                       tree->f.fvalue = subtre->l.lvalue;
+#else
+                       tree->f.fvalue = fp_long_to_double(subtre->l.lvalue);
+#endif
+                       return(optim(tree));
+               }
+               if (subtre->t.type==UNLONG) 
+                       tree->t.op = ULTOF;
+               break;
+
+       case ITOF:
+               if (subtre->t.op==CON) {
+                       tree = getblk(sizeof(struct ftconst));
+                       tree->t.op = FCON;
+                       tree->t.type = DOUBLE;
+                       tree->f.value = isn++;
+#ifdef pdp11
+                       if (uns(subtre))
+                               tree->f.fvalue = (_UNSIGNED_INT)subtre->c.value;
+                       else
+                               tree->f.fvalue = subtre->c.value;
+#else
+ /* revisit the unsigned case */
+                       if (uns(subtre))
+                               tree->f.fvalue = fp_long_to_double((_LONG)(_UNSIGNED_INT)subtre->c.value);
+                       else
+                               tree->f.fvalue = fp_int_to_double(subtre->c.value);
+#endif
+                       return(optim(tree));
+               }
+               if (uns(subtre)) {
+                       tree->t.tr1 = tnode(ITOL, LONG, subtre, TNULL);
+                       tree->t.op = LTOF;
+                       return(optim(tree));
+               }
+               break;
+
+       case ITOC:
+               /*
+                * Sign-extend PDP-11 characters
+                */
+               if (subtre->t.op==CON) {
+                       char c;
+                       c = subtre->c.value;
+                       subtre->c.value = c;
+                       subtre->t.type = tree->t.type;
+                       return(subtre);
+               } else if (subtre->t.op==NAME && tree->t.type==INT) {
+                       subtre->t.type = CHAR;
+                       return(subtre);
+               }
+               break;
+
+       case LTOI:
+               switch (subtre->t.op) {
+
+               case LCON:
+                       subtre->t.op = CON;
+                       subtre->t.type = tree->t.type;
+                       subtre->c.value = subtre->l.lvalue;
+                       return(subtre);
+
+               case NAME:
+                       subtre->n.offset += 2;
+                       subtre->t.type = tree->t.type;
+                       return(subtre);
+
+               case STAR:
+                       subtre->t.type = tree->t.type;
+                       subtre->t.tr1->t.type = tree->t.type+PTR;
+                       subtre->t.tr1 = tnode(PLUS, tree->t.type, subtre->t.tr1, tconst(2, INT));
+                       return(optim(subtre));
+
+               case ITOL:
+                       return(paint(subtre->t.tr1, tree->t.type));
+
+               case PLUS:
+               case MINUS:
+               case AND:
+               case ANDN:
+               case OR:
+               case EXOR:
+                       subtre->t.tr2 = tnode(LTOI, tree->t.type, subtre->t.tr2, TNULL);
+               case NEG:
+               case COMPL:
+                       subtre->t.tr1 = tnode(LTOI, tree->t.type, subtre->t.tr1, TNULL);
+                       subtre->t.type = tree->t.type;
+                       return(optim(subtre));
+               }
+               break;
+
+       case FSEL:
+               tree->t.op = AND;
+               tree->t.tr1 = tree->t.tr2->t.tr1;
+               tree->t.tr2->t.tr1 = subtre;
+               tree->t.tr2->t.op = RSHIFT;
+               tree->t.tr1->c.value = (1 << tree->t.tr1->c.value) - 1;
+               return(optim(tree));
+
+       case FSELR:
+               tree->t.op = LSHIFT;
+               tree->t.type = UNSIGN;
+               tree->t.tr1 = tree->t.tr2;
+               tree->t.tr1->t.op = AND;
+               tree->t.tr2 = tree->t.tr2->t.tr2;
+               tree->t.tr1->t.tr2 = subtre;
+               tree->t.tr1->t.tr1->c.value = (1 << tree->t.tr1->t.tr1->c.value) -1;
+               return(optim(tree));
+
+       case AMPER:
+               if (subtre->t.op==STAR)
+                       return(subtre->t.tr1);
+               if (subtre->t.op==NAME && subtre->n.class == OFFS) {
+                       p = tnode(PLUS, tree->t.type, subtre, tree);
+                       subtre->t.type = tree->t.type;
+                       tree->t.op = CON;
+                       tree->t.type = INT;
+                       tree->t.degree = 0;
+                       tree->c.value = subtre->n.offset;
+                       subtre->n.class = REG;
+                       subtre->n.nloc = subtre->n.regno;
+                       subtre->n.offset = 0;
+                       return(optim(p));
+               }
+               if (subtre->t.op==LOAD) {
+                       tree->t.tr1 = subtre->t.tr1;
+                       goto again;
+               }
+               break;
+
+       case STAR:
+               if (subtre->t.op==AMPER) {
+                       subtre->t.tr1->t.type = tree->t.type;
+                       return(subtre->t.tr1);
+               }
+               if (tree->t.type==STRUCT)
+                       break;
+               if (subtre->t.op==NAME && subtre->n.class==REG) {
+                       subtre->t.type = tree->t.type;
+                       subtre->n.class = OFFS;
+                       subtre->n.regno = subtre->n.nloc;
+                       return(subtre);
+               }
+               p = subtre->t.tr1;
+               if ((subtre->t.op==INCAFT||subtre->t.op==DECBEF)
+                && tree->t.type!=LONG && tree->t.type!=UNLONG
+                && p->t.op==NAME && p->n.class==REG && p->t.type==subtre->t.type) {
+                       p->t.type = tree->t.type;
+                       p->t.op = subtre->t.op==INCAFT? AUTOI: AUTOD;
+                       return(p);
+               }
+               if (subtre->t.op==PLUS && p->t.op==NAME && p->n.class==REG) {
+                       if (subtre->t.tr2->t.op==CON) {
+                               p->n.offset += subtre->t.tr2->c.value;
+                               p->n.class = OFFS;
+                               p->t.type = tree->t.type;
+                               p->n.regno = p->n.nloc;
+                               return(p);
+                       }
+                       if (subtre->t.tr2->t.op==AMPER) {
+                               subtre = subtre->t.tr2->t.tr1;
+                               subtre->n.class += XOFFS-EXTERN;
+                               subtre->n.regno = p->n.nloc;
+                               subtre->t.type = tree->t.type;
+                               return(subtre);
+                       }
+               }
+               if (subtre->t.op==MINUS && p->t.op==NAME && p->n.class==REG
+                && subtre->t.tr2->t.op==CON) {
+                       p->n.offset -= subtre->t.tr2->c.value;
+                       p->n.class = OFFS;
+                       p->t.type = tree->t.type;
+                       p->n.regno = p->n.nloc;
+                       return(p);
+               }
+               break;
+       case EXCLA:
+               if ((opdope[subtre->t.op]&RELAT)==0)
+                       break;
+               tree = subtre;
+               tree->t.op = notrel[tree->t.op-EQUAL];
+               break;
+
+       case COMPL:
+               if (tree->t.type==CHAR)
+                       tree->t.type = INT;
+               if (tree->t.op == subtre->t.op)
+                       return(paint(subtre->t.tr1, tree->t.type));
+               if (subtre->t.op==CON) {
+                       subtre->c.value = ~subtre->c.value;
+                       return(paint(subtre, tree->t.type));
+               }
+               if (subtre->t.op==LCON) {
+                       subtre->l.lvalue = ~subtre->l.lvalue;
+                       return(subtre);
+               }
+               if (subtre->t.op==ITOL) {
+                       if (subtre->t.tr1->t.op==CON) {
+                               tree = getblk(sizeof(struct lconst));
+                               tree->t.op = LCON;
+                               tree->t.type = LONG;
+                               if (uns(subtre->t.tr1))
+                                       tree->l.lvalue = ~(_LONG)(_UNSIGNED_INT)
+                                               subtre->t.tr1->c.value;
+                               else
+                                       tree->l.lvalue =
+                                               ~subtre->t.tr1->c.value;
+                               return(tree);
+                       }
+                       if (uns(subtre->t.tr1))
+                               break;
+                       subtre->t.op = tree->t.op;
+                       subtre->t.type = subtre->t.tr1->t.type;
+                       tree->t.op = ITOL;
+                       tree->t.type = LONG;
+                       goto again;
+               }
+
+       case NEG:
+               if (tree->t.type==CHAR)
+                       tree->t.type = INT;
+               if (tree->t.op==subtre->t.op)
+                       return(paint(subtre->t.tr1, tree->t.type));
+               if (subtre->t.op==CON) {
+                       subtre->c.value = -subtre->c.value;
+                       return(paint(subtre, tree->t.type));
+               }
+               if (subtre->t.op==LCON) {
+                       subtre->l.lvalue = -subtre->l.lvalue;
+                       return(subtre);
+               }
+               if (subtre->t.op==ITOL && subtre->t.tr1->t.op==CON) {
+                       tree = getblk(sizeof(struct lconst));
+                       tree->t.op = LCON;
+                       tree->t.type = LONG;
+                       if (uns(subtre->t.tr1))
+                               tree->l.lvalue = -(_LONG)(_UNSIGNED_INT)
+                                       subtre->t.tr1->c.value;
+                       else
+                               tree->l.lvalue = -subtre->t.tr1->c.value;
+                       return(tree);
+               }
+               /*
+                * PDP-11 FP negation
+                */
+               if (subtre->t.op==SFCON) {
+                       subtre->c.value ^= 0100000;
+#ifdef pdp11
+                       subtre->f.fvalue = -subtre->f.fvalue;
+#else
+                       subtre->f.fvalue = fp_neg(subtre->f.fvalue);
+#endif
+                       return(subtre);
+               }
+               if (subtre->t.op==FCON) {
+#ifdef pdp11
+                       subtre->f.fvalue = -subtre->f.fvalue;
+#else
+                       subtre->f.fvalue = fp_neg(subtre->f.fvalue);
+#endif
+                       return(subtre);
+               }
+       }
+       if ((opdope[tree->t.op]&LEAF)==0)
+               tree->t.degree = MAX(islong(tree->t.type), degree(subtre));
+       return(tree);
+}
+
+/*
+ * Deal with assignments to partial-word fields.
+ * The game is that select(x) += y turns into
+ * select(x += select(y)) where the shifts and masks
+ * are chosen properly.  The outer select
+ * is discarded where the value doesn't matter.
+ * Sadly, overflow is undetected on += and the like.
+ * Pure assignment is handled specially.
+ */
+
+union tree *lvfield(t) register union tree *t; {
+       register union tree *t1, *t2;
+
+       switch (t->t.op) {
+
+       case ASSIGN:
+               t2 = getblk(sizeof(struct fasgn));
+               t2->t.op = FSELA;
+               t2->t.type = UNSIGN;
+               t1 = t->t.tr1->t.tr2;
+               t2->F.mask = ((1<<t1->t.tr1->c.value)-1)<<t1->t.tr2->c.value;
+               t2->t.tr1 = t->t.tr1;
+               t2->t.tr2 = t->t.tr2;
+               t = t2;
+
+       case ASANDN:
+       case ASPLUS:
+       case ASMINUS:
+       case ASOR:
+       case ASXOR:
+       case INCBEF:
+       case INCAFT:
+       case DECBEF:
+       case DECAFT:
+               t1 = t->t.tr1;
+               t1->t.op = FSELR;
+               t->t.tr1 = t1->t.tr1;
+               t1->t.tr1 = t->t.tr2;
+               t->t.tr2 = t1;
+               t1 = t1->t.tr2;
+               t1 = tnode(COMMA, INT, tconst(t1->t.tr1->c.value, INT),
+                       tconst(t1->t.tr2->c.value, INT));
+               return(optim(tnode(FSELT, UNSIGN, t, t1)));
+
+       }
+       error("Unimplemented field operator");
+       return(t);
+}
+
+#if 0 /* now moved to c1.h */
+#define        LSTSIZ  20
+struct acl {
+       int nextl;
+       int nextn;
+       union tree *nlist[LSTSIZ];
+       union tree *llist[LSTSIZ+1];
+};
+#endif
+
+union tree *acommute(tree) register union tree *tree; {
+       struct acl acl;
+       int d, i, op, flt, d1, type;
+       register union tree *t1, **t2;
+       union tree *t;
+
+       acl.nextl = 0;
+       acl.nextn = 0;
+       op = tree->t.op;
+       type = tree->t.type;
+       flt = isfloat(tree);
+       insert(op, tree, &acl);
+       acl.nextl--;
+       t2 = &acl.llist[acl.nextl];
+       if (!flt) {
+               /* put constants together */
+               for (i=acl.nextl; i>0; i--) {
+                       d = t2[-1]->t.type==UNSIGN||t2[0]->t.type==UNSIGN?UNSIGN:INT;
+                       if (t2[0]->t.op==CON && t2[-1]->t.op==CON) {
+                               acl.nextl--;
+                               t2--;
+                               _const(op, &t2[0]->c.value, t2[1]->c.value, d);
+                               t2[0]->t.type = d;
+                       } else if (t = lconst(op, t2[-1], t2[0])) {
+                               acl.nextl--;
+                               t2--;
+                               t2[0] = t;
+                       }
+               }
+       }
+       if (op==PLUS || op==OR) {
+               /* toss out "+0" */
+               if (acl.nextl>0 && ((t1 = isconstant(*t2)) && t1->c.value==0
+                || (*t2)->t.op==LCON && (*t2)->l.lvalue==0)) {
+                       acl.nextl--;
+                       t2--;
+               }
+               if (acl.nextl <= 0) {
+                       if ((*t2)->t.type==CHAR || (*t2)->t.type==UNCHAR)
+                               *t2 = tnode(LOAD, tree->t.type, *t2, TNULL);
+                       (*t2)->t.type = tree->t.type;
+                       return(*t2);
+               }
+               /* subsume constant in "&x+c" */
+               if (op==PLUS && t2[0]->t.op==CON && t2[-1]->t.op==AMPER) {
+                       t2--;
+                       t2[0]->t.tr1->n.offset += t2[1]->c.value;
+                       acl.nextl--;
+               }
+       } else if (op==TIMES || op==AND) {
+               t1 = acl.llist[acl.nextl];
+               if (t1->t.op==CON) {
+                       if (t1->c.value==0) {
+                               for (i=0; i<acl.nextl; i++)
+                                       if (sideeffects(acl.llist[i]))
+                                               break;
+                               if (i==acl.nextl)
+                                       return(t1);
+                       }
+                       if (op==TIMES && t1->c.value==1 && acl.nextl>0)
+                               if (--acl.nextl <= 0) {
+                                       t1 = acl.llist[0];
+                                       if (uns(tree))
+                                               paint(t1, tree->t.type);
+                                       return(t1);
+                               }
+               }
+       }
+       if (op==PLUS && !flt)
+               distrib(&acl);
+       tree = *(t2 = &acl.llist[0]);
+       d = MAX(degree(tree), islong(tree->t.type));
+       if (op==TIMES && !flt) {
+               d += regpanic+1;
+               panicposs++;
+       }
+       for (i=0; i<acl.nextl; i++) {
+               t1 = acl.nlist[i];
+               t1->t.tr2 = t = *++t2;
+               d1 = degree(t);
+               /*
+                * PDP-11 strangeness:
+                * rt. op of ^ must be in a register.
+                */
+               if (op==EXOR && dcalc(t, 0)<=12) {
+                       t1->t.tr2 = t = optim(tnode(LOAD, t->t.type, t, TNULL));
+                       d1 = t->t.degree;
+               }
+               t1->t.degree = d = d==d1? d+islong(t1->t.type): MAX(d, d1);
+               t1->t.tr1 = tree;
+               tree = t1;
+               if (tree->t.type==LONG || tree->t.type==UNLONG) {
+                       if (tree->t.op==TIMES)
+                               tree = hardlongs(tree);
+                       else if (tree->t.op==PLUS && (t = isconstant(tree->t.tr1))
+                              && t->c.value < 0 && !uns(t)) {
+                               tree->t.op = MINUS;
+                               t->c.value = - t->c.value;
+                               t = tree->t.tr1;
+                               tree->t.tr1 = tree->t.tr2;
+                               tree->t.tr2 = t;
+                       }
+               }
+       }
+       if (tree->t.op==TIMES && ispow2(tree))
+               tree->t.degree = MAX(degree(tree->t.tr1), islong(tree->t.type));
+       paint(tree, type);
+       return(tree);
+}
+
+int sideeffects(tp) register union tree *tp; {
+       register int dope;
+
+       if (tp==NULL)
+               return(0);
+       dope = opdope[tp->t.op];
+       if (dope&LEAF) {
+               if (tp->t.op==AUTOI || tp->t.op==AUTOD)
+                       return(1);
+               return(0);
+       }
+       if (dope&ASSGOP)
+               return(1);
+       switch(tp->t.op) {
+       case CALL:
+       case FSELA:
+       case STRASG:
+               return(1);
+       }
+       if (sideeffects(tp->t.tr1))
+               return(1);
+       if (dope&BINARY)
+               return(sideeffects(tp->t.tr2));
+       return(0);
+}
+
+void distrib(list) struct acl *list; {
+/*
+ * Find a list member of the form c1c2*x such
+ * that c1c2 divides no other such constant, is divided by
+ * at least one other (say in the form c1*y), and which has
+ * fewest divisors. Reduce this pair to c1*(y+c2*x)
+ * and iterate until no reductions occur.
+ */
+       register union tree **p1, **p2;
+       union tree *t;
+       int ndmaj, ndmin;
+       union tree **dividend, **divisor;
+       union tree **maxnod, **mindiv;
+
+    loop:
+       maxnod = &list->llist[list->nextl];
+       ndmaj = 1000;
+       dividend = 0;
+       for (p1 = list->llist; p1 <= maxnod; p1++) {
+               if ((*p1)->t.op!=TIMES || (*p1)->t.tr2->t.op!=CON)
+                       continue;
+               ndmin = 0;
+               for (p2 = list->llist; p2 <= maxnod; p2++) {
+                       if (p1==p2 || (*p2)->t.op!=TIMES || (*p2)->t.tr2->t.op!=CON)
+                               continue;
+                       if ((*p1)->t.tr2->c.value == (*p2)->t.tr2->c.value) {
+                               (*p2)->t.tr2 = (*p1)->t.tr1;
+                               (*p2)->t.op = PLUS;
+                               (*p1)->t.tr1 = (*p2);
+                               *p1 = optim(*p1);
+                               squash(p2, maxnod);
+                               list->nextl--;
+                               goto loop;
+                       }
+                       if (((*p2)->t.tr2->c.value % (*p1)->t.tr2->c.value) == 0)
+                               goto contmaj;
+                       if (((*p1)->t.tr2->c.value % (*p2)->t.tr2->c.value) == 0) {
+                               ndmin++;
+                               mindiv = p2;
+                       }
+               }
+               if (ndmin > 0 && ndmin < ndmaj) {
+                       ndmaj = ndmin;
+                       dividend = p1;
+                       divisor = mindiv;
+               }
+    contmaj:;
+       }
+       if (dividend==0)
+               return;
+       t = list->nlist[--list->nextn];
+       p1 = dividend;
+       p2 = divisor;
+       t->t.op = PLUS;
+       t->t.type = (*p1)->t.type;
+       t->t.tr1 = (*p1);
+       t->t.tr2 = (*p2)->t.tr1;
+       (*p1)->t.tr2->c.value /= (*p2)->t.tr2->c.value;
+       (*p2)->t.tr1 = t;
+       t = optim(*p2);
+       if (p1 < p2) {
+               *p1 = t;
+               squash(p2, maxnod);
+       } else {
+               *p2 = t;
+               squash(p1, maxnod);
+       }
+       list->nextl--;
+       goto loop;
+}
+
+void squash(p, maxp) union tree **p; union tree **maxp; {
+       register union tree **np;
+
+       for (np = p; np < maxp; np++)
+               *np = *(np+1);
+}
+
+void _const(op, vp, v, type) int op; register _INT *vp; register _INT v; int type; {
+       switch (op) {
+
+       case PTOI:
+               (*vp) /= (_UNSIGNED_INT)v;
+               return;
+
+       case PLUS:
+               *vp += v;
+               return;
+
+       case TIMES:
+               *vp *= v;
+               return;
+
+       case AND:
+               *vp &= v;
+               return;
+
+       case OR:
+               *vp |= v;
+               return;
+
+       case EXOR:
+               *vp ^= v;
+               return;
+
+       case UDIV:
+       case UMOD:
+               type = UNSIGN;
+       case DIVIDE:
+       case MOD:
+               if (type==UNSIGN && v!=0 && v<=1) {
+                       if (op==UDIV || op==DIVIDE) {
+                               if (v==1)
+                                       return;
+                               *vp = *(_UNSIGNED_INT *)vp >= (_UNSIGNED_INT)v;
+                               return;
+                       } else {
+                               if (v==1) {
+                                       *vp = 0;
+                                       return;
+                               }
+                               if (*(_UNSIGNED_INT *)vp >= (_UNSIGNED_INT)v)
+                                       *vp -= v;
+                               return;
+                       }
+               }
+               if (v==0)
+                       werror("divide check");
+               else
+                       if (type==INT)
+                               if (op==DIVIDE || op==UDIV)
+                                       *vp /= v;
+                               else
+                                       *vp %= v;
+                       else
+                               if (op==DIVIDE || op==UDIV)
+                                       *(_UNSIGNED_INT *)vp /= (_UNSIGNED_INT)v;
+                               else
+                                       *(_UNSIGNED_INT *)vp %= (_UNSIGNED_INT)v;
+                       return;
+
+       case RSHIFT:
+       rshift:
+               if (v<0) {
+                       v = -v;
+                       goto lshift;
+               }
+               if (type==INT)
+                       *vp >>= v;
+               else
+                       *(_UNSIGNED_INT *)vp >>= (_UNSIGNED_INT)v;
+               return;
+
+       case ULSH:
+               type = UNSIGN;
+
+       case LSHIFT:
+       lshift:
+               if (v<0) {
+                       v = -v;
+                       goto rshift;
+               }
+               if (type==INT)
+                       *vp <<= v;
+               else
+                       *(_UNSIGNED_INT *)vp <<= (_UNSIGNED_INT)v;
+               return;
+
+       case ANDN:
+               *vp &= ~ v;
+               return;
+       }
+       error("C error: const");
+}
+
+union tree *lconst(op, lp, rp) int op; register union tree *lp; register union tree *rp; {
+       _UNSIGNED_LONG l, r;
+
+       if (lp->t.op==LCON)
+               l = lp->l.lvalue;
+       else if (lp->t.op==ITOL && lp->t.tr1->t.op==CON) {
+               if (lp->t.tr1->t.type==INT)
+                       l = lp->t.tr1->c.value;
+               else
+                       l = (_UNSIGNED_INT)lp->t.tr1->c.value;
+       } else
+               return(0);
+       if (rp->t.op==LCON)
+               r = rp->l.lvalue;
+       else if (rp->t.op==ITOL && rp->t.tr1->t.op==CON) {
+               if (rp->t.tr1->t.type==INT)
+                       r = rp->t.tr1->c.value;
+               else
+                       r = (_UNSIGNED_INT)rp->t.tr1->c.value;
+       } else
+               return(0);
+       switch (op) {
+
+       case PLUS:
+               l += r;
+               break;
+
+       case MINUS:
+               l -= r;
+               break;
+
+       case TIMES:
+       case LTIMES:
+               l *= r;
+               break;
+
+       case DIVIDE:
+       case LDIV:
+               if (r==0)
+                       error("Divide check");
+               else
+                       l /= r;
+               break;
+
+       case MOD:
+       case LMOD:
+               if (r==0)
+                       error("Divide check");
+               else
+                       l %= r;
+               break;
+
+       case AND:
+               l &= r;
+               break;
+
+       case ANDN:
+               l &= ~r;
+               break;
+
+       case OR:
+               l |= r;
+               break;
+
+       case EXOR:
+               l ^= r;
+               break;
+
+       case LSHIFT:
+               l <<= r;
+               break;
+
+       case RSHIFT:
+               l >>= r;
+               break;
+
+       default:
+               return(0);
+       }
+       if (lp->t.op==LCON) {
+               lp->l.lvalue = l;
+               return(lp);
+       }
+       lp = getblk(sizeof(struct lconst));
+       lp->t.op = LCON;
+       lp->t.type = LONG;
+       lp->l.lvalue = l;
+       return(lp);
+}
+
+void insert(op, tree, list) int op; register union tree *tree; register struct acl *list; {
+       register int d;
+       int d1, i;
+       union tree *t;
+
+ins:
+       if (tree->t.op != op)
+               tree = optim(tree);
+       if (tree->t.op == op && list->nextn < LSTSIZ-2) {
+               list->nlist[list->nextn++] = tree;
+               insert(op, tree->t.tr1, list);
+               insert(op, tree->t.tr2, list);
+               return;
+       }
+       if (!isfloat(tree)) {
+               /* c1*(x+c2) -> c1*x+c1*c2 */
+               if ((tree->t.op==TIMES||tree->t.op==LSHIFT)
+                 && tree->t.tr2->t.op==CON && tree->t.tr2->c.value>0
+                 && tree->t.tr1->t.op==PLUS && tree->t.tr1->t.tr2->t.op==CON) {
+                       d = tree->t.tr2->c.value;
+                       if (tree->t.op==TIMES)
+                               tree->t.tr2->c.value *= tree->t.tr1->t.tr2->c.value;
+                       else
+                               tree->t.tr2->c.value = tree->t.tr1->t.tr2->c.value << d;
+                       tree->t.tr1->t.tr2->c.value = d;
+                       tree->t.tr1->t.op = tree->t.op;
+                       tree->t.op = PLUS;
+                       tree = optim(tree);
+                       if (op==PLUS)
+                               goto ins;
+               }
+       }
+       d = degree(tree);
+       for (i=0; i<list->nextl; i++) {
+               if ((d1=degree(list->llist[i]))<d) {
+                       t = list->llist[i];
+                       list->llist[i] = tree;
+                       tree = t;
+                       d = d1;
+               }
+       }
+       list->llist[list->nextl++] = tree;
+}
+
+union tree *tnode(op, type, tr1, tr2) int op; int type; union tree *tr1; union tree *tr2; {
+       register union tree *p;
+
+       p = getblk(sizeof(struct tnode));
+       p->t.op = op;
+       p->t.type = type;
+       p->t.degree = 0;
+       p->t.tr1 = tr1;
+       p->t.tr2 = tr2;
+       return(p);
+}
+
+union tree *tconst(val, type) int val; int type; {
+       register union tree *p;
+
+       p = getblk(sizeof(struct tconst));
+       p->t.op = CON;
+       p->t.type = type;
+       p->c.value = val;
+       return(p);
+}
+
+union tree *getblk(size) int size; {
+       register union tree *p;
+
+       if (size&01)
+               size++;
+       p = (union tree *)curbase;
+       if ((curbase += size) >= coremax) {
+#ifdef pdp11
+               if (sbrk(1024) == (char *)-1) {
+#else
+               if (sbrk(1024) != coremax) {
+#endif
+                       error("Out of space-- c1");
+                       exit(1);
+               }
+               coremax += 1024;
+       }
+       return(p);
+}
+
+int islong(t) int t; {
+       if (t==LONG || t==UNLONG)
+               return(2);
+       return(1);
+}
+
+union tree *isconstant(t) register union tree *t; {
+       if (t->t.op==CON || t->t.op==SFCON)
+               return(t);
+       if (t->t.op==ITOL && t->t.tr1->t.op==CON)
+               return(t->t.tr1);
+       return(NULL);
+}
+
+union tree *hardlongs(t) register union tree *t; {
+       switch(t->t.op) {
+
+       case TIMES:
+       case DIVIDE:
+       case MOD:
+               if (t->t.type == UNLONG)
+                       t->t.op += ULTIMES-TIMES;
+               else
+                       t->t.op += LTIMES-TIMES;
+               break;
+
+       case ASTIMES:
+       case ASDIV:
+       case ASMOD:
+               if (t->t.type == UNLONG)
+                       t->t.op += ULASTIMES-ASTIMES;
+               else
+                       t->t.op += LASTIMES-ASTIMES;
+               t->t.tr1 = tnode(AMPER, LONG+PTR, t->t.tr1, TNULL);
+               break;
+
+       default:
+               return(t);
+       }
+       return(optim(t));
+}
+
+/*
+ * Is tree of unsigned type?
+ */
+int uns(tp) union tree *tp; {
+       register int t;
+
+       t = tp->t.type;
+       if (t==UNSIGN || t==UNCHAR || t==UNLONG || t&XTYPE)
+               return(1);
+       return(0);
+}
diff --git a/c13.c b/c13.c
new file mode 100644 (file)
index 0000000..77024ec
--- /dev/null
+++ b/c13.c
@@ -0,0 +1,459 @@
+/*
+ * C second pass -- tables
+ */
+
+#if    !defined(lint) && defined(DOSCCS)
+static char    sccsid[] = "@(#)c13.c   2.1 (2.11BSD GTE) 10/4/94";
+#endif
+
+#include "c1.h"
+/*
+ * Operator dope table-- see description in c0.
+ */
+int opdope[] = {
+       000000, /* EOFC (0) */
+       000000, /* ; */
+       000000, /* { */
+       000000, /* } */
+       036000, /* [ */
+       002000, /* ] */
+       036000, /* ( */
+       002000, /* ) */
+       014201, /* : */
+       007001, /* , */
+       000000, /* field selection (10) */
+       000000, /* reverse field selection */
+       000001, /* temporary field selection */
+       000001, /* int->ptr */
+       000001, /* ptr->int */
+       000001, /* long->ptr */
+       000001, /* field assignment */
+       000001, /* >> unsigned */
+       000001, /* >>= unsigned */
+       000000, /* keyword */
+       000400, /* name (20) */
+       000400, /* short constant */
+       000400, /* string */
+       000400, /* float */
+       000400, /* double */
+       000400, /* long const */
+       000400, /* long const <= 16 bits */
+       000400, /* autoi, *r++ */
+       000400, /* autod, *--r */
+       000400, /* () empty arglist */
+       034213, /* ++pre (30) */
+       034213, /* --pre */
+       034213, /* ++post */
+       034213, /* --post */
+       034220, /* !un */
+       034202, /* &un */
+       034220, /* *un */
+       034200, /* -un */
+       034220, /* ~un */
+       036001, /* . (structure reference) */
+       030101, /* + (40) */
+       030001, /* - */
+       032101, /* * */
+       032001, /* / */
+       032001, /* % */
+       026061, /* >> */
+       026061, /* << */
+       020161, /* & */
+       016161, /* | */
+       016161, /* ^ */
+       036001, /* -> (50) */
+       001000, /* int -> double */
+       001000, /* double -> int */
+       000001, /* && */
+       000001, /* || */
+       030001, /* &~ */
+       001000, /* double -> long */
+       001000, /* long -> double */
+       001000, /* integer -> long */
+       000000, /* long -> integer */
+       022005, /* == (60) */
+       022005, /* != */
+       024005, /* <= */
+       024005, /* < */
+       024005, /* >= */
+       024005, /* > */
+       024005, /* <p */
+       024005, /* <=p */
+       024005, /* >p */
+       024005, /* >=p */
+       012213, /* += (70) */
+       012213, /* -= */
+       012213, /* *= */
+       012213, /* /= */
+       012213, /* %= */
+       012253, /* >>= */
+       012253, /* <<= */
+       012253, /* &= */
+       012253, /* |= */
+       012253, /* ^= */
+       012213, /* = (80) */
+       030001, /* & for tests */
+       032001, /*  * (long) */
+       032001, /*  / (long) */
+       032001, /* % (long) */
+       012253, /* &= ~ */
+       012213, /* *= (long) */
+       012213, /* /= (long) */
+       012213, /* %= (long) */
+       000000, /* (89) */
+       014201, /* question '?' (90) */
+       026061, /* long << */
+       012253, /* long <<= */
+       000101, /* max */
+       000101, /* maxp */
+       000101, /* min */
+       000101, /* minp */
+       000001, /* , */
+       000000, /* call1 */
+       000000, /* call2 */
+       036001, /* call (100) */
+       036000, /* mcall */
+       000000, /* goto */
+       000000, /* jump cond */
+       000000, /* branch cond */
+       000400, /* set nregs */
+       000000, /* load */
+       030001, /* ptoi1 */
+       000000, /* (108) */
+       000000, /* int->char */
+       000000, /* force r0 (110) */
+       000000, /* branch */
+       000000, /* label */
+       000000, /* nlabel */
+       000000, /* rlabel */
+       000000, /* structure assign */
+       000001, /* struct assignment setup */
+       032001, /* unsigned / */
+       032001, /* unsigned % */
+       012213, /* unsigned /= */
+       012213, /* unsigned %= (120) */
+       032001, /* unsigned long * */
+       032001, /* unsigned long / */
+       032001, /* unsigned long % */
+       012213, /* unsigned long *= */
+       012213, /* unsigned long /= */
+       012213, /* unsigned long %= */
+       01000,  /* unsigned long -> float(double) */
+       026061, /* unsigned long >> */
+       012253, /* unsigned long >>= (129) */
+};
+
+char   *opntab[] = {
+       0,                      /* 0 */
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       ":",
+       ",",
+       "field select",         /* 10 */
+       0,
+       0,
+       "int->ptr",
+       "ptr->int",
+       "long->ptr",
+       "field assign",
+       ">>",
+       ">>=",
+       "keyword",
+       "name",                 /* 20 */
+       "short constant",
+       "string",
+       "float",
+       "double",
+       "long constant",
+       "long constant",
+       "*r++",
+       "*--r",
+       "()",
+       "++pre",                /* 30 */
+       "--pre",
+       "++post",
+       "--post",
+       "!un",
+       "&",
+       "*",
+       "-",
+       "~",
+       ".",
+       "+",                    /* 40 */
+       "-",
+       "*",
+       "/",
+       "%",
+       ">>",
+       "<<",
+       "&",
+       "|",
+       "^",
+       "->",                   /* 50 */
+       "int->double",
+       "double->int",
+       "&&",
+       "||",
+       "&~",
+       "double->long",
+       "long->double",
+       "integer->long",
+       "long->integer",
+       "==",                   /* 60 */
+       "!=",
+       "<=",
+       "<",
+       ">=",
+       ">",
+       "<p",
+       "<=p",
+       ">p",
+       ">=p",
+       "+=",                   /* 70 */
+       "-=",
+       "*=",
+       "/=",
+       "%=",
+       ">>=",
+       "<<=",
+       "&=",
+       "|=",
+       "^=",
+       "=",                    /* 80 */
+       "& for tests",
+       "*",
+       "/",
+       "%",
+       "&= ~",
+       "*=",
+       "/=",
+       "%=",
+       0,
+       "?",                    /* 90 */
+       "<<",
+       "<<=",
+       "\\/",
+       "\\/",
+       "/\\",
+       "/\\",
+       ",",
+       "call1",
+       "call2",
+       "call",                 /* 100 */
+       "mcall",
+       "goto",
+       "jump cond",
+       "branch cond",
+       "set nregs",
+       "load value",
+       "ptr->integer",
+       0,
+       "int->char",
+       "force register",       /* 110 */
+       "branch",
+       "label",
+       "nlabel",
+       "rlabel",
+       "=structure",
+       "= (struct setup)",
+       "/",
+       "%",
+       "/=",
+       "%=",                   /* 120 */
+       "*",                    /* unsigned long */
+       "/",                    /* unsigned long */
+       "%",                    /* unsigned long */
+       "*=",                   /* unsigned long */
+       "/=",                   /* unsigned long */
+       "%=",                   /* unsigned long */
+       "u_long->double",       /* unsigned long */
+       ">>",                   /* unsigned long */
+       ">>=",                  /* 129 unsigned long */
+};
+
+/*
+ * Strings for instruction tables.
+ */
+char mov[] = "mov";
+char clr[] = "clr";
+char cmp[] = "cmp";
+char tst[] = "tst";
+char add[] = "add";
+char sub[] = "sub";
+char inc[] = "inc";
+char dec[] = "dec";
+char mul[] = "mul";
+char _div[] = "div";
+char asr[] = "asr";
+char ash[] = "ash";
+char asl[] = "asl";
+char bic[] = "bic";
+char bic1[] = "bic $1,";
+char bit[] = "bit";
+char bit1[] = "bit $1,";
+char bis[] = "bis";
+char bis1[] = "bis $1,";
+char xor[] = "xor";
+char neg[] = "neg";
+char com[] = "com";
+char stdol[] = "*$";
+char ashc[] = "ashc";
+char slmul[] = "lmul";
+char sldiv[] = "ldiv";
+char slrem[] = "lrem";
+char uldiv[] = "uldiv";
+char ulrem[] = "ulrem";
+char ualdiv[] = "ualdiv";
+char ualrem[] = "ualrem";
+char ultof[] = "ultof";
+char ulsh[] = "ulsh";
+char ualsh[] = "ualsh";
+char almul[] = "almul";
+char aldiv[] = "aldiv";
+char alrem[] = "alrem";
+char udiv[] = "udiv";
+char urem[] = "urem";
+char jeq[] = "jeq";
+char jne[] = "jne";
+char jle[] = "jle";
+char jgt[] = "jgt";
+char jlt[] = "jlt";
+char jge[] = "jge";
+char jlos[] = "jlos";
+char jhi[] = "jhi";
+char jlo[] = "jlo";
+char jhis[] = "jhis";
+char nop[] = "/nop";
+char jbr[] = "jbr";
+char jpl[] = "jpl";
+char jmi[] = "jmi";
+char jmijne[] = "jmi\tL%d\njne";
+char jmijeq[] = "jmi\tL%d\njeq";
+
+/*
+ * Instruction tables, accessed by
+ * I (first operand) or I' (second) macros.
+ */
+
+struct instab instab[] = {
+       {LOAD,          mov,    tst},
+       {ASSIGN,        mov,    clr},
+       {EQUAL,         cmp,    tst},
+       {NEQUAL,        cmp,    tst},
+       {LESSEQ,        cmp,    tst},
+       {LESS,          cmp,    tst},
+       {GREATEQ,       cmp,    tst},
+       {GREAT,         cmp,    tst},
+       {LESSEQP,       cmp,    tst},
+       {LESSP,         cmp,    tst},
+       {GREATQP,       cmp,    tst},
+       {GREATP,        cmp,    tst},
+       {PLUS,          add,    inc},
+       {ASPLUS,        add,    inc},
+       {MINUS,         sub,    dec},
+       {ASMINUS,       sub,    dec},
+       {INCBEF,        add,    inc},
+       {DECBEF,        sub,    dec},
+       {INCAFT,        add,    inc},
+       {DECAFT,        sub,    dec},
+       {TIMES,         mul,    mul},
+       {ASTIMES,       mul,    mul},
+       {DIVIDE,        _div,   _div},
+       {ASDIV,         _div,   _div},
+       {MOD,           _div,   _div},
+       {ASMOD,         _div,   _div},
+       {PTOI,          _div,   _div},
+       {RSHIFT,        ash,    asr},
+       {ASRSH,         ash,    asr},
+       {LSHIFT,        ash,    asl},
+       {ASLSH,         ash,    asl},
+       {AND,           bic,    bic1},
+       {ANDN,          bic,    bic1},
+       {ASANDN,        bic,    bic1},
+       {TAND,          bit,    bit1},
+       {OR,            bis,    bis1},
+       {ASOR,          bis,    bis1},
+       {EXOR,          xor,    xor},
+       {ASXOR,         xor,    xor},
+       {NEG,           neg,    neg},
+       {COMPL,         com,    com},
+       {CALL1,         stdol,  stdol},
+       {CALL2,         "",     ""},
+       {LLSHIFT,       ashc,   ashc},
+       {ASLSHL,        ashc,   ashc},
+       {LTIMES,        slmul,  slmul},
+       {LDIV,          sldiv,  sldiv},
+       {LMOD,          slrem,  slrem},
+       {LASTIMES,      almul,  almul},
+       {LASDIV,        aldiv,  aldiv},
+       {LASMOD,        alrem,  alrem},
+       {ULSH,          ashc,   ashc},
+       {ASULSH,        ashc,   ashc},
+       {UDIV,          udiv,   udiv},
+       {UMOD,          urem,   urem},
+       {ASUDIV,        udiv,   udiv},
+       {ASUMOD,        urem,   urem},
+       {ULTIMES,       slmul,  slmul},         /* symmetry */
+       {ULDIV,         uldiv,  uldiv},
+       {ULMOD,         ulrem,  ulrem},
+       {ULASTIMES,     almul,  almul},         /* symmetry */
+       {ULASDIV,       ualdiv, ualdiv},
+       {ULASMOD,       ualrem, ualrem},
+       {ULTOF,         ultof,  ultof},
+       {ULLSHIFT,      ulsh,   ulsh},
+       {UASLSHL,       ualsh,  ualsh},
+       {0,             0,      0}
+};
+
+/*
+ * Similar table for relationals.
+ * The first string is for the positive
+ * test, the second for the inverted one.
+ * The '200+' entries are 
+ * used in tests against 0 where a 'tst'
+ * instruction is used; it clears the c-bit
+ * the c-bit so ptr tests are funny.
+ */
+struct instab branchtab[] = {
+       {EQUAL,         jeq,    jne},
+       {NEQUAL,        jne,    jeq},
+       {LESSEQ,        jle,    jgt},
+       {LESS,          jlt,    jge},
+       {GREATEQ,       jge,    jlt},
+       {GREAT,         jgt,    jle},
+       {LESSEQP,       jlos,   jhi},
+       {LESSP,         jlo,    jhis},
+       {GREATQP,       jhis,   jlo},
+       {GREATP,        jhi,    jlos},
+       {200+EQUAL,     jeq,    jne},
+       {200+NEQUAL,    jne,    jeq},
+       {200+LESSEQ,    jmijeq, jmijne},
+       {200+LESS,      jmi,    jpl},
+       {200+GREATEQ,   jpl,    jmi},
+       {200+GREAT,     jmijne, jmijeq},
+       {200+LESSEQP,   jeq,    jne},
+       {200+LESSP,     nop,    jbr},
+       {200+GREATQP,   jbr,    nop},
+       {200+GREATP,    jne,    jeq},
+       {0,             0,      0}
+};
+
+int    line;
+int    nerror;                 /* number of hard errors */
+struct table   lsptab[1];
+int    nstack;
+int    nfloat;
+char   *funcbase;
+char   *curbase;
+char   *coremax;
+long   totspace;
+int    regpanic;               /* set when SU register alg. fails */
+int    panicposs;              /* set when there might be need for regpanic */
+jmp_buf        jmpbuf;
+
+int    xlab1, xlab2, xop, xzero;
diff --git a/cvopt.c b/cvopt.c
new file mode 100644 (file)
index 0000000..b7d04dd
--- /dev/null
+++ b/cvopt.c
@@ -0,0 +1,461 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int    tabflg;
+int    labno   = 1;
+int opno;
+FILE   *curbuf;
+FILE   *obuf;
+FILE   *oobuf;
+char  oname[]="/tmp/cvoptaXXXXXX";
+char ooname[]="/tmp/cvoptbXXXXXX";
+char lbuf[BUFSIZ];
+char *lbufp = lbuf;
+
+#ifndef __P
+#ifdef __STDC__
+#define __P(args) args
+#else
+#define __P(args) ()
+#endif
+#endif
+
+int main __P((int argc, char **argv));
+int flag __P((void));
+void put __P((int c));
+void comment __P((int c));
+
+int main(argc, argv) int argc; char **argv; {
+/*
+       A1 -> A
+       A2    B
+       A     O
+       B1    C
+       B2    D
+       BE    L
+       BF    P
+       C1    E
+       C2    F
+       F     G
+       H     H
+       R     I
+       R1    J
+       S     K
+       I     M
+       M     N
+
+               *       +1
+               S       +2
+               C       +4
+               1       +8
+
+       z  -> 4
+       c     10
+       a     14
+       e     20
+       n     63
+       *       +0100
+*/
+
+       int c, snlflg, nlflg, t, smode, m, ssmode, peekc, side;
+#ifndef pdp11
+       int fd;
+#endif
+
+       smode = nlflg = snlflg = ssmode = 0;
+       if (argc>1)
+               if (freopen(argv[1], "r", stdin) == NULL) {
+                       fprintf(stderr, "%s?\n", argv[1]);
+                       return(1);
+               }
+       if (argc>2) 
+               if (freopen(argv[2], "w", stdout) == NULL) {
+                       fprintf(stderr, "%s?\n", argv[2]);
+                       return(1);
+               }
+#ifdef pdp11
+       mktemp(oname);
+       if ((obuf = fopen(oname, "w")) == NULL) {
+               fprintf(stderr, "%s?\n", oname);
+               exit(1);
+       }
+       mktemp(ooname);
+       if ((oobuf = fopen(ooname, "w")) == NULL) {
+               fprintf(stderr, "%s?\n", ooname);
+               exit(1);
+       }
+#else
+       fd = mkstemp(oname);
+       if (fd < 0 || (obuf = fdopen(fd, "w")) == NULL) {
+               fprintf(stderr, "%s?\n", oname);
+               exit(1);
+       }
+       fd = mkstemp(ooname);
+       if (fd < 0 || (oobuf = fdopen(fd, "w")) == NULL) {
+               fprintf(stderr, "%s?\n", ooname);
+               exit(1);
+       }
+#endif
+       printf("#include \"c1.h\"");
+       curbuf = obuf;
+loop:
+       c = getchar();
+       if (c!='\n' && c!='\t')
+               nlflg = 0;
+       if (ssmode!=0 && c!='%') {
+               ssmode = 0;
+               curbuf = stdout;
+               fprintf(curbuf, "\nstatic char L%d[]=\"", labno++);
+       }
+       switch(c) {
+
+       case EOF:
+               fprintf(obuf, "\t{0},\n};\n");
+               fclose(obuf);
+               if (freopen(oname, "r", stdin) == NULL) {
+                       fprintf(stderr, "%s?\n",oname);
+                       exit(1);
+               }
+               while ((c = getchar()) != EOF)
+                       putchar(c);
+               unlink(oname);
+               fclose(oobuf);
+               if (freopen(ooname, "r", stdin) == NULL) {
+                       fprintf(stderr, "%s?\n",ooname);
+                       exit(1);
+               }
+               while ((c = getchar()) != EOF)
+                       putchar(c);
+               unlink(ooname);
+               return(0);
+
+       case 'A':
+               if ((c=getchar())=='1' || c=='2') {
+                       put(c+'A'-'1');
+                       goto loop;
+               }
+               put('O');
+               ungetc(c, stdin);
+               goto loop;
+
+       case 'B':
+               switch (getchar()) {
+
+               case '1':
+                       put('C');
+                       goto loop;
+
+               case '2':
+                       put('D');
+                       goto loop;
+
+               case 'E':
+                       put('L');
+                       goto loop;
+
+               case 'F':
+                       put('P');
+                       goto loop;
+               }
+               put('?');
+               goto loop;
+
+       case 'C':
+               put(getchar()+'E'-'1');
+               goto loop;
+
+       case 'F':
+               put('G');
+               goto subtre;
+
+       case 'R':
+               if ((c=getchar()) == '1')
+               put('J'); else {
+                       put('I');
+                       ungetc(c, stdin);
+               }
+               goto loop;
+
+       case 'H':
+               put('H');
+               goto subtre;
+
+       case 'I':
+               put('M');
+               goto loop;
+
+       case 'S':
+               put('K');
+subtre:
+               snlflg = 1;
+               t = 'A';
+l1:
+               switch (c=getchar()) {
+
+               case '*':
+                       t++;
+                       goto l1;
+
+               case 'S':
+                       t += 2;
+                       goto l1;
+
+               case 'C':
+                       t += 4;
+                       goto l1;
+
+               case '1':
+                       t += 8;
+                       goto l1;
+
+               case '2':
+                       t += 16;
+                       goto l1;
+               }
+               ungetc(c, stdin);
+               put(t);
+               goto loop;
+
+       case '#':
+               if(getchar()=='1')
+                       put('#'); else
+                       put('"');
+               goto loop;
+
+       case '%':
+               if (smode)
+                       curbuf = obuf;
+               if (ssmode==0) {
+                       if ((peekc=getchar())=='[') {
+                               printf("\n#define ");
+                               while((c=getchar())!=']' && c!=':')
+                                       putchar(c);
+                               printf(" L%d\n",labno);
+                               if (c==':') getchar();
+                               getchar();
+                               curbuf = obuf;
+                               goto loop;
+                       }
+                       ungetc(peekc, stdin);
+               }
+               side=0;
+loop1:
+               switch (c=getchar()) {
+
+               case ' ':
+               case '\t':
+                       goto loop1;
+               case 'a':
+                       m = 16;
+                       t = flag();
+                       goto pf;
+
+               case ',':
+                       side=1;
+                       goto loop1;
+
+               case 'i':
+                       m = 12;
+                       t = flag();
+                       goto pf;
+               case 'z':
+                       m = 4;
+                       t = flag();
+                       goto pf;
+
+               case 'r':
+                       m = 9;
+                       t = flag();
+                       goto pf;
+
+               case '1':
+                       m = 5;
+                       t = flag();
+                       goto pf;
+
+               case 'c':
+                       t = 0;
+                       m = 8;
+                       goto pf;
+
+               case 'e':
+                       t = flag();
+                       m = 20;
+                       goto pf;
+
+               case 'n':
+                       t = flag();
+                       m = 63;
+pf:
+                       if ((c=getchar())=='*')
+                               m += 0100; else
+                               ungetc(c, stdin);
+                       if (side==0) {
+                               if (opno==0) fprintf(curbuf,"\nstruct optab optab[]={\n");
+                               fprintf(curbuf,"\t{");
+                       }
+                       fprintf(curbuf, "%d,%d,", m, t);
+                       goto loop1;
+               case '[':
+                       printf("\n#define L%d ", labno++);
+                       while ((c=getchar())!=']')
+                               putchar(c);
+                       printf("\n");
+                       ssmode = 0;
+                       smode = 0;
+                       goto loop;
+
+               case '{':
+               for(;;) {
+                       while ((c=getchar())!='%') putc(c,oobuf);
+                       if ((c=getchar())=='}') goto loop;
+                       else {putc('%',oobuf); putc(c,oobuf);}
+               }
+                       
+               case '\n':
+                       fprintf(curbuf, "L%d},  /* %d */\n", labno,opno);
+                       ++opno;
+                       ssmode = 1;
+                       nlflg = 1;
+                       smode = 1;
+                       goto loop;
+
+               case '/':
+                       comment(c); goto loop1;
+
+               }
+               put(c);
+               goto loop1;
+
+       case '\t':
+               if (nlflg) {
+                       nlflg = 0;
+                       goto loop;
+               }
+               if (smode) {
+                       tabflg++;
+                       goto loop;
+               }
+               put('\t');
+               goto loop;
+
+       case '\n':
+               lbufp=lbuf;
+               if (!smode)  {
+                       put('\n');
+                       goto loop;
+               }
+               if (nlflg) {
+                       nlflg = 0;
+                       fprintf(curbuf, "\";");
+                       curbuf = obuf;
+                       smode = 0;
+                       goto loop;
+               }
+               if (!snlflg)
+                       fprintf(curbuf, "\\n");
+               snlflg = 0;
+               nlflg = 1;
+               goto loop;
+
+       case '/':
+               comment(c); goto loop;
+
+       case 'X':
+       case 'Y':
+       case 'T':
+               snlflg++;
+               break;
+
+       case ':':
+               fseek(curbuf,(long)(lbuf-lbufp),2);
+               *lbufp='\0';
+               if (opno!=0) {fprintf(curbuf,"\t{0},\n"); ++opno;}
+               printf("\n#define %s &optab[%d]\n",lbuf,opno);
+               fprintf(curbuf,"/* %s */",lbuf);
+               lbufp=lbuf;
+               goto loop;
+
+       }
+       *lbufp++=c;
+       put(c);
+       goto loop;
+}
+
+int flag() {
+       register int c, f;
+
+       f = 0;
+l1:
+       switch(c=getchar()) {
+
+       case 'w':
+               f = 1;
+               goto l1;
+
+       case 'i':
+               f = 2;
+               goto l1;
+
+       case 'b':
+               if (f==9)               /* unsigned word/int seen yet? */
+                       f = 10;         /*  yes - it is unsigned byte */
+               else
+                       f = 3;          /*  no - it is regular (signed) byte */
+               goto l1;
+
+       case 'f':
+               f = 4;
+               goto l1;
+
+       case 'd':
+               f = 5;
+               goto l1;
+
+       case 'u':
+               if (f==3)               /* regular (signed) byte seen ? */
+                       f = 10;         /*  yes - unsigned byte now */
+               else if (f == 8)        /* regular (signed) long seen? */
+                       f = 11;         /*  yes - it is unsigned long now */
+               else
+                       f = 9;          /* otherwise we have unsigned word */
+               goto l1;
+
+       case 's':
+               f = 6;
+               goto l1;
+
+       case 'l':
+               if (f == 9)             /* seen unsigned yet? */
+                       f = 11;         /*  yes - it is unsigned long now */
+               else
+                       f = 8;          /*  no - it is unsigned word now */
+               goto l1;
+
+       case 'p':
+               f += 16;
+               goto l1;
+       }
+       ungetc(c, stdin);
+       return(f);
+}
+
+void put(c) int c; {
+       if (tabflg) {
+               tabflg = 0;
+               fprintf(curbuf, "\\%o", c+0200);
+       } else {
+               if (c=='"') putc('\\',curbuf);
+               putc(c, curbuf);
+       }
+}
+
+void comment(c) int c; {
+       putc(c,curbuf);
+       if ((c=getchar())=='*') for (;;) {
+               do putc(c,curbuf); while ((c=getchar())!='*');
+               putc(c,curbuf);
+               if ((c=getchar())=='/') {putc(c,curbuf); break;}
+       } else ungetc(c,stdin);
+}
diff --git a/fp.c b/fp.c
new file mode 100644 (file)
index 0000000..241b733
--- /dev/null
+++ b/fp.c
@@ -0,0 +1,681 @@
+#ifndef pdp11
+#include <errno.h>
+#include <stdlib.h>
+#include "c1.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 1
+#endif
+
+/* Floating point accumulators */
+
+#if 0
+/* PSW */
+
+#define        PSW_V_C         0                               /* condition codes */
+#define PSW_V_V                1
+#define PSW_V_Z                2
+#define PSW_V_N        3
+#endif
+
+/* FPS */
+
+#define        FPS_V_C         0                               /* condition codes */
+#define FPS_V_V                1
+#define FPS_V_Z                2
+#define FPS_V_N        3
+#define FPS_V_T                5                               /* truncate */
+#define FPS_V_L                6                               /* long */
+#define FPS_V_D                7                               /* double */
+#define FPS_V_IC       8                               /* ic err int */
+#define FPS_V_IV       9                               /* overflo err int */
+#define FPS_V_IU       10                              /* underflo err int */
+#define FPS_V_IUV      11                              /* undef var err int */
+#define FPS_V_ID       14                              /* int disable */
+#define FPS_V_ER       15                              /* error */
+
+/* Floating point status register */
+
+#define FPS_ER         (1u << FPS_V_ER)                /* error */
+#define FPS_ID         (1u << FPS_V_ID)                /* interrupt disable */
+#define FPS_IUV                (1u << FPS_V_IUV)               /* int on undef var */
+#define FPS_IU         (1u << FPS_V_IU)                /* int on underflow */
+#define FPS_IV         (1u << FPS_V_IV)                /* int on overflow */
+#define FPS_IC         (1u << FPS_V_IC)                /* int on conv error */
+#define FPS_D          (1u << FPS_V_D)                 /* single/double */
+#define FPS_L          (1u << FPS_V_L)                 /* word/long */
+#define FPS_T          (1u << FPS_V_T)                 /* round/truncate */
+#define FPS_N          (1u << FPS_V_N)
+#define FPS_Z          (1u << FPS_V_Z)
+#define FPS_V          (1u << FPS_V_V)
+#define FPS_C          (1u << FPS_V_C)
+#define FPS_CC         (FPS_N + FPS_Z + FPS_V + FPS_C)
+#define FPS_RW         (FPS_ER + FPS_ID + FPS_IUV + FPS_IU + FPS_IV + \
+                       FPS_IC + FPS_D + FPS_L + FPS_T + FPS_CC)
+
+/* Floating point exception codes */
+
+#define FEC_OP         2                               /* illegal op/mode */
+#define FEC_DZRO       4                               /* divide by zero */
+#define FEC_ICVT       6                               /* conversion error */
+#define FEC_OVFLO      8                               /* overflow */
+#define FEC_UNFLO      10                              /* underflow */
+#define FEC_UNDFV      12                              /* undef variable */
+
+/* Floating point format, all assignments 32b relative */
+
+#define FP_V_SIGN      (63 - 32)                       /* high lw: sign */
+#define FP_V_EXP       (55 - 32)                       /* exponent */
+#define FP_V_HB                FP_V_EXP                        /* hidden bit */
+#define FP_V_F0                (48 - 32)                       /* fraction 0 */
+#define FP_V_F1                (32 - 32)                       /* fraction 1 */
+#define FP_V_FROUND    (31 - 32)                       /* f round point */
+#define FP_V_F2                16                              /* low lw: fraction 2 */
+#define FP_V_F3                0                               /* fraction 3 */
+#define FP_V_DROUND    (-1)                            /* d round point */
+#define FP_M_EXP       0377
+#define FP_SIGN                (1u << FP_V_SIGN)
+#define FP_EXP         (FP_M_EXP << FP_V_EXP)
+#define FP_HB          (1u << FP_V_HB)
+#define FP_FRACH       ((1u << FP_V_HB) - 1)
+#define FP_FRACL       0xFFFFFFFF
+#define FP_BIAS                0200                            /* exponent bias */
+#define FP_GUARD       3                               /* guard bits */
+
+#if 0
+/* Data lengths */
+
+#define _WORD  2
+#define _LONG  4
+#define _QUAD  8
+#endif
+
+/* Double precision operations on 64b quantities */
+
+#define F_LOAD(qd,ac,ds) ds.h = ac.h; ds.l = (qd)? ac.l: 0
+#define F_LOAD_P(qd,ac,ds) ds->h = ac.h; ds->l = (qd)? ac.l: 0
+#define F_LOAD_FRAC(qd,ac,ds) ds.h = (ac.h & FP_FRACH) | FP_HB; \
+       ds.l = (qd)? ac.l: 0
+#define F_STORE(qd,sr,ac) ac.h = sr.h; if ((qd)) ac.l = sr.l
+#define F_STORE_P(qd,sr,ac) ac.h = sr->h; if ((qd)) ac.l = sr->l
+#define F_GET_FRAC_P(sr,ds) ds.l = sr->l; \
+       ds.h = (sr->h & FP_FRACH) | FP_HB
+#define F_ADD(s2,s1,ds) ds.l = (s1.l + s2.l) & 0xFFFFFFFF; \
+       ds.h = (s1.h + s2.h + (ds.l < s2.l)) & 0xFFFFFFFF
+#define F_SUB(s2,s1,ds) ds.h = (s1.h - s2.h - (s1.l < s2.l)) & 0xFFFFFFFF; \
+       ds.l = (s1.l - s2.l) & 0xFFFFFFFF
+#define F_LT(x,y) ((x.h < y.h) || ((x.h == y.h) && (x.l < y.l)))
+#define F_LT_AP(x,y) (((x->h & ~FP_SIGN) < (y->h & ~FP_SIGN)) || \
+       (((x->h & ~FP_SIGN) == (y->h & ~FP_SIGN)) && (x->l < y->l)))
+#define F_LSH_V(sr,n,ds) \
+       ds.h = (((n) >= 32)? (sr.l << ((n) - 32)): \
+               (sr.h << (n)) | ((sr.l >> (32 - (n))) & and_mask[n])) \
+               & 0xFFFFFFFF; \
+       ds.l = ((n) >= 32)? 0: (sr.l << (n)) & 0xFFFFFFFF
+#define F_RSH_V(sr,n,ds) \
+       ds.l = (((n) >= 32)? (sr.h >> ((n) - 32)) & and_mask[64 - (n)]: \
+               ((sr.l >> (n)) & and_mask[32 - (n)]) | \
+               (sr.h << (32 - (n)))) & 0xFFFFFFFF; \
+       ds.h = ((n) >= 32)? 0: \
+               ((sr.h >> (n)) & and_mask[32 - (n)]) & 0xFFFFFFFF
+
+/* For the constant shift macro, arguments must in the range [2,31] */
+
+#define F_LSH_1(ds) ds.h = ((ds.h << 1) | ((ds.l >> 31) & 1)) & 0xFFFFFFFF; \
+       ds.l = (ds.l << 1) & 0xFFFFFFFF
+#define F_RSH_1(ds) ds.l = ((ds.l >> 1) & 0x7FFFFFFF) | ((ds.h & 1) << 31); \
+       ds.h = ((ds.h >> 1) & 0x7FFFFFFF)
+#define F_LSH_K(sr,n,ds) \
+       ds.h =  ((sr.h << (n)) | ((sr.l >> (32 - (n))) & and_mask[n])) \
+               & 0xFFFFFFFF; \
+       ds.l = (sr.l << (n)) & 0xFFFFFFFF
+#define F_RSH_K(sr,n,ds) \
+       ds.l =  (((sr.l >> (n)) & and_mask[32 - (n)]) | \
+               (sr.h << (32 - (n)))) & 0xFFFFFFFF; \
+       ds.h =  ((sr.h >> (n)) & and_mask[32 - (n)]) & 0xFFFFFFFF
+#define F_LSH_GUARD(ds) F_LSH_K(ds,FP_GUARD,ds)
+#define F_RSH_GUARD(ds) F_RSH_K(ds,FP_GUARD,ds)
+
+#define GET_BIT(ir,n)  (((ir) >> (n)) & 1)
+#define GET_SIGN(ir)   GET_BIT((ir), FP_V_SIGN)
+#define GET_EXP(ir)    (((ir) >> FP_V_EXP) & FP_M_EXP)
+#define GET_SIGN_L(ir) GET_BIT((ir), 31)
+#define GET_SIGN_W(ir) GET_BIT((ir), 15)
+
+int32_t FEC = 0;
+int32_t FPS = FPS_D; /* default to double precision */
+
+_DOUBLE zero_fac = { 0, 0 };
+_DOUBLE one_fac = { 1, 0 };
+_DOUBLE fround_fac = { (1u << (FP_V_FROUND + 32)), 0 };
+_DOUBLE fround_guard_fac = { 0, (1u << (FP_V_FROUND + FP_GUARD)) };
+_DOUBLE dround_guard_fac = { (1u << (FP_V_DROUND + FP_GUARD)), 0 };
+_DOUBLE fmask_fac = { 0xFFFFFFFF, (1u << (FP_V_HB + FP_GUARD + 1)) - 1 };
+static const uint32_t and_mask[33] = { 0,
+       0x1, 0x3, 0x7, 0xF,
+       0x1F, 0x3F, 0x7F, 0xFF,
+       0x1FF, 0x3FF, 0x7FF, 0xFFF,
+       0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
+       0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF,
+       0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF,
+       0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,
+       0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF };
+
+#ifndef __P
+#ifdef __STDC__
+#define __P(params) params
+#else
+#define __P(params) ()
+#endif
+#endif
+
+static void tstfp11 __P((_DOUBLE *fsrc));
+static void absfp11 __P((_DOUBLE *fsrc));
+static void negfp11 __P((_DOUBLE *fsrc));
+static void cmpfp11 __P((_DOUBLE *fac, _DOUBLE *fsrc));
+static int32_t moviefp11 __P((int32_t val, _DOUBLE *fac));
+static int32_t moveifp11 __P((_DOUBLE *val));
+static int32_t moviffp11 __P((int32_t val, _DOUBLE *fac));
+static int32_t movfifp11 __P((_DOUBLE *val, int32_t *dst));
+static int32_t addfp11 __P((_DOUBLE *facp, _DOUBLE *fsrcp));
+static int32_t mulfp11 __P((_DOUBLE *facp, _DOUBLE *fsrcp));
+static void frac_mulfp11 __P((_DOUBLE *f1p, _DOUBLE *f2p));
+static int32_t divfp11 __P((_DOUBLE *facp, _DOUBLE *fsrcp));
+static int32_t roundfp11 __P((_DOUBLE *fptr));
+static int32_t round_and_pack __P((_DOUBLE *facp, int32_t exp, _DOUBLE *fracp, int r));
+static int32_t fpnotrap __P((int32_t code));
+
+int fp_tst(val) _DOUBLE val; {
+       tstfp11(&val);
+       return (FPS & FPS_Z) != 0;
+}
+
+_DOUBLE fp_abs(val) _DOUBLE val; {
+       absfp11(&val);
+       return val;
+}
+
+_DOUBLE fp_neg(val) _DOUBLE val; {
+       negfp11(&val);
+       return val;
+}
+
+int fp_le(val0, val1) _DOUBLE val0; _DOUBLE val1; {
+       cmpfp11(&val0, &val1);
+       return (FPS & FPS_N) == 0;
+}
+
+int fp_ge(val0, val1) _DOUBLE val0; _DOUBLE val1; {
+       cmpfp11(&val1, &val0);
+       return (FPS & FPS_N) == 0;
+}
+
+int fp_gt(val0, val1) _DOUBLE val0; _DOUBLE val1; {
+       cmpfp11(&val0, &val1);
+       return (FPS & FPS_N) != 0;
+}
+
+int fp_lt(val0, val1) _DOUBLE val0; _DOUBLE val1; {
+       cmpfp11(&val1, &val0);
+       return (FPS & FPS_N) != 0;
+}
+
+_INT fp_double_to_int(val) _DOUBLE val; {
+       int32_t res;
+
+       if (movfifp11(&val, &res))
+               abort();
+       return (_INT)res;
+}
+
+_LONG fp_double_to_long(val) _DOUBLE val; {
+       int32_t res;
+
+       FPS |= FPS_L;
+       if (movfifp11(&val, &res))
+               abort();
+       FPS &= ~FPS_L;
+       return (_LONG)res;
+}
+
+_FLOAT fp_double_to_float(val) _DOUBLE val; {
+       _FLOAT res;
+
+       if (roundfp11(&val))
+               abort();
+       res.h = val.h;
+       return res;
+}
+
+_DOUBLE fp_int_to_double(val) _INT val; {
+       _DOUBLE res;
+
+       if (moviffp11((int32_t)val << 16, &res))
+               abort();
+       return res;
+}
+
+_DOUBLE fp_long_to_double(val) _LONG val; {
+       _DOUBLE res;
+
+       FPS |= FPS_L;
+       if (moviffp11((int32_t)val, &res))
+               abort();
+       FPS &= ~FPS_L;
+       return res;
+}
+
+_DOUBLE fp_float_to_double(val) _FLOAT val; {
+       _DOUBLE res;
+
+       res.h = val.h;
+       res.l = 0;
+       return res;
+}
+
+_DOUBLE fp_add(val0, val1) _DOUBLE val0; _DOUBLE val1; {
+       if (addfp11(&val0, &val1))
+               abort();
+       return val0;
+}
+
+_DOUBLE fp_sub(val0, val1) _DOUBLE val0; _DOUBLE val1; {
+       negfp11(&val1);
+       if (addfp11(&val0, &val1))
+               abort();
+       return val0;
+}
+
+_DOUBLE fp_mul(val0, val1) _DOUBLE val0; _DOUBLE val1; {
+       if (mulfp11(&val0, &val1))
+               abort();
+       return val0;
+}
+
+_DOUBLE fp_div(val0, val1) _DOUBLE val0; _DOUBLE val1; {
+       if (divfp11(&val0, &val1))
+               abort();
+       return val0;
+}
+
+_DOUBLE fp_ldexp(val, exp) _DOUBLE val; _INT exp; {
+       tstfp11(&val);
+       if ((FPS & FPS_Z) == 0 && moviefp11(moveifp11(&val) + (int32_t)exp, &val)) {
+               val.l = 0xFFFFFFFF;
+               val.h = ((FPS << (31 - FPS_V_N)) | 0x7FFFFFFF) & 0xFFFFFFFF;
+               errno = ERANGE;
+       }
+       return val;
+}
+
+/* cut-down routines by Nick, previously inline to instruction decode */
+static void tstfp11(fsrc) _DOUBLE *fsrc; {
+       FPS = FPS & ~FPS_CC;
+       if (GET_SIGN (fsrc->h)) FPS = FPS | FPS_N;
+       if (GET_EXP (fsrc->h) == 0) FPS = FPS | FPS_Z;
+}
+
+static void absfp11(fsrc) _DOUBLE *fsrc; {
+       if (GET_EXP (fsrc->h) == 0) *fsrc = zero_fac;
+       else fsrc->h = fsrc->h & ~FP_SIGN;
+}
+
+static void negfp11(fsrc) _DOUBLE *fsrc; {
+       if (GET_EXP (fsrc->h) == 0) *fsrc = zero_fac;
+       else fsrc->h = fsrc->h ^ FP_SIGN;
+}
+
+/* from PDP-11/70 processor manual:
+ *   FC <- 0.
+ *   FV <- 0.
+ *   FZ <- 1 If (FSRC) - (AC) = 0, else FZ <- 0.
+ *   FN <- 1 If (FSRC) - (AC) < 0, else FN <- 0.
+ * (backwards compared to what I expected)
+ */
+static void cmpfp11(fac, fsrc) _DOUBLE *fac; _DOUBLE *fsrc; {
+       if (GET_EXP (fsrc->h) == 0) *fsrc = zero_fac;
+       if (GET_EXP (fac->h) == 0) *fac = zero_fac;
+       if ((fsrc->h == fac->h) && (fsrc->l == fac->l)) {       /* equal? */
+           FPS = (FPS & ~FPS_CC) | FPS_Z;
+           return;  }
+       FPS = (FPS & ~FPS_CC) | ((fsrc->h >> (FP_V_SIGN - FPS_V_N)) & FPS_N);
+       if ((GET_SIGN (fsrc->h ^ fac->h) == 0) && (fac->h != 0) &&
+           F_LT ((*fsrc), (*fac))) FPS = FPS ^ FPS_N;
+}
+
+static int32_t moviefp11(val, fac) int32_t val; _DOUBLE *fac; {
+       fac->h = (fac->h & ~FP_EXP) | (((val + FP_BIAS) & FP_M_EXP) << FP_V_EXP);
+       if ((val > 0177) && (val <= 0177600)) {
+           if (val < 0100000) {
+               if (fpnotrap (FEC_OVFLO)) *fac = zero_fac;
+               return FPS_V;  }
+           if (fpnotrap (FEC_UNFLO)) *fac = zero_fac;  }
+       return 0;
+}
+
+static int32_t moveifp11(val) _DOUBLE *val; {
+       return (GET_EXP (val->h) - FP_BIAS) & 0177777;
+}
+
+static int32_t moviffp11(val, fac) int32_t val; _DOUBLE *fac; {
+       int32_t i, qdouble, leni;
+       int32_t exp, sign;
+
+       qdouble = FPS & FPS_D;
+       fac->l = val;
+       fac->h = 0;
+       if (fac->l) {
+           if (sign = GET_SIGN_L (fac->l)) fac->l = (fac->l ^ 0xFFFFFFFF) + 1;
+           for (i = 0; GET_SIGN_L (fac->l) == 0; i++) fac->l = fac->l << 1;
+           exp = ((FPS & FPS_L)? FP_BIAS + 32: FP_BIAS + 16) - i;
+           fac->h = (sign << FP_V_SIGN) | (exp << FP_V_EXP) |
+               ((fac->l >> (31 - FP_V_HB)) & FP_FRACH);
+           fac->l = (fac->l << (FP_V_HB + 1)) & FP_FRACL;
+           if ((FPS & (FPS_D + FPS_T)) == 0) return roundfp11 (fac);  }
+       return 0;
+}
+
+static int32_t movfifp11(val, dst) _DOUBLE *val; int32_t *dst; {
+       int32_t i, qdouble, tolong;
+       int32_t exp, sign;
+       _DOUBLE fac, fsrc;
+       static const uint32_t i_limit[2][2] =
+               { { 0x80000000, 0x80010000 }, { 0x80000000, 0x80000001 } };
+
+       qdouble = FPS & FPS_D;
+       sign = GET_SIGN (val->h);                       /* get sign, */
+       exp = GET_EXP (val->h);                         /* exponent, */
+       F_LOAD_FRAC (qdouble, (*val), fac);             /* fraction */
+       if (FPS & FPS_L) {
+           tolong = 1;
+           i = FP_BIAS + 32;  }
+       else {
+           tolong = 0;
+           i = FP_BIAS + 16;  }
+       if (exp <= FP_BIAS) *dst = 0;
+       else if (exp > i) {
+           *dst = 0;
+           fpnotrap (FEC_ICVT);
+           return FPS_V;  }
+       F_RSH_V (fac, FP_V_HB + 1 + i - exp, fsrc);
+       if (!tolong) fsrc.l = fsrc.l & ~0177777;
+       if (fsrc.l >= i_limit[tolong][sign]) {
+           *dst = 0;
+           fpnotrap (FEC_ICVT);
+           return FPS_V;  }  
+       *dst = fsrc.l;
+       if (sign) *dst = -*dst;
+       return 0;
+}
+
+/* Floating point add
+
+   Inputs:
+       facp    =       pointer to src1 (output)
+       fsrcp   =       pointer to src2
+   Outputs:
+       ovflo   =       overflow variable
+*/
+
+static int32_t addfp11(facp, fsrcp) _DOUBLE *facp; _DOUBLE *fsrcp; {
+int32_t facexp, fsrcexp, ediff;
+_DOUBLE facfrac, fsrcfrac;
+
+if (F_LT_AP (facp, fsrcp)) {                           /* if !fac! < !fsrc! */
+       facfrac = *facp;
+       *facp = *fsrcp;                                 /* swap operands */
+       *fsrcp = facfrac;  }
+facexp = GET_EXP (facp->h);                            /* get exponents */
+fsrcexp = GET_EXP (fsrcp->h);
+if (facexp == 0) {                                     /* fac = 0? */
+       *facp = fsrcexp? *fsrcp: zero_fac;              /* result fsrc or 0 */
+       return 0;  }
+if (fsrcexp == 0) return 0;                            /* fsrc = 0? no op */
+ediff = facexp - fsrcexp;                              /* exponent diff */
+if (ediff >= 60) return 0;                             /* too big? no op */
+F_GET_FRAC_P (facp, facfrac);                          /* get fractions */
+F_GET_FRAC_P (fsrcp, fsrcfrac);
+F_LSH_GUARD (facfrac);                                 /* guard fractions */
+F_LSH_GUARD (fsrcfrac);
+if (GET_SIGN (facp->h) != GET_SIGN (fsrcp->h)) {       /* signs different? */
+       if (ediff) { F_RSH_V (fsrcfrac, ediff, fsrcfrac);  } /* sub, shf fsrc */
+       F_SUB (fsrcfrac, facfrac, facfrac);             /* sub fsrc from fac */
+       if ((facfrac.h | facfrac.l) == 0)  {            /* result zero? */
+           *facp = zero_fac;                           /* no overflow */
+           return 0;  }
+       if (ediff <= 1) {                               /* big normalize? */
+           if ((facfrac.h & (0x00FFFFFF << FP_GUARD)) == 0) {
+               F_LSH_K (facfrac, 24, facfrac);
+               facexp = facexp - 24;  }
+           if ((facfrac.h & (0x00FFF000 << FP_GUARD)) == 0) {
+               F_LSH_K (facfrac, 12, facfrac);
+               facexp = facexp - 12;  }
+           if ((facfrac.h & (0x00FC0000 << FP_GUARD)) == 0) {
+               F_LSH_K (facfrac, 6, facfrac);
+               facexp = facexp - 6;  }  }
+       while (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD) == 0) {
+           F_LSH_1 (facfrac);
+           facexp = facexp - 1;  }  }
+else { if (ediff) { F_RSH_V (fsrcfrac, ediff, fsrcfrac);  } /* add, shf fsrc */
+       F_ADD (fsrcfrac, facfrac, facfrac);             /* add fsrc to fac */
+       if (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD + 1)) {
+           F_RSH_1 (facfrac);                          /* carry out, shift */
+           facexp = facexp + 1;  }  }
+return round_and_pack (facp, facexp, &facfrac, 1);
+}
+
+/* Floating point multiply
+
+   Inputs:
+       facp    =       pointer to src1 (output)
+       fsrcp   =       pointer to src2
+   Outputs:
+       ovflo   =       overflow indicator
+*/
+
+static int32_t mulfp11(facp, fsrcp) _DOUBLE *facp; _DOUBLE *fsrcp; {
+int32_t facexp, fsrcexp;
+_DOUBLE facfrac, fsrcfrac;
+
+facexp = GET_EXP (facp->h);                            /* get exponents */
+fsrcexp = GET_EXP (fsrcp->h);
+if ((facexp == 0) || (fsrcexp == 0)) {                 /* test for zero */
+       *facp = zero_fac;
+       return 0;  }
+F_GET_FRAC_P (facp, facfrac);                          /* get fractions */
+F_GET_FRAC_P (fsrcp, fsrcfrac);
+facexp = facexp + fsrcexp - FP_BIAS;                   /* calculate exp */
+facp->h = facp->h  ^ fsrcp->h;                         /* calculate sign */
+frac_mulfp11 (&facfrac, &fsrcfrac);                    /* multiply fracs */
+
+/* Multiplying two numbers in the range [.5,1) produces a result in the
+   range [.25,1).  Therefore, at most one bit of normalization is required
+   to bring the result back to the range [.5,1).
+*/
+
+if (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD) == 0) {
+       F_LSH_1 (facfrac);
+       facexp = facexp - 1;  }
+return round_and_pack (facp, facexp, &facfrac, 1);
+}
+
+/* Fraction multiply
+
+   Inputs:
+       f1p     =       pointer to multiplier (output)
+       f2p     =       pointer to multiplicand fraction
+
+   Note: the inputs are unguarded; the output is guarded.
+
+   This routine performs a classic shift-and-add multiply.  The low
+   order bit of the multiplier is tested; if 1, the multiplicand is
+   added into the high part of the double precision result.  The
+   result and the multiplier are both shifted right 1.
+
+   For the 24b x 24b case, this routine develops 48b of result.
+   For the 56b x 56b case, this routine only develops the top 64b
+   of the the result.  Because the inputs are normalized fractions,
+   the interesting part of the result is the high 56+guard bits.
+   Everything shifted off to the right, beyond 64b, plays no part
+   in rounding or the result.
+
+   There are many possible optimizations in this routine: scanning
+   for groups of zeroes, particularly in the 56b x 56b case; using
+   "extended multiply" capability if available in the hardware.
+*/
+
+static void frac_mulfp11(f1p, f2p) _DOUBLE *f1p; _DOUBLE *f2p; {
+_DOUBLE result, mpy, mpc;
+int32_t i;
+
+result = zero_fac;                                     /* clear result */
+mpy = *f1p;                                            /* get operands */
+mpc = *f2p;
+F_LSH_GUARD (mpc);                                     /* guard multipicand */
+if ((mpy.l | mpc.l) == 0) {                            /* 24b x 24b? */
+       for (i = 0; i < 24; i++) {
+           if (mpy.h & 1) result.h = result.h + mpc.h;
+           F_RSH_1 (result);
+           mpy.h = mpy.h >> 1;  }  }
+else { if (mpy.l != 0) {                               /* 24b x 56b? */
+           for (i = 0; i < 32; i++) {
+               if (mpy.l & 1) { F_ADD (mpc, result, result);  }
+               F_RSH_1 (result);
+               mpy.l = mpy.l >> 1;  }  }
+       for (i = 0; i < 24; i++) {
+           if (mpy.h & 1) { F_ADD (mpc, result, result);  }
+           F_RSH_1 (result);
+           mpy.h = mpy.h >> 1;  }  }
+*f1p = result;
+return;
+}
+
+/* Floating point divide
+
+   Inputs:
+       facp    =       pointer to dividend (output)
+       fsrcp   =       pointer to divisor
+   Outputs:
+       ovflo   =       overflow indicator
+
+   Source operand must be checked for zero by caller!
+*/
+
+static int32_t divfp11(facp, fsrcp) _DOUBLE *facp; _DOUBLE *fsrcp; {
+int32_t facexp, fsrcexp, i, count, qd;
+_DOUBLE facfrac, fsrcfrac, quo;
+
+fsrcexp = GET_EXP (fsrcp->h);                          /* get divisor exp */
+facexp = GET_EXP (facp->h);                            /* get dividend exp */
+if (facexp == 0) {                                     /* test for zero */
+       *facp = zero_fac;                               /* result zero */
+       return 0;  }
+F_GET_FRAC_P (facp, facfrac);                          /* get fractions */
+F_GET_FRAC_P (fsrcp, fsrcfrac);
+F_LSH_GUARD (facfrac);                                 /* guard fractions */
+F_LSH_GUARD (fsrcfrac);
+facexp = facexp - fsrcexp + FP_BIAS + 1;               /* calculate exp */
+facp->h = facp->h ^ fsrcp->h;                          /* calculate sign */
+qd = FPS & FPS_D;
+count = FP_V_HB + FP_GUARD + (qd? 33: 1);              /* count = 56b/24b */
+
+quo = zero_fac;
+for (i = count; (i > 0) && ((facfrac.h | facfrac.l) != 0); i--) {
+       F_LSH_1 (quo);                                  /* shift quotient */
+       if (!F_LT (facfrac, fsrcfrac)) {                /* divd >= divr? */
+           F_SUB (fsrcfrac, facfrac, facfrac);         /* divd - divr */
+           if (qd) quo.l = quo.l | 1;                  /* double or single? */
+           else quo.h = quo.h | 1;  }
+       F_LSH_1 (facfrac);  }                           /* shift divd */
+if (i > 0) { F_LSH_V (quo, i, quo);  }                 /* early exit? */
+
+/* Dividing two numbers in the range [.5,1) produces a result in the
+   range [.5,2).  Therefore, at most one bit of normalization is required
+   to bring the result back to the range [.5,1).  The choice of counts
+   and quotient bit positions makes this work correctly.
+*/
+
+if (GET_BIT (quo.h, FP_V_HB + FP_GUARD) == 0) {
+       F_LSH_1 (quo);
+       facexp = facexp - 1;  }
+return round_and_pack (facp, facexp, &quo, 1);
+}
+
+/* Round (in place) floating point number to f_floating
+
+   Inputs:
+       fptr    =       pointer to floating number
+   Outputs:
+       ovflow  =       overflow
+*/
+
+static int32_t roundfp11(fptr) _DOUBLE *fptr; {
+_DOUBLE outf;
+
+outf = *fptr;                                          /* get argument */
+F_ADD (fround_fac, outf, outf);                                /* round */
+if (GET_SIGN (outf.h ^ fptr->h)) {                     /* flipped sign? */
+       outf.h = (outf.h ^ FP_SIGN) & 0xFFFFFFFF;       /* restore sign */
+       if (fpnotrap (FEC_OVFLO)) *fptr = zero_fac;     /* if no int, clear */
+       else *fptr = outf;                              /* return rounded */
+       return FPS_V;  }                                /* overflow */
+else { *fptr = outf;                                   /* round was ok */
+       return 0;  }                                    /* no overflow */
+}
+
+/* Round result of calculation, test overflow, pack
+
+   Input:
+       facp    =       pointer to result, sign in place
+       exp     =       result exponent, right justified
+       fracp   =       pointer to result fraction, right justified with
+                       guard bits
+       r       =       round (1) or truncate (0)
+   Outputs:
+       ovflo   =       overflow indicator
+*/
+
+static int32_t round_and_pack(facp, exp, fracp, r) _DOUBLE *facp; int32_t exp; _DOUBLE *fracp; int r; {
+_DOUBLE frac;
+
+frac = *fracp;                                         /* get fraction */
+if (r && ((FPS & FPS_T) == 0)) { 
+       if (FPS & FPS_D) { F_ADD (dround_guard_fac, frac, frac);  }
+       else { F_ADD (fround_guard_fac, frac, frac);  }
+       if (GET_BIT (frac.h, FP_V_HB + FP_GUARD + 1)) {
+           F_RSH_1 (frac);
+           exp = exp + 1;  }  }
+F_RSH_GUARD (frac);
+facp->l = frac.l & FP_FRACL;
+facp->h = (facp->h & FP_SIGN) | ((exp & FP_M_EXP) << FP_V_EXP) |
+       (frac.h & FP_FRACH);
+if (exp > 0377) {
+       if (fpnotrap (FEC_OVFLO)) *facp = zero_fac;
+       return FPS_V;  }
+if ((exp <= 0) && (fpnotrap (FEC_UNFLO))) *facp = zero_fac;
+return 0;
+}
+
+/* Process floating point exception
+
+   Inputs:
+       code    =       exception code
+   Outputs:
+       int     =       FALSE if interrupt enabled, TRUE if disabled
+*/
+
+static int32_t fpnotrap(code) int32_t code; {
+static const int32_t test_code[] = { 0, 0, 0, FPS_IC, FPS_IV, FPS_IU, FPS_IUV };
+
+if ((code >= FEC_ICVT) && (code <= FEC_UNDFV) &&
+    ((FPS & test_code[code >> 1]) == 0)) return TRUE;
+FPS = FPS | FPS_ER;
+FEC = code;
+/*FEA = (backup_PC - 2) & 0177777;*/
+/*if ((FPS & FPS_ID) == 0) setTRAP (TRAP_FPE);*/
+return FALSE;
+}
+#endif
diff --git a/fp_atof.c b/fp_atof.c
new file mode 100644 (file)
index 0000000..c0b1e83
--- /dev/null
+++ b/fp_atof.c
@@ -0,0 +1,111 @@
+#ifndef pdp11
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)atof.c     2.2 (Berkeley) 1/22/87";
+#endif
+
+/*
+ *     C library - ascii to floating
+ */
+
+#include <ctype.h>
+#include "c1.h"
+
+/*#define HUGE 1.701411733192644270e38*/
+#define LOGHUGE 39
+
+_DOUBLE fp_atof(p) register char *p; {
+       register int c;
+       _DOUBLE fl, flexp, exp5;
+       _DOUBLE big = { 0, 056200 << 16 }; /*= 72057594037927936.;*/  /*2^56*/
+       _DOUBLE ten = { 0, 041040 << 16 }; /*= 10.;*/
+       /*_DOUBLE fp_ldexp();*/
+       int nd;
+       register int eexp, exp, neg, negexp, bexp;
+
+       neg = 1;
+       while((c = *p++) == ' ')
+               ;
+       if (c == '-')
+               neg = -1;
+       else if (c=='+')
+               ;
+       else
+               --p;
+
+       exp = 0;
+       /*fl = 0;*/ fl.l = 0; fl.h = 0;
+       nd = 0;
+       while ((c = *p++), isdigit(c)) {
+               if (fp_lt(fl, big))
+                       fl = fp_add(fp_mul(ten, fl), fp_int_to_double(c-'0'));
+               else
+                       exp++;
+               nd++;
+       }
+
+       if (c == '.') {
+               while ((c = *p++), isdigit(c)) {
+                       if (fp_lt(fl, big)) {
+                               fl = fp_add(fp_mul(ten, fl), fp_int_to_double(c-'0'));
+                               exp--;
+                       }
+               nd++;
+               }
+       }
+
+       negexp = 1;
+       eexp = 0;
+       if ((c == 'E') || (c == 'e')) {
+               if ((c= *p++) == '+')
+                       ;
+               else if (c=='-')
+                       negexp = -1;
+               else
+                       --p;
+
+               while ((c = *p++), isdigit(c)) {
+                       eexp = 10*eexp+(c-'0');
+               }
+               if (negexp<0)
+                       eexp = -eexp;
+               exp = exp + eexp;
+       }
+
+       negexp = 1;
+       if (exp<0) {
+               negexp = -1;
+               exp = -exp;
+       }
+
+
+       if((nd+exp*negexp) < -LOGHUGE){
+               /*fl = 0;*/ fl.l = 0; fl.h = 0;
+               exp = 0;
+       }
+       /*flexp = 1;*/ flexp.l = 0; flexp.h = 040200 << 16;
+       /*exp5 = 5;*/ exp5.l = 0; exp5.h = 040640 << 16;
+       bexp = exp;
+       for (;;) {
+               if (exp&01)
+                       flexp = fp_mul(flexp, exp5);
+               exp >>= 1;
+               if (exp==0)
+                       break;
+               exp5 = fp_mul(exp5, exp5);
+       }
+       if (negexp<0)
+               fl = fp_div(fl, flexp);
+       else
+               fl = fp_mul(fl, flexp);
+       fl = fp_ldexp(fl, negexp*bexp);
+       if (neg<0)
+               fl = fp_neg(fl);
+       return(fl);
+}
+#endif
diff --git a/n.sh b/n.sh
new file mode 100755 (executable)
index 0000000..b18b15b
--- /dev/null
+++ b/n.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+make CFLAGS=-g LDC0FLAGS= LDC1FLAGS= "$@"
diff --git a/optable b/optable
new file mode 100644 (file)
index 0000000..ed998e7
--- /dev/null
+++ b/optable
@@ -0,0 +1,2255 @@
+%{
+/*
+ * c code tables-- compile to register
+ */
+#if    !defined(lint) && defined(DOSCCS)
+static char    sccsid[] = "@(#)optable 2.1 (2.11BSD GTE) 10/4/94";
+#endif
+
+struct table regtab[] = {
+       {106,cr106},
+       {30,cr70},
+       {31,cr70},
+       {32,cr32},
+       {33,cr32},
+       {37,cr37},
+       {38,cr37},
+       {98,cr100},
+       {99,cr100},
+       {80,cr80},
+       {40,cr40},
+       {41,cr40        /* - like + */},
+       {42,cr42},
+       {43,cr43},
+       {14,cr14},
+       {44,cr43},
+       {45,cr45},
+       {46,cr40},
+       {55,cr40},
+       {48,cr40},
+       {49,cr49},
+       {70,cr70},
+       {71,cr70},
+       {72,cr72},
+       {73,cr73},
+       {74,cr74},
+       {75,cr75},
+       {76,cr72},
+       {78,cr78},      /* |= */
+       {85,cr78},      /* &= */
+       {79,cr79},
+       {102,cr102},
+       {51,cr51},
+       {52,cr52},
+       {56,cr56},
+       {57,cr57},
+       {58,cr58},
+       {59,cr59},
+       {91,cr91},
+       {82,cr82},
+       {83,cr82},
+       {84,cr82},
+       {86,cr86},
+       {87,cr86},
+       {88,cr86},
+       {16,cr16},
+       {92,cr92},
+       {17,cr43},
+       {18,cr74},
+       {109,cr109},
+       {117,cr117},
+       {118,cr117},
+       {119,cr119},
+       {120,cr119},
+       {107,cr107},
+       {121,cr121},
+       {122,cr121},
+       {123,cr121},
+       {124,cr124},
+       {125,cr124},
+       {126,cr124},
+       {127,cr127},
+       {128,cr128},
+       {129,cr129},
+       {0}
+};
+%}
+
+/* goto */
+cr102:
+%a,n
+       jmp     A1
+
+%n*,n
+       F*
+       jmp     #1(R)
+
+/* call */
+cr100:
+%a,n
+       jsr     pc,IA1
+
+%n*,n
+       F*
+       jsr     pc,#1(R)
+
+%n,n
+       F
+       jsr     pc,(R)
+
+/* addressible */
+cr106:
+%z,n
+       clr     R
+
+%zf,n
+       clrf    R
+
+%aub,n
+       clr     R
+       bisb    A1,R
+
+%a,n
+%ad,n
+       movB1   A1,R
+
+%af,n
+       movof   A1,R
+
+%nub*,n
+       F*
+       movb    #1(R),R
+       bic     $!377,R
+
+%n*,n
+%nd*,n
+       F*
+       movB1   #1(R),R
+
+%nf*,n
+       F*
+       movof   #1(R),R
+
+%al,n
+%aul,n
+       mov     A1+,R+
+       mov     A1,R
+
+%nl*,n
+%nul*,n
+       F*
+       mov     #1+2(R),R+
+       mov     #1(R),R
+
+%n,n
+       F
+
+/* ++,-- postfix */
+cr32:
+%a,1
+       movB1   A1',R
+       I'B1    A1''
+
+%aw,n
+       mov     A1',R
+       I       A2,A1''
+
+%aub,n
+       clr     R
+       bisb    A1',R
+       I'b     A1''
+
+%e*,1
+       F1*
+       movB1   #1(R1),R
+       I'B1    #1(R1)
+
+%n*,1
+       F*
+       movB1   #1(R),-(sp)
+       I'B1    #1(R)
+       movB1   (sp)+,R
+
+%ew*,n
+       F1*
+       mov     #1(R1),R
+       I       A2,#1(R1)
+
+%eub*,n
+       F1*
+       clr     R
+       bisb    #1(R1),R
+       I'b     #1(R1)
+
+%nw*,n
+       F*
+       mov     #1(R),-(sp)
+       I       A2,#1(R)
+       mov     (sp)+,R
+
+%nub*,n
+       F*
+       movb    (R),-(sp)
+       I'b     (R)
+       clr     R
+       bisb    (sp)+,R
+
+%al,1
+%aul,1
+       F
+       I       $1,A1+
+       V       A1
+
+%el*,1
+%eul*,1
+       F1*
+       mov     #1+2(R1),R+
+       mov     #1(R1),R
+       I       $1,#1+2(R1)
+       V       #1(R1)
+
+%nl*,1
+%nul*,1
+       F*
+       mov     #1+2(R),-(sp)
+       mov     #1(R),-(sp)
+       I       $1,#1+2(R)
+       V       #1(R)
+       mov     (sp)+,R
+       mov     (sp)+,R+
+
+/* - unary, ~ */
+cr37:
+%n,n
+%nf,n
+       F
+       IBF     R
+
+%nl,n
+%nul,n
+       F
+       I       R
+       I       R+
+       V       R
+
+/* = */
+cr80:
+%a,n
+%ad,nf
+       S
+       movB1   R,A1
+
+%aub,n
+       S
+       movB1   R,A1
+       bic     $!377,R
+
+%af,nf
+       S
+       movfo   R,A1
+
+%nd*,af
+       F*
+       S
+       movf    R,#1(R)
+
+%n*,aw
+       F*
+       movB1   A2,#1(R)
+       movB1   #1(R),R
+
+%nf*,af
+       F*
+       S
+       movfo   R,#1(R)
+
+%n*,e
+       F*
+       S1
+       movB1   R1,#1(R)
+       movB1   R1,R
+
+%nub*,e
+       F*
+       S1
+       movB1   R1,#1(R)
+       clr     R
+       bisb    R1,R
+
+%ed*,nf
+       S
+       F1*
+       movf    R,#1(R1)
+
+%ef*,nf
+       S
+       F1*
+       movfo   R,#1(R1)
+
+%n*,n
+%nd*,nf
+       FS*
+       S
+       movB1   R,*(sp)+
+
+%nub*,n
+       FS*
+       S
+       movB1   R,*(sp)+
+       bic     $!377,R
+
+%nf*,nf
+       FS*
+       S
+       movfo   R,*(sp)+
+
+%al,nl
+%al,nul
+%aul,nl
+%aul,nul
+       S
+       mov     R+,A1+
+       mov     R,A1
+
+%el*,nl
+%el*,nul
+%eul*,nl
+%eul*,nul
+       S
+       F1*
+       mov     R+,2+#1(R1)
+       mov     R,#1(R1)
+
+%nl*,nl
+%nl*,nul
+%nul*,nl
+%nul*,nul
+       FS*
+       S
+       mov     R,*(sp)
+       add     $2,(sp)
+       mov     R+,*(sp)+
+
+/* field assign, value in reg. */
+cr16:
+%a,n
+       S
+       bicB1   Z,A1'
+       bisB1   R,A1''
+
+%e*,n
+%      [fas1]
+
+%n*,n
+       SS
+       F*
+       bicB1   Z,#1(R)
+       bisB1   (sp),#1(R)
+       mov     (sp)+,R
+
+/* +, -, |, &~, << */
+cr40:
+%n,z
+       F
+
+%n,1
+       F
+       I'      R
+
+%[add1:]
+%n,aw
+%nf,ad
+       F
+       IB2     A2,R
+
+%[add2:]
+%n,ew*
+%nf,ed*
+       F
+       S1*
+       IB2     #2(R1),R
+
+%[add3:]
+%n,e
+%nf,ef
+       F
+       S1
+       IBF     R1,R
+
+%[add4:]
+%n,nw*
+%nf,nd*
+       SS*
+       F
+       IB2     *(sp)+,R
+
+%[add5:]
+%n,n
+%nf,nf
+       SS
+       F
+       IBF     (sp)+,R
+
+%nl,c
+%nl,au
+%nul,c
+%nul,au
+       F
+       I       A2,R+
+       V       R
+
+%nl,eu
+%nul,eu
+       F
+       S1
+       I       R1,R+
+       V       R
+
+%nl,al
+%nl,aul
+%nul,al
+%nul,aul
+       F
+       I       A2,R
+       I       A2+,R+
+       V       R
+
+%[addl1:]
+%nl,el
+%nl,eul
+%nul,el
+%nul,eul
+       F
+       S1
+       I       R1+,R+
+       V       R
+       I       R1,R
+
+%[addl2:]
+%nl,nl
+%nl,nul
+%nul,nl
+%nul,nul
+       SS
+       F
+       I       (sp)+,R
+       I       (sp)+,R+
+       V       R
+
+/* ^ -- xor */
+cr49:
+%n,e
+%      [add3]
+
+%n,n
+       FS
+       S
+       xor     R,(sp)
+       mov     (sp)+,R
+
+%nl,el
+%nl,eul
+%nul,el
+%nul,eul
+%      [addl1]
+
+%nl,nl
+%nl,nul
+%nul,nl
+%nul,nul
+       SS
+       F
+       I       R,(sp)
+       mov     (sp)+,R
+       I       R+,(sp)
+       mov     (sp)+,R+
+
+/* >> (all complicated cases taken care of by << -) */
+cr45:
+%n,1
+       F
+       asr     R
+
+/* * -- R must be odd on integers */
+cr42:
+%n,aw
+%nf,ad
+%      [add1]
+
+%n,ew*
+%nf,ed*
+%      [add2]
+
+%n,e
+%nf,ef
+%      [add3]
+
+%n,n
+%nf,nf
+%      [add5]
+
+/* / and >> R must be odd on integers */
+cr43:
+%n,aw
+       F
+       T
+       I       A2,R-
+
+%n,ew*
+       F
+       T
+       S1*
+       I       #2(R1),R-
+
+%n,e
+       F
+       T
+       S1
+       I       R1,R-
+
+%n,n
+       SS
+       F
+       T
+       I       (sp)+,R-
+
+%nf,ad
+%      [add1]
+
+%nf,ed*
+%      [add2]
+
+%nf,ef
+%      [add3]
+
+%nf,nf
+%      [add5]
+
+/* PTOI */
+cr14:
+%nl,a
+%nul,a
+       F!
+       div     A2,R
+
+/* =+, =- */
+cr70:
+%[addq1:]
+%aw,aw
+       I       A2,A1'
+       mov     A1'',R
+
+%[addq20:]
+%aub,aw
+       clr     R
+       bisb    A1',R
+       I       A2,R
+       movb    R,A1''
+       bic     $!377,R
+
+%[addq1a:]
+%a,aw
+%ad,ad
+       movB1   A1',R
+       IBF     A2,R
+       movB1   R,A1''
+
+%[addq2:]
+%aw,nw*
+       S*
+       I       #2(R),A1'
+       mov     A1'',R
+
+%[addq3:]
+%aw,n
+       S
+       I       R,A1'
+       mov     A1'',R
+
+%[addq21:]
+%aub,n
+       SS
+       clr     R
+       bisb    A1',R
+       I       (sp)+,R
+       movb    R,A1''
+       bic     $!377,R
+
+%[addq4:]
+%ew*,nw*
+       S*
+       F1*
+       I       #2(R),#1(R1)
+       mov     #1(R1),R
+
+%[addq4a:]
+%ad,ef
+       movf    A1',R
+       S1
+       IBF     R1,R
+       movf    R,A1''
+
+%[addq5:]
+%a,n
+%ad,nf
+       SS
+       movB1   A1',R
+       IBF     (sp)+,R
+       movB1   R,A1''
+
+%[addq6:]
+%af,nf
+       SS
+       movof   A1',R
+       IBF     (sp)+,R
+       movfo   R,A1''
+
+%[addq7:]
+%ew*,n
+       S
+       F1*
+       I       R,#1(R1)
+       mov     #1(R1),R
+
+%[addq8:]
+%nw*,n
+       SS
+       F*
+       I       (sp)+,#1(R)
+       mov     #1(R),R
+
+%[addq9:]
+%n*,n
+       FS*
+       SS
+       movB1   *2(sp),R
+       IBF     (sp)+,R
+       movB1   R,*(sp)+
+
+%[addq22:]
+%nub*,n
+       FS*
+       SS
+       clr     R
+       bisb    *2(sp),R
+       I       (sp)+,R
+       movb    R,*(sp)+
+       bic     $!377,R
+
+%[addq9a:]
+%nd*,nf
+       SS
+       F*
+       movB1   #1(R),R
+       IBF     (sp)+,R
+       movB1   R,#1(R)
+
+%[addq10:]
+%nf*,nf
+       SS
+       F*
+       movof   #1(R),R1
+       IBF     (sp)+,R1
+       movfo   R1,#1(R)
+       movf    R1,R
+
+%[addq11:]
+%al,c
+%aul,c
+       I       A2,A1+
+       V       A1
+       F
+
+%[addq12:]
+%al,al
+%al,aul
+%aul,al
+%aul,aul
+       I       A2+,A1+
+       V       A1
+       I       A2,A1
+       F
+
+%[addq13:]
+%al,nl
+%al,nul
+%aul,nl
+%aul,nul
+       S
+       I       R+,A1+
+       V       A1
+       I       R,A1
+       F
+
+%[addq14:]
+%nl*,c
+%nul*,c
+       F*
+       I       A2,#1+2(R)
+       V       #1(R)
+       mov     #1+2(R),R+
+       mov     #1(R),R
+
+%[addq15:]
+%nl*,al
+%nl*,aul
+%nul*,al
+%nul*,aul
+       F*
+       I       A2+,#1+2(R)
+       V       #1(R)
+       I       A2,#1(R)
+       mov     #1+2(R),R+
+       mov     #1(R),R
+
+%[addq16:]
+%nl*,nl
+%nl*,nul
+%nul*,nl
+%nul*,nul
+       SS
+       F*
+       I       (sp)+,#1(R)
+       I       (sp)+,#1+2(R)
+       V       #1(R)
+       mov     #1+2(R),R+
+       mov     #1(R),R
+
+/* *=, <<= (for integer multiply, R must be odd) */
+cr72:
+%a,aw
+%ad,ad
+%      [addq1a]
+
+%ad,ef
+%      [addq4a]
+
+%a,n
+%ad,nf
+%      [addq5]
+
+%af,nf
+%      [addq6]
+
+%aub,aw
+%      [addq20]
+
+%aub,n
+%      [addq21]
+
+%n*,n
+%      [addq9]
+
+%nub*,n
+%      [addq22]
+
+%nd*,nf
+%      [addq9a]
+
+%nf*,nf
+%      [addq10]
+
+/* =/ ;  R must be odd on integers */
+cr73:
+%a,aw
+       movB1   A1',R
+       V       R-
+       IBF     A2,R-
+       movB1   R-,A1''
+
+%a,n
+       SS
+       movB1   A1',R
+       V       R-
+       I       (sp)+,R-
+       movB1   R-,A1''
+
+%aub,n
+       SS
+       clr     R
+       bisB1   A1',R
+       V       R-
+       I       (sp)+,R-
+       movB1   R-,A1''
+       bic     $!377,R-
+
+%e*,n
+       SS
+       F1*
+       movB1   #1(R1),R
+       V       R-
+       I       (sp)+,R-
+       movB1   R-,#1(R1)
+
+%n*,n
+       FS*
+       SS
+       movB1   *2(sp),R
+       V       R-
+       I       (sp)+,R-
+       movB1   R-,*(sp)+
+
+%nub*,n
+       FS*
+       SS
+       clr     R
+       bisB1   *2(sp),R
+       V       R-
+       I       (sp)+,R-
+       movB1   R-,*(sp)+
+       bic     $!377,R-
+
+%ad,ad
+%      [addq1a]
+
+%ad,ef
+%      [addq4a]
+
+%ad,nf
+%      [addq5]
+
+%af,nf
+%      [addq6]
+
+%nd*,nf
+%      [addq9a]
+
+%nf*,nf
+%      [addq10]
+
+/* >>= and =mod; R must be odd on integers */
+cr74:
+%a,aw
+       movB1   A1',R
+       V       R-
+       I       A2,R-
+       movB1   R,A1''
+
+%a,n
+       SS
+       movB1   A1',R
+       V       R-
+       I       (sp)+,R-
+       movB1   R,A1''
+
+%aub,n
+       SS
+       clr     R
+       bisB1   A1',R
+       V       R-
+       I       (sp)+,R-
+       movB1   R,A1''
+       bic     $!377,R
+
+%e*,n
+       SS
+       F1*
+       movB1   #1(R1),R
+       V       R-
+       I       (sp)+,R-
+       movB1   R,#1(R1)
+
+%n*,n
+       FS*
+       SS
+       movB1   *2(sp),R
+       V       R-
+       I       (sp)+,R-
+       movB1   R,*(sp)+
+
+%nub*,n
+       FS*
+       SS
+       clr     R
+       bisB1   *2(sp),R
+       V       R-
+       I       (sp)+,R-
+       movB1   R,*(sp)+
+       bic     $!377,R
+
+/* =^ -- =xor */
+cr79:
+%aw,n
+%      [addq3]
+
+%ab,n
+       SS
+       movb    A1',R
+       xor     R,(sp)
+       mov     (sp)+,R
+       movb    R,A1''
+
+%aub,n
+       SS
+       movb    A1',R
+       xor     R,(sp)
+       clr     R
+       bisb    (sp)+,R
+       movb    R,A1''
+
+%n*,n
+       FS*
+       movB1   *(sp),-(sp)
+       S
+       xor     R,(sp)
+       movB1   (sp)+,R
+       movB1   R,*(sp)+
+
+%nub*,n
+       FS*
+       clr     -(sp)
+       bisb    *2(sp),(sp)
+       S
+       xor     R,(sp)
+       mov     (sp)+,R
+       movb    R,*(sp)+
+       bic     $!377,R
+
+/* =>> (all complicated cases done by =<< -) */
+cr75:
+%a,1
+       asrB1   A1'
+       movB1   A1'',R
+
+%n*,1
+       F*
+       asrB1   #1(R)
+       movB1   #1(R),R
+
+/* =|, =&~ */
+cr78:
+%aw,aw
+%      [addq1]
+
+%aub,a
+       IBE     A2,A1'
+       clr     R
+       bisb    A1'',R
+
+%a,aw
+%ad,ad
+%      [addq1a]
+
+%aw,nw*
+%      [addq2]
+
+%aw,n
+%      [addq3]
+
+%aub,n
+       SS
+       IBE     (sp)+,A1'
+       clr     R
+       bisb    A1'',R
+
+%ew*,nw*
+%      [addq4]
+
+%ad,ef
+%      [addq4a]
+
+%a,n
+%ad,nf
+%      [addq5]
+
+%af,nf
+%      [addq6]
+
+%ew*,n
+%      [addq7]
+
+%nw*,n
+%      [addq8]
+
+%n*,n
+%      [addq9]
+
+%nub*,n
+       FS*
+       SS
+       IBE     (sp),*2(sp)
+       tst     (sp)+
+       clr     R
+       bisb    *(sp)+,R
+
+%nd*,nf
+%      [addq9a]
+
+%nf*,nf
+%      [addq10]
+
+%al,c
+%aul,c
+%      [addq11]
+
+%al,al
+%al,aul
+%aul,al
+%aul,aul
+%      [addq12]
+
+%al,nl
+%al,nul
+%aul,nl
+%aul,nul
+%      [addq13]
+
+%nl*,c
+%nul*,c
+%      [addq14]
+
+%nl*,al
+%nl*,aul
+%nul*,al
+%nul*,aul
+%      [addq15]
+
+%nl*,nl
+%nl*,nul
+%nul*,nl
+%nul*,nul
+%      [addq16]
+
+/* << for longs */
+cr91:
+%nl,aw
+%nul,aw
+%      [add1]
+
+%nl,ew*
+%nul,ew*
+%      [add2]
+
+%nl,e
+%nul,e
+%      [add3]
+
+%nl,nw*
+%nul,nw*
+%      [add4]
+
+%nl,n
+%nul,n
+%      [add5]
+
+/* >> for unsigned long */
+cr128:
+%nl,n
+%nul,n
+       SS
+       F
+       jsr     pc,I
+       tst     (sp)+
+
+/* >>= for unsigned long  */
+cr129:
+%n,n
+       SS
+       FS
+       jsr     pc,I
+       cmp     (sp)+,(sp)+
+
+/* int -> float */
+cr51:
+%aw,n
+       movif   A1,R
+
+%nw*,n
+       F*
+       movif   #1(R),R
+
+%n,n
+       F
+       movif   R,R
+
+/* float, double -> int */
+cr52:
+%nf,n
+       F
+       movfi   R,R
+
+/* double (float) to long */
+cr56:
+%nf,n
+       F
+       setl
+       movfi   R,-(sp)
+       mov     (sp)+,R
+       mov     (sp)+,R+
+       seti
+
+/* long to double */
+cr57:
+%al,n
+       setl
+       movif   A1,R
+       seti
+
+%nl*,n
+       F*
+       setl
+       movif   #1(R),R
+       seti
+
+%nl,n
+       FS
+       setl
+       movif   (sp)+,R
+       seti
+
+/* unsigned long to float(double) */
+cr127:
+%aul,n
+       mov     A1+,-(sp)
+       mov     A1,-(sp)
+       jsr     pc,I
+       cmp     (sp)+,(sp)+
+
+%nul*,n
+       F*
+       mov     #1+2(R),-(sp)
+       mov     #1(R),-(sp)
+       jsr     pc,I
+       cmp     (sp)+,(sp)+
+
+%nul,n
+       FS
+       jsr     pc,I
+       cmp     (sp)+,(sp)+
+
+/* integer to long */
+cr58:
+%eu,n
+       F1!
+       clr     R
+
+%nu,n
+       F
+       mov     R,R1
+       clr     R
+
+%e,n
+       F1!
+       sxt     R
+
+%n,n
+       F
+       mov     R,R1
+       sxt     R
+
+/* long to integer */
+cr59:
+%al,n
+%aul,n
+       mov     A1+,R
+
+%nl*,n
+%nul*,n
+       F*
+       mov     #1+2(R),R
+
+/* *, /, remainder for longs. */
+cr82:
+%[l82:]
+%nl,nl
+%nl,nul
+%nul,nl
+%nul,nul
+       SS
+       FS
+       jsr     pc,I
+       add     $10,sp
+
+/* *, /, rem for unsigned long */
+cr121:
+%nul,nl
+%nl,nul
+%nul,nul
+%      [l82]
+
+/* *=, /=, %= for unsigned long */
+cr124:
+%n,nl
+%n,nul
+%nl,n
+%nul,n
+%      [l86]
+
+/* *=, /=, %= for longs */
+/* Operands of the form &x op y, so stack space is known. */
+cr86:
+%[l86:]
+%n,nl
+%n,nul
+       SS
+       FS
+       jsr     pc,I
+       add     $6,sp
+
+/* convert integer to character (sign extend) */
+cr109:
+%n,n
+       F
+       movb    R,R
+
+/* divide, remainder for unsigned */
+cr117:
+%n,e
+       F!
+       S1!
+       jsr     pc,I
+
+%n,n
+       SS
+       F!
+       mov     (sp)+,R1
+       jsr     pc,I
+
+/* /= mod for unsigned */
+cr119:
+%aw,e
+%ab,e
+       movB1   A1',R
+       S1!
+       jsr     pc,I
+       movB1   R,A1''
+
+%aub,e
+       clr     R
+       bisB1   A1',R
+       S1!
+       jsr     pc,I
+       movb    R,A1''
+
+%aw,n
+%ab,n
+       SS
+       movB1   A1',R
+       mov     (sp)+,R1
+       jsr     pc,I
+       movB1   R,A1''
+
+%nw*,n
+%nb*,n
+       FS*
+       S!
+       mov     R,R1
+       movB1   *(sp),R
+       jsr     pc,I
+       movB1   R,*(sp)+
+
+%aub,n
+       SS
+       clr     R
+       bisB1   A1',R
+       mov     (sp)+,R1
+       jsr     pc,I
+       movB1   R,A1''
+
+%nub*,n
+       FS*
+       S!
+       mov     R,R1
+       clr     R
+       bisb    *(sp),R
+       jsr     pc,I
+       movB1   R,*(sp)+
+
+/* (int *) - (int *) */
+cr107:
+%n,n
+       F?
+       ror     R
+
+%{
+/*
+ * c code tables -- compile for side effects.
+ * Also set condition codes properly (except for ++, --)
+ */
+
+struct table efftab[] = {
+       {30,ci70},
+       {31,ci70},
+       {32,ci70},
+       {33,ci70},
+       {80,ci80},
+       {70,ci70},
+       {71,ci70        /* - like + */},
+       {78,ci78},
+       {79,ci79},
+       {85,ci78},
+       {75,ci75},
+       {76,ci76},
+       {16,ci16},
+       {116,ci116},
+       {0}
+};
+%}
+
+/* = */
+ci80:
+%[move1:]
+%a,z
+%ad,zf
+%aub,z
+       I'B1    A1
+
+%[move2:]
+%n*,z
+%nd*,zf
+%nub*,z
+       F*
+       I'B1    #1(R)
+
+%[move3:]
+%a,aw
+%ab,a
+%ab,aub
+%aub,a
+%aub,ab
+       IBE     A2,A1
+
+%[move4:]
+%ab,n*
+%a,nw*
+%aub,n*
+       S*
+       IBE     #2(R),A1
+
+%[move5:]
+%a,n
+%aub,n
+       S
+       IB1     R,A1
+
+%[move6:]
+%n*,aw
+%nb*,a
+%nub*,a
+       F*
+       IBE     A2,#1(R)
+
+%[move7:]
+%n*,ew*
+%nb*,e*
+%nub*,e*
+       F*
+       S1*
+       IBE     #2(R1),#1(R)
+
+%[move8:]
+%n*,e
+%nub*,e
+       F*
+       S1
+       IB1     R1,#1(R)
+
+%[move9:]
+%e*,nw*
+%eb*,n*
+%eub*,n*
+       S*
+       F1*
+       IBE     #2(R),#1(R1)
+
+%[move10:]
+%e*,n
+%eub*,n
+       S
+       F1*
+       IB1     R,#1(R1)
+
+%[move11:]
+%n*,nw*
+%nb*,n*
+%nub*,n*
+       FS*
+       S*
+       IBE     #2(R),*(sp)+
+
+%[move12:]
+%n*,n
+%nub*,n
+       FS*
+       S
+       IB1     R,*(sp)+
+
+%aw,nf
+       S
+       movfi   R,A1
+
+%ew*,nf
+       S
+       F1*
+       movfi   R,#1(R1)
+
+%al,z
+%aul,z
+       clr     A1
+       clr     A1+
+
+%nl*,z
+%nul*,z
+       F*
+       clr     #1(R)
+       clr     2+#1(R)
+
+%[move13a:]
+%al,aw
+%aul,aw
+       I       A2,A1+
+       V       A1
+
+%al,nw*
+%aul,nw*
+       S*
+       mov     #2(R),A1+
+       V       A1
+
+%al,n
+%aul,n
+       S
+       mov     R,A1+
+       V       A1
+
+%al,nf
+%aul,nf
+       S
+       setl
+       movfi   R,A1
+       seti
+
+%el*,nf
+%eul*,nf
+       S
+       F1*
+       setl
+       movfi   R,#1(R1)
+       seti
+
+%[move13:]
+%al,al
+%al,aul
+%aul,al
+%aul,aul
+       I       A2,A1
+       I       A2+,A1+
+       V       A1
+
+%[move14:]
+%al,nl*
+%al,nul*
+%aul,nl*
+%aul,nul*
+       S*
+       I       #2(R),A1
+       I       #2+2(R),A1+
+       V       A1
+
+%[move15:]
+%al,nl
+%al,nul
+%aul,nl
+%aul,nul
+       S
+       I       R,A1
+       I       R+,A1+
+       V       A1
+
+%[move14a:]
+%nl*,aw
+%nul*,aw
+       F*
+       I       A2,#1+2(R)
+       V       #1(R)
+
+%[move16a:]
+%nl*,al
+%nl*,aul
+%nul*,al
+%nul*,aul
+       F*
+       I       A2+,#1+2(R)
+       V       #1(R)
+       I       A2,#1(R)
+
+%[move16:]
+%el*,nl
+%el*,nul
+%eul*,nl
+%eul*,nul
+       S
+       F1*
+       I       R+,#1+2(R1)
+       V       #1(R1)
+       I       R,#1(R1)
+
+%nl*,n
+%nul*,n
+       SS
+       F*
+       mov     (sp)+,#1+2(R)
+       V       #1(R)
+
+%[move17:]
+%nl*,nl
+%nl*,nul
+%nul*,nl
+%nul*,nul
+       SS
+       F*
+       I       (sp)+,#1(R)
+       I       (sp)+,#1+2(R)
+       V       #1(R)
+
+/* =| and =& ~ */
+ci78:
+%a,a
+%a,ab
+%a,aub
+%ab,a
+%ab,ab
+%ab,aub
+%aub,a
+%aub,ab
+%aub,aub
+%      [move3]
+
+%aub,n
+       S
+       IBE     R,A1
+
+%a,n
+%      [move5]
+
+%n*,aw
+%nb*,a
+%nub*,a
+%      [move6]
+
+%n*,ew*
+%nb*,e*
+%nub*,e*
+%      [move7]
+
+%n*,e
+%      [move8]
+
+%e*,nw*
+%eb*,n*
+%eub*,n*
+%      [move9]
+
+%e*,n
+%      [move10]
+
+%n*,nw*
+%nb*,n*
+%nub*,n*
+%      [move11]
+
+%n*,n
+%      [move12]
+
+%al,c
+%al,au
+%aul,c
+%aul,au
+%      [move13a]
+
+%al,al
+%al,aul
+%aul,al
+%aul,aul
+%      [move13]
+
+%al,nl*
+%al,nul*
+%aul,nl*
+%aul,nul*
+%      [move14]
+
+%al,nl
+%al,nul
+%aul,nl
+%aul,nul
+%      [move15]
+
+%nl*,c
+%nul*,c
+%      [move14a]
+
+%nl*,al
+%nl*,aul
+%nul*,al
+%nul*,aul
+%      [move16a]
+
+%el*,nl
+%el*,nul
+%eul*,nl
+%eul*,nul
+%      [move16]
+
+%nl*,nl
+%nl*,nul
+%nul*,nl
+%nul*,nul
+%      [move17]
+
+/* =^ */
+ci79:
+%al,nl
+%al,nul
+%aul,nl
+%aul,nul
+%      [move15]
+
+%el*,nl
+%el*,nul
+%eul*,nl
+%eul*,nul
+%      [move16]
+
+%nl*,nl
+%nl*,nul
+%nul*,nl
+%nul*,nul
+       FS*
+       S
+       I       R,*(sp)
+       mov     (sp)+,R
+       I       R+,2(R)
+
+/* =+ */
+ci70:
+%n*,z
+%a,z
+%ab,1
+%aub,1
+%a,1
+       I'B1    A1
+
+%aw,aw
+%      [move3]
+
+%aw,nw*
+%      [move4]
+
+%aw,n
+%      [move5]
+
+%n*,1
+%nub*,1
+%      [move2]
+
+%ew*,nw*
+%      [move9]
+
+%a,ew*
+       S*
+       movB1   A1',R1
+       I       #2(R),R1
+       movB1   R1,A1''
+
+%a,n
+       S
+       movB1   A1',R1
+       I       R,R1
+       movB1   R1,A1''
+
+%aub,n
+       S
+       clr     R1
+       bisB1   A1',R1
+       I       R,R1
+       movB1   R1,A1''
+
+%ew*,n
+%      [move10]
+
+%nw*,n
+%      [move12]
+
+%n*,n
+       SS
+       F*
+       movB1   #1(R),R1
+       I       (sp)+,R1
+       movB1   R1,#1(R)
+
+%nub*,n
+       SS
+       F*
+       clr     R1
+       bisB1   #1(R),R1
+       I       (sp)+,R1
+       movB1   R1,#1(R)
+
+%al,c
+%al,au
+%aul,au
+%aul,c
+%      [move13a]
+
+%al,al
+%al,aul
+%aul,al
+%aul,aul
+%      [move13]
+
+%al,nl*
+%al,nul*
+%aul,nl*
+%aul,nul*
+%      [move14]
+
+%al,nl
+%al,nul
+%aul,nl
+%aul,nul
+%      [move15]
+
+%nl*,c
+%nl*,au
+%nul*,c
+%nul*,au
+%      [move14a]
+
+%nl*,al
+%nl*,aul
+%nul*,al
+%nul*,aul
+%      [move16a]
+
+%el*,nl
+%el*,nul
+%eul*,nl
+%eul*,nul
+%      [move16]
+
+%nl*,nl
+%nl*,nul
+%nul*,nl
+%nul*,nul
+%      [move17]
+
+/* =>> (all harder cases handled by =<< -) */
+ci75:
+%a,1
+       asrB1   A1
+
+%aub,1
+       clc
+       rorB1   A1
+
+%n*,1
+       F*
+       asrB1   #1(R)
+
+%nub*,1
+       F*
+       clc
+       rorB1   #1(R)
+
+/* =<< */
+ci76:
+%a,1
+%aub,1
+       aslB1   A1
+
+%n*,1
+%nub*,1
+       F*
+       aslB1   #1(R)
+
+%r,aw
+       ash     A2,A1
+
+%r,nw*
+       S*
+       ash     #2(R),A1
+
+%r,n
+       S
+       ash     R,A1
+
+/* =<< for longs */
+cr92:
+%al,aw
+%aul,aw
+       F
+       ashc    A2,R
+       mov     R,A1
+       mov     R+,A1+
+
+%al,n
+%aul,n
+       SS
+       F
+       ashc    (sp)+,R
+       mov     R,A1
+       mov     R+,A1+
+
+%nl*,n
+%nul*,n
+       FS*
+       SS
+       mov     2(sp),R
+       mov     2(R),R+
+       mov     (R),R
+       ashc    (sp)+,R
+       mov     R,*(sp)
+       add     $2,(sp)
+       mov     R+,*(sp)+
+
+/* field = ... */
+ci16:
+%a,a
+       bicB1   Z,A1'
+       bisB1   A2,A1''
+
+%a,n
+       S
+       bicB1   Z,A1'
+       bisB1   R,A1''
+
+%n*,a
+       F*
+       bicB1   Z,#1(R)
+       bisB1   A2,#1(R)
+
+%[fas1:]
+%e*,n
+       S
+       F1*
+       bicB1   Z,#1(R1)
+       bisB1   R,#1(R1)
+
+%n*,e
+       F*
+       S1
+       bicB1   Z,#1(R)
+       bisB1   R1,#1(R)
+
+%n*,n
+       SS
+       F*
+       bicB1   Z,#1(R)
+       bisB1   (sp)+,#1(R)
+
+%{
+/*
+ * c code tables-- set condition codes
+ */
+
+struct table cctab[] = {
+       {106,cc60},
+       {28,rest},
+       {55,rest},
+       {34,rest},
+       {35,rest},
+       {36,rest},
+       {37,rest},
+       {40,rest},
+       {41,rest},
+       {43,rest},
+       {81,cc81        /* & as in "if ((a&b)==0)" */},
+       {48,rest},
+       {60,cc60},
+       {61,cc60},
+       {62,cc60},
+       {63,cc60},
+       {64,cc60},
+       {65,cc60},
+       {66,cc60},
+       {67,cc60},
+       {68,cc60},
+       {69,cc60},
+       {72,rest},
+       {73,rest},
+       {79,rest},
+       {0}
+};
+%}
+
+/* relationals */
+cc60:
+%a,z
+%ad,zf
+%aub,z
+%      [move1]
+
+%af,z
+       movof   A1,R
+
+%n*,z
+%nd*,zf
+%nub*,z
+%      [move2]
+
+%nf*,z
+       F*
+       movof   #1(R),R
+
+%n,z
+%nf,zf
+       FC
+
+%aw,aw
+%ab,ab
+%aub,a
+%aub,aub
+%      [move3]
+
+%nw*,aw
+%nb*,ab
+%nub*,aub
+%      [move6]
+
+%n,aw
+%nf,ad
+%      [add1]
+
+%nw*,ew*
+%nb*,eb*
+%nub*,eub*
+%      [move7]
+
+%nw*,e
+%      [move8]
+
+%n,ew*
+%nf,ed*
+%      [add2]
+
+%n,e
+%nf,ef
+%      [add3]
+
+%nw*,nw*
+%nb*,nb*
+%nub*,nub*
+%      [move11]
+
+%nw*,n
+%      [move12]
+
+%n,n
+%nf,nf
+%      [add5]
+
+%al,z
+%aul,z
+       tst     A1
+       X0
+       tst     A1+
+       X1
+
+%al,c
+%al,au
+%aul,c
+%aul,au
+       tst     A1
+       X0
+       cmp     A1+,A2
+       X1
+
+%[lcmp1:]
+%al,al
+%al,aul
+%aul,al
+%aul,aul
+       I       A1,A2
+       X0
+       I       A1+,A2+
+       X1
+
+%nl*,z
+%nul*,z
+       F*
+       tst     #1(R)
+       X0
+       tst     #1+2(R)
+       X1
+
+%nl*,c
+%nul*,c
+%nl*,au
+%nul*,au
+       F*
+       tst     #1(R)
+       X0
+       cmp     #1+2(R),A2
+       X1
+
+%[lcmp2:]
+%nl*,al
+%nl*,aul
+%nul*,al
+%nl*,aul
+       F*
+       I       #1(R),A2
+       X0
+       I       #1+2(R),A2+
+       X1
+
+%nl,z
+%nul,z
+       F
+       tst     R
+       X0
+       tst     R+
+       X1
+
+%nl,c
+%nul,c
+%nl,au
+%nul,au
+       F
+       tst     R
+       X0
+       cmp     R+,A2
+       X1
+
+%[lcmp3:]
+%nl,al
+%nl,aul
+%nul,al
+%nul,aul
+       F
+       I       R,A2
+       X0
+       I       R+,A2+
+       X1
+
+%[lcmp4:]
+%nl*,el*
+%nl*,eul*
+%nul*,el*
+%nul*,eul*
+       F*
+       S1*
+       I       #1(R),#2(R1)
+       X0
+       I       #1+2(R),#2+2(R1)
+       X1
+
+%[lcmp5:]
+%nl,el*
+%nl,eul*
+%nul,el*
+%nul,eul*
+       F
+       S1*
+       I       R,#2(R1)
+       X0
+       I       R+,#2+2(R1)
+       X1
+
+%[lcmp6:]
+%nl,nl
+%nl,nul
+%nul,nl
+%nul,nul
+       FS
+       S
+       mov     R,-(sp)
+       mov     4(sp),R
+       mov     (sp)+,2(sp)
+       I       (sp)+,(sp)+
+       X0
+       I       R,R+
+       X1
+
+/* & as in "if ((a&b) ==0)" */
+cc81:
+%a,a
+%a,ab
+%a,aub
+%ab,a
+%ab,ab
+%ab,aub
+%aub,a
+%aub,ab
+%aub,aub
+%      [move3]
+
+/*
+   special case. apparently "u_char b; [u_]char a; if (b & a)..." was
+   too complicated.  the resulting code was horrid.  this cuts the
+   waste by 33%
+*/
+   
+%a,e
+%aub,e
+       S
+       IBE     R,A1
+
+%n*,a
+%nu*,a
+%nub*,a
+%      [move6]
+
+%n,a
+%      [add1]
+
+%n,e
+%      [add3]
+
+%n,n
+%      [add5]
+
+%al,c
+%aul,c
+%al,au
+%aul,au
+       bit     A2,A1+
+       X1
+
+%nl*,c
+%nul*,c
+%nl*,au
+%nul*,au
+       F*
+       bit     A2,#2+2(R)
+       X1
+
+%al,al
+%al,aul
+%aul,al
+%aul,aul
+%      [lcmp1]
+
+%nl*,al
+%nl*,aul
+%nul*,al
+%nul*,aul
+%      [lcmp2]
+
+%nl,al
+%nl,aul
+%nul,al
+%nul,aul
+%      [lcmp3]
+
+%nl*,el*
+%nl*,eul*
+%nul*,el*
+%nul*,eul*
+%      [lcmp4]
+
+%nl,el*
+%nl,eul*
+%nul,el*
+%nul,eul*
+%      [lcmp5]
+
+%nl,nl
+%nl,nul
+%nul,nl
+%nul,nul
+%      [lcmp6]
+
+%nl,c
+%nul,c
+%nl,au
+%nul,au
+       F
+       bit     A2,R+
+       X1
+
+/* set codes right */
+rest:
+%n,n
+%nf,nf
+       H
+
+%{
+/*
+ * c code tables-- expression to -(sp)
+ */
+
+struct table sptab[] = {
+       {106,cs106},
+       {40,cs40},
+       {41,cs40},
+       {55,cs40},
+       {48,cs40},
+       {58,cs58},
+       {56,cs56},
+       {0}
+};
+%}
+
+/* name */
+cs106:
+%z,n
+%zf,n
+       clrB1   -(sp)
+
+%aw,n
+       mov     A1,-(sp)
+
+%aub,n
+       clr     -(sp)
+       bisb    A1,(sp)
+
+%nw*,n
+       F*
+       mov     #1(R),-(sp)
+
+%al,n
+%aul,n
+       mov     A1+,-(sp)
+       mov     A1,-(sp)
+
+/* +, -, |, &~ */
+cs40:
+%a,1
+       FS
+       I'      (sp)
+
+%a,aw
+       FS
+       I       A2,(sp)
+
+%a,nw*
+       FS
+       S*
+       I       #2(R),(sp)
+
+%a,n
+       FS
+       S
+       I       R,(sp)
+
+/* integer to long */
+cs58:
+%nu,n
+       FS
+       clr     -(sp)
+
+%aw,n
+       mov     A1,-(sp)
+       sxt     -(sp)
+
+/* float to long */
+cs56:
+%nf,n
+       F
+       setl
+       movfi   R,-(sp)
+       seti
+
+/* setup for structure assign */
+ci116:
+%n,e
+       F!
+       S1!
+
+%n,n
+       SS
+       F!
+       mov     (sp)+,r1
+