I can't tell you exactly how the dereferencing breaks down, but I can tell you that evalop() gets an array of arrrays, where each array element is a reference to a closure (I think I'm using the right term. If not, call them anonymous subroutines).

The basic theory behind demo_calc.pl is that it builds a list of operations, where each operation (numbers, function, whatever) is a closure. It, in effect, is building a TIL, or threaded interpeted language. Unlike a language like Forth, the thread only survives for the life of the operation (but that really doesn't matter).

I spent some time trying to use Data::Dumper to dump the thread, but because Data::Dumper doesn't know what to do with code refs, it really didn't break down well. The closest I came was the implementation below, which gives you a better feel for how it operates. It could be a little clearer, but I was starting to get frusterated with it all.

I didn't test with range operators or variables, but basic operations like 1/2+2 vs. 1/(2+2)/4, etc.
#! /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; }
--Chris

e-mail jcwren

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

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.