Add original unix v6
This commit is contained in:
+709
@@ -0,0 +1,709 @@
|
||||
#
|
||||
/* C compiler
|
||||
*
|
||||
*
|
||||
*
|
||||
* Called from cc:
|
||||
* c0 source temp1 temp2 [ profileflag ]
|
||||
* temp1 contains some ascii text and the binary expression
|
||||
* trees. Each tree is introduced by the # character.
|
||||
* Strings are put on temp2, which cc tacks onto
|
||||
* temp1 for assembly.
|
||||
*/
|
||||
|
||||
#include "c0h.c"
|
||||
|
||||
int isn 1;
|
||||
int stflg 1;
|
||||
int peeksym -1;
|
||||
int line 1;
|
||||
int debug 0;
|
||||
int dimp 0;
|
||||
struct tname funcblk { NAME, 0, 0, REG, 0, 0 };
|
||||
int *treespace { osspace };
|
||||
|
||||
struct kwtab {
|
||||
char *kwname;
|
||||
int kwval;
|
||||
} kwtab[]
|
||||
{
|
||||
"int", INT,
|
||||
"char", CHAR,
|
||||
"float", FLOAT,
|
||||
"double", DOUBLE,
|
||||
"struct", STRUCT,
|
||||
"long", LONG,
|
||||
"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,
|
||||
0, 0,
|
||||
};
|
||||
|
||||
main(argc, argv)
|
||||
char *argv[];
|
||||
{
|
||||
extern fin;
|
||||
register char *sp;
|
||||
register i;
|
||||
register struct kwtab *ip;
|
||||
|
||||
if(argc<3) {
|
||||
error("Arg count");
|
||||
exit(1);
|
||||
}
|
||||
if((fin=open(argv[1],0))<0) {
|
||||
error("Can't find %s", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
if (fcreat(argv[2], obuf)<0 || fcreat(argv[3], sbuf)<0) {
|
||||
error("Can't create temp");
|
||||
exit(1);
|
||||
}
|
||||
if (argc>4)
|
||||
proflg++;
|
||||
/*
|
||||
* 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; (sp = ip->kwname); ip++) {
|
||||
i = 0;
|
||||
while (*sp)
|
||||
i =+ *sp++;
|
||||
hshtab[i%hshsiz].hflag = FKEYW;
|
||||
}
|
||||
while(!eof) {
|
||||
extdef();
|
||||
blkend();
|
||||
}
|
||||
outcode("B", EOF);
|
||||
strflg++;
|
||||
outcode("B", EOF);
|
||||
fflush(obuf);
|
||||
fflush(sbuf);
|
||||
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. An initial "." is ignored in the hash.
|
||||
* Return is a ptr to the symbol table entry.
|
||||
*/
|
||||
lookup()
|
||||
{
|
||||
int ihash;
|
||||
register struct hshtab *rp;
|
||||
register char *sp, *np;
|
||||
|
||||
ihash = 0;
|
||||
sp = symbuf;
|
||||
if (*sp=='.')
|
||||
sp++;
|
||||
while (sp<symbuf+ncps)
|
||||
ihash =+ *sp++;
|
||||
rp = &hshtab[ihash%hshsiz];
|
||||
if (rp->hflag&FKEYW)
|
||||
if (findkw())
|
||||
return(KEYW);
|
||||
while (*(np = rp->name)) {
|
||||
for (sp=symbuf; sp<symbuf+ncps;)
|
||||
if (*np++ != *sp++)
|
||||
goto no;
|
||||
csym = rp;
|
||||
return(NAME);
|
||||
no:
|
||||
if (++rp >= &hshtab[hshsiz])
|
||||
rp = hshtab;
|
||||
}
|
||||
if(++hshused >= hshsiz) {
|
||||
error("Symbol table overflow");
|
||||
exit(1);
|
||||
}
|
||||
rp->hclass = 0;
|
||||
rp->htype = 0;
|
||||
rp->hoffset = 0;
|
||||
rp->dimp = 0;
|
||||
rp->hflag =| xdflg;
|
||||
sp = symbuf;
|
||||
for (np=rp->name; sp<symbuf+ncps;)
|
||||
*np++ = *sp++;
|
||||
csym = rp;
|
||||
return(NAME);
|
||||
}
|
||||
|
||||
/*
|
||||
* Search the keyword table.
|
||||
* Ignore initial "." to avoid member-of-structure
|
||||
* problems.
|
||||
*/
|
||||
findkw()
|
||||
{
|
||||
register struct kwtab *kp;
|
||||
register char *p1, *p2;
|
||||
char *wp;
|
||||
|
||||
wp = symbuf;
|
||||
if (*wp=='.')
|
||||
wp++;
|
||||
for (kp=kwtab; (p2 = kp->kwname); kp++) {
|
||||
p1 = wp;
|
||||
while (*p1 == *p2++)
|
||||
if (*p1++ == '\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, and it
|
||||
* gets a "." prepended to it to distinguish
|
||||
* it from other identifiers.
|
||||
*/
|
||||
symbol() {
|
||||
register c;
|
||||
register char *sp;
|
||||
|
||||
if (peeksym>=0) {
|
||||
c = peeksym;
|
||||
peeksym = -1;
|
||||
if (c==NAME)
|
||||
mosflg = 0;
|
||||
return(c);
|
||||
}
|
||||
if (peekc) {
|
||||
c = peekc;
|
||||
peekc = 0;
|
||||
} else
|
||||
if (eof)
|
||||
return(EOF);
|
||||
else
|
||||
c = getchar();
|
||||
loop:
|
||||
switch(ctab[c]) {
|
||||
|
||||
case INSERT: /* ignore newlines */
|
||||
inhdr = 1;
|
||||
c = getchar();
|
||||
goto loop;
|
||||
|
||||
case NEWLN:
|
||||
if (!inhdr)
|
||||
line++;
|
||||
inhdr = 0;
|
||||
|
||||
case SPACE:
|
||||
c = getchar();
|
||||
goto loop;
|
||||
|
||||
case EOF:
|
||||
eof++;
|
||||
return(0);
|
||||
|
||||
case PLUS:
|
||||
return(subseq(c,PLUS,INCBEF));
|
||||
|
||||
case MINUS:
|
||||
return(subseq(c,subseq('>',MINUS,ARROW),DECBEF));
|
||||
|
||||
case ASSIGN:
|
||||
if (subseq(' ',0,1)) return(ASSIGN);
|
||||
c = symbol();
|
||||
if (c>=PLUS && c<=EXOR) {
|
||||
if (spnextchar() != ' '
|
||||
&& (c==MINUS || c==AND || c==TIMES)) {
|
||||
error("Warning: assignment operator assumed");
|
||||
nerror--;
|
||||
}
|
||||
return(c+ASPLUS-PLUS);
|
||||
}
|
||||
if (c==ASSIGN)
|
||||
return(EQUAL);
|
||||
peeksym = c;
|
||||
return(ASSIGN);
|
||||
|
||||
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 DIVIDE:
|
||||
if (subseq('*',1,0))
|
||||
return(DIVIDE);
|
||||
while ((c = spnextchar()) != EOF) {
|
||||
peekc = 0;
|
||||
if (c=='*') {
|
||||
if (spnextchar() == '/') {
|
||||
peekc = 0;
|
||||
c = getchar();
|
||||
goto loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
eof++;
|
||||
error("Nonterminated comment");
|
||||
return(0);
|
||||
|
||||
case PERIOD:
|
||||
case DIGIT:
|
||||
peekc = c;
|
||||
if ((c=getnum(c=='0'?8:10)) == FCON)
|
||||
cval = isn++;
|
||||
return(c);
|
||||
|
||||
case DQUOTE:
|
||||
return(getstr());
|
||||
|
||||
case SQUOTE:
|
||||
return(getcc());
|
||||
|
||||
case LETTER:
|
||||
sp = symbuf;
|
||||
if (mosflg) {
|
||||
*sp++ = '.';
|
||||
mosflg = 0;
|
||||
}
|
||||
while(ctab[c]==LETTER || ctab[c]==DIGIT) {
|
||||
if (sp<symbuf+ncps) *sp++ = c;
|
||||
c = getchar();
|
||||
}
|
||||
while(sp<symbuf+ncps)
|
||||
*sp++ = '\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:
|
||||
error("Unknown character");
|
||||
c = getchar();
|
||||
goto loop;
|
||||
|
||||
}
|
||||
return(ctab[c]);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the next input character is c, return a and advance.
|
||||
* Otherwise push back the character and return a.
|
||||
*/
|
||||
subseq(c,a,b)
|
||||
{
|
||||
if (spnextchar() != c)
|
||||
return(a);
|
||||
peekc = 0;
|
||||
return(b);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a double-quoted string, placing it on the
|
||||
* string buffer.
|
||||
*/
|
||||
getstr()
|
||||
{
|
||||
register int c;
|
||||
register char *sp;
|
||||
|
||||
nchstr = 1;
|
||||
sp = savstr;
|
||||
while((c=mapch('"')) >= 0) {
|
||||
nchstr++;
|
||||
if (sp >= &savstr[STRSIZ]) {
|
||||
sp = savstr;
|
||||
error("String too long");
|
||||
}
|
||||
*sp++ = c;
|
||||
}
|
||||
strptr = sp;
|
||||
cval = isn++;
|
||||
return(STRING);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out a string, either in-line
|
||||
* or in the string temp file labelled by
|
||||
* lab.
|
||||
*/
|
||||
putstr(lab)
|
||||
{
|
||||
register char *sp;
|
||||
|
||||
if (lab) {
|
||||
strflg++;
|
||||
outcode("BNB", LABEL, lab, BDATA);
|
||||
} else
|
||||
outcode("B", BDATA);
|
||||
for (sp = savstr; sp<strptr; )
|
||||
outcode("1N", *sp++ & 0377);
|
||||
outcode("100");
|
||||
strflg = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* read a single-quoted character constant.
|
||||
* The routine is sensitive to the layout of
|
||||
* characters in a word.
|
||||
*/
|
||||
getcc()
|
||||
{
|
||||
register int c, cc;
|
||||
register char *ccp;
|
||||
|
||||
cval = 0;
|
||||
ccp = &cval;
|
||||
cc = 0;
|
||||
while((c=mapch('\'')) >= 0)
|
||||
if(cc++ < NCPW)
|
||||
*ccp++ = c;
|
||||
if(cc>NCPW)
|
||||
error("Long character constant");
|
||||
return(CON);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a character in a string or character constant,
|
||||
* detecting the end of the string.
|
||||
* It implements the escape sequences.
|
||||
*/
|
||||
mapch(ac)
|
||||
{
|
||||
register int a, c, n;
|
||||
static 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 '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':
|
||||
if (!inhdr)
|
||||
line++;
|
||||
inhdr = 0;
|
||||
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 delimitesrs are special
|
||||
* in initializer (and some other) expressions.
|
||||
*/
|
||||
tree()
|
||||
{
|
||||
#define SEOF 200
|
||||
#define SSIZE 20
|
||||
int *op, opst[SSIZE], *pp, prst[SSIZE];
|
||||
register int andflg, o;
|
||||
register struct hshtab *cs;
|
||||
int p, ps, os;
|
||||
|
||||
space = treespace;
|
||||
op = opst;
|
||||
pp = prst;
|
||||
cp = cmst;
|
||||
*op = SEOF;
|
||||
*pp = 06;
|
||||
andflg = 0;
|
||||
|
||||
advanc:
|
||||
switch (o=symbol()) {
|
||||
|
||||
case NAME:
|
||||
cs = csym;
|
||||
if (cs->hclass==0 && cs->htype==0)
|
||||
if(nextchar()=='(') {
|
||||
/* set function */
|
||||
cs->hclass = EXTERN;
|
||||
cs->htype = FUNC;
|
||||
} else if (initflg)
|
||||
cs->hclass = EXTERN;
|
||||
else {
|
||||
/* set label */
|
||||
cs->htype = ARRAY;
|
||||
if (cs->hoffset==0)
|
||||
cs->hoffset = isn++;
|
||||
}
|
||||
*cp++ = copname(cs);
|
||||
goto tand;
|
||||
|
||||
case FCON:
|
||||
if (!initflg)
|
||||
outcode("BBNB1N1N1N1N0B", DATA,LABEL,
|
||||
cval, WDATA, fcval, PROG);
|
||||
|
||||
case CON:
|
||||
case SFCON:
|
||||
*cp++ = block(1,o,(o==CON?INT:DOUBLE),0,cval);
|
||||
goto tand;
|
||||
|
||||
/* fake a static char array */
|
||||
case STRING:
|
||||
putstr(cval);
|
||||
*cp++ = block(3, NAME, ARRAY+CHAR,0,STATIC,0,cval);
|
||||
|
||||
tand:
|
||||
if(cp>=cmst+cmsiz) {
|
||||
error("Expression overflow");
|
||||
exit(1);
|
||||
}
|
||||
if (andflg)
|
||||
goto syntax;
|
||||
andflg = 1;
|
||||
goto advanc;
|
||||
|
||||
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) {
|
||||
if ((peeksym=symbol())==FCON) {
|
||||
fcval = - fcval;
|
||||
goto advanc;
|
||||
}
|
||||
if (peeksym==SFCON) {
|
||||
fcval = - fcval;
|
||||
cval =^ 0100000;
|
||||
goto advanc;
|
||||
}
|
||||
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++;
|
||||
break;
|
||||
|
||||
}
|
||||
/* binaries */
|
||||
if (!andflg)
|
||||
goto syntax;
|
||||
andflg = 0;
|
||||
|
||||
oponst:
|
||||
p = (opdope[o]>>9) & 077;
|
||||
if ((o==COMMA || o==COLON) && initflg)
|
||||
p = 05;
|
||||
opon1:
|
||||
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 (op >= &opst[SSIZE-1]) {
|
||||
error("expression overflow");
|
||||
exit(1);
|
||||
}
|
||||
*++op = o;
|
||||
*++pp = p;
|
||||
goto advanc;
|
||||
}
|
||||
--pp;
|
||||
switch (os = *op--) {
|
||||
|
||||
case SEOF:
|
||||
peeksym = o;
|
||||
build(0); /* flush conversions */
|
||||
return(*--cp);
|
||||
|
||||
case CALL:
|
||||
if (o!=RPARN)
|
||||
goto syntax;
|
||||
build(os);
|
||||
goto advanc;
|
||||
|
||||
case MCALL:
|
||||
*cp++ = block(0,0,0,0); /* 0 arg call */
|
||||
os = CALL;
|
||||
break;
|
||||
|
||||
case INCBEF:
|
||||
case INCAFT:
|
||||
case DECBEF:
|
||||
case DECAFT:
|
||||
*cp++ = block(1, CON, INT, 0, 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);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a tree node for a name.
|
||||
* All the relevant info from the symbol table is
|
||||
* copied out, including the name if it's an external.
|
||||
* This is because the symbol table is gone in the next
|
||||
* pass, so a ptr isn't sufficient.
|
||||
*/
|
||||
copname(acs)
|
||||
struct hshtab *acs;
|
||||
{
|
||||
register struct hshtab *cs;
|
||||
register struct tname *tp;
|
||||
register char *cp1;
|
||||
int i;
|
||||
char *cp2;
|
||||
|
||||
cs = acs;
|
||||
tp = gblock(sizeof(*tp)/NCPW);
|
||||
tp->op = NAME;
|
||||
tp->type = cs->htype;
|
||||
tp->dimp = cs->hdimp;
|
||||
if ((tp->class = cs->hclass)==0)
|
||||
tp->class = STATIC;
|
||||
tp->offset = 0;
|
||||
tp->nloc = cs->hoffset;
|
||||
if (cs->hclass==EXTERN) {
|
||||
gblock((ncps-NCPW)/NCPW);
|
||||
cp1 = tp->nname;
|
||||
cp2 = cs->name;
|
||||
i = ncps;
|
||||
do {
|
||||
*cp1++ = *cp2++;
|
||||
} while (--i);
|
||||
}
|
||||
if (cs->hflag&FFIELD)
|
||||
tp->class = FMOS;
|
||||
return(tp);
|
||||
}
|
||||
Reference in New Issue
Block a user