diff options
Diffstat (limited to 'utils/c2l/lex.c')
| -rw-r--r-- | utils/c2l/lex.c | 1675 |
1 files changed, 1675 insertions, 0 deletions
diff --git a/utils/c2l/lex.c b/utils/c2l/lex.c new file mode 100644 index 00000000..5701dd99 --- /dev/null +++ b/utils/c2l/lex.c @@ -0,0 +1,1675 @@ +#include "cc.h" +#include "y.tab.h" + +#ifndef CPP +#define CPP "/bin/cpp" +#endif + +static int ansip; + +void +main(int argc, char *argv[]) +{ + char *defs[50], *p; + int nproc, nout, status, i, c, ndef; + + tinit(); + cinit(); + ginit(); + arginit(); + + tufield = simplet((1L<<tfield->etype) | BUNSIGNED); + ndef = 0; + include[ninclude++] = "."; + strings = 1; + passes = 1; + + ARGBEGIN { + default: + break; + + case 'p': + ansip = 1; + break; + + case 'D': + p = ARGF(); + if(p) { + defs[ndef++] = p; + dodefine(p); + } + break; + + case 'I': + p = ARGF(); + setinclude(p); + break; + + case 'm': + domod = 1; + break; + + case 'i': + doinc = 1; + break; + + case 'l': + doloc = 1; + break; + + case 'c': + justcode = 1; + break; + + case 'v': + comm = 1; + break; + + case 's': + strings = 0; + break; + + case 'S': + strings = 2; + break; + + case 'M': + inmain = 1; + break; + + case 'q': + passes = 0; + break; + + case 'a': + doaddr = 1; + break; + + case 'A': + doaddr = 1; + doalladdr = 1; + break; + + } ARGEND + + if(doinc) + domod = doloc = 0; + + linit(); + + if(argc != 1) { + print("usage: c2l [-options] file\n"); + errorexit(); + } + if(argc > 1 && systemtype(Windows)){ + print("can't compile multiple files on windows\n"); + errorexit(); + } + if(argc > 1 && !systemtype(Windows)) { + nproc = 1; + if(p = getenv("NPROC")) + nproc = atol(p); /* */ + c = 0; + nout = 0; + for(;;) { + while(nout < nproc && argc > 0) { + i = myfork(); + if(i < 0) { + i = mywait(&status); + if(i < 0) { + print("cannot create a process\n"); + errorexit(); + } + if(status) + c++; + nout--; + continue; + } + if(i == 0) { + fprint(2, "%s:\n", *argv); + if (compile(*argv, defs, ndef)) + errorexit(); + exits(0); + } + nout++; + argc--; + argv++; + } + i = mywait(&status); + if(i < 0) { + if(c) + errorexit(); + exits(0); + } + if(status) + c++; + nout--; + } + } + + 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[200], incfile[20]; + char *p, *av[100], opt[256]; + int i, c, fd[2]; + + strcpy(ofile, file); + p = utfrrune(ofile, pathchar()); + if(p) { + *p++ = 0; + include[0] = strdup(ofile); + } else + p = ofile; + + USED(p); + if(p = getenv("INCLUDE")) { + setinclude(p); + } else { + if(systemtype(Plan9)) { + sprint(incfile, "/%s/include", thestring); + setinclude(strdup(incfile)); + setinclude("/sys/include"); + } + } + newio(); + + /* Use an ANSI preprocessor */ + if(ansip) { + if(systemtype(Windows)) { + diag(Z, "-p option not supported on windows"); + errorexit(); + } + if(mypipe(fd) < 0) { + diag(Z, "pipe failed"); + errorexit(); + } + switch(myfork()) { + case -1: + diag(Z, "fork failed"); + errorexit(); + case 0: + close(fd[0]); + mydup(fd[1], 1); + close(fd[1]); + av[0] = CPP; + i = 1; + for(c = 0; c < ndef; c++) { + sprint(opt, "-D%s", defs[c]); + av[i++] = strdup(opt); + } + for(c = 0; c < ninclude; c++) { + sprint(opt, "-I%s", include[c]); + av[i++] = strdup(opt); + } + if(strcmp(file, "stdin") != 0) + av[i++] = file; + av[i] = 0; + if(0) { + for(c = 0; c < i; c++) + fprint(2, "%s ", av[c]); + print("\n"); + } + myexec(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); + } + + clbegin(); + yyparse(); + clend(); + newsec(0); + return nerrors; +} + +void +errorexit(void) +{ + 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(); + } + 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(0) + 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("c2l: %r: %s", s); + errorexit(); + } + fi.c = 0; + linehist(s, 0); + outpush(s); +} + +Sym* +slookup(char *s) +{ + + strcpy(symb, s); + return lookup(); +} + +Sym* +lookup(void) +{ + static Sym zsym; + Sym *s; + ulong h; + char *p; + int c, n; + + h = 0; + for(p=symb; *p;) { + h = h * 3; + h += *p++; + } + n = (p - symb) + 1; + if((long)h < 0) + h = ~h; + 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 = zsym; + s->name = alloc(n); + memmove(s->name, symb, n); + + strcpy(s->name, symb); + s->link = hash[h]; + hash[h] = s; + syminit(s); + + return s; +} + +void +syminit(Sym *s) +{ + s->lexical = LNAME; + s->type = T; + s->suetag = T; + s->class = CXXX; + s->lname = s->mod = nil; + s->lineno = lineno; + s->tenum = T; +} + +#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, +}; + +static int ypeek = 0; + +long +yylex(void) +{ + vlong vv; + 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.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%lx", c); + else + if(c & 0x80) + warn(Z, "sign-extended character constant"); + yylval.vval = convvtox(vv, TCHAR); + return LCHARACTER; + + case '/': + c1 = GETC(); + if(c1 == '*') { + startcom(lineno); + for(;;) { + c = getr(); + if(c == '*'){ + while(c == '*') { + c = getr(); + if(c == '/'){ + endcom(); + goto l0; + } + addcom('*'); + } + addcom(c); + } + else + addcom(c); + if(c == EOF) { + yyerror("eof in comment"); + errorexit(); + } + } + } + if(c1 == '/') { + startcom(lineno); + for(;;) { + c = getr(); + if(c == '\n'){ + endcom(); + goto l0; + } + addcom(c); + 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(0) + print("%L: %s\n", lineno, symb); + peekc = c; + s = lookup(); + if(s->macro && !ypeek) { + 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; + } + /* outpush(nil); */ + goto l0; + } + yylval.sym = s; + if(s->class == CTYPEDEF) { + if(s->type && typesu[s->type->etype]) + return LCTYPE; + return LSTYPE; + } + return s->lexical; + +tnum: + lastnumbase = KDEC; + 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'){ + lastnumbase = KHEX; + 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; + } + } + else + lastnumbase = KOCT; + if(c < '0' || c > '7'){ + lastnumbase = KDEC; + 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) { + c = LUVLCONST; + goto nret; + } + yylval.vval = convvtox(yylval.vval, TVLONG); + if(yylval.vval < 0) { + c = LUVLCONST; + goto nret; + } + c = LVLCONST; + goto nret; + } + if(c1 & Numlong) { + if(c1 & Numuns) { + c = LULCONST; + goto nret; + } + yylval.vval = convvtox(yylval.vval, TLONG); + if(yylval.vval < 0) { + c = LULCONST; + goto nret; + } + c = LLCONST; + goto nret; + } + if(c1 & Numuns) { + c = LUCONST; + goto nret; + } + yylval.vval = convvtox(yylval.vval, TINT); + if(yylval.vval < 0) { + c = LUCONST; + goto nret; + } + c = LCONST; + goto nret; + +nret: + 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; + if(mpatof(symb, &yylval.dval)) { + yyerror("overflow in float constant"); + yylval.dval = 0; + } + if(c1 & Numflt) + return LFCONST; + return LDCONST; +} + +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; 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(); + } + return 0; +} + +void +unget(int c) +{ + + peekc = c; + if(c == '\n') + lineno--; +} + +long +escchar(long e, int longflg, int escflg) +{ + long 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, + "int", LINT, TINT, + "long", LLONG, TLONG, + "register", LREGISTER, 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, + "union", LUNION, 0, + "unsigned", LUNSIGNED, 0, + "USED", LUSED, 0, + "void", LVOID, TVOID, + "volatile", LVOLATILE, 0, + "while", LWHILE, 0, + "__int64", LVLONG, TVLONG, /* for windows */ + 0 +}; + +static char *litab[] = +{ + "adt", + "alt", + "array", + "big", + "break", + "byte", + "case", + "chan", + "con", + "continue", + "cyclic", + "do", + "else", + "exit", + "fn", + "for", + "hd", + "if", + "implement", + "import", + "include", + "int", + "len", + "list", + "load", + "module", + "nil", + "of", + "or", + "pick", + "real", + "ref", + "return", + "self", + "spawn", + "string", + "tagof", + "tl", + "to", + "type", + "while", + 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]); + stringtype = typ(TSTRING, T); + fdtype = typ(TSTRUCT, typ(TFD, T)); + fdtype->width = 4; + pfdtype = typ(TIND, fdtype); + + 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]; + } + for(i=0; litab[i]; i++){ + s = slookup(litab[i]); + s->lkw = 1; + } + 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(mygetwd(pathname, 99) == 0) { + pathname = allocn(pathname, 100, 900); + if(mygetwd(pathname, 999) == 0) + strcpy(pathname, "/???"); + } + + fmtinstall('f', gfltconv); + fmtinstall('F', gfltconv); + fmtinstall('g', gfltconv); + fmtinstall('G', gfltconv); + fmtinstall('e', gfltconv); + fmtinstall('E', gfltconv); + + fmtinstall('O', Oconv); + fmtinstall('T', Tconv); + fmtinstall('F', FNconv); + 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); + linehist(0, 0); + goto pop; + } + fi.p = i->b + 1; + return i->b[0] & 0xff; + +pop: + if(i->f >= 0) + outpop(lineno); + 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; + char s[STRINGSZ]; + + a = va_arg(fp->args, int); + if(a < OXXX || a > OEND) { + sprint(s, "***badO %d***", a); + fmtstrcpy(fp, s); + } else + fmtstrcpy(fp, onames[a]); + return 0; +} + +int +Lconv(Fmt *fp) +{ + 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; + + l = va_arg(fp->args, long); + 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:%ld[%s:%ld]", + a[i].line->name, l-a[i].ldel+1, + a[i].incl->name, l-a[i].idel+1); + else + snprint(s, STRINGSZ, "%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, "<eof>"); + fmtstrcpy(fp, str); + return 0; +} + +int +Tconv(Fmt *fp) +{ + char str[STRINGSZ+20], s[STRINGSZ+20]; + Type *t, *t1; + int et; + long 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) { + sprint(s, "%s ", gnames[t->garb]); + 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, "[%ld]", 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; + } + } + fmtstrcpy(fp, str); + return 0; +} + +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; + fmtstrcpy(fp, str); + return 0; +} + +int +Qconv(Fmt *fp) +{ + char str[STRINGSZ+20], *s; + long b; + int i; + + str[0] = 0; + for(b = va_arg(fp->args, long); 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); + } + fmtstrcpy(fp, str); + return 0; +} + +int +VBconv(Fmt *fp) +{ + char str[STRINGSZ]; + int i, n, t, pc; + + n = va_arg(fp->args, int); + pc = 0; /*was 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; + fmtstrcpy(fp, str); + return 0; +} + +/* + * real allocs + */ +void* +alloc(long n) +{ + void *p; + + while((ulong)hunk & MAXALIGN) { + hunk++; + nhunk--; + } + while(nhunk < n) + gethunk(); + p = hunk; + nhunk -= n; + hunk += n; + return p; +} + +void* +allocn(void *p, long on, long n) +{ + void *q; + + q = (uchar*)p + on; + if(q != hunk || nhunk < n) { + while(nhunk < on+n) + gethunk(); + memmove(hunk, p, on); + p = hunk; + hunk += on; + nhunk -= on; + } + hunk += n; + nhunk -= n; + return p; +} + +void +setinclude(char *p) +{ + int i; + char *e; + + while(*p != 0) { + e = strchr(p, ' '); + if(e != 0) + *e = '\0'; + + for(i=1; i < ninclude; i++) + if(strcmp(p, include[i]) == 0) + break; + + if(i >= ninclude) + include[ninclude++] = p; + + if(ninclude > nelem(include)) { + diag(Z, "ninclude too small %d", nelem(include)); + exits("ninclude"); + } + + if(e == 0) + break; + p = e+1; + } +} + +static void +doio(char *s) +{ + char *cp; + + newio(); + cp = ionext->b; + strcpy(cp, s); + 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; + } +} + +static void +undoio(void) +{ + Io *i; + + i = iostack; + iostack = i->link; + i->link = iofree; + iofree = i; + i = iostack; + fi.p = i->p; + fi.c = i->c; +} + +/* rm // comment from a string */ +static void +slashslash(char *s) +{ + for( ; *s != '\0'; s++) + if(*s == '/' && s[1] == '/'){ + *s = '\0'; + return; + } +} + +int +iscon(char *str) +{ + int olineno, opeekc, con, tok, t; + Sym *s; + char buf[1024]; + + if(str == nil || *str == 0 || strlen(str)+16 > 1024) + return 0; + ypeek = 1; + olineno = lineno; + opeekc = peekc; + peekc = IGN; + strcpy(buf, str); + slashslash(buf); + strcat(buf, " break break"); + doio(buf); + tok = 0; + con = 1; + while(con){ + t = yylex(); + if(t == LBREAK) + break; + switch(t){ + case LSTRING: + case LLSTRING: + tok = 1; + free(yylval.sval.s); + break; + case LNAME: + tok = 1; + s = yylval.sym; + if(s->macro || s->type == T || s->type->etype != TENUM) + con = 0; + break; + case LCHARACTER: + case LCONST: + case LLCONST: + case LUCONST: + case LULCONST: + case LVLCONST: + case LUVLCONST: + case LFCONST: + case LDCONST: + tok = 1; + break; + case '+': + case '-': + case '*': + case '/': + case '%': + case LPP: + case LMM: + case '<': + case '>': + case LGE: + case LLE: + case LEQ: + case LNE: + case LLSH: + case LRSH: + case '!': + case '~': + case '&': + case '|': + case '^': + case '(': + case ')': + break; + default: + con = 0; + break; + } + } + undoio(); + peekc = opeekc; + lineno = olineno; + ypeek = 0; + return con && tok; +} + +void +doasenum(Sym *s) +{ + char *b, buf[1024]; + + b = s->macro; + s->macro = nil; + lineno--; + slashslash(b+1); + sprint(buf, "enum{ %s = %s };\n", s->name, b+1); + doio(buf); + /* outpush(nil); */ + free(b); +} |
