source: mainline/uspace/app/pcc/mip/common.c@ fae4d30

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since fae4d30 was a7de7182, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 14 years ago

Added pcc source tree (contents of pcc-1.0.0.tgz)

  • Property mode set to 100644
File size: 15.9 KB
Line 
1/* $Id: common.c,v 1.93 2011/01/22 22:08:23 ragge Exp $ */
2/*
3 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27/*
28 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 *
34 * Redistributions of source code and documentation must retain the above
35 * copyright notice, this list of conditions and the following disclaimer.
36 * Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditionsand the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed or owned by Caldera
42 * International, Inc.
43 * Neither the name of Caldera International, Inc. nor the names of other
44 * contributors may be used to endorse or promote products derived from
45 * this software without specific prior written permission.
46 *
47 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
48 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
49 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
50 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
51 * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
52 * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
56 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
57 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
58 * POSSIBILITY OF SUCH DAMAGE.
59 */
60
61#include <stdarg.h>
62#include <stdlib.h>
63#include <stdio.h>
64#include <string.h>
65
66#include "pass2.h"
67
68# ifndef EXIT
69# define EXIT exit
70# endif
71
72int nerrors = 0; /* number of errors */
73extern char *ftitle;
74int lineno;
75
76int warniserr = 0;
77
78#ifndef WHERE
79#define WHERE(ch) fprintf(stderr, "%s, line %d: ", ftitle, lineno);
80#endif
81
82static void
83incerr(void)
84{
85 if (++nerrors > 30)
86 cerror("too many errors");
87}
88
89/*
90 * nonfatal error message
91 * the routine where is different for pass 1 and pass 2;
92 * it tells where the error took place
93 */
94void
95uerror(char *s, ...)
96{
97 va_list ap;
98
99 va_start(ap, s);
100 WHERE('u');
101 vfprintf(stderr, s, ap);
102 fprintf(stderr, "\n");
103 va_end(ap);
104 incerr();
105}
106
107/*
108 * compiler error: die
109 */
110void
111cerror(char *s, ...)
112{
113 va_list ap;
114
115 va_start(ap, s);
116 WHERE('c');
117
118 /* give the compiler the benefit of the doubt */
119 if (nerrors && nerrors <= 30) {
120 fprintf(stderr,
121 "cannot recover from earlier errors: goodbye!\n");
122 } else {
123 fprintf(stderr, "compiler error: ");
124 vfprintf(stderr, s, ap);
125 fprintf(stderr, "\n");
126 }
127 va_end(ap);
128 EXIT(1);
129}
130
131/*
132 * warning
133 */
134void
135werror(char *s, ...)
136{
137 va_list ap;
138
139 va_start(ap, s);
140 WHERE('w');
141 fprintf(stderr, "warning: ");
142 vfprintf(stderr, s, ap);
143 fprintf(stderr, "\n");
144 va_end(ap);
145 if (warniserr)
146 incerr();
147}
148
149#ifndef MKEXT
150
151bittype warnary[(NUMW/NUMBITS)+1], werrary[(NUMW/NUMBITS)+1];
152
153static char *warntxt[] = {
154 "conversion to '%s' from '%s' may alter its value",
155 "function declaration isn't a prototype", /* Wstrict_prototypes */
156 "no previous prototype for `%s'", /* Wmissing_prototypes */
157 "return type defaults to `int'", /* Wimplicit_int */
158 /* Wimplicit_function_declaration */
159 "implicit declaration of function '%s'",
160 "declaration of '%s' shadows a %s declaration", /* Wshadow */
161 "illegal pointer combination", /* Wpointer_sign */
162 "comparison between signed and unsigned", /* Wsign_compare */
163 "ignoring #pragma %s %s", /* Wunknown_pragmas */
164 "statement not reached", /* Wunreachable_code */
165};
166
167char *flagstr[] = {
168 "truncate", "strict-prototypes", "missing-prototypes",
169 "implicit-int", "implicit-function-declaration", "shadow",
170 "pointer-sign", "sign-compare", "unknown-pragmas",
171 "unreachable-code",
172};
173
174/*
175 * "emulate" the gcc warning flags.
176 */
177void
178Wflags(char *str)
179{
180 int i, flagval;
181
182 if (strncmp("no-", str, 3) == 0) {
183 str += 3;
184 flagval = 0;
185 } else
186 flagval = 1;
187 if (strcmp(str, "error") == 0) {
188 /* special */
189 for (i = 0; i < NUMW; i++)
190 BITSET(werrary, i);
191 return;
192 }
193 for (i = 0; i < NUMW; i++) {
194 if (strcmp(flagstr[i], str) != 0)
195 continue;
196 if (flagval)
197 BITSET(warnary, i);
198 else
199 BITCLEAR(warnary, i);
200 return;
201 }
202 fprintf(stderr, "unrecognised warning option '%s'\n", str);
203}
204
205/*
206 * Deal with gcc warnings.
207 */
208void
209warner(int type, ...)
210{
211 va_list ap;
212 char *w;
213
214 if (TESTBIT(warnary, type) == 0)
215 return; /* no warning */
216 if (TESTBIT(werrary, type)) {
217 w = "error";
218 incerr();
219 } else
220 w = "warning";
221
222 va_start(ap, type);
223 fprintf(stderr, "%s:%d: %s: ", ftitle, lineno, w);
224 vfprintf(stderr, warntxt[type], ap);
225 fprintf(stderr, "\n");
226 va_end(ap);
227}
228#endif /* MKEXT */
229
230#ifndef MKEXT
231static NODE *freelink;
232static int usednodes;
233
234#ifndef LANG_F77
235NODE *
236talloc()
237{
238 register NODE *p;
239
240 usednodes++;
241
242 if (freelink != NULL) {
243 p = freelink;
244 freelink = p->next;
245 if (p->n_op != FREE)
246 cerror("node not FREE: %p", p);
247 if (nflag)
248 printf("alloc node %p from freelist\n", p);
249 return p;
250 }
251
252 p = permalloc(sizeof(NODE));
253 p->n_op = FREE;
254 if (nflag)
255 printf("alloc node %p from memory\n", p);
256 return p;
257}
258#endif
259
260/*
261 * make a fresh copy of p
262 */
263NODE *
264tcopy(NODE *p)
265{
266 NODE *q;
267
268 q = talloc();
269 *q = *p;
270
271 switch (optype(q->n_op)) {
272 case BITYPE:
273 q->n_right = tcopy(p->n_right);
274 case UTYPE:
275 q->n_left = tcopy(p->n_left);
276 }
277
278 return(q);
279}
280
281#ifndef LANG_F77
282/*
283 * ensure that all nodes have been freed
284 */
285void
286tcheck()
287{
288 extern int inlnodecnt;
289
290 if (nerrors)
291 return;
292
293 if ((usednodes - inlnodecnt) != 0)
294 cerror("usednodes == %d, inlnodecnt %d", usednodes, inlnodecnt);
295}
296#endif
297
298/*
299 * free the tree p
300 */
301void
302tfree(NODE *p)
303{
304 if (p->n_op != FREE)
305 walkf(p, (void (*)(NODE *, void *))nfree, 0);
306}
307
308/*
309 * Free a node, and return its left descendant.
310 * It is up to the caller to know whether the return value is usable.
311 */
312NODE *
313nfree(NODE *p)
314{
315 NODE *l;
316#ifdef PCC_DEBUG_NODES
317 NODE *q;
318#endif
319
320 if (p == NULL)
321 cerror("freeing blank node!");
322
323 l = p->n_left;
324 if (p->n_op == FREE)
325 cerror("freeing FREE node", p);
326#ifdef PCC_DEBUG_NODES
327 q = freelink;
328 while (q != NULL) {
329 if (q == p)
330 cerror("freeing free node %p", p);
331 q = q->next;
332 }
333#endif
334
335 if (nflag)
336 printf("freeing node %p\n", p);
337 p->n_op = FREE;
338 p->next = freelink;
339 freelink = p;
340 usednodes--;
341 return l;
342}
343#endif
344
345#ifdef LANG_F77
346#define OPTYPE(x) optype(x)
347#else
348#define OPTYPE(x) coptype(x)
349#endif
350
351#ifdef MKEXT
352#define coptype(o) (dope[o]&TYFLG)
353#else
354int cdope(int);
355#define coptype(o) (cdope(o)&TYFLG)
356#endif
357
358void
359fwalk(NODE *t, void (*f)(NODE *, int, int *, int *), int down)
360{
361
362 int down1, down2;
363
364 more:
365 down1 = down2 = 0;
366
367 (*f)(t, down, &down1, &down2);
368
369 switch (OPTYPE( t->n_op )) {
370
371 case BITYPE:
372 fwalk( t->n_left, f, down1 );
373 t = t->n_right;
374 down = down2;
375 goto more;
376
377 case UTYPE:
378 t = t->n_left;
379 down = down1;
380 goto more;
381
382 }
383}
384
385void
386walkf(NODE *t, void (*f)(NODE *, void *), void *arg)
387{
388 int opty;
389
390
391 opty = OPTYPE(t->n_op);
392
393 if (opty != LTYPE)
394 walkf( t->n_left, f, arg );
395 if (opty == BITYPE)
396 walkf( t->n_right, f, arg );
397 (*f)(t, arg);
398}
399
400int dope[DSIZE];
401char *opst[DSIZE];
402
403struct dopest {
404 int dopeop;
405 char opst[8];
406 int dopeval;
407} indope[] = {
408 { NAME, "NAME", LTYPE, },
409 { REG, "REG", LTYPE, },
410 { OREG, "OREG", LTYPE, },
411 { TEMP, "TEMP", LTYPE, },
412 { ICON, "ICON", LTYPE, },
413 { FCON, "FCON", LTYPE, },
414 { CCODES, "CCODES", LTYPE, },
415 { UMINUS, "U-", UTYPE, },
416 { UMUL, "U*", UTYPE, },
417 { FUNARG, "FUNARG", UTYPE, },
418 { UCALL, "UCALL", UTYPE|CALLFLG, },
419 { UFORTCALL, "UFCALL", UTYPE|CALLFLG, },
420 { COMPL, "~", UTYPE, },
421 { FORCE, "FORCE", UTYPE, },
422 { XARG, "XARG", UTYPE, },
423 { XASM, "XASM", BITYPE, },
424 { SCONV, "SCONV", UTYPE, },
425 { PCONV, "PCONV", UTYPE, },
426 { PLUS, "+", BITYPE|FLOFLG|SIMPFLG|COMMFLG, },
427 { MINUS, "-", BITYPE|FLOFLG|SIMPFLG, },
428 { MUL, "*", BITYPE|FLOFLG|MULFLG, },
429 { AND, "&", BITYPE|SIMPFLG|COMMFLG, },
430 { CM, ",", BITYPE, },
431 { ASSIGN, "=", BITYPE|ASGFLG, },
432 { DIV, "/", BITYPE|FLOFLG|MULFLG|DIVFLG, },
433 { MOD, "%", BITYPE|DIVFLG, },
434 { LS, "<<", BITYPE|SHFFLG, },
435 { RS, ">>", BITYPE|SHFFLG, },
436 { OR, "|", BITYPE|COMMFLG|SIMPFLG, },
437 { ER, "^", BITYPE|COMMFLG|SIMPFLG, },
438 { STREF, "->", BITYPE, },
439 { CALL, "CALL", BITYPE|CALLFLG, },
440 { FORTCALL, "FCALL", BITYPE|CALLFLG, },
441 { EQ, "==", BITYPE|LOGFLG, },
442 { NE, "!=", BITYPE|LOGFLG, },
443 { LE, "<=", BITYPE|LOGFLG, },
444 { LT, "<", BITYPE|LOGFLG, },
445 { GE, ">=", BITYPE|LOGFLG, },
446 { GT, ">", BITYPE|LOGFLG, },
447 { UGT, "UGT", BITYPE|LOGFLG, },
448 { UGE, "UGE", BITYPE|LOGFLG, },
449 { ULT, "ULT", BITYPE|LOGFLG, },
450 { ULE, "ULE", BITYPE|LOGFLG, },
451 { CBRANCH, "CBRANCH", BITYPE, },
452 { FLD, "FLD", UTYPE, },
453 { PMCONV, "PMCONV", BITYPE, },
454 { PVCONV, "PVCONV", BITYPE, },
455 { RETURN, "RETURN", BITYPE|ASGFLG|ASGOPFLG, },
456 { GOTO, "GOTO", UTYPE, },
457 { STASG, "STASG", BITYPE|ASGFLG, },
458 { STARG, "STARG", UTYPE, },
459 { STCALL, "STCALL", BITYPE|CALLFLG, },
460 { USTCALL, "USTCALL", UTYPE|CALLFLG, },
461 { ADDROF, "U&", UTYPE, },
462
463 { -1, "", 0 },
464};
465
466void
467mkdope()
468{
469 struct dopest *q;
470
471 for( q = indope; q->dopeop >= 0; ++q ){
472 dope[q->dopeop] = q->dopeval;
473 opst[q->dopeop] = q->opst;
474 }
475}
476
477/*
478 * output a nice description of the type of t
479 */
480void
481tprint(FILE *fp, TWORD t, TWORD q)
482{
483 static char * tnames[] = {
484 "undef",
485 "farg",
486 "char",
487 "uchar",
488 "short",
489 "ushort",
490 "int",
491 "unsigned",
492 "long",
493 "ulong",
494 "longlong",
495 "ulonglong",
496 "float",
497 "double",
498 "ldouble",
499 "strty",
500 "unionty",
501 "enumty",
502 "moety",
503 "void",
504 "signed", /* pass1 */
505 "bool", /* pass1 */
506 "fimag", /* pass1 */
507 "dimag", /* pass1 */
508 "limag", /* pass1 */
509 "fcomplex", /* pass1 */
510 "dcomplex", /* pass1 */
511 "lcomplex", /* pass1 */
512 "enumty", /* pass1 */
513 "?", "?"
514 };
515
516 for(;; t = DECREF(t), q = DECREF(q)) {
517 if (ISCON(q))
518 fputc('C', fp);
519 if (ISVOL(q))
520 fputc('V', fp);
521
522 if (ISPTR(t))
523 fprintf(fp, "PTR ");
524 else if (ISFTN(t))
525 fprintf(fp, "FTN ");
526 else if (ISARY(t))
527 fprintf(fp, "ARY ");
528 else {
529 fprintf(fp, "%s%s%s", ISCON(q << TSHIFT) ? "const " : "",
530 ISVOL(q << TSHIFT) ? "volatile " : "", tnames[t]);
531 return;
532 }
533 }
534}
535
536/*
537 * Memory allocation routines.
538 * Memory are allocated from the system in MEMCHUNKSZ blocks.
539 * permalloc() returns a bunch of memory that is never freed.
540 * Memory allocated through tmpalloc() will be released the
541 * next time a function is ended (via tmpfree()).
542 */
543
544#define MEMCHUNKSZ 8192 /* 8k per allocation */
545struct balloc {
546 char a1;
547 union {
548 long long l;
549 long double d;
550 } a2;
551};
552
553#define ALIGNMENT ((long)&((struct balloc *)0)->a2)
554#define ROUNDUP(x) (((x) + ((ALIGNMENT)-1)) & ~((ALIGNMENT)-1))
555
556static char *allocpole;
557static int allocleft;
558int permallocsize, tmpallocsize, lostmem;
559
560void *
561permalloc(int size)
562{
563 void *rv;
564
565 if (size > MEMCHUNKSZ) {
566 if ((rv = malloc(size)) == NULL)
567 cerror("permalloc: missing %d bytes", size);
568 return rv;
569 }
570 if (size <= 0)
571 cerror("permalloc2");
572 if (allocleft < size) {
573 /* looses unused bytes */
574 lostmem += allocleft;
575 if ((allocpole = malloc(MEMCHUNKSZ)) == NULL)
576 cerror("permalloc: out of memory");
577 allocleft = MEMCHUNKSZ;
578 }
579 size = ROUNDUP(size);
580 rv = &allocpole[MEMCHUNKSZ-allocleft];
581 allocleft -= size;
582 permallocsize += size;
583 return rv;
584}
585
586void *
587tmpcalloc(int size)
588{
589 void *rv;
590
591 rv = tmpalloc(size);
592 memset(rv, 0, size);
593 return rv;
594}
595
596/*
597 * Duplicate a string onto the temporary heap.
598 */
599char *
600tmpstrdup(char *str)
601{
602 int len;
603
604 len = strlen(str) + 1;
605 return memcpy(tmpalloc(len), str, len);
606}
607
608/*
609 * Allocation routines for temporary memory.
610 */
611#if 0
612#define ALLDEBUG(x) printf x
613#else
614#define ALLDEBUG(x)
615#endif
616
617#define NELEM ((MEMCHUNKSZ-ROUNDUP(sizeof(struct xalloc *)))/ALIGNMENT)
618#define ELEMSZ (ALIGNMENT)
619#define MAXSZ (NELEM*ELEMSZ)
620struct xalloc {
621 struct xalloc *next;
622 union {
623 struct balloc b; /* for initial alignment */
624 char elm[MAXSZ];
625 } u;
626} *tapole, *tmpole;
627int uselem = NELEM; /* next unused element */
628
629void *
630tmpalloc(int size)
631{
632 struct xalloc *xp;
633 void *rv;
634 size_t nelem;
635
636 nelem = ROUNDUP(size)/ELEMSZ;
637 ALLDEBUG(("tmpalloc(%ld,%ld) %d (%zd) ", ELEMSZ, NELEM, size, nelem));
638 if (nelem > NELEM/2) {
639 xp = malloc(size + ROUNDUP(sizeof(struct xalloc *)));
640 if (xp == NULL)
641 cerror("out of memory");
642 ALLDEBUG(("XMEM! (%ld,%p) ",
643 size + ROUNDUP(sizeof(struct xalloc *)), xp));
644 xp->next = tmpole;
645 tmpole = xp;
646 ALLDEBUG(("rv %p\n", &xp->u.elm[0]));
647 return &xp->u.elm[0];
648 }
649 if (nelem + uselem >= NELEM) {
650 ALLDEBUG(("MOREMEM! "));
651 /* alloc more */
652 if ((xp = malloc(sizeof(struct xalloc))) == NULL)
653 cerror("out of memory");
654 xp->next = tapole;
655 tapole = xp;
656 uselem = 0;
657 } else
658 xp = tapole;
659 rv = &xp->u.elm[uselem * ELEMSZ];
660 ALLDEBUG(("elemno %d ", uselem));
661 uselem += nelem;
662 ALLDEBUG(("new %d rv %p\n", uselem, rv));
663 return rv;
664}
665
666void
667tmpfree()
668{
669 struct xalloc *x1;
670
671 while (tmpole) {
672 x1 = tmpole;
673 tmpole = tmpole->next;
674 ALLDEBUG(("XMEM! free %p\n", x1));
675 free(x1);
676 }
677 while (tapole && tapole->next) {
678 x1 = tapole;
679 tapole = tapole->next;
680 ALLDEBUG(("MOREMEM! free %p\n", x1));
681 free(x1);
682 }
683 if (tapole)
684 uselem = 0;
685}
686
687/*
688 * Set a mark for later removal from the temp heap.
689 */
690void
691markset(struct mark *m)
692{
693 m->tmsav = tmpole;
694 m->tasav = tapole;
695 m->elem = uselem;
696}
697
698/*
699 * Remove everything on tmp heap from a mark.
700 */
701void
702markfree(struct mark *m)
703{
704 struct xalloc *x1;
705
706 while (tmpole != m->tmsav) {
707 x1 = tmpole;
708 tmpole = tmpole->next;
709 free(x1);
710 }
711 while (tapole != m->tasav) {
712 x1 = tapole;
713 tapole = tapole->next;
714 free(x1);
715 }
716 uselem = m->elem;
717}
718
719/*
720 * Allocate space on the permanent stack for a string of length len+1
721 * and copy it there.
722 * Return the new address.
723 */
724char *
725newstring(char *s, int len)
726{
727 char *u, *c;
728
729 len++;
730 if (allocleft < len) {
731 u = c = permalloc(len);
732 } else {
733 u = c = &allocpole[MEMCHUNKSZ-allocleft];
734 allocleft -= ROUNDUP(len+1);
735 }
736 while (len--)
737 *c++ = *s++;
738 return u;
739}
740
741/*
742 * Do a preorder walk of the CM list p and apply function f on each element.
743 */
744void
745flist(NODE *p, void (*f)(NODE *, void *), void *arg)
746{
747 if (p->n_op == CM) {
748 (*f)(p->n_right, arg);
749 flist(p->n_left, f, arg);
750 } else
751 (*f)(p, arg);
752}
753
754/*
755 * The same as flist but postorder.
756 */
757void
758listf(NODE *p, void (*f)(NODE *))
759{
760 if (p->n_op == CM) {
761 listf(p->n_left, f);
762 (*f)(p->n_right);
763 } else
764 (*f)(p);
765}
766
767/*
768 * Get list argument number n from list, or NIL if out of list.
769 */
770NODE *
771listarg(NODE *p, int n, int *cnt)
772{
773 NODE *r;
774
775 if (p->n_op == CM) {
776 r = listarg(p->n_left, n, cnt);
777 if (n == ++(*cnt))
778 r = p->n_right;
779 } else {
780 *cnt = 0;
781 r = n == 0 ? p : NIL;
782 }
783 return r;
784}
Note: See TracBrowser for help on using the repository browser.