Well, if you are confident that the users of your software are trustworthy, you could simply apply one or more s///'s to the value and eval it:

$value =~ s/\./->/g; ... my $generator = eval "sub { $value }"; die if $@; for (@rows) { ... print $generator->(); ... }

This gives you tremendous power with a minimum amount of work. Though, if you don't completely trust your users, it may give you too much power. You could limit that with Safe, but that has been shown not to be a complete sandbox (it makes it much harder for the user to inadvertently screw up things, but if they have their heart set on it, they can exploit certain flaws).

HOP::Parser is great but very, very slow. You only need it if you are parsing streams. Here you have very short strings and, if the above solution won't work for you, you can use traditional lexing semantics to build up a list of tokens. Your grammar is probably simple enough to simply iterator over those tokens and generate valid perl to be eval'ed (or derive the value as you go).

# untested, just pseudo code my @tokens; local $_ = $value; while ( !/\G$/gc ) { # while not at end of string push @tokens, /\G\./gc ? [ 'DOT', '.' ] : /\G(\$\w+)/gc ? [ 'VAR', $1 ] : /\G(\w+)\((.*?)\)/gc ? [ 'METHOD', $1, [ split /\s*,\s*/, $2 ] : /\G(\w+)/gc ? [ 'METHOD', $1, [] ] : ... last }

Note that if you want proper nesting of () in method calls, you will need to use a better regex. Continue to add tokenizers for operators (|, &) etc. When done, just iterate over the list of tokens and generate either the value or if necessary generate trusted perl code and eval it.

update:

# again, untested, just for demonstration my $code = ''; for (@tokens) { my ($type, $source, @params) = @$_; if ($type eq 'VAR') { $code .= $source; } elsif ($type eq 'DOT') { $code .= '->'; } elsif ($type eq 'METHOD') { .... } my $generator = eval "sub { $code }"; die if $@; for (@rows) { ... print $generator->(); ... }

update 2:

If you choose either eval option above, you can expose variables to your value code like this:

my $generator = eval "sub { my (\$order, \$order_line) = @_; $code }"; ... $generator->($row->{order}, $row->{order_line});

This exposes variables to your value code without the need of globals and namespaces.

Ted Young

It is almost impossible for me to read contemporary mathematicians who, instead of saying "Petya washed his hands," write simply: "There is a t1 < 0 such that the image of t1 under the natural mapping t1 -> Petya(t1) belongs to the set of dirty hands, and a t2, t1 < t2 <= 0, such that the image of t2 under the above-mentioned mapping belongs to the complement of the set defined in the preceding sentence."
The Russian mathematician V. I. Arnol'd

In reply to Re: How to parse a limited grammar by TedYoung
in thread How to parse a limited grammar by clinton

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.