Expand PMF_FN_* macros.
[netbsd-mini2440.git] / usr.bin / xlint / lint1 / emit1.c
blob2ea32aa12bff5b95eacae1b75b3d5aaf036fb291
1 /* $NetBSD: emit1.c,v 1.18 2008/04/26 23:34:55 christos Exp $ */
3 /*
4 * Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
5 * Copyright (c) 1994, 1995 Jochen Pohl
6 * All Rights Reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Jochen Pohl for
19 * The NetBSD Project.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #if HAVE_NBTOOL_CONFIG_H
36 #include "nbtool_config.h"
37 #endif
39 #include <sys/cdefs.h>
40 #if defined(__RCSID) && !defined(lint)
41 __RCSID("$NetBSD: emit1.c,v 1.18 2008/04/26 23:34:55 christos Exp $");
42 #endif
44 #include <ctype.h>
46 #include "lint1.h"
48 static void outtt(sym_t *, sym_t *);
49 static void outfstrg(strg_t *);
52 * Write type into the output buffer.
53 * The type is written as a sequence of substrings, each of which describes a
54 * node of type type_t
55 * a node is coded as follows:
56 * _Bool B
57 * _Complex float s X
58 * _Complex double X
59 * _Complex long double l X
60 * char C
61 * signed char s C
62 * unsigned char u C
63 * short S
64 * unsigned short u S
65 * int I
66 * unsigned int u I
67 * long L
68 * unsigned long u L
69 * long long Q
70 * unsigned long long u Q
71 * float s D
72 * double D
73 * long double l D
74 * void V
75 * * P
76 * [n] A n
77 * () F
78 * (void) F 0
79 * (n arguments) F n arg1 arg2 ... argn
80 * (n arguments, ...) F n arg1 arg2 ... argn-1 E
81 * (a, b, c, ...) f n arg1 arg2 ...
82 * enum tag e T tag_or_typename
83 * struct tag s T tag_or_typename
84 * union tag u T tag_or_typename
86 * tag_or_typename 0 no tag or type name
87 * 1 n tag Tag
88 * 2 n typename only type name
90 * spaces are only for better readability
91 * additionaly it is possible to prepend the characters 'c' (for const)
92 * and 'v' (for volatile)
94 void
95 outtype(type_t *tp)
97 int t, s, na;
98 sym_t *arg;
99 tspec_t ts;
101 while (tp != NULL) {
102 if ((ts = tp->t_tspec) == INT && tp->t_isenum)
103 ts = ENUM;
104 switch (ts) {
105 case BOOL: t = 'B'; s = '\0'; break;
106 case CHAR: t = 'C'; s = '\0'; break;
107 case SCHAR: t = 'C'; s = 's'; break;
108 case UCHAR: t = 'C'; s = 'u'; break;
109 case SHORT: t = 'S'; s = '\0'; break;
110 case USHORT: t = 'S'; s = 'u'; break;
111 case INT: t = 'I'; s = '\0'; break;
112 case UINT: t = 'I'; s = 'u'; break;
113 case LONG: t = 'L'; s = '\0'; break;
114 case ULONG: t = 'L'; s = 'u'; break;
115 case QUAD: t = 'Q'; s = '\0'; break;
116 case UQUAD: t = 'Q'; s = 'u'; break;
117 case FLOAT: t = 'D'; s = 's'; break;
118 case DOUBLE: t = 'D'; s = '\0'; break;
119 case LDOUBLE: t = 'D'; s = 'l'; break;
120 case VOID: t = 'V'; s = '\0'; break;
121 case PTR: t = 'P'; s = '\0'; break;
122 case ARRAY: t = 'A'; s = '\0'; break;
123 case FUNC: t = 'F'; s = '\0'; break;
124 case ENUM: t = 'T'; s = 'e'; break;
125 case STRUCT: t = 'T'; s = 's'; break;
126 case UNION: t = 'T'; s = 'u'; break;
127 case FCOMPLEX: t = 'X'; s = 's'; break;
128 case DCOMPLEX: t = 'X'; s = '\0'; break;
129 case LCOMPLEX: t = 'X'; s = 'l'; break;
130 default:
131 LERROR("outtyp()");
133 if (tp->t_const)
134 outchar('c');
135 if (tp->t_volatile)
136 outchar('v');
137 if (s != '\0')
138 outchar(s);
139 outchar(t);
140 if (ts == ARRAY) {
141 outint(tp->t_dim);
142 } else if (ts == ENUM) {
143 outtt(tp->t_enum->etag, tp->t_enum->etdef);
144 } else if (ts == STRUCT || ts == UNION) {
145 outtt(tp->t_str->stag, tp->t_str->stdef);
146 } else if (ts == FUNC && tp->t_proto) {
147 na = 0;
148 for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt)
149 na++;
150 if (tp->t_vararg)
151 na++;
152 outint(na);
153 for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt)
154 outtype(arg->s_type);
155 if (tp->t_vararg)
156 outchar('E');
158 tp = tp->t_subt;
163 * type to string
164 * used for debugging output
166 * it uses its own output buffer for conversion
168 const char *
169 ttos(type_t *tp)
171 static ob_t tob;
172 ob_t tmp;
174 if (tob.o_buf == NULL) {
175 tob.o_len = 64;
176 tob.o_buf = tob.o_nxt = xmalloc(tob.o_len);
177 tob.o_end = tob.o_buf + tob.o_len;
180 tmp = ob;
181 ob = tob;
182 ob.o_nxt = ob.o_buf;
183 outtype(tp);
184 outchar('\0');
185 tob = ob;
186 ob = tmp;
188 return (tob.o_buf);
192 * write the name of a tag or typename
194 * if the tag is named, the name of the
195 * tag is written, otherwise, if a typename exists which
196 * refers to this tag, this typename is written
198 static void
199 outtt(sym_t *tag, sym_t *tdef)
203 * 0 is no longer used.
205 if (tag->s_name != unnamed) {
206 outint(1);
207 outname(tag->s_name);
208 } else if (tdef != NULL) {
209 outint(2);
210 outname(tdef->s_name);
211 } else {
212 outint(3);
213 outint(tag->s_dpos.p_line);
214 outchar('.');
215 outint(getfnid(tag->s_dpos.p_file));
216 outchar('.');
217 outint(tag->s_dpos.p_uniq);
222 * write information about an global declared/defined symbol
223 * with storage class extern
225 * informations about function definitions are written in outfdef(),
226 * not here
228 void
229 outsym(sym_t *sym, scl_t sc, def_t def)
233 * Static function declarations must also be written to the output
234 * file. Compatibility of function declarations (for both static
235 * and extern functions) must be checked in lint2. Lint1 can't do
236 * this, especially not, if functions are declared at block level
237 * before their first declaration at level 0.
239 if (sc != EXTERN && !(sc == STATIC && sym->s_type->t_tspec == FUNC))
240 return;
242 /* reset buffer */
243 outclr();
246 * line number of .c source, 'd' for declaration, Id of current
247 * source (.c or .h), and line in current source.
249 outint(csrc_pos.p_line);
250 outchar('d');
251 outint(getfnid(sym->s_dpos.p_file));
252 outchar('.');
253 outint(sym->s_dpos.p_line);
255 /* flags */
257 switch (def) {
258 case DEF:
259 /* defined */
260 outchar('d');
261 break;
262 case TDEF:
263 /* tentative defined */
264 outchar('t');
265 break;
266 case DECL:
267 /* declared */
268 outchar('e');
269 break;
270 default:
271 LERROR("outsym()");
273 if (llibflg && def != DECL) {
275 * mark it as used so we get no warnings from lint2 about
276 * unused symbols in libraries.
278 outchar('u');
281 if (sc == STATIC)
282 outchar('s');
284 /* name of the symbol */
285 outname(sym->s_name);
287 /* renamed name of symbol, if necessary */
288 if (sym->s_rename) {
289 outchar('r');
290 outname(sym->s_rename);
293 /* type of the symbol */
294 outtype(sym->s_type);
298 * write information about function definition
300 * this is also done for static functions so we are able to check if
301 * they are called with proper argument types
303 void
304 outfdef(sym_t *fsym, pos_t *posp, int rval, int osdef, sym_t *args)
306 int narg;
307 sym_t *arg;
309 /* reset the buffer */
310 outclr();
313 * line number of .c source, 'd' for declaration, Id of current
314 * source (.c or .h), and line in current source
316 * we are already at the end of the function. If we are in the
317 * .c source, posp->p_line is correct, otherwise csrc_pos.p_line
318 * (for functions defined in header files).
320 if (posp->p_file == csrc_pos.p_file) {
321 outint(posp->p_line);
322 } else {
323 outint(csrc_pos.p_line);
325 outchar('d');
326 outint(getfnid(posp->p_file));
327 outchar('.');
328 outint(posp->p_line);
330 /* flags */
332 /* both SCANFLIKE and PRINTFLIKE imply VARARGS */
333 if (prflstrg != -1) {
334 nvararg = prflstrg;
335 } else if (scflstrg != -1) {
336 nvararg = scflstrg;
339 if (nvararg != -1) {
340 outchar('v');
341 outint(nvararg);
343 if (scflstrg != -1) {
344 outchar('S');
345 outint(scflstrg);
347 if (prflstrg != -1) {
348 outchar('P');
349 outint(prflstrg);
351 nvararg = prflstrg = scflstrg = -1;
353 outchar('d');
355 if (rval)
356 /* has return value */
357 outchar('r');
359 if (llibflg)
361 * mark it as used so lint2 does not complain about
362 * unused symbols in libraries
364 outchar('u');
366 if (osdef)
367 /* old style function definition */
368 outchar('o');
370 if (fsym->s_scl == STATIC)
371 outchar('s');
373 /* name of function */
374 outname(fsym->s_name);
376 /* renamed name of function, if necessary */
377 if (fsym->s_rename) {
378 outchar('r');
379 outname(fsym->s_rename);
382 /* argument types and return value */
383 if (osdef) {
384 narg = 0;
385 for (arg = args; arg != NULL; arg = arg->s_nxt)
386 narg++;
387 outchar('f');
388 outint(narg);
389 for (arg = args; arg != NULL; arg = arg->s_nxt)
390 outtype(arg->s_type);
391 outtype(fsym->s_type->t_subt);
392 } else {
393 outtype(fsym->s_type);
398 * write out all information necessary for lint2 to check function
399 * calls
401 * rvused is set if the return value is used (asigned to a variable)
402 * rvdisc is set if the return value is not used and not ignored
403 * (casted to void)
405 void
406 outcall(tnode_t *tn, int rvused, int rvdisc)
408 tnode_t *args, *arg;
409 int narg, n, i;
410 int64_t q;
411 tspec_t t;
413 /* reset buffer */
414 outclr();
417 * line number of .c source, 'c' for function call, Id of current
418 * source (.c or .h), and line in current source
420 outint(csrc_pos.p_line);
421 outchar('c');
422 outint(getfnid(curr_pos.p_file));
423 outchar('.');
424 outint(curr_pos.p_line);
427 * flags; 'u' and 'i' must be last to make sure a letter
428 * is between the numeric argument of a flag and the name of
429 * the function
431 narg = 0;
432 args = tn->tn_right;
433 for (arg = args; arg != NULL; arg = arg->tn_right)
434 narg++;
435 /* informations about arguments */
436 for (n = 1; n <= narg; n++) {
437 /* the last argument is the top one in the tree */
438 for (i = narg, arg = args; i > n; i--, arg = arg->tn_right)
439 continue;
440 arg = arg->tn_left;
441 if (arg->tn_op == CON) {
442 if (isityp(t = arg->tn_type->t_tspec)) {
444 * XXX it would probably be better to
445 * explicitly test the sign
447 if ((q = arg->tn_val->v_quad) == 0) {
448 /* zero constant */
449 outchar('z');
450 } else if (msb(q, t, 0) == 0) {
451 /* positive if casted to signed */
452 outchar('p');
453 } else {
454 /* negative if casted to signed */
455 outchar('n');
457 outint(n);
459 } else if (arg->tn_op == AMPER &&
460 arg->tn_left->tn_op == STRING &&
461 arg->tn_left->tn_strg->st_tspec == CHAR) {
462 /* constant string, write all format specifiers */
463 outchar('s');
464 outint(n);
465 outfstrg(arg->tn_left->tn_strg);
469 /* return value discarded/used/ignored */
470 outchar(rvdisc ? 'd' : (rvused ? 'u' : 'i'));
472 /* name of the called function */
473 outname(tn->tn_left->tn_left->tn_sym->s_name);
475 /* types of arguments */
476 outchar('f');
477 outint(narg);
478 for (n = 1; n <= narg; n++) {
479 /* the last argument is the top one in the tree */
480 for (i = narg, arg = args; i > n; i--, arg = arg->tn_right)
481 continue;
482 outtype(arg->tn_left->tn_type);
484 /* expected type of return value */
485 outtype(tn->tn_type);
489 * extracts potential format specifiers for printf() and scanf() and
490 * writes them, enclosed in "" and qouted if necessary, to the output buffer
492 static void
493 outfstrg(strg_t *strg)
495 int c, oc, first;
496 u_char *cp;
498 if (strg->st_tspec != CHAR)
499 LERROR("outfstrg()");
501 cp = strg->st_cp;
503 outchar('"');
505 c = *cp++;
507 while (c != '\0') {
509 if (c != '%') {
510 c = *cp++;
511 continue;
514 outqchar('%');
515 c = *cp++;
517 /* flags for printf and scanf and *-fieldwidth for printf */
518 while (c != '\0' && (c == '-' || c == '+' || c == ' ' ||
519 c == '#' || c == '0' || c == '*')) {
520 outqchar(c);
521 c = *cp++;
524 /* numeric field width */
525 while (c != '\0' && isdigit(c)) {
526 outqchar(c);
527 c = *cp++;
530 /* precision for printf */
531 if (c == '.') {
532 outqchar(c);
533 if ((c = *cp++) == '*') {
534 outqchar(c);
535 c = *cp++;
536 } else {
537 while (c != '\0' && isdigit(c)) {
538 outqchar(c);
539 c = *cp++;
544 /* h, l, L and q flags fpr printf and scanf */
545 if (c == 'h' || c == 'l' || c == 'L' || c == 'q') {
546 outqchar(c);
547 c = *cp++;
551 * The last character. It is always written so we can detect
552 * invalid format specifiers.
554 if (c != '\0') {
555 outqchar(c);
556 oc = c;
557 c = *cp++;
559 * handle [ for scanf. [-] means that a minus sign
560 * was found at an undefined position.
562 if (oc == '[') {
563 if (c == '^')
564 c = *cp++;
565 if (c == ']')
566 c = *cp++;
567 first = 1;
568 while (c != '\0' && c != ']') {
569 if (c == '-') {
570 if (!first && *cp != ']')
571 outqchar(c);
573 first = 0;
574 c = *cp++;
576 if (c == ']') {
577 outqchar(c);
578 c = *cp++;
585 outchar('"');
589 * writes a record if sym was used
591 void
592 outusg(sym_t *sym)
594 /* reset buffer */
595 outclr();
598 * line number of .c source, 'u' for used, Id of current
599 * source (.c or .h), and line in current source
601 outint(csrc_pos.p_line);
602 outchar('u');
603 outint(getfnid(curr_pos.p_file));
604 outchar('.');
605 outint(curr_pos.p_line);
607 /* necessary to delimit both numbers */
608 outchar('x');
610 /* Den Namen des Symbols ausgeben */
611 outname(sym->s_name);