<?xml version="1.0" encoding="windows-1252"?>
<node id="92509" title="Undumper" created="2001-06-29 00:58:17" updated="2005-08-11 05:55:15">
<type id="1748">
sourcecode</type>
<author id="58729">
ton</author>
<data>
<field name="doctext">
&lt;CODE&gt;
#####
# Package: Undumper
# Author: Ton Sistos
#
# Usage:
# 
# my $undumper = Undumper-&gt;new();
# my $string = my &lt;&lt;'_EOSTRING_';
# {
#  '1' =&gt; {string=&gt;"hello"}, 
#  '2' =&gt; [2,4,6,[0,3],[1,2]], 
#  bar =&gt; [1, 2, { this =&gt; 'that', 5, "world"}, baz],
#  5, 4.023421, 
#  'foo', "hello world"
# }
# _EOSTRING_
# my $struct = $undumper-&gt;Undump($string) or die "Bad string";
#####
package Undumper;

use Parse::RecDescent;
use strict;
use vars qw($grammar);

# Enable warnings within the Parse::RecDescent module.

$::RD_ERRORS = 1; # Make sure the parser dies when it encounters an error
$::RD_WARN   = 1; # Enable warnings. This will warn on unused rules &amp;c.
$::RD_HINT   = 1; # Give out hints to help fix problems.


$grammar = &lt;&lt;'_GRAMMAR_';
    { my $u = '^%$&amp;undef&amp;$*!'; }

    # Terminals first
    INTEGER : /[-+]?\d+/
            { $return = int($item[1]); }
    FLOAT : /[-+]?\d*\.\d+[eE][-+]?\d+/
          | /[-+]?\d+\.\d*[eE][-+]?\d+/
          | /[-+]?\d*\.\d+/
    STRING : /"((.*?(\\\\)*(\\")*)*?)"/s
           { $return = $1; $return =~ s/\\"/"/g; $return =~ s/\\\\/\\/g; }
           | /'((.*?(\\\\)*(\\')*)*?)'/s
           { $return = $1; $return =~ s/\\'/'/g; $return =~ s/\\\\/\\/g; }
    SIMPLESTRING : /[a-zA-Z]\w*/

    term : FLOAT
         | INTEGER
         | STRING
         | SIMPLESTRING

    goodterm : FLOAT
             | INTEGER
             | STRING

    anystring : STRING
              | SIMPLESTRING
    
    hashpair : goodterm ',' expression
             { $return = [$item[1], $item[3] eq $u ? undef : $item[3]]; }
             | term '=&gt;' expression
             { $return = [$item[1], $item[3] eq $u ? undef : $item[3]]; }
    
    arraylist : expression ',' arraylist
              { $return = [$item[1] eq $u ? undef : $item[1], @{$item[3]}]; }
              | expression ','
              { $return = [$item[1] eq $u ? undef : $item[1]]; }
              | expression
              { $return = [$item[1] eq $u ? undef : $item[1]]; }
    
    hashlist : hashpair ',' hashlist
             { $return = [@{$item[1]}, @{$item[3]}]; }
             | hashpair ','
             { $return = $item[1]; }
             | hashpair
             { $return = $item[1]; }
    
    array : '[' arraylist ']'
          { $return = $item[2]; }
          | '[' ']'
          { $return = []; }
    
    hash : '{' hashlist '}'
         { $return = { @{$item[2]} };  }
         | '{' '}'
         { $return = {}; }

    object : 'bless' '(' primitive ',' anystring ')'
           { $return = bless($item[3], $item[5]); }

    primitive : hash
              | array
              | term

    expression : object
               | 'undef'
               { $return = $u; }
               | primitive
        
    startrule : expression
              { $return = (($text =~ m/^[\s;]*$/) ? ($item[1] eq $u ? undef : $item[1]) : undef); }

_GRAMMAR_

sub new($$)
{
    my $invocant = shift;
    my $paramHRef = shift;
    my $class = ref($invocant) || $invocant;   # object or class name
    my $self = { };
    bless($self, $class);
    $self-&gt;_Initialize();
    return $self;
}

sub Undump($$)
{
    my $self = shift;
    my $string = shift;
    return $self-&gt;{'parser'}-&gt;startrule($string);
}

sub _Initialize($)
{
    my $self = shift;
    my $parser = Parse::RecDescent-&gt;new($grammar);
    $self-&gt;{'parser'} = $parser;
}
&lt;/CODE&gt;</field>
<field name="codedescription">
[Data::Dumper] is a great utility that converts Perl structures into eval-able strings.  These strings can be stored to text files, providing an easy way to save the state of your program.&lt;P&gt;
Unfortunately, evaling strings from a file is usually a giant security hole; imagine if someone replaced your stucture with system("rm -R /"), for instance.  This code provides a non-eval way of reading in [Data::Dumper] structures.&lt;P&gt;
Note: This code requires [Parse::RecDescent].&lt;P&gt;

&lt;B&gt;Update:&lt;/B&gt; Added support for blessed references.&lt;BR&gt;
&lt;B&gt;Update:&lt;/B&gt; Added support for undef, for structures like &lt;CODE&gt;[3, undef, 5, [undef]]&lt;/CODE&gt;.  Note that the undef support is extremely kludgy; better implementations would be much appreciated!&lt;BR&gt;
&lt;B&gt;Update2:&lt;/B&gt; Swapped the order of FLOAT and INTEGER in 'term' and 'goodterm' productions.  FLOAT &lt;EM&gt;must&lt;/EM&gt; come before INTEGER, otherwise it will never be matched!</field>
<field name="codecategory">
Text Processing</field>
<field name="codeauthor">
Ton Sistos&lt;BR&gt;
antonio@moonlight.com</field>
</data>
</node>
