--- /dev/null
+*.bak
+*.o
+c0
+c1
+cvopt
--- /dev/null
+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?
--- /dev/null
+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:
--- /dev/null
+ 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)))
--- /dev/null
+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
--- /dev/null
+%{
+/*
+ * 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);
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+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);
+}
--- /dev/null
+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);
+}
--- /dev/null
+main()
+{
+ int a = 15,
+ b = 20;
+
+ b =& a;
+ printf("20 & 15 = %d\n",b);
+ a =- 8;
+ printf("15 - 8 = %d\n",a);
+}
--- /dev/null
+#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);
+ }
+}
--- /dev/null
+#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);
+ }
+}
--- /dev/null
+main()
+{
+ int foobarbyfar, foobarbyfar2;
+
+ foobarbyfar = 6;
+ foobarbyfar2 = 12;
+ printf("foobarbyfar=%d, foobarbyfar=%d, should be 6, 12\n",
+ foobarbyfar, foobarbyfar2);
+}
--- /dev/null
+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
+ */
+}
--- /dev/null
+long *pl;
+main()
+{
+ register i;
+
+ (pl-pl)+(long)i;
+}
--- /dev/null
+long *pl;
+main()
+{
+ register i, j;
+
+ (pl-pl)+(long)i;
+}
--- /dev/null
+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");
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/* 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 = ¶ml->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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#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;
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
--- /dev/null
+#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);
+}
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#!/bin/sh
+make CFLAGS=-g LDC0FLAGS= LDC1FLAGS= "$@"
--- /dev/null
+%{
+/*
+ * 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
+