|  | // 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(); | 
|  | } | 
|  |  | 
|  | LSym *thetext; | 
|  |  | 
|  | void | 
|  | settext(LSym *s) | 
|  | { | 
|  | thetext = s; | 
|  | } | 
|  |  | 
|  | Sym* | 
|  | labellookup(Sym *s) | 
|  | { | 
|  | char *p; | 
|  | Sym *lab; | 
|  |  | 
|  | if(thetext == nil) { | 
|  | s->labelname = s->name; | 
|  | return s; | 
|  | } | 
|  | p = smprint("%s.%s", thetext->name, s->name); | 
|  | lab = slookup(p); | 
|  | free(p); | 
|  | lab->labelname = s->name; | 
|  | return lab; | 
|  | } | 
|  |  | 
|  | 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; | 
|  | if(c == '\n') | 
|  | lineno++; | 
|  | 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; | 
|  | } | 
|  | } | 
|  | unget(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<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); | 
|  | 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); | 
|  | } |