
DrZed
User
Jul 9, 2000, 7:42 AM
Post #1 of 4
(306 views)
|
|
I'm having trouble with references...
|
Can't Post
|
|
Ultra short version, since the forum keeps refreshing and I've typed a verbose version twice now: I want to create a data structure from a reference being passed. For example: sub x { my ($ref) = shift; $ref->[0] = "One"; $ref->[1] = "Two"; $ref->[2] = "Three"; } &x($r); # $r->[0] eq "One" I run into problems such as: Not an ARRAY reference at dzlib-io.cgi line 278 It seems like the reference is already typed. Would something like the following be stable: sub x { my ($ref); my (@a) = ("One","Two","Three"); $ref=\@a; return $ref } $r=&x; # $r->[0] eq "One" The above looks like a bad idea, since $r will point to @a, which no longer exists. However, taking a reference which is undefined and assigning values to it seems to work most but not all of the time. If your interested, here are the functions I'm working with <BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR> ################################################################ # DATA TO TEXT # # Usage: # &data_to_text($DATA_REFERENCE) # Description: # This subroutine returns the data refered to by # $DATA_REFERENCE in a formatted text structure. It will # parse complex data sctructures, but can only parse the # following types: SCALAR, ARRAY, HASH, REF. It will not # parse, for example, CODE and GLOB. # Parameters: # $DATA_REFERENCE # A pointer to any type of data structure that does # not contain a glob. The data structure can be # either simple or complex. # Internal parameters # The code also uses a number of internal parameters. # These parameters are not designed to recieve data # from outside calls. They are used during recursion. # Result: # The data is returned in a format designed to be accessable # to text editors as well as to be loaded by the # &text_to_data subroutine. # # References to external (to the data structure) variables: # While data referenced will be saved and can therefore be # loaded, if the REF referenced another data structure, the # reference will NOT reference the other data structure upon # being loaded. # # For example, if the data structure referenced an array # named @colors. After saving and loading the data, the # reference would reference an array with the same values as # @colors. However, changes to @colors would be INDEPENDANT # of changes to the reference. # # It would be possible to enchance this routine to allow for # external references to be maintained. To do so, it would # require any potentially referenced variables to have their # names passed so that it could check for references to # their addresses and record the variable's name. This has # NOT be done. # # References to internal (to the data structure) variables: # In the event that the REF referenced part of the data # structure already parsed, it will note the internal # reference and it will not duplicate the data. This will # also prevent an infinite loop from forming in the instance # where a data structure references itself. # sub data_to_text { my (%main_occ); my ($r,$h,$occ_ref) = (shift,shift | | "",shift | | \%main_occ); my ($type) = ref($r); my ($addr) = scalar($r) | | "UNDEF"; my ($ret); sub leading_header { my ($data,$header) = (shift,shift); $data.="\n"; $data =~ s|^|$header|gm; return $data; } $h=~s/ /\t/; if (defined($occ_ref->{$addr})) { $ret = "$h|$addr\n"; $occ_ref->{$addr} = 2; } else { $ret = "$h<$type:$addr>\n"; $occ_ref->{$addr} = 1; if ($type eq "SCALAR") { $ret .= &leading_header($$r,"$h |"); } elsif ($type eq "ARRAY") { foreach (@$r) { $ret .= &data_to_text(\$_,"$h ",$occ_ref); } } elsif ($type eq "HASH") { my ($key); foreach $key (keys %$r) { $ret .= "$h <SCALAR>\n"; $ret .= &leading_header($key,"$h |"); $ret .= "$h </SCALAR>\n"; $ret .= &data_to_text(\$r->{$key},"$h ",$occ_ref); } } elsif ($type eq "REF") { $ret .= &data_to_text($$r,"$h ",$occ_ref); } elsif ($type eq "") { $ret .= "$h UNDEFINED\n"; } else { $ret .= "$h TYPE NOT SUPPORTED: <$type>\n"; } $ret .= "$h</$type>\n"; } if ($h eq "") { # Strip out addresses that are not duplicated. e.g. <SCALAR:SCALAR(0xba6f74)> -> <SCALAR> $ret =~ s!^(\s*<\w+) .+)>!($occ_ref->{$2} == 2)?("$1:$2>") "$1>")!gem; # Reduce tags for single line values. # e.g. the following.... # <SCALAR> # |One liner. # </SCALAR> # .... would become the following.... # <SCALAR=One liner.> # If there's a shared address, it would be as follows: # <SCALAR:SCALAR(0xba6f74)=One liner.> $ret =~ s!^(\s*<(\w+)[\:.+]?)>\n\s*\|(.*)\n\s*</\2>!$1=$3>!gm; } return $ret; } ################################################################ ################################################################ # TEXT TO DATA # # Usage: # &text_to_data($DATA_REFERENCE, $TEXT_REFERENCE) # Description: # This subroutine parses the text referenced by # $TEXT_REFERENCE and creates the data structure encoded in # the text using the variable referenced by $DATA_REFERENCE. # It can parse complex data structures, but can only parse # the following types: SCALAR, ARRAY, HASH, REF. It will # not parse, for example, CODE and GLOB. # Parameters: # $DATA_REFERENCE # A reference to the variable to be assigned a value. # The variable referenced will be type checked, but # the type checking will rely on the existance of the # &diag routine. # $TEXT_REFERENCE # A reference to the text to be parsed. This text is # passed using a reference to avoid making multiple # copies for each recursion of what will probably be # large amounts of text. # Internal parameters # The code also uses a number of internal parameters. # These parameters are not designed to recieve data # from outside calls. They are used during recursion. # Result: # The result is a data structure based on the recieved text. # # References to external (to the data structure) variables: # While data referenced will be loaded, if the REF # originally referenced another data structure outside of # the data structure referenced, the reference will NOT # reference the other data structure upon being loaded. # # For example, if the data structure referenced an array # named @colors. After saving and loading the data, the # reference would reference an array with the same values as # @colors. However, changes to @colors would be INDEPENDANT # of changes to the reference. # # It would be possible to enchance this routine to allow for # external references to be maintained. To do so, it would # require any potentially referenced variables to have their # names passed so that it could check for references to # their addresses and record the variable's name. This has # NOT be done. # # References to internal (to the data structure) variables: # In the event that the REF referenced part of the data # structure already parsed, it will note the internal # reference and it will not duplicate the data. # sub text_to_data { my (%main_occ,@main_lines); my ($data_ref,$text_ref) = (shift,shift); my ($occ_ref,$lines_ref) = (shift | | \%main_occ, shift | | &split_into_lines($text_ref,\@main_lines)); my ($line_count) = (shift | | $#{$lines_ref}); sub split_into_lines { my ($sil_text_ref,$sil_lines_ref) = @_; @{$sil_lines_ref} = split (/\n/,${$sil_text_ref}); return $sil_lines_ref } my ($line) = shift(@{$lines_ref}); if ($line =~ m/^\s*<(\w+)( \w+\(\w+\)))?(=(.+))?>$/) { my ($type) = $1; my ($addr) = $3; my ($value) = $5; #&dzlib_io_error("LINE=$line; TYPE=$type; ADDR=$addr; VALUE=$value; ref()=",ref($data_ref)); # Check type vs. reference if ( ( $type ne ref($data_ref) ) && ( ( $type ne "REF" ) | | ( ref($data_ref) ne "SCALAR" ) ) ) { dzlib_io_error(qq{Mismatched data types. Expected: },ref($data_ref),qq{ Recieved: $type Line number: },($line_count-$#{$lines_ref})); } # If the address of the data structure is defined, # note the reference to the data in the hash referenced by $occ_ref. if (defined($addr)) { $occ_ref->{$addr} = $data_ref; } # If the value was in the tag (i.e. it's a one-liner), # then $value is already set. Otherwise, set it by # reading multiple lines. my ($entry); if (!defined($value)) { if ($type eq "ARRAY") { while ($lines_ref->[0] !~ m|^\s*</|) { &text_to_data(\$entry,$text_ref,$occ_ref,$lines_ref,$line_count); push(@{$data_ref},$entry); } } elsif ($type eq "HASH") { while ($lines_ref->[0] !~ m|^\s*</|) { &text_to_data(\$value,$text_ref,$occ_ref,$lines_ref,$line_count); &text_to_data(\$entry,$text_ref,$occ_ref,$lines_ref,$line_count); $data_ref->{$value}=$entry; } } elsif ($type eq "REF") { my ($ref); &text_to_data(\$ref,$text_ref,$occ_ref,$lines_ref,$line_count); ${$data_ref} = \$ref; } elsif ($type eq "SCALAR") { $value=""; $line = shift(@{$lines_ref}); while ( $line =~ m/^\s*\|/ ) { $value.="$'\n"; $line = shift(@{$lines_ref}); } chomp($value); if ($line !~ m|^\s*</$type>$|) { $line =~ m/^\s*(.*)/; dzlib_io_error(qq{Improper close of data text. Expected: </$type> Recieved: $1 Line number: },($line_count-$#{$lines_ref})); } ${$data_ref}=$value; } else { dzlib_io_error("Invalid type: $type"); } } else { if ($type eq "ARRAY") { dzlib_io_error("Invalid direct assignment of an array.\n$line"); } elsif ($type eq "HASH") { dzlib_io_error("Invalid direct assignment of a hash.\n$line"); } elsif ($type eq "REF") { ${$data_ref}=$occ_ref->{$value}; } elsif ($type eq "SCALAR") { ${$data_ref}=$value; } else { dzlib_io_error("Invalid type: $type\nValue: $value"); } } } else { dzlib_io_error(qq{Improper start of data text. Recieved: $line Line number: },($line_count-$#{$lines_ref})); } } ################################################################ </pre><HR></BLOCKQUOTE>
|