#include "cc.h" #include "y.tab.h" /* * known debug flags * -o file output file * -s tag debug structure output * -D name define * -I path include * -H sym help symbol output * -B * -L * -a * -d * -i * -r * -t * -v * -w */ void main(int argc, char *argv[]) { char ofile[100], incfile[20], *p, *q, *r; int nproc, nout, status, i, c; Sym *s, *t; memset(debug, 0, sizeof(debug)); cinit(); ginit(); outfile = 0; include[ninclude++] = "."; ARGBEGIN { default: c = ARGC(); if(c >= 0 && c < sizeof(debug)) debug[c]++; break; case 'o': outfile = ARGF(); break; case 's': debug['H']++; suedebug = ARGF(); break; case 'D': p = ARGF(); if(p) dodefine(p); break; case 'I': p = ARGF(); if(p) include[ninclude++] = p; break; case 'H': debug['H']++; p = ARGF(); if(p) { i = 0; t = 0; q = utfrune(p, ':'); if(q) { *q++ = 0; r = utfrune(q, ':'); if(r) { *r++ = 0; i = atol(r); r = utfrrune(q, '/'); if(r) q = r+1; t = slookup(q); } else i = atol(q); } s = slookup(p); if(!s->ref) { ALLOC(s->ref, Ref); s->ref->class = CHELP; s->ref->lineno = i; s->ref->sym = t; } } break; } ARGEND if(argc < 1 && outfile == 0) { print("usage: %cc [-options] files\n", thechar); errorexit(); } nproc = 1; if(p = getenv("NPROC")) nproc = atol(p); /* */ if(argc > 1) { c = 0; nout = 0; for(;;) { while(nout < nproc && argc > 0) { i = fork(); if(i < 0) { i = mywait(&status); if(i < 0) { print("cannot create a process\n"); errorexit(); } if(status) c++; nout--; continue; } if(i == 0) goto child; nout++; argc--; argv++; } i = mywait(&status); if(i < 0) { if(c) errorexit(); exits(0); } if(status) c++; nout--; } } child: if(argc < 1) strcpy(ofile, "stdin"); else strcpy(ofile, *argv); if(p = utfrrune(ofile, '/')) { include[0] = ofile; *p++ = 0; } else p = ofile; if(outfile == 0) { outfile = p; if(p = utfrrune(outfile, '.')) if(p[1] == 'c' && p[2] == 0) p[0] = 0; p = utfrune(outfile, 0); p[0] = '.'; p[1] = thechar; p[2] = 0; } if(unix()) { strcpy(incfile, "/usr/%include"); p = utfrrune(incfile, '%'); if(p) *p = thechar; } else { strcpy(incfile, "/"); strcat(incfile, thestring); strcat(incfile, "/include"); } if(p = getenv("INCLUDE")) { include[ninclude++] = p; } else { include[ninclude++] = incfile; include[ninclude++] = "/sys/include"; } if(debug['H']) outfile = 0; else close(mycreat(outfile, 0664)); newio(); if(argc < 1) newfile("stdin", 0); else newfile(*argv, -1); yyparse(); if(!debug['H']) gclean(); reftrace(); if(nerrors) errorexit(); exits(0); } void errorexit(void) { if(outfile) remove(outfile); exits("error"); } void pushio(void) { Io *i; i = iostack; if(i == I) { yyerror("botch in pushio"); errorexit(); } i->p = fi.p; i->c = fi.c; } void newio(void) { Io *i; static pushdepth = 0; i = iofree; if(i == I) { pushdepth++; if(pushdepth > 1000) { yyerror("macro/io expansion too deep"); errorexit(); } ALLOC(i, Io); } else iofree = i->link; i->c = 0; i->f = -1; ionext = i; } void newfile(char *s, int f) { Io *i; i = ionext; i->link = iostack; iostack = i; i->f = f; if(f < 0) i->f = open(s, 0); if(i->f < 0) { yyerror("%cc: %s: %s", thechar, myerrstr(i->f), s); errorexit(); } fi.c = 0; linehist(s, 0); } Sym* slookup(char *s) { strcpy(symb, s); return lookup(); } Sym* lookup(void) { Sym *s; Ref *r; ulong h; long g; char *p, c0; int i; g = 0; for(p=symb; *p;) { g = g * 3; g += *p++; } if(g < 0) g = ~g; h = g; if(p >= symb+CNNAME) { /* * long names are first CNNAME/2-2 chars * last CNNAME/2-2 chars and three pieces of hash */ memmove(symb+(CNNAME/2-2), p-(CNNAME/2-2), CNNAME/2-2); for(i=0; i<3; i++) { c0 = g % 62; g = g / 62; if(c0 < 26) c0 += 'a'; else if(c0 < 52) c0 += 'A'-26; else c0 += '0'-52; symb[CNNAME-4+i] = c0; } symb[CNNAME-1] = 0; } h %= NHASH; c0 = symb[0]; for(s = hash[h]; s != S; s = s->link) { if(s->name[0] != c0) continue; if(strcmp(s->name, symb) == 0) { if(s->ref) { ALLOC(r, Ref); r->link = s->ref; s->ref = r; r->lineno = lineno; } return s; } } ALLOC(s, Sym); strcpy(s->name, symb); s->link = hash[h]; hash[h] = s; syminit(s); return s; } void syminit(Sym *s) { s->lexical = LNAME; s->block = 0; s->offset = 0; s->type = T; s->suetag = T; s->class = CXXX; s->ref = 0; s->aused = 0; } #define EOF (-1) #define IGN (-2) #define ESC (1<<20) #define GETC() ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff)) enum { Numdec = 1<<0, Numlong = 1<<1, Numuns = 1<<2, Numvlong = 1<<3, Numflt = 1<<4, }; long yylex(void) { long c, c1; char *cp; Rune rune; Sym *s; if(peekc != IGN) { c = peekc; peekc = IGN; goto l1; } l0: c = GETC(); l1: if(c >= Runeself) { /* * extension -- * all multibyte runes are alpha */ cp = symb; goto talph; } if(isspace(c)) { if(c == '\n') lineno++; goto l0; } if(isalpha(c)) { cp = symb; if(c != 'L') goto talph; *cp++ = c; c = GETC(); if(c == '\'') { /* L'x' */ c = escchar('\'', 1, 0); if(c == EOF) c = '\''; c1 = escchar('\'', 1, 0); if(c1 != EOF) { yyerror("missing '"); peekc = c1; } yylval.lval = castto(c, TUSHORT); return LUCONST; } if(c == '"') { cp = hunk; c1 = 0; strcpy(symb, "\"\""); goto caselq; } goto talph; } if(isdigit(c)) goto tnum; switch(c) { case EOF: peekc = EOF; return -1; case '_': cp = symb; goto talph; case '#': domacro(); goto l0; case '.': c1 = GETC(); if(isdigit(c1)) { cp = symb; *cp++ = c; c = c1; c1 = 0; goto casedot; } break; case '"': strcpy(symb, "\"L\""); cp = hunk; c1 = 0; caseq: /* "..." */ for(;;) { c = escchar('"', 0, 1); if(c == EOF) break; if(c & ESC) { ALLOCN(cp, c1, 1); cp[c1] = c; c1++; } else { rune = c; c = runelen(rune); ALLOCN(cp, c1, c); runetochar(cp+c1, &rune); c1 += c; } } for(;;) { /* it takes 2 peekc's to skip comments */ c = getc(); if(isspace(c)) continue; if(c == '"') goto caseq; unget(c); break; } lnstring = c1+1; do { ALLOCN(cp, c1, 1); cp[c1++] = 0; } while(c1 & 3); yylval.sval = cp; return LSTRING; caselq: /* L"..." */ for(;;) { c = escchar('"', 1, 0); if(c == EOF) break; ALLOCN(cp, c1, sizeof(ushort)); *(ushort*)(cp + c1) = c; c1 += sizeof(ushort); } for(;;) { /* it takes 2 peekc's to skip comments */ c = getc(); if(isspace(c)) continue; if(c == '"') goto caselq; unget(c); break; } lnstring = c1+sizeof(ushort); do { ALLOCN(cp, c1, sizeof(ushort)); *(ushort*)(cp + c1) = 0; c1 += sizeof(ushort); } while(c1 & 3); yylval.rval = (ushort*)cp; return LLSTRING; case '\'': /* '.' */ c = escchar('\'', 0, 0); if(c == EOF) c = '\''; c1 = escchar('\'', 0, 0); if(c1 != EOF) { yyerror("missing '"); peekc = c1; } if(ovflo(c, TUCHAR)) yyerror("overflow in character constant: 0x%x", c); c = castto(c, TCHAR); yylval.lval = c; return LCONST; case '/': c1 = GETC(); if(c1 == '*') { for(;;) { c = getr(); while(c == '*') { c = getr(); if(c == '/') goto l0; } if(c == EOF) { yyerror("eof in comment"); errorexit(); } } } if(c1 == '=') return LDVE; break; case '*': c1 = GETC(); if(c1 == '=') return LMLE; break; case '%': c1 = GETC(); if(c1 == '=') return LMDE; break; case '+': c1 = GETC(); if(c1 == '+') return LPP; if(c1 == '=') return LPE; break; case '-': c1 = GETC(); if(c1 == '-') return LMM; if(c1 == '=') return LME; if(c1 == '>') return LMG; break; case '>': c1 = GETC(); if(c1 == '>') { c = LRSH; c1 = GETC(); if(c1 == '=') return LRSHE; break; } if(c1 == '=') return LGE; break; case '<': c1 = GETC(); if(c1 == '<') { c = LLSH; c1 = GETC(); if(c1 == '=') return LLSHE; break; } if(c1 == '=') return LLE; break; case '=': c1 = GETC(); if(c1 == '=') return LEQ; break; case '!': c1 = GETC(); if(c1 == '=') return LNE; break; case '&': c1 = GETC(); if(c1 == '&') return LANDAND; if(c1 == '=') return LANDE; break; case '|': c1 = GETC(); if(c1 == '|') return LOROR; if(c1 == '=') return LORE; break; case '^': c1 = GETC(); if(c1 == '=') return LXORE; break; default: return c; } peekc = c1; return c; talph: /* * cp is set to symb and some * prefix has been stored */ for(;;) { if(c >= Runeself) { for(c1=0;;) { cp[c1++] = c; if(fullrune(cp, c1)) break; c = GETC(); } cp += c1; c = GETC(); continue; } if(!isalnum(c) && c != '_') break; *cp++ = c; c = GETC(); } *cp = 0; if(debug['L']) print("%L %s\n", lineno, symb); peekc = c; s = lookup(); if(s->macro) { if(s->ref) s->ref->class = CMACRO; newio(); cp = ionext->b; macexpand(s, cp); pushio(); ionext->link = iostack; iostack = ionext; fi.p = cp; fi.c = strlen(cp); if(peekc != IGN) { cp[fi.c++] = peekc; cp[fi.c] = 0; peekc = IGN; } goto l0; } yylval.sym = s; if(s->class == CTYPEDEF) return LTYPE; if(s->lexical == LNAME) return LNAME; if(s->ref) s->ref->class = CLEXICAL; return s->lexical; tnum: c1 = 0; cp = symb; if(c != '0') { c1 |= Numdec; for(;;) { *cp++ = c; c = GETC(); if(isdigit(c)) continue; goto dc; } } *cp++ = c; c = GETC(); if(c == 'x' || c == 'X') for(;;) { *cp++ = c; c = GETC(); if(isdigit(c)) continue; if(c >= 'a' && c <= 'f') continue; if(c >= 'A' && c <= 'F') continue; if(cp == symb+2) yyerror("malformed hex constant"); goto ncu; } if(c < '0' || c > '7') goto dc; for(;;) { if(c >= '0' && c <= '7') { *cp++ = c; c = GETC(); continue; } goto ncu; } dc: if(c == '.') goto casedot; if(c == 'e' || c == 'E') goto casee; ncu: *cp = 0; if(c == 'U' || c == 'u') { c = GETC(); c1 |= Numuns; if(c == 'L' || c == 'l') { c = GETC(); c1 |= Numlong; } } else if(c == 'L' || c == 'l') { c = GETC(); c1 |= Numlong; if(c == 'U' || c == 'u') { c = GETC(); c1 |= Numuns; } else if(c == 'L' || c == 'l') { c = GETC(); c1 |= Numvlong; } } peekc = c; if(c1 & Numvlong) { if(FPCHIP) { if(mpatof(symb, &yylval.dval)) { yyerror("overflow in vl constant"); yylval.dval = 0; } return LVLCONST; } if(!fperror) { yyerror("compiler cannot interpret vl constants"); fperror = 1; } yylval.lval = 1; return LCONST; } if(mpatol(symb, &yylval.lval)) yyerror("overflow in integer constant"); if(tint == types[TSHORT]) { /* does it fit in a short */ if(!ovflo(yylval.lval, TSHORT)) goto nret; /* does it fit in a ushort */ if(!ovflo(yylval.lval, TUSHORT)) { if(c1 & (Numuns|Numlong)) goto nret; if(c1 & Numdec) { c1 |= Numlong; goto ndiag; } c1 |= Numuns; goto nret; } /* does it fit in a long */ if(!ovflo(yylval.lval, TLONG)) { if(c1 & Numlong) goto nret; c1 |= Numlong; goto ndiag; } /* then a ulong */ if(c1 & Numlong) { if(c1 & Numuns) goto nret; c1 |= Numuns; if(c1 & Numdec) goto ndiag; goto nret; } c1 |= Numuns|Numlong; goto ndiag; } /* does it fit in a long */ if(!ovflo(yylval.lval, TLONG)) goto nret; /* then a ulong */ if(c1 & Numuns) goto nret; c1 |= Numuns; if(c1 & Numdec) goto ndiag; goto nret; casedot: for(;;) { *cp++ = c; c = GETC(); if(!isdigit(c)) break; } if(c != 'e' && c != 'E') goto caseout; casee: *cp++ = 'e'; c = GETC(); if(c == '+' || c == '-') { *cp++ = c; c = GETC(); } if(!isdigit(c)) yyerror("malformed fp constant exponent"); while(isdigit(c)) { *cp++ = c; c = GETC(); } caseout: if(c == 'L' || c == 'l') { c = GETC(); c1 |= Numlong; } else if(c == 'F' || c == 'f') { c = GETC(); c1 |= Numflt; } *cp = 0; peekc = c; if(FPCHIP) { if(mpatof(symb, &yylval.dval)) { yyerror("overflow in float constant"); yylval.dval = 0; } if(c1 & Numflt) return LFCONST; return LDCONST; } if(!fperror) { yyerror("compiler cannot interpret fp constants"); fperror = 1; } yylval.lval = 1; return LCONST; ndiag: nearln = lineno; warn(Z, "constant promotion"); nret: if(c1 & Numlong) { if(c1 & Numuns) return LULCONST; return LLCONST; } if(c1 & Numuns) return LUCONST; return LCONST; } int getc(void) { int c; if(peekc != IGN) { c = peekc; peekc = IGN; } else c = GETC(); if(c == '\n') lineno++; if(c == EOF) { yyerror("End of file"); errorexit(); } return c; } long getr(void) { int c, i; char str[UTFmax+1]; Rune rune; c = getc(); if(c < Runeself) return c; i = 0; str[i++] = c; loop: c = getc(); str[i++] = c; if(!fullrune(str, i)) goto loop; c = chartorune(&rune, str); if(rune == Runeerror && c == 1) { nearln = lineno; diag(Z, "illegal rune in string"); for(c=0; c0; i--) { c = getc(); if(c >= '0' && c <= '7') { l = l*16 + c-'0'; continue; } if(c >= 'a' && c <= 'f') { l = l*16 + c-'a' + 10; continue; } if(c >= 'A' && c <= 'F') { l = l*16 + c-'A' + 10; continue; } unget(c); break; } if(escflg) l |= ESC; return l; } if(c >= '0' && c <= '7') { /* * note this is not ansi, * supposed to only accept 3 oct */ i = 2; if(longflg) i = 5; l = c - '0'; for(; i>0; i--) { c = getc(); if(c >= '0' && c <= '7') { l = l*8 + c-'0'; continue; } unget(c); } if(escflg) l |= ESC; return l; } switch(c) { case '\n': goto loop; case 'n': return '\n'; case 't': return '\t'; case 'b': return '\b'; case 'r': return '\r'; case 'f': return '\f'; case 'a': return '\a'; case 'v': return '\v'; } return c; } struct { char *name; ushort lexical; } itab[] = { "auto", LAUTO, "break", LBREAK, "case", LCASE, "char", LCHAR, "const", LCONSTNT, "continue", LCONTINUE, "default", LDEFAULT, "do", LDO, "double", LDOUBLE, "else", LELSE, "enum", LENUM, "extern", LEXTERN, "float", LFLOAT, "for", LFOR, "goto", LGOTO, "if", LIF, "int", LINT, "long", LLONG, "register", LREGISTER, "return", LRETURN, "SET", LSET, "short", LSHORT, "signed", LSIGNED, "sizeof", LSIZEOF, "static", LSTATIC, "struct", LSTRUCT, "switch", LSWITCH, "typedef", LTYPEDEF, "union", LUNION, "unsigned", LUNSIGNED, "USED", LUSED, "void", LVOID, "volatile", LVOLATILE, "while", LWHILE, 0 }; void cinit(void) { Sym *s; int i; Type *t; nerrors = 0; lineno = 1; iostack = I; iofree = I; peekc = IGN; nhunk = 0; for(i=0; ilexical = itab[i].lexical; } blockno = 0; autobn = 0; autoffset = 0; types[TXXX] = T; types[TCHAR] = typ(TCHAR, T); types[TUCHAR] = typ(TUCHAR, T); types[TSHORT] = typ(TSHORT, T); types[TUSHORT] = typ(TUSHORT, T); types[TLONG] = typ(TLONG, T); types[TULONG] = typ(TULONG, T); types[TVLONG] = typ(TVLONG, T); types[TFLOAT] = typ(TFLOAT, T); types[TDOUBLE] = typ(TDOUBLE, T); types[TVOID] = typ(TVOID, T); types[TENUM] = typ(TENUM, T); types[TFUNC] = typ(TFUNC, types[TLONG]); types[TIND] = typ(TIND, types[TVOID]); tint = types[TLONG]; /* assuming long, ginit knows */ tuint = types[TULONG]; t = typ(TARRAY, types[TCHAR]); t->width = 0; symstring = slookup(".string"); symstring->class = CSTATIC; symstring->type = t; t = typ(TARRAY, types[TCHAR]); t->width = 0; nodproto = new(OPROTO, Z, Z); dclstack = D; fmtinstall('O', Oconv); fmtinstall('T', Tconv); fmtinstall('F', Fconv); fmtinstall('L', Lconv); fmtinstall('Q', Qconv); fmtinstall('|', VBconv); } int filbuf(void) { Io *i; loop: i = iostack; if(i == I) return EOF; if(i->f < 0) goto pop; fi.c = read(i->f, i->b, BUFSIZ) - 1; if(fi.c < 0) { close(i->f); while((ulong)hunk & 3) { hunk++; nhunk--; } linehist(0, 0); goto pop; } fi.p = i->b + 1; return i->b[0] & 0xff; pop: iostack = i->link; i->link = iofree; iofree = i; i = iostack; if(i == I) return EOF; fi.p = i->p; fi.c = i->c; if(--fi.c < 0) goto loop; return *fi.p++ & 0xff; } int Oconv(void *o, int f1, int f2, int f3, int chr) { int a; USED(chr); a = *(int*)o; if(a < OXXX || a > OEND) strconv(xOconv(a), f1, f2, f3); else strconv(onames[a], f1, f2, f3); return sizeof(a); } int Lconv(void *o, int f1, int f2, int f3, int chr) { char str[STRINGSZ], s[STRINGSZ]; Hist *h; struct { Hist* incl; /* start of this include file */ long idel; /* delta line number to apply to include */ Hist* line; /* start of this #line directive */ long ldel; /* delta line number to apply to #line */ } a[HISTSZ]; long l, d; int i, n; USED(chr); l = *(long*)o; n = 0; for(h = hist; h != H; h = h->link) { if(l < h->line) break; if(h->name) { if(h->offset != 0) { /* #line directive, not #pragma */ if(n > 0 && n < HISTSZ && h->offset >= 0) { a[n-1].line = h; a[n-1].ldel = h->line - h->offset + 1; } } else { if(n < HISTSZ) { /* beginning of file */ a[n].incl = h; a[n].idel = h->line; a[n].line = 0; } n++; } continue; } n--; if(n > 0 && n < HISTSZ) { d = h->line - a[n].incl->line; a[n-1].ldel += d; a[n-1].idel += d; } } if(n > HISTSZ) n = HISTSZ; str[0] = 0; for(i=n-1; i>=0; i--) { if(i != n-1) { if(f3) break; strcat(str, " "); } if(a[i].line) sprint(s, "%s:%ld[%s:%ld]", a[i].line->name, l-a[i].ldel+1, a[i].incl->name, l-a[i].idel+1); else sprint(s, "%s:%ld", a[i].incl->name, l-a[i].idel+1); if(strlen(s)+strlen(str) >= STRINGSZ-10) break; strcat(str, s); l = a[i].incl->line - 1; /* now print out start of this file */ } if(n == 0) strcat(str, ""); strconv(str, f1, f2, f3); return sizeof(l); } int Tconv(void *o, int f1, int f2, int f3, int chr) { char str[STRINGSZ], s[STRINGSZ]; Type *t, *t1; int et; USED(chr); str[0] = 0; for(t = *(Type**)o; t != T; t = t->link) { et = t->etype; if(str[0]) strcat(str, " "); sprint(s, "%s", tnames[et]); if(strlen(str) + strlen(s) < STRINGSZ) strcat(str, s); if(et == TFUNC && (t1 = t->down)) { sprint(s, "(%T", t1); strcat(str, s); while(t1 = t1->down) { sprint(s, ", %T", t1); strcat(str, s); } strcat(str, ")"); } if(et == TARRAY) { sprint(s, "[%ld]", t->width); strcat(str, s); } if(t->nbits) { sprint(s, " %d:%d", t->shift, t->nbits); if(strlen(str) + strlen(s) < STRINGSZ) strcat(str, s); } if(typesu[et]) { if(t->tag) { strcat(str, " "); strcat(str, t->tag->name); } else strcat(str, " {}"); break; } } strconv(str, f1, f2, f3); return sizeof(t); } int Fconv(void *o, int f1, int f2, int f3, int chr) { char str[STRINGSZ]; Node *n; USED(chr); n = *(Node**)o; strcpy(str, ""); if(n != Z && (n->op == ONAME || n->op == ODOT)) strcpy(str, n->sym->name); strconv(str, f1, f2, f3); return sizeof(n); } int Qconv(void *o, int f1, int f2, int f3, int chr) { char str[STRINGSZ], *s; long b; int i; USED(chr); str[0] = 0; for(b = *(long*)o; b;) { i = bitno(b); if(str[0]) strcat(str, " "); s = qnames[i]; if(strlen(str) + strlen(s) + 1 >= STRINGSZ) break; strcat(str, s); b &= ~(1L << i); } strconv(str, f1, f2, f3); return sizeof(b); } int VBconv(void *o, int f1, int f2, int f3, int chr) { char str[STRINGSZ]; int i, n, t, pc; extern printcol; USED(chr); n = *(int*)o; pc = printcol; i = 0; while(pc < n) { t = (pc+8) & ~7; if(t <= n) { str[i++] = '\t'; pc = t; continue; } str[i++] = ' '; pc++; } str[i] = 0; strconv(str, f1, f2, f3); return sizeof(n); } /* * fake malloc */ void* malloc(long n) { void *p; while(n & 3) n++; while(nhunk < n) gethunk(); p = hunk; nhunk -= n; hunk += n; return p; } void free(void *p) { USED(p); } void* calloc(long m, long n) { void *p; n *= m; p = malloc(n); memset(p, 0, n); return p; } void* realloc(void *p, long n) { USED(p); USED(n); fprint(2, "realloc called\n"); abort(); return 0; }