// Inferno utils/cc/lexbody // http://code.google.com/p/inferno-os/source/browse/utils/cc/lexbody // // 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. /* * common code for all the assemblers */ void pragpack(void) { while(getnsc() != '\n') ; } void pragvararg(void) { while(getnsc() != '\n') ; } void pragdynld(void) { while(getnsc() != '\n') ; } void pragfpround(void) { while(getnsc() != '\n') ; } void pragtextflag(void) { while(getnsc() != '\n') ; } void pragprofile(void) { while(getnsc() != '\n') ; } void pragincomplete(void) { while(getnsc() != '\n') ; } void gethunk(void) { hunk = malloc(NHUNK); memset(hunk, 0, NHUNK); nhunk = NHUNK; } void* alloc(int32 n) { void *p; while((uintptr)hunk & MAXALIGN) { hunk++; nhunk--; } while(nhunk < n) gethunk(); p = hunk; nhunk -= n; hunk += n; return p; } void* allocn(void *p, int32 on, int32 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; if(p == 0) return; for(i=1; i < ninclude; i++) if(strcmp(p, include[i]) == 0) return; if(ninclude >= nelem(include)) { yyerror("ninclude too small %d", nelem(include)); exits("ninclude"); } include[ninclude++] = p; } 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; i = ionext; i->link = iostack; iostack = i; i->f = f; if(f < 0) i->f = open(s, 0); if(i->f < 0) { yyerror("%ca: %r: %s", thechar, s); errorexit(); } fi.c = 0; linehist(s, 0); } Sym* slookup(char *s) { strcpy(symb, s); return lookup(); } Sym* lookup(void) { Sym *s; int32 h; char *p; int c, l; h = 0; for(p=symb; c = *p; p++) h = h+h+h + c; l = (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(memcmp(s->name, symb, l) == 0) return s; } s = alloc(sizeof(*s)); s->name = alloc(l); memmove(s->name, symb, l); s->link = hash[h]; hash[h] = s; syminit(s); return s; } int ISALPHA(int c) { if(isalpha(c)) return 1; if(c >= Runeself) return 1; return 0; } int32 yylex(void) { int c, c1; char *cp; Sym *s; c = peekc; if(c != IGN) { peekc = IGN; goto l1; } l0: c = GETC(); l1: if(c == EOF) { peekc = EOF; return -1; } if(isspace(c)) { if(c == '\n') { lineno++; return ';'; } goto l0; } if(ISALPHA(c)) goto talph; if(isdigit(c)) goto tnum; switch(c) { case '\n': lineno++; return ';'; case '#': domacro(); goto l0; case '.': c = GETC(); if(ISALPHA(c)) { cp = symb; *cp++ = '.'; goto aloop; } if(isdigit(c)) { cp = symb; *cp++ = '.'; goto casedot; } peekc = c; return '.'; talph: case '_': case '@': cp = symb; aloop: *cp++ = c; c = GETC(); if(ISALPHA(c) || isdigit(c) || c == '_' || c == '$') goto aloop; *cp = 0; 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; } if(s->type == 0) s->type = LNAME; if(s->type == LNAME || s->type == LVAR || s->type == LLAB) { yylval.sym = s; return s->type; } yylval.lval = s->value; return s->type; tnum: cp = symb; if(c != '0') goto dc; *cp++ = c; c = GETC(); c1 = 3; if(c == 'x' || c == 'X') { c1 = 4; c = GETC(); } else if(c < '0' || c > '7') goto dc; yylval.lval = 0; for(;;) { if(c >= '0' && c <= '9') { if(c > '7' && c1 == 3) break; yylval.lval <<= c1; yylval.lval += c - '0'; c = GETC(); continue; } if(c1 == 3) break; if(c >= 'A' && c <= 'F') c += 'a' - 'A'; if(c >= 'a' && c <= 'f') { yylval.lval <<= c1; yylval.lval += c - 'a' + 10; c = GETC(); continue; } break; } goto ncu; dc: for(;;) { if(!isdigit(c)) break; *cp++ = c; c = GETC(); } if(c == '.') goto casedot; if(c == 'e' || c == 'E') goto casee; *cp = 0; if(sizeof(yylval.lval) == sizeof(vlong)) yylval.lval = strtoll(symb, nil, 10); else yylval.lval = strtol(symb, nil, 10); ncu: while(c == 'U' || c == 'u' || c == 'l' || c == 'L') c = GETC(); peekc = c; return LCONST; casedot: for(;;) { *cp++ = c; c = GETC(); if(!isdigit(c)) break; } if(c == 'e' || c == 'E') goto casee; goto caseout; casee: *cp++ = 'e'; c = GETC(); if(c == '+' || c == '-') { *cp++ = c; c = GETC(); } while(isdigit(c)) { *cp++ = c; c = GETC(); } caseout: *cp = 0; peekc = c; if(FPCHIP) { yylval.dval = atof(symb); return LFCONST; } yyerror("assembler cannot interpret fp constants"); yylval.lval = 1L; return LCONST; case '"': memcpy(yylval.sval, nullgen.sval, sizeof(yylval.sval)); cp = yylval.sval; c1 = 0; for(;;) { c = escchar('"'); if(c == EOF) break; if(c1 < sizeof(yylval.sval)) *cp++ = c; c1++; } if(c1 > sizeof(yylval.sval)) yyerror("string constant too long"); return LSCONST; case '\'': c = escchar('\''); if(c == EOF) c = '\''; if(escchar('\'') != EOF) yyerror("missing '"); yylval.lval = c; return LCONST; case '/': c1 = GETC(); if(c1 == '/') { for(;;) { c = GETC(); if(c == '\n') goto l1; if(c == EOF) { yyerror("eof in comment"); errorexit(); } } } if(c1 == '*') { for(;;) { c = GETC(); while(c == '*') { c = GETC(); if(c == '/') goto l0; } if(c == EOF) { yyerror("eof in comment"); errorexit(); } if(c == '\n') lineno++; } } break; default: return c; } peekc = c1; return c; } int getc(void) { int c; c = peekc; if(c != IGN) { peekc = IGN; return c; } c = GETC(); if(c == '\n') lineno++; if(c == EOF) { yyerror("End of file"); errorexit(); } return c; } int getnsc(void) { int c; for(;;) { c = getc(); if(!isspace(c) || c == '\n') return c; } } void unget(int c) { peekc = c; if(c == '\n') lineno--; } int escchar(int e) { int c, l; loop: c = getc(); if(c == '\n') { yyerror("newline in string"); return EOF; } if(c != '\\') { if(c == e) return EOF; return c; } c = getc(); if(c >= '0' && c <= '7') { l = c - '0'; c = getc(); if(c >= '0' && c <= '7') { l = l*8 + c-'0'; c = getc(); if(c >= '0' && c <= '7') { l = l*8 + c-'0'; return l; } } peekc = c; 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 0x07; case 'v': return 0x0b; case 'z': return 0x00; } return c; } void pinit(char *f) { int i; Sym *s; lineno = 1; newio(); newfile(f, -1); pc = 0; peekc = IGN; sym = 1; for(i=0; ilink) s->macro = 0; } 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]; 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++; } void yyerror(char *a, ...) { char buf[200]; va_list arg; /* * hack to intercept message from yaccpar */ if(strcmp(a, "syntax error") == 0) { yyerror("syntax error, last name: %s", symb); return; } prfile(lineno); va_start(arg, a); vseprint(buf, buf+sizeof(buf), a, arg); va_end(arg); print("%s\n", buf); nerrors++; if(nerrors > 10) { print("too many errors\n"); errorexit(); } } void prfile(int32 l) { int i, n; Hist a[HISTSZ], *h; int32 d; n = 0; for(h = hist; h != H; h = h->link) { if(l < h->line) break; if(h->name) { if(h->offset == 0) { if(n >= 0 && n < HISTSZ) a[n] = *h; n++; continue; } if(n > 0 && n < HISTSZ) if(a[n-1].offset == 0) { a[n] = *h; n++; } else a[n-1] = *h; continue; } n--; if(n >= 0 && n < HISTSZ) { d = h->line - a[n].line; for(i=0; i HISTSZ) n = HISTSZ; for(i=0; ih |= 0x80000000L; return; } if(native == 0) { ieee->l = 0; ieee->h = 0; return; } fr = frexp(native, &exp); f = 2097152L; /* shouldnt use fp constants here */ fr = modf(fr*f, &ho); ieee->h = ho; ieee->h &= 0xfffffL; ieee->h |= (exp+1022L) << 20; f = 65536L; fr = modf(fr*f, &ho); ieee->l = ho; ieee->l <<= 16; ieee->l |= (int32)(fr*f); }