plan9fox/sys/src/cmd/cc/macbody

839 lines
12 KiB
Plaintext
Raw Normal View History

#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;;) {
2016-05-16 20:02:17 +00:00
if(cp <= symb+NSYMB-UTFmax)
cp[c1++] = c;
if(fullrune(cp, c1))
break;
c = getc();
}
cp += c1;
}else
2016-05-16 20:02:17 +00:00
if(cp <= symb+NSYMB-UTFmax)
*cp++ = c;
c = getc();
if(c >= Runeself || isalnum(c) || c == '_')
continue;
unget(c);
break;
}
*cp = 0;
2016-05-16 20:02:17 +00:00
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;
strncpy(symb, cp, NSYMB);
if(symb[NSYMB-1] != '\0'){
yyerror("macro too long: %s", cp);
symb[NSYMB-1] = 0;
}
p = strchr(symb, '=');
if(p) {
*p++ = 0;
s = lookup();
l = strlen(p) + 2; /* +1 null, +1 nargs */
s->macro = alloc(l);
memcpy(s->macro, p-1, 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 = alloc(1);
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 = GETC();
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();
}
int
macexpand(Sym *s, char *b, int blen)
{
char buf[2000];
int n, l, c, nargs;
char *arg[NARG], *cp, *ob, *eb, *ecp, dots;
if(*s->macro == 0) {
b[blen-1] = 0;
strncpy(b, s->macro+1, blen);
if(b[blen-1] != '\0')
goto toobig;
if(debug['m'])
2020-04-19 21:57:33 +00:00
print("#expand %s %s\n", s->name, b);
return 1;
}
nargs = (char)(*s->macro & ~VARMAC) - 1;
dots = *s->macro & VARMAC;
c = getnsc();
if(c != '('){
unget(c);
return 0;
}
n = 0;
c = getc();
if(c != ')') {
unget(c);
l = 0;
cp = buf;
2016-05-16 20:02:17 +00:00
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 0;
}
ob = b;
eb = b + blen-1;
cp = s->macro+1;
for(;;) {
if(b >= eb)
goto toobig;
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;
l = strlen(arg[c]);
if(b+l > eb)
goto toobig;
memmove(b, arg[c], l);
b += l;
}
*b = 0;
if(debug['m'])
print("#expand %s %s\n", s->name, ob);
return 1;
bad:
yyerror("syntax in macro expansion: %s", s->name);
*b = 0;
return 0;
toobig:
yyerror("too much text in macro expansion: %s", s->name);
*b = 0;
return 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;
if(hp >= &str[STRINGSZ-1]){
yyerror("name too long for #include");
break;
}
*hp++ = c;
}
*hp = 0;
c = getcom();
if(c != '\n')
goto bad;
f = -1;
for(i=0; i<ninclude; i++) {
if(i == 0 && c0 == '>')
continue;
c = snprint(symb, NSYMB, "%s/%s", include[i], str);;
while(strncmp(symb, "./", 2) == 0){
c -= 2;
memmove(symb, symb+2, c+1);
}
f = open(symb, 0);
if(f >= 0)
break;
}
if(f < 0)
snprint(symb, NSYMB, "%s", str);
newio();
pushio();
newfile(strdup(symb), 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;
cp = alloc(c);
memcpy(cp, symb, 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;
h = alloc(sizeof(Hist));
h->name = alloc(c);
memcpy(h->name, symb, c);
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;
}