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
);
54 TAO_NL_2::TAO_NL_2 (void)
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 (void)
83 for (unsigned long i
= 0; i
< be_global
->tab_size (); ++i
)
85 this->tab_unit_str_
+= ' ';
89 TAO_OutStream::~TAO_OutStream (void)
91 // Close the underlying I/O handle only if it exists.
94 ACE_OS::fclose (this->fp_
);
102 TAO_OutStream::open (const char *fname
,
103 TAO_OutStream::STREAM_TYPE st
)
107 // File name exists, open an I/O file handle.
108 this->fp_
= ACE_OS::fopen (fname
, "w");
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 (void)
148 // Return the underlying lowlevel file pointer.
151 TAO_OutStream::file (void)
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 (void)
197 this->indent_level_
= 0;
203 TAO_OutStream::indent (void)
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 ());
219 TAO_OutStream::nl (void)
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
));
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 (void)
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_
,
316 TAO_OutStream::operator<< (const char *str
)
318 ACE_OS::fprintf (this->fp_
, "%s", str
);
323 TAO_OutStream::operator<< (char ch
)
325 ACE_OS::fprintf (this->fp_
, "%c", ch
);
330 TAO_OutStream::operator<< (const ACE_CString
&str
)
332 ACE_OS::fprintf (this->fp_
, "%s", str
.c_str ());
337 TAO_OutStream::operator<< (const ACE_CDR::UShort num
)
339 ACE_OS::fprintf (this->fp_
,
347 TAO_OutStream::operator<< (const ACE_CDR::Short num
)
349 ACE_OS::fprintf (this->fp_
,
357 TAO_OutStream::operator<< (const ACE_CDR::ULong num
)
359 ACE_OS::fprintf (this->fp_
,
361 (unsigned long) num
);
367 TAO_OutStream::operator<< (const ACE_CDR::Long num
)
369 ACE_OS::fprintf (this->fp_
,
377 TAO_OutStream::operator<< (const ACE_CDR::ULongLong num
)
379 ACE_OS::fprintf (this->fp_
,
380 ACE_UINT64_FORMAT_SPECIFIER_ASCII
,
387 TAO_OutStream::operator<< (const ACE_CDR::LongLong num
)
389 ACE_OS::fprintf (this->fp_
,
390 ACE_INT64_FORMAT_SPECIFIER_ASCII
,
397 TAO_OutStream::operator<< (const TAO_NL
&)
399 ACE_OS::fprintf (this->fp_
,
407 TAO_OutStream::operator<< (const TAO_NL_2
&)
409 ACE_OS::fprintf (this->fp_
,
411 ACE_OS::fprintf (this->fp_
,
418 TAO_OutStream::operator<< (const TAO_INDENT
& i
)
420 this->incr_indent (0);
431 TAO_OutStream::operator<< (const TAO_UNINDENT
& i
)
433 this->decr_indent (0);
444 TAO_OutStream::operator<< (Identifier
*id
)
446 return this->print (id
);
450 TAO_OutStream::operator<< (UTL_IdList
*id
)
452 return this->print (id
);
456 TAO_OutStream::operator<< (AST_Expression
*expr
)
458 return this->print (expr
);
462 TAO_OutStream::print (Identifier
*id
)
464 ACE_OS::fprintf (this->fp_
, "%s", id
->get_string ());
470 TAO_OutStream::print (UTL_IdList
*idl
)
476 for (UTL_IdListActiveIterator
i (idl
); !i
.is_done (); i
.next ())
484 first
= second
= false;
487 // Print the identifier.
493 if (ACE_OS::strcmp (id
->get_string (), "") != 0
494 && ACE_OS::strcmp (id
->get_string (), "::") != 0)
496 // Does not start with a "".
509 template <typename IntType
>
511 signed_int_helper (TAO_OutStream
&os
, IntType value
, IntType min
, const char *specifier
)
514 * It seems that in C/C++ the minus sign and the bare number are parsed
515 * separately for negative integer literals. This can cause compilers
516 * to complain when using the minimum value of a signed integer because
517 * the number without the minus sign is 1 past the max signed value.
519 * https://stackoverflow.com/questions/65007935
521 * Apparently the workaround is to write it as `VALUE_PLUS_ONE - 1`.
523 const bool min_value
= value
== min
;
524 if (min_value
) ++value
;
525 os
.print (specifier
, value
);
526 if (min_value
) os
.print (" - 1");
530 TAO_OutStream::print (AST_Expression
*expr
)
532 AST_Expression::AST_ExprValue
*ev
= expr
->ev ();
534 /// Never happens as far as I know, but just in case...
537 ACE_ERROR ((LM_ERROR
,
538 ACE_TEXT ("TAO_OutStream::print() - ")
539 ACE_TEXT ("expression not evaluated\n")));
546 case AST_Expression::EV_short
:
547 this->TAO_OutStream::print (ACE_INT32_FORMAT_SPECIFIER_ASCII
, ev
->u
.sval
);
549 case AST_Expression::EV_ushort
:
550 this->TAO_OutStream::print (ACE_INT32_FORMAT_SPECIFIER_ASCII
"%c", ev
->u
.usval
, 'U');
552 case AST_Expression::EV_long
:
553 signed_int_helper
<ACE_CDR::Long
> (
554 *this, ev
->u
.lval
, ACE_INT32_MIN
, ACE_INT32_FORMAT_SPECIFIER_ASCII
);
556 case AST_Expression::EV_ulong
:
557 this->TAO_OutStream::print (ACE_UINT32_FORMAT_SPECIFIER_ASCII
"%c", ev
->u
.ulval
, 'U');
559 case AST_Expression::EV_longlong
:
560 this->TAO_OutStream::print ("ACE_INT64_LITERAL (");
561 signed_int_helper
<ACE_CDR::LongLong
> (
562 *this, ev
->u
.llval
, ACE_INT64_MIN
, ACE_INT64_FORMAT_SPECIFIER_ASCII
);
563 this->TAO_OutStream::print (")");
565 case AST_Expression::EV_ulonglong
:
566 this->TAO_OutStream::print ("ACE_UINT64_LITERAL (");
567 this->TAO_OutStream::print (ACE_UINT64_FORMAT_SPECIFIER_ASCII
,
569 this->TAO_OutStream::print (")");
571 case AST_Expression::EV_float
:
572 this->TAO_OutStream::print ("%f%c", ev
->u
.fval
, 'F');
574 case AST_Expression::EV_double
:
575 this->TAO_OutStream::print ("%24.16G", ev
->u
.dval
);
577 case AST_Expression::EV_longdouble
:
579 case AST_Expression::EV_char
:
580 // isprint() sees \ and ' as printable characters
581 // so we have to test for them first.
582 if (ev
->u
.cval
== '\\')
583 this->TAO_OutStream::print ("'\\\\'");
584 else if (ev
->u
.cval
== '\'')
585 this->TAO_OutStream::print ("'\\''");
587 // This handles hex and octal escape sequences
588 // that would print out as weird characters.
589 else if (ACE_OS::ace_isprint (ev
->u
.cval
))
590 this->TAO_OutStream::print ("'%c'", ev
->u
.cval
);
591 else if (ACE_OS::ace_iscntrl (ev
->u
.cval
))
595 this->TAO_OutStream::print ("'\\n'");
598 this->TAO_OutStream::print ("'\\t'");
601 this->TAO_OutStream::print ("'\\r'");
604 this->TAO_OutStream::print ("'\\v'");
607 this->TAO_OutStream::print ("'\\f'");
610 this->TAO_OutStream::print ("'\\b'");
613 this->TAO_OutStream::print ("'\\a'");
616 this->TAO_OutStream::print ("'?'");
619 this->TAO_OutStream::print ("'\\x%x'", ev
->u
.oval
);
622 this->TAO_OutStream::print ("'\\x%x'", ev
->u
.oval
);
624 case AST_Expression::EV_wchar
:
625 this->TAO_OutStream::print ("L'%lc'", ev
->u
.wcval
);
627 case AST_Expression::EV_octet
:
628 this->TAO_OutStream::print ("0x%02x", ev
->u
.oval
);
630 case AST_Expression::EV_bool
:
631 this->TAO_OutStream::print ("%s", ev
->u
.bval
? "true" : "false");
633 case AST_Expression::EV_string
:
634 this->TAO_OutStream::print ("\"%s\"", ev
->u
.strval
->get_string ());
636 case AST_Expression::EV_wstring
:
637 this->TAO_OutStream::print ("L\"%s\"", ev
->u
.wstrval
);
639 case AST_Expression::EV_enum
:
640 this->print (expr
->n ());
642 case AST_Expression::EV_int8
:
643 this->TAO_OutStream::print ("%d", ev
->u
.int8val
);
645 case AST_Expression::EV_uint8
:
646 this->TAO_OutStream::print ("%uu", ev
->u
.uint8val
);
655 void TAO_OutStream::insert_comment (const char *file
, int line
)
657 *this << be_nl
<< "// TAO_IDL - Generated from" << be_nl
658 << "// " << file
<< ':' << static_cast<ACE_CDR::ULong
> (line
)