#include "cc.h"
#include "y.tab.h"
enum
{
Fnone = 0,
Fl,
Fvl,
Fignor,
Fstar,
Fadj,
Fverb = 10,
};
typedef struct Tprot Tprot;
struct Tprot
{
Type* type;
Bits flag;
Tprot* link;
};
typedef struct Tname Tname;
struct Tname
{
char* name;
int param;
Tname* link;
};
static Type* indchar;
static uchar flagbits[512];
static char fmtbuf[100];
static int lastadj;
static int lastverb;
static int nstar;
static Tprot* tprot;
static Tname* tname;
void
argflag(int c, int v)
{
switch(v) {
case Fignor:
case Fstar:
case Fl:
case Fvl:
flagbits[c] = v;
break;
case Fverb:
flagbits[c] = lastverb;
/*print("flag-v %c %d\n", c, lastadj);*/
lastverb++;
break;
case Fadj:
flagbits[c] = lastadj;
/*print("flag-l %c %d\n", c, lastadj);*/
lastadj++;
break;
}
}
Bits
getflag(char *s)
{
Bits flag;
int f;
char *fmt;
Rune c;
fmt = fmtbuf;
flag = zbits;
nstar = 0;
for(;;) {
s += chartorune(&c, s);
fmt += runetochar(fmt, &c);
if(c == 0 || c >= nelem(flagbits))
break;
f = flagbits[c];
switch(f) {
case Fnone:
argflag(c, Fverb);
f = flagbits[c];
break;
case Fstar:
nstar++;
case Fignor:
continue;
case Fl:
if(bset(flag, Fl))
flag = bor(flag, blsh(Fvl));
}
flag = bor(flag, blsh(f));
if(f >= Fverb)
break;
}
*fmt = 0;
return flag;
}
void
newprot(Sym *m, Type *t, char *s)
{
Bits flag;
Tprot *l;
if(t == T) {
warn(Z, "%s: newprot: type not defined", m->name);
return;
}
flag = getflag(s);
for(l=tprot; l; l=l->link)
if(beq(flag, l->flag) && sametype(t, l->type))
return;
l = alloc(sizeof(*l));
l->type = t;
l->flag = flag;
l->link = tprot;
tprot = l;
}
void
newname(char *s, int p)
{
Tname *l;
for(l=tname; l; l=l->link)
if(strcmp(l->name, s) == 0) {
if(l->param != p)
yyerror("vargck %s already defined\n", s);
return;
}
l = alloc(sizeof(*l));
l->name = s;
l->param = p;
l->link = tname;
tname = l;
}
void
arginit(void)
{
int i;
/* debug['F'] = 1;*/
/* debug['w'] = 1;*/
lastadj = Fadj;
lastverb = Fverb;
indchar = typ(TIND, types[TCHAR]);
memset(flagbits, Fnone, sizeof(flagbits));
for(i='0'; i<='9'; i++)
argflag(i, Fignor);
argflag('.', Fignor);
argflag('#', Fignor);
argflag('u', Fignor);
argflag('h', Fignor);
argflag('+', Fignor);
argflag('-', Fignor);
argflag('*', Fstar);
argflag('l', Fl);
argflag('o', Fverb);
flagbits['x'] = flagbits['o'];
flagbits['X'] = flagbits['o'];
}
void
pragvararg(void)
{
Sym *s;
int n, c;
char *t;
Rune r;
Type *ty;
if(!debug['F'])
goto out;
s = getsym();
if(s && strcmp(s->name, "argpos") == 0)
goto ckpos;
if(s && strcmp(s->name, "type") == 0)
goto cktype;
if(s && strcmp(s->name, "flag") == 0)
goto ckflag;
yyerror("syntax in #pragma varargck");
goto out;
ckpos:
/*#pragma varargck argpos warn 2*/
s = getsym();
if(s == S)
goto bad;
n = getnsn();
if(n < 0)
goto bad;
newname(s->name, n);
goto out;
ckflag:
/*#pragma varargck flag 'c'*/
c = getnsc();
if(c != '\'')
goto bad;
c = getr();
if(c == '\\')
c = getr();
else if(c == '\'')
goto bad;
if(c == '\n')
goto bad;
if(getc() != '\'')
goto bad;
argflag(c, Fignor);
goto out;
cktype:
/*#pragma varargck type O int*/
c = getnsc();
if(c != '"')
goto bad;
t = fmtbuf;
for(;;) {
r = getr();
if(r == ' ' || r == '\n')
goto bad;
if(r == '"')
break;
t += runetochar(t, &r);
}
*t = 0;
t = strdup(fmtbuf);
s = getsym();
if(s == S)
goto bad;
ty = s->type;
while((c = getnsc()) == '*')
ty = typ(TIND, ty);
unget(c);
newprot(s, ty, t);
goto out;
bad:
yyerror("syntax in #pragma varargck");
out:
while(getnsc() != '\n')
;
}
Node*
nextarg(Node *n, Node **a)
{
if(n == Z) {
*a = Z;
return Z;
}
if(n->op == OLIST) {
*a = n->left;
return n->right;
}
*a = n;
return Z;
}
void
checkargs(Node *nn, char *s, int pos)
{
Node *a, *n;
Bits flag;
Tprot *l;
if(!debug['F'])
return;
n = nn;
for(;;) {
s = strchr(s, '%');
if(s == 0) {
nextarg(n, &a);
if(a != Z)
warn(nn, "more arguments than format %T",
a->type);
return;
}
s++;
flag = getflag(s);
while(nstar > 0) {
n = nextarg(n, &a);
pos++;
nstar--;
if(a == Z) {
warn(nn, "more format than arguments %s",
fmtbuf);
return;
}
if(a->type == T)
continue;
if(!sametype(types[TINT], a->type) &&
!sametype(types[TUINT], a->type))
warn(nn, "format mismatch '*' in %s %T, arg %d",
fmtbuf, a->type, pos);
}
for(l=tprot; l; l=l->link)
if(sametype(types[TVOID], l->type)) {
if(beq(flag, l->flag)) {
s++;
goto loop;
}
}
n = nextarg(n, &a);
pos++;
if(a == Z) {
warn(nn, "more format than arguments %s",
fmtbuf);
return;
}
if(a->type == 0)
continue;
for(l=tprot; l; l=l->link)
if(sametype(a->type, l->type)) {
/*print("checking %T/%ulx %T/%ulx\n", a->type, flag.b[0], l->type, l->flag.b[0]);*/
if(beq(flag, l->flag))
goto loop;
}
warn(nn, "format mismatch %s %T, arg %d", fmtbuf, a->type, pos);
loop:;
}
}
void
dpcheck(Node *n)
{
char *s;
Node *a, *b;
Tname *l;
int i;
if(n == Z)
return;
b = n->left;
if(b == Z || b->op != ONAME)
return;
s = b->sym->name;
for(l=tname; l; l=l->link)
if(strcmp(s, l->name) == 0)
break;
if(l == 0)
return;
i = l->param;
b = n->right;
while(i > 0) {
b = nextarg(b, &a);
i--;
}
if(a == Z) {
warn(n, "cant find format arg");
return;
}
if(!sametype(indchar, a->type)) {
warn(n, "format arg type %T", a->type);
return;
}
if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) {
/* warn(n, "format arg not constant string");*/
return;
}
s = a->left->cstring;
checkargs(b, s, l->param);
}
void
pragpack(void)
{
Sym *s;
packflg = 0;
s = getsym();
if(s) {
packflg = atoi(s->name+1);
if(strcmp(s->name, "on") == 0 ||
strcmp(s->name, "yes") == 0)
packflg = 1;
}
while(getnsc() != '\n')
;
if(debug['f'])
if(packflg)
print("%4ld: pack %d\n", lineno, packflg);
else
print("%4ld: pack off\n", lineno);
}
void
pragfpround(void)
{
Sym *s;
fproundflg = 0;
s = getsym();
if(s) {
fproundflg = atoi(s->name+1);
if(strcmp(s->name, "on") == 0 ||
strcmp(s->name, "yes") == 0)
fproundflg = 1;
}
while(getnsc() != '\n')
;
if(debug['f'])
if(fproundflg)
print("%4ld: fproundflg %d\n", lineno, fproundflg);
else
print("%4ld: fproundflg off\n", lineno);
}
void
pragprofile(void)
{
Sym *s;
profileflg = 0;
s = getsym();
if(s) {
profileflg = atoi(s->name+1);
if(strcmp(s->name, "on") == 0 ||
strcmp(s->name, "yes") == 0)
profileflg = 1;
}
while(getnsc() != '\n')
;
if(debug['f'])
if(profileflg)
print("%4ld: profileflg %d\n", lineno, profileflg);
else
print("%4ld: profileflg off\n", lineno);
}
void
pragincomplete(void)
{
Sym *s;
Type *t;
int istag, w, et;
istag = 0;
s = getsym();
if(s == nil)
goto out;
et = 0;
w = s->lexical;
if(w == LSTRUCT)
et = TSTRUCT;
else if(w == LUNION)
et = TUNION;
if(et != 0){
s = getsym();
if(s == nil){
yyerror("missing struct/union tag in pragma incomplete");
goto out;
}
if(s->lexical != LNAME && s->lexical != LTYPE){
yyerror("invalid struct/union tag: %s", s->name);
goto out;
}
dotag(s, et, 0);
istag = 1;
}else if(strcmp(s->name, "_off_") == 0){
debug['T'] = 0;
goto out;
}else if(strcmp(s->name, "_on_") == 0){
debug['T'] = 1;
goto out;
}
t = s->type;
if(istag)
t = s->suetag;
if(t == T)
yyerror("unknown type %s in pragma incomplete", s->name);
else if(!typesu[t->etype])
yyerror("not struct/union type in pragma incomplete: %s", s->name);
else
t->garb |= GINCOMPLETE;
out:
while(getnsc() != '\n')
;
if(debug['f'])
print("%s incomplete\n", s->name);
}
|