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