emit1.c revision 1.14 1 /* $NetBSD: emit1.c,v 1.14 2004/06/20 22:20:16 jmc Exp $ */
2
3 /*
4 * Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
5 * Copyright (c) 1994, 1995 Jochen Pohl
6 * All Rights Reserved.
7 *
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.
22 *
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.
33 */
34
35 #if HAVE_NBTOOL_CONFIG_H
36 #include "nbtool_config.h"
37 #endif
38
39 #include <sys/cdefs.h>
40 #if defined(__RCSID) && !defined(lint)
41 __RCSID("$NetBSD: emit1.c,v 1.14 2004/06/20 22:20:16 jmc Exp $");
42 #endif
43
44 #include <ctype.h>
45
46 #include "lint1.h"
47
48 static void outtt(sym_t *, sym_t *);
49 static void outfstrg(strg_t *);
50
51 /*
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 * char C
57 * signed char s C
58 * unsigned char u C
59 * short S
60 * unsigned short u S
61 * int I
62 * unsigned int u I
63 * long L
64 * unsigned long u L
65 * long long Q
66 * unsigned long long u Q
67 * float s D
68 * double D
69 * long double l D
70 * void V
71 * * P
72 * [n] A n
73 * () F
74 * (void) F 0
75 * (n arguments) F n arg1 arg2 ... argn
76 * (n arguments, ...) F n arg1 arg2 ... argn-1 E
77 * (a, b, c, ...) f n arg1 arg2 ...
78 * enum tag e T tag_or_typename
79 * struct tag s T tag_or_typename
80 * union tag u T tag_or_typename
81 *
82 * tag_or_typename 0 no tag or type name
83 * 1 n tag Tag
84 * 2 n typename only type name
85 *
86 * spaces are only for better readability
87 * additionaly it is possible to prepend the characters 'c' (for const)
88 * and 'v' (for volatile)
89 */
90 void
91 outtype(type_t *tp)
92 {
93 int t, s, na;
94 sym_t *arg;
95 tspec_t ts;
96
97 while (tp != NULL) {
98 if ((ts = tp->t_tspec) == INT && tp->t_isenum)
99 ts = ENUM;
100 switch (ts) {
101 case CHAR: t = 'C'; s = '\0'; break;
102 case SCHAR: t = 'C'; s = 's'; break;
103 case UCHAR: t = 'C'; s = 'u'; break;
104 case SHORT: t = 'S'; s = '\0'; break;
105 case USHORT: t = 'S'; s = 'u'; break;
106 case INT: t = 'I'; s = '\0'; break;
107 case UINT: t = 'I'; s = 'u'; break;
108 case LONG: t = 'L'; s = '\0'; break;
109 case ULONG: t = 'L'; s = 'u'; break;
110 case QUAD: t = 'Q'; s = '\0'; break;
111 case UQUAD: t = 'Q'; s = 'u'; break;
112 case FLOAT: t = 'D'; s = 's'; break;
113 case DOUBLE: t = 'D'; s = '\0'; break;
114 case LDOUBLE: t = 'D'; s = 'l'; break;
115 case VOID: t = 'V'; s = '\0'; break;
116 case PTR: t = 'P'; s = '\0'; break;
117 case ARRAY: t = 'A'; s = '\0'; break;
118 case FUNC: t = 'F'; s = '\0'; break;
119 case ENUM: t = 'T'; s = 'e'; break;
120 case STRUCT: t = 'T'; s = 's'; break;
121 case UNION: t = 'T'; s = 'u'; break;
122 default:
123 LERROR("outtyp()");
124 }
125 if (tp->t_const)
126 outchar('c');
127 if (tp->t_volatile)
128 outchar('v');
129 if (s != '\0')
130 outchar(s);
131 outchar(t);
132 if (ts == ARRAY) {
133 outint(tp->t_dim);
134 } else if (ts == ENUM) {
135 outtt(tp->t_enum->etag, tp->t_enum->etdef);
136 } else if (ts == STRUCT || ts == UNION) {
137 outtt(tp->t_str->stag, tp->t_str->stdef);
138 } else if (ts == FUNC && tp->t_proto) {
139 na = 0;
140 for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt)
141 na++;
142 if (tp->t_vararg)
143 na++;
144 outint(na);
145 for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt)
146 outtype(arg->s_type);
147 if (tp->t_vararg)
148 outchar('E');
149 }
150 tp = tp->t_subt;
151 }
152 }
153
154 /*
155 * type to string
156 * used for debugging output
157 *
158 * it uses its own output buffer for conversion
159 */
160 const char *
161 ttos(type_t *tp)
162 {
163 static ob_t tob;
164 ob_t tmp;
165
166 if (tob.o_buf == NULL) {
167 tob.o_len = 64;
168 tob.o_buf = tob.o_nxt = xmalloc(tob.o_len);
169 tob.o_end = tob.o_buf + tob.o_len;
170 }
171
172 tmp = ob;
173 ob = tob;
174 ob.o_nxt = ob.o_buf;
175 outtype(tp);
176 outchar('\0');
177 tob = ob;
178 ob = tmp;
179
180 return (tob.o_buf);
181 }
182
183 /*
184 * write the name of a tag or typename
185 *
186 * if the tag is named, the name of the
187 * tag is written, otherwise, if a typename exists which
188 * refers to this tag, this typename is written
189 */
190 static void
191 outtt(sym_t *tag, sym_t *tdef)
192 {
193
194 /*
195 * 0 is no longer used.
196 */
197 if (tag->s_name != unnamed) {
198 outint(1);
199 outname(tag->s_name);
200 } else if (tdef != NULL) {
201 outint(2);
202 outname(tdef->s_name);
203 } else {
204 outint(3);
205 outint(tag->s_dpos.p_line);
206 outchar('.');
207 outint(getfnid(tag->s_dpos.p_file));
208 outchar('.');
209 outint(tag->s_dpos.p_uniq);
210 }
211 }
212
213 /*
214 * write information about an global declared/defined symbol
215 * with storage class extern
216 *
217 * informations about function definitions are written in outfdef(),
218 * not here
219 */
220 void
221 outsym(sym_t *sym, scl_t sc, def_t def)
222 {
223
224 /*
225 * Static function declarations must also be written to the output
226 * file. Compatibility of function declarations (for both static
227 * and extern functions) must be checked in lint2. Lint1 can't do
228 * this, especially not, if functions are declared at block level
229 * before their first declaration at level 0.
230 */
231 if (sc != EXTERN && !(sc == STATIC && sym->s_type->t_tspec == FUNC))
232 return;
233
234 /* reset buffer */
235 outclr();
236
237 /*
238 * line number of .c source, 'd' for declaration, Id of current
239 * source (.c or .h), and line in current source.
240 */
241 outint(csrc_pos.p_line);
242 outchar('d');
243 outint(getfnid(sym->s_dpos.p_file));
244 outchar('.');
245 outint(sym->s_dpos.p_line);
246
247 /* flags */
248
249 switch (def) {
250 case DEF:
251 /* defined */
252 outchar('d');
253 break;
254 case TDEF:
255 /* tentative defined */
256 outchar('t');
257 break;
258 case DECL:
259 /* declared */
260 outchar('e');
261 break;
262 default:
263 LERROR("outsym()");
264 }
265 if (llibflg && def != DECL) {
266 /*
267 * mark it as used so we get no warnings from lint2 about
268 * unused symbols in libraries.
269 */
270 outchar('u');
271 }
272
273 if (sc == STATIC)
274 outchar('s');
275
276 /* name of the symbol */
277 outname(sym->s_name);
278
279 /* renamed name of symbol, if necessary */
280 if (sym->s_rename) {
281 outchar('r');
282 outname(sym->s_rename);
283 }
284
285 /* type of the symbol */
286 outtype(sym->s_type);
287 }
288
289 /*
290 * write information about function definition
291 *
292 * this is also done for static functions so we are able to check if
293 * they are called with proper argument types
294 */
295 void
296 outfdef(sym_t *fsym, pos_t *posp, int rval, int osdef, sym_t *args)
297 {
298 int narg;
299 sym_t *arg;
300
301 /* reset the buffer */
302 outclr();
303
304 /*
305 * line number of .c source, 'd' for declaration, Id of current
306 * source (.c or .h), and line in current source
307 *
308 * we are already at the end of the function. If we are in the
309 * .c source, posp->p_line is correct, otherwise csrc_pos.p_line
310 * (for functions defined in header files).
311 */
312 if (posp->p_file == csrc_pos.p_file) {
313 outint(posp->p_line);
314 } else {
315 outint(csrc_pos.p_line);
316 }
317 outchar('d');
318 outint(getfnid(posp->p_file));
319 outchar('.');
320 outint(posp->p_line);
321
322 /* flags */
323
324 /* both SCANFLIKE and PRINTFLIKE imply VARARGS */
325 if (prflstrg != -1) {
326 nvararg = prflstrg;
327 } else if (scflstrg != -1) {
328 nvararg = scflstrg;
329 }
330
331 if (nvararg != -1) {
332 outchar('v');
333 outint(nvararg);
334 }
335 if (scflstrg != -1) {
336 outchar('S');
337 outint(scflstrg);
338 }
339 if (prflstrg != -1) {
340 outchar('P');
341 outint(prflstrg);
342 }
343 nvararg = prflstrg = scflstrg = -1;
344
345 outchar('d');
346
347 if (rval)
348 /* has return value */
349 outchar('r');
350
351 if (llibflg)
352 /*
353 * mark it as used so lint2 does not complain about
354 * unused symbols in libraries
355 */
356 outchar('u');
357
358 if (osdef)
359 /* old style function definition */
360 outchar('o');
361
362 if (fsym->s_scl == STATIC)
363 outchar('s');
364
365 /* name of function */
366 outname(fsym->s_name);
367
368 /* renamed name of function, if necessary */
369 if (fsym->s_rename) {
370 outchar('r');
371 outname(fsym->s_rename);
372 }
373
374 /* argument types and return value */
375 if (osdef) {
376 narg = 0;
377 for (arg = args; arg != NULL; arg = arg->s_nxt)
378 narg++;
379 outchar('f');
380 outint(narg);
381 for (arg = args; arg != NULL; arg = arg->s_nxt)
382 outtype(arg->s_type);
383 outtype(fsym->s_type->t_subt);
384 } else {
385 outtype(fsym->s_type);
386 }
387 }
388
389 /*
390 * write out all information necessary for lint2 to check function
391 * calls
392 *
393 * rvused is set if the return value is used (asigned to a variable)
394 * rvdisc is set if the return value is not used and not ignored
395 * (casted to void)
396 */
397 void
398 outcall(tnode_t *tn, int rvused, int rvdisc)
399 {
400 tnode_t *args, *arg;
401 int narg, n, i;
402 int64_t q;
403 tspec_t t;
404
405 /* reset buffer */
406 outclr();
407
408 /*
409 * line number of .c source, 'c' for function call, Id of current
410 * source (.c or .h), and line in current source
411 */
412 outint(csrc_pos.p_line);
413 outchar('c');
414 outint(getfnid(curr_pos.p_file));
415 outchar('.');
416 outint(curr_pos.p_line);
417
418 /*
419 * flags; 'u' and 'i' must be last to make sure a letter
420 * is between the numeric argument of a flag and the name of
421 * the function
422 */
423 narg = 0;
424 args = tn->tn_right;
425 for (arg = args; arg != NULL; arg = arg->tn_right)
426 narg++;
427 /* informations about arguments */
428 for (n = 1; n <= narg; n++) {
429 /* the last argument is the top one in the tree */
430 for (i = narg, arg = args; i > n; i--, arg = arg->tn_right)
431 continue;
432 arg = arg->tn_left;
433 if (arg->tn_op == CON) {
434 if (isityp(t = arg->tn_type->t_tspec)) {
435 /*
436 * XXX it would probably be better to
437 * explizitly test the sign
438 */
439 if ((q = arg->tn_val->v_quad) == 0) {
440 /* zero constant */
441 outchar('z');
442 } else if (msb(q, t, 0) == 0) {
443 /* positive if casted to signed */
444 outchar('p');
445 } else {
446 /* negative if casted to signed */
447 outchar('n');
448 }
449 outint(n);
450 }
451 } else if (arg->tn_op == AMPER &&
452 arg->tn_left->tn_op == STRING &&
453 arg->tn_left->tn_strg->st_tspec == CHAR) {
454 /* constant string, write all format specifiers */
455 outchar('s');
456 outint(n);
457 outfstrg(arg->tn_left->tn_strg);
458 }
459
460 }
461 /* return value discarded/used/ignored */
462 outchar(rvdisc ? 'd' : (rvused ? 'u' : 'i'));
463
464 /* name of the called function */
465 outname(tn->tn_left->tn_left->tn_sym->s_name);
466
467 /* types of arguments */
468 outchar('f');
469 outint(narg);
470 for (n = 1; n <= narg; n++) {
471 /* the last argument is the top one in the tree */
472 for (i = narg, arg = args; i > n; i--, arg = arg->tn_right)
473 continue;
474 outtype(arg->tn_left->tn_type);
475 }
476 /* expected type of return value */
477 outtype(tn->tn_type);
478 }
479
480 /*
481 * extracts potential format specifiers for printf() and scanf() and
482 * writes them, enclosed in "" and qouted if necessary, to the output buffer
483 */
484 static void
485 outfstrg(strg_t *strg)
486 {
487 int c, oc, first;
488 u_char *cp;
489
490 if (strg->st_tspec != CHAR)
491 LERROR("outfstrg()");
492
493 cp = strg->st_cp;
494
495 outchar('"');
496
497 c = *cp++;
498
499 while (c != '\0') {
500
501 if (c != '%') {
502 c = *cp++;
503 continue;
504 }
505
506 outqchar('%');
507 c = *cp++;
508
509 /* flags for printf and scanf and *-fieldwidth for printf */
510 while (c != '\0' && (c == '-' || c == '+' || c == ' ' ||
511 c == '#' || c == '0' || c == '*')) {
512 outqchar(c);
513 c = *cp++;
514 }
515
516 /* numeric field width */
517 while (c != '\0' && isdigit(c)) {
518 outqchar(c);
519 c = *cp++;
520 }
521
522 /* precision for printf */
523 if (c == '.') {
524 outqchar(c);
525 if ((c = *cp++) == '*') {
526 outqchar(c);
527 c = *cp++;
528 } else {
529 while (c != '\0' && isdigit(c)) {
530 outqchar(c);
531 c = *cp++;
532 }
533 }
534 }
535
536 /* h, l, L and q flags fpr printf and scanf */
537 if (c == 'h' || c == 'l' || c == 'L' || c == 'q') {
538 outqchar(c);
539 c = *cp++;
540 }
541
542 /*
543 * The last character. It is always written so we can detect
544 * invalid format specifiers.
545 */
546 if (c != '\0') {
547 outqchar(c);
548 oc = c;
549 c = *cp++;
550 /*
551 * handle [ for scanf. [-] means that a minus sign
552 * was found at an undefined position.
553 */
554 if (oc == '[') {
555 if (c == '^')
556 c = *cp++;
557 if (c == ']')
558 c = *cp++;
559 first = 1;
560 while (c != '\0' && c != ']') {
561 if (c == '-') {
562 if (!first && *cp != ']')
563 outqchar(c);
564 }
565 first = 0;
566 c = *cp++;
567 }
568 if (c == ']') {
569 outqchar(c);
570 c = *cp++;
571 }
572 }
573 }
574
575 }
576
577 outchar('"');
578 }
579
580 /*
581 * writes a record if sym was used
582 */
583 void
584 outusg(sym_t *sym)
585 {
586 /* reset buffer */
587 outclr();
588
589 /*
590 * line number of .c source, 'u' for used, Id of current
591 * source (.c or .h), and line in current source
592 */
593 outint(csrc_pos.p_line);
594 outchar('u');
595 outint(getfnid(curr_pos.p_file));
596 outchar('.');
597 outint(curr_pos.p_line);
598
599 /* necessary to delimit both numbers */
600 outchar('x');
601
602 /* Den Namen des Symbols ausgeben */
603 outname(sym->s_name);
604 }
605