2011-10-13 4 views
1
#!/usr/bin/perl 

use warnings; 

use Scalar::Util qw(looks_like_number); 

sub term_value(); 
sub factor_value(); 

sub expression_value() 
{ 
    $num = @_; 
    @expression = $_[0]; 
    print "expression[0]: " . $expression[0] . "\n"; 

    $index = $_[$num-1]; 
    print "index: $index\n"; 

    $result = &term_value(@expression, $index); 
    $more = 1; 

    while($more) 
    { 
     $op = $expression[$index]; 
     print "$op\n"; 
     if ($op eq "+" || $op eq "-") 
     { 
      $index++; 
      $value = &term_value(@expression, $index); 
      if ($op eq '+') 
      { 
       $result = $result + $value; 
      } else { 
       $result = $result - $value; 
      } 
     } 
     else 
     { 
      $more = 0; 
     } 
    } 
    return $result; 
} 

sub term_value() 
{ 
    $num = @_; 
    @expression = $_[0]; 
    print "expression[0]: " . $expression[0] . "\n"; 

    $index = $_[$num-1]; 
    print "index: $index\n"; 
    $result = &factor_value(@expression, $index); 
    $more = 1; 

    while($more) 
    { 
     $op = $expression[$index]; 
     if ($op eq "*" || $op eq "/") 
     { 
      $index++; 
      $value = &factor_value(@expression, $index); 
      if ($op eq '*') 
      { 
       $result = $result * $value; 
      } else { 
       $result = $result/$value; 
      } 
     } else { 
      $more = 0; 
     } 
    } 
    return $result; 
} 

sub factor_value() 
{ 
    $num = @_; 
    @expression = $_[0]; 
    print "expression[0]: " . $expression[0] . "\n"; 

    $index = $_[$num-1]; 
    print "index: $index\n"; 
    $result = 0; 
    $c = $expression[$index]; 
    if ($c eq '(') 
    { 
     $index++; 
     $result = &expression_value(@expression, $index); 
     $index++; 
    } else { 
     while (looks_like_number($c)) 
     { 
      $result = 10 * $result + $c - '0'; 
      $index++; 
      $c = $expression[$index]; 
     } 
    } 
    return $result; 
} 

#Collect argument and separate by character 
@one_char = split(//, $ARGV[0]); 

$index = 0; 
$result = &expression_value(@one_char, $index); 

print $result . "\n"; 

내 콘솔은 이러한 경고를 반환합니다. 나는 이것이 범위 문제일지도 모른다라고 생각하고있다. .. 그러나 나는 그것을 이해할 수 없다. 나는 내가 생각할 수있는 모든 것을 시도했다. (루프 밖에서 변수를 초기화한다.)하지만 그 중 아무 것도 프로그램을 실행할 때 차이를 만드는 것 같지는 않다. 어떤 제안이라도 대단히 감사하겠습니다!초기화되지 않은 변수 문제는

+2

더? 프로토 타입? 수행해야 할 코드는 무엇입니까? –

+0

이것은 표현 문자열 (예 : "1 + 2 * 3")을 평가하는 데 사용 된 C++ 코드의 빠른 번역이었습니다. –

+8

각 서브 루틴 선언에서 이름 뒤에'()'를 제거하면 그 단어를 계속 말하고 있지만 코드의 맨 위에'use strict; '를 놓고 모든 오류를 수정하십시오. 이전을 수행하는 동안'Perl is not C++'을 반복해서 반복하십시오 :) –

답변

5

재귀 함수를 사용하고 있습니다! 추가로 시작

use strict; 

주로 이것은 선언하지 않은 변수를 나타냅니다. 적절한 범위에서 선언하려면 my을 사용하십시오.


서브 시스템에 배열을 전달 하려는데 실패했습니다. 하위로 전달할 수있는 유일한 것은 스칼라 목록입니다. 배열을 하위에 전달하려면 배열에 참조 (~ 포인터)를 전달해야합니다.

sub foo { 
    my ($expressions, $index) = @_; 
    print($expressions->[$index], "\n"); 
} 

foo(\@expressions, $index); 

경고의 원인입니다. 하나의 요소를 배열 (@expression = $_[0])에 할당하면 두 번째 또는 그 이후 요소를 인덱싱하려고합니다.


프로토 타입 ()을 사용하면 하위에 인수가 필요 없다는 것을 알 수 있습니다. 그런 다음 &을 사용하여 Perl에 프로토 타입을 무시하도록 지시하여 인수에 인수를 전달할 수 있습니다. 하위 이름 다음에 ()을 제거하고 하위 호출 전에 &을 제거하십시오.


my $more = 1; 
while ($more) { 
    ... 
    if (cond) { 
     ... 
    } else { 
     $more = 0; 
    } 
} 

가 신안의 대답 추론의 비트로

while (1) { 
    ... 
    last if !cond; 
    ... 
} 
2

Higher Order Perlchapter on parsing입니다. 표현 파서와 평가자를 처음부터 어떻게 만들지는 8.1.2 절을 보라.

Parse::RecDescent과 함께 제공되는 demo calculator script을 살펴볼 수도 있습니다.

호기심에서 벗어나 파서를 사용하지 않고 얻을 수있는 것을보고 싶었습니다. 다음 스크립트는 많은 가정을하지만 간단한 경우에는 "작동"합니다.

#!/usr/bin/env perl 

use strict; 
use warnings; 

use Regexp::Common qw(balanced number); 

die "Need expression\n" unless @ARGV; 
my ($expression) = @ARGV; 

my $result = evaluate_expression($expression); 

printf(
    "'%s' evaluated to %g\n", 
    $expression, $result 
); 

my $expected = eval $expression; 

unless ($result == $expected) { 
    die "Wrong result, should have been '$expected'\n"; 
} 

sub evaluate_expression { 
    my ($expression) = @_; 

    my $n = qr!$RE{num}{real}!; 
    my $mul = qr![*/]!; 
    my $add = qr![+-]!; 
    my $subexpr = qr!$RE{balanced}{-parens=>'()'}{-keep}!; 

    1 while 
     $expression =~ s! 
      $subexpr 
     ! 
      my $s = $1; 
      $s =~ s{(?:^\()|(?:\)\z)}{}g; 
      evaluate_expression($s) 
     !gex; 

    1 while 
     $expression =~ s!($n) \s* ($mul) \s* ($n)!"$1 $2 $3"!geex; 

    1 while 
     $expression =~ s!($n) \s* ($add) \s* ($n)!"$1 $2 $3"!geex; 

    return $expression; 
} 

출력 : 그것이 깨지기 과정의

C:\Temp> z "((1+1)*3 +2)*5" 
'((1+1)*3 +2)*5' evaluated to 40 

C:\Temp> z "(1+1)*3 + 2*5" 
'(1+1)*3 + 2*5' evaluated to 16

그러나 : 당신은 주어진 큰 문제입니다 패키지 (~ 전역) 변수를 사용하고

C:\Temp> z "2*3+2*5" 
'2*3+2*5' evaluated to 610 
Wrong result, should have been '16'
0

로 감소 될 수 있고, 여기 낙의 다른 측면에서 작성된 "파서"이다.

use 5.010; 
use strict; 
use warnings; 

my @ops; 
use overload map { 
    my $op = $_; 
    $op => sub { 
     my ($x, $y) = @_[$_[2] ? (1, 0) : (0, 1)]; 
     bless [$x, $op, $y] 
    } 
} @ops = qw(+ -/*); 

my %ops = map {$_ => eval "sub {\$_[0] $_ \$_[1]}"} @ops; 

sub eval { 
    my $self = shift; 
    return $$self[0] if @$self == 1; 

    my ($x, $op, $y) = map {ref eq 'main' ? $_->eval : $_} @$self; 

    my $ret = $ops{$op}->($x, $y); 
    say "$ret = $x $op $y"; 
    $ret; 
} 

BEGIN {overload::constant integer => sub {bless [$_[1]]}} 

eval->eval for "@ARGV"; 

어느 때 실행 :

$ perl eval.pl 2*3+2*5 

인쇄 :

백 개 라인없이`strict`보다
6 = 2 * 3 
10 = 2 * 5 
16 = 6 + 10