mirror of https://github.com/golang/go.git
735 lines
11 KiB
Plaintext
735 lines
11 KiB
Plaintext
// 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;
|
||
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<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);
|
||
}
|