http://qs321.pair.com?node_id=624487


in reply to Breaking The Rules II

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, 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.

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.

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.

#!/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::OPERATOR +S 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" +; } }

Prints:
-------------------- - 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]


my @a=qw(random brilliant braindead); print $a[rand(@a)];