1/* Id: common.c,v 1.122 2015/09/30 20:04:30 ragge Exp */ 2/* $NetBSD: common.c,v 1.7 2016/02/09 20:37:32 plunky Exp $ */ 3/* 4 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28/* 29 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. 30 * 31 * Redistribution and use in source and binary forms, with or without 32 * modification, are permitted provided that the following conditions 33 * are met: 34 * 35 * Redistributions of source code and documentation must retain the above 36 * copyright notice, this list of conditions and the following disclaimer. 37 * Redistributions in binary form must reproduce the above copyright 38 * notice, this list of conditionsand the following disclaimer in the 39 * documentation and/or other materials provided with the distribution. 40 * All advertising materials mentioning features or use of this software 41 * must display the following acknowledgement: 42 * This product includes software developed or owned by Caldera 43 * International, Inc. 44 * Neither the name of Caldera International, Inc. nor the names of other 45 * contributors may be used to endorse or promote products derived from 46 * this software without specific prior written permission. 47 * 48 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 49 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 50 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 51 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 52 * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE 53 * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, 57 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 58 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 59 * POSSIBILITY OF SUCH DAMAGE. 60 */ 61 62#include <stdarg.h> 63#include <stddef.h> 64#include <stdlib.h> 65#include <stdio.h> 66#include <string.h> 67 68#include "pass2.h" 69#include "unicode.h" 70 71# ifndef EXIT 72# define EXIT exit 73# endif 74 75int nerrors = 0; /* number of errors */ 76extern char *ftitle; 77int lineno; 78int savstringsz, newattrsz, nodesszcnt; 79 80int warniserr = 0; 81 82#ifndef WHERE 83#define WHERE(ch) fprintf(stderr, "%s, line %d: ", ftitle, lineno); 84#endif 85 86static void 87incerr(void) 88{ 89 if (++nerrors > 30) 90 cerror("too many errors"); 91} 92 93/* 94 * nonfatal error message 95 * the routine where is different for pass 1 and pass 2; 96 * it tells where the error took place 97 */ 98void 99uerror(const char *s, ...) 100{ 101 va_list ap; 102 103 va_start(ap, s); 104 WHERE('u'); 105 vfprintf(stderr, s, ap); 106 fprintf(stderr, "\n"); 107 va_end(ap); 108 incerr(); 109} 110 111/* 112 * compiler error: die 113 */ 114void 115cerror(const char *s, ...) 116{ 117 va_list ap; 118 119 va_start(ap, s); 120 WHERE('c'); 121 122 /* give the compiler the benefit of the doubt */ 123 if (nerrors && nerrors <= 30) { 124 fprintf(stderr, 125 "cannot recover from earlier errors: goodbye!\n"); 126 } else { 127 fprintf(stderr, "compiler error: "); 128 vfprintf(stderr, s, ap); 129 fprintf(stderr, "\n"); 130 } 131 va_end(ap); 132 EXIT(1); 133} 134 135/* 136 * warning 137 */ 138void 139u8error(const char *s, ...) 140{ 141 va_list ap; 142 va_start(ap, s); 143 WHERE('w'); 144 fprintf(stderr, "warning: "); 145 vfprintf(stderr, s, ap); 146 fprintf(stderr, "\n"); 147 va_end(ap); 148 if (warniserr) 149 incerr(); 150} 151 152#ifdef MKEXT 153int wdebug; 154#endif 155 156/* 157 * warning 158 */ 159void 160werror(const char *s, ...) 161{ 162 extern int wdebug; 163 va_list ap; 164 165 if (wdebug) 166 return; 167 va_start(ap, s); 168 WHERE('w'); 169 fprintf(stderr, "warning: "); 170 vfprintf(stderr, s, ap); 171 fprintf(stderr, "\n"); 172 va_end(ap); 173 if (warniserr) 174 incerr(); 175} 176 177#ifndef MKEXT 178 179struct Warning { 180 char *flag; 181 char warn; 182 char err; 183 char *fmt; 184}; 185 186/* 187 * conditional warnings 188 */ 189struct Warning Warnings[] = { 190 { 191 "truncate", 0, 0, 192 "conversion from '%s' to '%s' may alter its value" 193 }, { 194 "strict-prototypes", 0, 0, 195 "function declaration isn't a prototype" 196 }, { 197 "missing-prototypes", 0, 0, 198 "no previous prototype for `%s'" 199 }, { 200 "implicit-int", 0, 0, 201 "return type defaults to `int'", 202 }, { 203 "implicit-function-declaration", 0, 0, 204 "implicit declaration of function '%s'" 205 }, { 206 "shadow", 0, 0, 207 "declaration of '%s' shadows a %s declaration" 208 }, { 209 "pointer-sign", 0, 0, 210 "illegal pointer combination" 211 }, { 212 "sign-compare", 0, 0, 213 "comparison between signed and unsigned" 214 }, { 215 "unknown-pragmas", 0, 0, 216 "ignoring #pragma %s %s" 217 }, { 218 "unreachable-code", 0, 0, 219 "statement not reached" 220 }, { 221 "deprecated-declarations", 1, 0, 222 "`%s' is deprecated" 223 }, { 224 "attributes", 1, 0, 225 "unsupported attribute `%s'" 226 }, { NULL } 227}; 228 229/* 230 * set the warn/err status of a conditional warning 231 */ 232int 233Wset(char *str, int warn, int err) 234{ 235 struct Warning *w = Warnings; 236 237 for (w = Warnings; w->flag; w++) { 238 if (strcmp(w->flag, str) == 0) { 239 w->warn = warn; 240 w->err = err; 241 return 0; 242 } 243 } 244 return 1; 245} 246 247/* 248 * handle a conditional warning flag. 249 */ 250void 251Wflags(char *str) 252{ 253 struct Warning *w; 254 int isset, iserr; 255 256 /* handle -Werror specially */ 257 if (strcmp("error", str) == 0) { 258 for (w = Warnings; w->flag; w++) 259 w->err = 1; 260 261 warniserr = 1; 262 return; 263 } 264 265 isset = 1; 266 if (strncmp("no-", str, 3) == 0) { 267 str += 3; 268 isset = 0; 269 } 270 271 iserr = 0; 272 if (strncmp("error=", str, 6) == 0) { 273 str += 6; 274 iserr = 1; 275 } 276 277 for (w = Warnings; w->flag; w++) { 278 if (strcmp(w->flag, str) != 0) 279 continue; 280 281 if (isset) { 282 if (iserr) 283 w->err = 1; 284 w->warn = 1; 285 } else if (iserr) { 286 w->err = 0; 287 } else { 288 w->warn = 0; 289 } 290 291 return; 292 } 293 294 fprintf(stderr, "unrecognised warning option '%s'\n", str); 295} 296 297/* 298 * emit a conditional warning 299 */ 300void 301warner(int type, ...) 302{ 303 va_list ap; 304 char *t; 305#ifndef PASS2 306 extern int issyshdr; 307 308 if (issyshdr && type == Wtruncate) 309 return; /* Too many false positives */ 310#endif 311 312 if (Warnings[type].warn == 0) 313 return; /* no warning */ 314 if (Warnings[type].err) { 315 t = "error"; 316 incerr(); 317 } else 318 t = "warning"; 319 320 va_start(ap, type); 321 fprintf(stderr, "%s:%d: %s: ", ftitle, lineno, t); 322 vfprintf(stderr, Warnings[type].fmt, ap); 323 fprintf(stderr, "\n"); 324 va_end(ap); 325} 326#endif /* MKEXT */ 327 328#ifndef MKEXT 329static NODE *freelink; 330int usednodes; 331 332#ifndef LANG_F77 333NODE * 334talloc(void) 335{ 336 register NODE *p; 337 338 usednodes++; 339 340 if (freelink != NULL) { 341 p = freelink; 342 freelink = p->n_left; 343 if (p->n_op != FREE) 344 cerror("node not FREE: %p", p); 345 if (ndebug) 346 printf("alloc node %p from freelist\n", p); 347 return p; 348 } 349 350 p = permalloc(sizeof(NODE)); 351 nodesszcnt += sizeof(NODE); 352 p->n_op = FREE; 353 if (ndebug) 354 printf("alloc node %p from memory\n", p); 355 return p; 356} 357#endif 358 359/* 360 * make a fresh copy of p 361 */ 362NODE * 363tcopy(NODE *p) 364{ 365 NODE *q; 366 367 q = talloc(); 368 *q = *p; 369 370 switch (optype(q->n_op)) { 371 case BITYPE: 372 q->n_right = tcopy(p->n_right); 373 case UTYPE: 374 q->n_left = tcopy(p->n_left); 375 } 376 377 return(q); 378} 379 380#ifndef LANG_F77 381/* 382 * ensure that all nodes have been freed 383 */ 384void 385tcheck(void) 386{ 387#ifdef LANG_CXX 388 extern int inlnodecnt; 389#else 390#define inlnodecnt 0 391#endif 392 393 if (nerrors) 394 return; 395 396 if ((usednodes - inlnodecnt) != 0) 397 cerror("usednodes == %d, inlnodecnt %d", usednodes, inlnodecnt); 398} 399#endif 400 401/* 402 * free the tree p 403 */ 404void 405tfree(NODE *p) 406{ 407 if (p->n_op != FREE) 408 walkf(p, (void (*)(NODE *, void *))nfree, 0); 409} 410 411/* 412 * Free a node, and return its left descendant. 413 * It is up to the caller to know whether the return value is usable. 414 */ 415NODE * 416nfree(NODE *p) 417{ 418 NODE *l; 419#ifdef PCC_DEBUG_NODES 420 NODE *q; 421#endif 422 423 if (p == NULL) 424 cerror("freeing blank node!"); 425 426 l = p->n_left; 427 if (p->n_op == FREE) 428 cerror("freeing FREE node", p); 429#ifdef PCC_DEBUG_NODES 430 q = freelink; 431 while (q != NULL) { 432 if (q == p) 433 cerror("freeing free node %p", p); 434 q = q->n_left; 435 } 436#endif 437 438 if (ndebug) 439 printf("freeing node %p\n", p); 440 p->n_op = FREE; 441 p->n_left = freelink; 442 freelink = p; 443 usednodes--; 444 return l; 445} 446#endif 447 448#ifdef LANG_F77 449#define OPTYPE(x) optype(x) 450#else 451#define OPTYPE(x) coptype(x) 452#endif 453 454#ifdef MKEXT 455#define coptype(o) (dope[o]&TYFLG) 456#else 457#ifndef PASS2 458int cdope(int); 459#define coptype(o) (cdope(o)&TYFLG) 460#else 461#define coptype(o) (dope[o]&TYFLG) 462#endif 463#endif 464 465void 466fwalk(NODE *t, void (*f)(NODE *, int, int *, int *), int down) 467{ 468 469 int down1, down2; 470 471 more: 472 down1 = down2 = 0; 473 474 (*f)(t, down, &down1, &down2); 475 476 switch (OPTYPE( t->n_op )) { 477 478 case BITYPE: 479 fwalk( t->n_left, f, down1 ); 480 t = t->n_right; 481 down = down2; 482 goto more; 483 484 case UTYPE: 485 t = t->n_left; 486 down = down1; 487 goto more; 488 489 } 490} 491 492void 493walkf(NODE *t, void (*f)(NODE *, void *), void *arg) 494{ 495 int opty; 496 497 498 opty = OPTYPE(t->n_op); 499 500 if (opty != LTYPE) 501 walkf( t->n_left, f, arg ); 502 if (opty == BITYPE) 503 walkf( t->n_right, f, arg ); 504 (*f)(t, arg); 505} 506 507int dope[DSIZE]; 508char *opst[DSIZE]; 509 510struct dopest { 511 int dopeop; 512 char opst[8]; 513 int dopeval; 514} indope[] = { 515 { NAME, "NAME", LTYPE, }, 516 { REG, "REG", LTYPE, }, 517 { OREG, "OREG", LTYPE, }, 518 { TEMP, "TEMP", LTYPE, }, 519 { ICON, "ICON", LTYPE, }, 520 { FCON, "FCON", LTYPE, }, 521 { CCODES, "CCODES", LTYPE, }, 522 { UMINUS, "U-", UTYPE, }, 523 { UMUL, "U*", UTYPE, }, 524 { FUNARG, "FUNARG", UTYPE, }, 525 { UCALL, "UCALL", UTYPE|CALLFLG, }, 526 { UFORTCALL, "UFCALL", UTYPE|CALLFLG, }, 527 { COMPL, "~", UTYPE, }, 528 { FORCE, "FORCE", UTYPE, }, 529 { XARG, "XARG", UTYPE, }, 530 { XASM, "XASM", BITYPE, }, 531 { SCONV, "SCONV", UTYPE, }, 532 { PCONV, "PCONV", UTYPE, }, 533 { PLUS, "+", BITYPE|FLOFLG|SIMPFLG|COMMFLG, }, 534 { MINUS, "-", BITYPE|FLOFLG|SIMPFLG, }, 535 { MUL, "*", BITYPE|FLOFLG|MULFLG, }, 536 { AND, "&", BITYPE|SIMPFLG|COMMFLG, }, 537 { CM, ",", BITYPE, }, 538 { ASSIGN, "=", BITYPE|ASGFLG, }, 539 { DIV, "/", BITYPE|FLOFLG|MULFLG|DIVFLG, }, 540 { MOD, "%", BITYPE|DIVFLG, }, 541 { LS, "<<", BITYPE|SHFFLG, }, 542 { RS, ">>", BITYPE|SHFFLG, }, 543 { OR, "|", BITYPE|COMMFLG|SIMPFLG, }, 544 { ER, "^", BITYPE|COMMFLG|SIMPFLG, }, 545 { CALL, "CALL", BITYPE|CALLFLG, }, 546 { FORTCALL, "FCALL", BITYPE|CALLFLG, }, 547 { EQ, "==", BITYPE|LOGFLG, }, 548 { NE, "!=", BITYPE|LOGFLG, }, 549 { LE, "<=", BITYPE|LOGFLG, }, 550 { LT, "<", BITYPE|LOGFLG, }, 551 { GE, ">=", BITYPE|LOGFLG, }, 552 { GT, ">", BITYPE|LOGFLG, }, 553 { UGT, "UGT", BITYPE|LOGFLG, }, 554 { UGE, "UGE", BITYPE|LOGFLG, }, 555 { ULT, "ULT", BITYPE|LOGFLG, }, 556 { ULE, "ULE", BITYPE|LOGFLG, }, 557 { CBRANCH, "CBRANCH", BITYPE, }, 558 { FLD, "FLD", UTYPE, }, 559 { PMCONV, "PMCONV", BITYPE, }, 560 { PVCONV, "PVCONV", BITYPE, }, 561 { RETURN, "RETURN", BITYPE|ASGFLG|ASGOPFLG, }, 562 { GOTO, "GOTO", UTYPE, }, 563 { STASG, "STASG", BITYPE|ASGFLG, }, 564 { STARG, "STARG", UTYPE, }, 565 { STCALL, "STCALL", BITYPE|CALLFLG, }, 566 { USTCALL, "USTCALL", UTYPE|CALLFLG, }, 567 { ADDROF, "U&", UTYPE, }, 568 569 { -1, "", 0 }, 570}; 571 572void 573mkdope(void) 574{ 575 struct dopest *q; 576 577 for( q = indope; q->dopeop >= 0; ++q ){ 578 dope[q->dopeop] = q->dopeval; 579 opst[q->dopeop] = q->opst; 580 } 581} 582 583/* 584 * output a nice description of the type of t 585 */ 586void 587tprint(TWORD t, TWORD q) 588{ 589 static char * tnames[BTMASK+1] = { 590 "undef", 591 "bool", 592 "char", 593 "uchar", 594 "short", 595 "ushort", 596 "int", 597 "unsigned", 598 "long", 599 "ulong", 600 "longlong", 601 "ulonglong", 602 "float", 603 "double", 604 "ldouble", 605 "strty", 606 "unionty", 607 "enumty", 608 "moety", 609 "void", 610 "signed", /* pass1 */ 611 "farg", /* pass1 */ 612 "fimag", /* pass1 */ 613 "dimag", /* pass1 */ 614 "limag", /* pass1 */ 615 "fcomplex", /* pass1 */ 616 "dcomplex", /* pass1 */ 617 "lcomplex", /* pass1 */ 618 "enumty", /* pass1 */ 619 "?", "?", "?" 620 }; 621 622 for(;; t = DECREF(t), q = DECREF(q)) { 623 if (ISCON(q)) 624 putchar('C'); 625 if (ISVOL(q)) 626 putchar('V'); 627 628 if (ISPTR(t)) 629 printf("PTR "); 630 else if (ISFTN(t)) 631 printf("FTN "); 632 else if (ISARY(t)) 633 printf("ARY "); 634 else { 635 printf("%s%s%s", ISCON(q << TSHIFT) ? "const " : "", 636 ISVOL(q << TSHIFT) ? "volatile " : "", tnames[t]); 637 return; 638 } 639 } 640} 641 642/* 643 * Memory allocation routines. 644 * Memory are allocated from the system in MEMCHUNKSZ blocks. 645 * permalloc() returns a bunch of memory that is never freed. 646 * Memory allocated through tmpalloc() will be released the 647 * next time a function is ended (via tmpfree()). 648 */ 649 650#define MEMCHUNKSZ 8192 /* 8k per allocation */ 651struct balloc { 652 char a1; 653 union { 654 long long l; 655 long double d; 656 } a2; 657}; 658 659#define ALIGNMENT offsetof(struct balloc, a2) 660#define ROUNDUP(x) (((x) + ((ALIGNMENT)-1)) & ~((ALIGNMENT)-1)) 661 662static char *allocpole; 663static size_t allocleft; 664size_t permallocsize, tmpallocsize, lostmem; 665 666void * 667permalloc(size_t size) 668{ 669 void *rv; 670 671 if (size > MEMCHUNKSZ) { 672 if ((rv = malloc(size)) == NULL) 673 cerror("permalloc: missing %d bytes", size); 674 return rv; 675 } 676 if (size == 0) 677 cerror("permalloc2"); 678 if (allocleft < size) { 679 /* loses unused bytes */ 680 lostmem += allocleft; 681 if ((allocpole = malloc(MEMCHUNKSZ)) == NULL) 682 cerror("permalloc: out of memory"); 683 allocleft = MEMCHUNKSZ; 684 } 685 size = ROUNDUP(size); 686 rv = &allocpole[MEMCHUNKSZ-allocleft]; 687 allocleft -= size; 688 permallocsize += size; 689 return rv; 690} 691 692void * 693tmpcalloc(size_t size) 694{ 695 void *rv; 696 697 rv = tmpalloc(size); 698 memset(rv, 0, size); 699 return rv; 700} 701 702/* 703 * Duplicate a string onto the temporary heap. 704 */ 705char * 706tmpstrdup(char *str) 707{ 708 size_t len; 709 710 len = strlen(str) + 1; 711 return memcpy(tmpalloc(len), str, len); 712} 713 714/* 715 * Allocation routines for temporary memory. 716 */ 717#if 0 718#define ALLDEBUG(x) printf x 719#else 720#define ALLDEBUG(x) 721#endif 722 723#define NELEM ((MEMCHUNKSZ-ROUNDUP(sizeof(struct xalloc *)))/ALIGNMENT) 724#define ELEMSZ (ALIGNMENT) 725#define MAXSZ (NELEM*ELEMSZ) 726struct xalloc { 727 struct xalloc *next; 728 union { 729 struct balloc b; /* for initial alignment */ 730 char elm[MAXSZ]; 731 } u; 732} *tapole, *tmpole; 733int uselem = NELEM; /* next unused element */ 734 735void * 736tmpalloc(size_t size) 737{ 738 struct xalloc *xp; 739 void *rv; 740 size_t nelem; 741 742 nelem = ROUNDUP(size)/ELEMSZ; 743 ALLDEBUG(("tmpalloc(%ld,%ld) %zd (%zd) ", ELEMSZ, NELEM, size, nelem)); 744 if (nelem > NELEM/2) { 745 size += ROUNDUP(sizeof(struct xalloc *)); 746 if ((xp = malloc(size)) == NULL) 747 cerror("out of memory"); 748 ALLDEBUG(("XMEM! (%zd,%p) ", size, xp)); 749 xp->next = tmpole; 750 tmpole = xp; 751 ALLDEBUG(("rv %p\n", &xp->u.elm[0])); 752 return &xp->u.elm[0]; 753 } 754 if (nelem + uselem >= NELEM) { 755 ALLDEBUG(("MOREMEM! ")); 756 /* alloc more */ 757 if ((xp = malloc(sizeof(struct xalloc))) == NULL) 758 cerror("out of memory"); 759 xp->next = tapole; 760 tapole = xp; 761 uselem = 0; 762 } else 763 xp = tapole; 764 rv = &xp->u.elm[uselem * ELEMSZ]; 765 ALLDEBUG(("elemno %d ", uselem)); 766 uselem += nelem; 767 ALLDEBUG(("new %d rv %p\n", uselem, rv)); 768 return rv; 769} 770 771void 772tmpfree(void) 773{ 774 struct xalloc *x1; 775 776 while (tmpole) { 777 x1 = tmpole; 778 tmpole = tmpole->next; 779 ALLDEBUG(("XMEM! free %p\n", x1)); 780 free(x1); 781 } 782 while (tapole && tapole->next) { 783 x1 = tapole; 784 tapole = tapole->next; 785 ALLDEBUG(("MOREMEM! free %p\n", x1)); 786 free(x1); 787 } 788 if (tapole) 789 uselem = 0; 790} 791 792/* 793 * Set a mark for later removal from the temp heap. 794 */ 795void 796markset(struct mark *m) 797{ 798 m->tmsav = tmpole; 799 m->tasav = tapole; 800 m->elem = uselem; 801} 802 803/* 804 * Remove everything on tmp heap from a mark. 805 */ 806void 807markfree(struct mark *m) 808{ 809 struct xalloc *x1; 810 811 while (tmpole != m->tmsav) { 812 x1 = tmpole; 813 tmpole = tmpole->next; 814 free(x1); 815 } 816 while (tapole != m->tasav) { 817 x1 = tapole; 818 tapole = tapole->next; 819 free(x1); 820 } 821 uselem = m->elem; 822} 823 824/* 825 * Allocate space on the permanent stack for a string of length len+1 826 * and copy it there. 827 * Return the new address. 828 */ 829char * 830newstring(char *s, size_t len) 831{ 832 char *u, *c; 833 834 len++; 835 savstringsz += len; 836 if (allocleft < len) { 837 u = c = permalloc(len); 838 } else { 839 u = c = &allocpole[MEMCHUNKSZ-allocleft]; 840 allocleft -= ROUNDUP(len); 841 permallocsize += ROUNDUP(len); 842 } 843 while (len--) 844 *c++ = *s++; 845 return u; 846} 847 848/* 849 * Do a preorder walk of the CM list p and apply function f on each element. 850 */ 851void 852flist(NODE *p, void (*f)(NODE *, void *), void *arg) 853{ 854 if (p->n_op == CM) { 855 (*f)(p->n_right, arg); 856 flist(p->n_left, f, arg); 857 } else 858 (*f)(p, arg); 859} 860 861/* 862 * The same as flist but postorder. 863 */ 864void 865listf(NODE *p, void (*f)(NODE *)) 866{ 867 if (p->n_op == CM) { 868 listf(p->n_left, f); 869 (*f)(p->n_right); 870 } else 871 (*f)(p); 872} 873 874/* 875 * Get list argument number n from list, or NIL if out of list. 876 */ 877NODE * 878listarg(NODE *p, int n, int *cnt) 879{ 880 NODE *r; 881 882 if (p->n_op == CM) { 883 r = listarg(p->n_left, n, cnt); 884 if (n == ++(*cnt)) 885 r = p->n_right; 886 } else { 887 *cnt = 0; 888 r = n == 0 ? p : NIL; 889 } 890 return r; 891} 892 893/* 894 * Make a type unsigned, if possible. 895 */ 896TWORD 897enunsign(TWORD t) 898{ 899 if (BTYPE(t) >= CHAR && BTYPE(t) <= ULONGLONG) 900 t |= 1; 901 return t; 902} 903 904/* 905 * Make a type signed, if possible. 906 */ 907TWORD 908deunsign(TWORD t) 909{ 910 if (BTYPE(t) >= CHAR && BTYPE(t) <= ULONGLONG) 911 t &= ~1; 912 return t; 913} 914 915/* 916 * Attribute functions. 917 */ 918struct attr * 919attr_new(int type, int nelem) 920{ 921 struct attr *ap; 922 int sz; 923 924 sz = sizeof(struct attr) + nelem * sizeof(union aarg); 925 926 ap = memset(permalloc(sz), 0, sz); 927 newattrsz += sz; 928 ap->atype = type; 929 ap->sz = nelem; 930 return ap; 931} 932 933/* 934 * Add attribute list new before old and return new. 935 */ 936struct attr * 937attr_add(struct attr *old, struct attr *new) 938{ 939 struct attr *ap; 940 941 if (new == NULL) 942 return old; /* nothing to add */ 943 944 for (ap = new; ap->next; ap = ap->next) 945 ; 946 ap->next = old; 947 return new; 948} 949 950/* 951 * Search for attribute type in list ap. Return entry or NULL. 952 */ 953struct attr * 954attr_find(struct attr *ap, int type) 955{ 956 957 for (; ap && ap->atype != type; ap = ap->next) 958 ; 959 return ap; 960} 961 962/* 963 * Copy an attribute struct. 964 * Return destination. 965 */ 966struct attr * 967attr_copy(struct attr *aps, struct attr *apd, int n) 968{ 969 int sz = sizeof(struct attr) + n * sizeof(union aarg); 970 return memcpy(apd, aps, sz); 971} 972 973/* 974 * Duplicate an attribute, like strdup. 975 */ 976struct attr * 977attr_dup(struct attr *ap) 978{ 979 int sz = sizeof(struct attr) + ap->sz * sizeof(union aarg); 980 ap = memcpy(permalloc(sz), ap, sz); 981 ap->next = NULL; 982 return ap; 983} 984 985void * 986xmalloc(int size) 987{ 988 void *rv; 989 990 if ((rv = malloc(size)) == NULL) 991 cerror("out of memory!"); 992 return rv; 993} 994 995void * 996xstrdup(char *s) 997{ 998 void *rv; 999 1000 if ((rv = strdup(s)) == NULL) 1001 cerror("out of memory!"); 1002 return rv; 1003} 1004 1005void * 1006xcalloc(int a, int b) 1007{ 1008 void *rv; 1009 1010 if ((rv = calloc(a, b)) == NULL) 1011 cerror("out of memory!"); 1012 return rv; 1013} 1014