#!/usr/bin/perl # # idl2ada.pl IDL symbol tree to Ada95 translator # Author: Oliver M. Kellogg (oliver.kellogg@vs.dasa.de) # Copyright: (C) 1998, Daimler-Benz Aerospace AG (DASA), Ulm, Germany # # This file is part of GNACK, the GNU Ada CORBA Kit. # # GNACK is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GNACK is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ----------------------------------------------------------------------------- # Ver. | Date | History # -----+----------+------------------------------------------------------------ # 0.0 1998/yy/xx First public release, alpha stage, Ada pkg. specs only # Features known to be missing: # * package body generation: at this point it is unclear # whether to interface to an existing C- or C++-based # ORB (such as ILU, Flick, OmniORB, TAO) or to implement # the entire ORB here -- ideas welcome. # * #define (C++ preprocessor definitions) # * forward declarations # * multiple inheritance # * the _IDL_File package for declarations in the IDL # global scope # * renaming/subtyping of parent type/constant/exception # declarations in the child package (single inheritance) # * Typecodes ; type Any # * non-void methods with inout or out parameters # * typedef struct (and other complicated typedefs) # * expressions as the maximum length in bounded sequences # and bounded strings # * More things missing? Tell me about it! (e-mail, above) # ----------------------------------------------------------------------------- # use CORBA::IDLtree; # Subroutine forward declarations sub gen_ada; sub gen_ada_recursive; sub mapped_type; sub check_scope; sub open_files; sub espec; sub ebody; sub eispec; sub eibody; sub especs; sub ebodies; sub eiboth; sub eboth; sub eall; sub pspec; sub pbody; sub pboth; # print to both (SPEC and BODY files) sub pispec; sub pibody; sub piboth; # print to both (ISPEC and IBODY files) sub pspecs; sub pbodies; sub pall; sub specindent; sub specdedent; sub print_spec_beginning; sub print_body_beginning; sub print_ispec_beginning; sub print_ibody_beginning; sub print_pkg_prologues; sub print_spec_interface; sub print_body_interface; sub print_ispec_interface; sub print_ibody_interface; sub print_interface_prologues; # Constants $INDENT = 3; # Number of spaces for one indentation $INDENT2 = (1 << (5 - $INDENT)) + 4; # Number of indents for an approx. 1/3-page (25 space) indentation @proxy_spec_file_handle = qw/ PS0 PS1 PS2 PS3 PS4 PS5 PS6 PS7 PS8 PS9 /; @proxy_body_file_handle = qw/ PB0 PB1 PB2 PB3 PB4 PB5 PB6 PB7 PB8 PB9 /; @impl_spec_file_handle = qw/ IS0 IS1 IS2 IS3 IS4 IS5 IS6 IS7 IS8 IS9 /; @impl_body_file_handle = qw/ IB0 IB1 IB2 IB3 IB4 IB5 IB6 IB7 IB8 IB9 /; # The file handles are indexed by $#scopestack. # Global variables @gen_ispec = (); # Generate implementation package spec (see gen_ada) @gen_ibody = (); # Generate implementation package body (see gen_ada) $in_comment = 0; # Auxiliary to sub getline (multi-line comment processing) @spec_ilvl = (); # Proxy-indentlevel @body_ilvl = (); # Proxy-indentlevel @ispec_ilvl = (); # Impl-indentlevel @ibody_ilvl = (); # Impl-indentlevel @scopestack = (); # Stack of module/interface names @withlist = (); # List of user packages to "with" $did_file_prologues = 0; # Flag; true when prologues were already written $psfh = 0; # Shorthand for $proxy_spec_file_handle[$#scopestack] $pbfh = 0; # Shorthand for $proxy_body_file_handle[$#scopestack] $isfh = 0; # Shorthand for $impl_spec_file_handle[$#scopestack] $ibfh = 0; # Shorthand for $impl_body_file_handle[$#scopestack] # Options processing $verbose = 0; for ($i=0; $i <= $#ARGV; $i++) { if ($ARGV[$i] =~ /^-/) { for (substr($ARGV[$i], 1)) { /^v$/ and $verbose = 1, last; /^V$/ and print("idl2ada version -.-\n"), last; die "unknown option: $ARGV[$i]\n"; } splice(@ARGV, $i--, 1); } } # Main program while (@ARGV) { $idl_filename = shift @ARGV; # $idl_filename is global and might be used in gen_ada for generating # the _IDL_File global-scope package. my $symroot = CORBA::IDLtree::Parse_File $idl_filename; die "idl2ada: errors while parsing $idl_filename\n" unless ($symroot); CORBA::IDLtree::Dump_Symbols($symroot) if ($verbose); gen_ada $symroot; } # End of main program # Ada back end subroutines sub mapped_type { # This is similar to typeof(), but the type returned is in Ada syntax. my $type_descr = shift; if (@_) { my $noderef = shift; if (exists $CORBA::IDLtree::Prefixes{$noderef}) { return($CORBA::IDLtree::Prefixes{$noderef}); } } if (CORBA::IDLtree::is_elementary_type $type_descr) { return "CORBA." . ucfirst($CORBA::IDLtree::predef_types[$type_descr]); } my @node = @{$type_descr}; # We are sure that it IS a node at this point if ($#node != 2) { return ""; } elsif ($node[$CORBA::IDLtree::TYPE] == $CORBA::IDLtree::BOUNDED_STRING) { return "CORBA.Bounded_String_" . $node[$CORBA::IDLtree::NAME] . ".Bounded_String"; } elsif ($node[$CORBA::IDLtree::TYPE] == $CORBA::IDLtree::INTERFACE) { return $node[$CORBA::IDLtree::NAME] . ".Ref"; } return $node[$CORBA::IDLtree::NAME]; } sub espec { my $text = shift; print $psfh $text; } sub ebody { my $text = shift; print $pbfh $text; } sub eispec { my $text = shift; if ($gen_ispec[$#scopestack]) { print $isfh $text; } } sub eibody { my $text = shift; if ($gen_ibody[$#scopestack]) { print $ibfh $text; } } sub especs { my $text = shift; espec $text; eispec $text; } sub ebodies { my $text = shift; ebody $text; eibody $text; } sub eiboth { my $text = shift; eispec $text; eibody $text; } sub eboth { my $text = shift; espec $text; ebody $text; } sub eall { my $text = shift; especs $text; ebodies $text; } sub pspec { my $text = (' ' x ($INDENT * $spec_ilvl[$#spec_ilvl])) . shift; espec $text; } sub pbody { my $text = (' ' x ($INDENT * $body_ilvl[$#body_ilvl])) . shift; ebody $text; } sub pboth { my $text = shift; pspec $text; pbody $text; } sub pispec { my $text = (' ' x ($INDENT * $ispec_ilvl[$#ispec_ilvl])) . shift; eispec $text; } sub pibody { my $text = (' ' x ($INDENT * $ibody_ilvl[$#ibody_ilvl])) . shift; eibody $text; } sub piboth { my $text = shift; pispec $text; pibody $text; } sub pspecs { my $text = shift; pspec $text; pispec $text; } sub pbodies { my $text = shift; pbody $text; pibody $text; } sub pall { my $text = shift; pspecs $text; pbodies $text; } sub specindent { pspec shift; $spec_ilvl[$#spec_ilvl]++; } sub specdedent { $spec_ilvl[$#spec_ilvl]--; pspec shift; } sub print_specfile_prologue { my $pkgname = shift; pspec "----------------------------------------------------------------\n"; pspec "-- WARNING: This is generated Ada source that is automatically\n"; pspec "-- overwritten when idl2ada.pl is run.\n"; pspec "-- Changes to this file will be lost.\n"; pspec "----------------------------------------------------------------\n"; pspec "\n\n"; pspec "with CORBA.Object;\n"; pspec "with CORBA.Trader;\n"; pspec "with CORBA.InterfaceDef;\n"; pspec "with CORBA.ImplementationDef;\n\n"; } sub print_bodyfile_prologue { my $pkgname = shift; pbody "----------------------------------------------------------------\n"; pbody "-- WARNING: This is generated Ada source that is automatically\n"; pbody "-- overwritten when idl2ada.pl is run.\n"; pbody "-- Changes to this file will be lost.\n"; pbody "----------------------------------------------------------------\n"; pbody "\n\n"; pbody "with CORBA.Environment;\n"; pbody "with System;\n"; pbody "with Interfaces.C.Strings;\n"; pbody "with Interfaces.C;\n\n"; } sub print_ispecfile_prologue { my $pkgname = shift; pispec "----------------------------------------------------------------\n"; pispec "-- $pkgname\.Impl (spec)\n"; pispec "--\n"; pispec "-- Changes to this file will not be overwritten by idl2ada.pl\n"; pispec "----------------------------------------------------------------\n"; pispec "\n\n"; } sub print_ibodyfile_prologue { my $pkgname = shift; pibody "----------------------------------------------------------------\n"; pibody "-- $pkgname\.Impl (body)\n"; pibody "--\n"; pibody "-- Changes to this file will not be overwritten by idl2ada.pl\n"; pibody "----------------------------------------------------------------\n"; pibody "\n\n"; pibody "with CORBA.Environment;\n"; pibody "with System.Address_To_Access_Conversions; \n"; pibody "with Interfaces.C.Strings;\n"; pibody "with Ada.Characters.Latin_1; \n"; pibody "with CORBA.C_Memory;\n"; pibody "with Interfaces.C;\n\n"; } sub print_withlist { if (@withlist) { print $psfh "with"; my $first = 1; foreach $w (@withlist) { if ($first) { $first = 0; } else { print $psfh ','; } print $psfh (' ' . $w); } print $psfh ";\n\n"; } } sub print_pkg_prologues { my $pkgname = shift; my $is_module = 0; if (@_) { $is_module = shift; } push @spec_ilvl, 0; push @body_ilvl, 0; print_specfile_prologue($pkgname, $is_module); print_bodyfile_prologue($pkgname, $is_module); if (! $is_module) { if ($gen_ispec[$#scopestack]) { push @ispec_ilvl, 0; print_ispecfile_prologue($pkgname); } if ($gen_ibody[$#scopestack]) { push @ibody_ilvl, 0; print_ibodyfile_prologue($pkgname); } } print_withlist; push @withlist, $pkgname; } sub print_pkg_decl { my $name = shift; specindent "package $name is\n\n"; pbody "package body $name is\n\n"; $body_ilvl[$#body_ilvl]++; if ($gen_ispec[$#scopestack]) { pispec "package $name\.Impl is\n\n"; $ispec_ilvl[$#ispec_ilvl]++; } if ($gen_ibody[$#scopestack]) { pibody "package body $name\.Impl is\n\n"; $ibody_ilvl[$#ibody_ilvl]++; } } sub finish_pkg_decl { my $name = shift; my $spartan = 0; if (@_) { $spartan = 1; } specdedent "end $name;\n\n"; $body_ilvl[$#body_ilvl]--; pbody "end $name;\n\n"; close $psfh; close $pbfh; if ($spartan) { return; } pop @spec_ilvl; pop @body_ilvl; if ($gen_ispec[$#scopestack]) { $ispec_ilvl[$#ispec_ilvl]--; pispec "end $name\.Impl;\n\n"; close $isfh; pop @ispec_ilvl; } if ($gen_ibody[$#scopestack]) { $ibody_ilvl[$#ibody_ilvl]--; pibody "end $name\.Impl;\n\n"; close $ibfh; pop @ibody_ilvl; } pop @scopestack; if (@scopestack) { $psfh = $proxy_spec_file_handle[$#scopestack]; $pbfh = $proxy_body_file_handle[$#scopestack]; if ($gen_ispec[$#scopestack]) { $isfh = $impl_spec_file_handle[$#scopestack]; } if ($gen_ibody[$#scopestack]) { $ibfh = $impl_body_file_handle[$#scopestack]; } } } sub print_spec_interface { my $iface = shift; my $ancestor = shift; # specindent "package $iface is\n\n"; pspec "type Ref is new "; if (@{$ancestor}) { espec ${$ancestor}[$CORBA::IDLtree::NAME]; } else { espec "CORBA.Object.Ref"; } espec " with null record;\n\n"; pspec "Typename : constant CORBA.String := CORBA.To_Unbounded_String ("; espec "\"$iface\");\n\n"; pspec "-- Narrow/Widen functions\n"; pspec "--\n"; pspec "function To_Ref (From: in CORBA.Object.Ref'CLASS) return Ref;\n"; pspec "function To_Ref (From: in CORBA.Any) return Ref;\n"; pspec "\n"; pspec "-- CW/Ada specific functions\n"; pspec "function Import (Trader : CORBA.Trader.Ref;\n"; pspec " Context : CORBA.String;\n"; pspec " Propbuf : CORBA.String) return Ref;\n"; pspec "function Get_Interface return CORBA.InterfaceDef.Ref;\n"; pspec "function Get_Implementation return CORBA.ImplementationDef.Ref;\n"; pspec "\n"; } sub print_body_interface { my $iface = shift; # pbody "package body $iface is\n\n"; # $body_ilvl[$#body_ilvl]++; pbody "function To_Ref (From: in CORBA.Any) return Ref is\n"; pbody " Temp: Ref;\n"; pbody "begin\n"; pbody " -- Not yet implemented\n"; pbody " -- \n"; pbody " return Temp;\n"; pbody "end To_Ref;\n"; pbody "\n\n"; pbody "function To_Ref (From: in CORBA.Object.Ref'CLASS) return Ref is\n"; pbody "begin\n"; pbody " return Ref (From);\n"; pbody "end To_Ref;\n"; pbody "\n\n"; pbody "function Import\n"; pbody " (Trader : in CORBA.Trader.Ref;\n"; pbody " Context : in CORBA.String;\n"; pbody " Propbuf : in CORBA.String)\n"; pbody " return Ref is\n"; pbody "begin\n"; pbody " return Ref'(CORBA.Trader.Import (Trader, Typename, Context, Propbuf)\n"; pbody " with null record);\n"; pbody "end Import;\n"; pbody "\n\n"; pbody "function Get_Interface return CORBA.InterfaceDef.Ref is\n"; pbody "\n"; pbody " procedure $iface\_Dispatcher (Attr: System.Address; Buf: System.Address);\n"; pbody " pragma Import (C, $iface\_Dispatcher, \"$iface\_Dispatcher\");\n"; pbody " Result: CORBA.InterfaceDef.Ref;\n"; pbody "\n"; pbody "begin\n"; pbody " CORBA.InterfaceDef.Set_C_Ref (Result, $iface\_Dispatcher'Address);\n"; pbody " return Result;\n"; pbody "end Get_Interface;\n"; pbody "\n\n"; pbody "function Get_Implementation return CORBA.ImplementationDef.Ref is\n"; pbody " Result : CORBA.ImplementationDef.Ref;\n"; pbody "begin\n"; pbody " CORBA.ImplementationDef.Set_C_Ref (Result, System.Null_Address);\n"; pbody " return Result;\n"; pbody "end Get_Implementation;\n"; pbody "\n\n"; } sub print_ispec_interface { my $iface = shift; my $ancestor = 0; if (@_) { $ancestor = shift; } # pispec "package $iface\.Impl is\n\n"; # $ispec_ilvl[$#ispec_ilvl]++; pispec "type Object is new "; if ( $ancestor and @{$ancestor}) { # multi-inheritance TBD eispec ${$ancestor}[$CORBA::IDLtree::NAME]; } else { eispec "CORBA.Object.Object"; } eispec " with private;\n\n"; } sub print_ibody_interface { my $iface = shift; # pibody "package body $iface\.Impl is\n\n"; # $ibody_ilvl[$#ibody_ilvl]++; # pibody "procedure Export\n"; # pibody " (Trader : in CORBA.Trader.Ref;\n"; # pibody " Context : in CORBA.String;\n"; # pibody " Propbuf : in CORBA.String;\n"; # pibody " Object : access Ref) is\n"; # pibody "begin\n"; # pibody " CORBA.Trader.Export (Trader, Typename, Context, Propbuf, Object);\n"; # pibody "end Export;\n"; # pibody "\n\n"; } sub print_interface_prologues { my $ancestor = shift; my $adaname = join ".", @scopestack; print_pkg_decl $adaname; print_spec_interface($adaname, $ancestor); print_body_interface $adaname; print_ispec_interface($adaname, $ancestor); print_ibody_interface $adaname; } sub open_files { my $name = shift; my $type = shift; push @scopestack, $name; my $basename = lc(join "-", @scopestack); my $specfile = $basename . ".ads"; my $bodyfile = $basename . ".adb"; $psfh = $proxy_spec_file_handle[$#scopestack]; $pbfh = $proxy_body_file_handle[$#scopestack]; open($psfh, ">$specfile") or die "cannot create file $specfile\n"; open($pbfh, ">$bodyfile") or die "cannot create file $bodyfile\n"; if ($type == $CORBA::IDLtree::INTERFACE) { my $ispecfile = $basename . "-impl.ads"; my $ibodyfile = $basename . "-impl.adb"; if (-e $ispecfile) { $gen_ispec[$#scopestack] = 0; } else { $isfh = $impl_spec_file_handle[$#scopestack]; open($isfh, ">$ispecfile") or die "cannot create $ispecfile\n"; $gen_ispec[$#scopestack] = 1; } if (-e $ibodyfile) { if ($gen_ispec[$#scopestack]) { print "$ispecfile does not exist, but $ibodyfile does\n"; print " => generating only $ispecfile\n"; } elsif ($verbose) { print "not generating $basename implementation files "; print "because they already exist\n"; } $gen_ibody[$#scopestack] = 0; } else { $ibfh = $impl_body_file_handle[$#scopestack]; open($ibfh, ">$ibodyfile") or die "cannot create $ibodyfile\n"; if (! $gen_ispec[$#scopestack]) { print "$ispecfile does exist, but $ibodyfile does not\n"; print " => generating only $ibodyfile\n"; } $gen_ibody[$#scopestack] = 1; } } print_pkg_prologues(join(".", @scopestack), $type == $CORBA::IDLtree::MODULE); } $globuf = ""; sub charlit { my $input = shift; my $pos = 0; if ($input !~ /^\\/) { $globuf = substr($input, $pos, 1); return 1; } my $ch = substr($input, ++$pos, 1); my $consumed = 2; my $output = ""; if ($ch eq 'n') { $output = '.LF'; } elsif ($ch eq 't') { $output = '.HT'; } elsif ($ch eq 'v') { $output = '.VT'; } elsif ($ch eq 'b') { $output = '.BS'; } elsif ($ch eq 'r') { $output = '.CR'; } elsif ($ch eq 'f') { $output = '.FF'; } elsif ($ch eq 'a') { $output = '.BEL'; } elsif ($ch eq 'x') { # hex number my $tuple = substr($input, ++$pos, 2); if ($tuple !~ /[0-9a-f]{2}/i) { $output = $ch; print "unknown escape \\x$tuple in string\n"; } else { $output = "'val (16#" . $tuple . "#)"; $consumed += 2; } } elsif ($ch eq '0' or $ch eq '1') { # octal number my $triple = substr($input, $pos, 3); if ($triple !~ /[0-7]{3}/) { $output = $ch; print "unknown escape \\$triple in string\n"; } else { $output = "'val (8#" . $triple . "#)"; $consumed += 2; } } else { $output = $ch; print("unknown escape \\$ch in string\n") if ($ch =~ /[0-9A-z]/); } $globuf = 'Ada.Characters.Latin_1' . $output; return $consumed; } sub cvt_expr { my $lref = shift; my $output = ""; foreach $input (@$lref) { # print "cvt input = $input\n"; my $ch = substr($input, 0, 1); if ($ch eq '"') { my $need_endquote = 1; $output .= '"'; my $i; for ($i = 1; $i < length($input) - 1; $i++) { my $consumed = charlit(substr($input, $i)); $i += $consumed - 1; if ($consumed > 1) { $output .= '" & '; } $output .= $globuf; if ($consumed > 1) { if ($i >= length($input) - 2) { $need_endquote = 0; } else { # We had an escape, and are not yet at the end, so # need to reopen the string $output .= ' & "'; } } } if ($need_endquote) { $output .= '"'; } } elsif ($ch eq "'") { my $consumed = charlit(substr($input, 1)); if ($consumed == 1) { $output .= " '" . $globuf . "'"; } else { $output .= " " . $globuf; } } elsif ($ch =~ /\d/) { if ($ch eq '0') { # check for hex/octal my $nxt = substr($input, 1, 1); if ($nxt eq 'x') { # hex const $output .= ' 16#' . substr($input, 2) . '#'; next; } elsif ($nxt =~ /[0-7]/) { # octal const $output .= ' 8#' . substr($input, 1) . '#'; next; } } $output .= ' ' . $input; } elsif ($ch eq '.') { $output .= '0' . $input; } elsif ($input =~ /;/) { print "where the hell does this semicolon come from ?!?\n"; } else { $output .= ' ' . $input; } } return $output; } sub check_sequence { my $type_descriptor = shift; my $scoperef = shift; if (! CORBA::IDLtree::isnode($type_descriptor)) { return mapped_type($type_descriptor, $scoperef); } my @node = @{$type_descriptor}; my $element_type = $node[$CORBA::IDLtree::SUBORDINATES]; my $eletypnam = mapped_type($element_type, $scoperef); if ($node[$CORBA::IDLtree::TYPE] != $CORBA::IDLtree::SEQUENCE) { return $eletypnam; } check_sequence($element_type, $scoperef); my $idltypnam = CORBA::IDLtree::typeof($element_type, $scoperef); $idltypnam =~ s/sequence<(.*)>/Seq_\1/; my $arrtypnam = "Seq_" . $idltypnam . "_Array"; pspec "type $arrtypnam is array (Integer range <>) of $eletypnam;\n"; my $bound = $node[$CORBA::IDLtree::NAME]; my $pkgname = "Seq"; if ($bound) { $pkgname .= "_" . $bound; } $pkgname .= "_" . $idltypnam; pspec "package $pkgname is new CORBA.Sequences."; espec(($bound ? "Bounded" : "Unbounded") . "\n"); $spec_ilvl[$#spec_ilvl] += $INDENT2; pspec "($eletypnam, $arrtypnam"; espec(", " . $bound) if ($bound); espec ");\n\n"; $spec_ilvl[$#spec_ilvl] -= $INDENT2; return($pkgname . ".Sequence"); } sub gen_ada_recursive { my $symroot = shift; if (! $symroot) { print "\ngen_ada: encountered empty elem (returning)\n"; return; } elsif (not ref $symroot) { print "\ngen_ada: incoming symroot is $symroot (returning)\n"; return; } if (not CORBA::IDLtree::isnode $symroot) { foreach $elem (@{$symroot}) { gen_ada_recursive $elem; } return; } my @node = @{$symroot}; my $name = $node[$CORBA::IDLtree::NAME]; my $type = $node[$CORBA::IDLtree::TYPE]; my $subord = $node[$CORBA::IDLtree::SUBORDINATES]; my @arg = @{$subord}; if ($type == $CORBA::IDLtree::TYPEDEF) { my $typeref = $arg[0]; my $dimref = $arg[1]; my $adatype = check_sequence($typeref, $subord); pspec "type $name is "; if ($dimref and @{$dimref}) { espec "array ("; my $is_first_dim = 1; foreach $dim (@{$dimref}) { if ($dim !~ /\D/) { # if the dim is a number $dim--; # then modify that number directly } else { $dim .= " - 1" ; # else leave it to the Ada compiler } if ($is_first_dim) { $is_first_dim = 0; } else { espec ", "; } espec("0.." . $dim); } espec ") of "; } else { espec "new "; } espec "$adatype;\n\n"; } elsif ($type == $CORBA::IDLtree::CONST) { pspec("$name : constant " . mapped_type($arg[0], $subord) . " := " . cvt_expr($arg[1]) . ";\n\n"); } elsif ($type == $CORBA::IDLtree::ENUM) { pspec("type $name is "); my $enum_literals = join(', ', @arg); if (length($name) + length($enum_literals) < 65) { espec "($enum_literals);\n\n"; } else { espec "\n"; my $first = 1; $spec_ilvl[$#spec_ilvl] += $INDENT2 - 1; foreach $lit (@arg) { if ($first) { pspec " ($lit"; $spec_ilvl[$#spec_ilvl]++; $first = 0; } else { espec ",\n"; pspec $lit; } } espec ");\n\n"; $spec_ilvl[$#spec_ilvl] -= $INDENT2; } } elsif ($type == $CORBA::IDLtree::STRUCT || $type == $CORBA::IDLtree::UNION || $type == $CORBA::IDLtree::EXCEPTION) { # First, generate array and sequence type declarations if necessary my $i = ($type == $CORBA::IDLtree::UNION ? 1 : 0); my @adatype = (); for (; $i <= $#arg; $i++) { my @node = @{$arg[$i]}; my $type = $node[$CORBA::IDLtree::TYPE]; next if ($type == $CORBA::IDLtree::CASE or $type == $CORBA::IDLtree::DEFAULT); push @adatype, check_sequence($type, $arg[$i]); my $dimref = $node[$CORBA::IDLtree::SUBORDINATES]; if ($dimref and @{$dimref}) { my $name = $node[$CORBA::IDLtree::NAME]; pspec("type " . $name . "_Array is array ("); my $is_first_dim = 1; foreach $dim (@{$dimref}) { if ($dim !~ /\D/) { # if the dim is a number $dim--; # then modify that number directly } else { $dim .= " - 1" ; # else leave it to the Ada compiler } if ($is_first_dim) { $is_first_dim = 0; } else { espec ", "; } espec("0.." . $dim); } espec(") of " . $adatype[$#adatype] . ";\n\n"); } } # Now comes the actual struct/union/exception my $need_end_record = 1; if ($type == $CORBA::IDLtree::EXCEPTION) { pspec "$name : exception;\n\n"; pspec "type $name\_Members is new CORBA.IDL_Exception_Members "; if (@arg) { espec "with record\n" } else { espec "with null record;\n\n"; $need_end_record = 0; } } else { pspec "type $name "; if ($type == $CORBA::IDLtree::UNION) { my $adatype = mapped_type(shift @arg, $subord); espec "(Switch : $adatype := $adatype\'first) "; } espec "is record\n"; } if ($need_end_record) { $spec_ilvl[$#spec_ilvl]++; my $had_case = 0; while (@arg) { my $node = shift @arg; my $name = $$node[$CORBA::IDLtree::NAME]; my $type = $$node[$CORBA::IDLtree::TYPE]; my $suboref = $$node[$CORBA::IDLtree::SUBORDINATES]; if ($type == $CORBA::IDLtree::CASE or $type == $CORBA::IDLtree::DEFAULT) { if ($had_case) { $spec_ilvl[$#spec_ilvl]--; } else { $had_case = 1; } if ($type == $CORBA::IDLtree::CASE) { pspec "when "; my $first_case = 1; foreach $case (@{$suboref}) { if ($first_case) { $first_case = 0; } else { espec "| "; } espec "$case "; } espec "=>\n"; } else { pspec "when others =>\n"; } $spec_ilvl[$#spec_ilvl]++; } else { pspec($name . " : " . shift(@adatype) . ";\n"); } } $spec_ilvl[$#spec_ilvl] -= $had_case; specdedent "end record;\n\n"; } if ($type == $CORBA::IDLtree::EXCEPTION) { pspec("procedure Get_Members (From : in " . "Ada.Exceptions.Exception_Occurrence;\n"); pspec " To : out $name\_Members);\n\n"; } } elsif ($type == $CORBA::IDLtree::INCFILE) { $name =~ s/\.idl//i; pspec "with $name;\n"; } elsif ($type == $CORBA::IDLtree::MODULE) { open_files($name, $type); my $adaname = join ".", @scopestack; print_pkg_decl $adaname; foreach $declaration (@arg) { gen_ada_recursive $declaration; } finish_pkg_decl $adaname; } elsif ($type == $CORBA::IDLtree::INTERFACE) { my $ancestor_ref = $arg[0]; open_files($name, $type); print_interface_prologues($ancestor_ref); # For each attribute, a private member variable will be added # to the implementation object type. my @attributes = (); foreach $decl (@{$arg[1]}) { gen_ada_recursive $decl; if (CORBA::IDLtree::isnode($decl) and ${$decl}[$CORBA::IDLtree::TYPE] == $CORBA::IDLtree::ATTRIBUTE) { push @attributes, $decl; } } if ($gen_ispec[$#scopestack]) { $ispec_ilvl[$#ispec_ilvl]--; pispec "private\n"; $ispec_ilvl[$#ispec_ilvl]++; pispec "type Object is new "; if (@{$ancestor_ref}) { my $first_ancestor_node = ${$ancestor_ref}[0]; eispec ${$first_ancestor_node}[$CORBA::IDLtree::NAME]; # multiple inheritance: TBD } else { eispec "CORBA.Object.Object"; } if (@attributes) { eispec " with record\n"; $ispec_ilvl[$#ispec_ilvl]++; foreach $attr_ref (@attributes) { my $name = ${$attr_ref}[$CORBA::IDLtree::NAME]; my $subord = ${$attr_ref}[$CORBA::IDLtree::SUBORDINATES]; my $typename = mapped_type(${$subord}[1], $subord); pispec "$name : $typename;"; eispec(" -- IDL: readonly") if (${$subord}[0]); eispec "\n"; } $ispec_ilvl[$#ispec_ilvl]--; pispec "end record;\n\n"; } else { pispec " with null record;\n\n"; } } finish_pkg_decl $adaname; } elsif ($type == $CORBA::IDLtree::ATTRIBUTE) { my $readonly = $arg[0]; my $typename = mapped_type($arg[1], $subord); pall "function Get_$name (Self : "; eboth "Ref"; eiboth "access Object"; eall ") return $typename"; especs ";\n"; ebodies " is\n"; pbodies "begin\n"; pbody " null; -- To Be Done\n"; pibody " return Self.$name;\n"; pbodies "end Get_$name;\n\n"; if ($readonly) { especs "\n"; return; } pall "procedure Set_$name (Self : "; eboth "Ref"; eiboth "access Object"; eall "; To : $typename)"; especs ";\n\n"; ebodies " is\n"; pbodies "begin\n"; pbody " null; -- To Be Done\n"; pibody " Self.$name := To;\n"; pbodies "end Set_$name;\n\n" } elsif ($type == $CORBA::IDLtree::METHOD) { my $rettype = shift @arg; if ($rettype == $CORBA::IDLtree::ONEWAY) { pspecs "-- oneway\n"; $rettype = $CORBA::IDLtree::VOID; } if ($rettype == $CORBA::IDLtree::VOID) { pall "procedure "; } else { pall "function "; } eall(sprintf "%-12s (Self : ", $name); eboth "in Ref"; eiboth "access Object"; if ($#arg > 0) { eall ";\n"; $spec_ilvl[$#spec_ilvl] += $INDENT2; $body_ilvl[$#body_ilvl] += $INDENT2; $ispec_ilvl[$#ispec_ilvl] += $INDENT2; $ibody_ilvl[$#ibody_ilvl] += $INDENT2; while ($#arg > 0) { my $pnode = shift @arg; my $ptype = mapped_type($$pnode[$CORBA::IDLtree::TYPE], $pnode); my $pname = $$pnode[$CORBA::IDLtree::NAME]; my $m = $$pnode[$CORBA::IDLtree::SUBORDINATES]; my $pmode = ($m == $CORBA::IDLtree::IN ? 'in' : $m == $CORBA::IDLtree::OUT ? 'out' : 'in out'); pall "$pname : $pmode $ptype"; eall(";\n") if ($#arg > 0); } $spec_ilvl[$#spec_ilvl] -= $INDENT2; $body_ilvl[$#body_ilvl] -= $INDENT2; $ispec_ilvl[$#ispec_ilvl] -= $INDENT2; $ibody_ilvl[$#ibody_ilvl] -= $INDENT2; } eall ")"; if ($rettype != $CORBA::IDLtree::VOID) { pall("\n return " . mapped_type($rettype, $subord)); } especs ";\n"; ebodies " is\n"; pbodies "begin\n"; pbody " null; -- To Be Done\n"; pibody " null; -- dear user, please fill me in\n"; pbodies "end $name;\n\n"; my @exc_list = @{shift @arg}; # last element in arg is exception list if (@exc_list) { pspecs "-- raises ("; foreach $exc (@exc_list) { especs(${$exc}[$CORBA::IDLtree::NAME] . " "); } especs ")\n"; } especs "\n"; } else { print "gen_ada: unknown type value $type\n"; } } sub gen_ada { my $symtree = shift; my $seen_global_scope = 0; @withlist = (); if (CORBA::IDLtree::isnode $symtree) { my $type = ${$symtree}[$CORBA::IDLtree::TYPE]; my $name = ${$symtree}[$CORBA::IDLtree::NAME]; if ($type != $CORBA::IDLtree::MODULE and $type != $CORBA::IDLtree::INTERFACE) { print "$name: expecting MODULE or INTERFACE\n"; return; } $did_file_prologues = 0; gen_ada_recursive $symtree; return; } elsif (not ref $symtree) { print "\ngen_ada: unsupported declaration $symtree (returning)\n"; return; } foreach $noderef (@{$symtree}) { my $type = ${$noderef}[$CORBA::IDLtree::TYPE]; my $name = ${$noderef}[$CORBA::IDLtree::NAME]; my $suboref = ${$noderef}[$CORBA::IDLtree::SUBORDINATES]; $did_file_prologues = 0; if ($type == $CORBA::IDLtree::MODULE or $type == $CORBA::IDLtree::INTERFACE) { gen_ada_recursive $noderef; } elsif ($type == $CORBA::IDLtree::INCFILE) { my @incnodes = @{$suboref}; if ($#incnodes > 0) { print("includefile $name: idl2ada.pl does not support " . "multiple file scoped declarations.\n"); print("Please put all declarations inside a single " . "MODULE or INTERFACE\n"); } elsif (not CORBA::IDLtree::isnode($incnodes[0])) { print("includefile $name: idl2ada.pl does not support " . "file scoped declarations.\n"); print("Please put all declarations inside a MODULE or " . "INTERFACE\n"); } else { my $inner_type = ${$incnodes[0]}[$CORBA::IDLtree::TYPE]; if ($inner_type != $CORBA::IDLtree::MODULE and $inner_type != $CORBA::IDLtree::INTERFACE) { print("enclosing definition in $name must be either a " . "MODULE or INTERFACE\n"); } else { push @withlist, ${$incnodes[0]}[$CORBA::IDLtree::NAME]; } } } else { if (not $seen_global_scope) { $global_scope_pkgname = $idl_filename; $global_scope_pkgname =~ s/\.idl$//; $global_scope_pkgname =~ s/\W/_/g; $global_scope_pkgname .= "_IDL_File"; open_files($global_scope_pkgname, $CORBA::IDLtree::MODULE); ############################################################### # Remove myself from the scope stack so that modules/interfaces # defined in this file will not be children of ..._IDL_File. pop @scopestack; ############################################################### print_withlist; print_pkg_decl $global_scope_pkgname; $seen_global_scope = 1; } gen_ada_recursive $noderef; } } if ($seen_global_scope) { finish_pkg_decl($global_scope_pkgname, 1); } } # The End.