2 //=============================================================================
6 * Provides helper classes to print generated code to the output
8 * @author Aniruddha Gokhale Improvements by Carlos O'Ryan
10 //=============================================================================
12 #include "be_helper.h"
13 #include "be_codegen.h"
14 #include "be_extern.h"
15 #include "ast_expression.h"
16 #include "idl_defines.h"
17 #include "utl_identifier.h"
18 #include "utl_idlist.h"
19 #include "utl_string.h"
20 #include "ace/OS_NS_string.h"
21 #include "ace/OS_NS_ctype.h"
22 #include "../../tao/Version.h"
24 static const char copyright
[] =
27 " * Code generated by the The ACE ORB (TAO) IDL Compiler v" TAO_VERSION
"\n"
28 " * TAO and the TAO IDL Compiler have been developed by:\n"
29 " * Center for Distributed Object Computing\n"
30 " * Washington University\n"
34 " * Distributed Object Computing Laboratory\n"
35 " * University of California at Irvine\n"
39 " * Institute for Software Integrated Systems\n"
40 " * Vanderbilt University\n"
43 " * https://www.isis.vanderbilt.edu/\n"
45 " * Information about TAO is available at:\n"
46 " * https://www.dre.vanderbilt.edu/~schmidt/TAO.html\n"
51 ACE_UNUSED_ARG (copyright
);
56 ACE_UNUSED_ARG (copyright
);
59 TAO_INDENT::TAO_INDENT (int do_now
)
64 TAO_UNINDENT::TAO_UNINDENT (int do_now
)
70 const TAO_NL_2 be_nl_2
;
71 const TAO_INDENT be_idt
;
72 const TAO_INDENT
be_idt_nl (1);
73 const TAO_UNINDENT be_uidt
;
74 const TAO_UNINDENT
be_uidt_nl (1);
76 // Methods of the TAO_OutStream class.
78 TAO_OutStream::TAO_OutStream ()
83 for (unsigned long i
= 0; i
< be_global
->tab_size (); ++i
)
85 this->tab_unit_str_
+= ' ';
89 TAO_OutStream::~TAO_OutStream ()
91 // Close the underlying I/O handle only if it exists.
92 if (this->fp_
!= nullptr)
94 ACE_OS::fclose (this->fp_
);
102 TAO_OutStream::open (const char *fname
,
103 TAO_OutStream::STREAM_TYPE st
)
105 if (fname
!= nullptr)
107 // File name exists, open an I/O file handle.
108 this->fp_
= ACE_OS::fopen (fname
, "w");
110 if (this->fp_
!= nullptr)
113 // Put the copyright notice. Not for the gperf's temp input
115 if (st
!= TAO_OutStream::TAO_GPERF_INPUT
)
117 ACE_OS::fprintf (this->fp_
,
135 // Set and get the stream type.
137 TAO_OutStream::stream_type (TAO_OutStream::STREAM_TYPE st
)
142 TAO_OutStream::STREAM_TYPE
143 TAO_OutStream::stream_type ()
148 // Return the underlying lowlevel file pointer.
151 TAO_OutStream::file ()
157 TAO_OutStream::incr_indent (unsigned short flag
)
163 return this->indent ();
167 // Do not indent output.
174 TAO_OutStream::decr_indent (unsigned short flag
)
176 --this->indent_level_
;
177 // Just in case somebody gets "unindent happy".
178 if (this->indent_level_
< 0)
180 // ACE_DEBUG ((LM_DEBUG, "negative indentation?\n"));
181 this->indent_level_
= 0;
185 return this->indent ();
189 // Do not indent output.
195 TAO_OutStream::reset ()
197 this->indent_level_
= 0;
203 TAO_OutStream::indent ()
205 // Based on the current indentation level, leave appropriate number of blank
206 // spaces in the output.
207 if (this->indent_level_
> 0)
209 for (int i
= 0; i
< this->indent_level_
; i
++)
211 ACE_OS::fprintf (this->fp_
, "%s", this->tab_unit_str_
.c_str ());
221 ACE_OS::fprintf (this->fp_
, "\n");
228 TAO_OutStream::gen_ifdef_macro (const char *flat_name
,
230 bool add_stream_type_suffix
)
232 static char macro
[NAMEBUFSIZE
];
234 ACE_OS::memset (macro
,
238 ACE_OS::sprintf (macro
,
240 tao_cg
->upcase (flat_name
));
242 if (suffix
!= nullptr)
244 ACE_OS::strcat (macro
, "_");
245 ACE_OS::strcat (macro
, tao_cg
->upcase (suffix
));
246 ACE_OS::strcat (macro
, "_");
249 // Append a suffix representing the stream type.
250 if (add_stream_type_suffix
)
254 case TAO_OutStream::TAO_CLI_HDR
:
255 ACE_OS::strcat (macro
, "CH_");
257 case TAO_OutStream::TAO_CLI_INL
:
258 ACE_OS::strcat (macro
, "CI_");
260 case TAO_OutStream::TAO_CLI_IMPL
:
261 ACE_OS::strcat (macro
, "CS_");
263 case TAO_OutStream::TAO_SVR_HDR
:
264 ACE_OS::strcat (macro
, "SH_");
266 case TAO_OutStream::TAO_IMPL_HDR
:
267 ACE_OS::strcat (macro
, "IH_");
269 case TAO_OutStream::TAO_IMPL_SKEL
:
270 ACE_OS::strcat (macro
, "IS_");
272 case TAO_OutStream::TAO_SVR_INL
:
273 ACE_OS::strcat (macro
, "SI_");
275 case TAO_OutStream::TAO_SVR_IMPL
:
276 ACE_OS::strcat (macro
, "SS_");
283 *this << "\n\n#if !defined (" << macro
<< ")\n";
284 *this << "#define " << macro
;
290 TAO_OutStream::gen_endif ()
292 *this << "\n\n#endif /* end #if !defined */";
297 // Printf style variable argument print.
299 TAO_OutStream::print (const char *format
, ...)
303 va_start (ap
, format
);
304 ACE_OSCALL (::vfprintf (this->fp_
,
315 TAO_OutStream::operator<< (const char *str
)
317 ACE_OS::fprintf (this->fp_
, "%s", str
);
322 TAO_OutStream::operator<< (char ch
)
324 ACE_OS::fprintf (this->fp_
, "%c", ch
);
329 TAO_OutStream::operator<< (const ACE_CString
&str
)
331 ACE_OS::fprintf (this->fp_
, "%s", str
.c_str ());
336 TAO_OutStream::operator<< (const ACE_CDR::UShort num
)
338 ACE_OS::fprintf (this->fp_
,
346 TAO_OutStream::operator<< (const ACE_CDR::Short num
)
348 ACE_OS::fprintf (this->fp_
,
356 TAO_OutStream::operator<< (const ACE_CDR::ULong num
)
358 ACE_OS::fprintf (this->fp_
,
360 (unsigned long) num
);
366 TAO_OutStream::operator<< (const ACE_CDR::Long num
)
368 ACE_OS::fprintf (this->fp_
,
376 TAO_OutStream::operator<< (const ACE_CDR::ULongLong num
)
378 ACE_OS::fprintf (this->fp_
,
379 ACE_UINT64_FORMAT_SPECIFIER_ASCII
,
386 TAO_OutStream::operator<< (const ACE_CDR::LongLong num
)
388 ACE_OS::fprintf (this->fp_
,
389 ACE_INT64_FORMAT_SPECIFIER_ASCII
,
396 TAO_OutStream::operator<< (const TAO_NL
&)
398 ACE_OS::fprintf (this->fp_
,
406 TAO_OutStream::operator<< (const TAO_NL_2
&)
408 ACE_OS::fprintf (this->fp_
,
410 ACE_OS::fprintf (this->fp_
,
417 TAO_OutStream::operator<< (const TAO_INDENT
& i
)
419 this->incr_indent (0);
430 TAO_OutStream::operator<< (const TAO_UNINDENT
& i
)
432 this->decr_indent (0);
443 TAO_OutStream::operator<< (Identifier
*id
)
445 return this->print (id
);
449 TAO_OutStream::operator<< (UTL_IdList
*id
)
451 return this->print (id
);
455 TAO_OutStream::operator<< (AST_Expression
*expr
)
457 return this->print (expr
);
461 TAO_OutStream::print (Identifier
*id
)
463 ACE_OS::fprintf (this->fp_
, "%s", id
->get_string ());
469 TAO_OutStream::print (UTL_IdList
*idl
)
473 Identifier
*id
= nullptr;
475 for (UTL_IdListActiveIterator
i (idl
); !i
.is_done (); i
.next ())
483 first
= second
= false;
486 // Print the identifier.
492 if (ACE_OS::strcmp (id
->get_string (), "") != 0
493 && ACE_OS::strcmp (id
->get_string (), "::") != 0)
495 // Does not start with a "".
508 template <typename IntType
>
510 signed_int_helper (TAO_OutStream
&os
, IntType value
, IntType min
, const char *specifier
)
513 * It seems that in C/C++ the minus sign and the bare number are parsed
514 * separately for negative integer literals. This can cause compilers
515 * to complain when using the minimum value of a signed integer because
516 * the number without the minus sign is 1 past the max signed value.
518 * https://stackoverflow.com/questions/65007935
520 * Apparently the workaround is to write it as `VALUE_PLUS_ONE - 1`.
522 const bool min_value
= value
== min
;
523 if (min_value
) ++value
;
524 os
.print (specifier
, value
);
525 if (min_value
) os
.print (" - 1");
529 TAO_OutStream::print (AST_Expression
*expr
)
531 AST_Expression::AST_ExprValue
*ev
= expr
->ev ();
533 /// Never happens as far as I know, but just in case...
536 ACE_ERROR ((LM_ERROR
,
537 ACE_TEXT ("TAO_OutStream::print() - ")
538 ACE_TEXT ("expression not evaluated\n")));
545 case AST_Expression::EV_short
:
546 this->TAO_OutStream::print (ACE_INT32_FORMAT_SPECIFIER_ASCII
, ev
->u
.sval
);
548 case AST_Expression::EV_ushort
:
549 this->TAO_OutStream::print (ACE_INT32_FORMAT_SPECIFIER_ASCII
"%c", ev
->u
.usval
, 'U');
551 case AST_Expression::EV_long
:
552 signed_int_helper
<ACE_CDR::Long
> (
553 *this, ev
->u
.lval
, ACE_INT32_MIN
, ACE_INT32_FORMAT_SPECIFIER_ASCII
);
555 case AST_Expression::EV_ulong
:
556 this->TAO_OutStream::print (ACE_UINT32_FORMAT_SPECIFIER_ASCII
"%c", ev
->u
.ulval
, 'U');
558 case AST_Expression::EV_longlong
:
559 this->TAO_OutStream::print ("ACE_INT64_LITERAL (");
560 signed_int_helper
<ACE_CDR::LongLong
> (
561 *this, ev
->u
.llval
, ACE_INT64_MIN
, ACE_INT64_FORMAT_SPECIFIER_ASCII
);
562 this->TAO_OutStream::print (")");
564 case AST_Expression::EV_ulonglong
:
565 this->TAO_OutStream::print ("ACE_UINT64_LITERAL (");
566 this->TAO_OutStream::print (ACE_UINT64_FORMAT_SPECIFIER_ASCII
,
568 this->TAO_OutStream::print (")");
570 case AST_Expression::EV_float
:
571 this->TAO_OutStream::print ("%f%c", ev
->u
.fval
, 'F');
573 case AST_Expression::EV_double
:
574 this->TAO_OutStream::print ("%24.16G", ev
->u
.dval
);
576 case AST_Expression::EV_longdouble
:
578 case AST_Expression::EV_char
:
579 // isprint() sees \ and ' as printable characters
580 // so we have to test for them first.
581 if (ev
->u
.cval
== '\\')
582 this->TAO_OutStream::print ("'\\\\'");
583 else if (ev
->u
.cval
== '\'')
584 this->TAO_OutStream::print ("'\\''");
586 // This handles hex and octal escape sequences
587 // that would print out as weird characters.
588 else if (ACE_OS::ace_isprint (ev
->u
.cval
))
589 this->TAO_OutStream::print ("'%c'", ev
->u
.cval
);
590 else if (ACE_OS::ace_iscntrl (ev
->u
.cval
))
594 this->TAO_OutStream::print ("'\\n'");
597 this->TAO_OutStream::print ("'\\t'");
600 this->TAO_OutStream::print ("'\\r'");
603 this->TAO_OutStream::print ("'\\v'");
606 this->TAO_OutStream::print ("'\\f'");
609 this->TAO_OutStream::print ("'\\b'");
612 this->TAO_OutStream::print ("'\\a'");
615 this->TAO_OutStream::print ("'?'");
618 this->TAO_OutStream::print ("'\\x%x'", ev
->u
.oval
);
621 this->TAO_OutStream::print ("'\\x%x'", ev
->u
.oval
);
623 case AST_Expression::EV_wchar
:
624 this->TAO_OutStream::print ("L'%lc'", ev
->u
.wcval
);
626 case AST_Expression::EV_octet
:
627 this->TAO_OutStream::print ("0x%02x", ev
->u
.oval
);
629 case AST_Expression::EV_bool
:
630 this->TAO_OutStream::print ("%s", ev
->u
.bval
? "true" : "false");
632 case AST_Expression::EV_string
:
633 this->TAO_OutStream::print ("\"%s\"", ev
->u
.strval
->get_string ());
635 case AST_Expression::EV_wstring
:
636 this->TAO_OutStream::print ("L\"%s\"", ev
->u
.wstrval
);
638 case AST_Expression::EV_enum
:
639 this->print (expr
->n ());
641 case AST_Expression::EV_int8
:
642 this->TAO_OutStream::print ("%d", ev
->u
.int8val
);
644 case AST_Expression::EV_uint8
:
645 this->TAO_OutStream::print ("%uu", ev
->u
.uint8val
);
654 void TAO_OutStream::insert_comment (const char *file
, int line
)
656 *this << be_nl
<< "// TAO_IDL - Generated from" << be_nl
657 << "// " << file
<< ':' << static_cast<ACE_CDR::ULong
> (line
)