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