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
argflag(int c,int v)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
getflag(char * s)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 fmt += runetochar(fmt, &c);
79 if(c == 0 || c >= nelem(flagbits))
80 break;
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
newprot(Sym * m,Type * t,char * s)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
newname(char * s,int p)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
arginit(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
pragvararg(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*
nextarg(Node * n,Node ** a)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
checkargs(Node * nn,char * s,int pos)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
dpcheck(Node * n)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
pragpack(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
pragfpround(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
pragprofile(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
pragincomplete(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