note
Rhandom
There are a few other options to place under existing wheels. Each of the mini-language based templating languages have expression parsing. Unfortunately most of the expression parsing isn't abstracted. There is at least one though, [cpan://Template::Alloy] (formerly known as CGI::Ex::Template) that does abstract the parsing of expressions, functions and operators. It does allow adding variables, functions, and custom operators.
<br><br>
It seems that the point of your node was to show various attempts to get a working grammar going - more as an exercise. In that case, Template::Alloy is sort of besides the point. But if you were just wanting to find an existing parser that would work for your use case, then maybe it would help.
<br><br>
I'm looking forward to Perl 6 and being able to use the existing grammar to parse expressions. I'll be interested to see how easy it will be to translate the parse tree into an easier to use AST.
<br><br>
<code>
#!/usr/bin/perl
use Template::Alloy;
my $ta = Template::Alloy->new;
$ta->_vars->{'func'} = sub { local $" = ', '; "You passed me (@_)" };
$ta->_vars->{'a'} = 3;
$ta->_vars->{'b'} = 4;
$ta->define_operator({
type => 'left', # actually associativiy
precedence => 85, # same as '+' in $Template::Alloy::OPERATORS table
symbols => ['+++'],
play_sub => sub { int($_[0]) + int($_[1]) },
});
for my $expr (
'1 + 2',
'1 + 2 * 3',
'(1 + 2) * 3',
'2.7e+10 * 3.0e-9', # scientific
'a + b', # variables
'func(1 + 2, 3)', # functions
'1.2 +++ 3.4 * 2', # custom ops
'1 ? 2 : 3',
'a + (b',
'3 + 4 foobar',
) {
my $copy = $expr;
print "--------------------\n";
print "- expr: $expr\n";
print "- outp: ".eval{ $ta->play_expr($ta->parse_expr(\$copy)) }."\n";
if ($@) {
print "- err : $@\n";
} else {
print "- err : Failed to consume entire string\n" if pos $copy != length $expr;
print "- tree: ".Template::Alloy->dump_parse_expr(\$expr)."\n";
}
}
</code>
<br>
Prints:
<br>
<code>
--------------------
- expr: 1 + 2
- outp: 3
- tree: [[undef, '+', 1, 2], 0]
--------------------
- expr: 1 + 2 * 3
- outp: 7
- tree: [[undef, '+', 1, [[undef, '*', 2, 3], 0]], 0]
--------------------
- expr: (1 + 2) * 3
- outp: 9
- tree: [[undef, '*', [[undef, '+', 1, 2], 0], 3], 0]
--------------------
- expr: 2.7e+10 * 3.0e-9
- outp: 81
- tree: [[undef, '*', 27000000000, '3e-09'], 0]
--------------------
- expr: a + b
- outp: 7
- tree: [[undef, '+', ['a', 0], ['b', 0]], 0]
--------------------
- expr: func(1 + 2, 3)
- outp: You passed me (3, 3)
- tree: ['func', [[[undef, '+', 1, 2], 0], 3]]
--------------------
- expr: 1.2 +++ 3.4 * 2
- outp: 7
- tree: [[undef, '+++', '1.2', [[undef, '*', '3.4', 2], 0]], 0]
--------------------
- expr: 1 ? 2 : 3
- outp: 2
- tree: [[undef, '?', 1, 2, 3], 0]
--------------------
- expr: a + (b
- outp:
- err : parse.missing.paren error - Missing close ) in group (At char 6)
--------------------
- expr: 3 + 4 foobar
- outp: 7
- err : Failed to consume entire string
- tree: [[undef, '+', 3, 4], 0]
</code>
<br><br>
<!-- Node text goes above. Div tags should contain sig only -->
<div class="pmsig"><div class="pmsig-1598">
<font size=1>my @a=qw(random brilliant braindead); print $a[rand(@a)];</font>
</div></div>
624445
624445