# /* 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 (sphflag&FKEYW) if (findkw()) return(KEYW); while (*(np = rp->name)) { for (sp=symbuf; sp= &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; spkwname); 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= 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= 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); }