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#include <sys/cdefs.h> 36#if defined(__RCSID) && !defined(lint) 37__RCSID("$NetBSD: emit1.c,v 1.14 2004/06/20 22:20:16 jmc Exp $"); 38#endif 39__FBSDID("$FreeBSD$"); 40 41#include <ctype.h> 42 43#include "lint1.h" 44 45static void outtt(sym_t *, sym_t *); 46static 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 */ 87void 88outtype(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()"); 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 */ 157const char * 158ttos(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 */ 187static void 188outtt(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 */ 217void 218outsym(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()"); 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 */ 292void 293outfdef(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 */ 394void 395outcall(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 */ 481static void 482outfstrg(strg_t *strg) 483{ 484 int c, oc, first; 485 u_char *cp; 486 487 if (strg->st_tspec != CHAR) 488 LERROR("outfstrg()"); 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 */ 580void 581outusg(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} 602