// 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 pragcgo(char *name) { USED(name); while(getnsc() != '\n') ; } void pragfpround(void) { while(getnsc() != '\n') ; } void pragtextflag(void) { while(getnsc() != '\n') ; } void pragdataflag(void) { while(getnsc() != '\n') ; } void pragprofile(void) { while(getnsc() != '\n') ; } void pragincomplete(void) { while(getnsc() != '\n') ; } 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; } } 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%8 == 0) include = allocn(include, ninclude*sizeof(char *), 8*sizeof(char *)); include[ninclude++] = p; } 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; 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; 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, l; 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; 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(strcmp(s->name, symb) == 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 = (uvlong)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 = (uvlong)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.u.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); linklinehist(ctxt, lineno, 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; } 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) { linkprfile(ctxt, l); }