|
|
1.1 root 1: /****************************************************************
2: Copyright 1990, 1991, 1992, 1993 by AT&T Bell Laboratories and Bellcore.
3:
4: Permission to use, copy, modify, and distribute this software
5: and its documentation for any purpose and without fee is hereby
6: granted, provided that the above copyright notice appear in all
7: copies and that both that the copyright notice and this
8: permission notice and warranty disclaimer appear in supporting
9: documentation, and that the names of AT&T Bell Laboratories or
10: Bellcore or any of their entities not be used in advertising or
11: publicity pertaining to distribution of the software without
12: specific, written prior permission.
13:
14: AT&T and Bellcore disclaim all warranties with regard to this
15: software, including all implied warranties of merchantability
16: and fitness. In no event shall AT&T or Bellcore be liable for
17: any special, indirect or consequential damages or any damages
18: whatsoever resulting from loss of use, data or profits, whether
19: in an action of contract, negligence or other tortious action,
20: arising out of or in connection with the use or performance of
21: this software.
22: ****************************************************************/
23:
24: #include "defs.h"
25: #include "names.h"
26: #include "output.h"
27:
28: #ifndef TRUE
29: #define TRUE 1
30: #endif
31: #ifndef FALSE
32: #define FALSE 0
33: #endif
34:
35: char _assoc_table[] = { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
36:
37: /* Opcode table -- This array is indexed by the OP_____ macros defined in
38: defines.h; these macros are expected to be adjacent integers, so that
39: this table is as small as possible. */
40:
41: table_entry opcode_table[] = {
42: { 0, 0, NULL },
43: /* OPPLUS 1 */ { BINARY_OP, 12, "%l + %r" },
44: /* OPMINUS 2 */ { BINARY_OP, 12, "%l - %r" },
45: /* OPSTAR 3 */ { BINARY_OP, 13, "%l * %r" },
46: /* OPSLASH 4 */ { BINARY_OP, 13, "%l / %r" },
47: /* OPPOWER 5 */ { BINARY_OP, 0, "power (%l, %r)" },
48: /* OPNEG 6 */ { UNARY_OP, 14, "-%l" },
49: /* OPOR 7 */ { BINARY_OP, 4, "%l || %r" },
50: /* OPAND 8 */ { BINARY_OP, 5, "%l && %r" },
51: /* OPEQV 9 */ { BINARY_OP, 9, "%l == %r" },
52: /* OPNEQV 10 */ { BINARY_OP, 9, "%l != %r" },
53: /* OPNOT 11 */ { UNARY_OP, 14, "! %l" },
54: /* OPCONCAT 12 */ { BINARY_OP, 0, "concat (%l, %r)" },
55: /* OPLT 13 */ { BINARY_OP, 10, "%l < %r" },
56: /* OPEQ 14 */ { BINARY_OP, 9, "%l == %r" },
57: /* OPGT 15 */ { BINARY_OP, 10, "%l > %r" },
58: /* OPLE 16 */ { BINARY_OP, 10, "%l <= %r" },
59: /* OPNE 17 */ { BINARY_OP, 9, "%l != %r" },
60: /* OPGE 18 */ { BINARY_OP, 10, "%l >= %r" },
61: /* OPCALL 19 */ { BINARY_OP, 15, SPECIAL_FMT },
62: /* OPCCALL 20 */ { BINARY_OP, 15, SPECIAL_FMT },
63:
64: /* Left hand side of an assignment cannot have outermost parens */
65:
66: /* OPASSIGN 21 */ { BINARY_OP, 2, "%l = %r" },
67: /* OPPLUSEQ 22 */ { BINARY_OP, 2, "%l += %r" },
68: /* OPSTAREQ 23 */ { BINARY_OP, 2, "%l *= %r" },
69: /* OPCONV 24 */ { BINARY_OP, 14, "%l" },
70: /* OPLSHIFT 25 */ { BINARY_OP, 11, "%l << %r" },
71: /* OPMOD 26 */ { BINARY_OP, 13, "%l %% %r" },
72: /* OPCOMMA 27 */ { BINARY_OP, 1, "%l, %r" },
73:
74: /* Don't want to nest the colon operator in parens */
75:
76: /* OPQUEST 28 */ { BINARY_OP, 3, "%l ? %r" },
77: /* OPCOLON 29 */ { BINARY_OP, 3, "%l : %r" },
78: /* OPABS 30 */ { UNARY_OP, 0, "abs(%l)" },
79: /* OPMIN 31 */ { BINARY_OP, 0, SPECIAL_FMT },
80: /* OPMAX 32 */ { BINARY_OP, 0, SPECIAL_FMT },
81: /* OPADDR 33 */ { UNARY_OP, 14, "&%l" },
82:
83: /* OPCOMMA_ARG 34 */ { BINARY_OP, 15, SPECIAL_FMT },
84: /* OPBITOR 35 */ { BINARY_OP, 6, "%l | %r" },
85: /* OPBITAND 36 */ { BINARY_OP, 8, "%l & %r" },
86: /* OPBITXOR 37 */ { BINARY_OP, 7, "%l ^ %r" },
87: /* OPBITNOT 38 */ { UNARY_OP, 14, "~ %l" },
88: /* OPRSHIFT 39 */ { BINARY_OP, 11, "%l >> %r" },
89:
90: /* This isn't quite right -- it doesn't handle arrays, for instance */
91:
92: /* OPWHATSIN 40 */ { UNARY_OP, 14, "*%l" },
93: /* OPMINUSEQ 41 */ { BINARY_OP, 2, "%l -= %r" },
94: /* OPSLASHEQ 42 */ { BINARY_OP, 2, "%l /= %r" },
95: /* OPMODEQ 43 */ { BINARY_OP, 2, "%l %%= %r" },
96: /* OPLSHIFTEQ 44 */ { BINARY_OP, 2, "%l <<= %r" },
97: /* OPRSHIFTEQ 45 */ { BINARY_OP, 2, "%l >>= %r" },
98: /* OPBITANDEQ 46 */ { BINARY_OP, 2, "%l &= %r" },
99: /* OPBITXOREQ 47 */ { BINARY_OP, 2, "%l ^= %r" },
100: /* OPBITOREQ 48 */ { BINARY_OP, 2, "%l |= %r" },
101: /* OPPREINC 49 */ { UNARY_OP, 14, "++%l" },
102: /* OPPREDEC 50 */ { UNARY_OP, 14, "--%l" },
103: /* OPDOT 51 */ { BINARY_OP, 15, "%l.%r" },
104: /* OPARROW 52 */ { BINARY_OP, 15, "%l -> %r"},
105: /* OPNEG1 53 */ { UNARY_OP, 14, "-%l" },
106: /* OPDMIN 54 */ { BINARY_OP, 0, "dmin(%l,%r)" },
107: /* OPDMAX 55 */ { BINARY_OP, 0, "dmax(%l,%r)" },
108: /* OPASSIGNI 56 */ { BINARY_OP, 2, "%l = &%r" },
109: /* OPIDENTITY 57 */ { UNARY_OP, 15, "%l" },
110: /* OPCHARCAST 58 */ { UNARY_OP, 14, "(char *)&%l" },
111: /* OPDABS 59 */ { UNARY_OP, 0, "dabs(%l)" },
112: /* OPMIN2 60 */ { BINARY_OP, 0, "min(%l,%r)" },
113: /* OPMAX2 61 */ { BINARY_OP, 0, "max(%l,%r)" },
114:
115: /* kludge to imitate (under forcedouble) f77's bizarre treatement of OPNEG... */
116:
117: /* OPNEG KLUDGE */ { UNARY_OP, 14, "-(doublereal)%l" }
118: }; /* opcode_table */
119:
120: #define OPNEG_KLUDGE (sizeof(opcode_table)/sizeof(table_entry) - 1)
121:
122: static char opeqable[sizeof(opcode_table)/sizeof(table_entry)];
123:
124:
125: static void output_prim ();
126: static void output_unary (), output_binary (), output_arg_list ();
127: static void output_list (), output_literal ();
128:
129:
130: void expr_out (fp, e)
131: FILE *fp;
132: expptr e;
133: {
134: if (e == (expptr) NULL)
135: return;
136:
137: switch (e -> tag) {
138: case TNAME: out_name (fp, (struct Nameblock *) e);
139: return;
140:
141: case TCONST: out_const(fp, &e->constblock);
142: goto end_out;
143: case TEXPR:
144: break;
145:
146: case TADDR: out_addr (fp, &(e -> addrblock));
147: goto end_out;
148:
149: case TPRIM: warn ("expr_out: got TPRIM");
150: output_prim (fp, &(e -> primblock));
151: return;
152:
153: case TLIST: output_list (fp, &(e -> listblock));
154: end_out: frexpr(e);
155: return;
156:
157: case TIMPLDO: err ("expr_out: got TIMPLDO");
158: return;
159:
160: case TERROR:
161: default:
162: erri ("expr_out: bad tag '%d'", e -> tag);
163: } /* switch */
164:
165: /* Now we know that the tag is TEXPR */
166:
167: /* Optimize on simple expressions, such as "a = a + b" ==> "a += b" */
168:
169: if (e -> exprblock.opcode == OPASSIGN && e -> exprblock.rightp &&
170: e -> exprblock.rightp -> tag == TEXPR) {
171: int opcode;
172:
173: opcode = e -> exprblock.rightp -> exprblock.opcode;
174:
175: if (opeqable[opcode]) {
176: expptr leftp, rightp;
177:
178: if ((leftp = e -> exprblock.leftp) &&
179: (rightp = e -> exprblock.rightp -> exprblock.leftp)) {
180:
181: if (same_ident (leftp, rightp)) {
182: expptr temp = e -> exprblock.rightp;
183:
184: e -> exprblock.opcode = op_assign(opcode);
185:
186: e -> exprblock.rightp = temp -> exprblock.rightp;
187: temp->exprblock.rightp = 0;
188: frexpr(temp);
189: } /* if same_ident (leftp, rightp) */
190: } /* if leftp && rightp */
191: } /* if opcode == OPPLUS || */
192: } /* if e -> exprblock.opcode == OPASSIGN */
193:
194:
195: /* Optimize on increment or decrement by 1 */
196:
197: {
198: int opcode = e -> exprblock.opcode;
199: expptr leftp = e -> exprblock.leftp;
200: expptr rightp = e -> exprblock.rightp;
201:
202: if (leftp && rightp && (leftp -> headblock.vstg == STGARG ||
203: ISINT (leftp -> headblock.vtype)) &&
204: (opcode == OPPLUSEQ || opcode == OPMINUSEQ) &&
205: ISINT (rightp -> headblock.vtype) &&
206: ISICON (e -> exprblock.rightp) &&
207: (ISONE (e -> exprblock.rightp) ||
208: e -> exprblock.rightp -> constblock.Const.ci == -1)) {
209:
210: /* Allow for the '-1' constant value */
211:
212: if (!ISONE (e -> exprblock.rightp))
213: opcode = (opcode == OPPLUSEQ) ? OPMINUSEQ : OPPLUSEQ;
214:
215: /* replace the existing opcode */
216:
217: if (opcode == OPPLUSEQ)
218: e -> exprblock.opcode = OPPREINC;
219: else
220: e -> exprblock.opcode = OPPREDEC;
221:
222: /* Free up storage used by the right hand side */
223:
224: frexpr (e -> exprblock.rightp);
225: e->exprblock.rightp = 0;
226: } /* if opcode == OPPLUS */
227: } /* block */
228:
229:
230: if (is_unary_op (e -> exprblock.opcode))
231: output_unary (fp, &(e -> exprblock));
232: else if (is_binary_op (e -> exprblock.opcode))
233: output_binary (fp, &(e -> exprblock));
234: else
235: erri ("expr_out: bad opcode '%d'", (int) e -> exprblock.opcode);
236:
237: free((char *)e);
238:
239: } /* expr_out */
240:
241:
242: void out_and_free_statement (outfile, expr)
243: FILE *outfile;
244: expptr expr;
245: {
246: if (expr)
247: expr_out (outfile, expr);
248:
249: nice_printf (outfile, ";\n");
250: } /* out_and_free_statement */
251:
252:
253:
254: int same_ident (left, right)
255: expptr left, right;
256: {
257: if (!left || !right)
258: return 0;
259:
260: if (left -> tag == TNAME && right -> tag == TNAME && left == right)
261: return 1;
262:
263: if (left -> tag == TADDR && right -> tag == TADDR &&
264: left -> addrblock.uname_tag == right -> addrblock.uname_tag)
265: switch (left -> addrblock.uname_tag) {
266: case UNAM_REF:
267: case UNAM_NAME:
268:
269: /* Check for array subscripts */
270:
271: if (left -> addrblock.user.name -> vdim ||
272: right -> addrblock.user.name -> vdim)
273: if (left -> addrblock.user.name !=
274: right -> addrblock.user.name ||
275: !same_expr (left -> addrblock.memoffset,
276: right -> addrblock.memoffset))
277: return 0;
278:
279: return same_ident ((expptr) (left -> addrblock.user.name),
280: (expptr) right -> addrblock.user.name);
281: case UNAM_IDENT:
282: return strcmp(left->addrblock.user.ident,
283: right->addrblock.user.ident) == 0;
284: case UNAM_CHARP:
285: return strcmp(left->addrblock.user.Charp,
286: right->addrblock.user.Charp) == 0;
287: default:
288: return 0;
289: } /* switch */
290:
291: if (left->tag == TEXPR && left->exprblock.opcode == OPWHATSIN
292: && right->tag == TEXPR && right->exprblock.opcode == OPWHATSIN)
293: return same_ident(left->exprblock.leftp,
294: right->exprblock.leftp);
295:
296: return 0;
297: } /* same_ident */
298:
299: static int
300: samefpconst(c1, c2, n)
301: register Constp c1, c2;
302: register int n;
303: {
304: char *s1, *s2;
305: if (!c1->vstg && !c2->vstg)
306: return c1->Const.cd[n] == c2->Const.cd[n];
307: s1 = c1->vstg ? c1->Const.cds[n] : dtos(c1->Const.cd[n]);
308: s2 = c2->vstg ? c2->Const.cds[n] : dtos(c2->Const.cd[n]);
309: return !strcmp(s1, s2);
310: }
311:
312: static int
313: sameconst(c1, c2)
314: register Constp c1, c2;
315: {
316: switch(c1->vtype) {
317: case TYCOMPLEX:
318: case TYDCOMPLEX:
319: if (!samefpconst(c1,c2,1))
320: return 0;
321: case TYREAL:
322: case TYDREAL:
323: return samefpconst(c1,c2,0);
324: case TYCHAR:
325: return c1->Const.ccp1.blanks == c2->Const.ccp1.blanks
326: && c1->vleng->constblock.Const.ci
327: == c2->vleng->constblock.Const.ci
328: && !memcmp(c1->Const.ccp, c2->Const.ccp,
329: (int)c1->vleng->constblock.Const.ci);
330: case TYSHORT:
331: case TYINT:
332: case TYLOGICAL:
333: return c1->Const.ci == c2->Const.ci;
334: }
335: err("unexpected type in sameconst");
336: return 0;
337: }
338:
339: /* same_expr -- Returns true only if e1 and e2 match. This is
340: somewhat pessimistic, but can afford to be because it's just used to
341: optimize on the assignment operators (+=, -=, etc). */
342:
343: int same_expr (e1, e2)
344: expptr e1, e2;
345: {
346: if (!e1 || !e2)
347: return !e1 && !e2;
348:
349: if (e1 -> tag != e2 -> tag || e1 -> headblock.vtype != e2 -> headblock.vtype)
350: return 0;
351:
352: switch (e1 -> tag) {
353: case TEXPR:
354: if (e1 -> exprblock.opcode != e2 -> exprblock.opcode)
355: return 0;
356:
357: return same_expr (e1 -> exprblock.leftp, e2 -> exprblock.leftp) &&
358: same_expr (e1 -> exprblock.rightp, e2 -> exprblock.rightp);
359: case TNAME:
360: case TADDR:
361: return same_ident (e1, e2);
362: case TCONST:
363: return sameconst(&e1->constblock, &e2->constblock);
364: default:
365: return 0;
366: } /* switch */
367: } /* same_expr */
368:
369:
370:
371: void out_name (fp, namep)
372: FILE *fp;
373: Namep namep;
374: {
375: extern int usedefsforcommon;
376: Extsym *comm;
377:
378: if (namep == NULL)
379: return;
380:
381: /* DON'T want to use oneof_stg() here; need to find the right common name
382: */
383:
384: if (namep->vstg == STGCOMMON && !namep->vcommequiv && !usedefsforcommon) {
385: comm = &extsymtab[namep->vardesc.varno];
386: extern_out(fp, comm);
387: nice_printf(fp, "%d.", comm->curno);
388: } /* if namep -> vstg == STGCOMMON */
389:
390: if (namep->vprocclass == PTHISPROC && namep->vtype != TYSUBR)
391: nice_printf(fp, xretslot[namep->vtype]->user.ident);
392: else
393: nice_printf (fp, "%s", namep->cvarname);
394: } /* out_name */
395:
396:
397: static char *Longfmt = "%ld";
398:
399: #define cpd(n) cp->vstg ? cp->Const.cds[n] : dtos(cp->Const.cd[n])
400:
401: void out_const(fp, cp)
402: FILE *fp;
403: register Constp cp;
404: {
405: static char real_buf[50], imag_buf[50];
406: unsigned int k;
407: int type = cp->vtype;
408:
409: switch (type) {
410: case TYINT1:
411: case TYSHORT:
412: nice_printf (fp, "%ld", cp->Const.ci); /* don't cast ci! */
413: break;
414: case TYLONG:
415: #ifdef TYQUAD
416: case TYQUAD:
417: #endif
418: nice_printf (fp, Longfmt, cp->Const.ci); /* don't cast ci! */
419: break;
420: case TYREAL:
421: nice_printf(fp, "%s", flconst(real_buf, cpd(0)));
422: break;
423: case TYDREAL:
424: nice_printf(fp, "%s", cpd(0));
425: break;
426: case TYCOMPLEX:
427: nice_printf(fp, cm_fmt_string, flconst(real_buf, cpd(0)),
428: flconst(imag_buf, cpd(1)));
429: break;
430: case TYDCOMPLEX:
431: nice_printf(fp, dcm_fmt_string, cpd(0), cpd(1));
432: break;
433: case TYLOGICAL1:
434: case TYLOGICAL2:
435: case TYLOGICAL:
436: nice_printf (fp, "%s", cp->Const.ci ? "TRUE_" : "FALSE_");
437: break;
438: case TYCHAR: {
439: char *c = cp->Const.ccp, *ce;
440:
441: if (c == NULL) {
442: nice_printf (fp, "\"\"");
443: break;
444: } /* if c == NULL */
445:
446: nice_printf (fp, "\"");
447: ce = c + cp->vleng->constblock.Const.ci;
448: while(c < ce) {
449: k = *(unsigned char *)c++;
450: nice_printf(fp, str_fmt[k], k);
451: }
452: for(k = cp->Const.ccp1.blanks; k > 0; k--)
453: nice_printf(fp, " ");
454: nice_printf (fp, "\"");
455: break;
456: } /* case TYCHAR */
457: default:
458: erri ("out_const: bad type '%d'", (int) type);
459: break;
460: } /* switch */
461:
462: } /* out_const */
463: #undef cpd
464:
465: static void
466: out_args(fp, ep) FILE *fp; expptr ep;
467: {
468: chainp arglist;
469:
470: if(ep->tag != TLIST)
471: badtag("out_args", ep->tag);
472: for(arglist = ep->listblock.listp;;) {
473: expr_out(fp, (expptr)arglist->datap);
474: arglist->datap = 0;
475: if (!(arglist = arglist->nextp))
476: break;
477: nice_printf(fp, ", ");
478: }
479: }
480:
481:
482: /* out_addr -- this routine isn't local because it is called by the
483: system-generated identifier printing routines */
484:
485: void out_addr (fp, addrp)
486: FILE *fp;
487: struct Addrblock *addrp;
488: {
489: extern Extsym *extsymtab;
490: int was_array = 0;
491: char *s;
492:
493:
494: if (addrp == NULL)
495: return;
496: if (doin_setbound
497: && addrp->vstg == STGARG
498: && addrp->vtype != TYCHAR
499: && ISICON(addrp->memoffset)
500: && !addrp->memoffset->constblock.Const.ci)
501: nice_printf(fp, "*");
502:
503: switch (addrp -> uname_tag) {
504: case UNAM_REF:
505: nice_printf(fp, "%s_%s(", addrp->user.name->cvarname,
506: addrp->cmplx_sub ? "subscr" : "ref");
507: out_args(fp, addrp->memoffset);
508: nice_printf(fp, ")");
509: return;
510: case UNAM_NAME:
511: out_name (fp, addrp -> user.name);
512: break;
513: case UNAM_IDENT:
514: if (*(s = addrp->user.ident) == ' ') {
515: if (multitype)
516: nice_printf(fp, "%s",
517: xretslot[addrp->vtype]->user.ident);
518: else
519: nice_printf(fp, "%s", s+1);
520: }
521: else {
522: nice_printf(fp, "%s", s);
523: }
524: break;
525: case UNAM_CHARP:
526: nice_printf(fp, "%s", addrp->user.Charp);
527: break;
528: case UNAM_EXTERN:
529: extern_out (fp, &extsymtab[addrp -> memno]);
530: break;
531: case UNAM_CONST:
532: switch(addrp->vstg) {
533: case STGCONST:
534: out_const(fp, (Constp)addrp);
535: break;
536: case STGMEMNO:
537: output_literal (fp, (int)addrp->memno,
538: (Constp)addrp);
539: break;
540: default:
541: Fatal("unexpected vstg in out_addr");
542: }
543: break;
544: case UNAM_UNKNOWN:
545: default:
546: nice_printf (fp, "Unknown Addrp");
547: break;
548: } /* switch */
549:
550: /* It's okay to just throw in the brackets here because they have a
551: precedence level of 15, the highest value. */
552:
553: if ((addrp->uname_tag == UNAM_NAME && addrp->user.name->vdim
554: || addrp->ntempelt > 1 || addrp->isarray)
555: && addrp->vtype != TYCHAR) {
556: expptr offset;
557:
558: was_array = 1;
559:
560: offset = addrp -> memoffset;
561: addrp->memoffset = 0;
562: if (ONEOF(addrp->vstg, M(STGCOMMON)|M(STGEQUIV))
563: && addrp -> uname_tag == UNAM_NAME
564: && !addrp->skip_offset)
565: offset = mkexpr (OPMINUS, offset, mkintcon (
566: addrp -> user.name -> voffset));
567:
568: nice_printf (fp, "[");
569:
570: offset = mkexpr (OPSLASH, offset,
571: ICON (typesize[addrp -> vtype] * (addrp -> Field ? 2 : 1)));
572: expr_out (fp, offset);
573: nice_printf (fp, "]");
574: }
575:
576: /* Check for structure field reference */
577:
578: if (addrp -> Field && addrp -> uname_tag != UNAM_CONST &&
579: addrp -> uname_tag != UNAM_UNKNOWN) {
580: if (oneof_stg((addrp -> uname_tag == UNAM_NAME ? addrp -> user.name :
581: (Namep) NULL), addrp -> vstg, M(STGARG)|M(STGEQUIV))
582: && !was_array && (addrp->vclass != CLPROC || !multitype))
583: nice_printf (fp, "->%s", addrp -> Field);
584: else
585: nice_printf (fp, ".%s", addrp -> Field);
586: } /* if */
587:
588: /* Check for character subscripting */
589:
590: if (addrp->vtype == TYCHAR &&
591: (addrp->vclass != CLPROC || addrp->uname_tag == UNAM_NAME
592: && addrp->user.name->vprocclass == PTHISPROC) &&
593: addrp -> memoffset &&
594: (addrp -> uname_tag != UNAM_NAME ||
595: addrp -> user.name -> vtype == TYCHAR) &&
596: (!ISICON (addrp -> memoffset) ||
597: (addrp -> memoffset -> constblock.Const.ci))) {
598:
599: int use_paren = 0;
600: expptr e = addrp -> memoffset;
601:
602: if (!e)
603: return;
604: addrp->memoffset = 0;
605:
606: if (ONEOF(addrp->vstg, M(STGCOMMON)|M(STGEQUIV))
607: && addrp -> uname_tag == UNAM_NAME) {
608: e = mkexpr (OPMINUS, e, mkintcon (addrp -> user.name -> voffset));
609:
610: /* mkexpr will simplify it to zero if possible */
611: if (e->tag == TCONST && e->constblock.Const.ci == 0)
612: return;
613: } /* if addrp -> vstg == STGCOMMON */
614:
615: /* In the worst case, parentheses might be needed OUTSIDE the expression,
616: too. But since I think this subscripting can only appear as a
617: parameter in a procedure call, I don't think outside parens will ever
618: be needed. INSIDE parens are handled below */
619:
620: nice_printf (fp, " + ");
621: if (e -> tag == TEXPR) {
622: int arg_prec = op_precedence (e -> exprblock.opcode);
623: int prec = op_precedence (OPPLUS);
624: use_paren = arg_prec && (arg_prec < prec || (arg_prec == prec &&
625: is_left_assoc (OPPLUS)));
626: } /* if e -> tag == TEXPR */
627: if (use_paren) nice_printf (fp, "(");
628: expr_out (fp, e);
629: if (use_paren) nice_printf (fp, ")");
630: } /* if */
631: } /* out_addr */
632:
633:
634: static void output_literal (fp, memno, cp)
635: FILE *fp;
636: int memno;
637: Constp cp;
638: {
639: struct Literal *litp, *lastlit;
640: extern char *lit_name ();
641:
642: lastlit = litpool + nliterals;
643:
644: for (litp = litpool; litp < lastlit; litp++) {
645: if (litp -> litnum == memno)
646: break;
647: } /* for litp */
648:
649: if (litp >= lastlit)
650: out_const (fp, cp);
651: else {
652: nice_printf (fp, "%s", lit_name (litp));
653: litp->lituse++;
654: }
655: } /* output_literal */
656:
657:
658: static void output_prim (fp, primp)
659: FILE *fp;
660: struct Primblock *primp;
661: {
662: if (primp == NULL)
663: return;
664:
665: out_name (fp, primp -> namep);
666: if (primp -> argsp)
667: output_arg_list (fp, primp -> argsp);
668:
669: if (primp -> fcharp != (expptr) NULL || primp -> lcharp != (expptr) NULL)
670: nice_printf (fp, "Sorry, no substrings yet");
671: }
672:
673:
674:
675: static void output_arg_list (fp, listp)
676: FILE *fp;
677: struct Listblock *listp;
678: {
679: chainp arg_list;
680:
681: if (listp == (struct Listblock *) NULL || listp -> listp == (chainp) NULL)
682: return;
683:
684: nice_printf (fp, "(");
685:
686: for (arg_list = listp -> listp; arg_list; arg_list = arg_list -> nextp) {
687: expr_out (fp, (expptr) arg_list -> datap);
688: if (arg_list -> nextp != (chainp) NULL)
689:
690: /* Might want to add a hook in here to accomodate the style setting which
691: wants spaces after commas */
692:
693: nice_printf (fp, ",");
694: } /* for arg_list */
695:
696: nice_printf (fp, ")");
697: } /* output_arg_list */
698:
699:
700:
701: static void output_unary (fp, e)
702: FILE *fp;
703: struct Exprblock *e;
704: {
705: if (e == NULL)
706: return;
707:
708: switch (e -> opcode) {
709: case OPNEG:
710: if (e->vtype == TYREAL && forcedouble) {
711: e->opcode = OPNEG_KLUDGE;
712: output_binary(fp,e);
713: e->opcode = OPNEG;
714: break;
715: }
716: case OPNEG1:
717: case OPNOT:
718: case OPABS:
719: case OPBITNOT:
720: case OPWHATSIN:
721: case OPPREINC:
722: case OPPREDEC:
723: case OPADDR:
724: case OPIDENTITY:
725: case OPCHARCAST:
726: case OPDABS:
727: output_binary (fp, e);
728: break;
729: case OPCALL:
730: case OPCCALL:
731: nice_printf (fp, "Sorry, no OPCALL yet");
732: break;
733: default:
734: erri ("output_unary: bad opcode", (int) e -> opcode);
735: break;
736: } /* switch */
737: } /* output_unary */
738:
739:
740: static char *
741: findconst(m)
742: register long m;
743: {
744: register struct Literal *litp, *litpe;
745:
746: litp = litpool;
747: for(litpe = litp + nliterals; litp < litpe; litp++)
748: if (litp->litnum == m)
749: return litp->cds[0];
750: Fatal("findconst failure!");
751: return 0;
752: }
753:
754: static int
755: opconv_fudge(fp,e)
756: FILE *fp;
757: struct Exprblock *e;
758: {
759: /* special handling for ichar and character*1 */
760: register expptr lp;
761: register union Expression *Offset;
762: register char *cp;
763: int lt;
764: char buf[8];
765: unsigned int k;
766: Namep np;
767:
768: if (!(lp = e->leftp)) /* possible with erroneous Fortran */
769: return 1;
770: lt = lp->headblock.vtype;
771: if (lt == TYCHAR) {
772: switch(lp->tag) {
773: case TNAME:
774: nice_printf(fp, "*");
775: out_name(fp, (Namep)lp);
776: return 1;
777: case TCONST:
778: tconst:
779: cp = lp->constblock.Const.ccp;
780: tconst1:
781: k = *(unsigned char *)cp;
782: sprintf(buf, chr_fmt[k], k);
783: nice_printf(fp, "'%s'", buf);
784: return 1;
785: case TADDR:
786: switch(lp->addrblock.vstg) {
787: case STGMEMNO:
788: if (halign && e->vtype != TYCHAR) {
789: nice_printf(fp, "*(%s *)",
790: c_type_decl(e->vtype));
791: expr_out(fp, lp);
792: return 1;
793: }
794: cp = findconst(lp->addrblock.memno);
795: goto tconst1;
796: case STGCONST:
797: goto tconst;
798: }
799: lp->addrblock.vtype = tyint;
800: Offset = lp->addrblock.memoffset;
801: switch(lp->addrblock.uname_tag) {
802: case UNAM_REF:
803: nice_printf(fp, "*");
804: return 0;
805: case UNAM_NAME:
806: np = lp->addrblock.user.name;
807: if (ONEOF(np->vstg,
808: M(STGCOMMON)|M(STGEQUIV)))
809: Offset = mkexpr(OPMINUS, Offset,
810: ICON(np->voffset));
811: }
812: lp->addrblock.memoffset = Offset ?
813: mkexpr(OPSTAR, Offset,
814: ICON(typesize[tyint]))
815: : ICON(0);
816: lp->addrblock.isarray = 1;
817: /* STGCOMMON or STGEQUIV would cause */
818: /* voffset to be added in a second time */
819: lp->addrblock.vstg = STGUNKNOWN;
820: break;
821: default:
822: badtag("opconv_fudge", lp->tag);
823: }
824: }
825: if (lt != e->vtype)
826: nice_printf(fp, "(%s) ",
827: c_type_decl(e->vtype, 0));
828: return 0;
829: }
830:
831:
832: static void output_binary (fp, e)
833: FILE *fp;
834: struct Exprblock *e;
835: {
836: char *format;
837: extern table_entry opcode_table[];
838: int prec;
839:
840: if (e == NULL || e -> tag != TEXPR)
841: return;
842:
843: /* Instead of writing a huge switch, I've incorporated the output format
844: into a table. Things like "%l" and "%r" stand for the left and
845: right subexpressions. This should allow both prefix and infix
846: functions to be specified (e.g. "(%l * %r", "z_div (%l, %r"). Of
847: course, I should REALLY think out the ramifications of writing out
848: straight text, as opposed to some intermediate format, which could
849: figure out and optimize on the the number of required blanks (we don't
850: want "x - (-y)" to become "x --y", for example). Special cases (such as
851: incomplete implementations) could still be implemented as part of the
852: switch, they will just have some dummy value instead of the string
853: pattern. Another difficulty is the fact that the complex functions
854: will differ from the integer and real ones */
855:
856: /* Handle a special case. We don't want to output "x + - 4", or "y - - 3"
857: */
858: if ((e -> opcode == OPPLUS || e -> opcode == OPMINUS) &&
859: e -> rightp && e -> rightp -> tag == TCONST &&
860: isnegative_const (&(e -> rightp -> constblock)) &&
861: is_negatable (&(e -> rightp -> constblock))) {
862:
863: e -> opcode = (e -> opcode == OPPLUS) ? OPMINUS : OPPLUS;
864: negate_const (&(e -> rightp -> constblock));
865: } /* if e -> opcode == PLUS or MINUS */
866:
867: prec = op_precedence (e -> opcode);
868: format = op_format (e -> opcode);
869:
870: if (format != SPECIAL_FMT) {
871: while (*format) {
872: if (*format == '%') {
873: int arg_prec, use_paren = 0;
874: expptr lp, rp;
875:
876: switch (*(format + 1)) {
877: case 'l':
878: lp = e->leftp;
879: if (lp && lp->tag == TEXPR) {
880: arg_prec = op_precedence(lp->exprblock.opcode);
881:
882: use_paren = arg_prec &&
883: (arg_prec < prec || (arg_prec == prec &&
884: is_right_assoc (prec)));
885: } /* if e -> leftp */
886: if (e->opcode == OPCONV && opconv_fudge(fp,e))
887: break;
888: if (use_paren)
889: nice_printf (fp, "(");
890: expr_out(fp, lp);
891: if (use_paren)
892: nice_printf (fp, ")");
893: break;
894: case 'r':
895: rp = e->rightp;
896: if (rp && rp->tag == TEXPR) {
897: arg_prec = op_precedence(rp->exprblock.opcode);
898:
899: use_paren = arg_prec &&
900: (arg_prec < prec || (arg_prec == prec &&
901: is_left_assoc (prec)));
902: use_paren = use_paren ||
903: (rp->exprblock.opcode == OPNEG
904: && prec >= op_precedence(OPMINUS));
905: } /* if e -> rightp */
906: if (use_paren)
907: nice_printf (fp, "(");
908: expr_out(fp, rp);
909: if (use_paren)
910: nice_printf (fp, ")");
911: break;
912: case '\0':
913: case '%':
914: nice_printf (fp, "%%");
915: break;
916: default:
917: erri ("output_binary: format err: '%%%c' illegal",
918: (int) *(format + 1));
919: break;
920: } /* switch */
921: format += 2;
922: } else
923: nice_printf (fp, "%c", *format++);
924: } /* while *format */
925: } else {
926:
927: /* Handle Special cases of formatting */
928:
929: switch (e -> opcode) {
930: case OPCCALL:
931: case OPCALL:
932: out_call (fp, (int) e -> opcode, e -> vtype,
933: e -> vleng, e -> leftp, e -> rightp);
934: break;
935:
936: case OPCOMMA_ARG:
937: doin_setbound = 1;
938: nice_printf(fp, "(");
939: expr_out(fp, e->leftp);
940: nice_printf(fp, ", &");
941: doin_setbound = 0;
942: expr_out(fp, e->rightp);
943: nice_printf(fp, ")");
944: break;
945:
946: case OPADDR:
947: default:
948: nice_printf (fp, "Sorry, can't format OPCODE '%d'",
949: e -> opcode);
950: break;
951: }
952:
953: } /* else */
954: } /* output_binary */
955:
956:
957: out_call (outfile, op, ftype, len, name, args)
958: FILE *outfile;
959: int op, ftype;
960: expptr len, name, args;
961: {
962: chainp arglist; /* Pointer to any actual arguments */
963: chainp cp; /* Iterator over argument lists */
964: Addrp ret_val = (Addrp) NULL;
965: /* Function return value buffer, if any is
966: required */
967: int byvalue; /* True iff we're calling a C library
968: routine */
969: int done_once; /* Used for writing commas to outfile */
970: int narg, t;
971: register expptr q;
972: long L;
973: Argtypes *at;
974: Atype *A, *Ac;
975: Namep np;
976: extern int forcereal;
977:
978: /* Don't use addresses if we're calling a C function */
979:
980: byvalue = op == OPCCALL;
981:
982: if (args)
983: arglist = args -> listblock.listp;
984: else
985: arglist = CHNULL;
986:
987: /* If this is a CHARACTER function, the first argument is the result */
988:
989: if (ftype == TYCHAR)
990: if (ISICON (len)) {
991: ret_val = (Addrp) (arglist -> datap);
992: arglist = arglist -> nextp;
993: } else {
994: err ("adjustable character function");
995: return;
996: } /* else */
997:
998: /* If this is a COMPLEX function, the first argument is the result */
999:
1000: else if (ISCOMPLEX (ftype)) {
1001: ret_val = (Addrp) (arglist -> datap);
1002: arglist = arglist -> nextp;
1003: } /* if ISCOMPLEX */
1004:
1005: /* Now we can actually start to write out the function invocation */
1006:
1007: if (ftype == TYREAL && forcereal)
1008: nice_printf(outfile, "(real)");
1009: if (name -> tag == TEXPR && name -> exprblock.opcode == OPWHATSIN) {
1010: nice_printf (outfile, "(");
1011: np = (Namep)name->exprblock.leftp; /*expr_out will free name */
1012: expr_out (outfile, name);
1013: nice_printf (outfile, ")");
1014: }
1015: else {
1016: np = (Namep)name;
1017: expr_out(outfile, name);
1018: }
1019:
1020: /* prepare to cast procedure parameters -- set A if we know how */
1021:
1022: A = Ac = 0;
1023: if (np->tag == TNAME && (at = np->arginfo)) {
1024: if (at->nargs > 0)
1025: A = at->atypes;
1026: if (Ansi && (at->defined || at->nargs > 0))
1027: Ac = at->atypes;
1028: }
1029:
1030: nice_printf(outfile, "(");
1031:
1032: if (ret_val) {
1033: if (ISCOMPLEX (ftype))
1034: nice_printf (outfile, "&");
1035: expr_out (outfile, (expptr) ret_val);
1036: if (Ac)
1037: Ac++;
1038:
1039: /* The length of the result of a character function is the second argument */
1040: /* It should be in place from putcall(), so we won't touch it explicitly */
1041:
1042: } /* if ret_val */
1043: done_once = ret_val ? TRUE : FALSE;
1044:
1045: /* Now run through the named arguments */
1046:
1047: narg = -1;
1048: for (cp = arglist; cp; cp = cp -> nextp, done_once = TRUE) {
1049:
1050: if (done_once)
1051: nice_printf (outfile, ", ");
1052: narg++;
1053:
1054: if (!( q = (expptr)cp->datap) )
1055: continue;
1056:
1057: if (q->tag == TADDR) {
1058: if (q->addrblock.vtype > TYERROR) {
1059: /* I/O block */
1060: nice_printf(outfile, "&%s", q->addrblock.user.ident);
1061: continue;
1062: }
1063: if (!byvalue && q->addrblock.isarray
1064: && q->addrblock.vtype != TYCHAR
1065: && q->addrblock.memoffset->tag == TCONST) {
1066:
1067: /* check for 0 offset -- after */
1068: /* correcting for equivalence. */
1069: L = q->addrblock.memoffset->constblock.Const.ci;
1070: if (ONEOF(q->addrblock.vstg, M(STGCOMMON)|M(STGEQUIV))
1071: && q->addrblock.uname_tag == UNAM_NAME)
1072: L -= q->addrblock.user.name->voffset;
1073: if (L)
1074: goto skip_deref;
1075:
1076: if (Ac && narg < at->dnargs
1077: && q->headblock.vtype != (t = Ac[narg].type)
1078: && t > TYADDR && t < TYSUBR)
1079: nice_printf(outfile, "(%s*)", typename[t]);
1080:
1081: /* &x[0] == x */
1082: /* This also prevents &sizeof(doublereal)[0] */
1083:
1084: switch(q->addrblock.uname_tag) {
1085: case UNAM_NAME:
1086: out_name(outfile, q->addrblock.user.name);
1087: continue;
1088: case UNAM_IDENT:
1089: nice_printf(outfile, "%s",
1090: q->addrblock.user.ident);
1091: continue;
1092: case UNAM_CHARP:
1093: nice_printf(outfile, "%s",
1094: q->addrblock.user.Charp);
1095: continue;
1096: case UNAM_EXTERN:
1097: extern_out(outfile,
1098: &extsymtab[q->addrblock.memno]);
1099: continue;
1100: }
1101: }
1102: }
1103:
1104: /* Skip over the dereferencing operator generated only for the
1105: intermediate file */
1106: skip_deref:
1107: if (q -> tag == TEXPR && q -> exprblock.opcode == OPWHATSIN)
1108: q = q -> exprblock.leftp;
1109:
1110: if (q->headblock.vclass == CLPROC) {
1111: if (Castargs && (q->tag != TNAME
1112: || q->nameblock.vprocclass != PTHISPROC))
1113: {
1114: if (A && (t = A[narg].type) >= 200)
1115: t %= 100;
1116: else {
1117: t = q->headblock.vtype;
1118: if (q->tag == TNAME && q->nameblock.vimpltype)
1119: t = TYUNKNOWN;
1120: }
1121: nice_printf(outfile, "(%s)", usedcasts[t] = casttypes[t]);
1122: }
1123: }
1124: else if (Ac && narg < at->dnargs
1125: && q->headblock.vtype != (t = Ac[narg].type)
1126: && t > TYADDR && t < TYSUBR)
1127: nice_printf(outfile, "(%s*)", typename[t]);
1128:
1129: if ((q -> tag == TADDR || q-> tag == TNAME) &&
1130: (byvalue || q -> headblock.vstg != STGREG)) {
1131: if (q -> headblock.vtype != TYCHAR)
1132: if (byvalue) {
1133:
1134: if (q -> tag == TADDR &&
1135: q -> addrblock.uname_tag == UNAM_NAME &&
1136: ! q -> addrblock.user.name -> vdim &&
1137: oneof_stg(q -> addrblock.user.name, q -> addrblock.vstg,
1138: M(STGARG)|M(STGEQUIV)) &&
1139: ! ISCOMPLEX(q->addrblock.user.name->vtype))
1140: nice_printf (outfile, "*");
1141: else if (q -> tag == TNAME
1142: && oneof_stg(&q->nameblock, q -> nameblock.vstg,
1143: M(STGARG)|M(STGEQUIV))
1144: && !(q -> nameblock.vdim))
1145: nice_printf (outfile, "*");
1146:
1147: } else {
1148: expptr memoffset;
1149:
1150: if (q->tag == TADDR &&
1151: !ONEOF (q -> addrblock.vstg, M(STGEXT)|M(STGLENG))
1152: && (
1153: ONEOF(q->addrblock.vstg,
1154: M(STGCOMMON)|M(STGEQUIV)|M(STGMEMNO))
1155: || ((memoffset = q->addrblock.memoffset)
1156: && (!ISICON(memoffset)
1157: || memoffset->constblock.Const.ci)))
1158: || ONEOF(q->addrblock.vstg,
1159: M(STGINIT)|M(STGAUTO)|M(STGBSS))
1160: && !q->addrblock.isarray)
1161: nice_printf (outfile, "&");
1162: else if (q -> tag == TNAME
1163: && !oneof_stg(&q->nameblock, q -> nameblock.vstg,
1164: M(STGARG)|M(STGEXT)|M(STGEQUIV)))
1165: nice_printf (outfile, "&");
1166: } /* else */
1167:
1168: expr_out (outfile, q);
1169: } /* if q -> tag == TADDR || q -> tag == TNAME */
1170:
1171: /* Might be a Constant expression, e.g. string length, character constants */
1172:
1173: else if (q -> tag == TCONST) {
1174: if (tyioint == TYLONG)
1175: Longfmt = "%ldL";
1176: out_const(outfile, &q->constblock);
1177: Longfmt = "%ld";
1178: }
1179:
1180: /* Must be some other kind of expression, or register var, or constant.
1181: In particular, this is likely to be a temporary variable assignment
1182: which was generated in p1put_call */
1183:
1184: else if (!ISCOMPLEX (q -> headblock.vtype) && !ISCHAR (q)){
1185: int use_paren = q -> tag == TEXPR &&
1186: op_precedence (q -> exprblock.opcode) <=
1187: op_precedence (OPCOMMA);
1188:
1189: if (use_paren) nice_printf (outfile, "(");
1190: expr_out (outfile, q);
1191: if (use_paren) nice_printf (outfile, ")");
1192: } /* if !ISCOMPLEX */
1193: else
1194: err ("out_call: unknown parameter");
1195:
1196: } /* for (cp = arglist */
1197:
1198: if (arglist)
1199: frchain (&arglist);
1200:
1201: nice_printf (outfile, ")");
1202:
1203: } /* out_call */
1204:
1205:
1206: char *
1207: flconst(buf, x)
1208: char *buf, *x;
1209: {
1210: sprintf(buf, fl_fmt_string, x);
1211: return buf;
1212: }
1213:
1214: char *
1215: dtos(x)
1216: double x;
1217: {
1218: static char buf[64];
1219: sprintf(buf, db_fmt_string, x);
1220: return buf;
1221: }
1222:
1223: char tr_tab[Table_size];
1224:
1225: /* out_init -- Initialize the data structures used by the routines in
1226: output.c. These structures include the output format to be used for
1227: Float, Double, Complex, and Double Complex constants. */
1228:
1229: void out_init ()
1230: {
1231: extern int tab_size;
1232: register char *s;
1233:
1234: s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+-.";
1235: while(*s)
1236: tr_tab[*s++] = 3;
1237: tr_tab['>'] = 1;
1238:
1239: opeqable[OPPLUS] = 1;
1240: opeqable[OPMINUS] = 1;
1241: opeqable[OPSTAR] = 1;
1242: opeqable[OPSLASH] = 1;
1243: opeqable[OPMOD] = 1;
1244: opeqable[OPLSHIFT] = 1;
1245: opeqable[OPBITAND] = 1;
1246: opeqable[OPBITXOR] = 1;
1247: opeqable[OPBITOR ] = 1;
1248:
1249:
1250: /* Set the output format for both types of floating point constants */
1251:
1252: if (fl_fmt_string == NULL || *fl_fmt_string == '\0')
1253: fl_fmt_string = Ansi == 1 ? "%sf" : "(float)%s";
1254:
1255: if (db_fmt_string == NULL || *db_fmt_string == '\0')
1256: db_fmt_string = "%.17g";
1257:
1258: /* Set the output format for both types of complex constants. They will
1259: have string parameters rather than float or double so that the decimal
1260: point may be added to the strings generated by the {db,fl}_fmt_string
1261: formats above */
1262:
1263: if (cm_fmt_string == NULL || *cm_fmt_string == '\0') {
1264: cm_fmt_string = "{%s,%s}";
1265: } /* if cm_fmt_string == NULL */
1266:
1267: if (dcm_fmt_string == NULL || *dcm_fmt_string == '\0') {
1268: dcm_fmt_string = "{%s,%s}";
1269: } /* if dcm_fmt_string == NULL */
1270:
1271: tab_size = 4;
1272: } /* out_init */
1273:
1274:
1275: void extern_out (fp, extsym)
1276: FILE *fp;
1277: Extsym *extsym;
1278: {
1279: if (extsym == (Extsym *) NULL)
1280: return;
1281:
1282: nice_printf (fp, "%s", extsym->cextname);
1283:
1284: } /* extern_out */
1285:
1286:
1287:
1288: static void output_list (fp, listp)
1289: FILE *fp;
1290: struct Listblock *listp;
1291: {
1292: int did_one = 0;
1293: chainp elts;
1294:
1295: nice_printf (fp, "(");
1296: if (listp)
1297: for (elts = listp -> listp; elts; elts = elts -> nextp) {
1298: if (elts -> datap) {
1299: if (did_one)
1300: nice_printf (fp, ", ");
1301: expr_out (fp, (expptr) elts -> datap);
1302: did_one = 1;
1303: } /* if elts -> datap */
1304: } /* for elts */
1305: nice_printf (fp, ")");
1306: } /* output_list */
1307:
1308:
1309: void out_asgoto (outfile, expr)
1310: FILE *outfile;
1311: expptr expr;
1312: {
1313: char *user_label();
1314: chainp value;
1315: Namep namep;
1316: int k;
1317:
1318: if (expr == (expptr) NULL) {
1319: err ("out_asgoto: NULL variable expr");
1320: return;
1321: } /* if expr */
1322:
1323: nice_printf (outfile, Ansi ? "switch (" : "switch ((int)"); /*)*/
1324: expr_out (outfile, expr);
1325: nice_printf (outfile, ") {\n");
1326: next_tab (outfile);
1327:
1328: /* The initial addrp value will be stored as a namep pointer */
1329:
1330: switch(expr->tag) {
1331: case TNAME:
1332: /* local variable */
1333: namep = &expr->nameblock;
1334: break;
1335: case TEXPR:
1336: if (expr->exprblock.opcode == OPWHATSIN
1337: && expr->exprblock.leftp->tag == TNAME)
1338: /* argument */
1339: namep = &expr->exprblock.leftp->nameblock;
1340: else
1341: goto bad;
1342: break;
1343: case TADDR:
1344: if (expr->addrblock.uname_tag == UNAM_NAME) {
1345: /* initialized local variable */
1346: namep = expr->addrblock.user.name;
1347: break;
1348: }
1349: default:
1350: bad:
1351: err("out_asgoto: bad expr");
1352: return;
1353: }
1354:
1355: for(k = 0, value = namep -> varxptr.assigned_values; value;
1356: value = value->nextp, k++) {
1357: nice_printf (outfile, "case %d: goto %s;\n", k,
1358: user_label((long)value->datap));
1359: } /* for value */
1360: prev_tab (outfile);
1361:
1362: nice_printf (outfile, "}\n");
1363: } /* out_asgoto */
1364:
1365: void out_if (outfile, expr)
1366: FILE *outfile;
1367: expptr expr;
1368: {
1369: nice_printf (outfile, "if (");
1370: expr_out (outfile, expr);
1371: nice_printf (outfile, ") {\n");
1372: next_tab (outfile);
1373: } /* out_if */
1374:
1375: static void
1376: output_rbrace(outfile, s)
1377: FILE *outfile;
1378: char *s;
1379: {
1380: extern int last_was_label;
1381: register char *fmt;
1382:
1383: if (last_was_label) {
1384: last_was_label = 0;
1385: fmt = ";%s";
1386: }
1387: else
1388: fmt = "%s";
1389: nice_printf(outfile, fmt, s);
1390: }
1391:
1392: void out_else (outfile)
1393: FILE *outfile;
1394: {
1395: prev_tab (outfile);
1396: output_rbrace(outfile, "} else {\n");
1397: next_tab (outfile);
1398: } /* out_else */
1399:
1400: void elif_out (outfile, expr)
1401: FILE *outfile;
1402: expptr expr;
1403: {
1404: prev_tab (outfile);
1405: output_rbrace(outfile, "} else ");
1406: out_if (outfile, expr);
1407: } /* elif_out */
1408:
1409: void endif_out (outfile)
1410: FILE *outfile;
1411: {
1412: prev_tab (outfile);
1413: output_rbrace(outfile, "}\n");
1414: } /* endif_out */
1415:
1416: void end_else_out (outfile)
1417: FILE *outfile;
1418: {
1419: prev_tab (outfile);
1420: output_rbrace(outfile, "}\n");
1421: } /* end_else_out */
1422:
1423:
1424:
1425: void compgoto_out (outfile, index, labels)
1426: FILE *outfile;
1427: expptr index, labels;
1428: {
1429: char *s1, *s2;
1430:
1431: if (index == ENULL)
1432: err ("compgoto_out: null index for computed goto");
1433: else if (labels && labels -> tag != TLIST)
1434: erri ("compgoto_out: expected label list, got tag '%d'",
1435: labels -> tag);
1436: else {
1437: extern char *user_label ();
1438: chainp elts;
1439: int i = 1;
1440:
1441: s2 = /*(*/ ") {\n"; /*}*/
1442: if (Ansi)
1443: s1 = "switch ("; /*)*/
1444: else if (index->tag == TNAME || index->tag == TEXPR
1445: && index->exprblock.opcode == OPWHATSIN)
1446: s1 = "switch ((int)"; /*)*/
1447: else {
1448: s1 = "switch ((int)(";
1449: s2 = ")) {\n"; /*}*/
1450: }
1451: nice_printf(outfile, s1);
1452: expr_out (outfile, index);
1453: nice_printf (outfile, s2);
1454: next_tab (outfile);
1455:
1456: for (elts = labels -> listblock.listp; elts; elts = elts -> nextp, i++) {
1457: if (elts -> datap) {
1458: if (ISICON(((expptr) (elts -> datap))))
1459: nice_printf (outfile, "case %d: goto %s;\n", i,
1460: user_label(((expptr)(elts->datap))->constblock.Const.ci));
1461: else
1462: err ("compgoto_out: bad label in label list");
1463: } /* if (elts -> datap) */
1464: } /* for elts */
1465: prev_tab (outfile);
1466: nice_printf (outfile, /*{*/ "}\n");
1467: } /* else */
1468: } /* compgoto_out */
1469:
1470:
1471: void out_for (outfile, init, test, inc)
1472: FILE *outfile;
1473: expptr init, test, inc;
1474: {
1475: nice_printf (outfile, "for (");
1476: expr_out (outfile, init);
1477: nice_printf (outfile, "; ");
1478: expr_out (outfile, test);
1479: nice_printf (outfile, "; ");
1480: expr_out (outfile, inc);
1481: nice_printf (outfile, ") {\n");
1482: next_tab (outfile);
1483: } /* out_for */
1484:
1485:
1486: void out_end_for (outfile)
1487: FILE *outfile;
1488: {
1489: prev_tab (outfile);
1490: nice_printf (outfile, "}\n");
1491: } /* out_end_for */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.