

pl@nereida:~/Lregexpgrammars/demo$ cat -n exprdamian.pl
1 use strict;
2 use warnings;
3 use 5.010;
4 use Data::Dumper;
5 $Data::Dumper::Indent = 1;
6
7 my $rbb = do {
8 use Regexp::Grammars;
9
10 qr{
11 \A<expr>\z
12
13 <objrule: expr> <MATCH=term> (?! <addop> ) # bypass
14 | <[operands=term]> ** <[operators=addop]>
15
16 <objrule: term> <MATCH=factor> (?! <mulop> ) # bypass
17 | <[operands=factor]> ** <[operators=mulop]>
18
19 <objrule: factor> <val=([+-]?\d+(?:\.\d*)?)>
20 | \( <MATCH=expr> \)
21
22 <token: addop> [+-]
23
24 <token: mulop> [*/]
25
26 }x;
27 };
28
29 while (my $input = <>) {
30 chomp($input);
31 if ($input =~ m{$rbb}) {
32 my $tree = $/{expr};
33 say Dumper $tree;
34 say $tree->ceval;
35
36 }
37 else {
38 say("does not match");
39 }
40 }
41
42 BEGIN {
43
44 package LeftBinaryOp;
45 use strict;
46 use base qw(Class::Accessor);
47
48 LeftBinaryOp->mk_accessors(qw{operators operands});
49
50 my %f = (
51 '+' => sub { shift() + shift() },
52 '-' => sub { shift() - shift() },
53 '*' => sub { shift() * shift() },
54 '/' => sub { shift() / shift() },
55 );
56
57 sub ceval {
58 my $self = shift;
59
60 # recursively evaluate the children first
61 my @operands = map { $_->ceval } @{$self->operands};
62
63 # then combine them
64 my $s = shift @operands;
65 for (@{$self->operators}) {
66 $s = $f{$_}->($s, shift @operands);
67 }
68 return $s;
69 }
70
71 package term;
72 use base qw{LeftBinaryOp};
73
74 package expr;
75 use base qw{LeftBinaryOp};
76
77 package factor;
78
79 sub ceval {
80 my $self = shift;
81
82 return $self->{val};
83 }
84
85 1;
86 }
Ejecuciones:
pl@nereida:~/Lregexpgrammars/demo$ perl5.10.1 exprdamian.pl
4-2-2
$VAR1 = bless( {
'operands' => [
bless( {
'' => '4',
'val' => '4'
}, 'factor' ),
bless( {
'' => '2',
'val' => '2'
}, 'factor' ),
bless( {
'' => '2',
'val' => '2'
}, 'factor' )
],
'' => '4-2-2',
'operators' => [
'-',
'-'
]
}, 'expr' );
0
8/4/2
$VAR1 = bless( {
'operands' => [
bless( {
'' => '8',
'val' => '8'
}, 'factor' ),
bless( {
'' => '4',
'val' => '4'
}, 'factor' ),
bless( {
'' => '2',
'val' => '2'
}, 'factor' )
],
'' => '8/4/2',
'operators' => [
'/',
'/'
]
}, 'term' );
1
3
$VAR1 = bless( {
'' => '3',
'val' => '3'
}, 'factor' );
3
2*(3+4)
$VAR1 = bless( {
'operands' => [
bless( {
'' => '2',
'val' => '2'
}, 'factor' ),
bless( {
'operands' => [
bless( {
'' => '3',
'val' => '3'
}, 'factor' ),
bless( {
'' => '4',
'val' => '4'
}, 'factor' )
],
'' => '3+4',
'operators' => [
'+'
]
}, 'expr' )
],
'' => '2*(3+4)',
'operators' => [
'*'
]
}, 'term' );
14

