use IO::File; my (%classes, %graph); read_classes(IO::File->new("test.ppl"), \%classes); read_graph(IO::File->new("test.gr"), \%graph); use Data::Dumper; print Dumper \%classes; print Dumper \%graph; sub read_classes { my ($input, $classes) = @_; while (1) { chomp(my $proto = <$input>); return unless $proto; my ($class_state, @args) = split /\s/, $proto; my $code = ""; while (1) { my $line = <$input>; last if !$line || $line =~ /^$/s; $code .= $line; } my %arg_type_by_name; for my $arg (@args) { my ($arg_type, $arg_name) = $arg =~ /^([<>\.])(\w+)$/; die "invalid argument $arg" unless defined $arg_name; $arg_type_by_name{$arg_name} = $arg_type; } my $args = join ' ', map "$arg_type_by_name{$_}$_", sort keys %arg_type_by_name; $classes->{$class_state}{$args} = $code; } } sub read_graph { my ($input, $graph) = @_; # read instances while (1) { chomp (my $decl = <$input>); last unless $decl; my ($instance, $class_state) = split /\s/, $decl; $graph->{$instance} = bless {}, $class_state; # make an instance? } # read links while (1) { chomp (my $link = <$input>); last unless $link; my @nodes = split /\s=\s/, $link; my $value; # the last term can be the name of an instance, a literal, or a normal term if ($nodes[-1] =~ /^[a-zA-Z]\w*(\.[a-zA-Z]\w*)+$/) { } elsif ($nodes[-1] =~ /^[a-zA-Z]\w*$/) { # must be an instance $value = $graph->{pop @nodes}; } else { # must be a literal $value = eval pop @nodes; } for my $node (@nodes) { my ($instance, $arg) = split /\./, $node; $graph->{$instance}{$arg} = \$value; } } }