9d46360c9d
the assemblers share gethunk() cc/macbody but are compiled without compat.c, so calls such as getenv() trigger malloc() which does its own sbrk() calls, breaking the continuity of the hunk. so this change needs another revision. until then, this is backed out.
869 lines
12 KiB
Plaintext
869 lines
12 KiB
Plaintext
#define VARMAC 0x80
|
|
|
|
long
|
|
getnsn(void)
|
|
{
|
|
long n;
|
|
int c;
|
|
|
|
c = getnsc();
|
|
if(c < '0' || c > '9')
|
|
return -1;
|
|
n = 0;
|
|
while(c >= '0' && c <= '9') {
|
|
n = n*10 + c-'0';
|
|
c = getc();
|
|
}
|
|
unget(c);
|
|
return n;
|
|
}
|
|
|
|
static void
|
|
nextsym(int c)
|
|
{
|
|
int c1;
|
|
char *cp;
|
|
|
|
for(cp = symb;;) {
|
|
if(c >= Runeself) {
|
|
for(c1=0;;) {
|
|
if(cp <= symb+NSYMB-UTFmax)
|
|
cp[c1++] = c;
|
|
if(fullrune(cp, c1))
|
|
break;
|
|
c = getc();
|
|
}
|
|
cp += c1;
|
|
}else
|
|
if(cp <= symb+NSYMB-UTFmax)
|
|
*cp++ = c;
|
|
c = getc();
|
|
if(c >= Runeself || isalnum(c) || c == '_')
|
|
continue;
|
|
unget(c);
|
|
break;
|
|
}
|
|
*cp = 0;
|
|
if(cp > symb+NSYMB-UTFmax)
|
|
yyerror("symbol too large: %s", symb);
|
|
}
|
|
|
|
Sym*
|
|
getsym(void)
|
|
{
|
|
int c;
|
|
|
|
c = getnsc();
|
|
if(c < Runeself && !isalpha(c) && c != '_') {
|
|
unget(c);
|
|
return S;
|
|
}
|
|
nextsym(c);
|
|
return lookup();
|
|
}
|
|
|
|
Sym*
|
|
getsymdots(int *dots)
|
|
{
|
|
int c;
|
|
Sym *s;
|
|
|
|
s = getsym();
|
|
if(s != S)
|
|
return s;
|
|
|
|
c = getnsc();
|
|
if(c != '.'){
|
|
unget(c);
|
|
return S;
|
|
}
|
|
if(getc() != '.' || getc() != '.')
|
|
yyerror("bad dots in macro");
|
|
*dots = 1;
|
|
return slookup("__VA_ARGS__");
|
|
}
|
|
|
|
int
|
|
getcom(void)
|
|
{
|
|
int c;
|
|
|
|
for(;;) {
|
|
c = getnsc();
|
|
if(c != '/')
|
|
break;
|
|
c = getc();
|
|
if(c == '/') {
|
|
while(c != '\n')
|
|
c = getc();
|
|
break;
|
|
}
|
|
if(c != '*')
|
|
break;
|
|
c = getc();
|
|
for(;;) {
|
|
if(c == '*') {
|
|
c = getc();
|
|
if(c != '/')
|
|
continue;
|
|
c = getc();
|
|
break;
|
|
}
|
|
if(c == '\n') {
|
|
yyerror("comment across newline");
|
|
break;
|
|
}
|
|
c = getc();
|
|
}
|
|
if(c == '\n')
|
|
break;
|
|
}
|
|
return c;
|
|
}
|
|
|
|
void
|
|
dodefine(char *cp)
|
|
{
|
|
Sym *s;
|
|
char *p;
|
|
long l;
|
|
|
|
strcpy(symb, cp);
|
|
p = strchr(symb, '=');
|
|
if(p) {
|
|
*p++ = 0;
|
|
s = lookup();
|
|
l = strlen(p) + 2; /* +1 null, +1 nargs */
|
|
while(l & 3)
|
|
l++;
|
|
while(nhunk < l)
|
|
gethunk();
|
|
*hunk = 0;
|
|
strcpy(hunk+1, p);
|
|
s->macro = hunk;
|
|
hunk += l;
|
|
nhunk -= l;
|
|
} else {
|
|
s = lookup();
|
|
s->macro = "\0001"; /* \000 is nargs */
|
|
}
|
|
if(debug['m'])
|
|
print("#define (-D) %s %s\n", s->name, s->macro+1);
|
|
}
|
|
|
|
struct
|
|
{
|
|
char *macname;
|
|
void (*macf)(void);
|
|
} mactab[] =
|
|
{
|
|
"ifdef", 0, /* macif(0) */
|
|
"ifndef", 0, /* macif(1) */
|
|
"else", 0, /* macif(2) */
|
|
|
|
"line", maclin,
|
|
"define", macdef,
|
|
"include", macinc,
|
|
"undef", macund,
|
|
|
|
"pragma", macprag,
|
|
"endif", macend,
|
|
0
|
|
};
|
|
|
|
void
|
|
domacro(void)
|
|
{
|
|
int i;
|
|
Sym *s;
|
|
|
|
s = getsym();
|
|
if(s == S)
|
|
s = slookup("endif");
|
|
for(i=0; mactab[i].macname; i++)
|
|
if(strcmp(s->name, mactab[i].macname) == 0) {
|
|
if(mactab[i].macf)
|
|
(*mactab[i].macf)();
|
|
else
|
|
macif(i);
|
|
return;
|
|
}
|
|
yyerror("unknown #: %s", s->name);
|
|
macend();
|
|
}
|
|
|
|
void
|
|
macund(void)
|
|
{
|
|
Sym *s;
|
|
|
|
s = getsym();
|
|
macend();
|
|
if(s == S) {
|
|
yyerror("syntax in #undef");
|
|
return;
|
|
}
|
|
s->macro = 0;
|
|
}
|
|
|
|
#define NARG 25
|
|
void
|
|
macdef(void)
|
|
{
|
|
Sym *s, *a;
|
|
char *args[NARG], *base;
|
|
int n, i, c, len, dots;
|
|
int ischr;
|
|
|
|
s = getsym();
|
|
if(s == S)
|
|
goto bad;
|
|
if(s->macro)
|
|
yyerror("macro redefined: %s", s->name);
|
|
c = getc();
|
|
n = -1;
|
|
dots = 0;
|
|
if(c == '(') {
|
|
n++;
|
|
c = getnsc();
|
|
if(c != ')') {
|
|
unget(c);
|
|
for(;;) {
|
|
a = getsymdots(&dots);
|
|
if(a == S)
|
|
goto bad;
|
|
if(n >= NARG) {
|
|
yyerror("too many arguments in #define: %s", s->name);
|
|
goto bad;
|
|
}
|
|
args[n++] = a->name;
|
|
c = getnsc();
|
|
if(c == ')')
|
|
break;
|
|
if(c != ',' || dots)
|
|
goto bad;
|
|
}
|
|
}
|
|
c = getc();
|
|
}
|
|
if(isspace(c))
|
|
if(c != '\n')
|
|
c = getnsc();
|
|
base = hunk;
|
|
len = 1;
|
|
ischr = 0;
|
|
for(;;) {
|
|
if(c >= Runeself || isalpha(c) || c == '_') {
|
|
nextsym(c);
|
|
c = getc();
|
|
for(i=0; i<n; i++)
|
|
if(strcmp(symb, args[i]) == 0)
|
|
break;
|
|
if(i >= n) {
|
|
i = strlen(symb);
|
|
base = allocn(base, len, i);
|
|
memcpy(base+len, symb, i);
|
|
len += i;
|
|
continue;
|
|
}
|
|
base = allocn(base, len, 2);
|
|
base[len++] = '#';
|
|
base[len++] = 'a' + i;
|
|
continue;
|
|
}
|
|
if(ischr){
|
|
if(c == '\\'){
|
|
base = allocn(base, len, 1);
|
|
base[len++] = c;
|
|
c = getc();
|
|
}else if(c == ischr)
|
|
ischr = 0;
|
|
}else{
|
|
if(c == '"' || c == '\''){
|
|
base = allocn(base, len, 1);
|
|
base[len++] = c;
|
|
ischr = c;
|
|
c = getc();
|
|
continue;
|
|
}
|
|
if(c == '/') {
|
|
c = getc();
|
|
if(c == '/'){
|
|
c = getc();
|
|
for(;;) {
|
|
if(c == '\n')
|
|
break;
|
|
c = getc();
|
|
}
|
|
continue;
|
|
}
|
|
if(c == '*'){
|
|
c = getc();
|
|
for(;;) {
|
|
if(c == '*') {
|
|
c = getc();
|
|
if(c != '/')
|
|
continue;
|
|
c = getc();
|
|
break;
|
|
}
|
|
if(0 && c == '\n') {
|
|
yyerror("comment and newline in define: %s", s->name);
|
|
break;
|
|
}
|
|
c = getc();
|
|
}
|
|
continue;
|
|
}
|
|
base = allocn(base, len, 1);
|
|
base[len++] = '/';
|
|
continue;
|
|
}
|
|
}
|
|
if(c == '\\') {
|
|
c = getc();
|
|
if(c == '\n') {
|
|
c = getc();
|
|
continue;
|
|
}
|
|
else if(c == '\r') {
|
|
c = getc();
|
|
if(c == '\n') {
|
|
c = getc();
|
|
continue;
|
|
}
|
|
}
|
|
base = allocn(base, len, 1);
|
|
base[len++] = '\\';
|
|
continue;
|
|
}
|
|
if(c == '\n')
|
|
break;
|
|
if(c == '#')
|
|
if(n > 0) {
|
|
base = allocn(base, len, 1);
|
|
base[len++] = c;
|
|
}
|
|
base = allocn(base, len, 1);
|
|
base[len++] = c;
|
|
c = ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff));
|
|
if(c == '\n')
|
|
lineno++;
|
|
if(c == -1) {
|
|
yyerror("eof in a macro: %s", s->name);
|
|
break;
|
|
}
|
|
}
|
|
do {
|
|
base = allocn(base, len, 1);
|
|
base[len++] = 0;
|
|
} while(len & 3);
|
|
|
|
*base = n+1;
|
|
if(dots)
|
|
*base |= VARMAC;
|
|
s->macro = base;
|
|
if(debug['m'])
|
|
print("#define %s %s\n", s->name, s->macro+1);
|
|
return;
|
|
|
|
bad:
|
|
if(s == S)
|
|
yyerror("syntax in #define");
|
|
else
|
|
yyerror("syntax in #define: %s", s->name);
|
|
macend();
|
|
}
|
|
|
|
void
|
|
macexpand(Sym *s, char *b)
|
|
{
|
|
char buf[2000];
|
|
int n, l, c, nargs;
|
|
char *arg[NARG], *cp, *ob, *ecp, dots;
|
|
|
|
ob = b;
|
|
if(*s->macro == 0) {
|
|
strcpy(b, s->macro+1);
|
|
if(debug['m'])
|
|
print("#expand %s %s\n", s->name, ob);
|
|
return;
|
|
}
|
|
|
|
nargs = (char)(*s->macro & ~VARMAC) - 1;
|
|
dots = *s->macro & VARMAC;
|
|
|
|
c = getnsc();
|
|
if(c != '(')
|
|
goto bad;
|
|
n = 0;
|
|
c = getc();
|
|
if(c != ')') {
|
|
unget(c);
|
|
l = 0;
|
|
cp = buf;
|
|
ecp = cp + sizeof(buf)-UTFmax;
|
|
arg[n++] = cp;
|
|
for(;;) {
|
|
if(cp >= ecp)
|
|
goto toobig;
|
|
c = getc();
|
|
if(c == '"')
|
|
for(;;) {
|
|
if(cp >= ecp)
|
|
goto toobig;
|
|
*cp++ = c;
|
|
c = getc();
|
|
if(c == '\\') {
|
|
*cp++ = c;
|
|
c = getc();
|
|
continue;
|
|
}
|
|
if(c == '\n')
|
|
goto bad;
|
|
if(c == '"')
|
|
break;
|
|
}
|
|
if(c == '\'')
|
|
for(;;) {
|
|
if(cp >= ecp)
|
|
goto toobig;
|
|
*cp++ = c;
|
|
c = getc();
|
|
if(c == '\\') {
|
|
*cp++ = c;
|
|
c = getc();
|
|
continue;
|
|
}
|
|
if(c == '\n')
|
|
goto bad;
|
|
if(c == '\'')
|
|
break;
|
|
}
|
|
if(c == '/') {
|
|
c = getc();
|
|
switch(c) {
|
|
case '*':
|
|
for(;;) {
|
|
c = getc();
|
|
if(c == '*') {
|
|
c = getc();
|
|
if(c == '/')
|
|
break;
|
|
}
|
|
}
|
|
*cp++ = ' ';
|
|
continue;
|
|
case '/':
|
|
while((c = getc()) != '\n')
|
|
;
|
|
break;
|
|
default:
|
|
unget(c);
|
|
c = '/';
|
|
}
|
|
}
|
|
if(l == 0) {
|
|
if(c == ',') {
|
|
if(n == nargs && dots) {
|
|
*cp++ = ',';
|
|
continue;
|
|
}
|
|
*cp++ = 0;
|
|
arg[n++] = cp;
|
|
if(n > nargs)
|
|
break;
|
|
continue;
|
|
}
|
|
if(c == ')')
|
|
break;
|
|
}
|
|
if(c == '\n')
|
|
c = ' ';
|
|
*cp++ = c;
|
|
if(c == '(')
|
|
l++;
|
|
if(c == ')')
|
|
l--;
|
|
}
|
|
*cp = 0;
|
|
}
|
|
if(n != nargs) {
|
|
yyerror("argument mismatch expanding: %s", s->name);
|
|
*b = 0;
|
|
return;
|
|
}
|
|
cp = s->macro+1;
|
|
for(;;) {
|
|
c = *cp++;
|
|
if(c == '\n')
|
|
c = ' ';
|
|
if(c != '#') {
|
|
*b++ = c;
|
|
if(c == 0)
|
|
break;
|
|
continue;
|
|
}
|
|
c = *cp++;
|
|
if(c == 0)
|
|
goto bad;
|
|
if(c == '#') {
|
|
*b++ = c;
|
|
continue;
|
|
}
|
|
c -= 'a';
|
|
if(c < 0 || c >= n)
|
|
continue;
|
|
strcpy(b, arg[c]);
|
|
b += strlen(arg[c]);
|
|
}
|
|
*b = 0;
|
|
if(debug['m'])
|
|
print("#expand %s %s\n", s->name, ob);
|
|
return;
|
|
|
|
bad:
|
|
yyerror("syntax in macro expansion: %s", s->name);
|
|
*b = 0;
|
|
return;
|
|
|
|
toobig:
|
|
yyerror("too much text in macro expansion: %s", s->name);
|
|
*b = 0;
|
|
}
|
|
|
|
void
|
|
macinc(void)
|
|
{
|
|
int c0, c, i, f;
|
|
char str[STRINGSZ], *hp;
|
|
|
|
c0 = getnsc();
|
|
if(c0 != '"') {
|
|
c = c0;
|
|
if(c0 != '<')
|
|
goto bad;
|
|
c0 = '>';
|
|
}
|
|
for(hp = str;;) {
|
|
c = getc();
|
|
if(c == c0)
|
|
break;
|
|
if(c == '\n')
|
|
goto bad;
|
|
*hp++ = c;
|
|
}
|
|
*hp = 0;
|
|
|
|
c = getcom();
|
|
if(c != '\n')
|
|
goto bad;
|
|
|
|
f = -1;
|
|
for(i=0; i<ninclude; i++) {
|
|
if(i == 0 && c0 == '>')
|
|
continue;
|
|
strcpy(symb, include[i]);
|
|
strcat(symb, "/");
|
|
if(strcmp(symb, "./") == 0)
|
|
symb[0] = 0;
|
|
strcat(symb, str);
|
|
f = open(symb, 0);
|
|
if(f >= 0)
|
|
break;
|
|
}
|
|
if(f < 0)
|
|
strcpy(symb, str);
|
|
c = strlen(symb) + 1;
|
|
while(c & 3)
|
|
c++;
|
|
while(nhunk < c)
|
|
gethunk();
|
|
hp = hunk;
|
|
memcpy(hunk, symb, c);
|
|
nhunk -= c;
|
|
hunk += c;
|
|
newio();
|
|
pushio();
|
|
newfile(hp, f);
|
|
return;
|
|
|
|
bad:
|
|
unget(c);
|
|
yyerror("syntax in #include");
|
|
macend();
|
|
}
|
|
|
|
void
|
|
maclin(void)
|
|
{
|
|
char *cp;
|
|
int c;
|
|
long n;
|
|
|
|
n = getnsn();
|
|
c = getc();
|
|
if(n < 0)
|
|
goto bad;
|
|
|
|
for(;;) {
|
|
if(c == ' ' || c == '\t') {
|
|
c = getc();
|
|
continue;
|
|
}
|
|
if(c == '"')
|
|
break;
|
|
if(c == '\n') {
|
|
strcpy(symb, "<noname>");
|
|
goto nn;
|
|
}
|
|
goto bad;
|
|
}
|
|
cp = symb;
|
|
for(;;) {
|
|
c = getc();
|
|
if(c == '"')
|
|
break;
|
|
*cp++ = c;
|
|
}
|
|
*cp = 0;
|
|
c = getcom();
|
|
if(c != '\n')
|
|
goto bad;
|
|
|
|
nn:
|
|
c = strlen(symb) + 1;
|
|
while(c & 3)
|
|
c++;
|
|
while(nhunk < c)
|
|
gethunk();
|
|
cp = hunk;
|
|
memcpy(hunk, symb, c);
|
|
nhunk -= c;
|
|
hunk += c;
|
|
linehist(cp, n);
|
|
return;
|
|
|
|
bad:
|
|
unget(c);
|
|
yyerror("syntax in #line");
|
|
macend();
|
|
}
|
|
|
|
void
|
|
macif(int f)
|
|
{
|
|
int c, l, bol;
|
|
Sym *s;
|
|
|
|
if(f == 2)
|
|
goto skip;
|
|
s = getsym();
|
|
if(s == S)
|
|
goto bad;
|
|
if(getcom() != '\n')
|
|
goto bad;
|
|
if((s->macro != 0) ^ f)
|
|
return;
|
|
|
|
skip:
|
|
bol = 1;
|
|
l = 0;
|
|
for(;;) {
|
|
c = getc();
|
|
if(c != '#') {
|
|
if(!isspace(c))
|
|
bol = 0;
|
|
if(c == '\n')
|
|
bol = 1;
|
|
continue;
|
|
}
|
|
if(!bol)
|
|
continue;
|
|
s = getsym();
|
|
if(s == S)
|
|
continue;
|
|
if(strcmp(s->name, "endif") == 0) {
|
|
if(l) {
|
|
l--;
|
|
continue;
|
|
}
|
|
macend();
|
|
return;
|
|
}
|
|
if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) {
|
|
l++;
|
|
continue;
|
|
}
|
|
if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) {
|
|
macend();
|
|
return;
|
|
}
|
|
}
|
|
|
|
bad:
|
|
yyerror("syntax in #if(n)def");
|
|
macend();
|
|
}
|
|
|
|
void
|
|
macprag(void)
|
|
{
|
|
Sym *s;
|
|
int c0, c;
|
|
char *hp;
|
|
Hist *h;
|
|
|
|
s = getsym();
|
|
|
|
if(s && strcmp(s->name, "lib") == 0)
|
|
goto praglib;
|
|
if(s && strcmp(s->name, "pack") == 0) {
|
|
pragpack();
|
|
return;
|
|
}
|
|
if(s && strcmp(s->name, "fpround") == 0) {
|
|
pragfpround();
|
|
return;
|
|
}
|
|
if(s && strcmp(s->name, "profile") == 0) {
|
|
pragprofile();
|
|
return;
|
|
}
|
|
if(s && strcmp(s->name, "varargck") == 0) {
|
|
pragvararg();
|
|
return;
|
|
}
|
|
if(s && strcmp(s->name, "incomplete") == 0) {
|
|
pragincomplete();
|
|
return;
|
|
}
|
|
while(getnsc() != '\n')
|
|
;
|
|
return;
|
|
|
|
praglib:
|
|
c0 = getnsc();
|
|
if(c0 != '"') {
|
|
c = c0;
|
|
if(c0 != '<')
|
|
goto bad;
|
|
c0 = '>';
|
|
}
|
|
for(hp = symb;;) {
|
|
c = getc();
|
|
if(c == c0)
|
|
break;
|
|
if(c == '\n')
|
|
goto bad;
|
|
*hp++ = c;
|
|
}
|
|
*hp = 0;
|
|
c = getcom();
|
|
if(c != '\n')
|
|
goto bad;
|
|
|
|
/*
|
|
* put pragma-line in as a funny history
|
|
*/
|
|
c = strlen(symb) + 1;
|
|
while(c & 3)
|
|
c++;
|
|
while(nhunk < c)
|
|
gethunk();
|
|
hp = hunk;
|
|
memcpy(hunk, symb, c);
|
|
nhunk -= c;
|
|
hunk += c;
|
|
|
|
h = alloc(sizeof(Hist));
|
|
h->name = hp;
|
|
h->line = lineno;
|
|
h->offset = -1;
|
|
h->link = H;
|
|
if(ehist == H) {
|
|
hist = h;
|
|
ehist = h;
|
|
return;
|
|
}
|
|
ehist->link = h;
|
|
ehist = h;
|
|
return;
|
|
|
|
bad:
|
|
unget(c);
|
|
yyerror("syntax in #pragma lib");
|
|
macend();
|
|
}
|
|
|
|
void
|
|
macend(void)
|
|
{
|
|
int c;
|
|
|
|
for(;;) {
|
|
c = getnsc();
|
|
if(c < 0 || c == '\n')
|
|
return;
|
|
}
|
|
}
|
|
|
|
void
|
|
linehist(char *f, int offset)
|
|
{
|
|
Hist *h;
|
|
|
|
/*
|
|
* overwrite the last #line directive if
|
|
* no alloc has happened since the last one
|
|
*/
|
|
if(newflag == 0 && ehist != H && offset != 0 && ehist->offset != 0)
|
|
if(f && ehist->name && strcmp(f, ehist->name) == 0) {
|
|
ehist->line = lineno;
|
|
ehist->offset = offset;
|
|
return;
|
|
}
|
|
|
|
if(debug['f'])
|
|
if(f) {
|
|
if(offset)
|
|
print("%4ld: %s (#line %d)\n", lineno, f, offset);
|
|
else
|
|
print("%4ld: %s\n", lineno, f);
|
|
} else
|
|
print("%4ld: <pop>\n", lineno);
|
|
newflag = 0;
|
|
|
|
h = alloc(sizeof(Hist));
|
|
h->name = f;
|
|
h->line = lineno;
|
|
h->offset = offset;
|
|
h->link = H;
|
|
if(ehist == H) {
|
|
hist = h;
|
|
ehist = h;
|
|
return;
|
|
}
|
|
ehist->link = h;
|
|
ehist = h;
|
|
}
|
|
|
|
void
|
|
gethunk(void)
|
|
{
|
|
char *h;
|
|
long nh;
|
|
|
|
nh = NHUNK;
|
|
if(thunk >= 10L*NHUNK)
|
|
nh = 10L*NHUNK;
|
|
h = (char*)mysbrk(nh);
|
|
if(h == (char*)-1) {
|
|
yyerror("out of memory");
|
|
errorexit();
|
|
}
|
|
hunk = h;
|
|
nhunk = nh;
|
|
thunk += nh;
|
|
}
|