문제

I am writing some code for an automated theorem prover. I wanted to implement an option for the user to pass a file on the cmd line and have it operate in batch mode.

Here is the code to parse the file and fill the @clauses array.

# batch mode
if ($ARGV[0]) {

  my $filename = $ARGV[0];

  open(IN, "<", $filename);
  chomp(@clauses = <IN>);
  $conclusion2 = $clauses[@clauses - 1];

  # set sos as negated conclusion
  $SOS[0][0] = $conclusion2;

  # negate the negation to get the desired conclusion for later
  @conclusion = split(undef, $conclusion2);

  # look for a ~, remove it if you find it, add one if you don't
  for (my $i = 0 ; $i < @conclusion ; $i++) {

    # while you're at it.....
    # get rid of spaces and anything that isn't a ~ or letter
    $conclusion[$i] =~ s/( |[^A-Za-z~])//;
    if ($conclusion[$i] eq '~') {
      splice(@conclusion, $i, 1);
      $i--;
      $found = 1;
    }
  }

  if (!$found) {
    $conclusion = "~$conclusion2";
  }
  else {
    $conclusion = join(undef, @conclusion);
  }

  # now break up each line and make @clauses 2d
  for (my $a = 0 ; $a < @clauses ; $a++) {
    my $str = $clauses[$a];
    my @tmp = split(',', $str);
    for (my $b = 0; $b < @tmp; $b++) {
      $clauses[$a][$b] = $tmp[$b];       # ERROR HERE
    }
  }

  #       for(my $i=0; $i<@clauses;$i++)
  #       {
  #               print "$i";
  #               for(my $b=0; $b<=@{@clauses};$b++)
  #               {
  #                       print "$clauses[$a][$b]";
  #               }
  #               print "\n";
  #       }
}

I'm putting in more than I really need to, but the troublesome part is when I'm trying to break up the lines of the file by the commas and make the array two-dimensional.

At the line I have marked I get the error

Can't use string ("a,b,c") as an ARRAY ref while "strict refs" in use

The input file is set up like this

a,b,c
b,~c
~b
~a

This would be a proof to prove that a must be true

It's weird, because in the code for the interactive section, I do the exact same thing, almost verbatim and it works perfectly.

EDIT I'm certain that somehow, the error lies within this line

$clauses[$a][$b] = $tmp[$b];

the error message is as follows:

can't use string ("a,b,c") as ARRAY ref while strict refs in use.

I don't see the need for any dereferencing on my part so what could the problem be?

도움이 되었습니까?

해결책

You should really show as much of your program as possible, as it is hard to see the scope of the variables that you don't declare.

I can assure you that, if you have use warnings in place as you should, then split undef will cause the warning

Use of uninitialized value in regexp compilation

The problem is that you have set

$clauses[$a] = "a,b,c";
@tmp = ('a', 'b', 'c');

You then try to do

$clauses[$a][$b] = $tmp[$b] for 0 .. 2

but $clauses[$a] is a string, not an array reference. It is the same as writing

"a,b,c"[$b] = $tmp[$b] for 0 .. 2

which makes no sense. Hence the error message Can't use string ("a,b,c") as an ARRAY ref.

A trivial fix would be to write

$clauses[$a] = undef;

immediately after

my $str= $clauses[$a]

so that the array element is now undefined, and Perl can autovivify an anonymous array here when the elements are copied.

However your code could use a little more work, so here is a version that does what I think you want. I have dumped the values of @clauses and $conclusion at the end to show their contents

use strict;
use warnings;

my $conclusion;
my $conclusion2;
my @SOS;

if (@ARGV) {

  my ($filename) = @ARGV;

  open my $in_fh, '<', $filename or die qq{Unable to open "$filename" for input: $!};
  chomp(my @clauses = <DATA>);
  close $in_fh;

  $conclusion2 = $clauses[-1];
  $SOS[0][0] = $conclusion2;

  $conclusion = $conclusion2;
  $conclusion =~ tr/A-Za-z~//cd;
  $conclusion = '~'.$conclusion unless $conclusion =~ tr/~//d;

  $_ = [ split /,/ ] for @clauses;

  print $conclusion, "\n";
  use Data::Dump;
  dd \@clauses;
}

output

a
[["a", "b", "c"], ["b", "~c"], ["~b"], ["~a"]]

다른 팁

The problem is that $clauses[$a] is a string, not an arrayref, so $clauses[$a][$b] = ... doesn't really make sense. (It means "set element $b of the array referred to by $clauses[$a] to ...", but $clauses[$a] doesn't refer to an array.)

To fix that, change this:

    my $str = $clauses[$a];
    my @tmp = split(',', $str);
    for (my $b = 0; $b < @tmp; $b++) {
      $clauses[$a][$b] = $tmp[$b]; # ERROR 
    }

to this:

    $clauses[$a] = [split /,/, $clauses[$a]];

so as to set $clauses[$a] to an arrayref with the contents you want.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top