| // 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 | |
| pragdynimport(void) | |
| { | |
| while(getnsc() != '\n') | |
| ; | |
| } | |
| void | |
| pragdynexport(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* | |
| alloc(int32 n) | |
| { | |
| void *p; | |
| p = malloc(n); | |
| if(p == nil) { | |
| print("alloc out of mem\n"); | |
| exit(1); | |
| } | |
| 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"); | |
| exit(1); | |
| } | |
| 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) | |
| { | |
| 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) | |
| { | |
| ensuresymb(strlen(s)); | |
| strcpy(symb, s); | |
| return lookup(); | |
| } | |
| Sym* | |
| lookup(void) | |
| { | |
| Sym *s; | |
| int32 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] = '"'; | |
| } | |
| // 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; 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; i<NSYM; i++) { | |
| h[i].type = 0; | |
| h[i].sym = S; | |
| } | |
| for(i=0; i<NHASH; i++) | |
| for(s = hash[i]; s != S; s = s->link) | |
| 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<n; i++) | |
| a[i].line += d; | |
| } | |
| } | |
| if(n > HISTSZ) | |
| n = HISTSZ; | |
| for(i=0; i<n; i++) | |
| print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1)); | |
| } | |
| void | |
| ieeedtod(Ieee *ieee, double native) | |
| { | |
| double fr, ho, f; | |
| int exp; | |
| if(native < 0) { | |
| ieeedtod(ieee, -native); | |
| ieee->h |= 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); | |
| } |