1 /****************************************************************
2 Copyright 1990, 1991 by AT&T Bell Laboratories and Bellcore.
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.
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
22 ****************************************************************/
35 char _assoc_table[] = { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
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. */
41 table_entry opcode_table[] = {
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 },
64 /* Left hand side of an assignment cannot have outermost parens */
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" },
74 /* Don't want to nest the colon operator in parens */
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" },
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" },
90 /* This isn't quite right -- it doesn't handle arrays, for instance */
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)" },
115 /* kludge to imitate (under forcedouble) f77's bizarre treatement of OPNEG... */
117 /* OPNEG KLUDGE */ { UNARY_OP, 14, "-(doublereal)%l" }
118 }; /* opcode_table */
120 #define OPNEG_KLUDGE (sizeof(opcode_table)/sizeof(table_entry) - 1)
122 static char opeqable[sizeof(opcode_table)/sizeof(table_entry)];
125 static void output_prim ();
126 static void output_unary (), output_binary (), output_arg_list ();
127 static void output_list (), output_literal ();
130 void expr_out (fp, e)
134 if (e == (expptr) NULL)
138 case TNAME: out_name (fp, (struct Nameblock *) e);
141 case TCONST: out_const(fp, &e->constblock);
146 case TADDR: out_addr (fp, &(e -> addrblock));
149 case TPRIM: warn ("expr_out: got TPRIM");
150 output_prim (fp, &(e -> primblock));
153 case TLIST: output_list (fp, &(e -> listblock));
157 case TIMPLDO: err ("expr_out: got TIMPLDO");
162 erri ("expr_out: bad tag '%d'", e -> tag);
165 /* Now we know that the tag is TEXPR */
167 /* Optimize on simple expressions, such as "a = a + b" ==> "a += b" */
169 if (e -> exprblock.opcode == OPASSIGN && e -> exprblock.rightp &&
170 e -> exprblock.rightp -> tag == TEXPR) {
173 opcode = e -> exprblock.rightp -> exprblock.opcode;
175 if (opeqable[opcode]) {
176 expptr leftp, rightp;
178 if ((leftp = e -> exprblock.leftp) &&
179 (rightp = e -> exprblock.rightp -> exprblock.leftp)) {
181 if (same_ident (leftp, rightp)) {
182 expptr temp = e -> exprblock.rightp;
184 e -> exprblock.opcode = op_assign(opcode);
186 e -> exprblock.rightp = temp -> exprblock.rightp;
187 temp->exprblock.rightp = 0;
189 } /* if same_ident (leftp, rightp) */
190 } /* if leftp && rightp */
191 } /* if opcode == OPPLUS || */
192 } /* if e -> exprblock.opcode == OPASSIGN */
195 /* Optimize on increment or decrement by 1 */
198 int opcode = e -> exprblock.opcode;
199 expptr leftp = e -> exprblock.leftp;
200 expptr rightp = e -> exprblock.rightp;
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)) {
210 /* Allow for the '-1' constant value */
212 if (!ISONE (e -> exprblock.rightp))
213 opcode = (opcode == OPPLUSEQ) ? OPMINUSEQ : OPPLUSEQ;
215 /* replace the existing opcode */
217 if (opcode == OPPLUSEQ)
218 e -> exprblock.opcode = OPPREINC;
220 e -> exprblock.opcode = OPPREDEC;
222 /* Free up storage used by the right hand side */
224 frexpr (e -> exprblock.rightp);
225 e->exprblock.rightp = 0;
226 } /* if opcode == OPPLUS */
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));
235 erri ("expr_out: bad opcode '%d'", (int) e -> exprblock.opcode);
242 void out_and_free_statement (outfile, expr)
247 expr_out (outfile, expr);
249 nice_printf (outfile, ";\n");
250 } /* out_and_free_statement */
254 int same_ident (left, right)
260 if (left -> tag == TNAME && right -> tag == TNAME && left == right)
263 if (left -> tag == TADDR && right -> tag == TADDR &&
264 left -> addrblock.uname_tag == right -> addrblock.uname_tag)
265 switch (left -> addrblock.uname_tag) {
268 /* Check for array subscripts */
270 if (left -> addrblock.user.name -> vdim ||
271 right -> addrblock.user.name -> vdim)
272 if (left -> addrblock.user.name !=
273 right -> addrblock.user.name ||
274 !same_expr (left -> addrblock.memoffset,
275 right -> addrblock.memoffset))
278 return same_ident ((expptr) (left -> addrblock.user.name),
279 (expptr) right -> addrblock.user.name);
281 return strcmp(left->addrblock.user.ident,
282 right->addrblock.user.ident) == 0;
284 return strcmp(left->addrblock.user.Charp,
285 right->addrblock.user.Charp) == 0;
290 if (left->tag == TEXPR && left->exprblock.opcode == OPWHATSIN
291 && right->tag == TEXPR && right->exprblock.opcode == OPWHATSIN)
292 return same_ident(left->exprblock.leftp,
293 right->exprblock.leftp);
299 samefpconst(c1, c2, n)
300 register Constp c1, c2;
304 if (!c1->vstg && !c2->vstg)
305 return c1->Const.cd[n] == c2->Const.cd[n];
306 s1 = c1->vstg ? c1->Const.cds[n] : dtos(c1->Const.cd[n]);
307 s2 = c2->vstg ? c2->Const.cds[n] : dtos(c2->Const.cd[n]);
308 return !strcmp(s1, s2);
313 register Constp c1, c2;
318 if (!samefpconst(c1,c2,1))
322 return samefpconst(c1,c2,0);
324 return c1->Const.ccp1.blanks == c2->Const.ccp1.blanks
325 && c1->vleng->constblock.Const.ci
326 == c2->vleng->constblock.Const.ci
327 && !memcmp(c1->Const.ccp, c2->Const.ccp,
328 (int)c1->vleng->constblock.Const.ci);
332 return c1->Const.ci == c2->Const.ci;
334 err("unexpected type in sameconst");
338 /* same_expr -- Returns true only if e1 and e2 match. This is
339 somewhat pessimistic, but can afford to be because it's just used to
340 optimize on the assignment operators (+=, -=, etc). */
342 int same_expr (e1, e2)
348 if (e1 -> tag != e2 -> tag || e1 -> headblock.vtype != e2 -> headblock.vtype)
353 if (e1 -> exprblock.opcode != e2 -> exprblock.opcode)
356 return same_expr (e1 -> exprblock.leftp, e2 -> exprblock.leftp) &&
357 same_expr (e1 -> exprblock.rightp, e2 -> exprblock.rightp);
360 return same_ident (e1, e2);
362 return sameconst(&e1->constblock, &e2->constblock);
370 void out_name (fp, namep)
374 extern int usedefsforcommon;
380 /* DON'T want to use oneof_stg() here; need to find the right common name
383 if (namep->vstg == STGCOMMON && !namep->vcommequiv && !usedefsforcommon) {
384 comm = &extsymtab[namep->vardesc.varno];
385 extern_out(fp, comm);
386 nice_printf(fp, "%d.", comm->curno);
387 } /* if namep -> vstg == STGCOMMON */
389 if (namep->vprocclass == PTHISPROC && namep->vtype != TYSUBR)
390 nice_printf(fp, xretslot[namep->vtype]->user.ident);
392 nice_printf (fp, "%s", namep->cvarname);
396 static char *Longfmt = "%ld";
398 #define cpd(n) cp->vstg ? cp->Const.cds[n] : dtos(cp->Const.cd[n])
400 void out_const(fp, cp)
404 static char real_buf[50], imag_buf[50];
406 int type = cp->vtype;
410 nice_printf (fp, "%ld", cp->Const.ci); /* don't cast ci! */
413 nice_printf (fp, Longfmt, cp->Const.ci); /* don't cast ci! */
416 nice_printf(fp, "%s", flconst(real_buf, cpd(0)));
419 nice_printf(fp, "%s", cpd(0));
422 nice_printf(fp, cm_fmt_string, flconst(real_buf, cpd(0)),
423 flconst(imag_buf, cpd(1)));
426 nice_printf(fp, dcm_fmt_string, cpd(0), cpd(1));
429 nice_printf (fp, "%s", cp->Const.ci ? "TRUE_" : "FALSE_");
432 char *c = cp->Const.ccp, *ce;
435 nice_printf (fp, "\"\"");
439 nice_printf (fp, "\"");
440 ce = c + cp->vleng->constblock.Const.ci;
442 k = *(unsigned char *)c++;
443 nice_printf(fp, str_fmt[k], k);
445 for(k = cp->Const.ccp1.blanks; k > 0; k--)
446 nice_printf(fp, " ");
447 nice_printf (fp, "\"");
451 erri ("out_const: bad type '%d'", (int) type);
459 /* out_addr -- this routine isn't local because it is called by the
460 system-generated identifier printing routines */
462 void out_addr (fp, addrp)
464 struct Addrblock *addrp;
466 extern Extsym *extsymtab;
474 && addrp->vstg == STGARG
475 && addrp->vtype != TYCHAR
476 && ISICON(addrp->memoffset)
477 && !addrp->memoffset->constblock.Const.ci)
478 nice_printf(fp, "*");
480 switch (addrp -> uname_tag) {
482 out_name (fp, addrp -> user.name);
485 if (*(s = addrp->user.ident) == ' ') {
487 nice_printf(fp, "%s",
488 xretslot[addrp->vtype]->user.ident);
490 nice_printf(fp, "%s", s+1);
493 nice_printf(fp, "%s", s);
497 nice_printf(fp, "%s", addrp->user.Charp);
500 extern_out (fp, &extsymtab[addrp -> memno]);
503 switch(addrp->vstg) {
505 out_const(fp, (Constp)addrp);
508 output_literal (fp, (int)addrp->memno,
512 Fatal("unexpected vstg in out_addr");
517 nice_printf (fp, "Unknown Addrp");
521 /* It's okay to just throw in the brackets here because they have a
522 precedence level of 15, the highest value. */
524 if ((addrp->uname_tag == UNAM_NAME && addrp->user.name->vdim
525 || addrp->ntempelt > 1 || addrp->isarray)
526 && addrp->vtype != TYCHAR) {
531 offset = addrp -> memoffset;
532 addrp->memoffset = 0;
533 if (ONEOF(addrp->vstg, M(STGCOMMON)|M(STGEQUIV)) &&
534 addrp -> uname_tag == UNAM_NAME)
535 offset = mkexpr (OPMINUS, offset, mkintcon (
536 addrp -> user.name -> voffset));
538 nice_printf (fp, "[");
540 offset = mkexpr (OPSLASH, offset,
541 ICON (typesize[addrp -> vtype] * (addrp -> Field ? 2 : 1)));
542 expr_out (fp, offset);
543 nice_printf (fp, "]");
546 /* Check for structure field reference */
548 if (addrp -> Field && addrp -> uname_tag != UNAM_CONST &&
549 addrp -> uname_tag != UNAM_UNKNOWN) {
550 if (oneof_stg((addrp -> uname_tag == UNAM_NAME ? addrp -> user.name :
551 (Namep) NULL), addrp -> vstg, M(STGARG)|M(STGEQUIV))
552 && !was_array && (addrp->vclass != CLPROC || !multitype))
553 nice_printf (fp, "->%s", addrp -> Field);
555 nice_printf (fp, ".%s", addrp -> Field);
558 /* Check for character subscripting */
560 if (addrp->vtype == TYCHAR &&
561 (addrp->vclass != CLPROC || addrp->uname_tag == UNAM_NAME
562 && addrp->user.name->vprocclass == PTHISPROC) &&
563 addrp -> memoffset &&
564 (addrp -> uname_tag != UNAM_NAME ||
565 addrp -> user.name -> vtype == TYCHAR) &&
566 (!ISICON (addrp -> memoffset) ||
567 (addrp -> memoffset -> constblock.Const.ci))) {
570 expptr e = addrp -> memoffset;
574 addrp->memoffset = 0;
576 if (ONEOF(addrp->vstg, M(STGCOMMON)|M(STGEQUIV))
577 && addrp -> uname_tag == UNAM_NAME) {
578 e = mkexpr (OPMINUS, e, mkintcon (addrp -> user.name -> voffset));
580 /* mkexpr will simplify it to zero if possible */
581 if (e->tag == TCONST && e->constblock.Const.ci == 0)
583 } /* if addrp -> vstg == STGCOMMON */
585 /* In the worst case, parentheses might be needed OUTSIDE the expression,
586 too. But since I think this subscripting can only appear as a
587 parameter in a procedure call, I don't think outside parens will ever
588 be needed. INSIDE parens are handled below */
590 nice_printf (fp, " + ");
591 if (e -> tag == TEXPR) {
592 int arg_prec = op_precedence (e -> exprblock.opcode);
593 int prec = op_precedence (OPPLUS);
594 use_paren = arg_prec && (arg_prec < prec || (arg_prec == prec &&
595 is_left_assoc (OPPLUS)));
596 } /* if e -> tag == TEXPR */
597 if (use_paren) nice_printf (fp, "(");
599 if (use_paren) nice_printf (fp, ")");
604 static void output_literal (fp, memno, cp)
609 struct Literal *litp, *lastlit;
610 extern char *lit_name ();
612 lastlit = litpool + nliterals;
614 for (litp = litpool; litp < lastlit; litp++) {
615 if (litp -> litnum == memno)
622 nice_printf (fp, "%s", lit_name (litp));
625 } /* output_literal */
628 static void output_prim (fp, primp)
630 struct Primblock *primp;
635 out_name (fp, primp -> namep);
637 output_arg_list (fp, primp -> argsp);
639 if (primp -> fcharp != (expptr) NULL || primp -> lcharp != (expptr) NULL)
640 nice_printf (fp, "Sorry, no substrings yet");
645 static void output_arg_list (fp, listp)
647 struct Listblock *listp;
651 if (listp == (struct Listblock *) NULL || listp -> listp == (chainp) NULL)
654 nice_printf (fp, "(");
656 for (arg_list = listp -> listp; arg_list; arg_list = arg_list -> nextp) {
657 expr_out (fp, (expptr) arg_list -> datap);
658 if (arg_list -> nextp != (chainp) NULL)
660 /* Might want to add a hook in here to accomodate the style setting which
661 wants spaces after commas */
663 nice_printf (fp, ",");
666 nice_printf (fp, ")");
667 } /* output_arg_list */
671 static void output_unary (fp, e)
678 switch (e -> opcode) {
680 if (e->vtype == TYREAL && forcedouble) {
681 e->opcode = OPNEG_KLUDGE;
697 output_binary (fp, e);
701 nice_printf (fp, "Sorry, no OPCALL yet");
704 erri ("output_unary: bad opcode", (int) e -> opcode);
714 register struct Literal *litp, *litpe;
717 for(litpe = litp + nliterals; litp < litpe; litp++)
718 if (litp->litnum == m)
720 Fatal("findconst failure!");
729 /* special handling for ichar and character*1 */
730 register expptr lp = e->leftp;
731 register union Expression *Offset;
733 int lt = lp->headblock.vtype;
738 if (lp->addrblock.vtype == TYCHAR) {
741 nice_printf(fp, "*");
742 out_name(fp, (Namep)lp);
746 cp = lp->constblock.Const.ccp;
748 k = *(unsigned char *)cp;
749 sprintf(buf, chr_fmt[k], k);
750 nice_printf(fp, "'%s'", buf);
753 switch(lp->addrblock.vstg) {
755 cp = findconst(lp->addrblock.memno);
760 lt = lp->addrblock.vtype = tyint;
761 Offset = lp->addrblock.memoffset;
762 if (lp->addrblock.uname_tag == UNAM_NAME) {
763 np = lp->addrblock.user.name;
765 M(STGCOMMON)|M(STGEQUIV)))
766 Offset = mkexpr(OPMINUS, Offset,
769 lp->addrblock.memoffset = Offset ?
770 mkexpr(OPSTAR, Offset,
771 ICON(typesize[tyint]))
773 lp->addrblock.isarray = 1;
774 /* STGCOMMON or STGEQUIV would cause */
775 /* voffset to be added in a second time */
776 lp->addrblock.vstg = STGUNKNOWN;
779 badtag("opconv_fudge", lp->tag);
783 nice_printf(fp, "(%s) ",
784 c_type_decl(e->vtype, 0));
789 static void output_binary (fp, e)
794 extern table_entry opcode_table[];
797 if (e == NULL || e -> tag != TEXPR)
800 /* Instead of writing a huge switch, I've incorporated the output format
801 into a table. Things like "%l" and "%r" stand for the left and
802 right subexpressions. This should allow both prefix and infix
803 functions to be specified (e.g. "(%l * %r", "z_div (%l, %r"). Of
804 course, I should REALLY think out the ramifications of writing out
805 straight text, as opposed to some intermediate format, which could
806 figure out and optimize on the the number of required blanks (we don't
807 want "x - (-y)" to become "x --y", for example). Special cases (such as
808 incomplete implementations) could still be implemented as part of the
809 switch, they will just have some dummy value instead of the string
810 pattern. Another difficulty is the fact that the complex functions
811 will differ from the integer and real ones */
813 /* Handle a special case. We don't want to output "x + - 4", or "y - - 3"
815 if ((e -> opcode == OPPLUS || e -> opcode == OPMINUS) &&
816 e -> rightp && e -> rightp -> tag == TCONST &&
817 isnegative_const (&(e -> rightp -> constblock)) &&
818 is_negatable (&(e -> rightp -> constblock))) {
820 e -> opcode = (e -> opcode == OPPLUS) ? OPMINUS : OPPLUS;
821 negate_const (&(e -> rightp -> constblock));
822 } /* if e -> opcode == PLUS or MINUS */
824 prec = op_precedence (e -> opcode);
825 format = op_format (e -> opcode);
827 if (format != SPECIAL_FMT) {
829 if (*format == '%') {
830 int arg_prec, use_paren = 0;
833 switch (*(format + 1)) {
836 if (lp && lp->tag == TEXPR) {
837 arg_prec = op_precedence(lp->exprblock.opcode);
839 use_paren = arg_prec &&
840 (arg_prec < prec || (arg_prec == prec &&
841 is_right_assoc (prec)));
842 } /* if e -> leftp */
843 if (e->opcode == OPCONV && opconv_fudge(fp,e))
846 nice_printf (fp, "(");
849 nice_printf (fp, ")");
853 if (rp && rp->tag == TEXPR) {
854 arg_prec = op_precedence(rp->exprblock.opcode);
856 use_paren = arg_prec &&
857 (arg_prec < prec || (arg_prec == prec &&
858 is_left_assoc (prec)));
859 use_paren = use_paren ||
860 (rp->exprblock.opcode == OPNEG
861 && prec >= op_precedence(OPMINUS));
862 } /* if e -> rightp */
864 nice_printf (fp, "(");
867 nice_printf (fp, ")");
871 nice_printf (fp, "%%");
874 erri ("output_binary: format err: '%%%c' illegal",
875 (int) *(format + 1));
880 nice_printf (fp, "%c", *format++);
881 } /* while *format */
884 /* Handle Special cases of formatting */
886 switch (e -> opcode) {
889 out_call (fp, (int) e -> opcode, e -> vtype,
890 e -> vleng, e -> leftp, e -> rightp);
895 nice_printf(fp, "(");
896 expr_out(fp, e->leftp);
897 nice_printf(fp, ", &");
899 expr_out(fp, e->rightp);
900 nice_printf(fp, ")");
905 nice_printf (fp, "Sorry, can't format OPCODE '%d'",
911 } /* output_binary */
914 out_call (outfile, op, ftype, len, name, args)
917 expptr len, name, args;
919 chainp arglist; /* Pointer to any actual arguments */
920 chainp cp; /* Iterator over argument lists */
921 Addrp ret_val = (Addrp) NULL;
922 /* Function return value buffer, if any is
924 int byvalue; /* True iff we're calling a C library
926 int done_once; /* Used for writing commas to outfile */
933 extern int forcereal;
935 /* Don't use addresses if we're calling a C function */
937 byvalue = op == OPCCALL;
940 arglist = args -> listblock.listp;
944 /* If this is a CHARACTER function, the first argument is the result */
948 ret_val = (Addrp) (arglist -> datap);
949 arglist = arglist -> nextp;
951 err ("adjustable character function");
955 /* If this is a COMPLEX function, the first argument is the result */
957 else if (ISCOMPLEX (ftype)) {
958 ret_val = (Addrp) (arglist -> datap);
959 arglist = arglist -> nextp;
962 /* Now we can actually start to write out the function invocation */
964 if (ftype == TYREAL && forcereal)
965 nice_printf(outfile, "(real)");
966 if (name -> tag == TEXPR && name -> exprblock.opcode == OPWHATSIN) {
967 nice_printf (outfile, "(");
968 np = (Namep)name->exprblock.leftp; /*expr_out will free name */
969 expr_out (outfile, name);
970 nice_printf (outfile, ")");
974 expr_out(outfile, name);
977 /* prepare to cast procedure parameters -- set A if we know how */
979 A = np->tag == TNAME && (at = np->arginfo) && at->nargs > 0
982 nice_printf(outfile, "(");
985 if (ISCOMPLEX (ftype))
986 nice_printf (outfile, "&");
987 expr_out (outfile, (expptr) ret_val);
989 /* The length of the result of a character function is the second argument */
990 /* It should be in place from putcall(), so we won't touch it explicitly */
993 done_once = ret_val ? TRUE : FALSE;
995 /* Now run through the named arguments */
998 for (cp = arglist; cp; cp = cp -> nextp, done_once = TRUE) {
1001 nice_printf (outfile, ", ");
1004 if (!( q = (expptr)cp->datap) )
1007 if (q->tag == TADDR) {
1008 if (q->addrblock.vtype > TYERROR) {
1010 nice_printf(outfile, "&%s", q->addrblock.user.ident);
1013 if (!byvalue && q->addrblock.isarray
1014 && q->addrblock.vtype != TYCHAR
1015 && q->addrblock.memoffset->tag == TCONST) {
1017 /* check for 0 offset -- after */
1018 /* correcting for equivalence. */
1019 L = q->addrblock.memoffset->constblock.Const.ci;
1020 if (ONEOF(q->addrblock.vstg, M(STGCOMMON)|M(STGEQUIV))
1021 && q->addrblock.uname_tag == UNAM_NAME)
1022 L -= q->addrblock.user.name->voffset;
1027 /* This also prevents &sizeof(doublereal)[0] */
1028 switch(q->addrblock.uname_tag) {
1030 out_name(outfile, q->addrblock.user.name);
1033 nice_printf(outfile, "%s",
1034 q->addrblock.user.ident);
1037 nice_printf(outfile, "%s",
1038 q->addrblock.user.Charp);
1042 &extsymtab[q->addrblock.memno]);
1048 /* Skip over the dereferencing operator generated only for the
1049 intermediate file */
1051 if (q -> tag == TEXPR && q -> exprblock.opcode == OPWHATSIN)
1052 q = q -> exprblock.leftp;
1054 if (q->headblock.vclass == CLPROC
1057 || q->nameblock.vprocclass != PTHISPROC))
1059 if (A && (t = A[narg].type) >= 200)
1062 t = q->headblock.vtype;
1063 if (q->tag == TNAME && q->nameblock.vimpltype)
1066 nice_printf(outfile, "(%s)", usedcasts[t] = casttypes[t]);
1069 if ((q -> tag == TADDR || q-> tag == TNAME) &&
1070 (byvalue || q -> headblock.vstg != STGREG)) {
1071 if (q -> headblock.vtype != TYCHAR)
1074 if (q -> tag == TADDR &&
1075 q -> addrblock.uname_tag == UNAM_NAME &&
1076 ! q -> addrblock.user.name -> vdim &&
1077 oneof_stg(q -> addrblock.user.name, q -> addrblock.vstg,
1078 M(STGARG)|M(STGEQUIV)) &&
1079 ! ISCOMPLEX(q->addrblock.user.name->vtype))
1080 nice_printf (outfile, "*");
1081 else if (q -> tag == TNAME
1082 && oneof_stg(&q->nameblock, q -> nameblock.vstg,
1083 M(STGARG)|M(STGEQUIV))
1084 && !(q -> nameblock.vdim))
1085 nice_printf (outfile, "*");
1090 if (q->tag == TADDR &&
1091 !ONEOF (q -> addrblock.vstg, M(STGEXT)|M(STGLENG))
1093 ONEOF(q->addrblock.vstg,
1094 M(STGCOMMON)|M(STGEQUIV)|M(STGMEMNO))
1095 || ((memoffset = q->addrblock.memoffset)
1096 && (!ISICON(memoffset)
1097 || memoffset->constblock.Const.ci)))
1098 || ONEOF(q->addrblock.vstg,
1099 M(STGINIT)|M(STGAUTO)|M(STGBSS))
1100 && !q->addrblock.isarray)
1101 nice_printf (outfile, "&");
1102 else if (q -> tag == TNAME
1103 && !oneof_stg(&q->nameblock, q -> nameblock.vstg,
1104 M(STGARG)|M(STGEXT)|M(STGEQUIV)))
1105 nice_printf (outfile, "&");
1108 expr_out (outfile, q);
1109 } /* if q -> tag == TADDR || q -> tag == TNAME */
1111 /* Might be a Constant expression, e.g. string length, character constants */
1113 else if (q -> tag == TCONST) {
1114 if (tyioint == TYLONG)
1116 out_const(outfile, &q->constblock);
1120 /* Must be some other kind of expression, or register var, or constant.
1121 In particular, this is likely to be a temporary variable assignment
1122 which was generated in p1put_call */
1124 else if (!ISCOMPLEX (q -> headblock.vtype) && !ISCHAR (q)){
1125 int use_paren = q -> tag == TEXPR &&
1126 op_precedence (q -> exprblock.opcode) <=
1127 op_precedence (OPCOMMA);
1129 if (use_paren) nice_printf (outfile, "(");
1130 expr_out (outfile, q);
1131 if (use_paren) nice_printf (outfile, ")");
1132 } /* if !ISCOMPLEX */
1134 err ("out_call: unknown parameter");
1136 } /* for (cp = arglist */
1141 nice_printf (outfile, ")");
1150 sprintf(buf, fl_fmt_string, x);
1158 static char buf[64];
1159 sprintf(buf, db_fmt_string, x);
1163 char tr_tab[Table_size];
1165 /* out_init -- Initialize the data structures used by the routines in
1166 output.c. These structures include the output format to be used for
1167 Float, Double, Complex, and Double Complex constants. */
1171 extern int tab_size;
1174 s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+-.";
1179 opeqable[OPPLUS] = 1;
1180 opeqable[OPMINUS] = 1;
1181 opeqable[OPSTAR] = 1;
1182 opeqable[OPSLASH] = 1;
1183 opeqable[OPMOD] = 1;
1184 opeqable[OPLSHIFT] = 1;
1185 opeqable[OPBITAND] = 1;
1186 opeqable[OPBITXOR] = 1;
1187 opeqable[OPBITOR ] = 1;
1190 /* Set the output format for both types of floating point constants */
1192 if (fl_fmt_string == NULL || *fl_fmt_string == '\0')
1193 fl_fmt_string = Ansi == 1 ? "%sf" : "(float)%s";
1195 if (db_fmt_string == NULL || *db_fmt_string == '\0')
1196 db_fmt_string = "%.17g";
1198 /* Set the output format for both types of complex constants. They will
1199 have string parameters rather than float or double so that the decimal
1200 point may be added to the strings generated by the {db,fl}_fmt_string
1203 if (cm_fmt_string == NULL || *cm_fmt_string == '\0') {
1204 cm_fmt_string = "{%s,%s}";
1205 } /* if cm_fmt_string == NULL */
1207 if (dcm_fmt_string == NULL || *dcm_fmt_string == '\0') {
1208 dcm_fmt_string = "{%s,%s}";
1209 } /* if dcm_fmt_string == NULL */
1215 void extern_out (fp, extsym)
1219 if (extsym == (Extsym *) NULL)
1222 nice_printf (fp, "%s", extsym->cextname);
1228 static void output_list (fp, listp)
1230 struct Listblock *listp;
1235 nice_printf (fp, "(");
1237 for (elts = listp -> listp; elts; elts = elts -> nextp) {
1238 if (elts -> datap) {
1240 nice_printf (fp, ", ");
1241 expr_out (fp, (expptr) elts -> datap);
1243 } /* if elts -> datap */
1245 nice_printf (fp, ")");
1249 void out_asgoto (outfile, expr)
1258 if (expr == (expptr) NULL) {
1259 err ("out_asgoto: NULL variable expr");
1263 nice_printf (outfile, Ansi ? "switch (" : "switch ((int)"); /*)*/
1264 expr_out (outfile, expr);
1265 nice_printf (outfile, ") {\n");
1268 /* The initial addrp value will be stored as a namep pointer */
1272 /* local variable */
1273 namep = &expr->nameblock;
1276 if (expr->exprblock.opcode == OPWHATSIN
1277 && expr->exprblock.leftp->tag == TNAME)
1279 namep = &expr->exprblock.leftp->nameblock;
1284 if (expr->addrblock.uname_tag == UNAM_NAME) {
1285 /* initialized local variable */
1286 namep = expr->addrblock.user.name;
1291 err("out_asgoto: bad expr");
1295 for(k = 0, value = namep -> varxptr.assigned_values; value;
1296 value = value->nextp, k++) {
1297 nice_printf (outfile, "case %d: goto %s;\n", k,
1298 user_label((long)value->datap));
1302 nice_printf (outfile, "}\n");
1305 void out_if (outfile, expr)
1309 nice_printf (outfile, "if (");
1310 expr_out (outfile, expr);
1311 nice_printf (outfile, ") {\n");
1316 output_rbrace(outfile, s)
1320 extern int last_was_label;
1323 if (last_was_label) {
1329 nice_printf(outfile, fmt, s);
1332 void out_else (outfile)
1336 output_rbrace(outfile, "} else {\n");
1340 void elif_out (outfile, expr)
1345 output_rbrace(outfile, "} else ");
1346 out_if (outfile, expr);
1349 void endif_out (outfile)
1353 output_rbrace(outfile, "}\n");
1356 void end_else_out (outfile)
1360 output_rbrace(outfile, "}\n");
1361 } /* end_else_out */
1365 void compgoto_out (outfile, index, labels)
1367 expptr index, labels;
1372 err ("compgoto_out: null index for computed goto");
1373 else if (labels && labels -> tag != TLIST)
1374 erri ("compgoto_out: expected label list, got tag '%d'",
1377 extern char *user_label ();
1381 s2 = /*(*/ ") {\n"; /*}*/
1383 s1 = "switch ("; /*)*/
1384 else if (index->tag == TNAME || index->tag == TEXPR
1385 && index->exprblock.opcode == OPWHATSIN)
1386 s1 = "switch ((int)"; /*)*/
1388 s1 = "switch ((int)(";
1389 s2 = ")) {\n"; /*}*/
1391 nice_printf(outfile, s1);
1392 expr_out (outfile, index);
1393 nice_printf (outfile, s2);
1396 for (elts = labels -> listblock.listp; elts; elts = elts -> nextp, i++) {
1397 if (elts -> datap) {
1398 if (ISICON(((expptr) (elts -> datap))))
1399 nice_printf (outfile, "case %d: goto %s;\n", i,
1400 user_label(((expptr)(elts->datap))->constblock.Const.ci));
1402 err ("compgoto_out: bad label in label list");
1403 } /* if (elts -> datap) */
1406 nice_printf (outfile, /*{*/ "}\n");
1408 } /* compgoto_out */
1411 void out_for (outfile, init, test, inc)
1413 expptr init, test, inc;
1415 nice_printf (outfile, "for (");
1416 expr_out (outfile, init);
1417 nice_printf (outfile, "; ");
1418 expr_out (outfile, test);
1419 nice_printf (outfile, "; ");
1420 expr_out (outfile, inc);
1421 nice_printf (outfile, ") {\n");
1426 void out_end_for (outfile)
1430 nice_printf (outfile, "}\n");