The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
{ #  Example of support code
  use List::Util qw(reduce);
  my %Op = (PLUS=>'+', MINUS => '-', TIMES=>'*', DIV => '/');
}

algebra = fold wxz zxw neg;

fold: /TIMES|PLUS|DIV|MINUS/:b(NUM, NUM) => { 
  my $op = $Op{ref($b)};

  croak "Unexpected tree shape: ".$_[0]->str." can't find number in the expected place\n" unless exists ($NUM[0]->{attr}) && ($NUM[0]->{attr} =~ /^\d+/);

  $NUM[0]->{attr} = eval  "$NUM[0]->{attr} $op $NUM[1]->{attr}";
  $_[0] = $NUM[0]; 
}

zxw: TIMES(NUM, .) and {$NUM->{attr} == 0} => { $_[0] = $NUM }

wxz: TIMES(., NUM) and {$NUM->{attr} == 0} => { $_[0] = $NUM }

neg: NEG(NUM) => { $NUM->{attr} = -$NUM->{attr}; $_[0] = $NUM }

{{ 
  my $num = 1; # closure

  sub new_N_register {
    return '$N'.$num++;
  }
}}

reg_assign: $x  => { 
    if (ref($x) =~ /VAR|NUM/) {
      $x->{reg} = $x->{attr};
      return 1;
    }
    if (ref($x) =~ /ASSIGN/) {
      $x->{reg} = $x->child(0)->{attr};
      return 1;
    }
    $_[0]->{reg} = new_N_register(); 
  }


translation = t_num t_var t_op t_neg t_assign t_list t_print;

t_num: NUM => { $NUM->{tr} = $NUM->{attr} }

{ our %s; }

t_var: VAR => { 
   croak "Unexpected tree shape: ".$_[0]->str." can't find identifier in VAR node\n" unless exists $_[0]->{attr};
   $s{$_[0]->{attr}} = "num"; 
   $_[0]->{tr} = $_[0]->{attr}; 
}

t_op:  /TIMES|PLUS|DIV|MINUS/:b($x, $y) => {
    my $op = $Op{ref($b)};
    $b->{tr} = "$b->{reg} = $x->{reg} $op $y->{reg}"; 
  }

t_neg: NEG($exp) => { $NEG->{tr} = "$NEG->{reg} = - $exp->{reg}"; }

t_assign: ASSIGN($v, $e) => { 
  $s{$v->{attr}} = "num";
  $ASSIGN->{tr} = "$v->{reg} = $e->{reg}" 
}

{ my $cr = '\\n'; }
t_print: PRINT(., $var) => {
    $s{$var->{attr}} = "num";

    $PRINT->{tr} =<<"EOP";
print "$var->{attr} = "
print $var->{attr}
print "$cr"
EOP
  }

{
  # Concatenates the translations of the subtrees
  sub cat_trans {
    my $t = shift;

    my $tr = "";
    for ($t->children) {
      (ref($_) =~ m{NUM|VAR|TERMINAL}) 
        or $tr .= cat_trans($_)."\n" 
    }
    $tr .= $t->{tr} ;
  }
}

t_list: EXPS(@S) 
  => {
    $EXPS->{tr} = "";
    my @tr = map { cat_trans($_) } @S;
    $EXPS->{tr} = 
      reduce { "$a\n$b" } @tr if @tr;
  }