Trying to Develop PostFix Notation in Tree Using Perl -


i'm using perl run through tree, , calculate leaf nodes of tree using internal nodes operators. want able print in postfix manner, , managed this basic operands (simply call left , right nodes respectively before calling parent) having trouble producing desired output average function. don't have trouble printing actual result of calculation, want able print operators , operands in postfix notation.

for example, 1 + average(3, 4, 5) shown 1 ; 3 4 5 average +.

here code:

use strict; use warnings;  use data::dumper;  $data::dumper::indent = 0; $data::dumper::terse = 1;  $debug = 0;  # arithmetic expression tree reference list, can # of 2 kinds follows: #    [ 'leaf', value ] #    [ 'internal', operation, leftarg, rightarg ]  # evaluate($ex) takes arithmetic expression tree , returns  # evaluated value.  sub evaluate {     ($ex) = @_;      $debug ,         print "evaluating: ", dumper($ex), "\n";      # kind of node given in first element of array     $node_type = $ex->[0];      # if leaf, value number     if ( $node_type eq 'leaf' ) {         # base case         $value = $ex->[1];         $debug ,             print "returning leaf: $value\n";         return $value;                     }      # if not leaf, internal,      if ( $node_type ne 'internal' ) {         die "eval: strange node type '$node_type' when evaluating tree";     }      # should have operation , 2 arguments     $operation = $ex->[1];     $left_ex = $ex->[2];     $right_ex = $ex->[3];      # evaluate left , right arguments;     $left_value = evaluate($left_ex);     $right_value = evaluate($right_ex);      # if arguments undefined, our value undefined.     return undef unless          defined($left_value) , defined($right_value);      $result;      # or explicitly required operators ...     if ($operation eq 'average') {         $result = ($left_value + $right_value) / 2;     }     if ($operation eq '+') {         $result = $left_value + $right_value;     } elsif ($operation eq '-') {         $result = $left_value - $right_value;     } elsif ($operation eq '*') {         $result = $left_value * $right_value;     } elsif ($operation eq 'div') {         if ($right_value != 0 ) {         $result = int ($left_value / $right_value);         } else {             $result = undef;         }     } elsif ($operation eq 'mod') {         $result = $left_value % $right_value;     } elsif ($operation eq '/') {         if ( $right_value != 0 ) {             $result = $left_value / $right_value;             }         else {             $result = undef;             }     }      $debug ,         print "returning '$operation' on $left_value , $right_value result: $result\n";      return $result;     }   # display($ex, $style) takes arithmetic expression tree , style  # parameter ('infix' or 'postfix') , returns string represents  # printable form of expression in given style.  sub display {     ($ex, $style) = @_;      # kind of node given in first element of array     $node_type = $ex->[0];      # if leaf, value number     if ( $node_type eq 'leaf' ) {         # base case         $value = $ex->[1];         return $value;                     }      # if not leaf, internal,      if ( $node_type ne 'internal' ) {         die "display: strange node type '$node_type' when evaluating tree";     }      # should have operation , 2 arguments     $operation = $ex->[1];     $left_ex = $ex->[2];     $right_ex = $ex->[3];      # evaluate left , right arguments;     $left_value = display($left_ex, $style);     $right_value = display($right_ex, $style);      $result;     if ($operation ne 'average') {     $result = "($left_value $operation $right_value) \n $left_value $right_value $operation";     } else {     $result = "($left_value $operation $right_value) \n $left_value $right_value $operation";     }     return $result;     }  # module end; 1; 

and here test:

use strict; use warnings;  use display;  use arith;  $ex1 = [ 'leaf', 42];  $ex2 = [ 'internal', '+', [ 'leaf', 42], [ 'leaf', 10 ] ];  $ex3 = [ 'internal', 'average', $ex2, [ 'leaf', 1 ] ];    print "ex1 ", evaluate($ex1), "\n"; print "ex1: ", display($ex1), "\n"; print "\n";  print "ex2 ", evaluate($ex2), "\n"; print "ex2: ", display($ex2), "\n"; print "\n";  print "ex3 ", evaluate($ex3), "\n"; print "ex3: ", display($ex3), "\n"; print "\n"; display::render(\$ex3); 

in order this, realize have change subroutine "display", i'm not sure how output --> value value ; #to indicate values aren't averaged# value value average operand etc.

any ideas?

i not 100% sure understand problem, here cleanup / improvement of 2 functions:

my %ops = ( # dispatch table operations     average  => sub {my $acc; $acc += $_ @_; $acc / @_},     '+'      => sub {$_[0] + $_[1]},     '-'      => sub {$_[0] - $_[1]},     '*'      => sub {$_[0] * $_[1]},     'mod'    => sub {$_[0] % $_[1]},     (map {$_ => sub {$_[1] ? $_[0] / $_[1] : undef}} qw (/ div)), ); sub evaluate {     $ex = shift;     print "evaluating: ", dumper($ex), "\n" if $debug;      $node_type = $ex->[0];     if ( $node_type eq 'leaf' ) {         print "returning leaf: $$ex[1]\n" if $debug;         return $$ex[1];     }     elsif ( $node_type ne 'internal' ) {         die "eval: strange node type '$node_type' when evaluating tree";     }      $operation = $ex->[1];     @values    = map {evaluate($_)} @$ex[2 .. $#$ex];      defined or return @values;      if (my $op = $ops{$operation}) {         return $op->(@values);     } else {         print "operation $operation not found\n";         return undef;     } } 

here large if/elsif block replaced dispatch table. allows separate logic parser. have replaced $left_value , $right_value variables @values array, allowing code scale n-arity operations (like average).

the following display function has been updated handle n-arity operations:

my %is_infix = map {$_ => 1} qw( * + / - ); sub display {     ($ex, $style) = @_;      $node_type = $ex->[0];      # if leaf, value number     if ( $node_type eq 'leaf' ) {         return $$ex[1];     }      # if not leaf, internal,     if ( $node_type ne 'internal' ) {         die "display: strange node type '$node_type' when evaluating tree";     }      # should have operation , n arguments     $operation = $ex->[1];      if ($style , $style eq 'infix') {         @values = map {display($_, $style)} @$ex[2 .. $#$ex];         if ($is_infix{$operation}) {             return "$values[0] $operation $values[1]"         } else {             local $" = ', ';                 # "             return "$operation( @values )"         }     } else { # postfix default         @out;         (@$ex[2 .. $#$ex]) {             if (@out , $_->[0] eq 'internal') {                 push @out, ';'             }             push @out, display($_, $style)         }         return join ' ' => @out, $operation;     } } 

you can call display display($tree) or display($tree, 'postfix') postfix notation. , display($tree, 'infix') infix notation.

 ex1 42 ex1: 42 ex1: 42  ex2 52 ex2: 42 10 + ex2: 42 + 10  ex3 26.5 ex3: 42 10 + 1 average ex3: average( 42 + 10, 1 ) 

which believe looking for.

finally, using first example 1 + average(3, 4, 5):

my $avg = ['internal', 'average', [leaf => 3], [leaf => 4], [leaf => 5] ]; $ex4 = ['internal', '+', [leaf => 1], $avg ];  print "ex4 ", evaluate($ex4), "\n"; print "ex4: ", display($ex4), "\n"; print "ex4: ", display($ex4, 'infix'), "\n"; print "\n"; 

which prints:

 ex4 5 ex4: 1 ; 3 4 5 average + ex4: 1 + average( 3, 4, 5 ) 

Comments

Popular posts from this blog

javascript - Enclosure Memory Copies -

php - Replacing tags in braces, even nested tags, with regex -