// Inferno utils/cc/lex.c // http://code.google.com/p/inferno-os/source/browse/utils/cc/lex.c // // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) // Portions Copyright © 1997-1999 Vita Nuova Limited // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) // Portions Copyright © 2004,2006 Bruce Ellis // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others // Portions Copyright © 2009 The Go Authors. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. #include #include "cc.h" #include "y.tab.h" #ifndef CPP #define CPP "cpp" #endif int systemtype(int sys) { #ifdef _WIN32 return sys&Windows; #else return sys&Plan9; #endif } int pathchar(void) { return '/'; } /* * known debug flags * -a acid declaration output * -A !B * -B non ANSI * -d print declarations * -D name define * -F format specification check * -G print pgen stuff * -g print cgen trees * -i print initialization * -I path include * -l generate little-endian code * -L print every NAME symbol * -M constant multiplication * -m print add/sub/mul trees * -n print acid or godefs to file (%.c=%.acid) (with -a or -aa) * -o file output file * -p use standard cpp ANSI preprocessor (not on windows) * -p something with peepholes * -q print equivalent Go code for variables and types (lower-case identifiers) * -Q print equivalent Go code for variables and types (upper-case identifiers) * -r print registerization * -s print structure offsets (with -a or -aa) * -S print assembly * -t print type trees * -V enable void* conversion warnings * -v verbose printing * -w print warnings * -X abort on error * -. Inhibit search for includes in source directory */ void usage(void) { print("usage: %cc [options] file.c...\n", thechar); flagprint(1); errorexit(); } void dospim(void) { thechar = '0'; thestring = "spim"; } char **defs; int ndef; void dodef(char *p) { if(ndef%8 == 0) defs = allocn(defs, ndef*sizeof(char *), 8*sizeof(char *)); defs[ndef++] = p; dodefine(p); } void main(int argc, char *argv[]) { int c; char *p; // Allow GOARCH=thestring or GOARCH=thestringsuffix, // but not other values. p = getgoarch(); if(strncmp(p, thestring, strlen(thestring)) != 0) sysfatal("cannot use %cc with GOARCH=%s", thechar, p); if(strcmp(p, "amd64p32") == 0) // must be before cinit ewidth[TIND] = 4; nacl = strcmp(getgoos(), "nacl") == 0; if(nacl) flag_largemodel = 1; quotefmtinstall(); // before cinit, which overrides %Q linkarchinit(); ctxt = linknew(thelinkarch); ctxt->diag = yyerror; ctxt->bso = &bstdout; Binit(&bstdout, 1, OWRITE); ensuresymb(NSYMB); memset(debug, 0, sizeof(debug)); tinit(); cinit(); ginit(); arginit(); fmtstrinit(&pragcgobuf); tufield = simplet((1L<etype) | BUNSIGNED); ndef = 0; defs = nil; outfile = 0; setinclude("."); flagcount("+", "pass -+ to preprocessor", &debug['+']); flagcount(".", "pass -. to preprocessor", &debug['.']); flagcount("<", "debug shift", &debug['<']); flagcount("A", "debug alignment", &debug['A']); flagcount("B", "allow pre-ANSI code", &debug['B']); if(thechar == '5') flagcount("C", "debug constant propagation", &debug['C']); flagfn1("D", "name[=value]: add #define", dodef); flagcount("F", "enable print format checks", &debug['F']); if(thechar == '5') flagcount("H", "debug shift propagation", &debug['H']); flagfn1("I", "dir: add dir to include path", setinclude); flagcount("L", "debug lexer", &debug['L']); flagcount("M", "debug move generation", &debug['M']); flagcount("N", "disable optimizations", &debug['N']); flagcount("P", "debug peephole optimizer", &debug['P']); flagcount("Q", "print exported Go definitions", &debug['Q']); flagcount("R", "debug register optimizer", &debug['R']); flagcount("S", "print assembly", &debug['S']); flagcount("T", "enable type signatures", &debug['T']); flagcount("V", "enable pointer type checks", &debug['V']); flagcount("W", "debug switch generation", &debug['W']); flagcount("X", "abort on error", &debug['X']); flagcount("Y", "debug index generation", &debug['Y']); flagcount("Z", "skip code generation", &debug['Z']); flagcount("a", "print acid definitions", &debug['a']); flagcount("c", "debug constant evaluation", &debug['c']); flagcount("d", "debug declarations", &debug['d']); flagcount("e", "debug macro expansion", &debug['e']); flagcount("f", "debug pragmas", &debug['f']); flagcount("g", "debug code generation", &debug['g']); flagcount("i", "debug initialization", &debug['i']); if(thechar == 'v') flagfn0("l", "little-endian mips mode", dospim); flagcount("m", "debug multiplication", &debug['m']); flagcount("n", "print acid/Go to file, not stdout", &debug['n']); flagstr("o", "file: set output file", &outfile); flagcount("p", "invoke C preprocessor", &debug['p']); flagcount("q", "print Go definitions", &debug['q']); flagcount("s", "print #define assembly offsets", &debug['s']); flagcount("t", "debug code generation", &debug['t']); flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath); flagcount("w", "enable warnings", &debug['w']); flagcount("v", "increase debug verbosity", &debug['v']); if(thechar == '6') flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel); flagparse(&argc, &argv, usage); ctxt->debugasm = debug['S']; if(argc < 1 && outfile == 0) usage(); if(argc > 1){ print("can't compile multiple files\n"); errorexit(); } if(argc == 0) c = compile("stdin", defs, ndef); else c = compile(argv[0], defs, ndef); Bflush(&bstdout); if(c) errorexit(); exits(0); } int compile(char *file, char **defs, int ndef) { char *ofile; char *p, **av, opt[256]; int i, c, fd[2]; static int first = 1; ofile = alloc(strlen(file)+10); strcpy(ofile, file); p = utfrrune(ofile, pathchar()); if(p) { *p++ = 0; if(!debug['.']) include[0] = strdup(ofile); } else p = ofile; if(outfile == 0) { outfile = p; if(outfile) { if(p = utfrrune(outfile, '.')) if(p[1] == 'c' && p[2] == 0) p[0] = 0; p = utfrune(outfile, 0); if(debug['a'] && debug['n']) strcat(p, ".acid"); else if((debug['q'] || debug['Q']) && debug['n']) strcat(p, ".go"); else { p[0] = '.'; p[1] = thechar; p[2] = 0; } } else outfile = "/dev/null"; } if (first) Binit(&diagbuf, 1, OWRITE); /* * if we're writing acid to standard output, don't keep scratching * outbuf. */ if((debug['a'] || debug['q'] || debug['Q']) && !debug['n']) { if (first) { outfile = 0; Binit(&outbuf, dup(1, -1), OWRITE); dup(2, 1); } } else { c = create(outfile, OWRITE, 0664); if(c < 0) { diag(Z, "cannot open %s - %r", outfile); outfile = 0; errorexit(); } Binit(&outbuf, c, OWRITE); outfile = strdup(outfile); } newio(); first = 0; /* Use an ANSI preprocessor */ if(debug['p']) { if(systemtype(Windows)) { diag(Z, "-p option not supported on windows"); errorexit(); } if(access(file, AREAD) < 0) { diag(Z, "%s does not exist", file); errorexit(); } if(pipe(fd) < 0) { diag(Z, "pipe failed"); errorexit(); } switch(fork()) { case -1: diag(Z, "fork failed"); errorexit(); case 0: close(fd[0]); dup(fd[1], 1); close(fd[1]); av = alloc((ndef+ninclude+5)*sizeof(char *)); av[0] = CPP; i = 1; if(debug['.']){ sprint(opt, "-."); av[i++] = strdup(opt); } if(debug['+']) { sprint(opt, "-+"); av[i++] = strdup(opt); } for(c = 0; c < ndef; c++) av[i++] = smprint("-D%s", defs[c]); for(c = 0; c < ninclude; c++) av[i++] = smprint("-I%s", include[c]); if(strcmp(file, "stdin") != 0) av[i++] = file; av[i] = 0; if(debug['p'] > 1) { for(c = 0; c < i; c++) fprint(2, "%s ", av[c]); fprint(2, "\n"); } exec(av[0], av); fprint(2, "can't exec C preprocessor %s: %r\n", CPP); errorexit(); default: close(fd[1]); newfile(file, fd[0]); break; } } else { if(strcmp(file, "stdin") == 0) newfile(file, 0); else newfile(file, -1); } yyparse(); if(!debug['a'] && !debug['q'] && !debug['Q']) gclean(); return nerrors; } void errorexit(void) { Bflush(&bstdout); 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 int pushdepth = 0; i = iofree; if(i == I) { pushdepth++; if(pushdepth > 1000) { yyerror("macro/io expansion too deep"); errorexit(); } i = alloc(sizeof(*i)); } else iofree = i->link; i->c = 0; i->f = -1; ionext = i; } void newfile(char *s, int f) { Io *i; if(debug['e']) print("%L: %s\n", lineno, s); i = ionext; i->link = iostack; iostack = i; i->f = f; if(f < 0) i->f = open(s, 0); if(i->f < 0) { yyerror("%cc: %r: %s", thechar, s); errorexit(); } fi.c = 0; linklinehist(ctxt, lineno, s, 0); } Sym* slookup(char *s) { ensuresymb(strlen(s)); strcpy(symb, s); return lookup(); } Sym* lookup(void) { Sym *s; uint32 h; char *p; int c, n; char *r, *w; if((uchar)symb[0] == 0xc2 && (uchar)symb[1] == 0xb7) { // turn leading · into ""· h = strlen(symb); ensuresymb(h+2); memmove(symb+2, symb, h+1); symb[0] = '"'; symb[1] = '"'; } for(r=w=symb; *r; r++) { // turn · (U+00B7) into . // turn ∕ (U+2215) into / if((uchar)*r == 0xc2 && (uchar)*(r+1) == 0xb7) { *w++ = '.'; r++; }else if((uchar)*r == 0xe2 && (uchar)*(r+1) == 0x88 && (uchar)*(r+2) == 0x95) { *w++ = '/'; r++; r++; }else *w++ = *r; } *w = '\0'; h = 0; for(p=symb; *p;) { h = h * 3; h += *p++; } n = (p - symb) + 1; h &= 0xffffff; h %= NHASH; c = symb[0]; for(s = hash[h]; s != S; s = s->link) { if(s->name[0] != c) continue; if(strcmp(s->name, symb) == 0) return s; } s = alloc(sizeof(*s)); s->name = alloc(n); memmove(s->name, symb, n); 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->aused = 0; s->sig = SIGNONE; } #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, }; int32 yylex(void) { vlong vv; int32 c, c1, t; 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.vval = convvtox(c, TRUNE); return LUCONST; } if(c == '"') { 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, "\"\""); cp = alloc(0); c1 = 0; /* "..." */ for(;;) { c = escchar('"', 0, 1); if(c == EOF) break; if(c & ESC) { cp = allocn(cp, c1, 1); cp[c1++] = c; } else { rune = c; c = runelen(rune); cp = allocn(cp, c1, c); runetochar(cp+c1, &rune); c1 += c; } } yylval.sval.l = c1; do { cp = allocn(cp, c1, 1); cp[c1++] = 0; } while(c1 & MAXALIGN); yylval.sval.s = cp; return LSTRING; caselq: /* L"..." */ strcpy(symb, "\"L\""); cp = alloc(0); c1 = 0; for(;;) { c = escchar('"', 1, 0); if(c == EOF) break; cp = allocn(cp, c1, sizeof(TRune)); *(TRune*)(cp + c1) = c; c1 += sizeof(TRune); } yylval.sval.l = c1; do { cp = allocn(cp, c1, sizeof(TRune)); *(TRune*)(cp + c1) = 0; c1 += sizeof(TRune); } while(c1 & MAXALIGN); yylval.sval.s = cp; return LLSTRING; case '\'': /* '.' */ c = escchar('\'', 0, 0); if(c == EOF) c = '\''; c1 = escchar('\'', 0, 0); if(c1 != EOF) { yyerror("missing '"); peekc = c1; } vv = c; yylval.vval = convvtox(vv, TUCHAR); if(yylval.vval != vv) yyerror("overflow in character constant: 0x%x", c); else if(c & 0x80){ nearln = lineno; warn(Z, "sign-extended character constant"); } yylval.vval = convvtox(vv, TCHAR); 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 == '/') { for(;;) { c = getr(); if(c == '\n') 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) { 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 || s->class == CTYPESTR) return LTYPE; 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: if((c == 'U' || c == 'u') && !(c1 & Numuns)) { c = GETC(); c1 |= Numuns; goto ncu; } if((c == 'L' || c == 'l') && !(c1 & Numvlong)) { c = GETC(); if(c1 & Numlong) c1 |= Numvlong; c1 |= Numlong; goto ncu; } *cp = 0; peekc = c; if(mpatov(symb, &yylval.vval)) yyerror("overflow in constant"); vv = yylval.vval; if(c1 & Numvlong) { if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) { c = LUVLCONST; t = TUVLONG; goto nret; } c = LVLCONST; t = TVLONG; goto nret; } if(c1 & Numlong) { if((c1 & Numuns) || convvtox(vv, TLONG) < 0) { c = LULCONST; t = TULONG; goto nret; } c = LLCONST; t = TLONG; goto nret; } if((c1 & Numuns) || convvtox(vv, TINT) < 0) { c = LUCONST; t = TUINT; goto nret; } c = LCONST; t = TINT; goto nret; nret: yylval.vval = convvtox(vv, t); if(yylval.vval != vv){ nearln = lineno; warn(Z, "truncated constant: %T %s", types[t], symb); } return c; 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; yylval.dval = strtod(symb, nil); if(isInf(yylval.dval, 1) || isInf(yylval.dval, -1)) { yyerror("overflow in float constant"); yylval.dval = 0; } if(c1 & Numflt) return LFCONST; return LDCONST; } /* * convert a string, s, to vlong in *v * return conversion overflow. * required syntax is [0[x]]d* */ int mpatov(char *s, vlong *v) { vlong n, nn; int c; n = 0; c = *s; if(c == '0') goto oct; while(c = *s++) { if(c >= '0' && c <= '9') nn = n*10 + c-'0'; else goto bad; if(n < 0 && nn >= 0) goto bad; n = nn; } goto out; oct: s++; c = *s; if(c == 'x' || c == 'X') goto hex; while(c = *s++) { if(c >= '0' || c <= '7') nn = n*8 + c-'0'; else goto bad; if(n < 0 && nn >= 0) goto bad; n = nn; } goto out; hex: s++; while(c = *s++) { if(c >= '0' && c <= '9') c += 0-'0'; else if(c >= 'a' && c <= 'f') c += 10-'a'; else if(c >= 'A' && c <= 'F') c += 10-'A'; else goto bad; nn = (uvlong)n*16 + c; if(n < 0 && nn >= 0) goto bad; n = nn; } out: *v = n; return 0; bad: *v = ~0; return 1; } 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; } int32 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; c= Runeself || !isspace(c)) return c; if(c == '\n') { lineno++; return c; } c = GETC(); } } void unget(int c) { peekc = c; if(c == '\n') lineno--; } int32 escchar(int32 e, int longflg, int escflg) { int32 c, l; int i; loop: c = getr(); if(c == '\n') { yyerror("newline in string"); return EOF; } if(c != '\\') { if(c == e) c = EOF; return c; } c = getr(); if(c == 'x') { /* * note this is not ansi, * supposed to only accept 2 hex */ i = 2; if(longflg) i = 6; l = 0; for(; i>0; i--) { c = getc(); if(c >= '0' && c <= '9') { 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 = 8; 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; ushort type; } itab[] = { "auto", LAUTO, 0, "break", LBREAK, 0, "case", LCASE, 0, "char", LCHAR, TCHAR, "const", LCONSTNT, 0, "continue", LCONTINUE, 0, "default", LDEFAULT, 0, "do", LDO, 0, "double", LDOUBLE, TDOUBLE, "else", LELSE, 0, "enum", LENUM, 0, "extern", LEXTERN, 0, "float", LFLOAT, TFLOAT, "for", LFOR, 0, "goto", LGOTO, 0, "if", LIF, 0, "inline", LINLINE, 0, "int", LINT, TINT, "long", LLONG, TLONG, "PREFETCH", LPREFETCH, 0, "register", LREGISTER, 0, "restrict", LRESTRICT, 0, "return", LRETURN, 0, "SET", LSET, 0, "short", LSHORT, TSHORT, "signed", LSIGNED, 0, "signof", LSIGNOF, 0, "sizeof", LSIZEOF, 0, "static", LSTATIC, 0, "struct", LSTRUCT, 0, "switch", LSWITCH, 0, "typedef", LTYPEDEF, 0, "typestr", LTYPESTR, 0, "union", LUNION, 0, "unsigned", LUNSIGNED, 0, "USED", LUSED, 0, "void", LVOID, TVOID, "volatile", LVOLATILE, 0, "while", LWHILE, 0, 0 }; void cinit(void) { Sym *s; int i; Type *t; nerrors = 0; lineno = 1; iostack = I; iofree = I; peekc = IGN; nhunk = 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[TINT] = typ(TINT, T); types[TUINT] = typ(TUINT, T); types[TLONG] = typ(TLONG, T); types[TULONG] = typ(TULONG, T); types[TVLONG] = typ(TVLONG, T); types[TUVLONG] = typ(TUVLONG, 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[TINT]); types[TIND] = typ(TIND, types[TVOID]); for(i=0; ilexical = itab[i].lexical; if(itab[i].type != 0) s->type = types[itab[i].type]; } blockno = 0; autobn = 0; autoffset = 0; 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', FNconv); fmtinstall('L', Lconv); fmtinstall('Q', Qconv); fmtinstall('|', VBconv); fmtinstall('U', Uconv); fmtinstall('B', Bconv); } 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); linklinehist(ctxt, lineno, nil, 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(Fmt *fp) { int a; a = va_arg(fp->args, int); if(a < OXXX || a > OEND) return fmtprint(fp, "***badO %d***", a); return fmtstrcpy(fp, onames[a]); } int Lconv(Fmt *fp) { return linklinefmt(ctxt, fp); } int Tconv(Fmt *fp) { char str[STRINGSZ+20], s[STRINGSZ+20]; Type *t, *t1; int et; int32 n; str[0] = 0; for(t = va_arg(fp->args, Type*); t != T; t = t->link) { et = t->etype; if(str[0]) strcat(str, " "); if(t->garb&~GINCOMPLETE) { sprint(s, "%s ", gnames[t->garb&~GINCOMPLETE]); if(strlen(str) + strlen(s) < STRINGSZ) strcat(str, s); } sprint(s, "%s", tnames[et]); if(strlen(str) + strlen(s) < STRINGSZ) strcat(str, s); if(et == TFUNC && (t1 = t->down)) { sprint(s, "(%T", t1); if(strlen(str) + strlen(s) < STRINGSZ) strcat(str, s); while(t1 = t1->down) { sprint(s, ", %T", t1); if(strlen(str) + strlen(s) < STRINGSZ) strcat(str, s); } if(strlen(str) + strlen(s) < STRINGSZ) strcat(str, ")"); } if(et == TARRAY) { n = t->width; if(t->link && t->link->width) n /= t->link->width; sprint(s, "[%d]", n); if(strlen(str) + strlen(s) < STRINGSZ) 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, " "); if(strlen(str) + strlen(t->tag->name) < STRINGSZ) strcat(str, t->tag->name); } else strcat(str, " {}"); break; } } return fmtstrcpy(fp, str); } int FNconv(Fmt *fp) { char *str; Node *n; n = va_arg(fp->args, Node*); str = ""; if(n != Z && (n->op == ONAME || n->op == ODOT || n->op == OELEM)) str = n->sym->name; return fmtstrcpy(fp, str); } int Qconv(Fmt *fp) { char str[STRINGSZ+20], *s; int32 b; int i; str[0] = 0; for(b = va_arg(fp->args, int32); b;) { i = bitno(b); if(str[0]) strcat(str, " "); s = qnames[i]; if(strlen(str) + strlen(s) >= STRINGSZ) break; strcat(str, s); b &= ~(1L << i); } return fmtstrcpy(fp, str); } int VBconv(Fmt *fp) { char str[STRINGSZ]; int i, n, t, pc; n = va_arg(fp->args, int); pc = 0; /* BUG: was printcol */ i = 0; while(pc < n) { t = (pc+4) & ~3; if(t <= n) { str[i++] = '\t'; pc = t; continue; } str[i++] = ' '; pc++; } str[i] = 0; return fmtstrcpy(fp, str); } int Bconv(Fmt *fp) { char str[STRINGSZ], ss[STRINGSZ], *s; Bits bits; int i; str[0] = 0; bits = va_arg(fp->args, Bits); while(bany(&bits)) { i = bnum(bits); if(str[0]) strcat(str, " "); if(var[i].sym == nil) { sprint(ss, "$%lld", var[i].offset); s = ss; } else s = var[i].sym->name; if(strlen(str) + strlen(s) + 1 >= STRINGSZ) break; strcat(str, s); bits.b[i/32] &= ~(1L << (i%32)); } return fmtstrcpy(fp, str); } void setinclude(char *p) { int i; if(*p != 0) { for(i=1; i < ninclude; i++) if(strcmp(p, include[i]) == 0) return; if(ninclude%8 == 0) include = allocn(include, ninclude*sizeof(char *), 8*sizeof(char *)); include[ninclude++] = p; } } void* alloc(int32 n) { void *p; p = malloc(n); if(p == nil) { print("alloc out of mem\n"); exits("alloc: out of mem"); } memset(p, 0, n); return p; } void* allocn(void *p, int32 n, int32 d) { if(p == nil) return alloc(n+d); p = realloc(p, n+d); if(p == nil) { print("allocn out of mem\n"); exits("allocn: out of mem"); } if(d > 0) memset((char*)p+n, 0, d); return p; } void ensuresymb(int32 n) { if(symb == nil) { symb = alloc(NSYMB+1); nsymb = NSYMB; } if(n > nsymb) { symb = allocn(symb, nsymb, n+1-nsymb); nsymb = n; } }