diff options
Diffstat (limited to 'src/cmd/cc/lex.c')
-rw-r--r-- | src/cmd/cc/lex.c | 1561 |
1 files changed, 1561 insertions, 0 deletions
diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c new file mode 100644 index 000000000..9fb2f9e4d --- /dev/null +++ b/src/cmd/cc/lex.c @@ -0,0 +1,1561 @@ +// 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 <u.h> +#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 +main(int argc, char *argv[]) +{ + char **defs, *p; + int c, ndef; + + ensuresymb(NSYMB); + memset(debug, 0, sizeof(debug)); + tinit(); + cinit(); + ginit(); + arginit(); + + tufield = simplet((1L<<tfield->etype) | BUNSIGNED); + ndef = 0; + defs = nil; + outfile = 0; + setinclude("."); + ARGBEGIN { + default: + c = ARGC(); + if(c >= 0 && c < sizeof(debug)) + debug[c]++; + break; + + case 'l': /* for little-endian mips */ + if(thechar != 'v'){ + print("can only use -l with vc"); + errorexit(); + } + thechar = '0'; + thestring = "spim"; + break; + + case 'o': + outfile = ARGF(); + break; + + case 'D': + p = ARGF(); + if(p) { + if(ndef%8 == 0) + defs = allocn(defs, ndef*sizeof(char *), + 8*sizeof(char *)); + defs[ndef++] = p; + dodefine(p); + } + break; + + case 'I': + p = ARGF(); + setinclude(p); + break; + } ARGEND + if(argc < 1 && outfile == 0) { + print("usage: %cc [-options] files\n", thechar); + errorexit(); + } + 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); + + 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) +{ + 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; + linehist(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] = '"'; + } + + // turn · into . + for(r=w=symb; *r; r++) { + if((uchar)*r == 0xc2 && (uchar)*(r+1) == 0xb7) { + *w++ = '.'; + 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, TUSHORT); + 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, "\"<string>\""); + 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<string>\""); + cp = alloc(0); + c1 = 0; + for(;;) { + c = escchar('"', 1, 0); + if(c == EOF) + break; + cp = allocn(cp, c1, sizeof(ushort)); + *(ushort*)(cp + c1) = c; + c1 += sizeof(ushort); + } + yylval.sval.l = c1; + do { + cp = allocn(cp, c1, sizeof(ushort)); + *(ushort*)(cp + c1) = 0; + c1 += sizeof(ushort); + } 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 = 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<i; c++) + print(" %.2x", *(uchar*)(str+c)); + print("\n"); + } + return rune; +} + +int +getnsc(void) +{ + int c; + + if(peekc != IGN) { + c = peekc; + peekc = IGN; + } else + c = GETC(); + for(;;) { + if(!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 = 4; + 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 = 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; + 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, + "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; i<NHASH; i++) + hash[i] = S; + for(i=0; itab[i].name; i++) { + s = slookup(itab[i].name); + s->lexical = 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; + + pathname = allocn(pathname, 0, 100); + if(getwd(pathname, 99) == 0) { + pathname = allocn(pathname, 100, 900); + if(getwd(pathname, 999) == 0) + strcpy(pathname, "/???"); + } + + fmtinstall('O', Oconv); + fmtinstall('T', Tconv); + fmtinstall('F', FNconv); + fmtinstall('L', Lconv); + fmtinstall('Q', Qconv); + fmtinstall('|', VBconv); + fmtinstall('U', Uconv); +} + +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); + 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(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) +{ + char str[STRINGSZ], s[STRINGSZ]; + Hist *h; + struct + { + Hist* incl; /* start of this include file */ + int32 idel; /* delta line number to apply to include */ + Hist* line; /* start of this #line directive */ + int32 ldel; /* delta line number to apply to #line */ + } a[HISTSZ]; + int32 l, d; + int i, n; + + l = va_arg(fp->args, int32); + 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(fp->flags & ~(FmtWidth|FmtPrec)) /* BUG ROB - was f3 */ + break; + strcat(str, " "); + } + if(a[i].line) + snprint(s, STRINGSZ, "%s:%d[%s:%d]", + a[i].line->name, l-a[i].ldel+1, + a[i].incl->name, l-a[i].idel+1); + else + snprint(s, STRINGSZ, "%s:%d", + 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, "<eof>"); + return fmtstrcpy(fp, str); +} + +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 = "<indirect>"; + 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); +} + +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; + } +} |