Commit | Line | Data |
---|---|---|
3e019e8d DS |
1 | /* |
2 | * Copyright (c) 1980 Regents of the University of California. | |
3 | * All rights reserved. The Berkeley software License Agreement | |
4 | * specifies the terms and conditions for redistribution. | |
5 | */ | |
6 | ||
7 | #ifndef lint | |
8 | static char *sccsid[] = "@(#)expr.c 5.3 (Berkeley) 6/23/85"; | |
9 | #endif not lint | |
10 | ||
11 | /* | |
12 | * expr.c | |
13 | * | |
14 | * Routines for handling expressions, f77 compiler pass 1. | |
15 | * | |
16 | * University of Utah CS Dept modification history: | |
17 | * | |
18 | * $Log: expr.c,v $ | |
19 | * Revision 1.3 86/02/26 17:13:37 rcs | |
20 | * Correct COFR 411. | |
21 | * P. Wong | |
22 | * | |
23 | * Revision 3.16 85/06/21 16:38:09 donn | |
24 | * The fix to mkprim() didn't handle null substring parameters (sigh). | |
25 | * | |
26 | * Revision 3.15 85/06/04 04:37:03 donn | |
27 | * Changed mkprim() to force substring parameters to be integral types. | |
28 | * | |
29 | * Revision 3.14 85/06/04 03:41:52 donn | |
30 | * Change impldcl() to handle functions of type 'undefined'. | |
31 | * | |
32 | * Revision 3.13 85/05/06 23:14:55 donn | |
33 | * Changed mkconv() so that it calls mkaltemp() instead of mktemp() to get | |
34 | * a temporary when converting character strings to integers; previously we | |
35 | * were having problems because mkconv() was called after tempalloc(). | |
36 | * | |
37 | * Revision 3.12 85/03/18 08:07:47 donn | |
38 | * Fixes to help out with short integers -- if integers are by default short, | |
39 | * then so are constants; and if addresses can't be stored in shorts, complain. | |
40 | * | |
41 | * Revision 3.11 85/03/16 22:31:27 donn | |
42 | * Added hack to mkconv() to allow character values of length > 1 to be | |
43 | * converted to numeric types, for Helge Skrivervik. Note that this does | |
44 | * not affect use of the intrinsic ichar() conversion. | |
45 | * | |
46 | * Revision 3.10 85/01/15 21:06:47 donn | |
47 | * Changed mkconv() to comment on implicit conversions; added intrconv() for | |
48 | * use with explicit conversions by intrinsic functions. | |
49 | * | |
50 | * Revision 3.9 85/01/11 21:05:49 donn | |
51 | * Added changes to implement SAVE statements. | |
52 | * | |
53 | * Revision 3.8 84/12/17 02:21:06 donn | |
54 | * Added a test to prevent constant folding from being done on expressions | |
55 | * whose type is not known at that point in mkexpr(). | |
56 | * | |
57 | * Revision 3.7 84/12/11 21:14:17 donn | |
58 | * Removed obnoxious 'excess precision' warning. | |
59 | * | |
60 | * Revision 3.6 84/11/23 01:00:36 donn | |
61 | * Added code to trim excess precision from single-precision constants, and | |
62 | * to warn the user when this occurs. | |
63 | * | |
64 | * Revision 3.5 84/11/23 00:10:39 donn | |
65 | * Changed stfcall() to remark on argument type clashes in 'calls' to | |
66 | * statement functions. | |
67 | * | |
68 | * Revision 3.4 84/11/22 21:21:17 donn | |
69 | * Fixed bug in fix to mkexpr() that caused IMPLICIT to affect intrinsics. | |
70 | * | |
71 | * Revision 3.3 84/11/12 18:26:14 donn | |
72 | * Shuffled some code around so that the compiler remembers to free some vleng | |
73 | * structures which used to just sit around. | |
74 | * | |
75 | * Revision 3.2 84/10/16 19:24:15 donn | |
76 | * Fix for Peter Montgomery's bug with -C and invalid subscripts -- prevent | |
77 | * core dumps by replacing bad subscripts with good ones. | |
78 | * | |
79 | * Revision 3.1 84/10/13 01:31:32 donn | |
80 | * Merged Jerry Berkman's version into mine. | |
81 | * | |
82 | * Revision 2.7 84/09/27 15:42:52 donn | |
83 | * The last fix for multiplying undeclared variables by 0 isn't sufficient, | |
84 | * since the type of the 0 may not be the (implicit) type of the variable. | |
85 | * I added a hack to check the implicit type of implicitly declared | |
86 | * variables... | |
87 | * | |
88 | * Revision 2.6 84/09/14 19:34:03 donn | |
89 | * Problem noted by Mike Vevea -- mkexpr will sometimes attempt to convert | |
90 | * 0 to type UNKNOWN, which is illegal. Fix is to use native type instead. | |
91 | * Not sure how correct (or important) this is... | |
92 | * | |
93 | * Revision 2.5 84/08/05 23:05:27 donn | |
94 | * Added fixes to prevent fixexpr() from slicing and dicing complex conversions | |
95 | * with two operands. | |
96 | * | |
97 | * Revision 2.4 84/08/05 17:34:48 donn | |
98 | * Added an optimization to mklhs() to detect substrings of the form ch(i:i) | |
99 | * and assign constant length 1 to them. | |
100 | * | |
101 | * Revision 2.3 84/07/19 19:38:33 donn | |
102 | * Added a typecast to the last fix. Somehow I missed it the first time... | |
103 | * | |
104 | * Revision 2.2 84/07/19 17:19:57 donn | |
105 | * Caused OPPAREN expressions to inherit the length of their operands, so | |
106 | * that parenthesized character expressions work correctly. | |
107 | * | |
108 | * Revision 2.1 84/07/19 12:03:02 donn | |
109 | * Changed comment headers for UofU. | |
110 | * | |
111 | * Revision 1.2 84/04/06 20:12:17 donn | |
112 | * Fixed bug which caused programs with mixed-type multiplications involving | |
113 | * the constant 0 to choke the compiler. | |
114 | * | |
115 | */ | |
116 | ||
117 | #include "defs.h" | |
118 | ||
119 | ||
120 | /* little routines to create constant blocks */ | |
121 | ||
122 | Constp mkconst(t) | |
123 | register int t; | |
124 | { | |
125 | register Constp p; | |
126 | ||
127 | p = ALLOC(Constblock); | |
128 | p->tag = TCONST; | |
129 | p->vtype = t; | |
130 | return(p); | |
131 | } | |
132 | ||
133 | ||
134 | expptr mklogcon(l) | |
135 | register int l; | |
136 | { | |
137 | register Constp p; | |
138 | ||
139 | p = mkconst(TYLOGICAL); | |
140 | p->const.ci = l; | |
141 | return( (expptr) p ); | |
142 | } | |
143 | ||
144 | ||
145 | ||
146 | expptr mkintcon(l) | |
147 | ftnint l; | |
148 | { | |
149 | register Constp p; | |
150 | int usetype; | |
151 | ||
152 | if(tyint == TYSHORT) | |
153 | { | |
154 | short s = l; | |
155 | if(l != s) | |
156 | usetype = TYLONG; | |
157 | else | |
158 | usetype = TYSHORT; | |
159 | } | |
160 | else | |
161 | usetype = tyint; | |
162 | p = mkconst(usetype); | |
163 | p->const.ci = l; | |
164 | return( (expptr) p ); | |
165 | } | |
166 | ||
167 | ||
168 | ||
169 | expptr mkaddcon(l) | |
170 | register int l; | |
171 | { | |
172 | register Constp p; | |
173 | ||
174 | p = mkconst(TYADDR); | |
175 | p->const.ci = l; | |
176 | return( (expptr) p ); | |
177 | } | |
178 | ||
179 | ||
180 | ||
181 | expptr mkrealcon(t, d) | |
182 | register int t; | |
183 | double d; | |
184 | { | |
185 | register Constp p; | |
186 | ||
187 | p = mkconst(t); | |
188 | p->const.cd[0] = d; | |
189 | return( (expptr) p ); | |
190 | } | |
191 | ||
192 | expptr mkbitcon(shift, leng, s) | |
193 | int shift; | |
194 | register int leng; | |
195 | register char *s; | |
196 | { | |
197 | Constp p; | |
198 | register int i, j, k; | |
199 | register char *bp; | |
200 | int size; | |
201 | ||
202 | size = (shift*leng + BYTESIZE -1)/BYTESIZE; | |
203 | bp = (char *) ckalloc(size); | |
204 | ||
205 | i = 0; | |
206 | ||
207 | #if (HERE == PDP11 || HERE == VAX) | |
208 | j = 0; | |
209 | #else | |
210 | j = size; | |
211 | #endif | |
212 | ||
213 | k = 0; | |
214 | ||
215 | while (leng > 0) | |
216 | { | |
217 | k |= (hextoi(s[--leng]) << i); | |
218 | i += shift; | |
219 | if (i >= BYTESIZE) | |
220 | { | |
221 | #if (HERE == PDP11 || HERE == VAX) | |
222 | bp[j++] = k & MAXBYTE; | |
223 | #else | |
224 | bp[--j] = k & MAXBYTE; | |
225 | #endif | |
226 | k = k >> BYTESIZE; | |
227 | i -= BYTESIZE; | |
228 | } | |
229 | } | |
230 | ||
231 | if (k != 0) | |
232 | #if (HERE == PDP11 || HERE == VAX) | |
233 | bp[j++] = k; | |
234 | #else | |
235 | bp[--j] = k; | |
236 | #endif | |
237 | ||
238 | p = mkconst(TYBITSTR); | |
239 | p->vleng = ICON(size); | |
240 | p->const.ccp = bp; | |
241 | ||
242 | return ((expptr) p); | |
243 | } | |
244 | ||
245 | ||
246 | ||
247 | expptr mkstrcon(l,v) | |
248 | int l; | |
249 | register char *v; | |
250 | { | |
251 | register Constp p; | |
252 | register char *s; | |
253 | ||
254 | p = mkconst(TYCHAR); | |
255 | p->vleng = ICON(l); | |
256 | p->const.ccp = s = (char *) ckalloc(l); | |
257 | while(--l >= 0) | |
258 | *s++ = *v++; | |
259 | return( (expptr) p ); | |
260 | } | |
261 | ||
262 | ||
263 | expptr mkcxcon(realp,imagp) | |
264 | register expptr realp, imagp; | |
265 | { | |
266 | int rtype, itype; | |
267 | register Constp p; | |
268 | ||
269 | rtype = realp->headblock.vtype; | |
270 | itype = imagp->headblock.vtype; | |
271 | ||
272 | if( ISCONST(realp) && ISNUMERIC(rtype) && ISCONST(imagp) && ISNUMERIC(itype) ) | |
273 | { | |
274 | p = mkconst( (rtype==TYDREAL||itype==TYDREAL) ? TYDCOMPLEX : TYCOMPLEX); | |
275 | if( ISINT(rtype) ) | |
276 | p->const.cd[0] = realp->constblock.const.ci; | |
277 | else p->const.cd[0] = realp->constblock.const.cd[0]; | |
278 | if( ISINT(itype) ) | |
279 | p->const.cd[1] = imagp->constblock.const.ci; | |
280 | else p->const.cd[1] = imagp->constblock.const.cd[0]; | |
281 | } | |
282 | else | |
283 | { | |
284 | err("invalid complex constant"); | |
285 | p = (Constp) errnode(); | |
286 | } | |
287 | ||
288 | frexpr(realp); | |
289 | frexpr(imagp); | |
290 | return( (expptr) p ); | |
291 | } | |
292 | ||
293 | ||
294 | expptr errnode() | |
295 | { | |
296 | struct Errorblock *p; | |
297 | p = ALLOC(Errorblock); | |
298 | p->tag = TERROR; | |
299 | p->vtype = TYERROR; | |
300 | return( (expptr) p ); | |
301 | } | |
302 | ||
303 | ||
304 | ||
305 | ||
306 | ||
307 | expptr mkconv(t, p) | |
308 | register int t; | |
309 | register expptr p; | |
310 | { | |
311 | register expptr q; | |
312 | Addrp r, s; | |
313 | register int pt; | |
314 | expptr opconv(); | |
315 | ||
316 | if(t==TYUNKNOWN || t==TYERROR) | |
317 | badtype("mkconv", t); | |
318 | pt = p->headblock.vtype; | |
319 | if(t == pt) | |
320 | return(p); | |
321 | ||
322 | if( pt == TYCHAR && ISNUMERIC(t) ) | |
323 | { | |
324 | warn("implicit conversion of character to numeric type"); | |
325 | ||
326 | /* | |
327 | * Ugly kluge to copy character values into numerics. | |
328 | */ | |
329 | s = mkaltemp(t, ENULL); | |
330 | r = (Addrp) cpexpr(s); | |
331 | r->vtype = TYCHAR; | |
332 | r->varleng = typesize[t]; | |
333 | r->vleng = mkintcon(r->varleng); | |
334 | q = mkexpr(OPASSIGN, r, p); | |
335 | q = mkexpr(OPCOMMA, q, s); | |
336 | return(q); | |
337 | } | |
338 | ||
339 | #if SZADDR > SZSHORT | |
340 | if( pt == TYADDR && t == TYSHORT) | |
341 | { | |
342 | err("insufficient precision to hold address type"); | |
343 | return( errnode() ); | |
344 | } | |
345 | #endif | |
346 | if( pt == TYADDR && ISNUMERIC(t) ) | |
347 | warn("implicit conversion of address to numeric type"); | |
348 | ||
349 | if( ISCONST(p) && pt!=TYADDR) | |
350 | { | |
351 | q = (expptr) mkconst(t); | |
352 | consconv(t, &(q->constblock.const), | |
353 | p->constblock.vtype, &(p->constblock.const) ); | |
354 | frexpr(p); | |
355 | } | |
356 | #if TARGET == PDP11 | |
357 | else if(ISINT(t) && pt==TYCHAR) | |
358 | { | |
359 | q = mkexpr(OPBITAND, opconv(p,TYSHORT), ICON(255)); | |
360 | if(t == TYLONG) | |
361 | q = opconv(q, TYLONG); | |
362 | } | |
363 | #endif | |
364 | else | |
365 | q = opconv(p, t); | |
366 | ||
367 | if(t == TYCHAR) | |
368 | q->constblock.vleng = ICON(1); | |
369 | return(q); | |
370 | } | |
371 | ||
372 | ||
373 | ||
374 | /* intrinsic conversions */ | |
375 | expptr intrconv(t, p) | |
376 | register int t; | |
377 | register expptr p; | |
378 | { | |
379 | register expptr q; | |
380 | register int pt; | |
381 | expptr opconv(); | |
382 | ||
383 | if(t==TYUNKNOWN || t==TYERROR) | |
384 | badtype("intrconv", t); | |
385 | pt = p->headblock.vtype; | |
386 | if(t == pt) | |
387 | return(p); | |
388 | ||
389 | else if( ISCONST(p) && pt!=TYADDR) | |
390 | { | |
391 | q = (expptr) mkconst(t); | |
392 | consconv(t, &(q->constblock.const), | |
393 | p->constblock.vtype, &(p->constblock.const) ); | |
394 | frexpr(p); | |
395 | } | |
396 | #if TARGET == PDP11 | |
397 | else if(ISINT(t) && pt==TYCHAR) | |
398 | { | |
399 | q = mkexpr(OPBITAND, opconv(p,TYSHORT), ICON(255)); | |
400 | if(t == TYLONG) | |
401 | q = opconv(q, TYLONG); | |
402 | } | |
403 | #endif | |
404 | else | |
405 | q = opconv(p, t); | |
406 | ||
407 | if(t == TYCHAR) | |
408 | q->constblock.vleng = ICON(1); | |
409 | return(q); | |
410 | } | |
411 | ||
412 | ||
413 | ||
414 | expptr opconv(p, t) | |
415 | expptr p; | |
416 | int t; | |
417 | { | |
418 | register expptr q; | |
419 | ||
420 | q = mkexpr(OPCONV, p, PNULL); | |
421 | q->headblock.vtype = t; | |
422 | return(q); | |
423 | } | |
424 | ||
425 | ||
426 | ||
427 | expptr addrof(p) | |
428 | expptr p; | |
429 | { | |
430 | return( mkexpr(OPADDR, p, PNULL) ); | |
431 | } | |
432 | ||
433 | ||
434 | ||
435 | tagptr cpexpr(p) | |
436 | register tagptr p; | |
437 | { | |
438 | register tagptr e; | |
439 | int tag; | |
440 | register chainp ep, pp; | |
441 | tagptr cpblock(); | |
442 | ||
443 | static int blksize[ ] = | |
444 | { 0, | |
445 | sizeof(struct Nameblock), | |
446 | sizeof(struct Constblock), | |
447 | sizeof(struct Exprblock), | |
448 | sizeof(struct Addrblock), | |
449 | sizeof(struct Tempblock), | |
450 | sizeof(struct Primblock), | |
451 | sizeof(struct Listblock), | |
452 | sizeof(struct Errorblock) | |
453 | }; | |
454 | ||
455 | if(p == NULL) | |
456 | return(NULL); | |
457 | ||
458 | if( (tag = p->tag) == TNAME) | |
459 | return(p); | |
460 | ||
461 | e = cpblock( blksize[p->tag] , p); | |
462 | ||
463 | switch(tag) | |
464 | { | |
465 | case TCONST: | |
466 | if(e->constblock.vtype == TYCHAR) | |
467 | { | |
468 | e->constblock.const.ccp = | |
469 | copyn(1+strlen(e->constblock.const.ccp), | |
470 | e->constblock.const.ccp); | |
471 | e->constblock.vleng = | |
472 | (expptr) cpexpr(e->constblock.vleng); | |
473 | } | |
474 | case TERROR: | |
475 | break; | |
476 | ||
477 | case TEXPR: | |
478 | e->exprblock.leftp = (expptr) cpexpr(p->exprblock.leftp); | |
479 | e->exprblock.rightp = (expptr) cpexpr(p->exprblock.rightp); | |
480 | break; | |
481 | ||
482 | case TLIST: | |
483 | if(pp = p->listblock.listp) | |
484 | { | |
485 | ep = e->listblock.listp = | |
486 | mkchain( cpexpr(pp->datap), CHNULL); | |
487 | for(pp = pp->nextp ; pp ; pp = pp->nextp) | |
488 | ep = ep->nextp = | |
489 | mkchain( cpexpr(pp->datap), CHNULL); | |
490 | } | |
491 | break; | |
492 | ||
493 | case TADDR: | |
494 | e->addrblock.vleng = (expptr) cpexpr(e->addrblock.vleng); | |
495 | e->addrblock.memoffset = (expptr)cpexpr(e->addrblock.memoffset); | |
496 | e->addrblock.istemp = NO; | |
497 | break; | |
498 | ||
499 | case TTEMP: | |
500 | e->tempblock.vleng = (expptr) cpexpr(e->tempblock.vleng); | |
501 | e->tempblock.istemp = NO; | |
502 | break; | |
503 | ||
504 | case TPRIM: | |
505 | e->primblock.argsp = (struct Listblock *) | |
506 | cpexpr(e->primblock.argsp); | |
507 | e->primblock.fcharp = (expptr) cpexpr(e->primblock.fcharp); | |
508 | e->primblock.lcharp = (expptr) cpexpr(e->primblock.lcharp); | |
509 | break; | |
510 | ||
511 | default: | |
512 | badtag("cpexpr", tag); | |
513 | } | |
514 | ||
515 | return(e); | |
516 | } | |
517 | \f | |
518 | frexpr(p) | |
519 | register tagptr p; | |
520 | { | |
521 | register chainp q; | |
522 | ||
523 | if(p == NULL) | |
524 | return; | |
525 | ||
526 | switch(p->tag) | |
527 | { | |
528 | case TCONST: | |
529 | switch (p->constblock.vtype) | |
530 | { | |
531 | case TYBITSTR: | |
532 | case TYCHAR: | |
533 | case TYHOLLERITH: | |
534 | free( (charptr) (p->constblock.const.ccp) ); | |
535 | frexpr(p->constblock.vleng); | |
536 | } | |
537 | break; | |
538 | ||
539 | case TADDR: | |
540 | if (!optimflag && p->addrblock.istemp) | |
541 | { | |
542 | frtemp(p); | |
543 | return; | |
544 | } | |
545 | frexpr(p->addrblock.vleng); | |
546 | frexpr(p->addrblock.memoffset); | |
547 | break; | |
548 | ||
549 | case TTEMP: | |
550 | frexpr(p->tempblock.vleng); | |
551 | break; | |
552 | ||
553 | case TERROR: | |
554 | break; | |
555 | ||
556 | case TNAME: | |
557 | return; | |
558 | ||
559 | case TPRIM: | |
560 | frexpr(p->primblock.argsp); | |
561 | frexpr(p->primblock.fcharp); | |
562 | frexpr(p->primblock.lcharp); | |
563 | break; | |
564 | ||
565 | case TEXPR: | |
566 | frexpr(p->exprblock.leftp); | |
567 | if(p->exprblock.rightp) | |
568 | frexpr(p->exprblock.rightp); | |
569 | break; | |
570 | ||
571 | case TLIST: | |
572 | for(q = p->listblock.listp ; q ; q = q->nextp) | |
573 | frexpr(q->datap); | |
574 | frchain( &(p->listblock.listp) ); | |
575 | break; | |
576 | ||
577 | default: | |
578 | badtag("frexpr", p->tag); | |
579 | } | |
580 | ||
581 | free( (charptr) p ); | |
582 | } | |
583 | \f | |
584 | /* fix up types in expression; replace subtrees and convert | |
585 | names to address blocks */ | |
586 | ||
587 | expptr fixtype(p) | |
588 | register tagptr p; | |
589 | { | |
590 | ||
591 | if(p == 0) | |
592 | return(0); | |
593 | ||
594 | switch(p->tag) | |
595 | { | |
596 | case TCONST: | |
597 | return( (expptr) p ); | |
598 | ||
599 | case TADDR: | |
600 | p->addrblock.memoffset = fixtype(p->addrblock.memoffset); | |
601 | return( (expptr) p); | |
602 | ||
603 | case TTEMP: | |
604 | return( (expptr) p); | |
605 | ||
606 | case TERROR: | |
607 | return( (expptr) p); | |
608 | ||
609 | default: | |
610 | badtag("fixtype", p->tag); | |
611 | ||
612 | case TEXPR: | |
613 | return( fixexpr(p) ); | |
614 | ||
615 | case TLIST: | |
616 | return( (expptr) p ); | |
617 | ||
618 | case TPRIM: | |
619 | if(p->primblock.argsp && p->primblock.namep->vclass!=CLVAR) | |
620 | { | |
621 | if(p->primblock.namep->vtype == TYSUBR) | |
622 | { | |
623 | err("function invocation of subroutine"); | |
624 | return( errnode() ); | |
625 | } | |
626 | else | |
627 | return( mkfunct(p) ); | |
628 | } | |
629 | else return( mklhs(p) ); | |
630 | } | |
631 | } | |
632 | ||
633 | ||
634 | ||
635 | ||
636 | ||
637 | /* special case tree transformations and cleanups of expression trees */ | |
638 | ||
639 | expptr fixexpr(p) | |
640 | register Exprp p; | |
641 | { | |
642 | expptr lp; | |
643 | register expptr rp; | |
644 | register expptr q; | |
645 | int opcode, ltype, rtype, ptype, mtype; | |
646 | expptr lconst, rconst; | |
647 | expptr mkpower(); | |
648 | ||
649 | if( ISERROR(p) ) | |
650 | return( (expptr) p ); | |
651 | else if(p->tag != TEXPR) | |
652 | badtag("fixexpr", p->tag); | |
653 | opcode = p->opcode; | |
654 | if (ISCONST(p->leftp)) | |
655 | lconst = (expptr) cpexpr(p->leftp); | |
656 | else | |
657 | lconst = NULL; | |
658 | if (p->rightp && ISCONST(p->rightp)) | |
659 | rconst = (expptr) cpexpr(p->rightp); | |
660 | else | |
661 | rconst = NULL; | |
662 | lp = p->leftp = fixtype(p->leftp); | |
663 | ltype = lp->headblock.vtype; | |
664 | if(opcode==OPASSIGN && lp->tag!=TADDR && lp->tag!=TTEMP) | |
665 | { | |
666 | err("left side of assignment must be variable"); | |
667 | frexpr(p); | |
668 | return( errnode() ); | |
669 | } | |
670 | ||
671 | if(p->rightp) | |
672 | { | |
673 | rp = p->rightp = fixtype(p->rightp); | |
674 | rtype = rp->headblock.vtype; | |
675 | } | |
676 | else | |
677 | { | |
678 | rp = NULL; | |
679 | rtype = 0; | |
680 | } | |
681 | ||
682 | if(ltype==TYERROR || rtype==TYERROR) | |
683 | { | |
684 | frexpr(p); | |
685 | frexpr(lconst); | |
686 | frexpr(rconst); | |
687 | return( errnode() ); | |
688 | } | |
689 | ||
690 | /* force folding if possible */ | |
691 | if( ISCONST(lp) && (rp==NULL || ISCONST(rp)) ) | |
692 | { | |
693 | q = mkexpr(opcode, lp, rp); | |
694 | if( ISCONST(q) ) | |
695 | { | |
696 | frexpr(lconst); | |
697 | frexpr(rconst); | |
698 | return(q); | |
699 | } | |
700 | free( (charptr) q ); /* constants did not fold */ | |
701 | } | |
702 | ||
703 | if( (ptype = cktype(opcode, ltype, rtype)) == TYERROR) | |
704 | { | |
705 | frexpr(p); | |
706 | frexpr(lconst); | |
707 | frexpr(rconst); | |
708 | return( errnode() ); | |
709 | } | |
710 | ||
711 | switch(opcode) | |
712 | { | |
713 | case OPCONCAT: | |
714 | if(p->vleng == NULL) | |
715 | p->vleng = mkexpr(OPPLUS, | |
716 | cpexpr(lp->headblock.vleng), | |
717 | cpexpr(rp->headblock.vleng) ); | |
718 | break; | |
719 | ||
720 | case OPASSIGN: | |
721 | case OPPLUSEQ: | |
722 | case OPSTAREQ: | |
723 | if(ltype == rtype) | |
724 | break; | |
725 | #if TARGET == VAX | |
726 | if( ! rconst && ISREAL(ltype) && ISREAL(rtype) ) | |
727 | break; | |
728 | #endif | |
729 | if( ISCOMPLEX(ltype) || ISCOMPLEX(rtype) ) | |
730 | break; | |
731 | if( ONEOF(ltype, MSKADDR|MSKINT) && ONEOF(rtype, MSKADDR|MSKINT) | |
732 | #if FAMILY==PCC | |
733 | && typesize[ltype]>=typesize[rtype] ) | |
734 | #else | |
735 | && typesize[ltype]==typesize[rtype] ) | |
736 | #endif | |
737 | break; | |
738 | if (rconst) | |
739 | { | |
740 | p->rightp = fixtype( mkconv(ptype, cpexpr(rconst)) ); | |
741 | frexpr(rp); | |
742 | } | |
743 | else | |
744 | p->rightp = fixtype(mkconv(ptype, rp)); | |
745 | break; | |
746 | ||
747 | case OPSLASH: | |
748 | if( ISCOMPLEX(rtype) ) | |
749 | { | |
750 | p = (Exprp) call2(ptype, | |
751 | ptype==TYCOMPLEX? "c_div" : "z_div", | |
752 | mkconv(ptype, lp), mkconv(ptype, rp) ); | |
753 | break; | |
754 | } | |
755 | case OPPLUS: | |
756 | case OPMINUS: | |
757 | case OPSTAR: | |
758 | case OPMOD: | |
759 | #if TARGET == VAX | |
760 | if(ptype==TYDREAL && ( (ltype==TYREAL && ! lconst ) || | |
761 | (rtype==TYREAL && ! rconst ) )) | |
762 | break; | |
763 | #endif | |
764 | if( ISCOMPLEX(ptype) ) | |
765 | break; | |
766 | if(ltype != ptype) | |
767 | if (lconst) | |
768 | { | |
769 | p->leftp = fixtype(mkconv(ptype, | |
770 | cpexpr(lconst))); | |
771 | frexpr(lp); | |
772 | } | |
773 | else | |
774 | p->leftp = fixtype(mkconv(ptype,lp)); | |
775 | if(rtype != ptype) | |
776 | if (rconst) | |
777 | { | |
778 | p->rightp = fixtype(mkconv(ptype, | |
779 | cpexpr(rconst))); | |
780 | frexpr(rp); | |
781 | } | |
782 | else | |
783 | p->rightp = fixtype(mkconv(ptype,rp)); | |
784 | break; | |
785 | ||
786 | case OPPOWER: | |
787 | return( mkpower(p) ); | |
788 | ||
789 | case OPLT: | |
790 | case OPLE: | |
791 | case OPGT: | |
792 | case OPGE: | |
793 | case OPEQ: | |
794 | case OPNE: | |
795 | if(ltype == rtype) | |
796 | break; | |
797 | mtype = cktype(OPMINUS, ltype, rtype); | |
798 | #if TARGET == VAX | |
799 | if(mtype==TYDREAL && ( (ltype==TYREAL && ! lconst) || | |
800 | (rtype==TYREAL && ! rconst) )) | |
801 | break; | |
802 | #endif | |
803 | if( ISCOMPLEX(mtype) ) | |
804 | break; | |
805 | if(ltype != mtype) | |
806 | if (lconst) | |
807 | { | |
808 | p->leftp = fixtype(mkconv(mtype, | |
809 | cpexpr(lconst))); | |
810 | frexpr(lp); | |
811 | } | |
812 | else | |
813 | p->leftp = fixtype(mkconv(mtype,lp)); | |
814 | if(rtype != mtype) | |
815 | if (rconst) | |
816 | { | |
817 | p->rightp = fixtype(mkconv(mtype, | |
818 | cpexpr(rconst))); | |
819 | frexpr(rp); | |
820 | } | |
821 | else | |
822 | p->rightp = fixtype(mkconv(mtype,rp)); | |
823 | break; | |
824 | ||
825 | ||
826 | case OPCONV: | |
827 | if(ISCOMPLEX(p->vtype)) | |
828 | { | |
829 | ptype = cktype(OPCONV, p->vtype, ltype); | |
830 | if(p->rightp) | |
831 | ptype = cktype(OPCONV, ptype, rtype); | |
832 | break; | |
833 | } | |
834 | ptype = cktype(OPCONV, p->vtype, ltype); | |
835 | if(lp->tag==TEXPR && lp->exprblock.opcode==OPCOMMA) | |
836 | { | |
837 | lp->exprblock.rightp = | |
838 | fixtype( mkconv(ptype, lp->exprblock.rightp) ); | |
839 | free( (charptr) p ); | |
840 | p = (Exprp) lp; | |
841 | } | |
842 | break; | |
843 | ||
844 | case OPADDR: | |
845 | if(lp->tag==TEXPR && lp->exprblock.opcode==OPADDR) | |
846 | fatal("addr of addr"); | |
847 | break; | |
848 | ||
849 | case OPCOMMA: | |
850 | case OPQUEST: | |
851 | case OPCOLON: | |
852 | break; | |
853 | ||
854 | case OPPAREN: | |
855 | p->vleng = (expptr) cpexpr( lp->headblock.vleng ); | |
856 | break; | |
857 | ||
858 | case OPMIN: | |
859 | case OPMAX: | |
860 | ptype = p->vtype; | |
861 | break; | |
862 | ||
863 | default: | |
864 | break; | |
865 | } | |
866 | ||
867 | p->vtype = ptype; | |
868 | frexpr(lconst); | |
869 | frexpr(rconst); | |
870 | return((expptr) p); | |
871 | } | |
872 | \f | |
873 | #if SZINT < SZLONG | |
874 | /* | |
875 | for efficient subscripting, replace long ints by shorts | |
876 | in easy places | |
877 | */ | |
878 | ||
879 | expptr shorten(p) | |
880 | register expptr p; | |
881 | { | |
882 | register expptr q; | |
883 | ||
884 | if(p->headblock.vtype != TYLONG) | |
885 | return(p); | |
886 | ||
887 | switch(p->tag) | |
888 | { | |
889 | case TERROR: | |
890 | case TLIST: | |
891 | return(p); | |
892 | ||
893 | case TCONST: | |
894 | case TADDR: | |
895 | return( mkconv(TYINT,p) ); | |
896 | ||
897 | case TEXPR: | |
898 | break; | |
899 | ||
900 | default: | |
901 | badtag("shorten", p->tag); | |
902 | } | |
903 | ||
904 | switch(p->exprblock.opcode) | |
905 | { | |
906 | case OPPLUS: | |
907 | case OPMINUS: | |
908 | case OPSTAR: | |
909 | q = shorten( cpexpr(p->exprblock.rightp) ); | |
910 | if(q->headblock.vtype == TYINT) | |
911 | { | |
912 | p->exprblock.leftp = shorten(p->exprblock.leftp); | |
913 | if(p->exprblock.leftp->headblock.vtype == TYLONG) | |
914 | frexpr(q); | |
915 | else | |
916 | { | |
917 | frexpr(p->exprblock.rightp); | |
918 | p->exprblock.rightp = q; | |
919 | p->exprblock.vtype = TYINT; | |
920 | } | |
921 | } | |
922 | break; | |
923 | ||
924 | case OPNEG: | |
925 | case OPPAREN: | |
926 | p->exprblock.leftp = shorten(p->exprblock.leftp); | |
927 | if(p->exprblock.leftp->headblock.vtype == TYINT) | |
928 | p->exprblock.vtype = TYINT; | |
929 | break; | |
930 | ||
931 | case OPCALL: | |
932 | case OPCCALL: | |
933 | p = mkconv(TYINT,p); | |
934 | break; | |
935 | default: | |
936 | break; | |
937 | } | |
938 | ||
939 | return(p); | |
940 | } | |
941 | #endif | |
942 | /* fix an argument list, taking due care for special first level cases */ | |
943 | ||
944 | fixargs(doput, p0) | |
945 | int doput; /* doput is true if the function is not intrinsic; | |
946 | was used to decide whether to do a putconst, | |
947 | but this is no longer done here (Feb82)*/ | |
948 | struct Listblock *p0; | |
949 | { | |
950 | register chainp p; | |
951 | register tagptr q, t; | |
952 | register int qtag; | |
953 | int nargs; | |
954 | Addrp mkscalar(); | |
955 | ||
956 | nargs = 0; | |
957 | if(p0) | |
958 | for(p = p0->listp ; p ; p = p->nextp) | |
959 | { | |
960 | ++nargs; | |
961 | q = p->datap; | |
962 | qtag = q->tag; | |
963 | if(qtag == TCONST) | |
964 | { | |
965 | ||
966 | /* | |
967 | if(q->constblock.vtype == TYSHORT) | |
968 | q = (tagptr) mkconv(tyint, q); | |
969 | */ | |
970 | p->datap = q ; | |
971 | } | |
972 | else if(qtag==TPRIM && q->primblock.argsp==0 && | |
973 | q->primblock.namep->vclass==CLPROC) | |
974 | p->datap = (tagptr) mkaddr(q->primblock.namep); | |
975 | else if(qtag==TPRIM && q->primblock.argsp==0 && | |
976 | q->primblock.namep->vdim!=NULL) | |
977 | p->datap = (tagptr) mkscalar(q->primblock.namep); | |
978 | else if(qtag==TPRIM && q->primblock.argsp==0 && | |
979 | q->primblock.namep->vdovar && | |
980 | (t = (tagptr) memversion(q->primblock.namep)) ) | |
981 | p->datap = (tagptr) fixtype(t); | |
982 | else | |
983 | p->datap = (tagptr) fixtype(q); | |
984 | } | |
985 | return(nargs); | |
986 | } | |
987 | ||
988 | ||
989 | Addrp mkscalar(np) | |
990 | register Namep np; | |
991 | { | |
992 | register Addrp ap; | |
993 | ||
994 | vardcl(np); | |
995 | ap = mkaddr(np); | |
996 | ||
997 | #if TARGET == VAX || TARGET == TAHOE | |
998 | /* on the VAX, prolog causes array arguments | |
999 | to point at the (0,...,0) element, except when | |
1000 | subscript checking is on | |
1001 | */ | |
1002 | #ifdef SDB | |
1003 | if( !checksubs && !sdbflag && np->vstg==STGARG) | |
1004 | #else | |
1005 | if( !checksubs && np->vstg==STGARG) | |
1006 | #endif | |
1007 | { | |
1008 | register struct Dimblock *dp; | |
1009 | dp = np->vdim; | |
1010 | frexpr(ap->memoffset); | |
1011 | ap->memoffset = mkexpr(OPSTAR, | |
1012 | (np->vtype==TYCHAR ? | |
1013 | cpexpr(np->vleng) : | |
1014 | (tagptr)ICON(typesize[np->vtype]) ), | |
1015 | cpexpr(dp->baseoffset) ); | |
1016 | } | |
1017 | #endif | |
1018 | return(ap); | |
1019 | } | |
1020 | ||
1021 | ||
1022 | ||
1023 | ||
1024 | ||
1025 | expptr mkfunct(p) | |
1026 | register struct Primblock *p; | |
1027 | { | |
1028 | struct Entrypoint *ep; | |
1029 | Addrp ap; | |
1030 | struct Extsym *extp; | |
1031 | register Namep np; | |
1032 | register expptr q; | |
1033 | expptr intrcall(), stfcall(); | |
1034 | int k, nargs; | |
1035 | int class; | |
1036 | ||
1037 | if(p->tag != TPRIM) | |
1038 | return( errnode() ); | |
1039 | ||
1040 | np = p->namep; | |
1041 | class = np->vclass; | |
1042 | ||
1043 | if(class == CLUNKNOWN) | |
1044 | { | |
1045 | np->vclass = class = CLPROC; | |
1046 | if(np->vstg == STGUNKNOWN) | |
1047 | { | |
1048 | if(np->vtype!=TYSUBR && (k = intrfunct(np->varname)) ) | |
1049 | { | |
1050 | np->vstg = STGINTR; | |
1051 | np->vardesc.varno = k; | |
1052 | np->vprocclass = PINTRINSIC; | |
1053 | } | |
1054 | else | |
1055 | { | |
1056 | extp = mkext( varunder(VL,np->varname) ); | |
1057 | if(extp->extstg == STGCOMMON) | |
1058 | warn("conflicting declarations", np->varname); | |
1059 | extp->extstg = STGEXT; | |
1060 | np->vstg = STGEXT; | |
1061 | np->vardesc.varno = extp - extsymtab; | |
1062 | np->vprocclass = PEXTERNAL; | |
1063 | } | |
1064 | } | |
1065 | else if(np->vstg==STGARG) | |
1066 | { | |
1067 | if(np->vtype!=TYCHAR && !ftn66flag) | |
1068 | warn("Dummy procedure not declared EXTERNAL. Code may be wrong."); | |
1069 | np->vprocclass = PEXTERNAL; | |
1070 | } | |
1071 | } | |
1072 | ||
1073 | if(class != CLPROC) | |
1074 | fatali("invalid class code %d for function", class); | |
1075 | if(p->fcharp || p->lcharp) | |
1076 | { | |
1077 | err("no substring of function call"); | |
1078 | goto error; | |
1079 | } | |
1080 | impldcl(np); | |
1081 | nargs = fixargs( np->vprocclass!=PINTRINSIC, p->argsp); | |
1082 | ||
1083 | switch(np->vprocclass) | |
1084 | { | |
1085 | case PEXTERNAL: | |
1086 | ap = mkaddr(np); | |
1087 | call: | |
1088 | q = mkexpr(OPCALL, ap, p->argsp); | |
1089 | if( (q->exprblock.vtype = np->vtype) == TYUNKNOWN) | |
1090 | { | |
1091 | err("attempt to use untyped function"); | |
1092 | goto error; | |
1093 | } | |
1094 | if(np->vleng) | |
1095 | q->exprblock.vleng = (expptr) cpexpr(np->vleng); | |
1096 | break; | |
1097 | ||
1098 | case PINTRINSIC: | |
1099 | q = intrcall(np, p->argsp, nargs); | |
1100 | break; | |
1101 | ||
1102 | case PSTFUNCT: | |
1103 | q = stfcall(np, p->argsp); | |
1104 | break; | |
1105 | ||
1106 | case PTHISPROC: | |
1107 | warn("recursive call"); | |
1108 | for(ep = entries ; ep ; ep = ep->entnextp) | |
1109 | if(ep->enamep == np) | |
1110 | break; | |
1111 | if(ep == NULL) | |
1112 | fatal("mkfunct: impossible recursion"); | |
1113 | ap = builtin(np->vtype, varstr(XL, ep->entryname->extname) ); | |
1114 | goto call; | |
1115 | ||
1116 | default: | |
1117 | fatali("mkfunct: impossible vprocclass %d", | |
1118 | (int) (np->vprocclass) ); | |
1119 | } | |
1120 | free( (charptr) p ); | |
1121 | return(q); | |
1122 | ||
1123 | error: | |
1124 | frexpr(p); | |
1125 | return( errnode() ); | |
1126 | } | |
1127 | ||
1128 | ||
1129 | ||
1130 | LOCAL expptr stfcall(np, actlist) | |
1131 | Namep np; | |
1132 | struct Listblock *actlist; | |
1133 | { | |
1134 | register chainp actuals; | |
1135 | int nargs; | |
1136 | chainp oactp, formals; | |
1137 | int type; | |
1138 | expptr q, rhs, ap; | |
1139 | Namep tnp; | |
1140 | register struct Rplblock *rp; | |
1141 | struct Rplblock *tlist; | |
1142 | ||
1143 | if(actlist) | |
1144 | { | |
1145 | actuals = actlist->listp; | |
1146 | free( (charptr) actlist); | |
1147 | } | |
1148 | else | |
1149 | actuals = NULL; | |
1150 | oactp = actuals; | |
1151 | ||
1152 | nargs = 0; | |
1153 | tlist = NULL; | |
1154 | if( (type = np->vtype) == TYUNKNOWN) | |
1155 | { | |
1156 | err("attempt to use untyped statement function"); | |
1157 | q = errnode(); | |
1158 | goto ret; | |
1159 | } | |
1160 | formals = (chainp) (np->varxptr.vstfdesc->datap); | |
1161 | rhs = (expptr) (np->varxptr.vstfdesc->nextp); | |
1162 | ||
1163 | /* copy actual arguments into temporaries */ | |
1164 | while(actuals!=NULL && formals!=NULL) | |
1165 | { | |
1166 | rp = ALLOC(Rplblock); | |
1167 | rp->rplnp = tnp = (Namep) (formals->datap); | |
1168 | ap = fixtype(actuals->datap); | |
1169 | if(tnp->vtype==ap->headblock.vtype && tnp->vtype!=TYCHAR | |
1170 | && (ap->tag==TCONST || ap->tag==TADDR || ap->tag==TTEMP) ) | |
1171 | { | |
1172 | rp->rplvp = (expptr) ap; | |
1173 | rp->rplxp = NULL; | |
1174 | rp->rpltag = ap->tag; | |
1175 | } | |
1176 | else { | |
1177 | rp->rplvp = (expptr) mktemp(tnp->vtype, tnp->vleng); | |
1178 | rp->rplxp = fixtype( mkexpr(OPASSIGN, cpexpr(rp->rplvp), ap) ); | |
1179 | if( (rp->rpltag = rp->rplxp->tag) == TERROR) | |
1180 | err("disagreement of argument types in statement function call"); | |
1181 | else if(tnp->vtype!=ap->headblock.vtype) | |
1182 | warn("argument type mismatch in statement function"); | |
1183 | } | |
1184 | rp->rplnextp = tlist; | |
1185 | tlist = rp; | |
1186 | actuals = actuals->nextp; | |
1187 | formals = formals->nextp; | |
1188 | ++nargs; | |
1189 | } | |
1190 | ||
1191 | if(actuals!=NULL || formals!=NULL) | |
1192 | err("statement function definition and argument list differ"); | |
1193 | ||
1194 | /* | |
1195 | now push down names involved in formal argument list, then | |
1196 | evaluate rhs of statement function definition in this environment | |
1197 | */ | |
1198 | ||
1199 | if(tlist) /* put tlist in front of the rpllist */ | |
1200 | { | |
1201 | for(rp = tlist; rp->rplnextp; rp = rp->rplnextp) | |
1202 | ; | |
1203 | rp->rplnextp = rpllist; | |
1204 | rpllist = tlist; | |
1205 | } | |
1206 | ||
1207 | q = (expptr) mkconv(type, fixtype(cpexpr(rhs)) ); | |
1208 | ||
1209 | /* now generate the tree ( t1=a1, (t2=a2,... , f))))) */ | |
1210 | while(--nargs >= 0) | |
1211 | { | |
1212 | if(rpllist->rplxp) | |
1213 | q = mkexpr(OPCOMMA, rpllist->rplxp, q); | |
1214 | rp = rpllist->rplnextp; | |
1215 | frexpr(rpllist->rplvp); | |
1216 | free(rpllist); | |
1217 | rpllist = rp; | |
1218 | } | |
1219 | ||
1220 | ret: | |
1221 | frchain( &oactp ); | |
1222 | return(q); | |
1223 | } | |
1224 | ||
1225 | ||
1226 | ||
1227 | ||
1228 | Addrp mkplace(np) | |
1229 | register Namep np; | |
1230 | { | |
1231 | register Addrp s; | |
1232 | register struct Rplblock *rp; | |
1233 | int regn; | |
1234 | ||
1235 | /* is name on the replace list? */ | |
1236 | ||
1237 | for(rp = rpllist ; rp ; rp = rp->rplnextp) | |
1238 | { | |
1239 | if(np == rp->rplnp) | |
1240 | { | |
1241 | if(rp->rpltag == TNAME) | |
1242 | { | |
1243 | np = (Namep) (rp->rplvp); | |
1244 | break; | |
1245 | } | |
1246 | else return( (Addrp) cpexpr(rp->rplvp) ); | |
1247 | } | |
1248 | } | |
1249 | ||
1250 | /* is variable a DO index in a register ? */ | |
1251 | ||
1252 | if(np->vdovar && ( (regn = inregister(np)) >= 0) ) | |
1253 | if(np->vtype == TYERROR) | |
1254 | return( (Addrp) errnode() ); | |
1255 | else | |
1256 | { | |
1257 | s = ALLOC(Addrblock); | |
1258 | s->tag = TADDR; | |
1259 | s->vstg = STGREG; | |
1260 | s->vtype = TYIREG; | |
1261 | s->issaved = np->vsave; | |
1262 | s->memno = regn; | |
1263 | s->memoffset = ICON(0); | |
1264 | return(s); | |
1265 | } | |
1266 | ||
1267 | vardcl(np); | |
1268 | return(mkaddr(np)); | |
1269 | } | |
1270 | ||
1271 | ||
1272 | ||
1273 | ||
1274 | expptr mklhs(p) | |
1275 | register struct Primblock *p; | |
1276 | { | |
1277 | expptr suboffset(); | |
1278 | register Addrp s; | |
1279 | Namep np; | |
1280 | ||
1281 | if(p->tag != TPRIM) | |
1282 | return( (expptr) p ); | |
1283 | np = p->namep; | |
1284 | ||
1285 | s = mkplace(np); | |
1286 | if(s->tag!=TADDR || s->vstg==STGREG) | |
1287 | { | |
1288 | free( (charptr) p ); | |
1289 | return( (expptr) s ); | |
1290 | } | |
1291 | ||
1292 | /* compute the address modified by subscripts */ | |
1293 | ||
1294 | s->memoffset = mkexpr(OPPLUS, s->memoffset, suboffset(p) ); | |
1295 | frexpr(p->argsp); | |
1296 | p->argsp = NULL; | |
1297 | ||
1298 | /* now do substring part */ | |
1299 | ||
1300 | if(p->fcharp || p->lcharp) | |
1301 | { | |
1302 | if(np->vtype != TYCHAR) | |
1303 | errstr("substring of noncharacter %s", varstr(VL,np->varname)); | |
1304 | else { | |
1305 | if(p->lcharp == NULL) | |
1306 | p->lcharp = (expptr) cpexpr(s->vleng); | |
1307 | frexpr(s->vleng); | |
1308 | if(p->fcharp) | |
1309 | { | |
1310 | if(p->fcharp->tag == TPRIM && p->lcharp->tag == TPRIM | |
1311 | && p->fcharp->primblock.namep == p->lcharp->primblock.namep) | |
1312 | /* A trivial optimization -- upper == lower */ | |
1313 | s->vleng = ICON(1); | |
1314 | else | |
1315 | s->vleng = mkexpr(OPMINUS, p->lcharp, | |
1316 | mkexpr(OPMINUS, p->fcharp, ICON(1) )); | |
1317 | } | |
1318 | else | |
1319 | s->vleng = p->lcharp; | |
1320 | } | |
1321 | } | |
1322 | ||
1323 | s->vleng = fixtype( s->vleng ); | |
1324 | s->memoffset = fixtype( s->memoffset ); | |
1325 | free( (charptr) p ); | |
1326 | return( (expptr) s ); | |
1327 | } | |
1328 | ||
1329 | ||
1330 | ||
1331 | ||
1332 | ||
1333 | deregister(np) | |
1334 | Namep np; | |
1335 | { | |
1336 | if(nregvar>0 && regnamep[nregvar-1]==np) | |
1337 | { | |
1338 | --nregvar; | |
1339 | #if FAMILY == DMR | |
1340 | putnreg(); | |
1341 | #endif | |
1342 | } | |
1343 | } | |
1344 | ||
1345 | ||
1346 | ||
1347 | ||
1348 | Addrp memversion(np) | |
1349 | register Namep np; | |
1350 | { | |
1351 | register Addrp s; | |
1352 | ||
1353 | if(np->vdovar==NO || (inregister(np)<0) ) | |
1354 | return(NULL); | |
1355 | np->vdovar = NO; | |
1356 | s = mkplace(np); | |
1357 | np->vdovar = YES; | |
1358 | return(s); | |
1359 | } | |
1360 | ||
1361 | ||
1362 | ||
1363 | inregister(np) | |
1364 | register Namep np; | |
1365 | { | |
1366 | register int i; | |
1367 | ||
1368 | for(i = 0 ; i < nregvar ; ++i) | |
1369 | if(regnamep[i] == np) | |
1370 | return( regnum[i] ); | |
1371 | return(-1); | |
1372 | } | |
1373 | ||
1374 | ||
1375 | ||
1376 | ||
1377 | enregister(np) | |
1378 | Namep np; | |
1379 | { | |
1380 | if( inregister(np) >= 0) | |
1381 | return(YES); | |
1382 | if(nregvar >= maxregvar) | |
1383 | return(NO); | |
1384 | vardcl(np); | |
1385 | if( ONEOF(np->vtype, MSKIREG) ) | |
1386 | { | |
1387 | regnamep[nregvar++] = np; | |
1388 | if(nregvar > highregvar) | |
1389 | highregvar = nregvar; | |
1390 | #if FAMILY == DMR | |
1391 | putnreg(); | |
1392 | #endif | |
1393 | return(YES); | |
1394 | } | |
1395 | else | |
1396 | return(NO); | |
1397 | } | |
1398 | ||
1399 | ||
1400 | ||
1401 | ||
1402 | expptr suboffset(p) | |
1403 | register struct Primblock *p; | |
1404 | { | |
1405 | int n; | |
1406 | expptr size; | |
1407 | expptr oftwo(); | |
1408 | chainp cp; | |
1409 | expptr offp, prod; | |
1410 | expptr subcheck(); | |
1411 | struct Dimblock *dimp; | |
1412 | expptr sub[MAXDIM+1]; | |
1413 | register Namep np; | |
1414 | ||
1415 | np = p->namep; | |
1416 | offp = ICON(0); | |
1417 | n = 0; | |
1418 | if(p->argsp) | |
1419 | for(cp = p->argsp->listp ; cp ; ++n, cp = cp->nextp) | |
1420 | { | |
1421 | sub[n] = fixtype(cpexpr(cp->datap)); | |
1422 | if ( ! ISINT(sub[n]->headblock.vtype)) { | |
1423 | errstr("%s: non-integer subscript expression", | |
1424 | varstr(VL, np->varname) ); | |
1425 | /* Provide a substitute -- go on to find more errors */ | |
1426 | frexpr(sub[n]); | |
1427 | sub[n] = ICON(1); | |
1428 | } | |
1429 | if(n > maxdim) | |
1430 | { | |
1431 | char str[28+VL]; | |
1432 | sprintf(str, "%s: more than %d subscripts", | |
1433 | varstr(VL, np->varname), maxdim ); | |
1434 | err( str ); | |
1435 | break; | |
1436 | } | |
1437 | } | |
1438 | ||
1439 | dimp = np->vdim; | |
1440 | if(n>0 && dimp==NULL) | |
1441 | errstr("%s: subscripts on scalar variable", | |
1442 | varstr(VL, np->varname), maxdim ); | |
1443 | else if(dimp && dimp->ndim!=n) | |
1444 | errstr("wrong number of subscripts on %s", | |
1445 | varstr(VL, np->varname) ); | |
1446 | else if(n > 0) | |
1447 | { | |
1448 | prod = sub[--n]; | |
1449 | while( --n >= 0) | |
1450 | prod = mkexpr(OPPLUS, sub[n], | |
1451 | mkexpr(OPSTAR, prod, cpexpr(dimp->dims[n].dimsize)) ); | |
1452 | #if TARGET == VAX || TARGET == TAHOE | |
1453 | #ifdef SDB | |
1454 | if(checksubs || np->vstg!=STGARG || sdbflag) | |
1455 | #else | |
1456 | if(checksubs || np->vstg!=STGARG) | |
1457 | #endif | |
1458 | prod = mkexpr(OPMINUS, prod, cpexpr(dimp->baseoffset)); | |
1459 | #else | |
1460 | prod = mkexpr(OPMINUS, prod, cpexpr(dimp->baseoffset)); | |
1461 | #endif | |
1462 | if(checksubs) | |
1463 | prod = subcheck(np, prod); | |
1464 | size = np->vtype == TYCHAR ? | |
1465 | (expptr) cpexpr(np->vleng) : ICON(typesize[np->vtype]); | |
1466 | if (!oftwo(size)) | |
1467 | prod = mkexpr(OPSTAR, prod, size); | |
1468 | else | |
1469 | prod = mkexpr(OPLSHIFT,prod,oftwo(size)); | |
1470 | ||
1471 | offp = mkexpr(OPPLUS, offp, prod); | |
1472 | } | |
1473 | ||
1474 | if(p->fcharp && np->vtype==TYCHAR) | |
1475 | offp = mkexpr(OPPLUS, offp, mkexpr(OPMINUS, cpexpr(p->fcharp), ICON(1) )); | |
1476 | ||
1477 | return(offp); | |
1478 | } | |
1479 | ||
1480 | ||
1481 | ||
1482 | ||
1483 | expptr subcheck(np, p) | |
1484 | Namep np; | |
1485 | register expptr p; | |
1486 | { | |
1487 | struct Dimblock *dimp; | |
1488 | expptr t, checkvar, checkcond, badcall; | |
1489 | ||
1490 | dimp = np->vdim; | |
1491 | if(dimp->nelt == NULL) | |
1492 | return(p); /* don't check arrays with * bounds */ | |
1493 | checkvar = NULL; | |
1494 | checkcond = NULL; | |
1495 | if( ISICON(p) ) | |
1496 | { | |
1497 | if(p->constblock.const.ci < 0) | |
1498 | goto badsub; | |
1499 | if( ISICON(dimp->nelt) ) | |
1500 | if(p->constblock.const.ci < dimp->nelt->constblock.const.ci) | |
1501 | return(p); | |
1502 | else | |
1503 | goto badsub; | |
1504 | } | |
1505 | if(p->tag==TADDR && p->addrblock.vstg==STGREG) | |
1506 | { | |
1507 | checkvar = (expptr) cpexpr(p); | |
1508 | t = p; | |
1509 | } | |
1510 | else { | |
1511 | checkvar = (expptr) mktemp(p->headblock.vtype, ENULL); | |
1512 | t = mkexpr(OPASSIGN, cpexpr(checkvar), p); | |
1513 | } | |
1514 | checkcond = mkexpr(OPLT, t, cpexpr(dimp->nelt) ); | |
1515 | if( ! ISICON(p) ) | |
1516 | checkcond = mkexpr(OPAND, checkcond, | |
1517 | mkexpr(OPLE, ICON(0), cpexpr(checkvar)) ); | |
1518 | ||
1519 | badcall = call4(p->headblock.vtype, "s_rnge", | |
1520 | mkstrcon(VL, np->varname), | |
1521 | mkconv(TYLONG, cpexpr(checkvar)), | |
1522 | mkstrcon(XL, procname), | |
1523 | ICON(lineno) ); | |
1524 | badcall->exprblock.opcode = OPCCALL; | |
1525 | p = mkexpr(OPQUEST, checkcond, | |
1526 | mkexpr(OPCOLON, checkvar, badcall)); | |
1527 | ||
1528 | return(p); | |
1529 | ||
1530 | badsub: | |
1531 | frexpr(p); | |
1532 | errstr("subscript on variable %s out of range", varstr(VL,np->varname)); | |
1533 | return ( ICON(0) ); | |
1534 | } | |
1535 | ||
1536 | ||
1537 | ||
1538 | ||
1539 | Addrp mkaddr(p) | |
1540 | register Namep p; | |
1541 | { | |
1542 | struct Extsym *extp; | |
1543 | register Addrp t; | |
1544 | Addrp intraddr(); | |
1545 | ||
1546 | switch( p->vstg) | |
1547 | { | |
1548 | case STGUNKNOWN: | |
1549 | if(p->vclass != CLPROC) | |
1550 | break; | |
1551 | extp = mkext( varunder(VL, p->varname) ); | |
1552 | extp->extstg = STGEXT; | |
1553 | p->vstg = STGEXT; | |
1554 | p->vardesc.varno = extp - extsymtab; | |
1555 | p->vprocclass = PEXTERNAL; | |
1556 | ||
1557 | case STGCOMMON: | |
1558 | case STGEXT: | |
1559 | case STGBSS: | |
1560 | case STGINIT: | |
1561 | case STGEQUIV: | |
1562 | case STGARG: | |
1563 | case STGLENG: | |
1564 | case STGAUTO: | |
1565 | t = ALLOC(Addrblock); | |
1566 | t->tag = TADDR; | |
1567 | if(p->vclass==CLPROC && p->vprocclass==PTHISPROC) | |
1568 | t->vclass = CLVAR; | |
1569 | else | |
1570 | t->vclass = p->vclass; | |
1571 | t->vtype = p->vtype; | |
1572 | t->vstg = p->vstg; | |
1573 | t->memno = p->vardesc.varno; | |
1574 | t->issaved = p->vsave; | |
1575 | if(p->vdim) t->isarray = YES; | |
1576 | t->memoffset = ICON(p->voffset); | |
1577 | if(p->vleng) | |
1578 | { | |
1579 | t->vleng = (expptr) cpexpr(p->vleng); | |
1580 | if( ISICON(t->vleng) ) | |
1581 | t->varleng = t->vleng->constblock.const.ci; | |
1582 | } | |
1583 | if (p->vstg == STGBSS) | |
1584 | t->varsize = p->varsize; | |
1585 | else if (p->vstg == STGEQUIV) | |
1586 | t->varsize = eqvclass[t->memno].eqvleng; | |
1587 | return(t); | |
1588 | ||
1589 | case STGINTR: | |
1590 | return( intraddr(p) ); | |
1591 | ||
1592 | } | |
1593 | /*debug*/fprintf(diagfile,"mkaddr. vtype=%d, vclass=%d\n", p->vtype, p->vclass); | |
1594 | badstg("mkaddr", p->vstg); | |
1595 | /* NOTREACHED */ | |
1596 | } | |
1597 | ||
1598 | ||
1599 | ||
1600 | ||
1601 | Addrp mkarg(type, argno) | |
1602 | int type, argno; | |
1603 | { | |
1604 | register Addrp p; | |
1605 | ||
1606 | p = ALLOC(Addrblock); | |
1607 | p->tag = TADDR; | |
1608 | p->vtype = type; | |
1609 | p->vclass = CLVAR; | |
1610 | p->vstg = (type==TYLENG ? STGLENG : STGARG); | |
1611 | p->memno = argno; | |
1612 | return(p); | |
1613 | } | |
1614 | ||
1615 | ||
1616 | ||
1617 | ||
1618 | expptr mkprim(v, args, substr) | |
1619 | register union | |
1620 | { | |
1621 | struct Paramblock paramblock; | |
1622 | struct Nameblock nameblock; | |
1623 | struct Headblock headblock; | |
1624 | } *v; | |
1625 | struct Listblock *args; | |
1626 | chainp substr; | |
1627 | { | |
1628 | register struct Primblock *p; | |
1629 | ||
1630 | if(v->headblock.vclass == CLPARAM) | |
1631 | { | |
1632 | if(args || substr) | |
1633 | { | |
1634 | errstr("no qualifiers on parameter name %s", | |
1635 | varstr(VL,v->paramblock.varname)); | |
1636 | frexpr(args); | |
1637 | if(substr) | |
1638 | { | |
1639 | frexpr(substr->datap); | |
1640 | frexpr(substr->nextp->datap); | |
1641 | frchain(&substr); | |
1642 | } | |
1643 | frexpr(v); | |
1644 | return( errnode() ); | |
1645 | } | |
1646 | return( (expptr) cpexpr(v->paramblock.paramval) ); | |
1647 | } | |
1648 | ||
1649 | p = ALLOC(Primblock); | |
1650 | p->tag = TPRIM; | |
1651 | p->vtype = v->nameblock.vtype; | |
1652 | p->namep = (Namep) v; | |
1653 | p->argsp = args; | |
1654 | if(substr) | |
1655 | { | |
1656 | p->fcharp = (expptr) substr->datap; | |
c6c5c165 | 1657 | if (p->fcharp != ENULL && ! ISINT(p->fcharp->headblock.vtype)) |
3e019e8d DS |
1658 | p->fcharp = mkconv(TYINT, p->fcharp); |
1659 | p->lcharp = (expptr) substr->nextp->datap; | |
c6c5c165 | 1660 | if (p->lcharp != ENULL && ! ISINT(p->lcharp->headblock.vtype)) |
3e019e8d DS |
1661 | p->lcharp = mkconv(TYINT, p->lcharp); |
1662 | frchain(&substr); | |
1663 | } | |
1664 | return( (expptr) p); | |
1665 | } | |
1666 | ||
1667 | ||
1668 | ||
1669 | vardcl(v) | |
1670 | register Namep v; | |
1671 | { | |
1672 | int nelt; | |
1673 | struct Dimblock *t; | |
1674 | Addrp p; | |
1675 | expptr neltp; | |
1676 | int eltsize; | |
1677 | int varsize; | |
1678 | int tsize; | |
1679 | int align; | |
1680 | ||
1681 | if(v->vdcldone) | |
1682 | return; | |
1683 | if(v->vclass == CLNAMELIST) | |
1684 | return; | |
1685 | ||
1686 | if(v->vtype == TYUNKNOWN) | |
1687 | impldcl(v); | |
1688 | if(v->vclass == CLUNKNOWN) | |
1689 | v->vclass = CLVAR; | |
1690 | else if(v->vclass!=CLVAR && v->vprocclass!=PTHISPROC) | |
1691 | { | |
1692 | dclerr("used both as variable and non-variable", v); | |
1693 | return; | |
1694 | } | |
1695 | if(v->vstg==STGUNKNOWN) | |
1696 | v->vstg = implstg[ letter(v->varname[0]) ]; | |
1697 | ||
1698 | switch(v->vstg) | |
1699 | { | |
1700 | case STGBSS: | |
1701 | v->vardesc.varno = ++lastvarno; | |
1702 | if (v->vclass != CLVAR) | |
1703 | break; | |
1704 | nelt = 1; | |
1705 | t = v->vdim; | |
1706 | if (t) | |
1707 | { | |
1708 | neltp = t->nelt; | |
1709 | if (neltp && ISICON(neltp)) | |
1710 | nelt = neltp->constblock.const.ci; | |
1711 | else | |
1712 | dclerr("improperly dimensioned array", v); | |
1713 | } | |
1714 | ||
1715 | if (v->vtype == TYCHAR) | |
1716 | { | |
1717 | v->vleng = fixtype(v->vleng); | |
1718 | if (v->vleng == NULL) | |
1719 | eltsize = typesize[TYCHAR]; | |
1720 | else if (ISICON(v->vleng)) | |
1721 | eltsize = typesize[TYCHAR] * | |
1722 | v->vleng->constblock.const.ci; | |
1723 | else if (v->vleng->tag != TERROR) | |
1724 | { | |
1725 | errstr("nonconstant string length on %s", | |
1726 | varstr(VL, v->varname)); | |
1727 | eltsize = 0; | |
1728 | } | |
1729 | } | |
1730 | else | |
1731 | eltsize = typesize[v->vtype]; | |
1732 | ||
1733 | v->varsize = nelt * eltsize; | |
1734 | break; | |
1735 | case STGAUTO: | |
1736 | if(v->vclass==CLPROC && v->vprocclass==PTHISPROC) | |
1737 | break; | |
1738 | nelt = 1; | |
1739 | if(t = v->vdim) | |
1740 | if( (neltp = t->nelt) && ISCONST(neltp) ) | |
1741 | nelt = neltp->constblock.const.ci; | |
1742 | else | |
1743 | dclerr("adjustable automatic array", v); | |
1744 | p = autovar(nelt, v->vtype, v->vleng); | |
1745 | v->vardesc.varno = p->memno; | |
1746 | v->voffset = p->memoffset->constblock.const.ci; | |
1747 | frexpr(p); | |
1748 | break; | |
1749 | ||
1750 | default: | |
1751 | break; | |
1752 | } | |
1753 | v->vdcldone = YES; | |
1754 | } | |
1755 | ||
1756 | ||
1757 | ||
1758 | ||
1759 | impldcl(p) | |
1760 | register Namep p; | |
1761 | { | |
1762 | register int k; | |
1763 | int type, leng; | |
1764 | ||
1765 | if(p->vdcldone || (p->vclass==CLPROC && p->vprocclass==PINTRINSIC) ) | |
1766 | return; | |
1767 | if(p->vtype == TYUNKNOWN) | |
1768 | { | |
1769 | k = letter(p->varname[0]); | |
1770 | type = impltype[ k ]; | |
1771 | leng = implleng[ k ]; | |
1772 | if(type == TYUNKNOWN) | |
1773 | { | |
1774 | if(p->vclass == CLPROC) | |
1775 | dclerr("attempt to use function of undefined type", p); | |
1776 | else | |
1777 | dclerr("attempt to use undefined variable", p); | |
1778 | type = TYERROR; | |
1779 | leng = 1; | |
1780 | } | |
1781 | settype(p, type, leng); | |
1782 | } | |
1783 | } | |
1784 | ||
1785 | ||
1786 | ||
1787 | ||
1788 | LOCAL letter(c) | |
1789 | register int c; | |
1790 | { | |
1791 | if( isupper(c) ) | |
1792 | c = tolower(c); | |
1793 | return(c - 'a'); | |
1794 | } | |
1795 | \f | |
1796 | #define ICONEQ(z, c) (ISICON(z) && z->constblock.const.ci==c) | |
1797 | #define COMMUTE { e = lp; lp = rp; rp = e; } | |
1798 | ||
1799 | ||
1800 | expptr mkexpr(opcode, lp, rp) | |
1801 | int opcode; | |
1802 | register expptr lp, rp; | |
1803 | { | |
1804 | register expptr e, e1; | |
1805 | int etype; | |
1806 | int ltype, rtype; | |
1807 | int ltag, rtag; | |
1808 | expptr q, q1; | |
1809 | expptr fold(); | |
1810 | int k; | |
1811 | ||
1812 | ltype = lp->headblock.vtype; | |
1813 | ltag = lp->tag; | |
1814 | if(rp && opcode!=OPCALL && opcode!=OPCCALL) | |
1815 | { | |
1816 | rtype = rp->headblock.vtype; | |
1817 | rtag = rp->tag; | |
1818 | } | |
1819 | else { | |
1820 | rtype = 0; | |
1821 | rtag = 0; | |
1822 | } | |
1823 | ||
1824 | /* | |
1825 | * Yuck. Why can't we fold constants AFTER | |
1826 | * variables are implicitly declared??? | |
1827 | */ | |
1828 | if(ltype == TYUNKNOWN && ltag == TPRIM && lp->primblock.argsp == NULL) | |
1829 | { | |
1830 | k = letter(lp->primblock.namep->varname[0]); | |
1831 | ltype = impltype[ k ]; | |
1832 | } | |
1833 | if(rtype == TYUNKNOWN && rtag == TPRIM && rp->primblock.argsp == NULL) | |
1834 | { | |
1835 | k = letter(rp->primblock.namep->varname[0]); | |
1836 | rtype = impltype[ k ]; | |
1837 | } | |
1838 | ||
1839 | etype = cktype(opcode, ltype, rtype); | |
1840 | if(etype == TYERROR) | |
1841 | goto error; | |
1842 | ||
1843 | if(etype != TYUNKNOWN) | |
1844 | switch(opcode) | |
1845 | { | |
1846 | /* check for multiplication by 0 and 1 and addition to 0 */ | |
1847 | ||
1848 | case OPSTAR: | |
1849 | if( ISCONST(lp) ) | |
1850 | COMMUTE | |
1851 | ||
1852 | if( ISICON(rp) ) | |
1853 | { | |
1854 | if(rp->constblock.const.ci == 0) | |
1855 | { | |
1856 | if(etype == TYUNKNOWN) | |
1857 | break; | |
1858 | rp = mkconv(etype, rp); | |
1859 | goto retright; | |
1860 | } | |
1861 | if ((lp->tag == TEXPR) && | |
1862 | ((lp->exprblock.opcode == OPPLUS) || | |
1863 | (lp->exprblock.opcode == OPMINUS)) && | |
1864 | ISCONST(lp->exprblock.rightp) && | |
1865 | ISINT(lp->exprblock.rightp->constblock.vtype)) | |
1866 | { | |
1867 | q1 = mkexpr(OPSTAR, lp->exprblock.rightp, | |
1868 | cpexpr(rp)); | |
1869 | q = mkexpr(OPSTAR, lp->exprblock.leftp, rp); | |
1870 | q = mkexpr(lp->exprblock.opcode, q, q1); | |
1871 | free ((char *) lp); | |
1872 | return q; | |
1873 | } | |
1874 | else | |
1875 | goto mulop; | |
1876 | } | |
1877 | break; | |
1878 | ||
1879 | case OPSLASH: | |
1880 | case OPMOD: | |
1881 | if( ICONEQ(rp, 0) ) | |
1882 | { | |
1883 | err("attempted division by zero"); | |
1884 | rp = ICON(1); | |
1885 | break; | |
1886 | } | |
1887 | if(opcode == OPMOD) | |
1888 | break; | |
1889 | ||
1890 | ||
1891 | mulop: | |
1892 | if( ISICON(rp) ) | |
1893 | { | |
1894 | if(rp->constblock.const.ci == 1) | |
1895 | goto retleft; | |
1896 | ||
1897 | if(rp->constblock.const.ci == -1) | |
1898 | { | |
1899 | frexpr(rp); | |
1900 | return( mkexpr(OPNEG, lp, PNULL) ); | |
1901 | } | |
1902 | } | |
1903 | ||
1904 | if( ISSTAROP(lp) && ISICON(lp->exprblock.rightp) ) | |
1905 | { | |
1906 | if(opcode == OPSTAR) | |
1907 | e = mkexpr(OPSTAR, lp->exprblock.rightp, rp); | |
1908 | else if(ISICON(rp) && | |
1909 | (lp->exprblock.rightp->constblock.const.ci % | |
1910 | rp->constblock.const.ci) == 0) | |
1911 | e = mkexpr(OPSLASH, lp->exprblock.rightp, rp); | |
1912 | else break; | |
1913 | ||
1914 | e1 = lp->exprblock.leftp; | |
1915 | free( (charptr) lp ); | |
1916 | return( mkexpr(OPSTAR, e1, e) ); | |
1917 | } | |
1918 | break; | |
1919 | ||
1920 | ||
1921 | case OPPLUS: | |
1922 | if( ISCONST(lp) ) | |
1923 | COMMUTE | |
1924 | goto addop; | |
1925 | ||
1926 | case OPMINUS: | |
1927 | if( ICONEQ(lp, 0) ) | |
1928 | { | |
1929 | frexpr(lp); | |
1930 | return( mkexpr(OPNEG, rp, ENULL) ); | |
1931 | } | |
1932 | ||
1933 | if( ISCONST(rp) ) | |
1934 | { | |
1935 | opcode = OPPLUS; | |
1936 | consnegop(rp); | |
1937 | } | |
1938 | ||
1939 | addop: | |
1940 | if( ISICON(rp) ) | |
1941 | { | |
1942 | if(rp->constblock.const.ci == 0) | |
1943 | goto retleft; | |
1944 | if( ISPLUSOP(lp) && ISICON(lp->exprblock.rightp) ) | |
1945 | { | |
1946 | e = mkexpr(OPPLUS, lp->exprblock.rightp, rp); | |
1947 | e1 = lp->exprblock.leftp; | |
1948 | free( (charptr) lp ); | |
1949 | return( mkexpr(OPPLUS, e1, e) ); | |
1950 | } | |
1951 | } | |
1952 | break; | |
1953 | ||
1954 | ||
1955 | case OPPOWER: | |
1956 | break; | |
1957 | ||
1958 | case OPNEG: | |
1959 | if(ltag==TEXPR && lp->exprblock.opcode==OPNEG) | |
1960 | { | |
1961 | e = lp->exprblock.leftp; | |
1962 | free( (charptr) lp ); | |
1963 | return(e); | |
1964 | } | |
1965 | break; | |
1966 | ||
1967 | case OPNOT: | |
1968 | if(ltag==TEXPR && lp->exprblock.opcode==OPNOT) | |
1969 | { | |
1970 | e = lp->exprblock.leftp; | |
1971 | free( (charptr) lp ); | |
1972 | return(e); | |
1973 | } | |
1974 | break; | |
1975 | ||
1976 | case OPCALL: | |
1977 | case OPCCALL: | |
1978 | etype = ltype; | |
1979 | if(rp!=NULL && rp->listblock.listp==NULL) | |
1980 | { | |
1981 | free( (charptr) rp ); | |
1982 | rp = NULL; | |
1983 | } | |
1984 | break; | |
1985 | ||
1986 | case OPAND: | |
1987 | case OPOR: | |
1988 | if( ISCONST(lp) ) | |
1989 | COMMUTE | |
1990 | ||
1991 | if( ISCONST(rp) ) | |
1992 | { | |
1993 | if(rp->constblock.const.ci == 0) | |
1994 | if(opcode == OPOR) | |
1995 | goto retleft; | |
1996 | else | |
1997 | goto retright; | |
1998 | else if(opcode == OPOR) | |
1999 | goto retright; | |
2000 | else | |
2001 | goto retleft; | |
2002 | } | |
2003 | case OPLSHIFT: | |
2004 | if (ISICON(rp)) | |
2005 | { | |
2006 | if (rp->constblock.const.ci == 0) | |
2007 | goto retleft; | |
2008 | if ((lp->tag == TEXPR) && | |
2009 | ((lp->exprblock.opcode == OPPLUS) || | |
2010 | (lp->exprblock.opcode == OPMINUS)) && | |
2011 | ISICON(lp->exprblock.rightp)) | |
2012 | { | |
2013 | q1 = mkexpr(OPLSHIFT, lp->exprblock.rightp, | |
2014 | cpexpr(rp)); | |
2015 | q = mkexpr(OPLSHIFT, lp->exprblock.leftp, rp); | |
2016 | q = mkexpr(lp->exprblock.opcode, q, q1); | |
2017 | free((char *) lp); | |
2018 | return q; | |
2019 | } | |
2020 | } | |
2021 | ||
2022 | case OPEQV: | |
2023 | case OPNEQV: | |
2024 | ||
2025 | case OPBITAND: | |
2026 | case OPBITOR: | |
2027 | case OPBITXOR: | |
2028 | case OPBITNOT: | |
2029 | case OPRSHIFT: | |
2030 | ||
2031 | case OPLT: | |
2032 | case OPGT: | |
2033 | case OPLE: | |
2034 | case OPGE: | |
2035 | case OPEQ: | |
2036 | case OPNE: | |
2037 | ||
2038 | case OPCONCAT: | |
2039 | break; | |
2040 | case OPMIN: | |
2041 | case OPMAX: | |
2042 | ||
2043 | case OPASSIGN: | |
2044 | case OPPLUSEQ: | |
2045 | case OPSTAREQ: | |
2046 | ||
2047 | case OPCONV: | |
2048 | case OPADDR: | |
2049 | ||
2050 | case OPCOMMA: | |
2051 | case OPQUEST: | |
2052 | case OPCOLON: | |
2053 | ||
2054 | case OPPAREN: | |
2055 | break; | |
2056 | ||
2057 | default: | |
2058 | badop("mkexpr", opcode); | |
2059 | } | |
2060 | ||
2061 | e = (expptr) ALLOC(Exprblock); | |
2062 | e->exprblock.tag = TEXPR; | |
2063 | e->exprblock.opcode = opcode; | |
2064 | e->exprblock.vtype = etype; | |
2065 | e->exprblock.leftp = lp; | |
2066 | e->exprblock.rightp = rp; | |
2067 | if(ltag==TCONST && (rp==0 || rtag==TCONST) ) | |
2068 | e = fold(e); | |
2069 | return(e); | |
2070 | ||
2071 | retleft: | |
2072 | frexpr(rp); | |
2073 | return(lp); | |
2074 | ||
2075 | retright: | |
2076 | frexpr(lp); | |
2077 | return(rp); | |
2078 | ||
2079 | error: | |
2080 | frexpr(lp); | |
2081 | if(rp && opcode!=OPCALL && opcode!=OPCCALL) | |
2082 | frexpr(rp); | |
2083 | return( errnode() ); | |
2084 | } | |
2085 | \f | |
2086 | #define ERR(s) { errs = s; goto error; } | |
2087 | ||
2088 | cktype(op, lt, rt) | |
2089 | register int op, lt, rt; | |
2090 | { | |
2091 | char *errs; | |
2092 | ||
2093 | if(lt==TYERROR || rt==TYERROR) | |
2094 | goto error1; | |
2095 | ||
2096 | if(lt==TYUNKNOWN) | |
2097 | return(TYUNKNOWN); | |
2098 | if(rt==TYUNKNOWN) | |
2099 | if (op!=OPNOT && op!=OPBITNOT && op!=OPNEG && op!=OPCALL && | |
2100 | op!=OPCCALL && op!=OPADDR && op!=OPPAREN) | |
2101 | return(TYUNKNOWN); | |
2102 | ||
2103 | switch(op) | |
2104 | { | |
2105 | case OPPLUS: | |
2106 | case OPMINUS: | |
2107 | case OPSTAR: | |
2108 | case OPSLASH: | |
2109 | case OPPOWER: | |
2110 | case OPMOD: | |
2111 | if( ISNUMERIC(lt) && ISNUMERIC(rt) ) | |
2112 | return( maxtype(lt, rt) ); | |
2113 | ERR("nonarithmetic operand of arithmetic operator") | |
2114 | ||
2115 | case OPNEG: | |
2116 | if( ISNUMERIC(lt) ) | |
2117 | return(lt); | |
2118 | ERR("nonarithmetic operand of negation") | |
2119 | ||
2120 | case OPNOT: | |
2121 | if(lt == TYLOGICAL) | |
2122 | return(TYLOGICAL); | |
2123 | ERR("NOT of nonlogical") | |
2124 | ||
2125 | case OPAND: | |
2126 | case OPOR: | |
2127 | case OPEQV: | |
2128 | case OPNEQV: | |
2129 | if(lt==TYLOGICAL && rt==TYLOGICAL) | |
2130 | return(TYLOGICAL); | |
2131 | ERR("nonlogical operand of logical operator") | |
2132 | ||
2133 | case OPLT: | |
2134 | case OPGT: | |
2135 | case OPLE: | |
2136 | case OPGE: | |
2137 | case OPEQ: | |
2138 | case OPNE: | |
2139 | if(lt==TYCHAR || rt==TYCHAR || lt==TYLOGICAL || rt==TYLOGICAL) | |
2140 | { | |
2141 | if(lt != rt) | |
2142 | ERR("illegal comparison") | |
2143 | } | |
2144 | ||
2145 | else if( ISCOMPLEX(lt) || ISCOMPLEX(rt) ) | |
2146 | { | |
2147 | if(op!=OPEQ && op!=OPNE) | |
2148 | ERR("order comparison of complex data") | |
2149 | } | |
2150 | ||
2151 | else if( ! ISNUMERIC(lt) || ! ISNUMERIC(rt) ) | |
2152 | ERR("comparison of nonarithmetic data") | |
2153 | return(TYLOGICAL); | |
2154 | ||
2155 | case OPCONCAT: | |
2156 | if(lt==TYCHAR && rt==TYCHAR) | |
2157 | return(TYCHAR); | |
2158 | ERR("concatenation of nonchar data") | |
2159 | ||
2160 | case OPCALL: | |
2161 | case OPCCALL: | |
2162 | return(lt); | |
2163 | ||
2164 | case OPADDR: | |
2165 | return(TYADDR); | |
2166 | ||
2167 | case OPCONV: | |
2168 | if(ISCOMPLEX(lt)) | |
2169 | { | |
2170 | if(ISNUMERIC(rt)) | |
2171 | return(lt); | |
2172 | ERR("impossible conversion") | |
2173 | } | |
2174 | if(rt == 0) | |
2175 | return(0); | |
2176 | if(lt==TYCHAR && ISINT(rt) ) | |
2177 | return(TYCHAR); | |
2178 | case OPASSIGN: | |
2179 | case OPPLUSEQ: | |
2180 | case OPSTAREQ: | |
2181 | if( ISINT(lt) && rt==TYCHAR) | |
2182 | return(lt); | |
2183 | if(lt==TYCHAR || rt==TYCHAR || lt==TYLOGICAL || rt==TYLOGICAL) | |
2184 | if(op!=OPASSIGN || lt!=rt) | |
2185 | { | |
2186 | /* debug fprintf(diagfile, " lt=%d, rt=%d, op=%d\n", lt, rt, op); */ | |
2187 | /* debug fatal("impossible conversion. possible compiler bug"); */ | |
2188 | ERR("impossible conversion") | |
2189 | } | |
2190 | return(lt); | |
2191 | ||
2192 | case OPMIN: | |
2193 | case OPMAX: | |
2194 | case OPBITOR: | |
2195 | case OPBITAND: | |
2196 | case OPBITXOR: | |
2197 | case OPBITNOT: | |
2198 | case OPLSHIFT: | |
2199 | case OPRSHIFT: | |
2200 | case OPPAREN: | |
2201 | return(lt); | |
2202 | ||
2203 | case OPCOMMA: | |
2204 | case OPQUEST: | |
2205 | case OPCOLON: | |
2206 | return(rt); | |
2207 | ||
2208 | default: | |
2209 | badop("cktype", op); | |
2210 | } | |
2211 | error: err(errs); | |
2212 | error1: return(TYERROR); | |
2213 | } | |
2214 | \f | |
2215 | LOCAL expptr fold(e) | |
2216 | register expptr e; | |
2217 | { | |
2218 | Constp p; | |
2219 | register expptr lp, rp; | |
2220 | int etype, mtype, ltype, rtype, opcode; | |
2221 | int i, ll, lr; | |
2222 | char *q, *s; | |
2223 | union Constant lcon, rcon; | |
2224 | ||
2225 | opcode = e->exprblock.opcode; | |
2226 | etype = e->exprblock.vtype; | |
2227 | ||
2228 | lp = e->exprblock.leftp; | |
2229 | ltype = lp->headblock.vtype; | |
2230 | rp = e->exprblock.rightp; | |
2231 | ||
2232 | if(rp == 0) | |
2233 | switch(opcode) | |
2234 | { | |
2235 | case OPNOT: | |
2236 | lp->constblock.const.ci = ! lp->constblock.const.ci; | |
2237 | return(lp); | |
2238 | ||
2239 | case OPBITNOT: | |
2240 | lp->constblock.const.ci = ~ lp->constblock.const.ci; | |
2241 | return(lp); | |
2242 | ||
2243 | case OPNEG: | |
2244 | consnegop(lp); | |
2245 | return(lp); | |
2246 | ||
2247 | case OPCONV: | |
2248 | case OPADDR: | |
2249 | case OPPAREN: | |
2250 | return(e); | |
2251 | ||
2252 | default: | |
2253 | badop("fold", opcode); | |
2254 | } | |
2255 | ||
2256 | rtype = rp->headblock.vtype; | |
2257 | ||
2258 | p = ALLOC(Constblock); | |
2259 | p->tag = TCONST; | |
2260 | p->vtype = etype; | |
2261 | p->vleng = e->exprblock.vleng; | |
2262 | ||
2263 | switch(opcode) | |
2264 | { | |
2265 | case OPCOMMA: | |
2266 | case OPQUEST: | |
2267 | case OPCOLON: | |
2268 | return(e); | |
2269 | ||
2270 | case OPAND: | |
2271 | p->const.ci = lp->constblock.const.ci && | |
2272 | rp->constblock.const.ci; | |
2273 | break; | |
2274 | ||
2275 | case OPOR: | |
2276 | p->const.ci = lp->constblock.const.ci || | |
2277 | rp->constblock.const.ci; | |
2278 | break; | |
2279 | ||
2280 | case OPEQV: | |
2281 | p->const.ci = lp->constblock.const.ci == | |
2282 | rp->constblock.const.ci; | |
2283 | break; | |
2284 | ||
2285 | case OPNEQV: | |
2286 | p->const.ci = lp->constblock.const.ci != | |
2287 | rp->constblock.const.ci; | |
2288 | break; | |
2289 | ||
2290 | case OPBITAND: | |
2291 | p->const.ci = lp->constblock.const.ci & | |
2292 | rp->constblock.const.ci; | |
2293 | break; | |
2294 | ||
2295 | case OPBITOR: | |
2296 | p->const.ci = lp->constblock.const.ci | | |
2297 | rp->constblock.const.ci; | |
2298 | break; | |
2299 | ||
2300 | case OPBITXOR: | |
2301 | p->const.ci = lp->constblock.const.ci ^ | |
2302 | rp->constblock.const.ci; | |
2303 | break; | |
2304 | ||
2305 | case OPLSHIFT: | |
2306 | p->const.ci = lp->constblock.const.ci << | |
2307 | rp->constblock.const.ci; | |
2308 | break; | |
2309 | ||
2310 | case OPRSHIFT: | |
2311 | p->const.ci = lp->constblock.const.ci >> | |
2312 | rp->constblock.const.ci; | |
2313 | break; | |
2314 | ||
2315 | case OPCONCAT: | |
2316 | ll = lp->constblock.vleng->constblock.const.ci; | |
2317 | lr = rp->constblock.vleng->constblock.const.ci; | |
2318 | p->const.ccp = q = (char *) ckalloc(ll+lr); | |
2319 | p->vleng = ICON(ll+lr); | |
2320 | s = lp->constblock.const.ccp; | |
2321 | for(i = 0 ; i < ll ; ++i) | |
2322 | *q++ = *s++; | |
2323 | s = rp->constblock.const.ccp; | |
2324 | for(i = 0; i < lr; ++i) | |
2325 | *q++ = *s++; | |
2326 | break; | |
2327 | ||
2328 | ||
2329 | case OPPOWER: | |
2330 | if( ! ISINT(rtype) ) | |
2331 | return(e); | |
2332 | conspower(&(p->const), lp, rp->constblock.const.ci); | |
2333 | break; | |
2334 | ||
2335 | ||
2336 | default: | |
2337 | if(ltype == TYCHAR) | |
2338 | { | |
2339 | lcon.ci = cmpstr(lp->constblock.const.ccp, | |
2340 | rp->constblock.const.ccp, | |
2341 | lp->constblock.vleng->constblock.const.ci, | |
2342 | rp->constblock.vleng->constblock.const.ci); | |
2343 | rcon.ci = 0; | |
2344 | mtype = tyint; | |
2345 | } | |
2346 | else { | |
2347 | mtype = maxtype(ltype, rtype); | |
2348 | consconv(mtype, &lcon, ltype, &(lp->constblock.const) ); | |
2349 | consconv(mtype, &rcon, rtype, &(rp->constblock.const) ); | |
2350 | } | |
2351 | consbinop(opcode, mtype, &(p->const), &lcon, &rcon); | |
2352 | break; | |
2353 | } | |
2354 | ||
2355 | frexpr(e); | |
2356 | return( (expptr) p ); | |
2357 | } | |
2358 | ||
2359 | ||
2360 | ||
2361 | /* assign constant l = r , doing coercion */ | |
2362 | ||
2363 | consconv(lt, lv, rt, rv) | |
2364 | int lt, rt; | |
2365 | register union Constant *lv, *rv; | |
2366 | { | |
2367 | switch(lt) | |
2368 | { | |
2369 | case TYCHAR: | |
2370 | *(lv->ccp = (char *) ckalloc(1)) = rv->ci; | |
2371 | break; | |
2372 | ||
2373 | case TYSHORT: | |
2374 | case TYLONG: | |
2375 | if(rt == TYCHAR) | |
2376 | lv->ci = rv->ccp[0]; | |
2377 | else if( ISINT(rt) ) | |
2378 | lv->ci = rv->ci; | |
2379 | else lv->ci = rv->cd[0]; | |
2380 | break; | |
2381 | ||
2382 | case TYCOMPLEX: | |
2383 | case TYDCOMPLEX: | |
2384 | switch(rt) | |
2385 | { | |
2386 | case TYSHORT: | |
2387 | case TYLONG: | |
2388 | /* fall through and do real assignment of | |
2389 | first element | |
2390 | */ | |
2391 | case TYREAL: | |
2392 | case TYDREAL: | |
2393 | lv->cd[1] = 0; break; | |
2394 | case TYCOMPLEX: | |
2395 | case TYDCOMPLEX: | |
2396 | lv->cd[1] = rv->cd[1]; break; | |
2397 | } | |
2398 | ||
2399 | case TYREAL: | |
2400 | case TYDREAL: | |
2401 | if( ISINT(rt) ) | |
2402 | lv->cd[0] = rv->ci; | |
2403 | else lv->cd[0] = rv->cd[0]; | |
2404 | if( lt == TYREAL) | |
2405 | { | |
2406 | float f = lv->cd[0]; | |
2407 | lv->cd[0] = f; | |
2408 | } | |
2409 | break; | |
2410 | ||
2411 | case TYLOGICAL: | |
2412 | lv->ci = rv->ci; | |
2413 | break; | |
2414 | } | |
2415 | } | |
2416 | ||
2417 | ||
2418 | ||
2419 | consnegop(p) | |
2420 | register Constp p; | |
2421 | { | |
2422 | switch(p->vtype) | |
2423 | { | |
2424 | case TYSHORT: | |
2425 | case TYLONG: | |
2426 | p->const.ci = - p->const.ci; | |
2427 | break; | |
2428 | ||
2429 | case TYCOMPLEX: | |
2430 | case TYDCOMPLEX: | |
2431 | p->const.cd[1] = - p->const.cd[1]; | |
2432 | /* fall through and do the real parts */ | |
2433 | case TYREAL: | |
2434 | case TYDREAL: | |
2435 | p->const.cd[0] = - p->const.cd[0]; | |
2436 | break; | |
2437 | default: | |
2438 | badtype("consnegop", p->vtype); | |
2439 | } | |
2440 | } | |
2441 | ||
2442 | ||
2443 | ||
2444 | LOCAL conspower(powp, ap, n) | |
2445 | register union Constant *powp; | |
2446 | Constp ap; | |
2447 | ftnint n; | |
2448 | { | |
2449 | register int type; | |
2450 | union Constant x; | |
2451 | ||
2452 | switch(type = ap->vtype) /* pow = 1 */ | |
2453 | { | |
2454 | case TYSHORT: | |
2455 | case TYLONG: | |
2456 | powp->ci = 1; | |
2457 | break; | |
2458 | case TYCOMPLEX: | |
2459 | case TYDCOMPLEX: | |
2460 | powp->cd[1] = 0; | |
2461 | case TYREAL: | |
2462 | case TYDREAL: | |
2463 | powp->cd[0] = 1; | |
2464 | break; | |
2465 | default: | |
2466 | badtype("conspower", type); | |
2467 | } | |
2468 | ||
2469 | if(n == 0) | |
2470 | return; | |
2471 | if(n < 0) | |
2472 | { | |
2473 | if( ISINT(type) ) | |
2474 | { | |
2475 | if (ap->const.ci == 0) | |
2476 | err("zero raised to a negative power"); | |
2477 | else if (ap->const.ci == 1) | |
2478 | return; | |
2479 | else if (ap->const.ci == -1) | |
2480 | { | |
2481 | if (n < -2) | |
2482 | n = n + 2; | |
2483 | n = -n; | |
2484 | if (n % 2 == 1) | |
2485 | powp->ci = -1; | |
2486 | } | |
2487 | else | |
2488 | powp->ci = 0; | |
2489 | return; | |
2490 | } | |
2491 | n = - n; | |
2492 | consbinop(OPSLASH, type, &x, powp, &(ap->const)); | |
2493 | } | |
2494 | else | |
2495 | consbinop(OPSTAR, type, &x, powp, &(ap->const)); | |
2496 | ||
2497 | for( ; ; ) | |
2498 | { | |
2499 | if(n & 01) | |
2500 | consbinop(OPSTAR, type, powp, powp, &x); | |
2501 | if(n >>= 1) | |
2502 | consbinop(OPSTAR, type, &x, &x, &x); | |
2503 | else | |
2504 | break; | |
2505 | } | |
2506 | } | |
2507 | ||
2508 | ||
2509 | ||
2510 | /* do constant operation cp = a op b */ | |
2511 | ||
2512 | ||
2513 | LOCAL consbinop(opcode, type, cp, ap, bp) | |
2514 | int opcode, type; | |
2515 | register union Constant *ap, *bp, *cp; | |
2516 | { | |
2517 | int k; | |
2518 | double temp; | |
2519 | ||
2520 | switch(opcode) | |
2521 | { | |
2522 | case OPPLUS: | |
2523 | switch(type) | |
2524 | { | |
2525 | case TYSHORT: | |
2526 | case TYLONG: | |
2527 | cp->ci = ap->ci + bp->ci; | |
2528 | break; | |
2529 | case TYCOMPLEX: | |
2530 | case TYDCOMPLEX: | |
2531 | cp->cd[1] = ap->cd[1] + bp->cd[1]; | |
2532 | case TYREAL: | |
2533 | case TYDREAL: | |
2534 | cp->cd[0] = ap->cd[0] + bp->cd[0]; | |
2535 | break; | |
2536 | } | |
2537 | break; | |
2538 | ||
2539 | case OPMINUS: | |
2540 | switch(type) | |
2541 | { | |
2542 | case TYSHORT: | |
2543 | case TYLONG: | |
2544 | cp->ci = ap->ci - bp->ci; | |
2545 | break; | |
2546 | case TYCOMPLEX: | |
2547 | case TYDCOMPLEX: | |
2548 | cp->cd[1] = ap->cd[1] - bp->cd[1]; | |
2549 | case TYREAL: | |
2550 | case TYDREAL: | |
2551 | cp->cd[0] = ap->cd[0] - bp->cd[0]; | |
2552 | break; | |
2553 | } | |
2554 | break; | |
2555 | ||
2556 | case OPSTAR: | |
2557 | switch(type) | |
2558 | { | |
2559 | case TYSHORT: | |
2560 | case TYLONG: | |
2561 | cp->ci = ap->ci * bp->ci; | |
2562 | break; | |
2563 | case TYREAL: | |
2564 | case TYDREAL: | |
2565 | cp->cd[0] = ap->cd[0] * bp->cd[0]; | |
2566 | break; | |
2567 | case TYCOMPLEX: | |
2568 | case TYDCOMPLEX: | |
2569 | temp = ap->cd[0] * bp->cd[0] - | |
2570 | ap->cd[1] * bp->cd[1] ; | |
2571 | cp->cd[1] = ap->cd[0] * bp->cd[1] + | |
2572 | ap->cd[1] * bp->cd[0] ; | |
2573 | cp->cd[0] = temp; | |
2574 | break; | |
2575 | } | |
2576 | break; | |
2577 | case OPSLASH: | |
2578 | switch(type) | |
2579 | { | |
2580 | case TYSHORT: | |
2581 | case TYLONG: | |
2582 | cp->ci = ap->ci / bp->ci; | |
2583 | break; | |
2584 | case TYREAL: | |
2585 | case TYDREAL: | |
2586 | cp->cd[0] = ap->cd[0] / bp->cd[0]; | |
2587 | break; | |
2588 | case TYCOMPLEX: | |
2589 | case TYDCOMPLEX: | |
2590 | zdiv(cp,ap,bp); | |
2591 | break; | |
2592 | } | |
2593 | break; | |
2594 | ||
2595 | case OPMOD: | |
2596 | if( ISINT(type) ) | |
2597 | { | |
2598 | cp->ci = ap->ci % bp->ci; | |
2599 | break; | |
2600 | } | |
2601 | else | |
2602 | fatal("inline mod of noninteger"); | |
2603 | ||
2604 | default: /* relational ops */ | |
2605 | switch(type) | |
2606 | { | |
2607 | case TYSHORT: | |
2608 | case TYLONG: | |
2609 | if(ap->ci < bp->ci) | |
2610 | k = -1; | |
2611 | else if(ap->ci == bp->ci) | |
2612 | k = 0; | |
2613 | else k = 1; | |
2614 | break; | |
2615 | case TYREAL: | |
2616 | case TYDREAL: | |
2617 | if(ap->cd[0] < bp->cd[0]) | |
2618 | k = -1; | |
2619 | else if(ap->cd[0] == bp->cd[0]) | |
2620 | k = 0; | |
2621 | else k = 1; | |
2622 | break; | |
2623 | case TYCOMPLEX: | |
2624 | case TYDCOMPLEX: | |
2625 | if(ap->cd[0] == bp->cd[0] && | |
2626 | ap->cd[1] == bp->cd[1] ) | |
2627 | k = 0; | |
2628 | else k = 1; | |
2629 | break; | |
2630 | } | |
2631 | ||
2632 | switch(opcode) | |
2633 | { | |
2634 | case OPEQ: | |
2635 | cp->ci = (k == 0); | |
2636 | break; | |
2637 | case OPNE: | |
2638 | cp->ci = (k != 0); | |
2639 | break; | |
2640 | case OPGT: | |
2641 | cp->ci = (k == 1); | |
2642 | break; | |
2643 | case OPLT: | |
2644 | cp->ci = (k == -1); | |
2645 | break; | |
2646 | case OPGE: | |
2647 | cp->ci = (k >= 0); | |
2648 | break; | |
2649 | case OPLE: | |
2650 | cp->ci = (k <= 0); | |
2651 | break; | |
2652 | default: | |
2653 | badop ("consbinop", opcode); | |
2654 | } | |
2655 | break; | |
2656 | } | |
2657 | } | |
2658 | ||
2659 | ||
2660 | ||
2661 | ||
2662 | conssgn(p) | |
2663 | register expptr p; | |
2664 | { | |
2665 | if( ! ISCONST(p) ) | |
2666 | fatal( "sgn(nonconstant)" ); | |
2667 | ||
2668 | switch(p->headblock.vtype) | |
2669 | { | |
2670 | case TYSHORT: | |
2671 | case TYLONG: | |
2672 | if(p->constblock.const.ci > 0) return(1); | |
2673 | if(p->constblock.const.ci < 0) return(-1); | |
2674 | return(0); | |
2675 | ||
2676 | case TYREAL: | |
2677 | case TYDREAL: | |
2678 | if(p->constblock.const.cd[0] > 0) return(1); | |
2679 | if(p->constblock.const.cd[0] < 0) return(-1); | |
2680 | return(0); | |
2681 | ||
2682 | case TYCOMPLEX: | |
2683 | case TYDCOMPLEX: | |
2684 | return(p->constblock.const.cd[0]!=0 || p->constblock.const.cd[1]!=0); | |
2685 | ||
2686 | default: | |
2687 | badtype( "conssgn", p->constblock.vtype); | |
2688 | } | |
2689 | /* NOTREACHED */ | |
2690 | } | |
2691 | \f | |
2692 | char *powint[ ] = { "pow_ii", "pow_ri", "pow_di", "pow_ci", "pow_zi" }; | |
2693 | ||
2694 | ||
2695 | LOCAL expptr mkpower(p) | |
2696 | register expptr p; | |
2697 | { | |
2698 | register expptr q, lp, rp; | |
2699 | int ltype, rtype, mtype; | |
2700 | ||
2701 | lp = p->exprblock.leftp; | |
2702 | rp = p->exprblock.rightp; | |
2703 | ltype = lp->headblock.vtype; | |
2704 | rtype = rp->headblock.vtype; | |
2705 | ||
2706 | if(ISICON(rp)) | |
2707 | { | |
2708 | if(rp->constblock.const.ci == 0) | |
2709 | { | |
2710 | frexpr(p); | |
2711 | if( ISINT(ltype) ) | |
2712 | return( ICON(1) ); | |
2713 | else | |
2714 | { | |
2715 | expptr pp; | |
2716 | pp = mkconv(ltype, ICON(1)); | |
2717 | return( pp ); | |
2718 | } | |
2719 | } | |
2720 | if(rp->constblock.const.ci < 0) | |
2721 | { | |
2722 | if( ISINT(ltype) ) | |
2723 | { | |
2724 | frexpr(p); | |
2725 | err("integer**negative"); | |
2726 | return( errnode() ); | |
2727 | } | |
2728 | rp->constblock.const.ci = - rp->constblock.const.ci; | |
2729 | p->exprblock.leftp = lp = fixexpr(mkexpr(OPSLASH, ICON(1), lp)); | |
2730 | } | |
2731 | if(rp->constblock.const.ci == 1) | |
2732 | { | |
2733 | frexpr(rp); | |
2734 | free( (charptr) p ); | |
2735 | return(lp); | |
2736 | } | |
2737 | ||
2738 | if( ONEOF(ltype, MSKINT|MSKREAL) ) | |
2739 | { | |
2740 | p->exprblock.vtype = ltype; | |
2741 | return(p); | |
2742 | } | |
2743 | } | |
2744 | if( ISINT(rtype) ) | |
2745 | { | |
2746 | if(ltype==TYSHORT && rtype==TYSHORT && (!ISCONST(lp) || tyint==TYSHORT) ) | |
2747 | q = call2(TYSHORT, "pow_hh", lp, rp); | |
2748 | else { | |
2749 | if(ltype == TYSHORT) | |
2750 | { | |
2751 | ltype = TYLONG; | |
2752 | lp = mkconv(TYLONG,lp); | |
2753 | } | |
2754 | q = call2(ltype, powint[ltype-TYLONG], lp, mkconv(TYLONG, rp)); | |
2755 | } | |
2756 | } | |
2757 | else if( ISREAL( (mtype = maxtype(ltype,rtype)) )) | |
2758 | q = call2(mtype, "pow_dd", mkconv(TYDREAL,lp), mkconv(TYDREAL,rp)); | |
2759 | else { | |
2760 | q = call2(TYDCOMPLEX, "pow_zz", | |
2761 | mkconv(TYDCOMPLEX,lp), mkconv(TYDCOMPLEX,rp)); | |
2762 | if(mtype == TYCOMPLEX) | |
2763 | q = mkconv(TYCOMPLEX, q); | |
2764 | } | |
2765 | free( (charptr) p ); | |
2766 | return(q); | |
2767 | } | |
2768 | \f | |
2769 | ||
2770 | ||
2771 | /* Complex Division. Same code as in Runtime Library | |
2772 | */ | |
2773 | ||
2774 | struct dcomplex { double dreal, dimag; }; | |
2775 | ||
2776 | ||
2777 | LOCAL zdiv(c, a, b) | |
2778 | register struct dcomplex *a, *b, *c; | |
2779 | { | |
2780 | double ratio, den; | |
2781 | double abr, abi; | |
2782 | ||
2783 | if( (abr = b->dreal) < 0.) | |
2784 | abr = - abr; | |
2785 | if( (abi = b->dimag) < 0.) | |
2786 | abi = - abi; | |
2787 | if( abr <= abi ) | |
2788 | { | |
2789 | if(abi == 0) | |
2790 | fatal("complex division by zero"); | |
2791 | ratio = b->dreal / b->dimag ; | |
2792 | den = b->dimag * (1 + ratio*ratio); | |
2793 | c->dreal = (a->dreal*ratio + a->dimag) / den; | |
2794 | c->dimag = (a->dimag*ratio - a->dreal) / den; | |
2795 | } | |
2796 | ||
2797 | else | |
2798 | { | |
2799 | ratio = b->dimag / b->dreal ; | |
2800 | den = b->dreal * (1 + ratio*ratio); | |
2801 | c->dreal = (a->dreal + a->dimag*ratio) / den; | |
2802 | c->dimag = (a->dimag - a->dreal*ratio) / den; | |
2803 | } | |
2804 | ||
2805 | } | |
2806 | ||
2807 | expptr oftwo(e) | |
2808 | expptr e; | |
2809 | { | |
2810 | int val,res; | |
2811 | ||
2812 | if (! ISCONST (e)) | |
2813 | return (0); | |
2814 | ||
2815 | val = e->constblock.const.ci; | |
2816 | switch (val) | |
2817 | { | |
2818 | case 2: res = 1; break; | |
2819 | case 4: res = 2; break; | |
2820 | case 8: res = 3; break; | |
2821 | case 16: res = 4; break; | |
2822 | case 32: res = 5; break; | |
2823 | case 64: res = 6; break; | |
2824 | case 128: res = 7; break; | |
2825 | case 256: res = 8; break; | |
2826 | default: return (0); | |
2827 | } | |
2828 | return (ICON (res)); | |
2829 | } |