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