Changed IDL translator to fix multiple message definitions.
[charm.git] / src / xlat-idl / be_produce.cc
1 // BE_produce.cc - Produce the work of the BE - does nothing in the
2 //                 dummy BE
3
4 #include        "idl.hh"
5 #include        "idl_extern.hh"
6 #include        "be.hh"
7
8 //----------------------------------------------------------------------
9 // TO DO
10
11 // test single class generation - DONE
12 // implement multi-class generation - DONE
13 // debug multi-file hello type program
14 // test multiple classes in a file - DONE
15 // primitive types: char, [unsigned] short, [unsigned] long, float, double- DONE
16 // struct's - DONE
17 // nested types - DONE for structs, etc.
18 // simple arrays - design done, code it. - DONE
19 // parameter passing: in, out, inout - design done, code it. - DONE
20 //   use futures to get back a value - DONE
21 // constructors - DONE
22 // can a constructor have inout parameters ? NO.  Why not ?
23 // Do we need to inherit ?  class myClass1 /*: public chare_object*/ {
24 // no, since user uses only stub, never the class.
25 // threaded keyword - DONE
26 // Actually, the word is just ignored; the user has to create a .ci
27 // file with the threaded stuff.
28
29 // intermixing itc++ and idl++ example
30
31 // const's - DONE
32 // enums - DONE, bug: spews twice, why ?
33
34 // return values
35 // cleanup M_Empty
36 // cleanup unnecessary params in return messages
37
38 // which items are used by the IDL, which items belong to the class
39 // being declared ?
40
41 // sequences: varsize arrays
42 // VARSIZE myClass1->myMethod1SETSIZE(-, 100, -)->myMethod1(a, b[], c)
43 // BOC's
44 // scoping
45 // structs within interfaces ?
46 // any - requires RTTI, right ?
47 // inheritance
48 // exceptions
49 // do away with user writing .ci file, idl need to understand message,
50 //   threaded.
51
52 //----------------------------------------------------------------------
53 #include <fstream.h>
54 #include <stdio.h>
55 #include <libgen.h>
56 #include <stdlib.h>
57
58 #include "idlString.hh"
59
60 const int MAX_STR_LEN = 10000;
61
62 #include<assert.h>
63
64 // Assumes s can grow to MAX_STR_LEN long.
65 // Basically, a safe form of strcat().
66 static void
67 string_append(char *const s, const char *const a)
68 {
69   assert( strlen(s) + strlen(a) < MAX_STR_LEN );
70   int i=0, j=0;
71   for(i = strlen(s), j=0; a[j]!='\0'; i++, j++)
72     s[i] = a[j];
73   s[i] = '\0';
74 }
75
76 static void
77 DebugPrint(char *s)
78 {
79   cerr << s << endl;
80 }
81
82 //----------------------------------------------------------------------
83 // Replace \1 by a1, \2 by a2, etc. in string b.  Sends output to
84 // outStream.
85 static void
86 spew(ostream& outStream, const char*b,
87      char *a1 = "ERROR", char *a2 = "ERROR",
88      char *a3 = "ERROR", char *a4 = "ERROR", char *a5 = "ERROR")
89 {
90   int i;
91   for(i=0; i<strlen(b); i++){
92     switch(b[i]){
93     case '\01':
94       outStream << a1;
95       break;
96     case '\02':
97       outStream << a2;
98       break;
99     case '\03':
100       outStream << a3;
101       break;
102     case '\04':
103       outStream << a4;
104       break;
105     case '\05':
106       outStream << a5;
107       break;
108     default:
109       outStream << b[i];
110     }
111   }
112 }
113
114 // Replace \1 by a1, \2 by a2, etc. in string b, and appends the
115 // result to outString.  Assumes outString is MAX_STR_LEN long.
116 static void
117 spew(char outString[], const char*b,
118      char *a1 = "ERROR", char *a2 = "ERROR",
119      char *a3 = "ERROR", char *a4 = "ERROR", char *a5 = "ERROR")
120 {
121   int eosi = strlen(outString); // one past end of string index
122   int i;
123   for(i=0; i<strlen(b); i++){
124     assert(eosi < MAX_STR_LEN-1);
125     switch(b[i]){
126     case '\01':
127       outString[eosi] = '\0';
128       string_append(outString, a1);
129       eosi += strlen(a1);
130       break;
131     case '\02':
132       outString[eosi] = '\0';
133       string_append(outString, a2);
134       eosi += strlen(a2);
135       break;
136     case '\03':
137       outString[eosi] = '\0';
138       string_append(outString, a3);
139       eosi += strlen(a3);
140       break;
141     case '\04':
142       outString[eosi] = '\0';
143       string_append(outString, a4);
144       eosi += strlen(a4);
145       break;
146     case '\05':
147       outString[eosi] = '\0';
148       string_append(outString, a5);
149       eosi += strlen(a5);
150       break;
151     default:
152       outString[eosi++] = b[i];
153     }
154   }
155 }
156
157 //----------------------------------------------------------------------
158 // Given "path/file.ext" we return "file".
159 // @@ Given "path/file.b.ext" we return "file.b".
160 // Caller must delete the returned string.
161 char *
162 get_basename_noextension(char *pathname)
163 {
164         char c = '/';
165         int i = 0;
166
167         for(i=strlen(pathname)-1; i>=0; i--)
168           if (pathname[i] == c)
169             break;
170         assert(i != 0);
171
172         i++;
173         char *basenm = new char[strlen(pathname) - i];
174
175         int j;
176         for(j=0; pathname[i]; i++, j++)
177           if (pathname[i] != '.')
178             basenm[j] = pathname[i];
179           else {
180             basenm[j] = '\0';
181             break;
182           }
183
184         cout << "MODULE " << basenm << endl;
185         return basenm;
186 }
187
188 // If the file is a/b/c/m.idl
189 //  we return a/b/c/m
190 // If the file is a/b/c/m.n.idl
191 //  we return a/b/c/m.n
192 // Caller must delete the returned string.
193 char *
194 get_fullname_noextension(char *pathname)
195 {
196         char c = '.';
197         int i = 0;
198
199         for(i=strlen(pathname)-1; i>=0; i--)
200           if (pathname[i] == c)
201             break;
202         assert(i != 0);
203
204         char *fullnm = new char[i+1];
205         strncpy(fullnm, pathname, i);
206         fullnm[i] = '\0';
207
208         return fullnm;
209 }
210
211 //----------------------------------------------------------------------
212 // Files to output to
213
214 ofstream *MESGH; // messages.h
215 ofstream *SKELH; // skeleton.h
216 ofstream *SKELC; // skeleton.C
217 ofstream *SKELCI; // front of skeleton.ci
218 ofstream *SKELCIREST; // tail of skeleton.ci
219 ofstream *STUBH; // stub.h
220 ofstream *STUBC; // stub.C
221 ofstream *STUBCI; // stub.ci
222 ofstream *STUBCIREST; // tail of stub.ci
223
224 // Global variables
225 char *fileBaseNameNoExt = 0;
226 char *fullNameNoExt = 0;
227
228 //----------------------------------------------------------------------
229 //This is the actual code that we output.  We use the spew function to
230 //replace \01, \02, etc. by the desired values.
231
232 // header stuff
233 const char *SKELHDR10 = // filename
234 "#ifndef \01_SKELETON_H\n"
235 "#define \01_SKELETON_H\n"
236 "// \01_skeleton.h\n"
237 "// The skeleton basically contains the class and forwards all messages\n"
238 "// received to it by invoking local function calls.\n"
239 "\n"
240 "//#include \"\01_messages.h\"\n"
241 "#include \"\01_skeleton.top.h\"\n"
242 "\n"
243 ;
244
245 // declare skeleton class and system-defined functions
246 const char *SKELHDR20 = // classname
247 "class \01_skeleton : public skel_object {\n"
248 "  private:\n"
249 "    \01 *myObj1;\n"
250 "\n"
251 "  public:\n"
252 "    \01_skeleton(M_Empty *m);\n"
253 "    void delete_\01_skeleton(M_Empty *m);\n"
254 "\n"
255 ;
256
257 // declare user-defined functions
258 const char *SKELHDR30 = // method return type, name, message type
259 "    \01 \02(\03 *m);\n"
260 ;
261
262 // end classname
263 const char *SKELHDR40 =
264 "};\n"
265 ;
266
267 // end filename
268 const char *SKELHDR50 =
269 "\n"
270 "#endif\n"
271 ;
272
273 //----------------------------------------------------------------------
274
275 // header stuff
276 const char *SKELCEE10 = // filename
277 "// \01_skeleton.C\n"
278 "\n"
279 "#include \"\01_skeleton.h\"\n"
280 "\n"
281 ;
282
283 // define system-defined functions
284 const char *SKELCEE20 = // classname
285 "//----------------------------------------\n"
286 "void \01_skeleton::delete_\01_skeleton(M_Empty *m) {\n"
287 "  delete m;\n"
288 "}\n"
289 "\n"
290 ;
291
292 // define user-defined functions, call local object
293 // classname, methodname, message type, return type
294 const char *SKELCEE30 = 
295 "//----------------------------------------\n"
296 "\04 \01_skeleton::\02(\03 *m) {\n"
297 "  myObj1->\02("
298 ;
299
300 // define user-defined constructor, call local object
301 // classname, methodname, message type, return type
302 const char *SKELCEE35 = 
303 "//----------------------------------------\n"
304 "\04 \01_skeleton::\02(\03 *m) {\n"
305 "  myObj1 = new \05("
306 ;
307
308 // list arguments
309 const char *SKELCEE40 = // argument name
310 "m->\01"
311 ;
312
313 // list arguments
314 // const char *SKELCEE42 = // array argument name, size
315 // "m->\01[\02]"
316 // ;
317
318 // also introduce comma's between arguments
319 const char *SKELCEE45 = //
320 ", "
321 ;
322
323 // end parameters
324 const char *SKELCEE50 =
325 ");\n"
326 ;
327
328 // return value stuff
329 const char *SKELCEE52 = // return message type
330 "  \01 *mret = new (MsgIndex(\01)) \01;\n"
331 ;
332
333 // assign arguments to return message elements
334 const char *SKELCEE53 = // argument name
335 "  mret->\01 = m->\01;\n"
336 ;
337
338 // return message
339 const char *SKELCEE54 =
340 "  return mret;\n"
341 ;
342
343 // end method
344 const char *SKELCEE55 =
345 "  delete m;\n"
346 "}\n"
347 "\n"
348 ;
349
350 // end filename
351 const char *SKELCEE60 = // filename
352 "//----------------------------------------\n"
353 "#include \"\01_skeleton.bot.h\"\n"
354 ;
355
356 //----------------------------------------------------------------------
357
358 // header stuff
359 const char *SKELCI10 = // filename
360 "// \01_skeleton.ci\n"
361 "\n"
362 // @@ should be extern, but then we need message.ci
363 "message M_Empty;\n"
364 ;
365
366 // declare marshalling messages
367 const char *SKELCI20 = // message type
368 "message \01;\n"
369 "\n"
370 ;
371
372 // declare system-defined functions
373 const char *SKELCI30 = // class name
374 "chare \01_skeleton {\n"
375 "  entry \01_skeleton(M_Empty *);\n"
376 "  entry delete_\01_skeleton(M_Empty *);\n"
377 "\n"
378 ;
379
380 // declare user-defined functions
381 const char *SKELCI40 = // operation name, message type, special return type
382 "  \03 entry \01(\02 *);\n"
383 ;
384
385 // end classname and filename
386 const char *SKELCI50 =
387 "};\n"
388 ;
389
390 //----------------------------------------------------------------------
391
392 // class specific messages
393
394 // header and system-defined stuff
395 const char *MESGOP10 = // filename
396 "#ifndef \01_MESSAGE_H\n"
397 "#define \01_MESSAGE_H\n"
398 "//#include \"ckdefs.h\"\n"
399 "//#include \"chare.h\"\n"
400 "//#include \"c++interface.h\"\n"
401 "#include \"charm++.h\"\n"
402 "\n"
403 "#ifndef COMMON_TEMPLATE\n"
404 "#define COMMON_TEMPLATE\n"
405 "template<class T>\n"
406 "void\n"
407 "copy_array(T to[], T from[], int size)\n"
408 "{\n"
409 "  for (int i=0; i < size; i++)\n"
410 "    to[i] = from[i];\n"
411 "};\n"
412 "#endif\n"
413 "\n"
414 "\n"
415 // @@ there should be a global messages file.
416 "#ifndef MESSAGE_H\n"
417 "#define MESSAGE_H\n"
418 "class skel_object;\n"
419 "class M_Empty;\n"
420 "// Right now contains nothing\n"
421 "class skel_object : public chare_object {\n"
422 "};\n"
423 "\n"
424 "class M_Empty : public comm_object {\n"
425 "};\n"
426 "#endif\n"
427 "\n"
428 "#include \"\01.h\"\n"
429 "\n"
430 ;
431
432 //define messages
433 const char *MESGOP20 = // messagename
434 "class \01 : public comm_object {\n"
435 "public:\n"
436 ;
437
438 const char *MESGOP30 = // argument type, name
439 "    \01 \02;\n"
440 ;
441
442 const char *MESGOP35 = // array argument type, name, size
443 "    \01 \02[\03];\n"
444 ;
445
446 // end messagename
447 const char *MESGOP40 =
448 "};\n"
449 ;
450
451 // end filename
452 const char *MESGOP50 =
453 "\n"
454 "#endif\n"
455 "\n"
456 ;
457
458 //----------------------------------------------------------------------
459 // @@ not yet implemented
460 const char *MESGCEE10 =
461 "\n"
462 "\n"
463 ;
464
465 //----------------------------------------------------------------------
466
467 // header stuff
468 const char *STUBHDR10 = // filename
469 "#ifndef \01_STUB_H\n"
470 "#define \01_STUB_H\n"
471 "\n"
472 "#include \"\01_skeleton.h\"\n"
473 "\n"
474 ;
475
476 // declare the stub class and system-defined functions
477 const char *STUBHDR20 = // classname
478 "class \01_stub : public chare_object {\n"
479 "  int shouldDelete; //virtual\n"
480 "  ChareIDType chare_Id; // virtual\n"
481 "public:\n"
482 "  \01_stub(int pe);\n"
483 "  \01_stub();\n"
484 "  \01_stub(ChareIDType id);\n"
485 "  ~\01_stub(void);\n"
486 "  ChareIDType getGlobalID() { return chare_Id; }\n"
487 "\n"
488 ;
489
490 // declare user-defined functions
491 const char *STUBHDR30 = // method return type, name
492 "  \01 \02("
493 ;
494
495 // pass by value
496 const char *STUBHDR40 = // argument type
497 "\01 "
498 ;
499
500 // pass by reference
501 const char *STUBHDR41 = // argument type
502 "\01 &"
503 ;
504
505 const char *STUBHDR42 = // array argument type, size
506 "\01[\02] "
507 ;
508
509 // also introduce comma's between arguments
510 const char *STUBHDR45 =
511 ", "
512 ;
513
514 // end arguments
515 const char *STUBHDR50 =
516 ");\n"
517 ;
518
519 // declare system-defined helper function, if needed
520 const char *STUBHDR55 = // return message type with ptr, marshall message type,
521  // methodname
522 "  \01 \03helper(\02 *);\n"
523 ;
524
525 // end classname
526 const char *STUBHDR60 =
527 "};\n"
528 ;
529
530 // end filename
531 const char *STUBHDR70 =
532 "\n"
533 "#endif\n"
534 ;
535
536 //----------------------------------------------------------------------
537
538 // header stuff
539 const char *STUBCEE10 = // filename
540 "// \01_stub.C\n"
541 "\n"
542 "#include \"\01_stub.h\"\n"
543 "#include \"\01_skeleton.h\"\n"
544 "#include \"\01_stub.top.h\"\n"
545 "\n"
546 ;
547
548 // define system-defined functions
549 const char *STUBCEE20 = // classname
550 "//\01_stub::\01_stub(int pe) {\n"
551 "//  // create new chare of type \01_skeleton on PE\n"
552 "//  // by sending a message of type M_Empty\n"
553 "//  // and store returned chareID in chareId;\n"
554 "//  M_Empty *msg = new (MsgIndex(M_Empty)) M_Empty;\n"
555 "//  new_chare2(\01_skeleton,M_Empty,msg,&chare_Id,pe);\n"
556 "//\n"
557 "//  shouldDelete = 1;\n"
558 "//}\n"
559 "\n"
560 "\01_stub::\01_stub() {\n"
561 "  // create new chare of type \01_skeleton on any PE\n"
562 "  // by sending a message of type M_Empty\n"
563 "  // and store returned chareID in chareId;\n"
564 "  M_Empty *msg = new (MsgIndex(M_Empty)) M_Empty;\n"
565 "  new_chare2(\01_skeleton,M_Empty,msg,&chare_Id,CK_PE_ANY);\n"
566 "\n"
567 "  shouldDelete = 1;\n"
568 "}\n"
569 "\n"
570 "\01_stub::\01_stub(ChareIDType id) {\n"
571 "  chare_Id = id;\n"
572 "  shouldDelete = 0;\n"
573 "}\n"
574 "\n"
575 "\01_stub::~\01_stub(void) {\n"
576 "  if(shouldDelete) {\n"
577 "    //M_Empty *m = new (MsgIndex(M_Empty)) M_Empty;\n"
578 "    //CSendMsg(\01_skeleton, delete_\01_skeleton, m, &chare_Id);\n"
579 "  } else {\n"
580 "    // do nothing\n"
581 "  }\n"
582 "}\n"
583 "\n"
584 "//------------------------------\n"
585 ;
586
587 // begin to define user-defined function
588 const char *STUBCEE30 = // class name, method return type, method name
589 "\02 \01_stub::\03("
590 ;
591
592 // OR begin to define user-defined constructor
593 const char *STUBCEE35 = // classname
594 "\01_stub::\01_stub("
595 ;
596
597 // @@ make sure out/inout parameters are references
598
599 // list parameters
600 const char *STUBCEE40 = // argument type, name
601 "\01 \02"
602 ;
603
604 // list parameters,  pass by reference
605 const char *STUBCEE41 = // argument type, name
606 "\01 &\02"
607 ;
608
609 // list parameters
610 const char *STUBCEE42 = // array argument type, name, size
611 "\01 \02[\03]"
612 ;
613
614 // also introduce comma's between parameters
615 const char *STUBCEE45 = //
616 ", "
617 ;
618
619 // end parameters
620 const char *STUBCEE50 =
621 ") {\n"
622 ;
623
624 // begin function body
625 const char *STUBCEE60 = // class name, method name, message type
626 //"  // CPrintf(\"\01_stub::\02: Message received %f\\n\", arg0);\n"
627 "  \03 *m = new (MsgIndex(\03)) \03;\n"
628 ;
629
630 // // assign arguments to message elements
631 // const char *STUBCEE70 = // arguments
632 // "  m->%s = %s;\n"
633 // ;
634
635 // assign arguments to message elements
636 const char *STUBCEE71 = // arguments
637 "  m->\01 = \01;\n"
638 ;
639
640 // // assign arguments to message elements
641 // const char *STUBCEE75 = // arguments
642 // "  copy_array(m->%s, %s, %s);\n"
643 // ;
644
645 // assign array arguments to message elements
646 const char *STUBCEE76 = // argument name, array size
647 "  copy_array(m->\01, \01, \02);\n"
648 ;
649
650 // send off the asynchronous message
651 const char *STUBCEE80 = //class name,  method name
652 "  CSendMsg(\01_skeleton, \02, \03, m, &chare_Id);\n"
653 ;
654
655 // OR send off a synchronous message
656 const char *STUBCEE82 = // return message type, method name
657 "  \01 * result;\n"
658 "  result = \02helper(m);\n"
659 "\n"
660 ;
661
662 // assign return message elements to arguments 
663 const char *STUBCEE84 = // arguments
664 "  \01 = result->\01;\n"
665 ;
666
667 // assign array message elements to arguments
668 const char *STUBCEE86 = // argument name, array size
669 "  copy_array(\01, result->\01, \02);\n"
670 ;
671
672 // OR create the skeleton
673 const char *STUBCEE88 = //class name
674 // @@ what about specific PE's ?  We need to generate another constructor.
675 "  // create new chare of type \01_skeleton on PE\n"
676 "  // by sending a message of type M_Empty\n"
677 "  // and store returned chareID in chareId;\n"
678 "  new_chare2(\01_skeleton,\02,m,&chare_Id,0);\n"
679 "\n"
680 "  shouldDelete = 1;\n"
681 "\n"
682 ;
683
684 // end user-defined function
685 const char *STUBCEE90 =
686 "}\n"
687 ;
688
689 // if needed, helper function
690 const char *STUBCEE92 = // return message type, marshall message type,
691  // class name, method name
692 "\01 * \03_stub::\04helper(\02 *m) {\n"
693 "  \01 * result;\n"
694 "  result = (\01 *) CRemoteCall(\03_skeleton,\04,\02,m,&chare_Id);\n"
695 "  return result;\n"
696 "}\n"
697 "\n"
698 ;
699
700 // if needed, helper function without return type
701 const char *STUBCEE94 = // return message type (void), marshall message type,
702  // class name, method name
703 "\01 \03_stub::\04helper(\02 *m) {\n"
704 "  \01 result;\n"
705 "  result = (\01 *) CRemoteCallFn(GetEntryPtr(\03_skeleton,\n"
706 "                                                     \04, \02), m, &chare_Id);\n"
707 "  return result;\n"
708 "}\n"
709 "\n"
710 ;
711
712 // end
713 const char *STUBCEE95 = // filename
714 "\n"
715 "#include \"\01_stub.bot.h\"\n"
716 ;
717
718 //----------------------------------------------------------------------
719
720 // declare marshalling messages
721 const char *STUBCI20 = // message type
722 "extern message \01;\n"
723 ;
724
725 // declare system-defined functions
726 const char *STUBCI30 = // class name
727 "\n"
728 "chare \01_stub {\n"
729 ;
730
731 // declare system-defined helper function, if needed
732 const char *STUBCI40 = // operation name, message type, special return type
733 "  threaded \03 entry \01helper(\02 *);\n"
734 ;
735
736 // end classname and filename
737 const char *STUBCI50 =
738 "};\n"
739 ;
740
741 //----------------------------------------------------------------------
742
743 // Traverse the method's parameters.
744 // Output code for:
745 //   1. the marshall message
746 //   2. the stub function (.h, .C)
747 //   3. the skeleton.C local invocation of the method
748 void
749 BE_produce_parameters(be_operation *bop,
750                       char stubcPass1B[],
751                       char mesghPass2[],
752                       char skelcPass2[],
753                       char stubcPass2[])
754 {
755   UTL_ScopeActiveIterator   *i;
756   AST_Decl                  *d;
757
758   // @@ what about the return value ?
759
760   i = new UTL_ScopeActiveIterator(bop, UTL_Scope::IK_decls);
761   int argNum = -1;
762   while (!(i->is_done())) {
763     d = i->item();
764     argNum++;
765
766     if (d->node_type() == AST_Decl::NT_argument) {
767       be_argument *a = be_argument::narrow_from_decl(d);
768       //      cout << "NT_argument" << endl;
769       char argName[100];
770       sprintf(argName, "%s%d", "arg", argNum);
771
772       if (a->isArray()) {
773         be_array *ar = be_array::narrow_from_decl(a->field_type());
774
775         char *arrayType = ar->base_type()->local_name()->get_string();
776         unsigned long arraySizeNum = ar->dims()[0]->ev()->u.ulval;
777         char arraySize[100];
778         strcpy(arraySize,"");
779         sprintf(arraySize, "%u", arraySizeNum);
780         spew(*MESGH, MESGOP35, arrayType, argName, arraySize);
781         if (bop->isReturnMessageNeeded())
782           spew(mesghPass2, MESGOP35, arrayType, argName, arraySize);
783         spew(*SKELC, SKELCEE40, argName);
784         if (bop->isReturnMessageNeeded())
785           spew(skelcPass2, SKELCEE53, argName);
786         spew(*STUBH, STUBHDR42, arrayType, arraySize);
787         spew(*STUBC, STUBCEE42, arrayType, argName, arraySize);
788
789         //sprintf(ta, STUBCEE75, argName, argName, arraySize);
790         spew(stubcPass1B, STUBCEE76, argName, arraySize);
791         if (bop->isReturnMessageNeeded())
792           spew(stubcPass2, STUBCEE86, argName, arraySize);
793       } else {
794         char *argType = a->field_type()->local_name()->get_string();
795         spew(*MESGH, MESGOP30, argType, argName);
796         if (bop->isReturnMessageNeeded())
797           spew(mesghPass2, MESGOP30, argType, argName);
798         spew(*SKELC, SKELCEE40, argName);
799         if (bop->isReturnMessageNeeded())
800           spew(skelcPass2, SKELCEE53, argName);
801
802         // do we need to use pass by reference for the parameter
803         if(a->direction() == AST_Argument::dir_IN) {
804           spew(*STUBH, STUBHDR40, argType);
805           spew(*STUBC, STUBCEE40, argType, argName);
806         } else {
807           spew(*STUBH, STUBHDR41, argType);
808           spew(*STUBC, STUBCEE41, argType, argName);
809         }
810
811         //sprintf(ta, STUBCEE70, argName);
812         spew(stubcPass1B, STUBCEE71, argName);
813         if (bop->isReturnMessageNeeded())
814           spew(stubcPass2, STUBCEE84, argName);
815       }
816       //      string_append(stubcPass1B, ta);
817
818       //   o << direction_to_string(pd_direction) << " ";
819       //   AST_Field::dump(o);
820     } else {
821       cerr << "LIMIT: Only arguments within method parameter list\n";
822     }
823
824     i->next();
825     if (!(i->is_done())) { // output commas between parameters
826       spew(*SKELC, SKELCEE45);
827       spew(*STUBH, STUBHDR45);
828       spew(*STUBC, STUBCEE45);
829     }
830   }
831   delete i;
832
833 }
834
835 // There are three types of methods:
836 // - a constructor (no return values, creates a chare)
837 // - an asynchronous call (no return values)
838 // - a synchronous call (has a return value)
839 // Furthermore, the method may be non-threaded (default), or threaded.
840 void
841 BE_produce_operation(AST_Decl *d_in, AST_Interface *parent_interface)
842   /* An operation is basically a C++ method. */
843 {
844   //AST_Operation *op = AST_Operation::narrow_from_decl(d_in);
845   be_operation *bop = be_operation::narrow_from_decl(d_in);
846
847   if (bop->isConstructor())
848     cerr << "DEBUG: isConstructor ";
849
850   if (bop->isMarshallMessageNeeded())
851     cerr << "DEBUG: isMarshallMessageNeeded ";
852
853   if (bop->isReturnMessageNeeded())
854     cerr << "DEBUG: isReturnMessageNeeded ";
855
856   if (bop->isThreaded())
857     cerr << "DEBUG: isThreaded found thread" << endl;
858   else
859     cerr << endl;
860
861   ostream &o(cout);
862
863   UTL_ScopeActiveIterator   *i;
864   UTL_StrlistActiveIterator *si;
865   UTL_ExceptlistActiveIterator *ei;
866   AST_Decl                  *d;
867   AST_Exception             *e;
868   String                    *s;
869
870   // @@ if not threaded, set a flag to disallow use of futures in the function.
871 //   if (pd_flags == OP_oneway)
872 //     o << "oneway ";
873 //   else if (pd_flags == OP_idempotent)
874 //     o << "idempotent ";
875
876   char *classname = parent_interface->local_name()->get_string();
877   char *methodname = bop->local_name()->get_string();
878   char *skelmethodname = new char[MAX_STR_LEN];
879   strcpy(skelmethodname, methodname);
880   char *stubmethodname = new char[MAX_STR_LEN];
881   strcpy(stubmethodname, methodname);
882   // If we have a constructor myClass::myClass, we need to change the
883   // methodname to the constructor name for a stub and a skeleton.
884   if (bop->isConstructor()) {
885     strcat(skelmethodname, "_skeleton"); // in case of a ret mesg
886     strcat(stubmethodname, "_stub");
887   }
888
889   // Create a message to marshall the method's parameters in.
890   char marshallMesgTypeName[MAX_STR_LEN];
891   sprintf(marshallMesgTypeName, "M%sM%d", classname,
892           bop->getMarshallMessageNumber());
893   //  bop->p_marshallMesgTypeName = marshallMesgTypeName;
894
895   // @@ document this: if there is no return value, the caller must
896   // assume an asynchronous call was made to this function.
897
898   // @@ I added the local_
899   // Method's return type.
900   char *methodReturnTypeName = bop->return_type()->local_name()->get_string();
901   if (bop->isConstructor()) {
902     methodReturnTypeName = "";
903   }
904
905   // If needed, create a message to marshall the method's return
906   // parameters in.
907   char returnMarshallMesgTypeName[MAX_STR_LEN];
908   strcpy(returnMarshallMesgTypeName,"void");
909   char returnMarshallMesgTypeNameWithPtr[MAX_STR_LEN];
910   strcpy(returnMarshallMesgTypeNameWithPtr,"void");
911   if (bop->isConstructor()) {
912     strcpy(returnMarshallMesgTypeName,"");
913     strcpy(returnMarshallMesgTypeNameWithPtr,"");
914   } else if (bop->isReturnMessageNeeded()) { // either a retval, or a retarg
915     sprintf(returnMarshallMesgTypeName, "M%sM%d", classname, 
916             bop->getReturnMessageNumber());
917     sprintf(returnMarshallMesgTypeNameWithPtr, "M%sM%d *", classname, 
918             bop->getReturnMessageNumber());
919   } else {
920     // they're already void.
921   }
922
923   // Marshall, return messages
924   // We always have a marshalling message since charmxi expects one
925   spew(*MESGH, MESGOP20, marshallMesgTypeName);
926   spew(*SKELCI, SKELCI20, marshallMesgTypeName);
927   spew(*STUBCI, STUBCI20, marshallMesgTypeName);
928   char mesghPass2[MAX_STR_LEN];
929   strcpy(mesghPass2,"");
930   if (bop->isReturnMessageNeeded())
931     spew(mesghPass2, MESGOP20, returnMarshallMesgTypeName);
932
933   // Output the method's return type and name.
934   spew(*SKELH, SKELHDR30,
935        returnMarshallMesgTypeNameWithPtr, skelmethodname, marshallMesgTypeName);
936   if (bop->isConstructor())
937     spew(*SKELC, SKELCEE35,
938          classname, skelmethodname, marshallMesgTypeName, 
939          returnMarshallMesgTypeNameWithPtr, methodname);
940   else
941     spew(*SKELC, SKELCEE30,
942          classname, skelmethodname, marshallMesgTypeName, 
943          returnMarshallMesgTypeNameWithPtr);
944   char skelcPass2[MAX_STR_LEN];
945   strcpy(skelcPass2,"");
946   if (bop->isReturnMessageNeeded()) {
947      // create retmsg instance
948     spew(skelcPass2, SKELCEE52, returnMarshallMesgTypeName);
949     // declare helper function
950     spew(*STUBH, STUBHDR55, returnMarshallMesgTypeNameWithPtr,
951          marshallMesgTypeName, stubmethodname);
952   }
953
954   // declare user function
955   spew(*STUBH, STUBHDR30, methodReturnTypeName, stubmethodname);
956   spew(*STUBC, STUBCEE30, classname, methodReturnTypeName, stubmethodname);
957
958   if (bop->isReturnMessageNeeded()) {
959     // declare retmsg
960     spew(*SKELCI, SKELCI20, returnMarshallMesgTypeName);
961     spew(*STUBCI, STUBCI20, returnMarshallMesgTypeName);
962     // declare EP
963     spew(*SKELCIREST, SKELCI40, skelmethodname, marshallMesgTypeName,
964          returnMarshallMesgTypeNameWithPtr);
965     spew(*STUBCIREST, STUBCI40, stubmethodname, marshallMesgTypeName,
966          returnMarshallMesgTypeNameWithPtr);
967   } else {
968     // do not declare the stub ep since no stub helper function is needed.
969     spew(*SKELCIREST, SKELCI40, skelmethodname, marshallMesgTypeName, "");
970   }
971
972   // FIRST PASS
973
974   // Output the stuff for the parameters.
975   char stubcPass1B[MAX_STR_LEN];
976   strcpy(stubcPass1B,"");
977   char stubcPass2[MAX_STR_LEN];
978   strcpy(stubcPass2,"");
979   BE_produce_parameters(bop, stubcPass1B, mesghPass2, skelcPass2, stubcPass2);
980
981   // Output the closing stuff for the method, i.e. parentheses, etc.
982   spew(*SKELC, SKELCEE50);
983   spew(*MESGH, MESGOP40, classname);
984   spew(*STUBH, STUBHDR50);
985   spew(*STUBC, STUBCEE50);
986   spew(*STUBC, STUBCEE60,
987        classname, stubmethodname, marshallMesgTypeName);
988   spew(*STUBC, stubcPass1B);  // body of the method
989
990   if(!bop->isReturnMessageNeeded()/* && !bop->is_threaded()*/) // invoke the remote call to the skeleton
991     if (bop->isConstructor()) // constructor
992       spew(*STUBC, STUBCEE88, classname, marshallMesgTypeName);
993     else // async. message
994       spew(*STUBC, STUBCEE80, classname, skelmethodname, marshallMesgTypeName);
995   else // sync message
996     if (bop->isConstructor()) // constructor
997       spew(*STUBC, STUBCEE88, "ERROR", "ERROR"); // constructor cannot have retval @@ but it can be threaded, right ?
998     else
999       spew(*STUBC, STUBCEE82, returnMarshallMesgTypeName, stubmethodname);
1000
1001   // SECOND PASS
1002   // rest of SKELC, STUBC, MESGH; i.e. return message stuff, if needed.
1003   if (bop->isReturnMessageNeeded()/* || bop->is_threaded()*/) {
1004     spew(mesghPass2, MESGOP40, classname);
1005     spew(skelcPass2, SKELCEE54);
1006   }
1007   spew(*MESGH, mesghPass2); 
1008   spew(*SKELC, skelcPass2);
1009   spew(*STUBC, stubcPass2);
1010
1011   spew(*SKELC, SKELCEE55);
1012   spew(*STUBC, STUBCEE90);
1013   if (bop->isReturnMessageNeeded()/* || bop->is_threaded()*/) // output the helper function for the op
1014     spew(*STUBC, STUBCEE92, returnMarshallMesgTypeName, marshallMesgTypeName,
1015          classname, stubmethodname);
1016
1017 //   i = new UTL_ScopeActiveIterator(op, UTL_Scope::IK_decls);
1018 //   op->return_type()->name()->dump(o);
1019 //   o << " ";
1020 //   op->local_name()->dump(o);
1021 //   o << "(";
1022 //   while (!(i->is_done())) {
1023 //     d = i->item();
1024 //     d->dump(o);
1025 //     i->next();
1026 //     if (!(i->is_done()))
1027 //       o << ", ";
1028 //   }
1029 //   delete i;
1030 //   o << ")";
1031
1032   // @@ We will deal with exceptions later
1033 //   if (op->exceptions() != NULL) {
1034 //     o << " raises(";
1035 //     ei = new UTL_ExceptlistActiveIterator(op->exceptions());
1036 //     while (!(ei->is_done())) {
1037 //       e = ei->item();
1038 //       ei->next();
1039 //       e->local_name()->dump(o);
1040 //       if (!(ei->is_done()))
1041 //      o << ", ";
1042 //     }
1043 //     delete ei;
1044 //     o << ")";
1045 //   }
1046 //   if (op->context() != NULL) {
1047 //     o << " context(";
1048 //     si = new UTL_StrlistActiveIterator(op->context());
1049 //     while (!(si->is_done())) {
1050 //       s = si->item();
1051 //       si->next();
1052 //       o << s->get_string();
1053 //       if (!(si->is_done()))
1054 //      o << ", ";
1055 //     }
1056 //     delete si;
1057 //     o << ")";
1058 //   }
1059 }
1060
1061 //----------------------------------------------------------------------
1062 void
1063 BE_produce_attribute(AST_Decl *d)
1064 {
1065   be_attribute *a = be_attribute::narrow_from_decl(d);
1066   cerr << "WARNING: Attributes unimplemented as yet." << endl;
1067   //exit (-1);
1068
1069 //   cout << "NT_attr " << a->field_type()->local_name()->get_string() << " "
1070 //        << a->local_name()->get_string() << endl;
1071
1072 //   o << (pd_readonly == I_TRUE ? "readonly" : "") << " attribute ";
1073 //   AST_Field::dump(o);
1074 }
1075
1076 //----------------------------------------------------------------------
1077 void
1078 BE_produce_interface(AST_Decl *d)
1079   /* An interface is basically a C++ class */
1080 {
1081   UTL_ScopeActiveIterator       *i;
1082   AST_Interface                 *m;
1083   ostream &o(cout);
1084
1085   m = AST_Interface::narrow_from_decl(d);
1086
1087   char *classname = m->local_name()->get_string();
1088   spew(*SKELH, SKELHDR20, classname);
1089   spew(*SKELC, SKELCEE20, classname);
1090   spew(*STUBH, STUBHDR20, classname);
1091   spew(*STUBC, STUBCEE20, classname);
1092   spew(*SKELCIREST, SKELCI30, classname);
1093   spew(*STUBCIREST, STUBCI30, classname);
1094
1095   //  if (UTL_Scope::decls_used() > 0) {
1096     i = new UTL_ScopeActiveIterator(m, UTL_Scope::IK_both);
1097     int count = 0;
1098     while (!(i->is_done())) {
1099       d = i->item();
1100       count++;
1101
1102       switch(d->node_type()){
1103       case AST_Decl::NT_attr:
1104         BE_produce_attribute(d);
1105         break;
1106       case AST_Decl::NT_op:
1107         BE_produce_operation(d, m);
1108         break;
1109       default:
1110         cerr << "LIMIT: Only Attributes and Operations within interface\n";
1111         break;
1112       }
1113
1114 //       if (!d->imported()) {
1115 //      cout << "count = " << count << endl;
1116 //      idl_global->indent()->skip_to(o);
1117 //      d->dump(o);
1118 //      o << ";\n";
1119 //       } else {
1120 //      cout << "count = " << count << " IMPORTED" << endl;
1121 //       }
1122
1123       i->next();
1124     }
1125     delete i;
1126     //  }
1127   spew(*SKELH, SKELHDR40);
1128   spew(*STUBH, STUBHDR60);
1129   spew(*SKELCIREST, SKELCI50);
1130   spew(*STUBCIREST, STUBCI50);
1131
1132 }
1133
1134 //----------------------------------------------------------------------
1135 void
1136 BE_produce_module(AST_Decl *d)
1137 {
1138   UTL_ScopeActiveIterator       *i;
1139   AST_Module                    *m;
1140   ostream &o(cout);
1141
1142   m = AST_Module::narrow_from_decl(d);
1143   //  if (UTL_Scope::decls_used() > 0) {
1144     i = new UTL_ScopeActiveIterator(m, UTL_Scope::IK_both);
1145     int count = 0;
1146     while (!(i->is_done())) {
1147       d = i->item();
1148       count++;
1149
1150       switch(d->node_type()){
1151       case AST_Decl::NT_interface:
1152         //cout << "NT_interface\n";
1153         BE_produce_interface(d);
1154         break;
1155       default:
1156         if (!d->imported()) {
1157           cerr << "LIMIT: Only Interfaces within Modules at top level\n";
1158         }
1159         break;
1160       }
1161
1162       i->next();
1163     }
1164     delete i;
1165     //  }
1166 }
1167
1168 //----------------------------------------------------------------------
1169 /*
1170   Output occurs at several levels of the hierarchy:
1171
1172   File Level
1173     Module Level (Basically a namespace)
1174       Interface Level (Basically a class)
1175         Operation Level (Basically a method)
1176           Parameter Level (Basically a list of parameters for the method)
1177
1178   In each case, we output when:
1179   1. Entering the level
1180   2. Within the level
1181   3. Leaving the level
1182  */
1183
1184 // Create the various files that the BE outputs.  Output the
1185 // file-level opening stuff.
1186 void
1187 initialize()
1188 {
1189   fullNameNoExt = get_fullname_noextension(
1190                       idl_global->main_filename()->get_string());
1191   // cout << "DEBUG:" << fullNameNoExt << endl;
1192   fileBaseNameNoExt = get_basename_noextension(
1193                       idl_global->main_filename()->get_string());
1194   // cout << "DEBUG:" << fileBaseNameNoExt << endl;
1195
1196   char filename[MAX_STR_LEN];
1197
1198   sprintf(filename, "%s_messages.h", fullNameNoExt);
1199   MESGH = new ofstream(filename);
1200   spew(*MESGH, MESGOP10, fullNameNoExt);
1201
1202   sprintf(filename, "%s_skeleton.h", fullNameNoExt);
1203   SKELH = new ofstream(filename);
1204   spew(*SKELH, SKELHDR10, fileBaseNameNoExt);
1205
1206   sprintf(filename, "%s_skeleton.C", fullNameNoExt);
1207   SKELC = new ofstream(filename);
1208   spew(*SKELC, SKELCEE10, fileBaseNameNoExt);
1209
1210   sprintf(filename, "%s_skeleton.ci", fullNameNoExt);
1211   SKELCI = new ofstream(filename);
1212   spew(*SKELCI, SKELCI10, fileBaseNameNoExt);
1213
1214   sprintf(filename, "%s_skeleton.ci.rest", fullNameNoExt);
1215   SKELCIREST = new ofstream(filename);
1216
1217   sprintf(filename, "%s_stub.h", fullNameNoExt);
1218   STUBH = new ofstream(filename);
1219   spew(*STUBH, STUBHDR10, fileBaseNameNoExt);
1220
1221   sprintf(filename, "%s_stub.C", fullNameNoExt);
1222   STUBC = new ofstream(filename);
1223   spew(*STUBC, STUBCEE10, fileBaseNameNoExt);
1224
1225   sprintf(filename, "%s_stub.ci", fullNameNoExt);
1226   STUBCI = new ofstream(filename);
1227
1228   sprintf(filename, "%s_stub.ci.rest", fullNameNoExt);
1229   STUBCIREST = new ofstream(filename);
1230 }
1231
1232 // At the top level we can have modules, interfaces, constants or type
1233 // declarations. @@
1234 void
1235 BE_produce_top_level()
1236 {
1237   // PROCESS the root/file level of the AST
1238   UTL_ScopeActiveIterator       *i;
1239   AST_Decl                      *d;
1240   ostream &o(cout);
1241
1242   //  if (UTL_Scope::decls_used() > 0) {
1243     i = new UTL_ScopeActiveIterator(idl_global->root(), UTL_Scope::IK_both);
1244
1245     //    o << GTDEVEL("\n/* Declarations0: */\n");
1246     int count = 0;
1247     while (!(i->is_done())) {
1248       d = i->item();
1249       count++;
1250
1251       switch(d->node_type()){
1252       case AST_Decl::NT_module:
1253         //cout << "NT_module\n";
1254         BE_produce_module(d);
1255         break;
1256       case AST_Decl::NT_interface:
1257         //cout << "NT_interface\n";
1258         BE_produce_interface(d);
1259         break;
1260       case AST_Decl::NT_const:
1261       case AST_Decl::NT_struct:
1262         if (!d->imported()) {
1263           d->dump(o);
1264           o << ";" << endl << endl;
1265         }
1266         break;
1267       default:
1268         if (!d->imported()) {
1269           cerr << "LIMIT: Only Modules and Interfaces at top level\n";
1270           d->dump(cout); o << ";" << endl << endl;
1271         }
1272         break;
1273       }
1274
1275 //       if (!d->imported()) {
1276 //      cout << "count = " << count << endl;
1277 //      idl_global->indent()->skip_to(o);
1278 //      d->dump(o);
1279 //      o << ";\n";
1280 //       } else {
1281 //      //      cout << "count = " << count << " IMPORTED" << endl;
1282 //       }
1283       i->next();
1284     }
1285     delete i;
1286     //  }
1287 }
1288
1289 // Output the file-level closing stuff; Close the output files.
1290 void
1291 clean_up()
1292 {
1293   spew(*MESGH, MESGOP50);
1294   delete MESGH;
1295
1296   spew(*SKELH, SKELHDR50);
1297   delete SKELH;
1298
1299   char cleanUpCommands[MAX_STR_LEN];
1300   sprintf(cleanUpCommands, "cat %s_skeleton.h >> %s_messages.h; "
1301           "mv %s_messages.h %s_skeleton.h", fullNameNoExt, fullNameNoExt,
1302           fullNameNoExt, fullNameNoExt);
1303   assert(system(cleanUpCommands) == 0);
1304
1305   spew(*SKELC, SKELCEE60, fileBaseNameNoExt);
1306   delete SKELC;
1307
1308   delete SKELCI;
1309   delete SKELCIREST;
1310   sprintf(cleanUpCommands, "cat %s_skeleton.ci.rest >> %s_skeleton.ci; "
1311           "rm %s_skeleton.ci.rest", fullNameNoExt, fullNameNoExt,
1312           fullNameNoExt);
1313   assert(system(cleanUpCommands) == 0);
1314
1315   spew(*STUBH, STUBHDR70);
1316   delete STUBH;
1317
1318   spew(*STUBC, STUBCEE95, fileBaseNameNoExt);
1319   delete STUBC;
1320
1321   delete STUBCI;
1322   delete STUBCIREST;
1323   sprintf(cleanUpCommands, "cat %s_stub.ci.rest >> %s_stub.ci; "
1324           "rm %s_stub.ci.rest", fullNameNoExt, fullNameNoExt,
1325           fullNameNoExt);
1326   assert(system(cleanUpCommands) == 0);
1327
1328   delete fullNameNoExt;
1329   delete fileBaseNameNoExt;
1330 }
1331
1332 /*
1333  * Do the work of this BE.
1334  */
1335 void
1336 BE_produce()
1337 {
1338   initialize();
1339
1340   BE_produce_top_level();
1341   
1342   clean_up();
1343 }
1344
1345 //----------------------------------------------------------------------
1346 /*
1347  * Abort this run of the BE
1348  */
1349 void
1350 BE_abort()
1351 {
1352 }
1353
1354 /*
1355
1356 COPYRIGHT
1357
1358 Copyright 1992, 1993, 1994 Sun Microsystems, Inc.  Printed in the United
1359 States of America.  All Rights Reserved.
1360
1361 This product is protected by copyright and distributed under the following
1362 license restricting its use.
1363
1364 The Interface Definition Language Compiler Front End (CFE) is made
1365 available for your use provided that you include this license and copyright
1366 notice on all media and documentation and the software program in which
1367 this product is incorporated in whole or part. You may copy and extend
1368 functionality (but may not remove functionality) of the Interface
1369 Definition Language CFE without charge, but you are not authorized to
1370 license or distribute it to anyone else except as part of a product or
1371 program developed by you or with the express written consent of Sun
1372 Microsystems, Inc. ("Sun").
1373
1374 The names of Sun Microsystems, Inc. and any of its subsidiaries or
1375 affiliates may not be used in advertising or publicity pertaining to
1376 distribution of Interface Definition Language CFE as permitted herein.
1377
1378 This license is effective until terminated by Sun for failure to comply
1379 with this license.  Upon termination, you shall destroy or return all code
1380 and documentation for the Interface Definition Language CFE.
1381
1382 INTERFACE DEFINITION LANGUAGE CFE IS PROVIDED AS IS WITH NO WARRANTIES OF
1383 ANY KIND INCLUDING THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS
1384 FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR ARISING FROM A COURSE OF
1385 DEALING, USAGE OR TRADE PRACTICE.
1386
1387 INTERFACE DEFINITION LANGUAGE CFE IS PROVIDED WITH NO SUPPORT AND WITHOUT
1388 ANY OBLIGATION ON THE PART OF Sun OR ANY OF ITS SUBSIDIARIES OR AFFILIATES
1389 TO ASSIST IN ITS USE, CORRECTION, MODIFICATION OR ENHANCEMENT.
1390
1391 SUN OR ANY OF ITS SUBSIDIARIES OR AFFILIATES SHALL HAVE NO LIABILITY WITH
1392 RESPECT TO THE INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY
1393 INTERFACE DEFINITION LANGUAGE CFE OR ANY PART THEREOF.
1394
1395 IN NO EVENT WILL SUN OR ANY OF ITS SUBSIDIARIES OR AFFILIATES BE LIABLE FOR
1396 ANY LOST REVENUE OR PROFITS OR OTHER SPECIAL, INDIRECT AND CONSEQUENTIAL
1397 DAMAGES, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
1398
1399 Use, duplication, or disclosure by the government is subject to
1400 restrictions as set forth in subparagraph (c)(1)(ii) of the Rights in
1401 Technical Data and Computer Software clause at DFARS 252.227-7013 and FAR
1402 52.227-19.
1403
1404 Sun, Sun Microsystems and the Sun logo are trademarks or registered
1405 trademarks of Sun Microsystems, Inc.
1406
1407 SunSoft, Inc.
1408 2550 Garcia Avenue
1409 Mountain View, California  94043
1410
1411 NOTE:
1412
1413 SunOS, SunSoft, Sun, Solaris, Sun Microsystems or the Sun logo are
1414 trademarks or registered trademarks of Sun Microsystems, Inc.
1415
1416  */
1417
1418 // #pragma ident "%@(#)BE_produce.cc    1.16% %92/06/10% Sun Microsystems"