xref: /inferno-os/utils/cc/dpchk.c (revision 9dbf735d35c339c90deaed43fc0ae17f16c122f7)
1 #include	"cc.h"
2 #include	"y.tab.h"
3 
4 enum
5 {
6 	Fnone	= 0,
7 	Fl,
8 	Fvl,
9 	Fignor,
10 	Fstar,
11 	Fadj,
12 
13 	Fverb	= 10,
14 };
15 
16 typedef	struct	Tprot	Tprot;
17 struct	Tprot
18 {
19 	Type*	type;
20 	Bits	flag;
21 	Tprot*	link;
22 };
23 
24 typedef	struct	Tname	Tname;
25 struct	Tname
26 {
27 	char*	name;
28 	int	param;
29 	Tname*	link;
30 };
31 
32 static	Type*	indchar;
33 static	uchar	flagbits[512];
34 static	char	fmtbuf[100];
35 static	int	lastadj;
36 static	int	lastverb;
37 static	int	nstar;
38 static	Tprot*	tprot;
39 static	Tname*	tname;
40 
41 void
42 argflag(int c, int v)
43 {
44 
45 	switch(v) {
46 	case Fignor:
47 	case Fstar:
48 	case Fl:
49 	case Fvl:
50 		flagbits[c] = v;
51 		break;
52 	case Fverb:
53 		flagbits[c] = lastverb;
54 /*print("flag-v %c %d\n", c, lastadj);*/
55 		lastverb++;
56 		break;
57 	case Fadj:
58 		flagbits[c] = lastadj;
59 /*print("flag-l %c %d\n", c, lastadj);*/
60 		lastadj++;
61 		break;
62 	}
63 }
64 
65 Bits
66 getflag(char *s)
67 {
68 	Bits flag;
69 	int f;
70 	char *fmt;
71 	Rune c;
72 
73 	fmt = fmtbuf;
74 	flag = zbits;
75 	nstar = 0;
76 	for(;;) {
77 		s += chartorune(&c, s);
78 		if(c == 0 || c >= nelem(flagbits))
79 			break;
80 		fmt += runetochar(fmt, &c);
81 		f = flagbits[c];
82 		switch(f) {
83 		case Fnone:
84 			argflag(c, Fverb);
85 			f = flagbits[c];
86 			break;
87 		case Fstar:
88 			nstar++;
89 		case Fignor:
90 			continue;
91 		case Fl:
92 			if(bset(flag, Fl))
93 				flag = bor(flag, blsh(Fvl));
94 		}
95 		flag = bor(flag, blsh(f));
96 		if(f >= Fverb)
97 			break;
98 	}
99 	*fmt = 0;
100 	return flag;
101 }
102 
103 void
104 newprot(Sym *m, Type *t, char *s)
105 {
106 	Bits flag;
107 	Tprot *l;
108 
109 	if(t == T) {
110 		warn(Z, "%s: newprot: type not defined", m->name);
111 		return;
112 	}
113 	flag = getflag(s);
114 	for(l=tprot; l; l=l->link)
115 		if(beq(flag, l->flag) && sametype(t, l->type))
116 			return;
117 	l = alloc(sizeof(*l));
118 	l->type = t;
119 	l->flag = flag;
120 	l->link = tprot;
121 	tprot = l;
122 }
123 
124 void
125 newname(char *s, int p)
126 {
127 	Tname *l;
128 
129 	for(l=tname; l; l=l->link)
130 		if(strcmp(l->name, s) == 0) {
131 			if(l->param != p)
132 				yyerror("vargck %s already defined\n", s);
133 			return;
134 		}
135 	l = alloc(sizeof(*l));
136 	l->name = s;
137 	l->param = p;
138 	l->link = tname;
139 	tname = l;
140 }
141 
142 void
143 arginit(void)
144 {
145 	int i;
146 
147 /* debug['F'] = 1;*/
148 /* debug['w'] = 1;*/
149 
150 	lastadj = Fadj;
151 	lastverb = Fverb;
152 	indchar = typ(TIND, types[TCHAR]);
153 
154 	memset(flagbits, Fnone, sizeof(flagbits));
155 
156 	for(i='0'; i<='9'; i++)
157 		argflag(i, Fignor);
158 	argflag('.', Fignor);
159 	argflag('#', Fignor);
160 	argflag('u', Fignor);
161 	argflag('h', Fignor);
162 	argflag('+', Fignor);
163 	argflag('-', Fignor);
164 
165 	argflag('*', Fstar);
166 	argflag('l', Fl);
167 
168 	argflag('o', Fverb);
169 	flagbits['x'] = flagbits['o'];
170 	flagbits['X'] = flagbits['o'];
171 }
172 
173 void
174 pragvararg(void)
175 {
176 	Sym *s;
177 	int n, c;
178 	char *t;
179 	Rune r;
180 	Type *ty;
181 
182 	if(!debug['F'])
183 		goto out;
184 	s = getsym();
185 	if(s && strcmp(s->name, "argpos") == 0)
186 		goto ckpos;
187 	if(s && strcmp(s->name, "type") == 0)
188 		goto cktype;
189 	if(s && strcmp(s->name, "flag") == 0)
190 		goto ckflag;
191 	yyerror("syntax in #pragma varargck");
192 	goto out;
193 
194 ckpos:
195 /*#pragma	varargck	argpos	warn	2*/
196 	s = getsym();
197 	if(s == S)
198 		goto bad;
199 	n = getnsn();
200 	if(n < 0)
201 		goto bad;
202 	newname(s->name, n);
203 	goto out;
204 
205 ckflag:
206 /*#pragma	varargck	flag	'c'*/
207 	c = getnsc();
208 	if(c != '\'')
209 		goto bad;
210 	c = getr();
211 	if(c == '\\')
212 		c = getr();
213 	else if(c == '\'')
214 		goto bad;
215 	if(c == '\n')
216 		goto bad;
217 	if(getc() != '\'')
218 		goto bad;
219 	argflag(c, Fignor);
220 	goto out;
221 
222 cktype:
223 /*#pragma	varargck	type	O	int*/
224 	c = getnsc();
225 	if(c != '"')
226 		goto bad;
227 	t = fmtbuf;
228 	for(;;) {
229 		r = getr();
230 		if(r == ' ' || r == '\n')
231 			goto bad;
232 		if(r == '"')
233 			break;
234 		t += runetochar(t, &r);
235 	}
236 	*t = 0;
237 	t = strdup(fmtbuf);
238 	s = getsym();
239 	if(s == S)
240 		goto bad;
241 	ty = s->type;
242 	while((c = getnsc()) == '*')
243 		ty = typ(TIND, ty);
244 	unget(c);
245 	newprot(s, ty, t);
246 	goto out;
247 
248 bad:
249 	yyerror("syntax in #pragma varargck");
250 
251 out:
252 	while(getnsc() != '\n')
253 		;
254 }
255 
256 Node*
257 nextarg(Node *n, Node **a)
258 {
259 	if(n == Z) {
260 		*a = Z;
261 		return Z;
262 	}
263 	if(n->op == OLIST) {
264 		*a = n->left;
265 		return n->right;
266 	}
267 	*a = n;
268 	return Z;
269 }
270 
271 void
272 checkargs(Node *nn, char *s, int pos)
273 {
274 	Node *a, *n;
275 	Bits flag;
276 	Tprot *l;
277 
278 	if(!debug['F'])
279 		return;
280 	n = nn;
281 	for(;;) {
282 		s = strchr(s, '%');
283 		if(s == 0) {
284 			nextarg(n, &a);
285 			if(a != Z)
286 				warn(nn, "more arguments than format %T",
287 					a->type);
288 			return;
289 		}
290 		s++;
291 		flag = getflag(s);
292 		while(nstar > 0) {
293 			n = nextarg(n, &a);
294 			pos++;
295 			nstar--;
296 			if(a == Z) {
297 				warn(nn, "more format than arguments %s",
298 					fmtbuf);
299 				return;
300 			}
301 			if(a->type == T)
302 				continue;
303 			if(!sametype(types[TINT], a->type) &&
304 			   !sametype(types[TUINT], a->type))
305 				warn(nn, "format mismatch '*' in %s %T, arg %d",
306 					fmtbuf, a->type, pos);
307 		}
308 		for(l=tprot; l; l=l->link)
309 			if(sametype(types[TVOID], l->type)) {
310 				if(beq(flag, l->flag)) {
311 					s++;
312 					goto loop;
313 				}
314 			}
315 
316 		n = nextarg(n, &a);
317 		pos++;
318 		if(a == Z) {
319 			warn(nn, "more format than arguments %s",
320 				fmtbuf);
321 			return;
322 		}
323 		if(a->type == 0)
324 			continue;
325 		for(l=tprot; l; l=l->link)
326 			if(sametype(a->type, l->type)) {
327 /*print("checking %T/%ulx %T/%ulx\n", a->type, flag.b[0], l->type, l->flag.b[0]);*/
328 				if(beq(flag, l->flag))
329 					goto loop;
330 			}
331 		warn(nn, "format mismatch %s %T, arg %d", fmtbuf, a->type, pos);
332 	loop:;
333 	}
334 }
335 
336 void
337 dpcheck(Node *n)
338 {
339 	char *s;
340 	Node *a, *b;
341 	Tname *l;
342 	int i;
343 
344 	if(n == Z)
345 		return;
346 	b = n->left;
347 	if(b == Z || b->op != ONAME)
348 		return;
349 	s = b->sym->name;
350 	for(l=tname; l; l=l->link)
351 		if(strcmp(s, l->name) == 0)
352 			break;
353 	if(l == 0)
354 		return;
355 
356 	i = l->param;
357 	b = n->right;
358 	while(i > 0) {
359 		b = nextarg(b, &a);
360 		i--;
361 	}
362 	if(a == Z) {
363 		warn(n, "cant find format arg");
364 		return;
365 	}
366 	if(!sametype(indchar, a->type)) {
367 		warn(n, "format arg type %T", a->type);
368 		return;
369 	}
370 	if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) {
371 /*		warn(n, "format arg not constant string");*/
372 		return;
373 	}
374 	s = a->left->cstring;
375 	checkargs(b, s, l->param);
376 }
377 
378 void
379 pragpack(void)
380 {
381 	Sym *s;
382 
383 	packflg = 0;
384 	s = getsym();
385 	if(s) {
386 		packflg = atoi(s->name+1);
387 		if(strcmp(s->name, "on") == 0 ||
388 		   strcmp(s->name, "yes") == 0)
389 			packflg = 1;
390 	}
391 	while(getnsc() != '\n')
392 		;
393 	if(debug['f'])
394 		if(packflg)
395 			print("%4ld: pack %d\n", lineno, packflg);
396 		else
397 			print("%4ld: pack off\n", lineno);
398 }
399 
400 void
401 pragfpround(void)
402 {
403 	Sym *s;
404 
405 	fproundflg = 0;
406 	s = getsym();
407 	if(s) {
408 		fproundflg = atoi(s->name+1);
409 		if(strcmp(s->name, "on") == 0 ||
410 		   strcmp(s->name, "yes") == 0)
411 			fproundflg = 1;
412 	}
413 	while(getnsc() != '\n')
414 		;
415 	if(debug['f'])
416 		if(fproundflg)
417 			print("%4ld: fproundflg %d\n", lineno, fproundflg);
418 		else
419 			print("%4ld: fproundflg off\n", lineno);
420 }
421 
422 void
423 pragprofile(void)
424 {
425 	Sym *s;
426 
427 	profileflg = 0;
428 	s = getsym();
429 	if(s) {
430 		profileflg = atoi(s->name+1);
431 		if(strcmp(s->name, "on") == 0 ||
432 		   strcmp(s->name, "yes") == 0)
433 			profileflg = 1;
434 	}
435 	while(getnsc() != '\n')
436 		;
437 	if(debug['f'])
438 		if(profileflg)
439 			print("%4ld: profileflg %d\n", lineno, profileflg);
440 		else
441 			print("%4ld: profileflg off\n", lineno);
442 }
443 
444 void
445 pragincomplete(void)
446 {
447 	Sym *s;
448 	Type *t;
449 	int istag, w, et;
450 
451 	istag = 0;
452 	s = getsym();
453 	if(s == nil)
454 		goto out;
455 	et = 0;
456 	w = s->lexical;
457 	if(w == LSTRUCT)
458 		et = TSTRUCT;
459 	else if(w == LUNION)
460 		et = TUNION;
461 	if(et != 0){
462 		s = getsym();
463 		if(s == nil){
464 			yyerror("missing struct/union tag in pragma incomplete");
465 			goto out;
466 		}
467 		if(s->lexical != LNAME && s->lexical != LTYPE){
468 			yyerror("invalid struct/union tag: %s", s->name);
469 			goto out;
470 		}
471 		dotag(s, et, 0);
472 		istag = 1;
473 	}else if(strcmp(s->name, "_off_") == 0){
474 		debug['T'] = 0;
475 		goto out;
476 	}else if(strcmp(s->name, "_on_") == 0){
477 		debug['T'] = 1;
478 		goto out;
479 	}
480 	t = s->type;
481 	if(istag)
482 		t = s->suetag;
483 	if(t == T)
484 		yyerror("unknown type %s in pragma incomplete", s->name);
485 	else if(!typesu[t->etype])
486 		yyerror("not struct/union type in pragma incomplete: %s", s->name);
487 	else
488 		t->garb |= GINCOMPLETE;
489 out:
490 	while(getnsc() != '\n')
491 		;
492 	if(debug['f'])
493 		print("%s incomplete\n", s->name);
494 }
495