From 3f8b1d2978562e7a1aa6693029d037ace7508768 Mon Sep 17 00:00:00 2001 From: Nick Downing Date: Tue, 7 Feb 2017 22:41:49 +1100 Subject: [PATCH] C compiler from 211bsd.git commit 98921db --- .gitignore | 5 + Makefile | 45 + TEST/Makefile | 54 ++ TEST/README | 197 ++++ TEST/ctest | 21 + TEST/old-assn.l | 172 ++++ TEST/tpr.c | 265 ++++++ TEST/tprint.c | 296 ++++++ TEST/tst_adec.c | 10 + TEST/tst_asm.c | 10 + TEST/tst_assign.c | 10 + TEST/tst_lgm-g.c | 48 + TEST/tst_lgm.c | 47 + TEST/tst_longsym.c | 9 + TEST/tst_pntint.c | 46 + TEST/tst_rhh-g.c | 7 + TEST/tst_rhh.c | 7 + TEST/tst_sgncmp.c | 39 + c0.h | 592 ++++++++++++ c00.c | 903 ++++++++++++++++++ c01.c | 954 +++++++++++++++++++ c02.c | 803 ++++++++++++++++ c03.c | 727 ++++++++++++++ c04.c | 422 +++++++++ c05.c | 250 +++++ c1.h | 576 +++++++++++ c10.c | 1382 +++++++++++++++++++++++++++ c11.c | 1190 +++++++++++++++++++++++ c12.c | 1221 ++++++++++++++++++++++++ c13.c | 459 +++++++++ cvopt.c | 461 +++++++++ fp.c | 681 +++++++++++++ fp_atof.c | 111 +++ n.sh | 2 + optable | 2255 ++++++++++++++++++++++++++++++++++++++++++++ 35 files changed, 14277 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 TEST/Makefile create mode 100644 TEST/README create mode 100644 TEST/ctest create mode 100644 TEST/old-assn.l create mode 100644 TEST/tpr.c create mode 100644 TEST/tprint.c create mode 100644 TEST/tst_adec.c create mode 100644 TEST/tst_asm.c create mode 100644 TEST/tst_assign.c create mode 100644 TEST/tst_lgm-g.c create mode 100644 TEST/tst_lgm.c create mode 100644 TEST/tst_longsym.c create mode 100644 TEST/tst_pntint.c create mode 100644 TEST/tst_rhh-g.c create mode 100644 TEST/tst_rhh.c create mode 100644 TEST/tst_sgncmp.c create mode 100644 c0.h create mode 100644 c00.c create mode 100644 c01.c create mode 100644 c02.c create mode 100644 c03.c create mode 100644 c04.c create mode 100644 c05.c create mode 100644 c1.h create mode 100644 c10.c create mode 100644 c11.c create mode 100644 c12.c create mode 100644 c13.c create mode 100644 cvopt.c create mode 100644 fp.c create mode 100644 fp_atof.c create mode 100755 n.sh create mode 100644 optable diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fc5c53 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.bak +*.o +c0 +c1 +cvopt diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a96c743 --- /dev/null +++ b/Makefile @@ -0,0 +1,45 @@ +HOSTCC=cc +INSTALL=install +CFLAGS = -O +LDC0FLAGS= -i +LDC1FLAGS= -n +DESTDIR = +LIB=/lib + +all: c0 c1 cvopt +c0: c00.o c01.o c02.o c03.o c04.o c05.o + ${CC} ${LDC0FLAGS} ${CFLAGS} -o c0 c00.o c01.o c02.o c03.o c04.o c05.o + +c00.o c01.o c02.o c03.o c04.o c05.o: c0.h + +c1: c10.o c11.o c12.o c13.o fp.o fp_atof.o table.o + ${CC} ${LDC1FLAGS} ${CFLAGS} -o c1 c10.o c11.o c12.o c13.o fp.o fp_atof.o table.o + +c10.o c11.o c12.o c13.o: c1.h + +table.o: optable cvopt + ./cvopt < optable > junk.c + ${CC} -S junk.c + sed 's/\.data/\.text/' < junk.s > junk.i + ${AS} -o table.o junk.i + rm -f junk.i junk.c junk.s + +cvopt: cvopt.c + ${HOSTCC} -o cvopt cvopt.c + +install: c0 c1 + -mv ${DESTDIR}${LIB}/c0 ${DESTDIR}${LIB}/oc0 + -mv ${DESTDIR}${LIB}/c1 ${DESTDIR}${LIB}/oc1 + ${INSTALL} -s c0 ${DESTDIR}${LIB}/c0 + ${INSTALL} -s c1 ${DESTDIR}${LIB}/c1 + +restore: + mv ${DESTDIR}${LIB}/oc0 ${DESTDIR}${LIB}/c0 + mv ${DESTDIR}${LIB}/oc1 ${DESTDIR}${LIB}/c1 + +lint: + lint -haxc -I. c0?.c > lint.c0 + lint -haxc -I. c1?.c > lint.c1 + +clean: + rm -f *.o c0 c1 cvopt lint.c? diff --git a/TEST/Makefile b/TEST/Makefile new file mode 100644 index 0000000..97bbc97 --- /dev/null +++ b/TEST/Makefile @@ -0,0 +1,54 @@ +LEX=lex +CFLAGS= -O +SEPFLAG= -i +LIB= /lib +ALL= tst_adec tst_rhh-g tst_pntint tst_asm tst_lgm-g \ + tst_sgncmp tst_assign old-assn + +all: ${ALL} + +tst_adec: tst_adec.o + ${CC} -o $@ tst_adec.o + +# This will fail... see README +#tst_rhh: tst_rhh.o +# ${CC} -o $@ tst_rhh.o + +tst_rhh-g: tst_rhh-g.o + ${CC} -o $@ tst_rhh-g.o + +tst_pntint: tst_pntint.o + ${CC} -o $@ tst_pntint.o + +tst_asm: tst_asm.o + ${CC} -o $@ tst_asm.o + +# This requires changes to the compiler to run, see README +#tst_longsym: tst_longsym.o +# ${CC} -o $@ tst_longsym.o + +tst_longsym: tst_longsym.o + ${CC} -o $@ tst_longsym.o + +tst_lgm: tst_lgm.o + ${CC} -o $@ tst_lgm.o + +# This will fail... see README +#tst_lgmgood: tst_lgmgood.o +# ${CC} -o $@ tst_lgmgood.o + +tst_assign: tst_assign.o + ${CC} -o $@ tst_assign.o + +tst_sgncmp: tst_sgncmp.o + ${CC} -o $@ tst_sgncmp.o + +old-assn: old-assn.l + ${LEX} old-assn.l + ${CC} ${SEPFLAG} ${CFLAGS} -o old-assn lex.yy.c -lln + rm lex.yy.c + +clean: + rm -f lex.yy.c *.o core ${ALL} + +install: diff --git a/TEST/README b/TEST/README new file mode 100644 index 0000000..5113854 --- /dev/null +++ b/TEST/README @@ -0,0 +1,197 @@ + This compiler is obviously based on a Ritchie compiler, roughly dated +1982, that was slipped under the door by an unnamed benefactor. It came here +with void, u_char, many cosmetic changes (use of += vs =+), table.s replaced +by "optable", and cvopt.c writing a ".c" file, rather than an ".s" file. +There are also many changes to the way code is generated. + Various files begining with "tst" test various bugs/enhancements that +have been seen in some versions of the Ritchie compiler. You can see some +of the bugs that have been fixed by running these test programs. These test +programs are far from being complete test suites. Just because you can get +one in particular to run doesn't necessarily mean that every case of that +feature will work. Other shakedown measures should be taken, for example, +recompiling & testing every program you can get your hands on. + + Stephen Uitti, Casey Leedom & Keith Bostic + +tst_adec.c + This bug is where a long is used as an index for an array, that gets + decremented. The bug is that only half of the long gets decremented, + corrupting its value. 0 goes to 65535 rather than -1. The stock + 2.9 BSD compiler had this bug. The bug was reported on USENET, with + no fix. This compiler fixes this bug, but 'causes' another - see + tstlgm.c, tstlgmgood.c. + +tst_pntint.c + The new compiler didn't allow assignment of pointers to integers + and vice-versa under any circumstances. This was changed to allow + the assignment, but warn the user, a la 4.3. + +tst_assign.c + The new compiler doesn't handle the old assignment operators at all. + It will object to *some* of the old operators, but since "foo =- 8" + can be translated "foo = (-8)", a lot of them slip by. Use the + program old-assn and a find to remove all instances of the old + operators from your source code. For example... + + find /usr/src -type f -name '*.[cl]' \ + -exec /usr/src/lib/ccom/TEST/old-assn {} \; >& old_list& + +tst_rhh.c and tst_rhh-g.c + This compiler fixes the "tstadec.c" bug, but in doing so creates this + other bug. The symptom is that the compiler runs out of registers + while trying to compile this code. The stock 2.9 BSD compiler + compiles this code correctly, but uses a "div" rather than an "ashc" + instruction at one point. "movreg" in c10.c gets called to move + values to an appropriate even/odd place, but there aren't enough + registers left to do this. It's unclear why r0 isn't used early on in + the developed code, since the stock 2.9 BSD compiler does, and thus + doesn't get into trouble. "tst_rhh-g.c" declares one less register, + and thus allows a compiler with the bug to compile the code. + +tst_asm.c + This tests (and shows how to use) the "asm" feature. These mods + were taken from in a version of the Ritchie compiler found on a + VAX at Purdue CS that had been converted into a cross C compiler. + These mods were done in c0.h, c1.h, c00.c, c02.c, c11.c, c0.h and + c1.h. + +tst_longsym.c + Mods (mostly to error messages) to allow the parameter NCPS (in both + c0.h and c1.h) to be changed to (for example) larger values. Normally, + a standard compiler will give you a message something like: + + tstlongsym.c:3: foobarby redeclared + + So, change NCPS to 16, try again, and it should actually run. It turns + out that "auto" symbol names never get used by the assembler, so it's + still happy. For globals, though, you need an assembler, linker, new + a.out format (for the symbol table), ar etc. that can deal with longer + names. These changes took place in c00.c, c01.c c02.c, c03.c, and + c11.c. + +tst_lgm.c and tst_lgm-g.c + These show a bug in union initialization. Both the stock 2.9 compiler + and this compiler allowed the initializations, but compiled incorrect + code. The bugfix allows them and does them correctly but warns that + they are non-portable. This bugfix still won't compile tstlgm.c, + since it is not syntactically correct. tstlgmgood.c is, and this fix + allows this code to be compiled. Note, this compiler will not allow + initialization of a union unless the type of the value is the type + of the first entry in the union; the stock 2.9 compiler didn't have + that limitation. This fix was applied to c02.c, and is attributed + to Doug Gwyn. + +tst_sgncmp.c + Both the stock 2.9 compiler & this compiler compare large (almost + negative) signed int's incorrectly. The bugfix allows this program + to say "true" always. These changes were made in c10.c, c11.c, c13.c, + c2.h, and c20.c. The bugfix is attributed to George Rosenberg, + whose "README" was as follows: + + There seems to be an anomaly in the code generation of + some pdp-11 C compilers. In certain contexts the wrong type of + conditional branch instruction is generated. Instructions such + as "jge" may occur rather than instructions such as "jpl". I + have observed the problem with a Whitesmith compiler and both + of the compilers distributed with UNIX version 7, Dennis M. + Ritchie's compiler and Stephen C. Johnson's compiler. The + expression, + "(j-i < 0) == (j-i < zero)", + + evaluates to zero (i.e. false) in the accompanying program, + "bug.c", as compiled with the UNIX compilers. The expression + evaluates as one (i.e. true), in the Whitesmith compiler, only + because it also incorrectly evaluates a previous expression in + the program. I suggest trying this program with your compiler + even if it isn't one of the above. + + In making the changes, the original sources were examined only + superficially (e.g. grep jlt), to find the offending code. + This code was then patched up. Programs compiled with the + modified compiler seem to work. By "seem to work", I mean that + as far as I know the coding anomalies described here are fixed + and no new bugs are introduced. Due to my ignorance of the + global workings of the compiler, there may be a possibility of + some unknown global effect coming back to haunt you. Here is a + summary of coding changes applicable in certain contexts. + + Old Coding New Coding + 1. jlt L001 jmi L001 + 2. jge L002 jpl L002 + 3. jle L003 jmi L003 + jeq L003 + 4. jgt L004 jmi L005 + jne L004 + L005: + +c11.c (stock 2.9 BSD compiler only) + An improvement to the optimizer, c21.c, does a little better at using + values which have been put into registers. To test the diff the + assembly output "cc -O -S c11.c". Of course c11.c is also useful as + part of the compiler. + +Other bugs (but no test files): + +==== An assignment bug fix - the code is in c01.c. The bugfix code claims + that t = (t, t) + 1; code was broken, now fixed. It didn't seem + broken to me, but I installed the fix anyway. + +==== A new type clash error is trapped for in c03.c. This fix attributed + to "IIASA (from MIT)" (whoever/whatever that is). + +==== A bug fix for "when there are unitialized static variables in the + middle of a routine". This fix is also attributed to "IIASA (from + MIT)", and is applied to c20.c. + +==== A bug fix for a typo in c10.c, attributed to ken@ukma. Search + for "typo". + +==== The pdp-11 compiler clears a little too much information when + it leaves certain scopes. The place you find this is in the + code: + f1() { extern int foo; } + + f2() { foo = 1; } + + According to sections 10 & 11.1 of K&R, this is legal, and, in fact, + the 4.3 compiler allows this. 2.10's doesn't. Because of the way + that 2.10's compiler handles its stack, this one will be *very* tough. + +==== Forward references are a bit paranoid in the 2.10 compiler, for + instance, the following code produces an error message that + + struct A { + struct B *bp; + } a = 0; + + struct B { + struct A *ap; + }; + + the line "a = 0" causes a reference to an "Undefined structure." + This isn't really a bug, and it can be easily worked around, but + it's certainly unreasonable. + +==== Also, something which isn't a bug in our compiler, but is in the + 4.3BSD compiler may cause you some problems when porting programs + from 4.3. The 4.3 compiler compares unsigned and signed ints + incorrectly (K&R, p. 184, 6.5 and p. 189, 7.6). Instead of + performing an unsigned comparison, it performs a signed comparison. + To get a feel for the degree of subtlety that this can lead to in + the way of bugs consider the following line from the original source + to the 4.3 ndbm standard library source: + + if (i1 <= (i2+3) * sizeof(short)) + + I1 and i2 are integers, but because sizeof has type unsigned the + entire right hand side of the comparison is converted to unsigned. + At this point our compiler and the 4.3 compiler diverge in their + treatment of the comparison: ours converts the left hand side of the + comparison to unsigned and performs an unsigned comparison. The + 4.3 compiler converts the right hand side to signed and performs a + signed comparison. In the particular case above, since i1 had been + (essentially) computed as i2 - with the possibility of a + negative result, this caused a problem ... The corrected code for + the above is: + + if (i1 <= (int)((i2+3) * sizeof(short))) diff --git a/TEST/ctest b/TEST/ctest new file mode 100644 index 0000000..bec19e3 --- /dev/null +++ b/TEST/ctest @@ -0,0 +1,21 @@ +x=`basename $1 .c` +if test "$2" != s -a "$3" != s +then + echo compiling with old + cc -S $x.c + echo finished compiling old + mv $x.s $x.so +fi +if test $2x = 0x +then + cc -t0 -S $x.c +fi +if test $2 = 1 +then + cc -t1 -S $x.c +fi +if test $2 != 0 -a $2 != 1 +then + cc -t01 -S $x.c +fi +diff $x.so $x.s diff --git a/TEST/old-assn.l b/TEST/old-assn.l new file mode 100644 index 0000000..5b81de0 --- /dev/null +++ b/TEST/old-assn.l @@ -0,0 +1,172 @@ +%{ +/* + * old-assn.l - find old C assignment operators + * + * Quick little lex program to find occurances of old form assignment + * operators in C source programs: =-, =+, etc. + * + * usage: old-assn [file] ... + * + * NOTES: + * Won't work on files with lines longer than MAXLINE + * File names should be less than MAXPATHLEN in length ... + * The standard lex environment already includes + * "yyin" is where lex reads its input from + * lex keeps the current input line number in "yylineno" + */ + +#include +#define MAXLINE 1024 + +static char *ourname, /* guess */ + **filelist; /* list of files we're checking */ +static int errors = 0, /* number of errors of course! */ + printnames = 0; /* if more than one file to scan */ + +main(argc, argv) + int argc; + char **argv; +{ + char *C, + *rindex(); + + ourname = (C = rindex(*argv,'/')) ? ++C : *argv; + if (argc == 1) + { + static char *siv[] = { "stdin", (char *)0 }; + filelist = siv; + } + else + { + filelist = argv+1; + printnames = 1; + if (yyopen() == 1) + exit(errors); + } + yylex(); + exit(errors); +} + +/* + * Open next file when end of file reached on current input. + */ +yywrap() +{ + filelist++; + return(yyopen()); +} + +/* + * Open next file from filelist and set it up as lex's input. Return 1 + * when no more files can be opened, 0 on success. + */ +yyopen() +{ + fclose(yyin); + yylineno = 1; + for (;;) + { + if (!*filelist) + return(1); + if (yyin = fopen(*filelist, "r")) + return(0); + else + { + perror(*filelist); + errors++; + filelist++; + } + } +} + +/* + * Catch cpp "# lineno file" controls and use them to set our current idea of + * what file we're reading and what line number we're on. + */ +yypunt(yytext) + char *yytext; +{ + static char curfile[MAXPATHLEN]; + register char *cp = curfile, + *yp = yytext; + + while (*yp < '0' || '9' < *yp) + yp++; + yylineno = *yp++ - '0'; + while ('0' <= *yp && *yp <= '9') + yylineno = 10*yylineno + *yp++ - '0'; + + while (*yp++ != '\"') + continue; + while (*yp != '\"') + *cp++ = *yp++; + *cp = '\0'; + *filelist = curfile; +} +%} + +%% + +%{ + /* + * The following definitions will appear within the function yylex. + * Note that yylex must *not* return except at an end of line or at + * end of file or the line buffer variable will be trashed (and *no*, + * you can't have a "static register ..." The use of register + * variables for "linep", "bufend" and "cp" below in the macro + * catenate speeds this program up by about 10%). + */ + +#define CATENATE(s) \ + { \ + for (cp = s;linep < bufend && *cp;*linep++ = *cp++); \ + *linep = '\0'; \ + } + + static char linebuf[MAXLINE+1]; /* current input line */ + register char *linep = linebuf, /* linebuf input pointer */ + *bufend = linebuf+MAXLINE+1, + *cp; + static short oldassn = 0, /* old assignment in line */ + string = 0; /* if in a string */ + +%} + +^\#(line)?\ [0-9]+\ \".*\"\n yypunt(yytext); + +[^<>!=]=[-+*&] | +=[/%^|] | +=>> | +=<< { + if (!string) + oldassn = 1; + CATENATE(yytext); + } + +\\\" CATENATE(yytext); + +\" { + string = !string; + CATENATE(yytext); + } + +\n { + /* + * If an old assignment occured on this line, + * then print the file name, line number and + * and line ala grep. + */ + if (oldassn) { + if (printnames) + printf("%s: %d: %s\n", + *filelist, yylineno-1, linebuf); + else + printf("%d: %s\N", + yylineno-1, linebuf); + oldassn = 0; + } + string = 0; + *(linep = linebuf) = '\0'; + } + +. CATENATE(yytext); diff --git a/TEST/tpr.c b/TEST/tpr.c new file mode 100644 index 0000000..90bdb83 --- /dev/null +++ b/TEST/tpr.c @@ -0,0 +1,265 @@ +/* + * Interpret a C intermediate file. + */ +#include +#include "c1.h" + +extern opdope[1]; +extern char *opntab[1]; + +struct table cctab[1], efftab[1], regtab[1], sptab[1]; +char maprel[1], notrel[1]; +char *outname(); + +main() +{ + register t, op; + static char s[9]; + register char *tp; + double atof(); + char numbuf[64]; + int lbl, cond; + int sdep; + + sdep = 0; + for (;;) { + op = getw(stdin); + if ((op&0177400) != 0177000) { + error("Intermediate file error"); + exit(1); + } + lbl = 0; + switch(op &= 0377) { + + case SINIT: + printf("init %d\n", getw(stdin)); + break; + + case EOFC: + printf("eof\n"); + exit(0); + + case BDATA: + if (getw(stdin) == 1) { + printf(".byte "); + for (;;) { + printf("%d", getw(stdin)); + if (getw(stdin) != 1) + break; + printf(","); + } + printf("\n"); + } + break; + + case PROG: + printf("prog\n"); + break; + + case DATA: + printf("data\n"); + break; + + case BSS: + printf("bss\n"); + break; + + case SYMDEF: + printf("symdef "); + outname(s); + printf("%s\n", s); + break; + + case RETRN: + printf("return\n"); + break; + + case CSPACE: + tp = outname(s); + printf("comm %s,%d\n", tp, getw(stdin)); + break; + + case SSPACE: + printf("space %d\n", getw(stdin)); + break; + + case EVEN: + printf("even\n"); + break; + + case SAVE: + printf("save\n"); + break; + + case SETSTK: + t = getw(stdin)-6; + printf("setstack %d\n", t); + break; + + case PROFIL: + t = getw(stdin); + printf("profil %d\n", t); + break; + + case SNAME: + tp = outname(s); + printf("sname %s s%d\n", tp, getw(stdin)); + break; + + case ANAME: + tp = outname(s); + printf("aname %s a%d\n", tp, getw(stdin)); + break; + + case RNAME: + tp = outname(s); + printf("rname %s r%d\n", tp, getw(stdin)); + break; + + case SWIT: + t = getw(stdin); + line = getw(stdin); + printf("switch line %d def %d\n", line, t); + while (t = getw(stdin)) { + printf(" %d %d\n", t, getw(stdin)); + } + break; + + case CBRANCH: + lbl = getw(stdin); + cond = getw(stdin); + case EXPR: + line = getw(stdin); + if (sdep != 1) { + error("Expression input botch"); + exit(1); + } + sdep = 0; + if (lbl) + printf("cbranch %d line %d\n", lbl, line); + else + printf("expr line %d\n", line); + break; + + case NAME: + t = getw(stdin); + if (t==EXTERN) { + t = getw(stdin); + printf("name %o, %s\n", t, outname(s)); + } else if (t==AUTO) { + t = getw(stdin); + printf("name %o a%d\n", t, getw(stdin)); + } else if (t==STATIC) { + t = getw(stdin); + printf("name %o s%d\n", t, getw(stdin)); + } else if (t==REG) { + t = getw(stdin); + printf("name %o r%d\n", t, getw(stdin)); + } else + printf("name botch\n"); + sdep++; + break; + + case CON: + t = getw(stdin); + printf("const %d %d\n", t, getw(stdin)); + sdep++; + break; + + case LCON: + getw(stdin); /* ignore type, assume long */ + t = getw(stdin); + op = getw(stdin); + printf("lconst %D\n", (((long)t<<16) | (unsigned)op)); + sdep++; + break; + + case FCON: + t = getw(stdin); + printf("fcon %s\n", outname(numbuf)); + sdep++; + break; + + case FSEL: + printf("fsel %o ", getw(stdin)); + printf("%d ", getw(stdin)); + printf("%d\n", getw(stdin)); + break; + + case STRASG: + t = getw(stdin); + printf("strasg %o ", getw(stdin)); + printf("%d\n", getw(stdin)); + break; + + case NULLOP: + printf("null\n"); + sdep++; + break; + + case LABEL: + printf("label %d\n", getw(stdin)); + break; + + case NLABEL: + tp = outname(s); + printf("nlabel %s\n", tp); + break; + + case RLABEL: + tp = outname(s); + printf("rlabel %s\n", tp); + break; + + case BRANCH: + printf("branch %d\n", getw(stdin)); + break; + + case SETREG: + printf("nreg %d\n", getw(stdin)); + break; + + default: + t = getw(stdin); + if (op <=0 || op >=120) { + printf("Unknown op %d\n", op); + exit(1); + } + if (opdope[op]&BINARY) + sdep--; + if (sdep<=0) + printf("Binary expression botch\n"); + if (opntab[op] == 0) + printf("op %d %o\n", op, t); + else + printf("%s %o\n", opntab[op], t); + break; + } + } +} + +char * +outname(s) +char *s; +{ + register char *p, c; + register n; + + p = s; + n = 0; + while (c = getc(stdin)) { + *p++ = c; + n++; + } + do { + *p++ = 0; + } while (n++ < 8); + return(s); +} + +error(s) +char *s; +{ + printf("%s\n", s); + exit(1); +} diff --git a/TEST/tprint.c b/TEST/tprint.c new file mode 100644 index 0000000..3b1f0df --- /dev/null +++ b/TEST/tprint.c @@ -0,0 +1,296 @@ +/* + * tree printer routine for C + */ + +#include "c1.h" + +char *strop[] { +"0", +";", +"{", +"}", +"[", +"]", +"(", +")", +":", +",", +"10", +"11", +"12", +"13", +"14", +"15", +"16", +"17", +"18", +"19", +"", +"", +"string", +"fcon", +"sfcon", +"25", +"26", +"", +"", +"sizeof", +"++pre", +"--pre", +"++post", +"--post", +"!un", +"&un", +"*un", +"-un", +"~un", +".", +"+", +"-", +"*", +"/", +"%", +">>", +"<<", +"&", +"|", +"^", +"->", +"itof", +"ftoi", +"&&", +"||", +"&~", +"ftol", +"ltof", +"itol", +"ltoi", +"==", +"!=", +"<=", +"<", +">=", +">", +"p", +">=p", +"=+", +"=-", +"=*", +"=/", +"=%", +"=>>", +"=<<", +"=&", +"=|", +"=^", +"=", +"&(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=spacemax) { + printf("%o: bad tree ptr\n", t); + return; + } + if (t->op<0 || t->op>RFORCE) { + printf("%d\n", t->op); + return; + } + printf("%s", strop[t->op]); + switch (t->op) { + + case SETREG: + printf("%d\n", t->type); + return; + + case PLUS: + case MINUS: + case TIMES: + case DIVIDE: + case MOD: + case LSHIFT: + case RSHIFT: + case AND: + case OR: + case EXOR: + case NAND: + case LOGAND: + case LOGOR: + case EQUAL: + case NEQUAL: + case LESSEQ: + case LESS: + case GREATEQ: + case GREAT: + case LESSEQP: + case LESSP: + case GREATQP: + case GREATP: + case ASPLUS: + case ASMINUS: + case ASTIMES: + case ASDIV: + case ASMOD: + case ASRSH: + case ASLSH: + case ASSAND: + case ASSNAND: + case ASOR: + case ASXOR: + case ASSIGN: + case QUEST: + case CALL: + case MCALL: + case CALL1: + case CALL2: + case TAND: + prtype(t); + + case COLON: + case COMMA: + printf("\n"); + tprt(t->tr1, l+1); + tprt(t->tr2, l+1); + return; + + case INCBEF: + case INCAFT: + case DECBEF: + case DECAFT: + printf(" (%d)", t->tr2); + + case EXCLA: + case AMPER: + case STAR: + case NEG: + case COMPL: + case INIT: + case JUMP: + case LOAD: + case RFORCE: + case ITOF: + case FTOI: + case FTOL: + case LTOF: + case LTOI: + case ITOL: + prtype(t); + printf("\n"); + tprt(t->tr1, l+1); + return; + + case NAME: + case CON: + case SFCON: + case FCON: + case AUTOI: + case AUTOD: + pname(t, 0); + prtype(t); + printf("\n"); + return; + + case CBRANCH: + printf(" (L%d)\n", t->lbl); + tprt(t->btree, l+1); + return; + + default: + printf(" unknown\n"); + return; + } +} + +char *typetab[] { + "int", + "char", + "float", + "double", + "struct", + "(?5)", + "long", + "(?7)", +}; + +char *modtab[] { + 0, + "*", + "()", + "[]", +}; + +prtype(atp) +struct tnode *atp; +{ + register struct tnode *tp; + register t; + + tp = atp; + printf(" %s", typetab[tp->type&07]); + t = (tp->type>>3) & 017777; + while (t&03) { + printf(modtab[t&03]); + t =>> 2; + } + printf(" (%d)", tp->degree); +} diff --git a/TEST/tst_adec.c b/TEST/tst_adec.c new file mode 100644 index 0000000..078526c --- /dev/null +++ b/TEST/tst_adec.c @@ -0,0 +1,10 @@ +int arr[100], x; +long p_end; +main() +{ + puts("test autodecrement inside array reference:"); + p_end = 0; + printf("before %ld (should be 0)\n", p_end); + x = arr[p_end--]; + printf("after %ld (should be -1)\n", p_end); +} diff --git a/TEST/tst_asm.c b/TEST/tst_asm.c new file mode 100644 index 0000000..f79d6e4 --- /dev/null +++ b/TEST/tst_asm.c @@ -0,0 +1,10 @@ +main() +{ + register foo; + int bar; + foo = 4; + bar = 6; + asm("dec r4"); + asm("inc 177766(r5)"); + printf("4-1=%d, 6+1=%d\n", foo, bar); +} diff --git a/TEST/tst_assign.c b/TEST/tst_assign.c new file mode 100644 index 0000000..c1a1317 --- /dev/null +++ b/TEST/tst_assign.c @@ -0,0 +1,10 @@ +main() +{ + int a = 15, + b = 20; + + b =& a; + printf("20 & 15 = %d\n",b); + a =- 8; + printf("15 - 8 = %d\n",a); +} diff --git a/TEST/tst_lgm-g.c b/TEST/tst_lgm-g.c new file mode 100644 index 0000000..7547fd9 --- /dev/null +++ b/TEST/tst_lgm-g.c @@ -0,0 +1,48 @@ +#include + +/* + * Initilization of structure containing a union: + * "tstlgm.c" actually is illegal anyway, since the structure + * only has four entries. This file is more legal. One set of + * compiler fixes allow this to compile (even correctly). + */ + +struct TEST { + int first; + int second; + union UTEST { + int u_int; + char *u_cptr; + int *u_iptr; + } third; + int fourth; +}; + +struct TEST test[] = { + {0}, + {1}, + {1}, + {1}, + {1,2,3,4}, /* was "{1,2,(char *)3,4}," but '82 Ritchie complains */ + {0}, + {1,2,0,0}, + {1,2,0,0}, + {0,0,0,0}, + {1} +}; + +main() +{ + int i; + + printf("Size of TEST structure = %d\n",sizeof(struct TEST)); + printf("Size of structure test = %d\n",sizeof(test)); + + for (i = 0; i < 10; ++i){ + printf("Cycle %d ",i); + printf("First = %d\tSecond = %d\t", + test[i].first, test[i].second); + printf("Union third = %d\t", test[i].third.u_int); + printf("Fourth = %d\n", test[i].fourth); + } +} diff --git a/TEST/tst_lgm.c b/TEST/tst_lgm.c new file mode 100644 index 0000000..548e021 --- /dev/null +++ b/TEST/tst_lgm.c @@ -0,0 +1,47 @@ +#include + +/* Initilization of structure containing a union: + * "tstlgm.c" actually is illegal anyway, since the structure + * only has four entries. This file is more legal. One set of + * compiler fixes allow this to compile (even correctly). + */ + +struct TEST { + int first; + int second; + union UTEST { + int u_int; + char *u_cptr; + int *u_iptr; + } third; + int fourth; +}; + +struct TEST test[] = { + {0}, + {1}, + {1}, + {1}, + {1,2,3,4,5,6}, /* this is what makes it actually illegal */ + {0}, + {1,2,0,0}, + {1,2,0,0}, + {0,0,0,0}, + {1} +}; + +main() +{ + int i; + + printf("Size of TEST structure = %d\n",sizeof(struct TEST)); + printf("Size of structure test = %d\n",sizeof(test)); + + for (i = 0; i < 10; ++i){ + printf("Cycle %d ",i); + printf("First = %d\tSecond = %d\t", + test[i].first, test[i].second); + printf("Union third = %d\t", test[i].third.u_int); + printf("Fourth = %d\n", test[i].fourth); + } +} diff --git a/TEST/tst_longsym.c b/TEST/tst_longsym.c new file mode 100644 index 0000000..a639bbd --- /dev/null +++ b/TEST/tst_longsym.c @@ -0,0 +1,9 @@ +main() +{ + int foobarbyfar, foobarbyfar2; + + foobarbyfar = 6; + foobarbyfar2 = 12; + printf("foobarbyfar=%d, foobarbyfar=%d, should be 6, 12\n", + foobarbyfar, foobarbyfar2); +} diff --git a/TEST/tst_pntint.c b/TEST/tst_pntint.c new file mode 100644 index 0000000..aff635b --- /dev/null +++ b/TEST/tst_pntint.c @@ -0,0 +1,46 @@ +main() +{ + short s; + int i; + long l; + float f; + char *p; + + s = "s = ..."; /* $L4 assigned to s */ + i = "i = ..."; /* $L5 assigned to i */ + + l = "l = ..."; /* $L6 assigned to low word of l, + * upper word cleared + */ + +/* f = "f = ..."; /* totally illegal */ + + s = p; /* p assigned to s */ + i = p; /* p assigned to i */ + + l = p; /* p assigned to low word of l, + * upper word cleared. + */ + +/* f = p; /* totally illegal */ + + p = 'a'; + p = 5; + p = 15L; + p = 100000L; /* -74540(8) is assigned to p, with no + * truncation warning, but then the same + * thing happens with the next statement, + * so this is a global error + */ + + i = 100000L; /* -74540(8) assigned to i */ + + p = s; /* s assigned to p */ + p = i; /* i assigned to p */ + p = l; /* low word of l assigned to p */ +/* p = f; /* totally illegal */ + + l = i; /* i assigned to low word of l, + * upper word sign extended + */ +} diff --git a/TEST/tst_rhh-g.c b/TEST/tst_rhh-g.c new file mode 100644 index 0000000..d29a991 --- /dev/null +++ b/TEST/tst_rhh-g.c @@ -0,0 +1,7 @@ +long *pl; +main() +{ + register i; + + (pl-pl)+(long)i; +} diff --git a/TEST/tst_rhh.c b/TEST/tst_rhh.c new file mode 100644 index 0000000..0674e35 --- /dev/null +++ b/TEST/tst_rhh.c @@ -0,0 +1,7 @@ +long *pl; +main() +{ + register i, j; + + (pl-pl)+(long)i; +} diff --git a/TEST/tst_sgncmp.c b/TEST/tst_sgncmp.c new file mode 100644 index 0000000..cca8276 --- /dev/null +++ b/TEST/tst_sgncmp.c @@ -0,0 +1,39 @@ +int zero = 0; +int selfinv; +int i; +int j; +int k; + +main() +{ + selfinv = ~(((unsigned)~0) >> 1); + i = selfinv + 0101; /* neg */ + j = selfinv - 0100; /* pos */ + printf("everything should be true\n"); + printf("selfinv = 0%o\n", selfinv); + printf("zero = %d\n", zero); + printf("i = 0%o = %d.\n", i, i); + printf("j = 0%o = %d.\n", j, j); + printf("j-i = 0%o = %d.\n", j - i); + printf("j - i < 0\t"); + if ((j-i) < 0) + printf("true\n"); + else + printf("false\n"); + k = j - i; + printf("k=j-i; (k < 0)\t"); + if (k < 0) + printf("true\n"); + else + printf("false\n"); + printf("j - i < zero\t"); + if (j - i < zero) + printf("true\n"); + else + printf("false\n"); + printf("(j-i < 0) == (j - i < zero)\t"); + if ((j-i < 0) == (j - i < zero)) + printf("true\n"); + else + printf("false\n"); +} diff --git a/c0.h b/c0.h new file mode 100644 index 0000000..4f86a65 --- /dev/null +++ b/c0.h @@ -0,0 +1,592 @@ +/* + * C compiler-- first pass header + */ + +#ifndef _C0_H +#define _C0_H 1 + +#include + +#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 +typedef int16_t _INT; +typedef int32_t _LONG; +typedef uint16_t _UNSIGNED_INT; +typedef uint32_t _UNSIGNED_LONG; +typedef struct { uint32_t h; } _FLOAT; +typedef struct { uint32_t l; uint32_t h; } _DOUBLE; +#endif + +/* + * This parameter is the _only_ one which affects the recognized length + * of symbols. Symbol names are dynamically allocated and null terminated + * now, the define below is the 'cutoff' or maximum length to permit. + * + * NOTE: there are _exactly_ 4 references to this in all of c0. There are + * _NO_ references to it in c1. Just make sure that the value is less than + * 79 and c1 will be oblivious to the length of a symbol name. + * + * NOTE: The optimizer (c2) needs to be updated if the size of a symbol + * changes. See the file c2.h +*/ + +#define MAXCPS 32 /* # chars per symbol */ + +#define MAXINT 077777 /* Largest positive short integer */ +#define MAXUINT 0177777 /* largest unsigned integer */ +#define HSHSIZ 300 /* # entries in hash table for names */ +#define CMSIZ 40 /* size of expression stack */ +#define SSIZE 40 /* size of other expression stack */ +#define SWSIZ 300 /* size of switch table */ +#define NMEMS 128 /* Number of members in a structure */ +#define NBPW 16 /* bits per word, object machine */ +#define NBPC 8 /* bits per character, object machine */ +#define NCPW 2 /* chars per word, object machine */ +#define LNCPW 2 /* chars per word, compiler's machine */ +#define LNBPW 16 /* bits per word, compiler's machine */ +/* dlf change +#define STAUTO (-6) offset of first auto variable */ +int STAUTO; +#define STARG 4 /* offset of first argument */ +#define DCLSLOP 512 /* Amount trees lie above declaration stuff */ + +/* Nick */ +#ifdef pdp11 +#define MAXPATHLEN 64 +#else +#define MAXPATHLEN 1024 +#endif + + +/* + * # bytes in primitive types + */ +#define SZCHAR 1 +#define SZINT 2 +#define SZPTR 2 +#define SZFLOAT 4 +#define SZLONG 4 +#define SZDOUB 8 + +/* + * Structure of namelist + */ +struct nmlist { + char hclass; /* storage class */ + char hflag; /* various flags */ + int htype; /* type */ + int *hsubsp; /* subscript list */ + union str *hstrp; /* structure description */ + int hoffset; /* post-allocation location */ + struct nmlist *nextnm; /* next name in chain */ + union str *sparent; /* Structure of which this is member */ + char hblklev; /* Block level of definition */ + char *name; /* ASCII name */ +}; + +/* + * format of a structure description + * Same gadget is also used for fields, + * which can't be structures also. + * Finally, it is used for parameter collection. + */ +union str { + struct SS { + int ssize; /* structure size */ + struct nmlist **memlist; /* member list */ + } S; + struct FS { + int flen; /* field width in bits */ + int bitoffs; /* shift count */ + } F; + struct nmlist P; +}; + +/* + * Structure of tree nodes for operators + */ +struct tnode { + int op; /* operator */ + int type; /* data type */ + int *subsp; /* subscript list (for arrays) */ + union str *strp; /* structure description for structs */ + union tree *tr1; /* left operand */ + union tree *tr2; /* right operand */ +}; + +/* + * Tree node for constants + */ +struct cnode { + int op; + int type; + int *subsp; + union str *strp; + int value; +}; + +/* + * Tree node for long constants + */ +struct lnode { + int op; + int type; + int *subsp; + union str *strp; + long lvalue; +}; + +/* + * tree node for floating + * constants + */ +struct fnode { + int op; + int type; + int *subsp; + union str *strp; + char *cstr; +}; + +/* + * All possibilities for tree nodes + */ +union tree { + struct tnode t; + struct cnode c; + struct lnode l; + struct fnode f; + struct nmlist n; + struct FS fld; +}; + + +/* + * Place used to keep dimensions + * during declarations + */ +struct tdim { + int rank; + int dimens[5]; +}; + +/* + * Table for recording switches. + */ +struct swtab { + int swlab; + int swval; +}; + +#define TNULL (union tree *)NULL + +extern char cvtab[4][4]; +extern char filename[MAXPATHLEN]; /* Nick */ +extern int opdope[]; +extern char ctab[]; +extern char symbuf[MAXCPS+2]; +extern struct nmlist *hshtab[HSHSIZ]; +extern int kwhash[(HSHSIZ+LNBPW-1)/LNBPW]; +extern union tree **cp; +extern int isn; +extern struct swtab swtab[SWSIZ]; +extern int unscflg; +extern struct swtab *swp; +extern int contlab; +extern int brklab; +extern int retlab; +extern int deflab; +extern unsigned autolen; /* make these int if necessary */ +extern unsigned maxauto; /* ... will only cause trouble rarely */ +extern int peeksym; +extern int peekc; +extern int eof; +extern int line; +extern char *locbase; +extern char *treebase; +extern char *treebot; +extern char *coremax; +extern struct nmlist *defsym; +extern struct nmlist *funcsym; +extern int proflg; +extern struct nmlist *csym; +extern int cval; +extern _LONG lcval; +extern int nchstr; +extern int nerror; +extern struct nmlist *paraml; +extern struct nmlist *parame; +extern int strflg; +extern int mosflg; +extern int initflg; +extern char sbuf[BUFSIZ]; +extern FILE *sbufp; +extern int regvar; +extern int bitoffs; +extern struct tnode funcblk; +extern char cvntab[]; +extern char numbuf[64]; +extern struct nmlist **memlist; +extern union str *sparent; +extern int nmems; +extern struct nmlist structhole; +extern int blklev; +extern int mossym; + +/* + operators +*/ +#define EOFC 0 +#define SEMI 1 +#define LBRACE 2 +#define RBRACE 3 +#define LBRACK 4 +#define RBRACK 5 +#define LPARN 6 +#define RPARN 7 +#define COLON 8 +#define COMMA 9 +#define FSEL 10 +#define CAST 11 +#define ETYPE 12 + +#define KEYW 19 +#define NAME 20 +#define CON 21 +#define STRING 22 +#define FCON 23 +#define SFCON 24 +#define LCON 25 +#define SLCON 26 +#define NULLOP 29 +#define XNULLOP 218 /* interface version */ + +#define SIZEOF 91 +#define INCBEF 30 +#define DECBEF 31 +#define INCAFT 32 +#define DECAFT 33 +#define EXCLA 34 +#define AMPER 35 +#define STAR 36 +#define NEG 37 +#define COMPL 38 + +#define DOT 39 +#define PLUS 40 +#define MINUS 41 +#define TIMES 42 +#define DIVIDE 43 +#define MOD 44 +#define RSHIFT 45 +#define LSHIFT 46 +#define AND 47 +#define OR 48 +#define EXOR 49 +#define ARROW 50 +#define ITOF 51 +#define FTOI 52 +#define LOGAND 53 +#define LOGOR 54 +#define FTOL 56 +#define LTOF 57 +#define ITOL 58 +#define LTOI 59 +#define ITOP 13 +#define PTOI 14 +#define LTOP 15 + +#define EQUAL 60 +#define NEQUAL 61 +#define LESSEQ 62 +#define LESS 63 +#define GREATEQ 64 +#define GREAT 65 +#define LESSEQP 66 +#define LESSP 67 +#define GREATQP 68 +#define GREATP 69 + +#define ASPLUS 70 +#define ASMINUS 71 +#define ASTIMES 72 +#define ASDIV 73 +#define ASMOD 74 +#define ASRSH 75 +#define ASLSH 76 +#define ASSAND 77 +#define ASOR 78 +#define ASXOR 79 +#define ASSIGN 80 + +#define QUEST 90 +#define MAX 93 +#define MAXP 94 +#define MIN 95 +#define MINP 96 +#define SEQNC 97 +#define CALL 100 +#define MCALL 101 +#define JUMP 102 +#define CBRANCH 103 +#define INIT 104 +#define SETREG 105 +#define RFORCE 110 +#define BRANCH 111 +#define LABEL 112 +#define NLABEL 113 +#define RLABEL 114 +#define STRASG 115 +#define ITOC 109 +#define SEOF 200 /* stack EOF marker in expr compilation */ + +/* + types +*/ +#define INT 0 +#define CHAR 1 +#define FLOAT 2 +#define DOUBLE 3 +#define STRUCT 4 +#define LONG 6 +#define UNSIGN 7 +#define UNCHAR 8 +#define UNLONG 9 +#define VOID 10 +#define UNION 8 /* adjusted later to struct */ + +#define ALIGN 01 +#define TYPE 017 +#define BIGTYPE 060000 +#define TYLEN 2 +#define XTYPE (03<<4) +#define PTR 020 +#define FUNC 040 +#define ARRAY 060 + +/* + storage classes +*/ +#define KEYWC 1 +#define TYPEDEF 9 +#define MOS 10 +#define AUTO 11 +#define EXTERN 12 +#define STATIC 13 +#define REG 14 +#define STRTAG 15 +#define ARG 16 +#define ARG1 17 +#define AREG 18 +#define DEFXTRN 20 +#define MOU 21 +#define ENUMTAG 22 +#define ENUMCON 24 + +/* + keywords +*/ +#define GOTO 20 +#define RETURN 21 +#define IF 22 +#define WHILE 23 +#define ELSE 24 +#define SWITCH 25 +#define CASE 26 +#define BREAK 27 +#define CONTIN 28 +#define DO 29 +#define DEFAULT 30 +#define FOR 31 +#define ENUM 32 +#define ASM 33 + +/* + characters +*/ +#define BSLASH 117 +#define SHARP 118 +#define INSERT 119 +#define PERIOD 120 +#define SQUOTE 121 +#define DQUOTE 122 +#define LETTER 123 +#define DIGIT 124 +#define NEWLN 125 +#define SPACE 126 +#define UNKN 127 + +/* + * Special operators in intermediate code + */ +#define BDATA 200 +#define WDATA 201 +#define PROG 202 +#define DATA 203 +#define BSS 204 +#define CSPACE 205 +#define SSPACE 206 +#define SYMDEF 207 +#define SAVE 208 +#define RETRN 209 +#define EVEN 210 +#define PROFIL 212 +#define SWIT 213 +#define EXPR 214 +#define SNAME 215 +#define RNAME 216 +#define ANAME 217 +#define SETSTK 219 +#define SINIT 220 +#define ASSEM 223 + +/* + Flag bits +*/ + +#define BINARY 01 +#define LVALUE 02 +#define RELAT 04 +#define ASSGOP 010 +#define LWORD 020 +#define RWORD 040 +#define COMMUTE 0100 +#define RASSOC 0200 +#define LEAF 0400 +#define PCVOK 040000 + +/* + * Conversion codes + */ +#define ITF 1 +#define ITL 2 +#define LTF 3 +#define ITP 4 +#define PTI 5 +#define FTI 6 +#define LTI 7 +#define FTL 8 +#define LTP 9 +#define ITC 10 +#define XX 15 + +/* + * symbol table flags + */ + +#define FMOS 01 +#define FTAG 02 +#define FENUM 03 +#define FUNION 04 +#define FKIND 07 +#define FFIELD 020 +#define FINIT 040 +#define FLABL 0100 + +#ifndef __P +#ifdef __STDC__ +#define __P(args) args +#else +#define __P(args) () +#endif +#endif + +/* c00.c */ +int main __P((int argc, char *argv[])); +int lookup __P((void)); +int findkw __P((void)); +int symbol __P((void)); +int getnum __P((void)); +int subseq __P((int c, int a, int b)); +void putstr __P((int lab, register int max)); +void cntstr __P((void)); +int getcc __P((void)); +int mapch __P((int ac)); +union tree *tree __P((int eflag)); +union tree *xprtype __P((void)); +char *copnum __P((int len)); + +/* c01.c */ +void build __P((int op)); +union tree *structident __P((register union tree *p1, register union tree *p2)); +union tree *convert __P((union tree *p, int t, int cvn, int len)); +void setype __P((register union tree *p, register int t, register union tree *newp)); +union tree *chkfun __P((register union tree *p)); +union tree *disarray __P((register union tree *p)); +void chkw __P((union tree *p, int okt)); +int lintyp __P((int t)); +void werror __P((char *s, ...)); +void error __P((char *s, ...)); +union tree *block __P((int op, int t, int *subs, union str *str, union tree *p1, union tree *p2)); +union tree *nblock __P((register struct nmlist *ds)); +union tree *cblock __P((int v)); +union tree *fblock __P((int t, char *string)); +char *Tblock __P((int n)); +char *starttree __P((void)); +void endtree __P((char *tp)); +char *Dblock __P((int n)); +void chklval __P((register union tree *p)); +int fold __P((int op, register union tree *p1, union tree *p2)); +int conexp __P((void)); +void assignop __P((int op, register union tree *p1, register union tree *p2)); +struct nmlist *gentemp __P((int type)); + +/* c02.c */ +void extdef __P((void)); +void cfunc __P((void)); +int cinit __P((struct nmlist *anp, int flex, int sclass)); +void strinit __P((struct nmlist *np, int sclass)); +void setinit __P((register struct nmlist *np)); +void statement __P((void)); +int forstmt __P((void)); +union tree *pexpr __P((int eflag)); +void pswitch __P((void)); +void funchead __P((void)); +void blockhead __P((void)); +void blkend __P((void)); +void nameconflict __P((register struct nmlist *ocs, register struct nmlist *cs)); +void prste __P((struct nmlist *cs)); +void errflush __P((int ao)); + +/* c03.c */ +int declist __P((int sclass)); +int getkeywords __P((int *scptr, struct nmlist *tptr)); +union str *strdec __P((int mosf, int kind)); +int declare __P((int askw, struct nmlist *tptr, int offset)); +int decl1 __P((int askw, struct nmlist *atptr, int offset, struct nmlist *absname)); +struct nmlist *pushdecl __P((register struct nmlist *sp)); +int getype __P((register struct tdim *dimp, struct nmlist *absname)); +void typov __P((void)); +int align __P((int type, int offset, int aflen)); +void decsyn __P((int o)); +void redec __P((void)); +int goodreg __P((struct nmlist *hp)); + +/* c04.c */ +int decref __P((register int t)); +int incref __P((register int t)); +void cbranch __P((union tree *t, int lbl, int cond)); +void rcexpr __P((register union tree *tp)); +void treeout __P((register union tree *tp, int isstruct)); +void branch __P((int lab)); +void label __P((int l)); +int plength __P((register union tree *p)); +int length __P((union tree *cs)); +int rlength __P((union tree *cs)); +int simplegoto __P((void)); +int nextchar __P((void)); +int spnextchar __P((void)); +void chconbrk __P((int l)); +void dogoto __P((void)); +void doret __P((void)); +void outcode __P((char *s, ...)); +unsigned int hash __P((register char *sp)); + +#endif diff --git a/c00.c b/c00.c new file mode 100644 index 0000000..240d482 --- /dev/null +++ b/c00.c @@ -0,0 +1,903 @@ +/* C compiler + * + * 2.1 (2.11BSD) 1996/01/04 + * + * Called from cc: + * c0 source temp1 temp2 [ profileflag ] + * temp1 gets most of the intermediate code; + * strings are put on temp2, which c1 reads after temp1. + */ + +#include +#include +#include +#include "c0.h" + +int isn = 1; +int peeksym = -1; +int line = 1; +struct tnode funcblk = { NAME }; + +struct kwtab { + char *kwname; + int kwval; +} kwtab[] = { + {"int", INT}, + {"char", CHAR}, + {"float", FLOAT}, + {"double", DOUBLE}, + {"struct", STRUCT}, + {"long", LONG}, + {"unsigned", UNSIGN}, + {"union", UNION}, + {"short", INT}, + {"void", VOID}, + {"auto", AUTO}, + {"extern", EXTERN}, + {"static", STATIC}, + {"register", REG}, + {"goto", GOTO}, + {"return", RETURN}, + {"if", IF}, + {"while", WHILE}, + {"else", ELSE}, + {"switch", SWITCH}, + {"case", CASE}, + {"break", BREAK}, + {"continue", CONTIN}, + {"do", DO}, + {"default", DEFAULT}, + {"for", FOR}, + {"sizeof", SIZEOF}, + {"typedef", TYPEDEF}, + {"enum", ENUM}, + {"asm", ASM}, + {0, 0} +}; + +union tree *cmst[CMSIZ]; +union tree **cp = cmst; +int Wflag; /* print warning messages */ + +int main(argc, argv) int argc; char *argv[]; { + register unsigned i; + register struct kwtab *ip; + char buf1[BUFSIZ], + buf2[BUFSIZ]; + + if (argc>1 && strcmp(argv[1], "-u")==0) { + argc--; + argv++; + unscflg++; + } + if(argc<4) { + error("Arg count"); + exit(1); + } + if (freopen(argv[1], "r", stdin)==NULL) { + error("Can't find %s", argv[1]); + exit(1); + } + setbuf(stdin,buf1); /* stdio sbrk problems */ + if (freopen(argv[2], "w", stdout)==NULL || (sbufp=fopen(argv[3],"w"))==NULL) { + error("Can't create temp"); + exit(1); + } + setbuf(stdout,buf2); /* stdio sbrk problems */ + setbuf(sbufp, sbuf); + /* + * Overlays: allow an extra word on the stack for + * each stack from to store the overlay number. + */ + STAUTO = -8; + while (argc>4) { + switch (argv[4][1]) { + case 'P': + proflg++; + break; + case 'V': /* overlays; default, now */ + break; + case 'w': + case 'W': /* don't print warning messages */ + Wflag++; + break; + } + argc--; argv++; + } + /* + * The hash table locations of the keywords + * are marked; if an identifier hashes to one of + * these locations, it is looked up in in the keyword + * table first. + */ + for (ip=kwtab; ip->kwname; ip++) { + i = hash(ip->kwname); + kwhash[i/LNBPW] |= 1 << (i%LNBPW); + } + coremax = locbase = sbrk(0); + while(!eof) + extdef(); + outcode("B", EOFC); + strflg++; + outcode("B", EOFC); + blkend(); + exit(nerror!=0); +} + +/* + * Look up the identifier in symbuf in the symbol table. + * If it hashes to the same spot as a keyword, try the keyword table + * first. + * Return is a ptr to the symbol table entry. + */ +int lookup() { + unsigned ihash; + register struct nmlist *rp; + + ihash = hash(symbuf); + if (kwhash[ihash/LNBPW] & (1 << (ihash%LNBPW))) + if (findkw()) + return(KEYW); + rp = hshtab[ihash]; + while (rp) { + if (strcmp(symbuf, rp->name) != 0) + goto no; + if (mossym != (rp->hflag&FKIND)) + goto no; + csym = rp; + return(NAME); + no: + rp = rp->nextnm; + } + rp = (struct nmlist *)Dblock(sizeof(struct nmlist)); + rp->nextnm = hshtab[ihash]; + hshtab[ihash] = rp; + rp->hclass = 0; + rp->htype = 0; + rp->hoffset = 0; + rp->hsubsp = NULL; + rp->hstrp = NULL; + rp->sparent = NULL; + rp->hblklev = blklev; + rp->hflag = mossym; + rp->name = Dblock((strlen(symbuf) + 1 + LNCPW - 1) & ~(LNCPW - 1)); + strcpy(rp->name, symbuf); + csym = rp; + return(NAME); +} + +/* + * Search the keyword table. + */ +int findkw() { + register struct kwtab *kp; + + for (kp=kwtab; kp->kwname; kp++) { + if (strcmp(symbuf, kp->kwname) == 0) { + cval = kp->kwval; + return(1); + } + } + return(0); +} + + +/* + * Return the next symbol from the input. + * peeksym is a pushed-back symbol, peekc is a pushed-back + * character (after peeksym). + * mosflg means that the next symbol, if an identifier, + * is a member of structure or a structure tag or an enum tag + */ +int symbol() { + register int c; + register char *sp; + register int tline; + + if (peeksym>=0) { + c = peeksym; + peeksym = -1; + if (c==NAME) + mosflg = 0; + return(c); + } + if (peekc) { + c = peekc; + peekc = 0; + } else + if (eof) + return(EOFC); + else + c = getchar(); +loop: + if (c==EOF) { + eof++; + return(EOFC); + } + switch(ctab[c]) { + + case SHARP: + if ((c=symbol())!=CON) { + error("Illegal #"); + return(c); + } + tline = cval; + while (ctab[peekc]==SPACE) + peekc = getchar(); + if (peekc=='"') { + sp = filename; + while (sp < filename + MAXPATHLEN - 1 && (c = mapch('"')) >= 0) /* Nick */ + *sp++ = c; + *sp++ = 0; + peekc = getchar(); + } + if (peekc != '\n') { + error("Illegal #"); + while (getchar()!='\n' && eof==0) + ; + } + peekc = 0; + line = tline; + return(symbol()); + + case NEWLN: + line++; + + case SPACE: + c = getchar(); + goto loop; + + case PLUS: + return(subseq(c,PLUS,INCBEF)); + + case MINUS: + if (subseq(c, 0, 1)) + return(DECBEF); + return(subseq('>', MINUS, ARROW)); + + case ASSIGN: + return(subseq(c, ASSIGN, EQUAL)); + + case LESS: + if (subseq(c,0,1)) + return(LSHIFT); + return(subseq('=',LESS,LESSEQ)); + + case GREAT: + if (subseq(c,0,1)) + return(RSHIFT); + return(subseq('=',GREAT,GREATEQ)); + + case EXCLA: + return(subseq('=',EXCLA,NEQUAL)); + + case BSLASH: + if (subseq('/', 0, 1)) + return(MAX); + goto unkn; + + case DIVIDE: + if (subseq('\\', 0, 1)) + return(MIN); + if (subseq('*',1,0)) + return(DIVIDE); + while ((c = spnextchar()) != EOFC) { + peekc = 0; + if (c=='*') { + if (spnextchar() == '/') { + peekc = 0; + c = getchar(); + goto loop; + } + } + } + eof++; + error("Nonterminated comment"); + return(0); + + case PERIOD: + case DIGIT: + peekc = c; + return(getnum()); + + case DQUOTE: + cval = isn++; + return(STRING); + + case SQUOTE: + return(getcc()); + + case LETTER: + sp = symbuf; + while (ctab[c]==LETTER || ctab[c]==DIGIT) { + if (sp < symbuf + MAXCPS) + *sp++ = c; + c = getchar(); + } + *sp++ = '\0'; + mossym = mosflg; + mosflg = 0; + peekc = c; + if ((c=lookup())==KEYW && cval==SIZEOF) + c = SIZEOF; + return(c); + + case AND: + return(subseq('&', AND, LOGAND)); + + case OR: + return(subseq('|', OR, LOGOR)); + + case UNKN: + unkn: + error("Unknown character"); + c = getchar(); + goto loop; + + } + return(ctab[c]); +} + +/* + * Read a number. Return kind. + */ +int getnum() { + register char *np; + register int c, base; + int expseen, sym, ndigit; + char *nsyn; + int maxdigit; + + nsyn = "Number syntax"; + lcval = 0; + base = 10; + maxdigit = 0; + np = numbuf; + ndigit = 0; + sym = CON; + expseen = 0; + if ((c=spnextchar()) == '0') + base = 8; + for (;; c = getchar()) { + *np++ = c; + if (ctab[c]==DIGIT || (base==16) && ('a'<=c&&c<='f'||'A'<=c&&c<='F')) { + if (base==8) + lcval <<= 3; + else if (base==10) + lcval = ((lcval<<2) + lcval)<<1; + else + lcval <<= 4; + if (ctab[c]==DIGIT) + c -= '0'; + else if (c>='a') + c -= 'a'-10; + else + c -= 'A'-10; + lcval += c; + ndigit++; + if (c>maxdigit) + maxdigit = c; + continue; + } + if (c=='.') { + if (base==16 || sym==FCON) + error(nsyn); + sym = FCON; + base = 10; + continue; + } + if (ndigit==0) { + sym = DOT; + break; + } + if ((c=='e'||c=='E') && expseen==0) { + expseen++; + sym = FCON; + if (base==16 || maxdigit>=10) + error(nsyn); + base = 10; + *np++ = c = getchar(); + if (c!='+' && c!='-' && ctab[c]!=DIGIT) + break; + } else if (c=='x' || c=='X') { + if (base!=8 || lcval!=0 || sym!=CON) + error(nsyn); + base = 16; + } else if ((c=='l' || c=='L') && sym==CON) { + c = getchar(); + sym = LCON; + break; + } else + break; + } + peekc = c; + if (maxdigit >= base) + error(nsyn); + if (sym==FCON) { + np[-1] = 0; + cval = np-numbuf; + return(FCON); + } + if (sym==CON && (lcval<0 || lcval>MAXINT&&base==10 || (lcval>>1)>MAXINT)) { + sym = LCON; + } + cval = lcval; + return(sym); +} + +/* + * If the next input character is c, return b and advance. + * Otherwise push back the character and return a. + */ +int subseq(c, a, b) int c; int a; int b; { + if (spnextchar() != c) + return(a); + peekc = 0; + return(b); +} + +/* + * Write out a string, either in-line + * or in the string temp file labelled by + * lab. + */ +void putstr(lab, max) int lab; register int max; { + register int c; + + nchstr = 0; + if (lab) { + strflg++; + outcode("BNB", LABEL, lab, BDATA); + max = 10000; + } else + outcode("B", BDATA); + while ((c = mapch('"')) >= 0) { + if (nchstr < max) { + nchstr++; + if (nchstr%15 == 0) + outcode("0B", BDATA); + outcode("1N", c & 0377); + } + } + if (nchstr < max) { + nchstr++; + outcode("10"); + } + outcode("0"); + strflg = 0; +} + +void cntstr() { + register int c; + + nchstr = 1; + while ((c = mapch('"')) >= 0) { + nchstr++; + } +} + +/* + * read a single-quoted character constant. + * The routine is sensitive to the layout of + * characters in a word. + */ +int getcc() { + register int c, cc; +#ifdef pdp11 + register char *ccp; + char realc; +#else + register int shift; +#endif + + cval = 0; +#ifdef pdp11 + ccp = (char *)&cval; +#else + shift = 0; +#endif + cc = 0; + while((c=mapch('\'')) >= 0) + if(cc++ < LNCPW) { +#ifdef pdp11 + *ccp++ = c; +#else + cval |= (c & 0377) << shift; + shift += 8; +#endif + } + if (cc>LNCPW) + error("Long character constant"); + if (cc==1) { +#ifdef pdp11 + realc = cval; + cval = realc; +#else + /* we default to signed char */ + if (cval & 0200) + cval |= ~0377; +#endif + } + return(CON); +} + +/* + * Read a character in a string or character constant, + * detecting the end of the string. + * It implements the escape sequences. + */ +int mapch(ac) int ac; { + register int a, c, n; + static int mpeek; + + c = ac; + if (a = mpeek) + mpeek = 0; + else + a = getchar(); +loop: + if (a==c) + return(-1); + switch(a) { + + case '\n': + case '\0': + error("Nonterminated string"); + peekc = a; + return(-1); + + case '\\': + switch (a=getchar()) { + + case 't': + return('\t'); + + case 'n': + return('\n'); + + case 'b': + return('\b'); + + case 'f': + return('\014'); + + case 'v': + return('\013'); + + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + n = 0; + c = 0; + while (++c<=3 && '0'<=a && a<='7') { + n <<= 3; + n += a-'0'; + a = getchar(); + } + mpeek = a; + return(n); + + case 'r': + return('\r'); + + case '\n': + line++; + a = getchar(); + goto loop; + } + } + return(a); +} + +/* + * Read an expression and return a pointer to its tree. + * It's the classical bottom-up, priority-driven scheme. + * The initflg prevents the parse from going past + * "," or ":" because those delimiters are special + * in initializer (and some other) expressions. + */ +union tree *tree(eflag) int eflag; { + int *op, opst[SSIZE], *pp, prst[SSIZE]; + register int andflg, o; + register struct nmlist *cs; + int p, ps, os, xo = 0, *xop; + char *svtree; + static struct cnode garbage = { CON, INT, (int *)NULL, (union str *)NULL, 0 }; + + svtree = starttree(); + op = opst; + pp = prst; + *op = SEOF; + *pp = 06; + andflg = 0; + +advanc: + switch (o=symbol()) { + + case NAME: + cs = csym; + if (cs->hclass==TYPEDEF) + goto atype; + if (cs->hclass==ENUMCON) { + *cp++ = cblock(cs->hoffset); + goto tand; + } + if (cs->hclass==0 && cs->htype==0) + if(nextchar()=='(') { + /* set function */ + cs->hclass = EXTERN; + cs->htype = FUNC; + } else { + cs->hclass = STATIC; + error("%s undefined; func. %s", cs->name, + funcsym ? funcsym->name : "(none)"); + } + *cp++ = nblock(cs); + goto tand; + + case FCON: + *cp++ = fblock(DOUBLE, copnum(cval)); + goto tand; + + case LCON: + *cp = (union tree *)Tblock(sizeof(struct lnode)); + (*cp)->l.op = LCON; + (*cp)->l.type = LONG; + (*cp)->l.lvalue = lcval; + cp++; + goto tand; + + case CON: + *cp++ = cblock(cval); + goto tand; + + /* fake a static char array */ + case STRING: +/* + * This hack is to compensate for a bit of simplemindedness I'm not sure how + * else to fix. + * + * i = sizeof ("foobar"); + * + * or + * i = sizeof "foobar"; + * + * would generate ".byte 'f,'o','o,'b,'a,'r,0" into the data segment! + * + * What I did here was to scan to "operator" stack looking for left parens + * "(" preceeded by a "sizeof". If both are seen and in that order or only + * a SIZEOF is sedn then the string is inside a 'sizeof' and should not + * generate any data to the object file. +*/ + xop = op; + while (xop > opst) + { + xo = *xop--; + if (xo != LPARN) + break; + } + if (xo == SIZEOF) + cntstr(); + else + putstr(cval, 0); + cs = (struct nmlist *)Tblock(sizeof(struct nmlist)); + cs->hclass = STATIC; + cs->hoffset = cval; + *cp++ = block(NAME, unscflg? ARRAY+UNCHAR:ARRAY+CHAR, &nchstr, + (union str *)NULL, (union tree *)cs, TNULL); + + tand: + if(cp>=cmst+CMSIZ) { + error("Expression overflow"); + exit(1); + } + if (andflg) + goto syntax; + andflg = 1; + goto advanc; + + case KEYW: + atype: + if (*op != LPARN || andflg) + goto syntax; + peeksym = o; + *cp++ = xprtype(); + if ((o=symbol()) != RPARN) + goto syntax; + o = CAST; + --op; + --pp; + if (*op == SIZEOF) { + andflg = 1; + *pp = 100; + goto advanc; + } + goto oponst; + + case INCBEF: + case DECBEF: + if (andflg) + o += 2; + goto oponst; + + case COMPL: + case EXCLA: + case SIZEOF: + if (andflg) + goto syntax; + goto oponst; + + case MINUS: + if (!andflg) + o = NEG; + andflg = 0; + goto oponst; + + case AND: + case TIMES: + if (andflg) + andflg = 0; + else if (o==AND) + o = AMPER; + else + o = STAR; + goto oponst; + + case LPARN: + if (andflg) { + o = symbol(); + if (o==RPARN) + o = MCALL; + else { + peeksym = o; + o = CALL; + andflg = 0; + } + } + goto oponst; + + case RBRACK: + case RPARN: + if (!andflg) + goto syntax; + goto oponst; + + case DOT: + case ARROW: + mosflg = FMOS; + break; + + case ASSIGN: + if (andflg==0 && PLUS<=*op && *op<=EXOR) { + o = *op-- + ASPLUS - PLUS; + pp--; + goto oponst; + } + break; + + } + /* binaries */ + if (andflg==0) + goto syntax; + andflg = 0; + +oponst: + p = (opdope[o]>>9) & 037; +opon1: + if (o==COLON && op[0]==COLON && op[-1]==QUEST) { + build(*op--); + build(*op--); + pp -= 2; + } + ps = *pp; + if (p>ps || p==ps && (opdope[o]&RASSOC)!=0) { + switch (o) { + + case INCAFT: + case DECAFT: + p = 37; + break; + case LPARN: + case LBRACK: + case CALL: + p = 04; + } + if (initflg) { + if ((o==COMMA && *op!=LPARN && *op!=CALL) + || (o==COLON && *op!=QUEST)) { + p = 00; + goto opon1; + } + } + if (op >= &opst[SSIZE-1]) { + error("expression overflow"); + exit(1); + } + *++op = o; + *++pp = p; + goto advanc; + } + --pp; + os = *op--; + if (andflg==0 && p>5 && ((opdope[o]&BINARY)==0 || o>=INCBEF&&o<=DECAFT) && opdope[os]&BINARY) + goto syntax; + switch (os) { + + case SEOF: + peeksym = o; + build(0); /* flush conversions */ + if (eflag) + endtree(svtree); + return(*--cp); + + case COMMA: + if (*op != CALL) + os = SEQNC; + break; + + case CALL: + if (o!=RPARN) + goto syntax; + build(os); + goto advanc; + + case MCALL: + *cp++ = block(NULLOP, INT, (int *)NULL, + (union str *)NULL, TNULL, TNULL); + os = CALL; + break; + + case INCBEF: + case INCAFT: + case DECBEF: + case DECAFT: + *cp++ = cblock(1); + break; + + case LPARN: + if (o!=RPARN) + goto syntax; + goto advanc; + + case LBRACK: + if (o!=RBRACK) + goto syntax; + build(LBRACK); + goto advanc; + } + build(os); + goto opon1; + +syntax: + error("Expression syntax"); + errflush(o); + if (eflag) + endtree(svtree); + return((union tree *) &garbage); +} + +union tree *xprtype() { + struct nmlist typer, absname; + int sc; + register union tree **scp; + + scp = cp; + sc = DEFXTRN; /* will cause error if class mentioned */ + getkeywords(&sc, &typer); + absname.hclass = 0; + absname.hblklev = blklev; + absname.hsubsp = NULL; + absname.hstrp = NULL; + absname.htype = 0; + decl1(sc, &typer, 0, &absname); + cp = scp; + return(block(ETYPE, absname.htype, absname.hsubsp, + absname.hstrp, TNULL, TNULL)); +} + +char *copnum(len) int len; { + register char *s1; + + s1 = Tblock((len+LNCPW-1) & ~(LNCPW-1)); + strcpy(s1, numbuf); + return(s1); +} diff --git a/c01.c b/c01.c new file mode 100644 index 0000000..6c01650 --- /dev/null +++ b/c01.c @@ -0,0 +1,954 @@ +/* + * C compiler + */ + +#include +#include +#include +#ifdef __STDC__ +#include +#define _va_start(ap, arg) va_start(ap, arg) +#else +#include +#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 && tt.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 = v1v2; + break; + + case LESSEQ: + v1 = v1<=v2; + break; + + case GREATEQ: + v1 = v1>=v2; + break; + + case LESSP: + v1 = (_UNSIGNED_INT)v1v2; + break; + + case LESSEQP: + v1 = (_UNSIGNED_INT)v1<=v2; + break; + + case GREATQP: + v1 = (_UNSIGNED_INT)v1>=v2; + break; + + divchk: + error("Divide check"); + nerror--; + default: + return(0); + } + p1->c.value = v1; + *cp++ = p1; + if (unsignf) + p1->t.type = UNSIGN; + return(1); +} + +/* + * Compile an expression expected to have constant value, + * for example an array bound or a case value. + */ +int conexp() { + register union tree *t; + + initflg++; + if (t = tree(1)) + if (t->t.op != CON) + error("Constant required"); + initflg--; + /*fprintf(stderr, "conexp() %d\n", t->c.value);*/ + return(t->c.value); +} + +/* + * Handle peculiar assignment ops that need a temporary. + */ +void assignop(op, p1, p2) int op; register union tree *p1; register union tree *p2; { + register struct nmlist *np; + + op += PLUS - ASPLUS; + if (p1->t.op==NAME) { + *cp++ = p1; + *cp++ = p1; + *cp++ = p2; + build(op); + build(ASSIGN); + return; + } + np = gentemp(incref(p1->t.type)); + *cp++ = nblock(np); + *cp++ = p1; + build(AMPER); + build(ASSIGN); + *cp++ = nblock(np); + build(STAR); + *cp++ = nblock(np); + build(STAR); + *cp++ = p2; + build(op); + build(ASSIGN); + build(SEQNC); +} + +/* + * Generate an automatic temporary for + * use in certain assignment ops + */ +struct nmlist *gentemp(type) int type; { + register struct nmlist *tp; + + tp = (struct nmlist *)Tblock(sizeof(struct nmlist)); + tp->hclass = AUTO; + tp->htype = type; + tp->hflag = 0; + tp->hsubsp = NULL; + tp->hstrp = NULL; + tp->hblklev = blklev; + autolen -= rlength((union tree *)tp); + tp->hoffset = autolen; + if (autolen < maxauto) + maxauto = autolen; + return(tp); +} diff --git a/c02.c b/c02.c new file mode 100644 index 0000000..d361fb4 --- /dev/null +++ b/c02.c @@ -0,0 +1,803 @@ +/* + * C compiler + */ + +#include +#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 && (ninitnel) { + 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; plnextnm) { + if (cs->hclass == ARG || cs->hclass==AREG) + error("Not an argument: %s", cs->name); + } + } + outcode("BN", SETREG, regvar); +} + +void blockhead() { + register int r; + + r = regvar; + blklev++; + declist(0); + if (r != regvar) + outcode("BN", SETREG, regvar); +} + +/* + * After the end of a block, delete local + * symbols; + * Also complain about undefined labels. + */ +void blkend() { + register struct nmlist *cs, **lcs; + register int i; + + blklev--; + for (i = 0; i < HSHSIZ; i++) { + lcs = &hshtab[i]; + cs = *lcs; + while (cs) { + if (cs->hblklev > blklev + && (((cs->hflag&FLABL)==0 && cs->hclass!=EXTERN) || blklev<=0)) { + if (cs->hclass==0) + error("%s undefined", cs->name); + if (cs->hclass==EXTERN) + nameconflict(hshtab[i], cs); + *lcs = cs->nextnm; + } else + lcs = &cs->nextnm; + cs = cs->nextnm; + } + } +} + +void nameconflict(ocs, cs) register struct nmlist *ocs; register struct nmlist *cs; { + + for (; ocs!=NULL; ocs = ocs->nextnm) + if (ocs!=cs && ocs->hclass==EXTERN && + strncmp(cs->name, ocs->name, MAXCPS-1) == 0) + error("names %s and %s conflict", cs->name, ocs->name); +} + +/* + * write out special definitions of local symbols for + * benefit of the debugger. None of these are used + * by the assembler except to save them. + */ +void prste(cs) struct nmlist *cs; { + register int nkind; + + switch (cs->hclass) { + case REG: + nkind = RNAME; + break; + + case AUTO: + nkind = ANAME; + break; + + case STATIC: + nkind = SNAME; + break; + + default: + return; + + } + outcode("BSN", nkind, cs->name, cs->hoffset); +} + +/* + * In case of error, skip to the next + * statement delimiter. + */ +void errflush(ao) int ao; { + register int o; + + o = ao; + while(o>RBRACE) { /* ; { } */ + if (o==STRING) + putstr(0, 0); + o = symbol(); + } + peeksym = o; +} diff --git a/c03.c b/c03.c new file mode 100644 index 0000000..bfa3a16 --- /dev/null +++ b/c03.c @@ -0,0 +1,727 @@ +/* + * C compiler, phase 1 + * Handles processing of declarations, + * except for top-level processing of + * externals. + */ + +#include +#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->hblklevhclass && 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 = ""; + 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; + } + 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->hblklevhclass==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>= 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 (ahsubsp = 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<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<offset) + bitoffs = 0; + } + if (flen) { + if (type==INT || type==UNSIGN) { + if (flen > NBPW) + error(ftl); + if (flen+bitoffs > NBPW) { + bitoffs = 0; + a += NCPW; + } + } else if (type==CHAR || type==UNCHAR) { + if (flen > NBPC) + error(ftl); + if (flen+bitoffs > NBPC) { + bitoffs = 0; + a += 1; + } + } else + error("Bad type for field"); + } + return(a-offset); +} + +/* + * Complain about syntax error in declaration + */ +void decsyn(o) int o; { + error("Declaration syntax"); + errflush(o); +} + +/* + * Complain about a redeclaration + */ +void redec() { + error("%s redeclared", defsym->name); +} + +/* + * Determine if a variable is suitable for storage in + * a register; if so return the register number + */ +int goodreg(hp) struct nmlist *hp; { + int type; + + type = hp->htype; + if ((type!=INT && type!=UNSIGN && (type&XTYPE)==0) + || (type&XTYPE)>PTR || regvar<3) + return(-1); + return(--regvar); +} diff --git a/c04.c b/c04.c new file mode 100644 index 0000000..7f8699f --- /dev/null +++ b/c04.c @@ -0,0 +1,422 @@ +/* + * C compiler + */ + +#include +#ifdef __STDC__ +#include +#define _va_start(ap, arg) va_start(ap, arg) +#else +#include +#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)<t.op==INIT && tp->t.tr1->t.op==CON) { + if (tp->t.type==CHAR || tp->t.type==UNCHAR) { + outcode("B1N0", BDATA, tp->t.tr1->c.value); + return; + } else if (tp->t.type==INT || tp->t.type==UNSIGN) { + outcode("BN", SINIT, tp->t.tr1->c.value); + return; + } + } + treeout(tp, 0); + outcode("BN", EXPR, line); +} + +void treeout(tp, isstruct) register union tree *tp; int isstruct; { + register struct nmlist *hp; + register int nextisstruct; + + if (tp == NULL || tp->t.op==NULLOP) { + outcode("B", XNULLOP); + return; + } + nextisstruct = tp->t.type==STRUCT; + switch(tp->t.op) { + + case NAME: + hp = &tp->t.tr1->n; + if (hp->hclass==TYPEDEF) + error("Illegal use of type name"); + outcode("BNN", NAME, hp->hclass==0?STATIC:hp->hclass, tp->t.type); + if (hp->hclass==EXTERN) + outcode("S", hp->name); + else + outcode("N", hp->hoffset); + break; + + case LCON: + outcode("BNNN", tp->l.op, tp->l.type, (_UNSIGNED_INT)(tp->l.lvalue>>16), + (_UNSIGNED_INT)tp->l.lvalue); + break; + + case CON: + outcode("BNN", tp->c.op, tp->c.type, tp->c.value); + break; + + case FCON: + outcode("BNF", tp->f.op, tp->f.type, tp->f.cstr); + break; + + case STRING: + outcode("BNNN", NAME, STATIC, tp->t.type, tp->t.tr1); + break; + + case FSEL: + treeout(tp->t.tr1, nextisstruct); + outcode("BNNN", tp->t.op, tp->t.type, + tp->t.tr2->fld.bitoffs, tp->t.tr2->fld.flen); + break; + + case ETYPE: + error("Illegal use of type"); + break; + + case AMPER: + treeout(tp->t.tr1, 1); + outcode("BN", tp->t.op, tp->t.type); + break; + + + case CALL: + treeout(tp->t.tr1, 1); + treeout(tp->t.tr2, 0); + outcode("BN", CALL, tp->t.type); + break; + + default: + treeout(tp->t.tr1, nextisstruct); + if (opdope[tp->t.op]&BINARY) + treeout(tp->t.tr2, nextisstruct); + outcode("BN", tp->t.op, tp->t.type); + break; + } + if (nextisstruct && isstruct==0) + outcode("BNN", STRASG, STRUCT, tp->t.strp->S.ssize); +} + +/* + * Generate a branch + */ +void branch(lab) int lab; { + outcode("BN", BRANCH, lab); +} + +/* + * Generate a label + */ +void label(l) int l; { + outcode("BN", LABEL, l); +} + +/* + * ap is a tree node whose type + * is some kind of pointer; return the size of the object + * to which the pointer points. + */ +int plength(p) register union tree *p; { + register int t, l; + + if (p==0 || ((t=p->t.type)&~TYPE) == 0) /* not a reference */ + return(1); + p->t.type = decref(t); + l = length(p); + p->t.type = t; + return(l); +} + +/* + * return the number of bytes in the object + * whose tree node is acs. + */ +int length(cs) union tree *cs; { + register int t, elsz; + long n; + int nd; + + t = cs->t.type; + n = 1; + nd = 0; + while ((t&XTYPE) == ARRAY) { + t = decref(t); + n *= cs->t.subsp[nd++]; + } + if ((t&~TYPE)==FUNC) + return(0); + if (t>=PTR) + elsz = SZPTR; + else switch(t&TYPE) { + + case VOID: + error("Illegal use of void object"); + return(2); + + case INT: + case UNSIGN: + elsz = SZINT; + break; + + case CHAR: + case UNCHAR: + elsz = 1; + break; + + case FLOAT: + elsz = SZFLOAT; + break; + + case UNLONG: + case LONG: + elsz = SZLONG; + break; + + case DOUBLE: + elsz = SZDOUB; + break; + + case STRUCT: + if ((elsz = cs->t.strp->S.ssize) == 0) + error("Undefined structure"); + break; + default: + error("Compiler error (length)"); + return(0); + } + n *= elsz; + if (n >= (_UNSIGNED_INT)50000) + werror("very large data structure"); + return(n); +} + +/* + * The number of bytes in an object, rounded up to a word. + */ +int rlength(cs) union tree *cs; { + return((length(cs)+ALIGN) & ~ALIGN); +} + +/* + * After an "if (...) goto", look to see if the transfer + * is to a simple label. + */ +int simplegoto() { + register struct nmlist *csp; + + if ((peeksym=symbol())==NAME && nextchar()==';') { + csp = csym; + if (csp->hblklev == 0) + csp = pushdecl(csp); + if (csp->hclass==0 && csp->htype==0) { + csp->htype = ARRAY; + csp->hflag |= FLABL; + if (csp->hoffset==0) + csp->hoffset = isn++; + } + if ((csp->hclass==0||csp->hclass==STATIC) + && csp->htype==ARRAY) { + peeksym = -1; + return(csp->hoffset); + } + } + return(0); +} + +/* + * Return the next non-white-space character + */ +int nextchar() { + while (spnextchar()==' ') + peekc = 0; + return(peekc); +} + +/* + * Return the next character, translating all white space + * to blank and handling line-ends. + */ +int spnextchar() { + register int c; + + if ((c = peekc)==0) + c = getchar(); + if (c=='\t' || c=='\014') /* FF */ + c = ' '; + else if (c=='\n') { + c = ' '; + line++; + } + peekc = c; + return(c); +} + +/* + * is a break or continue legal? + */ +void chconbrk(l) int l; { + if (l==0) + error("Break/continue error"); +} + +/* + * The goto statement. + */ +void dogoto() { + register union tree *np; + register char *st; + + st = starttree(); + *cp++ = tree(0); + build(STAR); + chkw(np = *--cp, -1); + rcexpr(block(JUMP, 0, (int *)NULL, (union str *)NULL, np, TNULL)); + endtree(st); +} + +/* + * The return statement, which has to convert + * the returned object to the function's type. + */ +void doret() { + if (nextchar() != ';') { + register char *st; + + st = starttree(); + *cp++ = (union tree *)&funcblk; + *cp++ = tree(0); + build(ASSIGN); + cp[-1] = cp[-1]->t.tr2; + build(RFORCE); + rcexpr(*--cp); + endtree(st); + } + branch(retlab); +} + +/* + * Write a character on the error output. + */ +/* + * Coded output: + * B: beginning of line; an operator + * N: a number + * S: a symbol (external) + * 1: number 1 + * 0: number 0 + */ +#ifdef __STDC__ +void outcode(char *s, ...) +#else +void outcode(s, va_alist) char *s; va_dcl +#endif +{ + va_list ap; + register FILE *bufp; + register int ni; + register char *np; + int n; + + bufp = stdout; + if (strflg) + bufp = sbufp; + _va_start(ap, s); + for (;;) switch(*s++) { + case 'B': + ni = va_arg(ap, int); + fputc(ni, bufp); + fputc(0376, bufp); + continue; + + case 'N': + ni = va_arg(ap, int); + fputc(ni, bufp); + fputc(ni>>8, bufp); + continue; + + case 'F': + np = va_arg(ap, char *); + n = 1000; + goto str; + + case 'S': + np = va_arg(ap, char *); + n = MAXCPS-1; + if (*np) + fputc('_', bufp); + str: + while(n-- && *np) { + fputc(*np++ & 0177, bufp); + } + fputc(0, bufp); + continue; + + case '1': + fputc(1, bufp); + fputc(0, bufp); + continue; + + case '0': + fputc(0, bufp); + fputc(0, bufp); + continue; + + case '\0': + va_end(ap); + if (ferror(bufp)) { + error("Write error on temp"); + exit(1); + } + return; + + default: + error("Botch in outcode"); + } +} + +unsigned int hash(sp) register char *sp; { + register unsigned int h; + + h = 0; + for (; *sp; sp++) { + h += h; + h += *sp; + } + return(h%HSHSIZ); +} diff --git a/c05.c b/c05.c new file mode 100644 index 0000000..5cf663b --- /dev/null +++ b/c05.c @@ -0,0 +1,250 @@ +#include "c0.h" +/* + * info on operators: + * 01-- is binary operator + * 02-- left (or only) operand must be lvalue + * 04-- is relational operator + * 010-- is assignment-type operator + * 020-- non-float req. on left + * 040-- non-float req. on right + * 0100-- is commutative + * 0200-- is right, not left-associative + * 0400-- is leaf of tree + * *0XX000-- XX is priority of operator + */ +int opdope[] = { + 000000, /* EOFC */ + 000000, /* ; */ + 000000, /* { */ + 000000, /* } */ + 036001, /* [ */ + 002000, /* ] */ + 037000, /* ( */ + 002000, /* ) */ + 014201, /* : */ + 007001, /* , */ + 000001, /* field selection */ + 034201, /* CAST */ + 000000, /* ETYPE */ + 000001, /* integer->ptr */ + 000001, /* ptr->integer */ + 000001, /* long->ptr */ + 000000, /* 16 */ + 000000, /* 17 */ + 000000, /* 18 */ + 000000, /* 19 */ + 000400, /* name */ + 000400, /* short constant */ + 000400, /* string */ + 000400, /* float */ + 000400, /* double */ + 000400, /* long constant */ + 000400, /* long constant <= 16 bits */ + 000000, /* 27 */ + 000000, /* 28 */ + 000400, /* () empty arglist */ + 074203, /* ++pre */ + 074203, /* --pre */ + 074203, /* ++post */ + 074203, /* --post */ + 034200, /* !un */ + 034202, /* &un */ + 034220, /* *un */ + 034200, /* -un */ + 034220, /* ~un */ + 036001, /* . (structure reference) */ + 070101, /* + */ + 070001, /* - */ + 032101, /* * */ + 032001, /* / */ + 032001, /* % */ + 026061, /* >> */ + 026061, /* << */ + 020161, /* & */ + 017161, /* | */ + 017161, /* ^ */ + 036001, /* -> */ + 000000, /* int -> double */ + 000000, /* double -> int */ + 016001, /* && */ + 015001, /* || */ + 030001, /* &~ */ + 000000, /* 56 */ + 000000, /* 57 */ + 000000, /* 58 */ + 000000, /* 59 */ + 022005, /* == */ + 022005, /* != */ + 024005, /* <= */ + 024005, /* < */ + 024005, /* >= */ + 024005, /* > */ + 024005, /*

p */ + 024005, /* >=p */ + 052213, /* += */ + 052213, /* -= */ + 012213, /* *= */ + 012213, /* /= */ + 012213, /* %= */ + 012253, /* >>= */ + 012253, /* <<= */ + 012253, /* &= */ + 012253, /* |= */ + 012253, /* ^= */ + 012213, /* = */ + 000000, /* 81 */ + 000000, /* 82 */ + 000000, /* 83 */ + 000000, /* 84 */ + 000000, /* 85 */ + 000000, /* 86 */ + 000000, /* 87 */ + 000000, /* 88 */ + 000000, /* 89 */ + 014201, /* ? */ + 034200, /* sizeof */ + 000000, /* 92 */ + 021101, /* min */ + 021101, /* minp */ + 021101, /* max */ + 021101, /* maxp */ + 007001, /* , */ + 000000, /* 98 */ + 000000, /* 99 */ + 036001, /* call */ + 036001, /* mcall */ + 000000, /* goto */ + 000000, /* jump cond */ + 000000, /* branch cond */ + 000000, /* 105 */ + 000000, /* 106 */ + 000000, /* 107 */ + 000000, /* 108 */ + 000000, /* char->int */ + 000000, /* 109 - force r0 */ + 000000, /* 110 */ + 000000, /* 111 */ + 000000, /* 112 */ + 000000, /* 113 */ + 000000, /* 114 */ + 000000, /* 115 */ + 000000, /* 116 */ + 000000, /* 117 */ + 000000, /* 118 */ + 000000, /* 119 */ + 000000, /* 120 */ + 000000, /* 121 */ + 000000, /* 122 */ + 000000, /* 123 */ + 000000, /* 124 */ + 000000, /* 125 */ + 000000, /* 126 */ + 000000, /* 127 */ + 026061, /* 128 - << unsigned long */ + 012253 /* 129 - <<= unsigned long */ +}; + +/* + * conversion table: + * FTI: float (or double) to integer + * ITF: integer to float + * ITP: integer to pointer + * ITL: integer to long + * LTI: long to integer + * LTF: long to float + * FTL: float to long + * PTI: pointer to integer + * LTP: long to ptr (ptr[long]) + * XX: usually illegal + * When FTI, LTI, FTL are added in they specify + * that it is the left operand that should be converted. + * For + this is done and the conversion is turned back into + * ITF, ITL, LTF. + * For = however the left operand can't be converted + * and the specified conversion is applied to the rhs. + */ +char cvtab[4][4] = { +/* int double long ptr */ +/* int */ {0, (FTI<<4)+ITF, (LTI<<4)+ITL, (ITP<<4)+ITP}, +/* double */ {ITF, 0, LTF, XX}, +/* long */ {ITL, (FTL<<4)+LTF, 0, (LTP<<4)+LTP}, +/* ptr */ {ITP, XX, LTP, PTI} +}; + +/* + * relate conversion numbers to operators + */ +char cvntab[] = { + 0, ITOF, ITOL, LTOF, ITOP, PTOI, FTOI, LTOI, FTOL, LTOP, +}; + +/* + * character type table + */ +char ctab[] = { + EOFC, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, + UNKN, SPACE, NEWLN, SPACE, SPACE, UNKN, UNKN, UNKN, + UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, + UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, UNKN, + SPACE, EXCLA, DQUOTE, SHARP, UNKN, MOD, AND, SQUOTE, + LPARN, RPARN, TIMES, PLUS, COMMA, MINUS, PERIOD, DIVIDE, + DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, + DIGIT, DIGIT, COLON, SEMI, LESS, ASSIGN, GREAT, QUEST, + UNKN, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, + LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, + LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, + LETTER, LETTER, LETTER, LBRACK, BSLASH, RBRACK, EXOR, LETTER, + UNKN, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, + LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, + LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, + LETTER, LETTER, LETTER, LBRACE, OR, RBRACE, COMPL, UNKN +}; + +int STAUTO; +char cvtab[4][4]; +char filename[MAXPATHLEN]; +char symbuf[MAXCPS+2]; +struct nmlist *hshtab[HSHSIZ]; +int kwhash[(HSHSIZ+LNBPW-1)/LNBPW]; +struct swtab swtab[SWSIZ]; +int unscflg; +struct swtab *swp; +int contlab; +int brklab; +int retlab; +int deflab; +unsigned autolen; /* make these int if necessary */ +unsigned maxauto; /* ... will only cause trouble rarely */ +int peekc; +int eof; +char *locbase; +char *treebase; +char *treebot; +char *coremax; +struct nmlist *defsym; +struct nmlist *funcsym; +int proflg; +struct nmlist *csym; +int cval; +_LONG lcval; +int nchstr; +int nerror; +struct nmlist *paraml; +struct nmlist *parame; +int strflg; +int mosflg; +int initflg; +char sbuf[BUFSIZ]; +FILE *sbufp; +int regvar; +int bitoffs; +char cvntab[]; +char numbuf[64]; +struct nmlist **memlist; +union str *sparent; +int nmems; +struct nmlist structhole; +int blklev; +int mossym; diff --git a/c1.h b/c1.h new file mode 100644 index 0000000..d6be7e7 --- /dev/null +++ b/c1.h @@ -0,0 +1,576 @@ +/* + * C code generator header + */ + +#ifndef _C1_H +#define _C1_H 1 + +#include +#include + +#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 +typedef int16_t _INT; +typedef int32_t _LONG; +typedef uint16_t _UNSIGNED_INT; +typedef uint32_t _UNSIGNED_LONG; +typedef struct { uint32_t h; } _FLOAT; +typedef struct { uint32_t l; uint32_t h; } _DOUBLE; +#endif + +#ifndef NULL +#define NULL 0 +#endif +#define TNULL (union tree *)NULL +#define UNS(x) ((unsigned short)(x)) + +/* + * Tree node for unary and binary + */ +struct tnode { + int op; + int type; + int degree; + union tree *tr1; + union tree *tr2; +}; + +/* + * tree names for locals + */ +struct tname { + int op; + int type; + char class; + char regno; + int offset; + int nloc; +}; + +/* + * tree names for externals + */ +struct xtname { + int op; + int type; + char class; + char regno; + int offset; + char *name; +}; + +/* + * short constants + */ +struct tconst { + int op; + int type; + _INT value; +}; + +/* + * long constants + */ +struct lconst { + int op; + int type; + _LONG lvalue; +}; + +/* + * Floating constants + */ +struct ftconst { + int op; + int type; + int value; + _DOUBLE fvalue; +}; + +/* + * Node used for field assignments + */ +struct fasgn { + int op; + int type; + int degree; + union tree *tr1; + union tree *tr2; + int mask; +}; + +union tree { + struct tnode t; + struct tname n; + struct xtname x; + struct tconst c; + struct lconst l; + struct ftconst f; + struct fasgn F; +}; + +struct optab { + char tabdeg1; + char tabtyp1; + char tabdeg2; + char tabtyp2; + char *tabstring; +}; + +struct table { + int tabop; + struct optab *tabp; +}; + +struct instab { + int iop; + char *str1; + char *str2; +}; + +struct swtab { + int swlab; + int swval; +}; + +extern char maprel[]; +extern char notrel[]; +extern int nreg; +extern int isn; +extern int line; +extern int nerror; /* number of hard errors */ +extern struct table cctab[]; +extern struct table efftab[]; +extern struct table regtab[]; +extern struct table sptab[]; +extern struct table lsptab[1]; +extern char mov[]; +extern char clr[]; +extern char cmp[]; +extern char tst[]; +extern char add[]; +extern char sub[]; +extern char inc[]; +extern char dec[]; +extern char mul[]; +extern char _div[]; +extern char asr[]; +extern char ash[]; +extern char asl[]; +extern char bic[]; +extern char bic1[]; +extern char bit[]; +extern char bit1[]; +extern char bis[]; +extern char bis1[]; +extern char xor[]; +extern char neg[]; +extern char com[]; +extern char stdol[]; +extern char ashc[]; +extern char slmul[]; +extern char sldiv[]; +extern char slrem[]; +extern char uldiv[]; +extern char ulrem[]; +extern char ualdiv[]; +extern char ualrem[]; +extern char ultof[]; +extern char ulsh[]; +extern char ualsh[]; +extern char almul[]; +extern char aldiv[]; +extern char alrem[]; +extern char udiv[]; +extern char urem[]; +extern char jeq[]; +extern char jne[]; +extern char jle[]; +extern char jgt[]; +extern char jlt[]; +extern char jge[]; +extern char jlos[]; +extern char jhi[]; +extern char jlo[]; +extern char jhis[]; +extern char nop[]; +extern char jbr[]; +extern char jpl[]; +extern char jmi[]; +extern char jmijne[]; +extern char jmijeq[]; +extern struct instab instab[]; +extern struct instab branchtab[]; +extern int opdope[]; +extern char *opntab[]; +extern int nstack; +extern int nfloat; +extern struct tname sfuncr; +extern char *funcbase; +extern char *curbase; +extern char *coremax; +extern struct tconst czero, cone; +extern long totspace; +extern int regpanic; /* set when SU register alg. fails */ +extern int panicposs; /* set when there might be need for regpanic */ +extern jmp_buf jmpbuf; +extern long ftell(); +extern char *sbrk(); +extern struct optab *match(); +extern union tree *optim(); +extern union tree *unoptim(); +extern union tree *pow2(); +extern union tree *tnode(); +extern union tree *sdelay(); +extern union tree *ncopy(); +extern union tree *getblk(); +extern union tree *strfunc(); +extern union tree *isconstant(); +extern union tree *tconst(); +extern union tree *hardlongs(); +extern union tree *lconst(); +extern union tree *acommute(); +extern union tree *lvfield(); +extern union tree *paint(); +extern long ftell(); + +/* + * Some special stuff for long comparisons + */ +extern int xlab1, xlab2, xop, xzero; + +/* + operators +*/ +#define EOFC 0 +#define SEMI 1 +#define LBRACE 2 +#define RBRACE 3 +#define LBRACK 4 +#define RBRACK 5 +#define LPARN 6 +#define RPARN 7 +#define COLON 8 +#define COMMA 9 +#define FSEL 10 +#define FSELR 11 +#define FSELT 12 +#define FSELA 16 +#define ULSH 17 +#define ASULSH 18 + +#define KEYW 19 +#define NAME 20 +#define CON 21 +#define STRING 22 +#define FCON 23 +#define SFCON 24 +#define LCON 25 +#define SLCON 26 + +#define AUTOI 27 +#define AUTOD 28 +#define NULLOP 218 +#define INCBEF 30 +#define DECBEF 31 +#define INCAFT 32 +#define DECAFT 33 +#define EXCLA 34 +#define AMPER 35 +#define STAR 36 +#define NEG 37 +#define COMPL 38 + +#define DOT 39 +#define PLUS 40 +#define MINUS 41 +#define TIMES 42 +#define DIVIDE 43 +#define MOD 44 +#define RSHIFT 45 +#define LSHIFT 46 +#define AND 47 +#define ANDN 55 +#define OR 48 +#define EXOR 49 +#define ARROW 50 +#define ITOF 51 +#define FTOI 52 +#define LOGAND 53 +#define LOGOR 54 +#define FTOL 56 +#define LTOF 57 +#define ITOL 58 +#define LTOI 59 +#define ITOP 13 +#define PTOI 14 +#define LTOP 15 + +#define EQUAL 60 +#define NEQUAL 61 +#define LESSEQ 62 +#define LESS 63 +#define GREATEQ 64 +#define GREAT 65 +#define LESSEQP 66 +#define LESSP 67 +#define GREATQP 68 +#define GREATP 69 + +#define ASPLUS 70 +#define ASMINUS 71 +#define ASTIMES 72 +#define ASDIV 73 +#define ASMOD 74 +#define ASRSH 75 +#define ASLSH 76 +#define ASAND 77 +#define ASOR 78 +#define ASXOR 79 +#define ASSIGN 80 +#define TAND 81 +#define LTIMES 82 +#define LDIV 83 +#define LMOD 84 +#define ASANDN 85 +#define LASTIMES 86 +#define LASDIV 87 +#define LASMOD 88 + +#define QUEST 90 +/* #define MAX 93 not used; wanted macros in param.h */ +#define MAXP 94 +/* #define MIN 95 not used; wanted macros in param.h */ +#define MINP 96 +#define LLSHIFT 91 +#define ASLSHL 92 +#define SEQNC 97 +#define CALL1 98 +#define CALL2 99 +#define CALL 100 +#define MCALL 101 +#define JUMP 102 +#define CBRANCH 103 +#define INIT 104 +#define SETREG 105 +#define LOAD 106 +#define PTOI1 107 +#define ITOC 109 +#define RFORCE 110 + +/* + * Intermediate code operators + */ +#define BRANCH 111 +#define LABEL 112 +#define NLABEL 113 +#define RLABEL 114 +#define STRASG 115 +#define STRSET 116 +#define UDIV 117 +#define UMOD 118 +#define ASUDIV 119 +#define ASUMOD 120 +#define ULTIMES 121 /* present for symmetry */ +#define ULDIV 122 +#define ULMOD 123 +#define ULASTIMES 124 /* present for symmetry */ +#define ULASDIV 125 +#define ULASMOD 126 +#define ULTOF 127 +#define ULLSHIFT 128 /* << for unsigned long */ +#define UASLSHL 129 /* <<= for unsigned long */ + +#define BDATA 200 +#define PROG 202 +#define DATA 203 +#define BSS 204 +#define CSPACE 205 +#define SSPACE 206 +#define SYMDEF 207 +#define SAVE 208 +#define RETRN 209 +#define EVEN 210 +#define PROFIL 212 +#define SWIT 213 +#define EXPR 214 +#define SNAME 215 +#define RNAME 216 +#define ANAME 217 +#define SETSTK 219 +#define SINIT 220 +#define GLOBAL 221 +#define C3BRANCH 222 +#define ASSEM 223 + +/* + * types + */ +#define INT 0 +#define CHAR 1 +#define FLOAT 2 +#define DOUBLE 3 +#define STRUCT 4 +#define RSTRUCT 5 +#define LONG 6 +#define UNSIGN 7 +#define UNCHAR 8 +#define UNLONG 9 +#define VOID 10 + +#define TYLEN 2 +#define TYPE 017 +#define XTYPE (03<<4) +#define PTR 020 +#define FUNC 040 +#define ARRAY 060 + +/* + storage classes +*/ +#define KEYWC 1 +#define MOS 10 +#define AUTO 11 +#define EXTERN 12 +#define STATIC 13 +#define REG 14 +#define STRTAG 15 +#define ARG 16 +#define OFFS 20 +#define XOFFS 21 +#define SOFFS 22 + +/* + Flag bits +*/ + +#define BINARY 01 +#define LVALUE 02 +#define RELAT 04 +#define ASSGOP 010 +#define LWORD 020 +#define RWORD 040 +#define COMMUTE 0100 +#define RASSOC 0200 +#define LEAF 0400 +#define CNVRT 01000 + +#if 1 /* moved here from c12.c */ +#define LSTSIZ 20 +struct acl { + int nextl; + int nextn; + union tree *nlist[LSTSIZ]; + union tree *llist[LSTSIZ+1]; +}; +#endif + +#ifndef __P +#ifdef __STDC__ +#define __P(args) args +#else +#define __P(args) () +#endif +#endif + +/* c10.c */ +int main __P((int argc, char *argv[])); +struct optab *match __P((union tree *tree, struct table *table, int nrleft, int nocvt)); +int rcexpr __P((union tree *atree, struct table *atable, int reg)); +int cexpr __P((register union tree *tree, struct table *table, int areg)); +int reorder __P((union tree **treep, struct table *table, int reg)); +int sreorder __P((union tree **treep, struct table *table, int reg, int recurf)); +int delay __P((union tree **treep, struct table *table, int reg)); +union tree *sdelay __P((union tree **ap)); +union tree *paint __P((register union tree *tp, register int type)); +union tree *ncopy __P((register union tree *p)); +int chkleaf __P((register union tree *tree, struct table *table, int reg)); +int comarg __P((register union tree *tree, int *flagp)); +union tree *strfunc __P((register union tree *tp)); +void doinit __P((register int type, register union tree *tree)); +void movreg __P((int r0, int r1, union tree *tree)); + +/* c11.c */ +int degree __P((register union tree *t)); +void pname __P((register union tree *p, int flag)); +void pbase __P((register union tree *p)); +int xdcalc __P((register union tree *p, int nrleft)); +int dcalc __P((register union tree *p, int nrleft)); +int notcompat __P((register union tree *p, int ast, int deg, int op)); +int prins __P((int op, int c, struct instab *itable, int lbl)); +int collcon __P((register union tree *p)); +int isfloat __P((register union tree *t)); +int oddreg __P((register union tree *t, register int reg)); +int arlength __P((int t)); +void pswitch __P((struct swtab *afp, struct swtab *alp, int deflab)); +void breq __P((int v, int l)); +int sort __P((struct swtab *afp, struct swtab *alp)); +int ispow2 __P((register union tree *tree)); +union tree *pow2 __P((register union tree *tree)); +void cbranch __P((union tree *atree, register int lbl, int cond, register int reg)); +void branch __P((int lbl, int aop, int c)); +void longrel __P((union tree *atree, int lbl, int cond, int reg)); +int xlongrel __P((int f)); +void label __P((int l)); +void popstk __P((int a)); +void werror __P((char *s)); +void error __P((char *s, ...)); +void psoct __P((int an)); +void getree __P((void)); +int geti __P((void)); +void strasg __P((union tree *atp)); +int decref __P((register int t)); +int incref __P((register int t)); + +/* c12.c */ +union tree *optim __P((register union tree *tree)); +union tree *unoptim __P((register union tree *tree)); +union tree *lvfield __P((register union tree *t)); +union tree *acommute __P((register union tree *tree)); +int sideeffects __P((register union tree *tp)); +void distrib __P((struct acl *list)); +void squash __P((union tree **p, union tree **maxp)); +void _const __P((int op, register _INT *vp, _INT v, int type)); +union tree *lconst __P((int op, register union tree *lp, register union tree *rp)); +void insert __P((int op, register union tree *tree, register struct acl *list)); +union tree *tnode __P((int op, int type, union tree *tr1, union tree *tr2)); +union tree *tconst __P((int val, int type)); +union tree *getblk __P((int size)); +int islong __P((int t)); +union tree *isconstant __P((register union tree *t)); +union tree *hardlongs __P((register union tree *t)); +int uns __P((union tree *tp)); + +#ifndef pdp11 +/* fp.c */ +int fp_tst __P((_DOUBLE val)); +_DOUBLE fp_abs __P((_DOUBLE val)); +_DOUBLE fp_neg __P((_DOUBLE val)); +int fp_le __P((_DOUBLE val0, _DOUBLE val1)); +int fp_ge __P((_DOUBLE val0, _DOUBLE val1)); +int fp_gt __P((_DOUBLE val0, _DOUBLE val1)); +int fp_lt __P((_DOUBLE val0, _DOUBLE val1)); +_INT fp_double_to_int __P((_DOUBLE val)); +_LONG fp_double_to_long __P((_DOUBLE val)); +_FLOAT fp_double_to_float __P((_DOUBLE val)); +_DOUBLE fp_int_to_double __P((_INT val)); +_DOUBLE fp_long_to_double __P((_LONG val)); +_DOUBLE fp_float_to_double __P((_FLOAT val)); +_DOUBLE fp_add __P((_DOUBLE val0, _DOUBLE val1)); +_DOUBLE fp_sub __P((_DOUBLE val0, _DOUBLE val1)); +_DOUBLE fp_mul __P((_DOUBLE val0, _DOUBLE val1)); +_DOUBLE fp_div __P((_DOUBLE val0, _DOUBLE val1)); +_DOUBLE fp_ldexp __P((_DOUBLE val, _INT exp)); + +/* fp_atof.c */ +_DOUBLE fp_atof __P((register char *p)); +#endif + +#endif diff --git a/c10.c b/c10.c new file mode 100644 index 0000000..8120924 --- /dev/null +++ b/c10.c @@ -0,0 +1,1382 @@ +/* + * C compiler, part 2 + * + * (long)btodb(l) produced 'no code table error for op: >>(17) type: 6' + * allow both long and ulong at line ~341. 1996/6/19 +*/ + +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)c10.c 2.1 (2.11BSD GTE) 10/4/94"; +#endif + +#include +#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; it.type==LONG || tree->t.type==UNLONG) { + rcexpr(tree, sptab, 0); + retval = arlength(tree->t.type); + } else { + (*flagp)++; + rcexpr(tree, lsptab, 0); + retval = 0; + } + return(retval); +} + +union tree *strfunc(tp) register union tree *tp; { + if (tp->t.op != CALL) + return(tp); + paint(tp, STRUCT+PTR); + return(tnode(STAR, STRUCT, tp, TNULL)); +} + +/* + * Compile an initializing expression + */ +void doinit(type, tree) register int type; register union tree *tree; { + _FLOAT sfval; + _DOUBLE fval; + _LONG lval; + + if (type==CHAR || type==UNCHAR) { + printf(".byte "); + if (tree->t.type&XTYPE) + goto illinit; + type = INT; + } + if (type&XTYPE) + type = INT; + switch (type) { + case INT: + case UNSIGN: + if (tree->t.op==FTOI) { + if (tree->t.tr1->t.op!=FCON && tree->t.tr1->t.op!=SFCON) + goto illinit; + tree = tree->t.tr1; +#ifdef pdp11 + tree->c.value = tree->f.fvalue; +#else + tree->c.value = fp_double_to_int(tree->f.fvalue); +#endif + tree->t.op = CON; + } else if (tree->t.op==LTOI) { + if (tree->t.tr1->t.op!=LCON) + goto illinit; + tree = tree->t.tr1; + lval = tree->l.lvalue; + tree->t.op = CON; + tree->c.value = lval; + } + if (tree->t.op == CON) + printf("%o\n", UNS(tree->c.value)); + else if (tree->t.op==AMPER) { + pname(tree->t.tr1, 0); + putchar('\n'); + } else + goto illinit; + return; + + case DOUBLE: + case FLOAT: + if (tree->t.op==ITOF) { + if (tree->t.tr1->t.op==CON) { +/* note: this should be changed to respect the signedness of the int */ +#ifdef pdp11 + fval = tree->t.tr1->c.value; +#else + fval = fp_int_to_double(tree->t.tr1->c.value); +#endif + } else + goto illinit; + } else if (tree->t.op==FCON || tree->t.op==SFCON) { + fval = tree->f.fvalue; + } else if (tree->t.op==LTOF) { + if (tree->t.tr1->t.op!=LCON) + goto illinit; +/* note: this should be changed to respect the signedness of the long */ +#ifdef pdp11 + fval = tree->t.tr1->l.lvalue; +#else + fval = fp_long_to_double(tree->t.tr1->l.lvalue); +#endif + } else + goto illinit; + /* note: value is still in emulated r0 and used again below */ + if (type==FLOAT) { +#ifdef pdp11 + sfval = fval; +/*nonportable*/ + printf("%o; %o\n", + ((_UNSIGNED_INT *)&sfval)[0], + ((_UNSIGNED_INT *)&sfval)[1]); +#else + sfval = fp_double_to_float(fval); + printf("%o; %o\n", + (int)(sfval.h >> 16) & 0xffff, + (int)sfval.h & 0xffff); +#endif + } else { +#ifdef pdp11 +/* nonportable */ + printf("%o; %o; %o; %o\n", + ((_UNSIGNED_INT *)&fval)[0], + ((_UNSIGNED_INT *)&fval)[1], + ((_UNSIGNED_INT *)&fval)[2], + ((_UNSIGNED_INT *)&fval)[3]); +#else + printf("%o; %o; %o; %o\n", + (int)(fval.h >> 16) & 0xffff, + (int)fval.h & 0xffff, + (int)(fval.l >> 16) & 0xffff, + (int)fval.l & 0xffff); +#endif + } + return; + + case UNLONG: + case LONG: + if (tree->t.op==FTOL) { + tree = tree->t.tr1; + if (tree->t.op==SFCON) + tree->t.op = FCON; + if (tree->t.op!= FCON) + goto illinit; +#ifdef pdp11 + lval = tree->f.fvalue; +#else + lval = fp_double_to_long(tree->f.fvalue); +#endif + } else if (tree->t.op==ITOL) { + if (tree->t.tr1->t.op != CON) + goto illinit; + if (uns(tree->t.tr1)) + lval = (_UNSIGNED_INT)tree->t.tr1->c.value; + else + lval = tree->t.tr1->c.value; + } else if (tree->t.op==LCON) { + lval = tree->l.lvalue; + } else + goto illinit; +/* nonportable */ + printf("%o; %o\n", UNS((lval>>16)), UNS(lval)); + return; + } +illinit: + error("Illegal initialization"); +} + +void movreg(r0, r1, tree) int r0; int r1; union tree *tree; { + register char *s; + char c; + + if (r0==r1) + return; + if (tree->t.type==LONG || tree->t.type == UNLONG) { + if (r0>=nreg || r1>=nreg) { + error("register overflow: compiler error"); + } + s = "mov r%d,r%d\nmov r%d,r%d\n"; + if (r0 < r1) + printf(s, r0+1,r1+1,r0,r1); + else + printf(s, r0,r1,r0+1,r1+1); + return; + } + c = isfloat(tree); + printf("mov%.1s r%d,r%d\n", &c, r0, r1); +} diff --git a/c11.c b/c11.c new file mode 100644 index 0000000..cf903af --- /dev/null +++ b/c11.c @@ -0,0 +1,1190 @@ +/* + * C compiler + */ + +#include +#include +#include +#ifdef __STDC__ +#include +#define _va_start(ap, arg) va_start(ap, arg) +#else +#include +#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 && att.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; jswval, i) */ + poctab[(_UNSIGNED_INT)swp->swval%i]++; + worst = 0; + for (j=0; jworst) + worst = poctab[j]; + if (i*worst < best) { + tabs = i; + best = i*worst; + } + } + i = isn++; + printf(hashsw, UNS(tabs), i, i); + isn++; + for (i=0; iswval, 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; cpswval == 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<t.op = ASAND; + tree->t.tr2->c.value = (1<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>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)< +#include "c1.h" +#include /* 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<t.tr1->c.value)-1)<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; ic.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; it.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; inextl; i++) { + if ((d1=degree(list->llist[i]))llist[i]; + list->llist[i] = tree; + tree = t; + d = d1; + } + } + list->llist[list->nextl++] = tree; +} + +union tree *tnode(op, type, tr1, tr2) int op; int type; union tree *tr1; union tree *tr2; { + register union tree *p; + + p = getblk(sizeof(struct tnode)); + p->t.op = op; + p->t.type = type; + p->t.degree = 0; + p->t.tr1 = tr1; + p->t.tr2 = tr2; + return(p); +} + +union tree *tconst(val, type) int val; int type; { + register union tree *p; + + p = getblk(sizeof(struct tconst)); + p->t.op = CON; + p->t.type = type; + p->c.value = val; + return(p); +} + +union tree *getblk(size) int size; { + register union tree *p; + + if (size&01) + size++; + p = (union tree *)curbase; + if ((curbase += size) >= coremax) { +#ifdef pdp11 + if (sbrk(1024) == (char *)-1) { +#else + if (sbrk(1024) != coremax) { +#endif + error("Out of space-- c1"); + exit(1); + } + coremax += 1024; + } + return(p); +} + +int islong(t) int t; { + if (t==LONG || t==UNLONG) + return(2); + return(1); +} + +union tree *isconstant(t) register union tree *t; { + if (t->t.op==CON || t->t.op==SFCON) + return(t); + if (t->t.op==ITOL && t->t.tr1->t.op==CON) + return(t->t.tr1); + return(NULL); +} + +union tree *hardlongs(t) register union tree *t; { + switch(t->t.op) { + + case TIMES: + case DIVIDE: + case MOD: + if (t->t.type == UNLONG) + t->t.op += ULTIMES-TIMES; + else + t->t.op += LTIMES-TIMES; + break; + + case ASTIMES: + case ASDIV: + case ASMOD: + if (t->t.type == UNLONG) + t->t.op += ULASTIMES-ASTIMES; + else + t->t.op += LASTIMES-ASTIMES; + t->t.tr1 = tnode(AMPER, LONG+PTR, t->t.tr1, TNULL); + break; + + default: + return(t); + } + return(optim(t)); +} + +/* + * Is tree of unsigned type? + */ +int uns(tp) union tree *tp; { + register int t; + + t = tp->t.type; + if (t==UNSIGN || t==UNCHAR || t==UNLONG || t&XTYPE) + return(1); + return(0); +} diff --git a/c13.c b/c13.c new file mode 100644 index 0000000..77024ec --- /dev/null +++ b/c13.c @@ -0,0 +1,459 @@ +/* + * C second pass -- tables + */ + +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)c13.c 2.1 (2.11BSD GTE) 10/4/94"; +#endif + +#include "c1.h" +/* + * Operator dope table-- see description in c0. + */ +int opdope[] = { + 000000, /* EOFC (0) */ + 000000, /* ; */ + 000000, /* { */ + 000000, /* } */ + 036000, /* [ */ + 002000, /* ] */ + 036000, /* ( */ + 002000, /* ) */ + 014201, /* : */ + 007001, /* , */ + 000000, /* field selection (10) */ + 000000, /* reverse field selection */ + 000001, /* temporary field selection */ + 000001, /* int->ptr */ + 000001, /* ptr->int */ + 000001, /* long->ptr */ + 000001, /* field assignment */ + 000001, /* >> unsigned */ + 000001, /* >>= unsigned */ + 000000, /* keyword */ + 000400, /* name (20) */ + 000400, /* short constant */ + 000400, /* string */ + 000400, /* float */ + 000400, /* double */ + 000400, /* long const */ + 000400, /* long const <= 16 bits */ + 000400, /* autoi, *r++ */ + 000400, /* autod, *--r */ + 000400, /* () empty arglist */ + 034213, /* ++pre (30) */ + 034213, /* --pre */ + 034213, /* ++post */ + 034213, /* --post */ + 034220, /* !un */ + 034202, /* &un */ + 034220, /* *un */ + 034200, /* -un */ + 034220, /* ~un */ + 036001, /* . (structure reference) */ + 030101, /* + (40) */ + 030001, /* - */ + 032101, /* * */ + 032001, /* / */ + 032001, /* % */ + 026061, /* >> */ + 026061, /* << */ + 020161, /* & */ + 016161, /* | */ + 016161, /* ^ */ + 036001, /* -> (50) */ + 001000, /* int -> double */ + 001000, /* double -> int */ + 000001, /* && */ + 000001, /* || */ + 030001, /* &~ */ + 001000, /* double -> long */ + 001000, /* long -> double */ + 001000, /* integer -> long */ + 000000, /* long -> integer */ + 022005, /* == (60) */ + 022005, /* != */ + 024005, /* <= */ + 024005, /* < */ + 024005, /* >= */ + 024005, /* > */ + 024005, /*

p */ + 024005, /* >=p */ + 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", + "+=", /* 70 */ + "-=", + "*=", + "/=", + "%=", + ">>=", + "<<=", + "&=", + "|=", + "^=", + "=", /* 80 */ + "& for tests", + "*", + "/", + "%", + "&= ~", + "*=", + "/=", + "%=", + 0, + "?", /* 90 */ + "<<", + "<<=", + "\\/", + "\\/", + "/\\", + "/\\", + ",", + "call1", + "call2", + "call", /* 100 */ + "mcall", + "goto", + "jump cond", + "branch cond", + "set nregs", + "load value", + "ptr->integer", + 0, + "int->char", + "force register", /* 110 */ + "branch", + "label", + "nlabel", + "rlabel", + "=structure", + "= (struct setup)", + "/", + "%", + "/=", + "%=", /* 120 */ + "*", /* unsigned long */ + "/", /* unsigned long */ + "%", /* unsigned long */ + "*=", /* unsigned long */ + "/=", /* unsigned long */ + "%=", /* unsigned long */ + "u_long->double", /* unsigned long */ + ">>", /* unsigned long */ + ">>=", /* 129 unsigned long */ +}; + +/* + * Strings for instruction tables. + */ +char mov[] = "mov"; +char clr[] = "clr"; +char cmp[] = "cmp"; +char tst[] = "tst"; +char add[] = "add"; +char sub[] = "sub"; +char inc[] = "inc"; +char dec[] = "dec"; +char mul[] = "mul"; +char _div[] = "div"; +char asr[] = "asr"; +char ash[] = "ash"; +char asl[] = "asl"; +char bic[] = "bic"; +char bic1[] = "bic $1,"; +char bit[] = "bit"; +char bit1[] = "bit $1,"; +char bis[] = "bis"; +char bis1[] = "bis $1,"; +char xor[] = "xor"; +char neg[] = "neg"; +char com[] = "com"; +char stdol[] = "*$"; +char ashc[] = "ashc"; +char slmul[] = "lmul"; +char sldiv[] = "ldiv"; +char slrem[] = "lrem"; +char uldiv[] = "uldiv"; +char ulrem[] = "ulrem"; +char ualdiv[] = "ualdiv"; +char ualrem[] = "ualrem"; +char ultof[] = "ultof"; +char ulsh[] = "ulsh"; +char ualsh[] = "ualsh"; +char almul[] = "almul"; +char aldiv[] = "aldiv"; +char alrem[] = "alrem"; +char udiv[] = "udiv"; +char urem[] = "urem"; +char jeq[] = "jeq"; +char jne[] = "jne"; +char jle[] = "jle"; +char jgt[] = "jgt"; +char jlt[] = "jlt"; +char jge[] = "jge"; +char jlos[] = "jlos"; +char jhi[] = "jhi"; +char jlo[] = "jlo"; +char jhis[] = "jhis"; +char nop[] = "/nop"; +char jbr[] = "jbr"; +char jpl[] = "jpl"; +char jmi[] = "jmi"; +char jmijne[] = "jmi\tL%d\njne"; +char jmijeq[] = "jmi\tL%d\njeq"; + +/* + * Instruction tables, accessed by + * I (first operand) or I' (second) macros. + */ + +struct instab instab[] = { + {LOAD, mov, tst}, + {ASSIGN, mov, clr}, + {EQUAL, cmp, tst}, + {NEQUAL, cmp, tst}, + {LESSEQ, cmp, tst}, + {LESS, cmp, tst}, + {GREATEQ, cmp, tst}, + {GREAT, cmp, tst}, + {LESSEQP, cmp, tst}, + {LESSP, cmp, tst}, + {GREATQP, cmp, tst}, + {GREATP, cmp, tst}, + {PLUS, add, inc}, + {ASPLUS, add, inc}, + {MINUS, sub, dec}, + {ASMINUS, sub, dec}, + {INCBEF, add, inc}, + {DECBEF, sub, dec}, + {INCAFT, add, inc}, + {DECAFT, sub, dec}, + {TIMES, mul, mul}, + {ASTIMES, mul, mul}, + {DIVIDE, _div, _div}, + {ASDIV, _div, _div}, + {MOD, _div, _div}, + {ASMOD, _div, _div}, + {PTOI, _div, _div}, + {RSHIFT, ash, asr}, + {ASRSH, ash, asr}, + {LSHIFT, ash, asl}, + {ASLSH, ash, asl}, + {AND, bic, bic1}, + {ANDN, bic, bic1}, + {ASANDN, bic, bic1}, + {TAND, bit, bit1}, + {OR, bis, bis1}, + {ASOR, bis, bis1}, + {EXOR, xor, xor}, + {ASXOR, xor, xor}, + {NEG, neg, neg}, + {COMPL, com, com}, + {CALL1, stdol, stdol}, + {CALL2, "", ""}, + {LLSHIFT, ashc, ashc}, + {ASLSHL, ashc, ashc}, + {LTIMES, slmul, slmul}, + {LDIV, sldiv, sldiv}, + {LMOD, slrem, slrem}, + {LASTIMES, almul, almul}, + {LASDIV, aldiv, aldiv}, + {LASMOD, alrem, alrem}, + {ULSH, ashc, ashc}, + {ASULSH, ashc, ashc}, + {UDIV, udiv, udiv}, + {UMOD, urem, urem}, + {ASUDIV, udiv, udiv}, + {ASUMOD, urem, urem}, + {ULTIMES, slmul, slmul}, /* symmetry */ + {ULDIV, uldiv, uldiv}, + {ULMOD, ulrem, ulrem}, + {ULASTIMES, almul, almul}, /* symmetry */ + {ULASDIV, ualdiv, ualdiv}, + {ULASMOD, ualrem, ualrem}, + {ULTOF, ultof, ultof}, + {ULLSHIFT, ulsh, ulsh}, + {UASLSHL, ualsh, ualsh}, + {0, 0, 0} +}; + +/* + * Similar table for relationals. + * The first string is for the positive + * test, the second for the inverted one. + * The '200+' entries are + * used in tests against 0 where a 'tst' + * instruction is used; it clears the c-bit + * the c-bit so ptr tests are funny. + */ +struct instab branchtab[] = { + {EQUAL, jeq, jne}, + {NEQUAL, jne, jeq}, + {LESSEQ, jle, jgt}, + {LESS, jlt, jge}, + {GREATEQ, jge, jlt}, + {GREAT, jgt, jle}, + {LESSEQP, jlos, jhi}, + {LESSP, jlo, jhis}, + {GREATQP, jhis, jlo}, + {GREATP, jhi, jlos}, + {200+EQUAL, jeq, jne}, + {200+NEQUAL, jne, jeq}, + {200+LESSEQ, jmijeq, jmijne}, + {200+LESS, jmi, jpl}, + {200+GREATEQ, jpl, jmi}, + {200+GREAT, jmijne, jmijeq}, + {200+LESSEQP, jeq, jne}, + {200+LESSP, nop, jbr}, + {200+GREATQP, jbr, nop}, + {200+GREATP, jne, jeq}, + {0, 0, 0} +}; + +int line; +int nerror; /* number of hard errors */ +struct table lsptab[1]; +int nstack; +int nfloat; +char *funcbase; +char *curbase; +char *coremax; +long totspace; +int regpanic; /* set when SU register alg. fails */ +int panicposs; /* set when there might be need for regpanic */ +jmp_buf jmpbuf; + +int xlab1, xlab2, xop, xzero; diff --git a/cvopt.c b/cvopt.c new file mode 100644 index 0000000..b7d04dd --- /dev/null +++ b/cvopt.c @@ -0,0 +1,461 @@ +#include +#include +#include + +int tabflg; +int labno = 1; +int opno; +FILE *curbuf; +FILE *obuf; +FILE *oobuf; +char oname[]="/tmp/cvoptaXXXXXX"; +char ooname[]="/tmp/cvoptbXXXXXX"; +char lbuf[BUFSIZ]; +char *lbufp = lbuf; + +#ifndef __P +#ifdef __STDC__ +#define __P(args) args +#else +#define __P(args) () +#endif +#endif + +int main __P((int argc, char **argv)); +int flag __P((void)); +void put __P((int c)); +void comment __P((int c)); + +int main(argc, argv) int argc; char **argv; { +/* + A1 -> A + A2 B + A O + B1 C + B2 D + BE L + BF P + C1 E + C2 F + F G + H H + R I + R1 J + S K + I M + M N + + * +1 + S +2 + C +4 + 1 +8 + + z -> 4 + c 10 + a 14 + e 20 + n 63 + * +0100 +*/ + + int c, snlflg, nlflg, t, smode, m, ssmode, peekc, side; +#ifndef pdp11 + int fd; +#endif + + smode = nlflg = snlflg = ssmode = 0; + if (argc>1) + if (freopen(argv[1], "r", stdin) == NULL) { + fprintf(stderr, "%s?\n", argv[1]); + return(1); + } + if (argc>2) + if (freopen(argv[2], "w", stdout) == NULL) { + fprintf(stderr, "%s?\n", argv[2]); + return(1); + } +#ifdef pdp11 + mktemp(oname); + if ((obuf = fopen(oname, "w")) == NULL) { + fprintf(stderr, "%s?\n", oname); + exit(1); + } + mktemp(ooname); + if ((oobuf = fopen(ooname, "w")) == NULL) { + fprintf(stderr, "%s?\n", ooname); + exit(1); + } +#else + fd = mkstemp(oname); + if (fd < 0 || (obuf = fdopen(fd, "w")) == NULL) { + fprintf(stderr, "%s?\n", oname); + exit(1); + } + fd = mkstemp(ooname); + if (fd < 0 || (oobuf = fdopen(fd, "w")) == NULL) { + fprintf(stderr, "%s?\n", ooname); + exit(1); + } +#endif + printf("#include \"c1.h\""); + curbuf = obuf; +loop: + c = getchar(); + if (c!='\n' && c!='\t') + nlflg = 0; + if (ssmode!=0 && c!='%') { + ssmode = 0; + curbuf = stdout; + fprintf(curbuf, "\nstatic char L%d[]=\"", labno++); + } + switch(c) { + + case EOF: + fprintf(obuf, "\t{0},\n};\n"); + fclose(obuf); + if (freopen(oname, "r", stdin) == NULL) { + fprintf(stderr, "%s?\n",oname); + exit(1); + } + while ((c = getchar()) != EOF) + putchar(c); + unlink(oname); + fclose(oobuf); + if (freopen(ooname, "r", stdin) == NULL) { + fprintf(stderr, "%s?\n",ooname); + exit(1); + } + while ((c = getchar()) != EOF) + putchar(c); + unlink(ooname); + return(0); + + case 'A': + if ((c=getchar())=='1' || c=='2') { + put(c+'A'-'1'); + goto loop; + } + put('O'); + ungetc(c, stdin); + goto loop; + + case 'B': + switch (getchar()) { + + case '1': + put('C'); + goto loop; + + case '2': + put('D'); + goto loop; + + case 'E': + put('L'); + goto loop; + + case 'F': + put('P'); + goto loop; + } + put('?'); + goto loop; + + case 'C': + put(getchar()+'E'-'1'); + goto loop; + + case 'F': + put('G'); + goto subtre; + + case 'R': + if ((c=getchar()) == '1') + put('J'); else { + put('I'); + ungetc(c, stdin); + } + goto loop; + + case 'H': + put('H'); + goto subtre; + + case 'I': + put('M'); + goto loop; + + case 'S': + put('K'); +subtre: + snlflg = 1; + t = 'A'; +l1: + switch (c=getchar()) { + + case '*': + t++; + goto l1; + + case 'S': + t += 2; + goto l1; + + case 'C': + t += 4; + goto l1; + + case '1': + t += 8; + goto l1; + + case '2': + t += 16; + goto l1; + } + ungetc(c, stdin); + put(t); + goto loop; + + case '#': + if(getchar()=='1') + put('#'); else + put('"'); + goto loop; + + case '%': + if (smode) + curbuf = obuf; + if (ssmode==0) { + if ((peekc=getchar())=='[') { + printf("\n#define "); + while((c=getchar())!=']' && c!=':') + putchar(c); + printf(" L%d\n",labno); + if (c==':') getchar(); + getchar(); + curbuf = obuf; + goto loop; + } + ungetc(peekc, stdin); + } + side=0; +loop1: + switch (c=getchar()) { + + case ' ': + case '\t': + goto loop1; + case 'a': + m = 16; + t = flag(); + goto pf; + + case ',': + side=1; + goto loop1; + + case 'i': + m = 12; + t = flag(); + goto pf; + case 'z': + m = 4; + t = flag(); + goto pf; + + case 'r': + m = 9; + t = flag(); + goto pf; + + case '1': + m = 5; + t = flag(); + goto pf; + + case 'c': + t = 0; + m = 8; + goto pf; + + case 'e': + t = flag(); + m = 20; + goto pf; + + case 'n': + t = flag(); + m = 63; +pf: + if ((c=getchar())=='*') + m += 0100; else + ungetc(c, stdin); + if (side==0) { + if (opno==0) fprintf(curbuf,"\nstruct optab optab[]={\n"); + fprintf(curbuf,"\t{"); + } + fprintf(curbuf, "%d,%d,", m, t); + goto loop1; + case '[': + printf("\n#define L%d ", labno++); + while ((c=getchar())!=']') + putchar(c); + printf("\n"); + ssmode = 0; + smode = 0; + goto loop; + + case '{': + for(;;) { + while ((c=getchar())!='%') putc(c,oobuf); + if ((c=getchar())=='}') goto loop; + else {putc('%',oobuf); putc(c,oobuf);} + } + + case '\n': + fprintf(curbuf, "L%d}, /* %d */\n", labno,opno); + ++opno; + ssmode = 1; + nlflg = 1; + smode = 1; + goto loop; + + case '/': + comment(c); goto loop1; + + } + put(c); + goto loop1; + + case '\t': + if (nlflg) { + nlflg = 0; + goto loop; + } + if (smode) { + tabflg++; + goto loop; + } + put('\t'); + goto loop; + + case '\n': + lbufp=lbuf; + if (!smode) { + put('\n'); + goto loop; + } + if (nlflg) { + nlflg = 0; + fprintf(curbuf, "\";"); + curbuf = obuf; + smode = 0; + goto loop; + } + if (!snlflg) + fprintf(curbuf, "\\n"); + snlflg = 0; + nlflg = 1; + goto loop; + + case '/': + comment(c); goto loop; + + case 'X': + case 'Y': + case 'T': + snlflg++; + break; + + case ':': + fseek(curbuf,(long)(lbuf-lbufp),2); + *lbufp='\0'; + if (opno!=0) {fprintf(curbuf,"\t{0},\n"); ++opno;} + printf("\n#define %s &optab[%d]\n",lbuf,opno); + fprintf(curbuf,"/* %s */",lbuf); + lbufp=lbuf; + goto loop; + + } + *lbufp++=c; + put(c); + goto loop; +} + +int flag() { + register int c, f; + + f = 0; +l1: + switch(c=getchar()) { + + case 'w': + f = 1; + goto l1; + + case 'i': + f = 2; + goto l1; + + case 'b': + if (f==9) /* unsigned word/int seen yet? */ + f = 10; /* yes - it is unsigned byte */ + else + f = 3; /* no - it is regular (signed) byte */ + goto l1; + + case 'f': + f = 4; + goto l1; + + case 'd': + f = 5; + goto l1; + + case 'u': + if (f==3) /* regular (signed) byte seen ? */ + f = 10; /* yes - unsigned byte now */ + else if (f == 8) /* regular (signed) long seen? */ + f = 11; /* yes - it is unsigned long now */ + else + f = 9; /* otherwise we have unsigned word */ + goto l1; + + case 's': + f = 6; + goto l1; + + case 'l': + if (f == 9) /* seen unsigned yet? */ + f = 11; /* yes - it is unsigned long now */ + else + f = 8; /* no - it is unsigned word now */ + goto l1; + + case 'p': + f += 16; + goto l1; + } + ungetc(c, stdin); + return(f); +} + +void put(c) int c; { + if (tabflg) { + tabflg = 0; + fprintf(curbuf, "\\%o", c+0200); + } else { + if (c=='"') putc('\\',curbuf); + putc(c, curbuf); + } +} + +void comment(c) int c; { + putc(c,curbuf); + if ((c=getchar())=='*') for (;;) { + do putc(c,curbuf); while ((c=getchar())!='*'); + putc(c,curbuf); + if ((c=getchar())=='/') {putc(c,curbuf); break;} + } else ungetc(c,stdin); +} diff --git a/fp.c b/fp.c new file mode 100644 index 0000000..241b733 --- /dev/null +++ b/fp.c @@ -0,0 +1,681 @@ +#ifndef pdp11 +#include +#include +#include "c1.h" + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 1 +#endif + +/* Floating point accumulators */ + +#if 0 +/* PSW */ + +#define PSW_V_C 0 /* condition codes */ +#define PSW_V_V 1 +#define PSW_V_Z 2 +#define PSW_V_N 3 +#endif + +/* FPS */ + +#define FPS_V_C 0 /* condition codes */ +#define FPS_V_V 1 +#define FPS_V_Z 2 +#define FPS_V_N 3 +#define FPS_V_T 5 /* truncate */ +#define FPS_V_L 6 /* long */ +#define FPS_V_D 7 /* double */ +#define FPS_V_IC 8 /* ic err int */ +#define FPS_V_IV 9 /* overflo err int */ +#define FPS_V_IU 10 /* underflo err int */ +#define FPS_V_IUV 11 /* undef var err int */ +#define FPS_V_ID 14 /* int disable */ +#define FPS_V_ER 15 /* error */ + +/* Floating point status register */ + +#define FPS_ER (1u << FPS_V_ER) /* error */ +#define FPS_ID (1u << FPS_V_ID) /* interrupt disable */ +#define FPS_IUV (1u << FPS_V_IUV) /* int on undef var */ +#define FPS_IU (1u << FPS_V_IU) /* int on underflow */ +#define FPS_IV (1u << FPS_V_IV) /* int on overflow */ +#define FPS_IC (1u << FPS_V_IC) /* int on conv error */ +#define FPS_D (1u << FPS_V_D) /* single/double */ +#define FPS_L (1u << FPS_V_L) /* word/long */ +#define FPS_T (1u << FPS_V_T) /* round/truncate */ +#define FPS_N (1u << FPS_V_N) +#define FPS_Z (1u << FPS_V_Z) +#define FPS_V (1u << FPS_V_V) +#define FPS_C (1u << FPS_V_C) +#define FPS_CC (FPS_N + FPS_Z + FPS_V + FPS_C) +#define FPS_RW (FPS_ER + FPS_ID + FPS_IUV + FPS_IU + FPS_IV + \ + FPS_IC + FPS_D + FPS_L + FPS_T + FPS_CC) + +/* Floating point exception codes */ + +#define FEC_OP 2 /* illegal op/mode */ +#define FEC_DZRO 4 /* divide by zero */ +#define FEC_ICVT 6 /* conversion error */ +#define FEC_OVFLO 8 /* overflow */ +#define FEC_UNFLO 10 /* underflow */ +#define FEC_UNDFV 12 /* undef variable */ + +/* Floating point format, all assignments 32b relative */ + +#define FP_V_SIGN (63 - 32) /* high lw: sign */ +#define FP_V_EXP (55 - 32) /* exponent */ +#define FP_V_HB FP_V_EXP /* hidden bit */ +#define FP_V_F0 (48 - 32) /* fraction 0 */ +#define FP_V_F1 (32 - 32) /* fraction 1 */ +#define FP_V_FROUND (31 - 32) /* f round point */ +#define FP_V_F2 16 /* low lw: fraction 2 */ +#define FP_V_F3 0 /* fraction 3 */ +#define FP_V_DROUND (-1) /* d round point */ +#define FP_M_EXP 0377 +#define FP_SIGN (1u << FP_V_SIGN) +#define FP_EXP (FP_M_EXP << FP_V_EXP) +#define FP_HB (1u << FP_V_HB) +#define FP_FRACH ((1u << FP_V_HB) - 1) +#define FP_FRACL 0xFFFFFFFF +#define FP_BIAS 0200 /* exponent bias */ +#define FP_GUARD 3 /* guard bits */ + +#if 0 +/* Data lengths */ + +#define _WORD 2 +#define _LONG 4 +#define _QUAD 8 +#endif + +/* Double precision operations on 64b quantities */ + +#define F_LOAD(qd,ac,ds) ds.h = ac.h; ds.l = (qd)? ac.l: 0 +#define F_LOAD_P(qd,ac,ds) ds->h = ac.h; ds->l = (qd)? ac.l: 0 +#define F_LOAD_FRAC(qd,ac,ds) ds.h = (ac.h & FP_FRACH) | FP_HB; \ + ds.l = (qd)? ac.l: 0 +#define F_STORE(qd,sr,ac) ac.h = sr.h; if ((qd)) ac.l = sr.l +#define F_STORE_P(qd,sr,ac) ac.h = sr->h; if ((qd)) ac.l = sr->l +#define F_GET_FRAC_P(sr,ds) ds.l = sr->l; \ + ds.h = (sr->h & FP_FRACH) | FP_HB +#define F_ADD(s2,s1,ds) ds.l = (s1.l + s2.l) & 0xFFFFFFFF; \ + ds.h = (s1.h + s2.h + (ds.l < s2.l)) & 0xFFFFFFFF +#define F_SUB(s2,s1,ds) ds.h = (s1.h - s2.h - (s1.l < s2.l)) & 0xFFFFFFFF; \ + ds.l = (s1.l - s2.l) & 0xFFFFFFFF +#define F_LT(x,y) ((x.h < y.h) || ((x.h == y.h) && (x.l < y.l))) +#define F_LT_AP(x,y) (((x->h & ~FP_SIGN) < (y->h & ~FP_SIGN)) || \ + (((x->h & ~FP_SIGN) == (y->h & ~FP_SIGN)) && (x->l < y->l))) +#define F_LSH_V(sr,n,ds) \ + ds.h = (((n) >= 32)? (sr.l << ((n) - 32)): \ + (sr.h << (n)) | ((sr.l >> (32 - (n))) & and_mask[n])) \ + & 0xFFFFFFFF; \ + ds.l = ((n) >= 32)? 0: (sr.l << (n)) & 0xFFFFFFFF +#define F_RSH_V(sr,n,ds) \ + ds.l = (((n) >= 32)? (sr.h >> ((n) - 32)) & and_mask[64 - (n)]: \ + ((sr.l >> (n)) & and_mask[32 - (n)]) | \ + (sr.h << (32 - (n)))) & 0xFFFFFFFF; \ + ds.h = ((n) >= 32)? 0: \ + ((sr.h >> (n)) & and_mask[32 - (n)]) & 0xFFFFFFFF + +/* For the constant shift macro, arguments must in the range [2,31] */ + +#define F_LSH_1(ds) ds.h = ((ds.h << 1) | ((ds.l >> 31) & 1)) & 0xFFFFFFFF; \ + ds.l = (ds.l << 1) & 0xFFFFFFFF +#define F_RSH_1(ds) ds.l = ((ds.l >> 1) & 0x7FFFFFFF) | ((ds.h & 1) << 31); \ + ds.h = ((ds.h >> 1) & 0x7FFFFFFF) +#define F_LSH_K(sr,n,ds) \ + ds.h = ((sr.h << (n)) | ((sr.l >> (32 - (n))) & and_mask[n])) \ + & 0xFFFFFFFF; \ + ds.l = (sr.l << (n)) & 0xFFFFFFFF +#define F_RSH_K(sr,n,ds) \ + ds.l = (((sr.l >> (n)) & and_mask[32 - (n)]) | \ + (sr.h << (32 - (n)))) & 0xFFFFFFFF; \ + ds.h = ((sr.h >> (n)) & and_mask[32 - (n)]) & 0xFFFFFFFF +#define F_LSH_GUARD(ds) F_LSH_K(ds,FP_GUARD,ds) +#define F_RSH_GUARD(ds) F_RSH_K(ds,FP_GUARD,ds) + +#define GET_BIT(ir,n) (((ir) >> (n)) & 1) +#define GET_SIGN(ir) GET_BIT((ir), FP_V_SIGN) +#define GET_EXP(ir) (((ir) >> FP_V_EXP) & FP_M_EXP) +#define GET_SIGN_L(ir) GET_BIT((ir), 31) +#define GET_SIGN_W(ir) GET_BIT((ir), 15) + +int32_t FEC = 0; +int32_t FPS = FPS_D; /* default to double precision */ + +_DOUBLE zero_fac = { 0, 0 }; +_DOUBLE one_fac = { 1, 0 }; +_DOUBLE fround_fac = { (1u << (FP_V_FROUND + 32)), 0 }; +_DOUBLE fround_guard_fac = { 0, (1u << (FP_V_FROUND + FP_GUARD)) }; +_DOUBLE dround_guard_fac = { (1u << (FP_V_DROUND + FP_GUARD)), 0 }; +_DOUBLE fmask_fac = { 0xFFFFFFFF, (1u << (FP_V_HB + FP_GUARD + 1)) - 1 }; +static const uint32_t and_mask[33] = { 0, + 0x1, 0x3, 0x7, 0xF, + 0x1F, 0x3F, 0x7F, 0xFF, + 0x1FF, 0x3FF, 0x7FF, 0xFFF, + 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, + 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF, + 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, + 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, + 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF }; + +#ifndef __P +#ifdef __STDC__ +#define __P(params) params +#else +#define __P(params) () +#endif +#endif + +static void tstfp11 __P((_DOUBLE *fsrc)); +static void absfp11 __P((_DOUBLE *fsrc)); +static void negfp11 __P((_DOUBLE *fsrc)); +static void cmpfp11 __P((_DOUBLE *fac, _DOUBLE *fsrc)); +static int32_t moviefp11 __P((int32_t val, _DOUBLE *fac)); +static int32_t moveifp11 __P((_DOUBLE *val)); +static int32_t moviffp11 __P((int32_t val, _DOUBLE *fac)); +static int32_t movfifp11 __P((_DOUBLE *val, int32_t *dst)); +static int32_t addfp11 __P((_DOUBLE *facp, _DOUBLE *fsrcp)); +static int32_t mulfp11 __P((_DOUBLE *facp, _DOUBLE *fsrcp)); +static void frac_mulfp11 __P((_DOUBLE *f1p, _DOUBLE *f2p)); +static int32_t divfp11 __P((_DOUBLE *facp, _DOUBLE *fsrcp)); +static int32_t roundfp11 __P((_DOUBLE *fptr)); +static int32_t round_and_pack __P((_DOUBLE *facp, int32_t exp, _DOUBLE *fracp, int r)); +static int32_t fpnotrap __P((int32_t code)); + +int fp_tst(val) _DOUBLE val; { + tstfp11(&val); + return (FPS & FPS_Z) != 0; +} + +_DOUBLE fp_abs(val) _DOUBLE val; { + absfp11(&val); + return val; +} + +_DOUBLE fp_neg(val) _DOUBLE val; { + negfp11(&val); + return val; +} + +int fp_le(val0, val1) _DOUBLE val0; _DOUBLE val1; { + cmpfp11(&val0, &val1); + return (FPS & FPS_N) == 0; +} + +int fp_ge(val0, val1) _DOUBLE val0; _DOUBLE val1; { + cmpfp11(&val1, &val0); + return (FPS & FPS_N) == 0; +} + +int fp_gt(val0, val1) _DOUBLE val0; _DOUBLE val1; { + cmpfp11(&val0, &val1); + return (FPS & FPS_N) != 0; +} + +int fp_lt(val0, val1) _DOUBLE val0; _DOUBLE val1; { + cmpfp11(&val1, &val0); + return (FPS & FPS_N) != 0; +} + +_INT fp_double_to_int(val) _DOUBLE val; { + int32_t res; + + if (movfifp11(&val, &res)) + abort(); + return (_INT)res; +} + +_LONG fp_double_to_long(val) _DOUBLE val; { + int32_t res; + + FPS |= FPS_L; + if (movfifp11(&val, &res)) + abort(); + FPS &= ~FPS_L; + return (_LONG)res; +} + +_FLOAT fp_double_to_float(val) _DOUBLE val; { + _FLOAT res; + + if (roundfp11(&val)) + abort(); + res.h = val.h; + return res; +} + +_DOUBLE fp_int_to_double(val) _INT val; { + _DOUBLE res; + + if (moviffp11((int32_t)val << 16, &res)) + abort(); + return res; +} + +_DOUBLE fp_long_to_double(val) _LONG val; { + _DOUBLE res; + + FPS |= FPS_L; + if (moviffp11((int32_t)val, &res)) + abort(); + FPS &= ~FPS_L; + return res; +} + +_DOUBLE fp_float_to_double(val) _FLOAT val; { + _DOUBLE res; + + res.h = val.h; + res.l = 0; + return res; +} + +_DOUBLE fp_add(val0, val1) _DOUBLE val0; _DOUBLE val1; { + if (addfp11(&val0, &val1)) + abort(); + return val0; +} + +_DOUBLE fp_sub(val0, val1) _DOUBLE val0; _DOUBLE val1; { + negfp11(&val1); + if (addfp11(&val0, &val1)) + abort(); + return val0; +} + +_DOUBLE fp_mul(val0, val1) _DOUBLE val0; _DOUBLE val1; { + if (mulfp11(&val0, &val1)) + abort(); + return val0; +} + +_DOUBLE fp_div(val0, val1) _DOUBLE val0; _DOUBLE val1; { + if (divfp11(&val0, &val1)) + abort(); + return val0; +} + +_DOUBLE fp_ldexp(val, exp) _DOUBLE val; _INT exp; { + tstfp11(&val); + if ((FPS & FPS_Z) == 0 && moviefp11(moveifp11(&val) + (int32_t)exp, &val)) { + val.l = 0xFFFFFFFF; + val.h = ((FPS << (31 - FPS_V_N)) | 0x7FFFFFFF) & 0xFFFFFFFF; + errno = ERANGE; + } + return val; +} + +/* cut-down routines by Nick, previously inline to instruction decode */ +static void tstfp11(fsrc) _DOUBLE *fsrc; { + FPS = FPS & ~FPS_CC; + if (GET_SIGN (fsrc->h)) FPS = FPS | FPS_N; + if (GET_EXP (fsrc->h) == 0) FPS = FPS | FPS_Z; +} + +static void absfp11(fsrc) _DOUBLE *fsrc; { + if (GET_EXP (fsrc->h) == 0) *fsrc = zero_fac; + else fsrc->h = fsrc->h & ~FP_SIGN; +} + +static void negfp11(fsrc) _DOUBLE *fsrc; { + if (GET_EXP (fsrc->h) == 0) *fsrc = zero_fac; + else fsrc->h = fsrc->h ^ FP_SIGN; +} + +/* from PDP-11/70 processor manual: + * FC <- 0. + * FV <- 0. + * FZ <- 1 If (FSRC) - (AC) = 0, else FZ <- 0. + * FN <- 1 If (FSRC) - (AC) < 0, else FN <- 0. + * (backwards compared to what I expected) + */ +static void cmpfp11(fac, fsrc) _DOUBLE *fac; _DOUBLE *fsrc; { + if (GET_EXP (fsrc->h) == 0) *fsrc = zero_fac; + if (GET_EXP (fac->h) == 0) *fac = zero_fac; + if ((fsrc->h == fac->h) && (fsrc->l == fac->l)) { /* equal? */ + FPS = (FPS & ~FPS_CC) | FPS_Z; + return; } + FPS = (FPS & ~FPS_CC) | ((fsrc->h >> (FP_V_SIGN - FPS_V_N)) & FPS_N); + if ((GET_SIGN (fsrc->h ^ fac->h) == 0) && (fac->h != 0) && + F_LT ((*fsrc), (*fac))) FPS = FPS ^ FPS_N; +} + +static int32_t moviefp11(val, fac) int32_t val; _DOUBLE *fac; { + fac->h = (fac->h & ~FP_EXP) | (((val + FP_BIAS) & FP_M_EXP) << FP_V_EXP); + if ((val > 0177) && (val <= 0177600)) { + if (val < 0100000) { + if (fpnotrap (FEC_OVFLO)) *fac = zero_fac; + return FPS_V; } + if (fpnotrap (FEC_UNFLO)) *fac = zero_fac; } + return 0; +} + +static int32_t moveifp11(val) _DOUBLE *val; { + return (GET_EXP (val->h) - FP_BIAS) & 0177777; +} + +static int32_t moviffp11(val, fac) int32_t val; _DOUBLE *fac; { + int32_t i, qdouble, leni; + int32_t exp, sign; + + qdouble = FPS & FPS_D; + fac->l = val; + fac->h = 0; + if (fac->l) { + if (sign = GET_SIGN_L (fac->l)) fac->l = (fac->l ^ 0xFFFFFFFF) + 1; + for (i = 0; GET_SIGN_L (fac->l) == 0; i++) fac->l = fac->l << 1; + exp = ((FPS & FPS_L)? FP_BIAS + 32: FP_BIAS + 16) - i; + fac->h = (sign << FP_V_SIGN) | (exp << FP_V_EXP) | + ((fac->l >> (31 - FP_V_HB)) & FP_FRACH); + fac->l = (fac->l << (FP_V_HB + 1)) & FP_FRACL; + if ((FPS & (FPS_D + FPS_T)) == 0) return roundfp11 (fac); } + return 0; +} + +static int32_t movfifp11(val, dst) _DOUBLE *val; int32_t *dst; { + int32_t i, qdouble, tolong; + int32_t exp, sign; + _DOUBLE fac, fsrc; + static const uint32_t i_limit[2][2] = + { { 0x80000000, 0x80010000 }, { 0x80000000, 0x80000001 } }; + + qdouble = FPS & FPS_D; + sign = GET_SIGN (val->h); /* get sign, */ + exp = GET_EXP (val->h); /* exponent, */ + F_LOAD_FRAC (qdouble, (*val), fac); /* fraction */ + if (FPS & FPS_L) { + tolong = 1; + i = FP_BIAS + 32; } + else { + tolong = 0; + i = FP_BIAS + 16; } + if (exp <= FP_BIAS) *dst = 0; + else if (exp > i) { + *dst = 0; + fpnotrap (FEC_ICVT); + return FPS_V; } + F_RSH_V (fac, FP_V_HB + 1 + i - exp, fsrc); + if (!tolong) fsrc.l = fsrc.l & ~0177777; + if (fsrc.l >= i_limit[tolong][sign]) { + *dst = 0; + fpnotrap (FEC_ICVT); + return FPS_V; } + *dst = fsrc.l; + if (sign) *dst = -*dst; + return 0; +} + +/* Floating point add + + Inputs: + facp = pointer to src1 (output) + fsrcp = pointer to src2 + Outputs: + ovflo = overflow variable +*/ + +static int32_t addfp11(facp, fsrcp) _DOUBLE *facp; _DOUBLE *fsrcp; { +int32_t facexp, fsrcexp, ediff; +_DOUBLE facfrac, fsrcfrac; + +if (F_LT_AP (facp, fsrcp)) { /* if !fac! < !fsrc! */ + facfrac = *facp; + *facp = *fsrcp; /* swap operands */ + *fsrcp = facfrac; } +facexp = GET_EXP (facp->h); /* get exponents */ +fsrcexp = GET_EXP (fsrcp->h); +if (facexp == 0) { /* fac = 0? */ + *facp = fsrcexp? *fsrcp: zero_fac; /* result fsrc or 0 */ + return 0; } +if (fsrcexp == 0) return 0; /* fsrc = 0? no op */ +ediff = facexp - fsrcexp; /* exponent diff */ +if (ediff >= 60) return 0; /* too big? no op */ +F_GET_FRAC_P (facp, facfrac); /* get fractions */ +F_GET_FRAC_P (fsrcp, fsrcfrac); +F_LSH_GUARD (facfrac); /* guard fractions */ +F_LSH_GUARD (fsrcfrac); +if (GET_SIGN (facp->h) != GET_SIGN (fsrcp->h)) { /* signs different? */ + if (ediff) { F_RSH_V (fsrcfrac, ediff, fsrcfrac); } /* sub, shf fsrc */ + F_SUB (fsrcfrac, facfrac, facfrac); /* sub fsrc from fac */ + if ((facfrac.h | facfrac.l) == 0) { /* result zero? */ + *facp = zero_fac; /* no overflow */ + return 0; } + if (ediff <= 1) { /* big normalize? */ + if ((facfrac.h & (0x00FFFFFF << FP_GUARD)) == 0) { + F_LSH_K (facfrac, 24, facfrac); + facexp = facexp - 24; } + if ((facfrac.h & (0x00FFF000 << FP_GUARD)) == 0) { + F_LSH_K (facfrac, 12, facfrac); + facexp = facexp - 12; } + if ((facfrac.h & (0x00FC0000 << FP_GUARD)) == 0) { + F_LSH_K (facfrac, 6, facfrac); + facexp = facexp - 6; } } + while (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD) == 0) { + F_LSH_1 (facfrac); + facexp = facexp - 1; } } +else { if (ediff) { F_RSH_V (fsrcfrac, ediff, fsrcfrac); } /* add, shf fsrc */ + F_ADD (fsrcfrac, facfrac, facfrac); /* add fsrc to fac */ + if (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD + 1)) { + F_RSH_1 (facfrac); /* carry out, shift */ + facexp = facexp + 1; } } +return round_and_pack (facp, facexp, &facfrac, 1); +} + +/* Floating point multiply + + Inputs: + facp = pointer to src1 (output) + fsrcp = pointer to src2 + Outputs: + ovflo = overflow indicator +*/ + +static int32_t mulfp11(facp, fsrcp) _DOUBLE *facp; _DOUBLE *fsrcp; { +int32_t facexp, fsrcexp; +_DOUBLE facfrac, fsrcfrac; + +facexp = GET_EXP (facp->h); /* get exponents */ +fsrcexp = GET_EXP (fsrcp->h); +if ((facexp == 0) || (fsrcexp == 0)) { /* test for zero */ + *facp = zero_fac; + return 0; } +F_GET_FRAC_P (facp, facfrac); /* get fractions */ +F_GET_FRAC_P (fsrcp, fsrcfrac); +facexp = facexp + fsrcexp - FP_BIAS; /* calculate exp */ +facp->h = facp->h ^ fsrcp->h; /* calculate sign */ +frac_mulfp11 (&facfrac, &fsrcfrac); /* multiply fracs */ + +/* Multiplying two numbers in the range [.5,1) produces a result in the + range [.25,1). Therefore, at most one bit of normalization is required + to bring the result back to the range [.5,1). +*/ + +if (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD) == 0) { + F_LSH_1 (facfrac); + facexp = facexp - 1; } +return round_and_pack (facp, facexp, &facfrac, 1); +} + +/* Fraction multiply + + Inputs: + f1p = pointer to multiplier (output) + f2p = pointer to multiplicand fraction + + Note: the inputs are unguarded; the output is guarded. + + This routine performs a classic shift-and-add multiply. The low + order bit of the multiplier is tested; if 1, the multiplicand is + added into the high part of the double precision result. The + result and the multiplier are both shifted right 1. + + For the 24b x 24b case, this routine develops 48b of result. + For the 56b x 56b case, this routine only develops the top 64b + of the the result. Because the inputs are normalized fractions, + the interesting part of the result is the high 56+guard bits. + Everything shifted off to the right, beyond 64b, plays no part + in rounding or the result. + + There are many possible optimizations in this routine: scanning + for groups of zeroes, particularly in the 56b x 56b case; using + "extended multiply" capability if available in the hardware. +*/ + +static void frac_mulfp11(f1p, f2p) _DOUBLE *f1p; _DOUBLE *f2p; { +_DOUBLE result, mpy, mpc; +int32_t i; + +result = zero_fac; /* clear result */ +mpy = *f1p; /* get operands */ +mpc = *f2p; +F_LSH_GUARD (mpc); /* guard multipicand */ +if ((mpy.l | mpc.l) == 0) { /* 24b x 24b? */ + for (i = 0; i < 24; i++) { + if (mpy.h & 1) result.h = result.h + mpc.h; + F_RSH_1 (result); + mpy.h = mpy.h >> 1; } } +else { if (mpy.l != 0) { /* 24b x 56b? */ + for (i = 0; i < 32; i++) { + if (mpy.l & 1) { F_ADD (mpc, result, result); } + F_RSH_1 (result); + mpy.l = mpy.l >> 1; } } + for (i = 0; i < 24; i++) { + if (mpy.h & 1) { F_ADD (mpc, result, result); } + F_RSH_1 (result); + mpy.h = mpy.h >> 1; } } +*f1p = result; +return; +} + +/* Floating point divide + + Inputs: + facp = pointer to dividend (output) + fsrcp = pointer to divisor + Outputs: + ovflo = overflow indicator + + Source operand must be checked for zero by caller! +*/ + +static int32_t divfp11(facp, fsrcp) _DOUBLE *facp; _DOUBLE *fsrcp; { +int32_t facexp, fsrcexp, i, count, qd; +_DOUBLE facfrac, fsrcfrac, quo; + +fsrcexp = GET_EXP (fsrcp->h); /* get divisor exp */ +facexp = GET_EXP (facp->h); /* get dividend exp */ +if (facexp == 0) { /* test for zero */ + *facp = zero_fac; /* result zero */ + return 0; } +F_GET_FRAC_P (facp, facfrac); /* get fractions */ +F_GET_FRAC_P (fsrcp, fsrcfrac); +F_LSH_GUARD (facfrac); /* guard fractions */ +F_LSH_GUARD (fsrcfrac); +facexp = facexp - fsrcexp + FP_BIAS + 1; /* calculate exp */ +facp->h = facp->h ^ fsrcp->h; /* calculate sign */ +qd = FPS & FPS_D; +count = FP_V_HB + FP_GUARD + (qd? 33: 1); /* count = 56b/24b */ + +quo = zero_fac; +for (i = count; (i > 0) && ((facfrac.h | facfrac.l) != 0); i--) { + F_LSH_1 (quo); /* shift quotient */ + if (!F_LT (facfrac, fsrcfrac)) { /* divd >= divr? */ + F_SUB (fsrcfrac, facfrac, facfrac); /* divd - divr */ + if (qd) quo.l = quo.l | 1; /* double or single? */ + else quo.h = quo.h | 1; } + F_LSH_1 (facfrac); } /* shift divd */ +if (i > 0) { F_LSH_V (quo, i, quo); } /* early exit? */ + +/* Dividing two numbers in the range [.5,1) produces a result in the + range [.5,2). Therefore, at most one bit of normalization is required + to bring the result back to the range [.5,1). The choice of counts + and quotient bit positions makes this work correctly. +*/ + +if (GET_BIT (quo.h, FP_V_HB + FP_GUARD) == 0) { + F_LSH_1 (quo); + facexp = facexp - 1; } +return round_and_pack (facp, facexp, &quo, 1); +} + +/* Round (in place) floating point number to f_floating + + Inputs: + fptr = pointer to floating number + Outputs: + ovflow = overflow +*/ + +static int32_t roundfp11(fptr) _DOUBLE *fptr; { +_DOUBLE outf; + +outf = *fptr; /* get argument */ +F_ADD (fround_fac, outf, outf); /* round */ +if (GET_SIGN (outf.h ^ fptr->h)) { /* flipped sign? */ + outf.h = (outf.h ^ FP_SIGN) & 0xFFFFFFFF; /* restore sign */ + if (fpnotrap (FEC_OVFLO)) *fptr = zero_fac; /* if no int, clear */ + else *fptr = outf; /* return rounded */ + return FPS_V; } /* overflow */ +else { *fptr = outf; /* round was ok */ + return 0; } /* no overflow */ +} + +/* Round result of calculation, test overflow, pack + + Input: + facp = pointer to result, sign in place + exp = result exponent, right justified + fracp = pointer to result fraction, right justified with + guard bits + r = round (1) or truncate (0) + Outputs: + ovflo = overflow indicator +*/ + +static int32_t round_and_pack(facp, exp, fracp, r) _DOUBLE *facp; int32_t exp; _DOUBLE *fracp; int r; { +_DOUBLE frac; + +frac = *fracp; /* get fraction */ +if (r && ((FPS & FPS_T) == 0)) { + if (FPS & FPS_D) { F_ADD (dround_guard_fac, frac, frac); } + else { F_ADD (fround_guard_fac, frac, frac); } + if (GET_BIT (frac.h, FP_V_HB + FP_GUARD + 1)) { + F_RSH_1 (frac); + exp = exp + 1; } } +F_RSH_GUARD (frac); +facp->l = frac.l & FP_FRACL; +facp->h = (facp->h & FP_SIGN) | ((exp & FP_M_EXP) << FP_V_EXP) | + (frac.h & FP_FRACH); +if (exp > 0377) { + if (fpnotrap (FEC_OVFLO)) *facp = zero_fac; + return FPS_V; } +if ((exp <= 0) && (fpnotrap (FEC_UNFLO))) *facp = zero_fac; +return 0; +} + +/* Process floating point exception + + Inputs: + code = exception code + Outputs: + int = FALSE if interrupt enabled, TRUE if disabled +*/ + +static int32_t fpnotrap(code) int32_t code; { +static const int32_t test_code[] = { 0, 0, 0, FPS_IC, FPS_IV, FPS_IU, FPS_IUV }; + +if ((code >= FEC_ICVT) && (code <= FEC_UNDFV) && + ((FPS & test_code[code >> 1]) == 0)) return TRUE; +FPS = FPS | FPS_ER; +FEC = code; +/*FEA = (backup_PC - 2) & 0177777;*/ +/*if ((FPS & FPS_ID) == 0) setTRAP (TRAP_FPE);*/ +return FALSE; +} +#endif diff --git a/fp_atof.c b/fp_atof.c new file mode 100644 index 0000000..c0b1e83 --- /dev/null +++ b/fp_atof.c @@ -0,0 +1,111 @@ +#ifndef pdp11 +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)atof.c 2.2 (Berkeley) 1/22/87"; +#endif + +/* + * C library - ascii to floating + */ + +#include +#include "c1.h" + +/*#define HUGE 1.701411733192644270e38*/ +#define LOGHUGE 39 + +_DOUBLE fp_atof(p) register char *p; { + register int c; + _DOUBLE fl, flexp, exp5; + _DOUBLE big = { 0, 056200 << 16 }; /*= 72057594037927936.;*/ /*2^56*/ + _DOUBLE ten = { 0, 041040 << 16 }; /*= 10.;*/ + /*_DOUBLE fp_ldexp();*/ + int nd; + register int eexp, exp, neg, negexp, bexp; + + neg = 1; + while((c = *p++) == ' ') + ; + if (c == '-') + neg = -1; + else if (c=='+') + ; + else + --p; + + exp = 0; + /*fl = 0;*/ fl.l = 0; fl.h = 0; + nd = 0; + while ((c = *p++), isdigit(c)) { + if (fp_lt(fl, big)) + fl = fp_add(fp_mul(ten, fl), fp_int_to_double(c-'0')); + else + exp++; + nd++; + } + + if (c == '.') { + while ((c = *p++), isdigit(c)) { + if (fp_lt(fl, big)) { + fl = fp_add(fp_mul(ten, fl), fp_int_to_double(c-'0')); + exp--; + } + nd++; + } + } + + negexp = 1; + eexp = 0; + if ((c == 'E') || (c == 'e')) { + if ((c= *p++) == '+') + ; + else if (c=='-') + negexp = -1; + else + --p; + + while ((c = *p++), isdigit(c)) { + eexp = 10*eexp+(c-'0'); + } + if (negexp<0) + eexp = -eexp; + exp = exp + eexp; + } + + negexp = 1; + if (exp<0) { + negexp = -1; + exp = -exp; + } + + + if((nd+exp*negexp) < -LOGHUGE){ + /*fl = 0;*/ fl.l = 0; fl.h = 0; + exp = 0; + } + /*flexp = 1;*/ flexp.l = 0; flexp.h = 040200 << 16; + /*exp5 = 5;*/ exp5.l = 0; exp5.h = 040640 << 16; + bexp = exp; + for (;;) { + if (exp&01) + flexp = fp_mul(flexp, exp5); + exp >>= 1; + if (exp==0) + break; + exp5 = fp_mul(exp5, exp5); + } + if (negexp<0) + fl = fp_div(fl, flexp); + else + fl = fp_mul(fl, flexp); + fl = fp_ldexp(fl, negexp*bexp); + if (neg<0) + fl = fp_neg(fl); + return(fl); +} +#endif diff --git a/n.sh b/n.sh new file mode 100755 index 0000000..b18b15b --- /dev/null +++ b/n.sh @@ -0,0 +1,2 @@ +#!/bin/sh +make CFLAGS=-g LDC0FLAGS= LDC1FLAGS= "$@" diff --git a/optable b/optable new file mode 100644 index 0000000..ed998e7 --- /dev/null +++ b/optable @@ -0,0 +1,2255 @@ +%{ +/* + * c code tables-- compile to register + */ +#if !defined(lint) && defined(DOSCCS) +static char sccsid[] = "@(#)optable 2.1 (2.11BSD GTE) 10/4/94"; +#endif + +struct table regtab[] = { + {106,cr106}, + {30,cr70}, + {31,cr70}, + {32,cr32}, + {33,cr32}, + {37,cr37}, + {38,cr37}, + {98,cr100}, + {99,cr100}, + {80,cr80}, + {40,cr40}, + {41,cr40 /* - like + */}, + {42,cr42}, + {43,cr43}, + {14,cr14}, + {44,cr43}, + {45,cr45}, + {46,cr40}, + {55,cr40}, + {48,cr40}, + {49,cr49}, + {70,cr70}, + {71,cr70}, + {72,cr72}, + {73,cr73}, + {74,cr74}, + {75,cr75}, + {76,cr72}, + {78,cr78}, /* |= */ + {85,cr78}, /* &= */ + {79,cr79}, + {102,cr102}, + {51,cr51}, + {52,cr52}, + {56,cr56}, + {57,cr57}, + {58,cr58}, + {59,cr59}, + {91,cr91}, + {82,cr82}, + {83,cr82}, + {84,cr82}, + {86,cr86}, + {87,cr86}, + {88,cr86}, + {16,cr16}, + {92,cr92}, + {17,cr43}, + {18,cr74}, + {109,cr109}, + {117,cr117}, + {118,cr117}, + {119,cr119}, + {120,cr119}, + {107,cr107}, + {121,cr121}, + {122,cr121}, + {123,cr121}, + {124,cr124}, + {125,cr124}, + {126,cr124}, + {127,cr127}, + {128,cr128}, + {129,cr129}, + {0} +}; +%} + +/* goto */ +cr102: +%a,n + jmp A1 + +%n*,n + F* + jmp #1(R) + +/* call */ +cr100: +%a,n + jsr pc,IA1 + +%n*,n + F* + jsr pc,#1(R) + +%n,n + F + jsr pc,(R) + +/* addressible */ +cr106: +%z,n + clr R + +%zf,n + clrf R + +%aub,n + clr R + bisb A1,R + +%a,n +%ad,n + movB1 A1,R + +%af,n + movof A1,R + +%nub*,n + F* + movb #1(R),R + bic $!377,R + +%n*,n +%nd*,n + F* + movB1 #1(R),R + +%nf*,n + F* + movof #1(R),R + +%al,n +%aul,n + mov A1+,R+ + mov A1,R + +%nl*,n +%nul*,n + F* + mov #1+2(R),R+ + mov #1(R),R + +%n,n + F + +/* ++,-- postfix */ +cr32: +%a,1 + movB1 A1',R + I'B1 A1'' + +%aw,n + mov A1',R + I A2,A1'' + +%aub,n + clr R + bisb A1',R + I'b A1'' + +%e*,1 + F1* + movB1 #1(R1),R + I'B1 #1(R1) + +%n*,1 + F* + movB1 #1(R),-(sp) + I'B1 #1(R) + movB1 (sp)+,R + +%ew*,n + F1* + mov #1(R1),R + I A2,#1(R1) + +%eub*,n + F1* + clr R + bisb #1(R1),R + I'b #1(R1) + +%nw*,n + F* + mov #1(R),-(sp) + I A2,#1(R) + mov (sp)+,R + +%nub*,n + F* + movb (R),-(sp) + I'b (R) + clr R + bisb (sp)+,R + +%al,1 +%aul,1 + F + I $1,A1+ + V A1 + +%el*,1 +%eul*,1 + F1* + mov #1+2(R1),R+ + mov #1(R1),R + I $1,#1+2(R1) + V #1(R1) + +%nl*,1 +%nul*,1 + F* + mov #1+2(R),-(sp) + mov #1(R),-(sp) + I $1,#1+2(R) + V #1(R) + mov (sp)+,R + mov (sp)+,R+ + +/* - unary, ~ */ +cr37: +%n,n +%nf,n + F + IBF R + +%nl,n +%nul,n + F + I R + I R+ + V R + +/* = */ +cr80: +%a,n +%ad,nf + S + movB1 R,A1 + +%aub,n + S + movB1 R,A1 + bic $!377,R + +%af,nf + S + movfo R,A1 + +%nd*,af + F* + S + movf R,#1(R) + +%n*,aw + F* + movB1 A2,#1(R) + movB1 #1(R),R + +%nf*,af + F* + S + movfo R,#1(R) + +%n*,e + F* + S1 + movB1 R1,#1(R) + movB1 R1,R + +%nub*,e + F* + S1 + movB1 R1,#1(R) + clr R + bisb R1,R + +%ed*,nf + S + F1* + movf R,#1(R1) + +%ef*,nf + S + F1* + movfo R,#1(R1) + +%n*,n +%nd*,nf + FS* + S + movB1 R,*(sp)+ + +%nub*,n + FS* + S + movB1 R,*(sp)+ + bic $!377,R + +%nf*,nf + FS* + S + movfo R,*(sp)+ + +%al,nl +%al,nul +%aul,nl +%aul,nul + S + mov R+,A1+ + mov R,A1 + +%el*,nl +%el*,nul +%eul*,nl +%eul*,nul + S + F1* + mov R+,2+#1(R1) + mov R,#1(R1) + +%nl*,nl +%nl*,nul +%nul*,nl +%nul*,nul + FS* + S + mov R,*(sp) + add $2,(sp) + mov R+,*(sp)+ + +/* field assign, value in reg. */ +cr16: +%a,n + S + bicB1 Z,A1' + bisB1 R,A1'' + +%e*,n +% [fas1] + +%n*,n + SS + F* + bicB1 Z,#1(R) + bisB1 (sp),#1(R) + mov (sp)+,R + +/* +, -, |, &~, << */ +cr40: +%n,z + F + +%n,1 + F + I' R + +%[add1:] +%n,aw +%nf,ad + F + IB2 A2,R + +%[add2:] +%n,ew* +%nf,ed* + F + S1* + IB2 #2(R1),R + +%[add3:] +%n,e +%nf,ef + F + S1 + IBF R1,R + +%[add4:] +%n,nw* +%nf,nd* + SS* + F + IB2 *(sp)+,R + +%[add5:] +%n,n +%nf,nf + SS + F + IBF (sp)+,R + +%nl,c +%nl,au +%nul,c +%nul,au + F + I A2,R+ + V R + +%nl,eu +%nul,eu + F + S1 + I R1,R+ + V R + +%nl,al +%nl,aul +%nul,al +%nul,aul + F + I A2,R + I A2+,R+ + V R + +%[addl1:] +%nl,el +%nl,eul +%nul,el +%nul,eul + F + S1 + I R1+,R+ + V R + I R1,R + +%[addl2:] +%nl,nl +%nl,nul +%nul,nl +%nul,nul + SS + F + I (sp)+,R + I (sp)+,R+ + V R + +/* ^ -- xor */ +cr49: +%n,e +% [add3] + +%n,n + FS + S + xor R,(sp) + mov (sp)+,R + +%nl,el +%nl,eul +%nul,el +%nul,eul +% [addl1] + +%nl,nl +%nl,nul +%nul,nl +%nul,nul + SS + F + I R,(sp) + mov (sp)+,R + I R+,(sp) + mov (sp)+,R+ + +/* >> (all complicated cases taken care of by << -) */ +cr45: +%n,1 + F + asr R + +/* * -- R must be odd on integers */ +cr42: +%n,aw +%nf,ad +% [add1] + +%n,ew* +%nf,ed* +% [add2] + +%n,e +%nf,ef +% [add3] + +%n,n +%nf,nf +% [add5] + +/* / and >> R must be odd on integers */ +cr43: +%n,aw + F + T + I A2,R- + +%n,ew* + F + T + S1* + I #2(R1),R- + +%n,e + F + T + S1 + I R1,R- + +%n,n + SS + F + T + I (sp)+,R- + +%nf,ad +% [add1] + +%nf,ed* +% [add2] + +%nf,ef +% [add3] + +%nf,nf +% [add5] + +/* PTOI */ +cr14: +%nl,a +%nul,a + F! + div A2,R + +/* =+, =- */ +cr70: +%[addq1:] +%aw,aw + I A2,A1' + mov A1'',R + +%[addq20:] +%aub,aw + clr R + bisb A1',R + I A2,R + movb R,A1'' + bic $!377,R + +%[addq1a:] +%a,aw +%ad,ad + movB1 A1',R + IBF A2,R + movB1 R,A1'' + +%[addq2:] +%aw,nw* + S* + I #2(R),A1' + mov A1'',R + +%[addq3:] +%aw,n + S + I R,A1' + mov A1'',R + +%[addq21:] +%aub,n + SS + clr R + bisb A1',R + I (sp)+,R + movb R,A1'' + bic $!377,R + +%[addq4:] +%ew*,nw* + S* + F1* + I #2(R),#1(R1) + mov #1(R1),R + +%[addq4a:] +%ad,ef + movf A1',R + S1 + IBF R1,R + movf R,A1'' + +%[addq5:] +%a,n +%ad,nf + SS + movB1 A1',R + IBF (sp)+,R + movB1 R,A1'' + +%[addq6:] +%af,nf + SS + movof A1',R + IBF (sp)+,R + movfo R,A1'' + +%[addq7:] +%ew*,n + S + F1* + I R,#1(R1) + mov #1(R1),R + +%[addq8:] +%nw*,n + SS + F* + I (sp)+,#1(R) + mov #1(R),R + +%[addq9:] +%n*,n + FS* + SS + movB1 *2(sp),R + IBF (sp)+,R + movB1 R,*(sp)+ + +%[addq22:] +%nub*,n + FS* + SS + clr R + bisb *2(sp),R + I (sp)+,R + movb R,*(sp)+ + bic $!377,R + +%[addq9a:] +%nd*,nf + SS + F* + movB1 #1(R),R + IBF (sp)+,R + movB1 R,#1(R) + +%[addq10:] +%nf*,nf + SS + F* + movof #1(R),R1 + IBF (sp)+,R1 + movfo R1,#1(R) + movf R1,R + +%[addq11:] +%al,c +%aul,c + I A2,A1+ + V A1 + F + +%[addq12:] +%al,al +%al,aul +%aul,al +%aul,aul + I A2+,A1+ + V A1 + I A2,A1 + F + +%[addq13:] +%al,nl +%al,nul +%aul,nl +%aul,nul + S + I R+,A1+ + V A1 + I R,A1 + F + +%[addq14:] +%nl*,c +%nul*,c + F* + I A2,#1+2(R) + V #1(R) + mov #1+2(R),R+ + mov #1(R),R + +%[addq15:] +%nl*,al +%nl*,aul +%nul*,al +%nul*,aul + F* + I A2+,#1+2(R) + V #1(R) + I A2,#1(R) + mov #1+2(R),R+ + mov #1(R),R + +%[addq16:] +%nl*,nl +%nl*,nul +%nul*,nl +%nul*,nul + SS + F* + I (sp)+,#1(R) + I (sp)+,#1+2(R) + V #1(R) + mov #1+2(R),R+ + mov #1(R),R + +/* *=, <<= (for integer multiply, R must be odd) */ +cr72: +%a,aw +%ad,ad +% [addq1a] + +%ad,ef +% [addq4a] + +%a,n +%ad,nf +% [addq5] + +%af,nf +% [addq6] + +%aub,aw +% [addq20] + +%aub,n +% [addq21] + +%n*,n +% [addq9] + +%nub*,n +% [addq22] + +%nd*,nf +% [addq9a] + +%nf*,nf +% [addq10] + +/* =/ ; R must be odd on integers */ +cr73: +%a,aw + movB1 A1',R + V R- + IBF A2,R- + movB1 R-,A1'' + +%a,n + SS + movB1 A1',R + V R- + I (sp)+,R- + movB1 R-,A1'' + +%aub,n + SS + clr R + bisB1 A1',R + V R- + I (sp)+,R- + movB1 R-,A1'' + bic $!377,R- + +%e*,n + SS + F1* + movB1 #1(R1),R + V R- + I (sp)+,R- + movB1 R-,#1(R1) + +%n*,n + FS* + SS + movB1 *2(sp),R + V R- + I (sp)+,R- + movB1 R-,*(sp)+ + +%nub*,n + FS* + SS + clr R + bisB1 *2(sp),R + V R- + I (sp)+,R- + movB1 R-,*(sp)+ + bic $!377,R- + +%ad,ad +% [addq1a] + +%ad,ef +% [addq4a] + +%ad,nf +% [addq5] + +%af,nf +% [addq6] + +%nd*,nf +% [addq9a] + +%nf*,nf +% [addq10] + +/* >>= and =mod; R must be odd on integers */ +cr74: +%a,aw + movB1 A1',R + V R- + I A2,R- + movB1 R,A1'' + +%a,n + SS + movB1 A1',R + V R- + I (sp)+,R- + movB1 R,A1'' + +%aub,n + SS + clr R + bisB1 A1',R + V R- + I (sp)+,R- + movB1 R,A1'' + bic $!377,R + +%e*,n + SS + F1* + movB1 #1(R1),R + V R- + I (sp)+,R- + movB1 R,#1(R1) + +%n*,n + FS* + SS + movB1 *2(sp),R + V R- + I (sp)+,R- + movB1 R,*(sp)+ + +%nub*,n + FS* + SS + clr R + bisB1 *2(sp),R + V R- + I (sp)+,R- + movB1 R,*(sp)+ + bic $!377,R + +/* =^ -- =xor */ +cr79: +%aw,n +% [addq3] + +%ab,n + SS + movb A1',R + xor R,(sp) + mov (sp)+,R + movb R,A1'' + +%aub,n + SS + movb A1',R + xor R,(sp) + clr R + bisb (sp)+,R + movb R,A1'' + +%n*,n + FS* + movB1 *(sp),-(sp) + S + xor R,(sp) + movB1 (sp)+,R + movB1 R,*(sp)+ + +%nub*,n + FS* + clr -(sp) + bisb *2(sp),(sp) + S + xor R,(sp) + mov (sp)+,R + movb R,*(sp)+ + bic $!377,R + +/* =>> (all complicated cases done by =<< -) */ +cr75: +%a,1 + asrB1 A1' + movB1 A1'',R + +%n*,1 + F* + asrB1 #1(R) + movB1 #1(R),R + +/* =|, =&~ */ +cr78: +%aw,aw +% [addq1] + +%aub,a + IBE A2,A1' + clr R + bisb A1'',R + +%a,aw +%ad,ad +% [addq1a] + +%aw,nw* +% [addq2] + +%aw,n +% [addq3] + +%aub,n + SS + IBE (sp)+,A1' + clr R + bisb A1'',R + +%ew*,nw* +% [addq4] + +%ad,ef +% [addq4a] + +%a,n +%ad,nf +% [addq5] + +%af,nf +% [addq6] + +%ew*,n +% [addq7] + +%nw*,n +% [addq8] + +%n*,n +% [addq9] + +%nub*,n + FS* + SS + IBE (sp),*2(sp) + tst (sp)+ + clr R + bisb *(sp)+,R + +%nd*,nf +% [addq9a] + +%nf*,nf +% [addq10] + +%al,c +%aul,c +% [addq11] + +%al,al +%al,aul +%aul,al +%aul,aul +% [addq12] + +%al,nl +%al,nul +%aul,nl +%aul,nul +% [addq13] + +%nl*,c +%nul*,c +% [addq14] + +%nl*,al +%nl*,aul +%nul*,al +%nul*,aul +% [addq15] + +%nl*,nl +%nl*,nul +%nul*,nl +%nul*,nul +% [addq16] + +/* << for longs */ +cr91: +%nl,aw +%nul,aw +% [add1] + +%nl,ew* +%nul,ew* +% [add2] + +%nl,e +%nul,e +% [add3] + +%nl,nw* +%nul,nw* +% [add4] + +%nl,n +%nul,n +% [add5] + +/* >> for unsigned long */ +cr128: +%nl,n +%nul,n + SS + F + jsr pc,I + tst (sp)+ + +/* >>= for unsigned long */ +cr129: +%n,n + SS + FS + jsr pc,I + cmp (sp)+,(sp)+ + +/* int -> float */ +cr51: +%aw,n + movif A1,R + +%nw*,n + F* + movif #1(R),R + +%n,n + F + movif R,R + +/* float, double -> int */ +cr52: +%nf,n + F + movfi R,R + +/* double (float) to long */ +cr56: +%nf,n + F + setl + movfi R,-(sp) + mov (sp)+,R + mov (sp)+,R+ + seti + +/* long to double */ +cr57: +%al,n + setl + movif A1,R + seti + +%nl*,n + F* + setl + movif #1(R),R + seti + +%nl,n + FS + setl + movif (sp)+,R + seti + +/* unsigned long to float(double) */ +cr127: +%aul,n + mov A1+,-(sp) + mov A1,-(sp) + jsr pc,I + cmp (sp)+,(sp)+ + +%nul*,n + F* + mov #1+2(R),-(sp) + mov #1(R),-(sp) + jsr pc,I + cmp (sp)+,(sp)+ + +%nul,n + FS + jsr pc,I + cmp (sp)+,(sp)+ + +/* integer to long */ +cr58: +%eu,n + F1! + clr R + +%nu,n + F + mov R,R1 + clr R + +%e,n + F1! + sxt R + +%n,n + F + mov R,R1 + sxt R + +/* long to integer */ +cr59: +%al,n +%aul,n + mov A1+,R + +%nl*,n +%nul*,n + F* + mov #1+2(R),R + +/* *, /, remainder for longs. */ +cr82: +%[l82:] +%nl,nl +%nl,nul +%nul,nl +%nul,nul + SS + FS + jsr pc,I + add $10,sp + +/* *, /, rem for unsigned long */ +cr121: +%nul,nl +%nl,nul +%nul,nul +% [l82] + +/* *=, /=, %= for unsigned long */ +cr124: +%n,nl +%n,nul +%nl,n +%nul,n +% [l86] + +/* *=, /=, %= for longs */ +/* Operands of the form &x op y, so stack space is known. */ +cr86: +%[l86:] +%n,nl +%n,nul + SS + FS + jsr pc,I + add $6,sp + +/* convert integer to character (sign extend) */ +cr109: +%n,n + F + movb R,R + +/* divide, remainder for unsigned */ +cr117: +%n,e + F! + S1! + jsr pc,I + +%n,n + SS + F! + mov (sp)+,R1 + jsr pc,I + +/* /= mod for unsigned */ +cr119: +%aw,e +%ab,e + movB1 A1',R + S1! + jsr pc,I + movB1 R,A1'' + +%aub,e + clr R + bisB1 A1',R + S1! + jsr pc,I + movb R,A1'' + +%aw,n +%ab,n + SS + movB1 A1',R + mov (sp)+,R1 + jsr pc,I + movB1 R,A1'' + +%nw*,n +%nb*,n + FS* + S! + mov R,R1 + movB1 *(sp),R + jsr pc,I + movB1 R,*(sp)+ + +%aub,n + SS + clr R + bisB1 A1',R + mov (sp)+,R1 + jsr pc,I + movB1 R,A1'' + +%nub*,n + FS* + S! + mov R,R1 + clr R + bisb *(sp),R + jsr pc,I + movB1 R,*(sp)+ + +/* (int *) - (int *) */ +cr107: +%n,n + F? + ror R + +%{ +/* + * c code tables -- compile for side effects. + * Also set condition codes properly (except for ++, --) + */ + +struct table efftab[] = { + {30,ci70}, + {31,ci70}, + {32,ci70}, + {33,ci70}, + {80,ci80}, + {70,ci70}, + {71,ci70 /* - like + */}, + {78,ci78}, + {79,ci79}, + {85,ci78}, + {75,ci75}, + {76,ci76}, + {16,ci16}, + {116,ci116}, + {0} +}; +%} + +/* = */ +ci80: +%[move1:] +%a,z +%ad,zf +%aub,z + I'B1 A1 + +%[move2:] +%n*,z +%nd*,zf +%nub*,z + F* + I'B1 #1(R) + +%[move3:] +%a,aw +%ab,a +%ab,aub +%aub,a +%aub,ab + IBE A2,A1 + +%[move4:] +%ab,n* +%a,nw* +%aub,n* + S* + IBE #2(R),A1 + +%[move5:] +%a,n +%aub,n + S + IB1 R,A1 + +%[move6:] +%n*,aw +%nb*,a +%nub*,a + F* + IBE A2,#1(R) + +%[move7:] +%n*,ew* +%nb*,e* +%nub*,e* + F* + S1* + IBE #2(R1),#1(R) + +%[move8:] +%n*,e +%nub*,e + F* + S1 + IB1 R1,#1(R) + +%[move9:] +%e*,nw* +%eb*,n* +%eub*,n* + S* + F1* + IBE #2(R),#1(R1) + +%[move10:] +%e*,n +%eub*,n + S + F1* + IB1 R,#1(R1) + +%[move11:] +%n*,nw* +%nb*,n* +%nub*,n* + FS* + S* + IBE #2(R),*(sp)+ + +%[move12:] +%n*,n +%nub*,n + FS* + S + IB1 R,*(sp)+ + +%aw,nf + S + movfi R,A1 + +%ew*,nf + S + F1* + movfi R,#1(R1) + +%al,z +%aul,z + clr A1 + clr A1+ + +%nl*,z +%nul*,z + F* + clr #1(R) + clr 2+#1(R) + +%[move13a:] +%al,aw +%aul,aw + I A2,A1+ + V A1 + +%al,nw* +%aul,nw* + S* + mov #2(R),A1+ + V A1 + +%al,n +%aul,n + S + mov R,A1+ + V A1 + +%al,nf +%aul,nf + S + setl + movfi R,A1 + seti + +%el*,nf +%eul*,nf + S + F1* + setl + movfi R,#1(R1) + seti + +%[move13:] +%al,al +%al,aul +%aul,al +%aul,aul + I A2,A1 + I A2+,A1+ + V A1 + +%[move14:] +%al,nl* +%al,nul* +%aul,nl* +%aul,nul* + S* + I #2(R),A1 + I #2+2(R),A1+ + V A1 + +%[move15:] +%al,nl +%al,nul +%aul,nl +%aul,nul + S + I R,A1 + I R+,A1+ + V A1 + +%[move14a:] +%nl*,aw +%nul*,aw + F* + I A2,#1+2(R) + V #1(R) + +%[move16a:] +%nl*,al +%nl*,aul +%nul*,al +%nul*,aul + F* + I A2+,#1+2(R) + V #1(R) + I A2,#1(R) + +%[move16:] +%el*,nl +%el*,nul +%eul*,nl +%eul*,nul + S + F1* + I R+,#1+2(R1) + V #1(R1) + I R,#1(R1) + +%nl*,n +%nul*,n + SS + F* + mov (sp)+,#1+2(R) + V #1(R) + +%[move17:] +%nl*,nl +%nl*,nul +%nul*,nl +%nul*,nul + SS + F* + I (sp)+,#1(R) + I (sp)+,#1+2(R) + V #1(R) + +/* =| and =& ~ */ +ci78: +%a,a +%a,ab +%a,aub +%ab,a +%ab,ab +%ab,aub +%aub,a +%aub,ab +%aub,aub +% [move3] + +%aub,n + S + IBE R,A1 + +%a,n +% [move5] + +%n*,aw +%nb*,a +%nub*,a +% [move6] + +%n*,ew* +%nb*,e* +%nub*,e* +% [move7] + +%n*,e +% [move8] + +%e*,nw* +%eb*,n* +%eub*,n* +% [move9] + +%e*,n +% [move10] + +%n*,nw* +%nb*,n* +%nub*,n* +% [move11] + +%n*,n +% [move12] + +%al,c +%al,au +%aul,c +%aul,au +% [move13a] + +%al,al +%al,aul +%aul,al +%aul,aul +% [move13] + +%al,nl* +%al,nul* +%aul,nl* +%aul,nul* +% [move14] + +%al,nl +%al,nul +%aul,nl +%aul,nul +% [move15] + +%nl*,c +%nul*,c +% [move14a] + +%nl*,al +%nl*,aul +%nul*,al +%nul*,aul +% [move16a] + +%el*,nl +%el*,nul +%eul*,nl +%eul*,nul +% [move16] + +%nl*,nl +%nl*,nul +%nul*,nl +%nul*,nul +% [move17] + +/* =^ */ +ci79: +%al,nl +%al,nul +%aul,nl +%aul,nul +% [move15] + +%el*,nl +%el*,nul +%eul*,nl +%eul*,nul +% [move16] + +%nl*,nl +%nl*,nul +%nul*,nl +%nul*,nul + FS* + S + I R,*(sp) + mov (sp)+,R + I R+,2(R) + +/* =+ */ +ci70: +%n*,z +%a,z +%ab,1 +%aub,1 +%a,1 + I'B1 A1 + +%aw,aw +% [move3] + +%aw,nw* +% [move4] + +%aw,n +% [move5] + +%n*,1 +%nub*,1 +% [move2] + +%ew*,nw* +% [move9] + +%a,ew* + S* + movB1 A1',R1 + I #2(R),R1 + movB1 R1,A1'' + +%a,n + S + movB1 A1',R1 + I R,R1 + movB1 R1,A1'' + +%aub,n + S + clr R1 + bisB1 A1',R1 + I R,R1 + movB1 R1,A1'' + +%ew*,n +% [move10] + +%nw*,n +% [move12] + +%n*,n + SS + F* + movB1 #1(R),R1 + I (sp)+,R1 + movB1 R1,#1(R) + +%nub*,n + SS + F* + clr R1 + bisB1 #1(R),R1 + I (sp)+,R1 + movB1 R1,#1(R) + +%al,c +%al,au +%aul,au +%aul,c +% [move13a] + +%al,al +%al,aul +%aul,al +%aul,aul +% [move13] + +%al,nl* +%al,nul* +%aul,nl* +%aul,nul* +% [move14] + +%al,nl +%al,nul +%aul,nl +%aul,nul +% [move15] + +%nl*,c +%nl*,au +%nul*,c +%nul*,au +% [move14a] + +%nl*,al +%nl*,aul +%nul*,al +%nul*,aul +% [move16a] + +%el*,nl +%el*,nul +%eul*,nl +%eul*,nul +% [move16] + +%nl*,nl +%nl*,nul +%nul*,nl +%nul*,nul +% [move17] + +/* =>> (all harder cases handled by =<< -) */ +ci75: +%a,1 + asrB1 A1 + +%aub,1 + clc + rorB1 A1 + +%n*,1 + F* + asrB1 #1(R) + +%nub*,1 + F* + clc + rorB1 #1(R) + +/* =<< */ +ci76: +%a,1 +%aub,1 + aslB1 A1 + +%n*,1 +%nub*,1 + F* + aslB1 #1(R) + +%r,aw + ash A2,A1 + +%r,nw* + S* + ash #2(R),A1 + +%r,n + S + ash R,A1 + +/* =<< for longs */ +cr92: +%al,aw +%aul,aw + F + ashc A2,R + mov R,A1 + mov R+,A1+ + +%al,n +%aul,n + SS + F + ashc (sp)+,R + mov R,A1 + mov R+,A1+ + +%nl*,n +%nul*,n + FS* + SS + mov 2(sp),R + mov 2(R),R+ + mov (R),R + ashc (sp)+,R + mov R,*(sp) + add $2,(sp) + mov R+,*(sp)+ + +/* field = ... */ +ci16: +%a,a + bicB1 Z,A1' + bisB1 A2,A1'' + +%a,n + S + bicB1 Z,A1' + bisB1 R,A1'' + +%n*,a + F* + bicB1 Z,#1(R) + bisB1 A2,#1(R) + +%[fas1:] +%e*,n + S + F1* + bicB1 Z,#1(R1) + bisB1 R,#1(R1) + +%n*,e + F* + S1 + bicB1 Z,#1(R) + bisB1 R1,#1(R) + +%n*,n + SS + F* + bicB1 Z,#1(R) + bisB1 (sp)+,#1(R) + +%{ +/* + * c code tables-- set condition codes + */ + +struct table cctab[] = { + {106,cc60}, + {28,rest}, + {55,rest}, + {34,rest}, + {35,rest}, + {36,rest}, + {37,rest}, + {40,rest}, + {41,rest}, + {43,rest}, + {81,cc81 /* & as in "if ((a&b)==0)" */}, + {48,rest}, + {60,cc60}, + {61,cc60}, + {62,cc60}, + {63,cc60}, + {64,cc60}, + {65,cc60}, + {66,cc60}, + {67,cc60}, + {68,cc60}, + {69,cc60}, + {72,rest}, + {73,rest}, + {79,rest}, + {0} +}; +%} + +/* relationals */ +cc60: +%a,z +%ad,zf +%aub,z +% [move1] + +%af,z + movof A1,R + +%n*,z +%nd*,zf +%nub*,z +% [move2] + +%nf*,z + F* + movof #1(R),R + +%n,z +%nf,zf + FC + +%aw,aw +%ab,ab +%aub,a +%aub,aub +% [move3] + +%nw*,aw +%nb*,ab +%nub*,aub +% [move6] + +%n,aw +%nf,ad +% [add1] + +%nw*,ew* +%nb*,eb* +%nub*,eub* +% [move7] + +%nw*,e +% [move8] + +%n,ew* +%nf,ed* +% [add2] + +%n,e +%nf,ef +% [add3] + +%nw*,nw* +%nb*,nb* +%nub*,nub* +% [move11] + +%nw*,n +% [move12] + +%n,n +%nf,nf +% [add5] + +%al,z +%aul,z + tst A1 + X0 + tst A1+ + X1 + +%al,c +%al,au +%aul,c +%aul,au + tst A1 + X0 + cmp A1+,A2 + X1 + +%[lcmp1:] +%al,al +%al,aul +%aul,al +%aul,aul + I A1,A2 + X0 + I A1+,A2+ + X1 + +%nl*,z +%nul*,z + F* + tst #1(R) + X0 + tst #1+2(R) + X1 + +%nl*,c +%nul*,c +%nl*,au +%nul*,au + F* + tst #1(R) + X0 + cmp #1+2(R),A2 + X1 + +%[lcmp2:] +%nl*,al +%nl*,aul +%nul*,al +%nl*,aul + F* + I #1(R),A2 + X0 + I #1+2(R),A2+ + X1 + +%nl,z +%nul,z + F + tst R + X0 + tst R+ + X1 + +%nl,c +%nul,c +%nl,au +%nul,au + F + tst R + X0 + cmp R+,A2 + X1 + +%[lcmp3:] +%nl,al +%nl,aul +%nul,al +%nul,aul + F + I R,A2 + X0 + I R+,A2+ + X1 + +%[lcmp4:] +%nl*,el* +%nl*,eul* +%nul*,el* +%nul*,eul* + F* + S1* + I #1(R),#2(R1) + X0 + I #1+2(R),#2+2(R1) + X1 + +%[lcmp5:] +%nl,el* +%nl,eul* +%nul,el* +%nul,eul* + F + S1* + I R,#2(R1) + X0 + I R+,#2+2(R1) + X1 + +%[lcmp6:] +%nl,nl +%nl,nul +%nul,nl +%nul,nul + FS + S + mov R,-(sp) + mov 4(sp),R + mov (sp)+,2(sp) + I (sp)+,(sp)+ + X0 + I R,R+ + X1 + +/* & as in "if ((a&b) ==0)" */ +cc81: +%a,a +%a,ab +%a,aub +%ab,a +%ab,ab +%ab,aub +%aub,a +%aub,ab +%aub,aub +% [move3] + +/* + special case. apparently "u_char b; [u_]char a; if (b & a)..." was + too complicated. the resulting code was horrid. this cuts the + waste by 33% +*/ + +%a,e +%aub,e + S + IBE R,A1 + +%n*,a +%nu*,a +%nub*,a +% [move6] + +%n,a +% [add1] + +%n,e +% [add3] + +%n,n +% [add5] + +%al,c +%aul,c +%al,au +%aul,au + bit A2,A1+ + X1 + +%nl*,c +%nul*,c +%nl*,au +%nul*,au + F* + bit A2,#2+2(R) + X1 + +%al,al +%al,aul +%aul,al +%aul,aul +% [lcmp1] + +%nl*,al +%nl*,aul +%nul*,al +%nul*,aul +% [lcmp2] + +%nl,al +%nl,aul +%nul,al +%nul,aul +% [lcmp3] + +%nl*,el* +%nl*,eul* +%nul*,el* +%nul*,eul* +% [lcmp4] + +%nl,el* +%nl,eul* +%nul,el* +%nul,eul* +% [lcmp5] + +%nl,nl +%nl,nul +%nul,nl +%nul,nul +% [lcmp6] + +%nl,c +%nul,c +%nl,au +%nul,au + F + bit A2,R+ + X1 + +/* set codes right */ +rest: +%n,n +%nf,nf + H + +%{ +/* + * c code tables-- expression to -(sp) + */ + +struct table sptab[] = { + {106,cs106}, + {40,cs40}, + {41,cs40}, + {55,cs40}, + {48,cs40}, + {58,cs58}, + {56,cs56}, + {0} +}; +%} + +/* name */ +cs106: +%z,n +%zf,n + clrB1 -(sp) + +%aw,n + mov A1,-(sp) + +%aub,n + clr -(sp) + bisb A1,(sp) + +%nw*,n + F* + mov #1(R),-(sp) + +%al,n +%aul,n + mov A1+,-(sp) + mov A1,-(sp) + +/* +, -, |, &~ */ +cs40: +%a,1 + FS + I' (sp) + +%a,aw + FS + I A2,(sp) + +%a,nw* + FS + S* + I #2(R),(sp) + +%a,n + FS + S + I R,(sp) + +/* integer to long */ +cs58: +%nu,n + FS + clr -(sp) + +%aw,n + mov A1,-(sp) + sxt -(sp) + +/* float to long */ +cs56: +%nf,n + F + setl + movfi R,-(sp) + seti + +/* setup for structure assign */ +ci116: +%n,e + F! + S1! + +%n,n + SS + F! + mov (sp)+,r1 + -- 2.34.1