--Chris#! /usr/local/bin/perl -ws use strict; use Parse::RecDescent; use Data::Dumper; my %hashlist = (); my $keycount = 0; my $parse = Parse::RecDescent->new(<<'EndGrammar'); main: expr /\s*\Z/ { $item[1]->() } | <error> expr: /for(each)?/ lvar range expr { my ($vname,$expr) = @item[2,4]; my ($from, $to) = @{$item[3]}; sub { my $val; no strict "refs"; for $$vname ($from->()..$to->()) { $val = $expr->() } return $val; } } | lvar '=' addition { my ($vname, $expr) = @item[1,3]; sub { no strict 'refs'; $$vname = $expr->() } } | addition range: "(" expr ".." expr ")" { [ @item[2,4] ] } addition: <leftop:multiplication add_op multiplication> { my $add = $item[1]; my $ref = sub { ::evaler ($add); ::eval +op $add }; ::push ('addevalop', $ref) } add_op: '+' { my $ref = sub { print "Add...$_[0] + $_[1]\n"; $_[0] ++= $_[1] }; ::push ('add', $ref) } | '-' { my $ref = sub { print "Sub...$_[0] - $_[1]\n"; $_[0] +-= $_[1] }; ::push ('sub', $ref) } multiplication: <leftop:factor mult_op factor> { my $mult = $item[1]; my $ref = sub { ::evaler ($mult); ::ev +alop $mult }; ::push ('mulevalop', $ref) } mult_op: '*' { my $ref = sub { print "Mul...$_[0] * $_[1]\n"; $_[ +0] *= $_[1] }; ::push ('mul', $ref) } | '/' { my $ref = sub { print "Div...$_[0] / $_[1]\n"; $_[ +0] /= $_[1] }; ::push ('div', $ref) } factor: number | rvar | '(' expr ')' { $item[2] } number: /[-+]?\d+(\.\d+)?/ { my $ref = sub { $item[1] }; ::push ('n +umber', $ref) } lvar: /\$([a-z]\w*)/ { $1 } rvar: lvar { my $ref = sub { no strict 'refs'; ${$item[1]} } +; ::push ('rvar', $ref) } EndGrammar print "> "; while (<>) { print $parse->main($_), "\n\n> "; } # # This allows us to 'name' the closures. We append an ever-increment +ing number to the hash key so that # multiple add, subtract, whatever operations won't overwrite the exi +sting key. Remember that each # operation is a standalone closure, and are not 'packed' down to one + common routine for each function. # sub evaler { my $arr = shift; print "Eval ", join (', ', map {$hashlist {$_}} @$arr), "\n"; } # # Build the hashlist so we know what the closures refer to. # sub push { my ($name, $ref) = @_; my $val = sprintf ("%s_%d", $name, $keycount++); print "key=$ref, val=$val"; print ", number=", &$ref if ($name eq 'number'); print "\n"; $hashlist {$ref} = $val; # # Have to return the ref, because Parse::RecDescent expects it # return $ref; } sub evalop { print Data::Dumper->Dump ([\@_]); my (@list) = @{[@{$_[0]}]}; my $val = shift(@list)->(); while (@list) { my ($op, $arg2) = splice @list, 0, 2; $op->($val,$arg2->()); } return $val; }
In reply to (jcwren) RE: Multiple Levels of Array Dereferencing Have me Stumped
by jcwren
in thread Multiple Levels of Array Dereferencing Have me Stumped
by metaperl
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |