xref: /csrg-svn/usr.bin/pascal/src/rval.c (revision 1555)
1771Speter /* Copyright (c) 1979 Regents of the University of California */
2771Speter 
3*1555Speter static	char sccsid[] = "@(#)rval.c 1.4 10/19/80";
4771Speter 
5771Speter #include "whoami.h"
6771Speter #include "0.h"
7771Speter #include "tree.h"
8771Speter #include "opcode.h"
9771Speter #include "objfmt.h"
10771Speter #ifdef PC
11771Speter #   include	"pc.h"
12771Speter #   include "pcops.h"
13771Speter #endif PC
14771Speter 
15771Speter extern	char *opnames[];
16771Speter 
17771Speter #ifdef PC
18771Speter     char	*relts[] =  {
19771Speter 				"_RELEQ" , "_RELNE" ,
20771Speter 				"_RELTLT" , "_RELTGT" ,
21771Speter 				"_RELTLE" , "_RELTGE"
22771Speter 			    };
23771Speter     char	*relss[] =  {
24771Speter 				"_RELEQ" , "_RELNE" ,
25771Speter 				"_RELSLT" , "_RELSGT" ,
26771Speter 				"_RELSLE" , "_RELSGE"
27771Speter 			    };
28771Speter     long	relops[] =  {
29771Speter 				P2EQ , P2NE ,
30771Speter 				P2LT , P2GT ,
31771Speter 				P2LE , P2GE
32771Speter 			    };
33771Speter     long	mathop[] =  {	P2MUL , P2PLUS , P2MINUS };
34771Speter     char	*setop[] =  {	"_MULT" , "_ADDT" , "_SUBT" };
35771Speter #endif PC
36771Speter /*
37771Speter  * Rvalue - an expression.
38771Speter  *
39771Speter  * Contype is the type that the caller would prefer, nand is important
40771Speter  * if constant sets or constant strings are involved, the latter
41771Speter  * because of string padding.
42771Speter  * required is a flag whether an lvalue or an rvalue is required.
43771Speter  * only VARs and structured things can have gt their lvalue this way.
44771Speter  */
45771Speter struct nl *
46771Speter rvalue(r, contype , required )
47771Speter 	int *r;
48771Speter 	struct nl *contype;
49771Speter 	int	required;
50771Speter {
51771Speter 	register struct nl *p, *p1;
52771Speter 	register struct nl *q;
53771Speter 	int c, c1, *rt, w, g;
54771Speter 	char *cp, *cp1, *opname;
55771Speter 	long l;
56771Speter 	double f;
57771Speter 	extern int	flagwas;
58771Speter 	struct csetstr	csetd;
59771Speter #	ifdef PC
60771Speter 	    struct nl	*rettype;
61771Speter 	    long	ctype;
62771Speter 	    long	tempoff;
63771Speter #	endif PC
64771Speter 
65771Speter 	if (r == NIL)
66771Speter 		return (NIL);
67771Speter 	if (nowexp(r))
68771Speter 		return (NIL);
69771Speter 	/*
70771Speter 	 * Pick up the name of the operation
71771Speter 	 * for future error messages.
72771Speter 	 */
73771Speter 	if (r[0] <= T_IN)
74771Speter 		opname = opnames[r[0]];
75771Speter 
76771Speter 	/*
77771Speter 	 * The root of the tree tells us what sort of expression we have.
78771Speter 	 */
79771Speter 	switch (r[0]) {
80771Speter 
81771Speter 	/*
82771Speter 	 * The constant nil
83771Speter 	 */
84771Speter 	case T_NIL:
85771Speter #		ifdef OBJ
86771Speter 		    put(2, O_CON2, 0);
87771Speter #		endif OBJ
88771Speter #		ifdef PC
891477Speter 		    putleaf( P2ICON , 0 , 0 , P2PTR|P2UNDEF , 0 );
90771Speter #		endif PC
91771Speter 		return (nl+TNIL);
92771Speter 
93771Speter 	/*
94771Speter 	 * Function call with arguments.
95771Speter 	 */
96771Speter 	case T_FCALL:
97771Speter #	    ifdef OBJ
98771Speter 		return (funccod(r));
99771Speter #	    endif OBJ
100771Speter #	    ifdef PC
101771Speter 		return (pcfunccod( r ));
102771Speter #	    endif PC
103771Speter 
104771Speter 	case T_VAR:
105771Speter 		p = lookup(r[2]);
106771Speter 		if (p == NIL || p->class == BADUSE)
107771Speter 			return (NIL);
108771Speter 		switch (p->class) {
109771Speter 		    case VAR:
110771Speter 			    /*
111771Speter 			     * If a variable is
112771Speter 			     * qualified then get
113771Speter 			     * the rvalue by a
114771Speter 			     * lvalue and an ind.
115771Speter 			     */
116771Speter 			    if (r[3] != NIL)
117771Speter 				    goto ind;
118771Speter 			    q = p->type;
119771Speter 			    if (q == NIL)
120771Speter 				    return (NIL);
121771Speter #			    ifdef OBJ
122771Speter 				w = width(q);
123771Speter 				switch (w) {
124771Speter 				    case 8:
125771Speter 					put(2, O_RV8 | bn << 8+INDX, p->value[0]);
126771Speter 					break;
127771Speter 				    case 4:
128771Speter 					put(2, O_RV4 | bn << 8+INDX, p->value[0]);
129771Speter 					break;
130771Speter 				    case 2:
131771Speter 					put(2, O_RV2 | bn << 8+INDX, p->value[0]);
132771Speter 					break;
133771Speter 				    case 1:
134771Speter 					put(2, O_RV1 | bn << 8+INDX, p->value[0]);
135771Speter 					break;
136771Speter 				    default:
137771Speter 					put(3, O_RV | bn << 8+INDX, p->value[0], w);
138771Speter 				}
139771Speter #			   endif OBJ
140771Speter #			   ifdef PC
141771Speter 				if ( required == RREQ ) {
142771Speter 				    putRV( p -> symbol , bn , p -> value[0]
143771Speter 					    , p2type( q ) );
144771Speter 				} else {
145771Speter 				    putLV( p -> symbol , bn , p -> value[0]
146771Speter 					    , p2type( q ) );
147771Speter 				}
148771Speter #			   endif PC
149771Speter 			   return (q);
150771Speter 
151771Speter 		    case WITHPTR:
152771Speter 		    case REF:
153771Speter 			    /*
154771Speter 			     * A lvalue for these
155771Speter 			     * is actually what one
156771Speter 			     * might consider a rvalue.
157771Speter 			     */
158771Speter ind:
159771Speter 			    q = lvalue(r, NOFLAGS , LREQ );
160771Speter 			    if (q == NIL)
161771Speter 				    return (NIL);
162771Speter #			    ifdef OBJ
163771Speter 				w = width(q);
164771Speter 				switch (w) {
165771Speter 				    case 8:
166771Speter 					    put(1, O_IND8);
167771Speter 					    break;
168771Speter 				    case 4:
169771Speter 					    put(1, O_IND4);
170771Speter 					    break;
171771Speter 				    case 2:
172771Speter 					    put(1, O_IND2);
173771Speter 					    break;
174771Speter 				    case 1:
175771Speter 					    put(1, O_IND1);
176771Speter 					    break;
177771Speter 				    default:
178771Speter 					    put(2, O_IND, w);
179771Speter 				}
180771Speter #			    endif OBJ
181771Speter #			    ifdef PC
182771Speter 				if ( required == RREQ ) {
183771Speter 				    putop( P2UNARY P2MUL , p2type( q ) );
184771Speter 				}
185771Speter #			    endif PC
186771Speter 			    return (q);
187771Speter 
188771Speter 		    case CONST:
189771Speter 			    if (r[3] != NIL) {
190771Speter 				error("%s is a constant and cannot be qualified", r[2]);
191771Speter 				return (NIL);
192771Speter 			    }
193771Speter 			    q = p->type;
194771Speter 			    if (q == NIL)
195771Speter 				    return (NIL);
196771Speter 			    if (q == nl+TSTR) {
197771Speter 				    /*
198771Speter 				     * Find the size of the string
199771Speter 				     * constant if needed.
200771Speter 				     */
201771Speter 				    cp = p->ptr[0];
202771Speter cstrng:
203771Speter 				    cp1 = cp;
204771Speter 				    for (c = 0; *cp++; c++)
205771Speter 					    continue;
206771Speter 				    if (contype != NIL && !opt('s')) {
207771Speter 					    if (width(contype) < c && classify(contype) == TSTR) {
208771Speter 						    error("Constant string too long");
209771Speter 						    return (NIL);
210771Speter 					    }
211771Speter 					    c = width(contype);
212771Speter 				    }
213771Speter #				    ifdef OBJ
214771Speter 					put( 2 + (sizeof(char *)/sizeof(short))
215771Speter 						, O_CONG, c, cp1);
216771Speter #				    endif OBJ
217771Speter #				    ifdef PC
218771Speter 					putCONG( cp1 , c , required );
219771Speter #				    endif PC
220771Speter 				    /*
221771Speter 				     * Define the string temporarily
222771Speter 				     * so later people can know its
223771Speter 				     * width.
224771Speter 				     * cleaned out by stat.
225771Speter 				     */
226771Speter 				    q = defnl(0, STR, 0, c);
227771Speter 				    q->type = q;
228771Speter 				    return (q);
229771Speter 			    }
230771Speter 			    if (q == nl+T1CHAR) {
231771Speter #				    ifdef OBJ
232771Speter 					put(2, O_CONC, p->value[0]);
233771Speter #				    endif OBJ
234771Speter #				    ifdef PC
235771Speter 					putleaf( P2ICON , p -> value[0] , 0
236771Speter 						, P2CHAR , 0 );
237771Speter #				    endif PC
238771Speter 				    return (q);
239771Speter 			    }
240771Speter 			    /*
241771Speter 			     * Every other kind of constant here
242771Speter 			     */
243771Speter 			    switch (width(q)) {
244771Speter 			    case 8:
245771Speter #ifndef DEBUG
246771Speter #				    ifdef OBJ
247771Speter 					put(2, O_CON8, p->real);
248771Speter #				    endif OBJ
249771Speter #				    ifdef PC
250771Speter 					putCON8( p -> real );
251771Speter #				    endif PC
252771Speter #else
253771Speter 				    if (hp21mx) {
254771Speter 					    f = p->real;
255771Speter 					    conv(&f);
256771Speter 					    l = f.plong;
257771Speter 					    put(2, O_CON4, l);
258771Speter 				    } else
259771Speter #					    ifdef OBJ
260771Speter 						put(2, O_CON8, p->real);
261771Speter #					    endif OBJ
262771Speter #					    ifdef PC
263771Speter 						putCON8( p -> real );
264771Speter #					    endif PC
265771Speter #endif
266771Speter 				    break;
267771Speter 			    case 4:
268771Speter #				    ifdef OBJ
269771Speter 					put(2, O_CON4, p->range[0]);
270771Speter #				    endif OBJ
271771Speter #				    ifdef PC
272771Speter 					putleaf( P2ICON , p -> range[0] , 0
273771Speter 						, P2INT , 0 );
274771Speter #				    endif PC
275771Speter 				    break;
276771Speter 			    case 2:
277771Speter #				    ifdef OBJ
278771Speter 					put(2, O_CON2, ( short ) p->range[0]);
279771Speter #				    endif OBJ
280771Speter #				    ifdef PC
281771Speter 					    /*
282771Speter 					     * make short constants ints
283771Speter 					     */
284771Speter 					putleaf( P2ICON , (short) p -> range[0]
285771Speter 						, 0 , P2INT , 0 );
286771Speter #				    endif PC
287771Speter 				    break;
288771Speter 			    case 1:
289771Speter #				    ifdef OBJ
290771Speter 					put(2, O_CON1, p->value[0]);
291771Speter #				    endif OBJ
292771Speter #				    ifdef PC
293771Speter 					    /*
294771Speter 					     * make char constants ints
295771Speter 					     */
296771Speter 					putleaf( P2ICON , p -> value[0] , 0
297771Speter 						, P2INT , 0 );
298771Speter #				    endif PC
299771Speter 				    break;
300771Speter 			    default:
301771Speter 				    panic("rval");
302771Speter 			    }
303771Speter 			    return (q);
304771Speter 
305771Speter 		    case FUNC:
3061200Speter 		    case FFUNC:
307771Speter 			    /*
308771Speter 			     * Function call with no arguments.
309771Speter 			     */
310771Speter 			    if (r[3]) {
311771Speter 				    error("Can't qualify a function result value");
312771Speter 				    return (NIL);
313771Speter 			    }
314771Speter #			    ifdef OBJ
315771Speter 				return (funccod((int *) r));
316771Speter #			    endif OBJ
317771Speter #			    ifdef PC
318771Speter 				return (pcfunccod( r ));
319771Speter #			    endif PC
320771Speter 
321771Speter 		    case TYPE:
322771Speter 			    error("Type names (e.g. %s) allowed only in declarations", p->symbol);
323771Speter 			    return (NIL);
324771Speter 
325771Speter 		    case PROC:
3261200Speter 		    case FPROC:
327771Speter 			    error("Procedure %s found where expression required", p->symbol);
328771Speter 			    return (NIL);
329771Speter 		    default:
330771Speter 			    panic("rvid");
331771Speter 		}
332771Speter 	/*
333771Speter 	 * Constant sets
334771Speter 	 */
335771Speter 	case T_CSET:
336771Speter #		ifdef OBJ
337771Speter 		    if ( precset( r , contype , &csetd ) ) {
338771Speter 			if ( csetd.csettype == NIL ) {
339771Speter 			    return NIL;
340771Speter 			}
341771Speter 			postcset( r , &csetd );
342771Speter 		    } else {
343771Speter 			put( 2, O_PUSH, -width(csetd.csettype));
344771Speter 			postcset( r , &csetd );
345771Speter 			setran( ( csetd.csettype ) -> type );
346771Speter 			put( 2, O_CON24, set.uprbp);
347771Speter 			put( 2, O_CON24, set.lwrb);
348771Speter 			put( 2, O_CTTOT, 5 + csetd.singcnt + 2 * csetd.paircnt);
349771Speter 		    }
350771Speter 		    return csetd.csettype;
351771Speter #		endif OBJ
352771Speter #		ifdef PC
353771Speter 		    if ( precset( r , contype , &csetd ) ) {
354771Speter 			if ( csetd.csettype == NIL ) {
355771Speter 			    return NIL;
356771Speter 			}
357771Speter 			postcset( r , &csetd );
358771Speter 		    } else {
359771Speter 			putleaf( P2ICON , 0 , 0
360771Speter 				, ADDTYPE( P2FTN | P2INT , P2PTR )
361771Speter 				, "_CTTOT" );
362771Speter 			/*
363771Speter 			 *	allocate a temporary and use it
364771Speter 			 */
365771Speter 			sizes[ cbn ].om_off -= lwidth( csetd.csettype );
366771Speter 			tempoff = sizes[ cbn ].om_off;
367771Speter 			putlbracket( ftnno , -tempoff );
368771Speter 			if ( tempoff < sizes[ cbn ].om_max ) {
369771Speter 			    sizes[ cbn ].om_max = tempoff;
370771Speter 			}
371771Speter 			putLV( 0 , cbn , tempoff , P2PTR|P2STRTY );
372771Speter 			setran( ( csetd.csettype ) -> type );
373771Speter 			putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 );
374771Speter 			putop( P2LISTOP , P2INT );
375771Speter 			putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 );
376771Speter 			putop( P2LISTOP , P2INT );
377771Speter 			postcset( r , &csetd );
378771Speter 			putop( P2CALL , P2INT );
379771Speter 		    }
380771Speter 		    return csetd.csettype;
381771Speter #		endif PC
382771Speter 
383771Speter 	/*
384771Speter 	 * Unary plus and minus
385771Speter 	 */
386771Speter 	case T_PLUS:
387771Speter 	case T_MINUS:
388771Speter 		q = rvalue(r[2], NIL , RREQ );
389771Speter 		if (q == NIL)
390771Speter 			return (NIL);
391771Speter 		if (isnta(q, "id")) {
392771Speter 			error("Operand of %s must be integer or real, not %s", opname, nameof(q));
393771Speter 			return (NIL);
394771Speter 		}
395771Speter 		if (r[0] == T_MINUS) {
396771Speter #		    ifdef OBJ
397771Speter 			put(1, O_NEG2 + (width(q) >> 2));
398771Speter #		    endif OBJ
399771Speter #		    ifdef PC
400771Speter 			putop( P2UNARY P2MINUS , p2type( q ) );
401771Speter #		    endif PC
402771Speter 		    return (isa(q, "d") ? q : nl+T4INT);
403771Speter 		}
404771Speter 		return (q);
405771Speter 
406771Speter 	case T_NOT:
407771Speter 		q = rvalue(r[2], NIL , RREQ );
408771Speter 		if (q == NIL)
409771Speter 			return (NIL);
410771Speter 		if (isnta(q, "b")) {
411771Speter 			error("not must operate on a Boolean, not %s", nameof(q));
412771Speter 			return (NIL);
413771Speter 		}
414771Speter #		ifdef OBJ
415771Speter 		    put(1, O_NOT);
416771Speter #		endif OBJ
417771Speter #		ifdef PC
418771Speter 		    putop( P2NOT , P2INT );
419771Speter #		endif PC
420771Speter 		return (nl+T1BOOL);
421771Speter 
422771Speter 	case T_AND:
423771Speter 	case T_OR:
424771Speter 		p = rvalue(r[2], NIL , RREQ );
425771Speter 		p1 = rvalue(r[3], NIL , RREQ );
426771Speter 		if (p == NIL || p1 == NIL)
427771Speter 			return (NIL);
428771Speter 		if (isnta(p, "b")) {
429771Speter 			error("Left operand of %s must be Boolean, not %s", opname, nameof(p));
430771Speter 			return (NIL);
431771Speter 		}
432771Speter 		if (isnta(p1, "b")) {
433771Speter 			error("Right operand of %s must be Boolean, not %s", opname, nameof(p1));
434771Speter 			return (NIL);
435771Speter 		}
436771Speter #		ifdef OBJ
437771Speter 		    put(1, r[0] == T_AND ? O_AND : O_OR);
438771Speter #		endif OBJ
439771Speter #		ifdef PC
440771Speter 			/*
441771Speter 			 * note the use of & and | rather than && and ||
442771Speter 			 * to force evaluation of all the expressions.
443771Speter 			 */
444771Speter 		    putop( r[ 0 ] == T_AND ? P2AND : P2OR , P2INT );
445771Speter #		endif PC
446771Speter 		return (nl+T1BOOL);
447771Speter 
448771Speter 	case T_DIVD:
449771Speter #		ifdef OBJ
450771Speter 		    p = rvalue(r[2], NIL , RREQ );
451771Speter 		    p1 = rvalue(r[3], NIL , RREQ );
452771Speter #		endif OBJ
453771Speter #		ifdef PC
454771Speter 			/*
455771Speter 			 *	force these to be doubles for the divide
456771Speter 			 */
457771Speter 		    p = rvalue( r[ 2 ] , NIL , RREQ );
458771Speter 		    if ( isnta( p , "d" ) ) {
459771Speter 			putop( P2SCONV , P2DOUBLE );
460771Speter 		    }
461771Speter 		    p1 = rvalue( r[ 3 ] , NIL , RREQ );
462771Speter 		    if ( isnta( p1 , "d" ) ) {
463771Speter 			putop( P2SCONV , P2DOUBLE );
464771Speter 		    }
465771Speter #		endif PC
466771Speter 		if (p == NIL || p1 == NIL)
467771Speter 			return (NIL);
468771Speter 		if (isnta(p, "id")) {
469771Speter 			error("Left operand of / must be integer or real, not %s", nameof(p));
470771Speter 			return (NIL);
471771Speter 		}
472771Speter 		if (isnta(p1, "id")) {
473771Speter 			error("Right operand of / must be integer or real, not %s", nameof(p1));
474771Speter 			return (NIL);
475771Speter 		}
476771Speter #		ifdef OBJ
477771Speter 		    return gen(NIL, r[0], width(p), width(p1));
478771Speter #		endif OBJ
479771Speter #		ifdef PC
480771Speter 		    putop( P2DIV , P2DOUBLE );
481771Speter 		    return nl + TDOUBLE;
482771Speter #		endif PC
483771Speter 
484771Speter 	case T_MULT:
485771Speter 	case T_ADD:
486771Speter 	case T_SUB:
487771Speter #		ifdef OBJ
488771Speter 		    /*
489*1555Speter 		     * If the context hasn't told us the type
490*1555Speter 		     * and a constant set is present
491*1555Speter 		     * we need to infer the type
492*1555Speter 		     * before generating code.
493771Speter 		     */
494*1555Speter 		    if ( contype == NIL ) {
495771Speter 			    codeoff();
496*1555Speter 			    contype = rvalue( r[3] , NIL , RREQ );
497771Speter 			    codeon();
498*1555Speter 			    if ( contype == lookup( intset ) -> type ) {
499*1555Speter 				codeoff();
500*1555Speter 				contype = rvalue( r[2] , NIL , RREQ );
501*1555Speter 				codeon();
502*1555Speter 			    }
503771Speter 		    }
504*1555Speter 		    if ( contype == NIL ) {
505*1555Speter 			return NIL;
506*1555Speter 		    }
507*1555Speter 		    p = rvalue( r[2] , contype , RREQ );
508*1555Speter 		    p1 = rvalue( r[3] , p , RREQ );
509*1555Speter 		    if ( p == NIL || p1 == NIL )
510*1555Speter 			    return NIL;
511771Speter 		    if (isa(p, "id") && isa(p1, "id"))
512771Speter 			return (gen(NIL, r[0], width(p), width(p1)));
513771Speter 		    if (isa(p, "t") && isa(p1, "t")) {
514771Speter 			    if (p != p1) {
515771Speter 				    error("Set types of operands of %s must be identical", opname);
516771Speter 				    return (NIL);
517771Speter 			    }
518771Speter 			    gen(TSET, r[0], width(p), 0);
519771Speter 			    return (p);
520771Speter 		    }
521771Speter #		endif OBJ
522771Speter #		ifdef PC
523771Speter 			/*
524771Speter 			 * the second pass can't do
525771Speter 			 *	long op double  or  double op long
526771Speter 			 * so we have to know the type of both operands
527771Speter 			 * also, it gets tricky for sets, which are done
528771Speter 			 * by function calls.
529771Speter 			 */
530771Speter 		    codeoff();
531771Speter 		    p1 = rvalue( r[ 3 ] , contype , RREQ );
532771Speter 		    codeon();
533771Speter 		    if ( isa( p1 , "id" ) ) {
534771Speter 			p = rvalue( r[ 2 ] , contype , RREQ );
535771Speter 			if ( ( p == NIL ) || ( p1 == NIL ) ) {
536771Speter 			    return NIL;
537771Speter 			}
538771Speter 			if ( isa( p , "i" ) && isa( p1 , "d" ) ) {
539771Speter 			    putop( P2SCONV , P2DOUBLE );
540771Speter 			}
541771Speter 			p1 = rvalue( r[ 3 ] , contype , RREQ );
542771Speter 			if ( isa( p , "d" ) && isa( p1 , "i" ) ) {
543771Speter 			    putop( P2SCONV , P2DOUBLE );
544771Speter 			}
545771Speter 			if ( isa( p , "id" ) ) {
546771Speter 			    if ( isa( p , "d" ) || isa( p1 , "d" ) ) {
547771Speter 				ctype = P2DOUBLE;
548771Speter 				rettype = nl + TDOUBLE;
549771Speter 			    } else {
550771Speter 				ctype = P2INT;
551771Speter 				rettype = nl + T4INT;
552771Speter 			    }
553771Speter 			    putop( mathop[ r[0] - T_MULT ] , ctype );
554771Speter 			    return rettype;
555771Speter 			}
556771Speter 		    }
557771Speter 		    if ( isa( p1 , "t" ) ) {
558771Speter 			putleaf( P2ICON , 0 , 0
559771Speter 			    , ADDTYPE( ADDTYPE( P2PTR | P2STRTY , P2FTN )
560771Speter 					, P2PTR )
561771Speter 			    , setop[ r[0] - T_MULT ] );
562*1555Speter 			if ( contype == NIL ) {
563*1555Speter 			    contype = p1;
564*1555Speter 			    if ( contype == lookup( intset ) -> type ) {
565*1555Speter 				codeoff();
566*1555Speter 				contype = rvalue( r[2] , NIL , LREQ );
567*1555Speter 				codeon();
568*1555Speter 			    }
569*1555Speter 			}
570*1555Speter 			if ( contype == NIL ) {
571*1555Speter 			    return NIL;
572*1555Speter 			}
573*1555Speter 			    /*
574*1555Speter 			     *	allocate a temporary and use it
575*1555Speter 			     */
576*1555Speter 			sizes[ cbn ].om_off -= lwidth( contype );
577771Speter 			tempoff = sizes[ cbn ].om_off;
578771Speter 			putlbracket( ftnno , -tempoff );
579771Speter 			if ( tempoff < sizes[ cbn ].om_max ) {
580771Speter 			    sizes[ cbn ].om_max = tempoff;
581771Speter 			}
582771Speter 			putLV( 0 , cbn , tempoff , P2PTR|P2STRTY );
583*1555Speter 			p = rvalue( r[2] , contype , LREQ );
584771Speter 			if ( isa( p , "t" ) ) {
585771Speter 			    putop( P2LISTOP , P2INT );
586771Speter 			    if ( p == NIL || p1 == NIL ) {
587771Speter 				return NIL;
588771Speter 			    }
589771Speter 			    p1 = rvalue( r[3] , p , LREQ );
590771Speter 			    if ( p != p1 ) {
591771Speter 				error("Set types of operands of %s must be identical", opname);
592771Speter 				return NIL;
593771Speter 			    }
594771Speter 			    putop( P2LISTOP , P2INT );
595771Speter 			    putleaf( P2ICON , lwidth( p1 ) / sizeof( long ) , 0
596771Speter 				    , P2INT , 0 );
597771Speter 			    putop( P2LISTOP , P2INT );
598771Speter 			    putop( P2CALL , P2PTR | P2STRTY );
599771Speter 			    return p;
600771Speter 			}
601771Speter 		    }
602771Speter 		    if ( isnta( p1 , "idt" ) ) {
603771Speter 			    /*
604771Speter 			     *	find type of left operand for error message.
605771Speter 			     */
606771Speter 			p = rvalue( r[2] , contype , RREQ );
607771Speter 		    }
608771Speter 			/*
609771Speter 			 *	don't give spurious error messages.
610771Speter 			 */
611771Speter 		    if ( p == NIL || p1 == NIL ) {
612771Speter 			return NIL;
613771Speter 		    }
614771Speter #		endif PC
615771Speter 		if (isnta(p, "idt")) {
616771Speter 			error("Left operand of %s must be integer, real or set, not %s", opname, nameof(p));
617771Speter 			return (NIL);
618771Speter 		}
619771Speter 		if (isnta(p1, "idt")) {
620771Speter 			error("Right operand of %s must be integer, real or set, not %s", opname, nameof(p1));
621771Speter 			return (NIL);
622771Speter 		}
623771Speter 		error("Cannot mix sets with integers and reals as operands of %s", opname);
624771Speter 		return (NIL);
625771Speter 
626771Speter 	case T_MOD:
627771Speter 	case T_DIV:
628771Speter 		p = rvalue(r[2], NIL , RREQ );
629771Speter 		p1 = rvalue(r[3], NIL , RREQ );
630771Speter 		if (p == NIL || p1 == NIL)
631771Speter 			return (NIL);
632771Speter 		if (isnta(p, "i")) {
633771Speter 			error("Left operand of %s must be integer, not %s", opname, nameof(p));
634771Speter 			return (NIL);
635771Speter 		}
636771Speter 		if (isnta(p1, "i")) {
637771Speter 			error("Right operand of %s must be integer, not %s", opname, nameof(p1));
638771Speter 			return (NIL);
639771Speter 		}
640771Speter #		ifdef OBJ
641771Speter 		    return (gen(NIL, r[0], width(p), width(p1)));
642771Speter #		endif OBJ
643771Speter #		ifdef PC
644771Speter 		    putop( r[ 0 ] == T_DIV ? P2DIV : P2MOD , P2INT );
645771Speter 		    return ( nl + T4INT );
646771Speter #		endif PC
647771Speter 
648771Speter 	case T_EQ:
649771Speter 	case T_NE:
650771Speter 	case T_LT:
651771Speter 	case T_GT:
652771Speter 	case T_LE:
653771Speter 	case T_GE:
654771Speter 		/*
655771Speter 		 * Since there can be no, a priori, knowledge
656771Speter 		 * of the context type should a constant string
657771Speter 		 * or set arise, we must poke around to find such
658771Speter 		 * a type if possible.  Since constant strings can
659771Speter 		 * always masquerade as identifiers, this is always
660771Speter 		 * necessary.
661771Speter 		 */
662771Speter 		codeoff();
663771Speter 		p1 = rvalue(r[3], NIL , RREQ );
664771Speter 		codeon();
665771Speter 		if (p1 == NIL)
666771Speter 			return (NIL);
667771Speter 		contype = p1;
668771Speter #		ifdef OBJ
669*1555Speter 		    if (p1->class == STR) {
670771Speter 			    /*
671771Speter 			     * For constant strings we want
672771Speter 			     * the longest type so as to be
673771Speter 			     * able to do padding (more importantly
674771Speter 			     * avoiding truncation). For clarity,
675771Speter 			     * we get this length here.
676771Speter 			     */
677771Speter 			    codeoff();
678771Speter 			    p = rvalue(r[2], NIL , RREQ );
679771Speter 			    codeon();
680771Speter 			    if (p == NIL)
681771Speter 				    return (NIL);
682*1555Speter 			    if (width(p) > width(p1))
683771Speter 				    contype = p;
684*1555Speter 		    } else if ( isa( p1 , "t" ) ) {
685*1555Speter 			if ( contype == lookup( intset ) -> type ) {
686*1555Speter 			    codeoff();
687*1555Speter 			    contype = rvalue( r[2] , NIL , RREQ );
688*1555Speter 			    codeon();
689*1555Speter 			    if ( contype == NIL ) {
690*1555Speter 				return NIL;
691*1555Speter 			    }
692*1555Speter 			}
693771Speter 		    }
694771Speter 		    /*
695771Speter 		     * Now we generate code for
696771Speter 		     * the operands of the relational
697771Speter 		     * operation.
698771Speter 		     */
699771Speter 		    p = rvalue(r[2], contype , RREQ );
700771Speter 		    if (p == NIL)
701771Speter 			    return (NIL);
702771Speter 		    p1 = rvalue(r[3], p , RREQ );
703771Speter 		    if (p1 == NIL)
704771Speter 			    return (NIL);
705771Speter #		endif OBJ
706771Speter #		ifdef PC
707771Speter 		    c1 = classify( p1 );
708771Speter 		    if ( c1 == TSET || c1 == TSTR || c1 == TREC ) {
709771Speter 			putleaf( P2ICON , 0 , 0
710771Speter 				, ADDTYPE( P2FTN | P2INT , P2PTR )
711771Speter 				, c1 == TSET  ? relts[ r[0] - T_EQ ]
712771Speter 					      : relss[ r[0] - T_EQ ] );
713771Speter 			    /*
714771Speter 			     *	for [] and strings, comparisons are done on
715771Speter 			     *	the maximum width of the two sides.
716771Speter 			     *	for other sets, we have to ask the left side
717771Speter 			     *	what type it is based on the type of the right.
718771Speter 			     *	(this matters for intsets).
719771Speter 			     */
720*1555Speter 			if ( c1 == TSTR ) {
721771Speter 			    codeoff();
722771Speter 			    p = rvalue( r[ 2 ] , NIL , LREQ );
723771Speter 			    codeon();
724*1555Speter 			    if ( p == NIL ) {
725*1555Speter 				return NIL;
726*1555Speter 			    }
727*1555Speter 			    if ( lwidth( p ) > lwidth( p1 ) ) {
728771Speter 				contype = p;
729771Speter 			    }
730*1555Speter 			} else if ( c1 == TSET ) {
731*1555Speter 			    if ( contype == lookup( intset ) -> type ) {
732*1555Speter 				codeoff();
733*1555Speter 				p = rvalue( r[ 2 ] , NIL , LREQ );
734*1555Speter 				codeon();
735*1555Speter 				if ( p == NIL ) {
736*1555Speter 				    return NIL;
737*1555Speter 				}
738*1555Speter 				contype = p;
739*1555Speter 			    }
740771Speter 			} else {
741771Speter 			    contype = p;
742771Speter 			}
743771Speter 			    /*
744771Speter 			     *	put out the width of the comparison.
745771Speter 			     */
746771Speter 			putleaf( P2ICON , lwidth( contype ) , 0 , P2INT , 0 );
747771Speter 			    /*
748771Speter 			     *	and the left hand side,
749771Speter 			     *	for sets, strings, records
750771Speter 			     */
751771Speter 			p = rvalue( r[ 2 ] , contype , LREQ );
752771Speter 			putop( P2LISTOP , P2INT );
753771Speter 			p1 = rvalue( r[ 3 ] , p , LREQ );
754771Speter 			putop( P2LISTOP , P2INT );
755771Speter 			putop( P2CALL , P2INT );
756771Speter 		    } else {
757771Speter 			    /*
758771Speter 			     *	the easy (scalar or error) case
759771Speter 			     */
760771Speter 			p = rvalue( r[ 2 ] , contype , RREQ );
761771Speter 			if ( p == NIL ) {
762771Speter 			    return NIL;
763771Speter 			    /*
764771Speter 			     * since the second pass can't do
765771Speter 			     *	long op double  or  double op long
766771Speter 			     * we may have to do some coercing.
767771Speter 			     */
768771Speter 			if ( isa( p , "i" ) && isa( p1 , "d" ) )
769771Speter 			    putop( P2SCONV , P2DOUBLE );
770771Speter 			}
771771Speter 			p1 = rvalue( r[ 3 ] , p , RREQ );
772771Speter 			if ( isa( p , "d" ) && isa( p1 , "i" ) )
773771Speter 			    putop( P2SCONV , P2DOUBLE );
774771Speter 			putop( relops[ r[0] - T_EQ ] , P2INT );
775771Speter 		    }
776771Speter #		endif PC
777771Speter 		c = classify(p);
778771Speter 		c1 = classify(p1);
779771Speter 		if (nocomp(c) || nocomp(c1))
780771Speter 			return (NIL);
781771Speter 		g = NIL;
782771Speter 		switch (c) {
783771Speter 			case TBOOL:
784771Speter 			case TCHAR:
785771Speter 				if (c != c1)
786771Speter 					goto clash;
787771Speter 				break;
788771Speter 			case TINT:
789771Speter 			case TDOUBLE:
790771Speter 				if (c1 != TINT && c1 != TDOUBLE)
791771Speter 					goto clash;
792771Speter 				break;
793771Speter 			case TSCAL:
794771Speter 				if (c1 != TSCAL)
795771Speter 					goto clash;
796771Speter 				if (scalar(p) != scalar(p1))
797771Speter 					goto nonident;
798771Speter 				break;
799771Speter 			case TSET:
800771Speter 				if (c1 != TSET)
801771Speter 					goto clash;
802771Speter 				if (p != p1)
803771Speter 					goto nonident;
804771Speter 				g = TSET;
805771Speter 				break;
806771Speter 			case TREC:
807771Speter 				if ( c1 != TREC ) {
808771Speter 				    goto clash;
809771Speter 				}
810771Speter 				if ( p != p1 ) {
811771Speter 				    goto nonident;
812771Speter 				}
813771Speter 				if (r[0] != T_EQ && r[0] != T_NE) {
814771Speter 					error("%s not allowed on records - only allow = and <>" , opname );
815771Speter 					return (NIL);
816771Speter 				}
817771Speter 				g = TREC;
818771Speter 				break;
819771Speter 			case TPTR:
820771Speter 			case TNIL:
821771Speter 				if (c1 != TPTR && c1 != TNIL)
822771Speter 					goto clash;
823771Speter 				if (r[0] != T_EQ && r[0] != T_NE) {
824771Speter 					error("%s not allowed on pointers - only allow = and <>" , opname );
825771Speter 					return (NIL);
826771Speter 				}
827771Speter 				break;
828771Speter 			case TSTR:
829771Speter 				if (c1 != TSTR)
830771Speter 					goto clash;
831771Speter 				if (width(p) != width(p1)) {
832771Speter 					error("Strings not same length in %s comparison", opname);
833771Speter 					return (NIL);
834771Speter 				}
835771Speter 				g = TSTR;
836771Speter 				break;
837771Speter 			default:
838771Speter 				panic("rval2");
839771Speter 		}
840771Speter #		ifdef OBJ
841771Speter 		    return (gen(g, r[0], width(p), width(p1)));
842771Speter #		endif OBJ
843771Speter #		ifdef PC
844771Speter 		    return nl + TBOOL;
845771Speter #		endif PC
846771Speter clash:
847771Speter 		error("%ss and %ss cannot be compared - operator was %s", clnames[c], clnames[c1], opname);
848771Speter 		return (NIL);
849771Speter nonident:
850771Speter 		error("%s types must be identical in comparisons - operator was %s", clnames[c1], opname);
851771Speter 		return (NIL);
852771Speter 
853771Speter 	case T_IN:
854771Speter 	    rt = r[3];
855771Speter #	    ifdef OBJ
856771Speter 		if (rt != NIL && rt[0] == T_CSET) {
857771Speter 			precset( rt , NIL , &csetd );
858771Speter 			p1 = csetd.csettype;
859771Speter 			if (p1 == NIL)
860771Speter 			    return NIL;
861771Speter 			postcset( rt, &csetd);
862771Speter 		    } else {
863771Speter 			p1 = stkrval(r[3], NIL , RREQ );
864771Speter 			rt = NIL;
865771Speter 		    }
866771Speter #		endif OBJ
867771Speter #		ifdef PC
868771Speter 		    if (rt != NIL && rt[0] == T_CSET) {
869771Speter 			if ( precset( rt , NIL , &csetd ) ) {
870*1555Speter 			    putleaf( P2ICON , 0 , 0
871*1555Speter 				    , ADDTYPE( P2FTN | P2INT , P2PTR )
872*1555Speter 				    , "_IN" );
873771Speter 			} else {
874771Speter 			    putleaf( P2ICON , 0 , 0
875771Speter 				    , ADDTYPE( P2FTN | P2INT , P2PTR )
876771Speter 				    , "_INCT" );
877771Speter 			}
878771Speter 			p1 = csetd.csettype;
879771Speter 			if (p1 == NIL)
880771Speter 			    return NIL;
881771Speter 		    } else {
882771Speter 			putleaf( P2ICON , 0 , 0
883771Speter 				, ADDTYPE( P2FTN | P2INT , P2PTR )
884771Speter 				, "_IN" );
885771Speter 			codeoff();
886771Speter 			p1 = rvalue(r[3], NIL , LREQ );
887771Speter 			codeon();
888771Speter 		    }
889771Speter #		endif PC
890771Speter 		p = stkrval(r[2], NIL , RREQ );
891771Speter 		if (p == NIL || p1 == NIL)
892771Speter 			return (NIL);
893771Speter 		if (p1->class != SET) {
894771Speter 			error("Right operand of 'in' must be a set, not %s", nameof(p1));
895771Speter 			return (NIL);
896771Speter 		}
897771Speter 		if (incompat(p, p1->type, r[2])) {
898771Speter 			cerror("Index type clashed with set component type for 'in'");
899771Speter 			return (NIL);
900771Speter 		}
901771Speter 		setran(p1->type);
902771Speter #		ifdef OBJ
903771Speter 		    if (rt == NIL || csetd.comptime)
904771Speter 			    put(4, O_IN, width(p1), set.lwrb, set.uprbp);
905771Speter 		    else
906771Speter 			    put(2, O_INCT, 3 + csetd.singcnt + 2*csetd.paircnt);
907771Speter #		endif OBJ
908771Speter #		ifdef PC
909771Speter 		    if ( rt == NIL || rt[0] != T_CSET ) {
910771Speter 			putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 );
911771Speter 			putop( P2LISTOP , P2INT );
912771Speter 			putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 );
913771Speter 			putop( P2LISTOP , P2INT );
914771Speter 			p1 = rvalue( r[3] , NIL , LREQ );
915771Speter 			putop( P2LISTOP , P2INT );
916771Speter 		    } else if ( csetd.comptime ) {
917771Speter 			putleaf( P2ICON , set.lwrb , 0 , P2INT , 0 );
918771Speter 			putop( P2LISTOP , P2INT );
919771Speter 			putleaf( P2ICON , set.uprbp , 0 , P2INT , 0 );
920771Speter 			putop( P2LISTOP , P2INT );
921771Speter 			postcset( r[3] , &csetd );
922771Speter 			putop( P2LISTOP , P2INT );
923771Speter 		    } else {
924771Speter 			postcset( r[3] , &csetd );
925771Speter 		    }
926771Speter 		    putop( P2CALL , P2INT );
927771Speter #		endif PC
928771Speter 		return (nl+T1BOOL);
929771Speter 	default:
930771Speter 		if (r[2] == NIL)
931771Speter 			return (NIL);
932771Speter 		switch (r[0]) {
933771Speter 		default:
934771Speter 			panic("rval3");
935771Speter 
936771Speter 
937771Speter 		/*
938771Speter 		 * An octal number
939771Speter 		 */
940771Speter 		case T_BINT:
941771Speter 			f = a8tol(r[2]);
942771Speter 			goto conint;
943771Speter 
944771Speter 		/*
945771Speter 		 * A decimal number
946771Speter 		 */
947771Speter 		case T_INT:
948771Speter 			f = atof(r[2]);
949771Speter conint:
950771Speter 			if (f > MAXINT || f < MININT) {
951771Speter 				error("Constant too large for this implementation");
952771Speter 				return (NIL);
953771Speter 			}
954771Speter 			l = f;
955771Speter 			if (bytes(l, l) <= 2) {
956771Speter #				ifdef OBJ
957771Speter 				    put(2, O_CON2, ( short ) l);
958771Speter #				endif OBJ
959771Speter #				ifdef PC
960771Speter 				        /*
961771Speter 					 * short constants are ints
962771Speter 					 */
963771Speter 				    putleaf( P2ICON , l , 0 , P2INT , 0 );
964771Speter #				endif PC
965771Speter 				return (nl+T2INT);
966771Speter 			}
967771Speter #			ifdef OBJ
968771Speter 			    put(2, O_CON4, l);
969771Speter #			endif OBJ
970771Speter #			ifdef PC
971771Speter 			    putleaf( P2ICON , l , 0 , P2INT , 0 );
972771Speter #			endif PC
973771Speter 			return (nl+T4INT);
974771Speter 
975771Speter 		/*
976771Speter 		 * A floating point number
977771Speter 		 */
978771Speter 		case T_FINT:
979771Speter #			ifdef OBJ
980771Speter 			    put(2, O_CON8, atof(r[2]));
981771Speter #			endif OBJ
982771Speter #			ifdef PC
983771Speter 			    putCON8( atof( r[2] ) );
984771Speter #			endif PC
985771Speter 			return (nl+TDOUBLE);
986771Speter 
987771Speter 		/*
988771Speter 		 * Constant strings.  Note that constant characters
989771Speter 		 * are constant strings of length one; there is
990771Speter 		 * no constant string of length one.
991771Speter 		 */
992771Speter 		case T_STRNG:
993771Speter 			cp = r[2];
994771Speter 			if (cp[1] == 0) {
995771Speter #				ifdef OBJ
996771Speter 				    put(2, O_CONC, cp[0]);
997771Speter #				endif OBJ
998771Speter #				ifdef PC
999771Speter 				    putleaf( P2ICON , cp[0] , 0 , P2CHAR , 0 );
1000771Speter #				endif PC
1001771Speter 				return (nl+T1CHAR);
1002771Speter 			}
1003771Speter 			goto cstrng;
1004771Speter 		}
1005771Speter 
1006771Speter 	}
1007771Speter }
1008771Speter 
1009771Speter /*
1010771Speter  * Can a class appear
1011771Speter  * in a comparison ?
1012771Speter  */
1013771Speter nocomp(c)
1014771Speter 	int c;
1015771Speter {
1016771Speter 
1017771Speter 	switch (c) {
1018771Speter 		case TREC:
1019771Speter 			if ( opt( 's' ) ) {
1020771Speter 			    standard();
1021771Speter 			    error("record comparison is non-standard");
1022771Speter 			}
1023771Speter 			break;
1024771Speter 		case TFILE:
1025771Speter 		case TARY:
1026771Speter 			error("%ss may not participate in comparisons", clnames[c]);
1027771Speter 			return (1);
1028771Speter 	}
1029771Speter 	return (NIL);
1030771Speter }
1031771Speter 
1032771Speter     /*
1033771Speter      *	this is sort of like gconst, except it works on expression trees
1034771Speter      *	rather than declaration trees, and doesn't give error messages for
1035771Speter      *	non-constant things.
1036771Speter      *	as a side effect this fills in the con structure that gconst uses.
1037771Speter      *	this returns TRUE or FALSE.
1038771Speter      */
1039771Speter constval(r)
1040771Speter 	register int *r;
1041771Speter {
1042771Speter 	register struct nl *np;
1043771Speter 	register *cn;
1044771Speter 	char *cp;
1045771Speter 	int negd, sgnd;
1046771Speter 	long ci;
1047771Speter 
1048771Speter 	con.ctype = NIL;
1049771Speter 	cn = r;
1050771Speter 	negd = sgnd = 0;
1051771Speter loop:
1052771Speter 	    /*
1053771Speter 	     *	cn[2] is nil if error recovery generated a T_STRNG
1054771Speter 	     */
1055771Speter 	if (cn == NIL || cn[2] == NIL)
1056771Speter 		return FALSE;
1057771Speter 	switch (cn[0]) {
1058771Speter 		default:
1059771Speter 			return FALSE;
1060771Speter 		case T_MINUS:
1061771Speter 			negd = 1 - negd;
1062771Speter 			/* and fall through */
1063771Speter 		case T_PLUS:
1064771Speter 			sgnd++;
1065771Speter 			cn = cn[2];
1066771Speter 			goto loop;
1067771Speter 		case T_NIL:
1068771Speter 			con.cpval = NIL;
1069771Speter 			con.cival = 0;
1070771Speter 			con.crval = con.cival;
1071771Speter 			con.ctype = nl + TNIL;
1072771Speter 			break;
1073771Speter 		case T_VAR:
1074771Speter 			np = lookup(cn[2]);
1075771Speter 			if (np == NIL || np->class != CONST) {
1076771Speter 				return FALSE;
1077771Speter 			}
1078771Speter 			if ( cn[3] != NIL ) {
1079771Speter 				return FALSE;
1080771Speter 			}
1081771Speter 			con.ctype = np->type;
1082771Speter 			switch (classify(np->type)) {
1083771Speter 				case TINT:
1084771Speter 					con.crval = np->range[0];
1085771Speter 					break;
1086771Speter 				case TDOUBLE:
1087771Speter 					con.crval = np->real;
1088771Speter 					break;
1089771Speter 				case TBOOL:
1090771Speter 				case TCHAR:
1091771Speter 				case TSCAL:
1092771Speter 					con.cival = np->value[0];
1093771Speter 					con.crval = con.cival;
1094771Speter 					break;
1095771Speter 				case TSTR:
1096771Speter 					con.cpval = np->ptr[0];
1097771Speter 					break;
1098771Speter 				default:
1099771Speter 					con.ctype = NIL;
1100771Speter 					return FALSE;
1101771Speter 			}
1102771Speter 			break;
1103771Speter 		case T_BINT:
1104771Speter 			con.crval = a8tol(cn[2]);
1105771Speter 			goto restcon;
1106771Speter 		case T_INT:
1107771Speter 			con.crval = atof(cn[2]);
1108771Speter 			if (con.crval > MAXINT || con.crval < MININT) {
1109771Speter 				derror("Constant too large for this implementation");
1110771Speter 				con.crval = 0;
1111771Speter 			}
1112771Speter restcon:
1113771Speter 			ci = con.crval;
1114771Speter #ifndef PI0
1115771Speter 			if (bytes(ci, ci) <= 2)
1116771Speter 				con.ctype = nl+T2INT;
1117771Speter 			else
1118771Speter #endif
1119771Speter 				con.ctype = nl+T4INT;
1120771Speter 			break;
1121771Speter 		case T_FINT:
1122771Speter 			con.ctype = nl+TDOUBLE;
1123771Speter 			con.crval = atof(cn[2]);
1124771Speter 			break;
1125771Speter 		case T_STRNG:
1126771Speter 			cp = cn[2];
1127771Speter 			if (cp[1] == 0) {
1128771Speter 				con.ctype = nl+T1CHAR;
1129771Speter 				con.cival = cp[0];
1130771Speter 				con.crval = con.cival;
1131771Speter 				break;
1132771Speter 			}
1133771Speter 			con.ctype = nl+TSTR;
1134771Speter 			con.cpval = cp;
1135771Speter 			break;
1136771Speter 	}
1137771Speter 	if (sgnd) {
1138771Speter 		if (isnta(con.ctype, "id")) {
1139771Speter 			derror("%s constants cannot be signed", nameof(con.ctype));
1140771Speter 			return FALSE;
1141771Speter 		} else if (negd)
1142771Speter 			con.crval = -con.crval;
1143771Speter 	}
1144771Speter 	return TRUE;
1145771Speter }
1146