From: srivasta@pilgrim.umass.edu (Manoj Srivastava)
Newsgroups: comp.lang.perl
Subject: [Question] Indirection
Keywords: glob,pointer.star value
Date: 4 Jan 93 19:05:42 GMT
Reply-To: srivasta@pilgrim.umass.edu
Organization: University of Massachusetts at Amherst


Hi,

	I have  a  question  about the  best  way  to  do address  the
following problem. I am parsing a set of object  specifications, where
an object could have a number of tuples of the  form (attribute value)
which I'd like  to place in  an associative  array, and it also has  a
list of other objects, which I place in an simple array.

	The  actual  parsing  is  done by  an  automatically generated
subroutine,  &yyparse, which modifies the global entities  %Attribute,
and  @Object  list.  I'd like  the outer level routine,  parse_obj (),
(which is recursively called  on  object list) to place  these  into a
form which can beaccessed by the name of the object.

	The way I see it, I have two options, firstly (Shamelessly
 copied from Tom Christiansen's article of 24 Jul 91 01:56:10 GMT Re:
 possibly novice associative array query) of using an associative
 array of uniquely named packages, keyed by object name, and use eval
 to create the package. (I think I understand how this works, I'm
 appending the code from Tom's posting at the end of this article; I'm
 still hazy about what those type globs are doing). The second option
 is to set up uniquely named arrays and use type globbing; like so:

sub parse_obj {
	local ($obj_name) = @_;

	...
	undef %Attribute;
	undef @Object;
	&yyparse;
	local ($code)=<<EOF;
	foreach \$key (keys \%Attribute){
		\$$obj_name{\$key} = \$Attribute{\$key};
	}
	foreach \$key (\@Object){
		push (\@$obj_name, \$key);
	}
	\$Global_attrs{\$$obj_name} = *$obj_name;
EOF
	eval $code;
	...
}

	And now I can set a pointer to reference the objects, as

	*ptr =  $Global_attrs{$obj_name};
	print "@ptr";
    	....

	Is there any other way to do this?  (Hah! this is perl.  there
_has  _ to be one).

Also, I'd appreciate an explanation of the lines like *'Current_Folder
= *Current_Folder; in  the  code snippet below, like  *'Current_Folder
referes to the current package,  right?  and what  would happen if the
refered value  changes?  (I'm sorry,  but  to me these look  like  C's
pointers, and if the referenced values change,  the  effect is noticed
by any alias reference).

In other words, if I type glob *new = *old, and then change $old, will
$new  change? If  this  is so,  then any solution to my  problem would
require a copying step,  since  yyparse keeps modifying %Attribute and
and @Object.

	manoj

Quote feom tchrist@convex.COM (Tom Christiansen)'s article dated
 24 Jul 91 01:56:10 GMT with 
Subject: Re: possibly novice associative array query

Tom> Let me discuss in brief two other strategems for magaging complex
Tom> data structures in perl.

Tom> The first is employed by the &activate_folder routine in plum.
Tom> Basically,  I want to keep around an associative array of active
Tom> folders (actually, active folder sequences).  Each active folder
Tom> has a bunch of properties of varying associated with it, such as
Tom> its cache's last mtime, all the line from scan, the mappings
Tom> between message ids to scan line indices, etc.

Tom> In C, the natural thing to do would be to use an array of
Tom> structures.  In perl, we must be sneakier than that.  What I've
Tom> done is selected an associative array called %Active_Folders; the
Tom> keys are the folder names, and the values are not pointers to
Tom> individual variables, but rather the names of UNIQUELY NAMED
Tom> PACKAGES in which all variables associated with the folder.  When
Tom> I activate one, I set the current pointers equal to the hidden
Tom> ones, and then normal variable references continue to work.
Tom> Since only one folder can be considered active (viewed) at any
Tom> given moment,  this works well.

Tom> Here's the trimmed-down routine:

Tom>     $gensym = 'a';

Tom>     sub gensym { 'gensym_' . $gensym++; }

Tom>     sub activate_folder {
Tom>         local($folder) = @_;

Tom>         &assert('$folder',$folder);

Tom>         $Last_Seq = $Current_Seq;

Tom>         $Active_Folders{$folder} = &gensym
Tom>             unless defined $Active_Folders{$folder};

Tom>         local($package) = $Active_Folders{$folder};

Tom>         # warning: it is important that any of these aggregate vars
Tom>         # get clearedinstead of undeffed.  otherwise you may get
Tom> 	      # a coredump.

Tom>         local($code)=<<"EOF";
Tom>             {
Tom>                 package $package;
Tom>                 *'Current_Folder    = *Current_Folder;
Tom>                 *'Current_Seq       = *Current_Seq;
Tom>                 *'Current_Line      = *Current_Line;
Tom>                 *'Top_Line          = *Top_Line;
Tom>                 *'Scan_Lines        = *Scan_Lines;
Tom>                 *'Scan_IDs          = *Scan_IDs;
Tom>                 *'Incomplete_Read   = *Incomplete_Read;
Tom>                 *'Folder_Cache_Time = *Folder_Cache_Time;
Tom>                 *'Last_Typed        = *Last_Typed;
Tom>                 *'Deleted           = *Deleted;
Tom>             }
Tom>     EOF
Tom>         eval $code;
Tom>         $Current_Seq = $folder;

Tom>         &panic("bad eval: $@\n$code\n") if $@;
Tom>     }

Tom> The typed variables I use are:

Tom>      $Current_Folder
Tom>      $Current_Seq
Tom>      $Current_Line
Tom>      $Top_Line
Tom>      @Scan_Lines
Tom>      %Scan_IDs
Tom>      $Incomplete_Read
Tom>      $Folder_Cache_Time
Tom>      $Last_Typed
Tom>      %Deleted
Tom>      $Deleted

Tom> In certain ways, the pseudo-anonymous packages provided by &gensym
Tom> are the key to this entire scheme.


	
Newsgroups: comp.lang.perl