Add : Mult /[+-]/ Add
| Mult
####
Add : Mult ( /[+-]/ Add )*
####
<[X=Mult]> ** <[Op=(\+|-)]>
####
|
####
Equal : Term OP Term
| LessGreater
####
Equal : LessGreater OP LessGreater
| LessGreater
####
Equal : LessGreater (?: OP LessGreater )?
####
(?: )?
####
(?:
(?{ ... }
|
(?{ ... }
)
####
#!perl
use v5.10;
use warnings;
use Data::Dump 'pp';
use List::Util qw(reduce);
use POSIX;
my $vars = {
a => 1,
b => 2,
};
my $grammar = do{
use Regexp::Grammars;
qr{
^
$
=\>
(?{ $MATCH = [$MATCH{K}, $MATCH{V}] })
# precedence level 12: left || //
<[X=And]> ** <[Op=(\|\||//)]>
(?{ $MATCH = shift @{$MATCH{X}};
for my $term (@{$MATCH{X}}) {
my $op = shift @{$MATCH{Op}//=[]};
if ($op eq '||') { $MATCH ||= $term }
elsif ($op eq '//') { $MATCH //= $term }
}
})
# precedence level 11: left &&
<[X=BitOrXor]> ** <[Op=(&&)]>
(?{ $MATCH = shift @{$MATCH{X}};
for my $term (@{$MATCH{X}}) {
my $op = shift @{$MATCH{Op}//=[]};
if ($op eq '&&') { $MATCH &&= $term }
}
})
# precedence level 10: left | ^
<[X=BitAnd]> ** <[Op=(\||\^)]>
(?{ $MATCH = shift @{$MATCH{X}};
for my $term (@{$MATCH{X}}) {
my $op = shift @{$MATCH{Op}//=[]};
if ($op eq '|') { $MATCH = $MATCH+0 | $term }
elsif ($op eq '^') { $MATCH = $MATCH+0 ^ $term }
}
})
# precedence level 9: left &
<[X=Equal]> ** <[Op=(&)]>
(?{ $MATCH = shift @{$MATCH{X}};
for my $term (@{$MATCH{X}}) {
my $op = shift @{$MATCH{Op}//=[]};
if ($op eq '&') { $MATCH = $MATCH+0 & $term }
}
})
# precedence level 8: nonassoc == != <=> eq ne cmp < > <= >= lt gt le ge
# \x3c = "<", \x3e = ">"
(?: )?
(?{ my ($x, $op, $y) = ($MATCH{X}, $MATCH{Op}, $MATCH{Y});
if (!defined($op)) { $MATCH = $x }
elsif ($op eq '==' ) { $MATCH = ($x == $y ?1:0) }
elsif ($op eq '!=' ) { $MATCH = ($x != $y ?1:0) }
elsif ($op eq '<=>' ) { $MATCH = ($x <=> $y ?1:0) }
elsif ($op eq 'eq' ) { $MATCH = ($x eq $y ?1:0) }
elsif ($op eq 'ne' ) { $MATCH = ($x ne $y ?1:0) }
elsif ($op eq 'cmp' ) { $MATCH = ($x cmp $y ?1:0) }
elsif ($op eq '<' ) { $MATCH = ($x < $y ?1:0) }
elsif ($op eq '<=' ) { $MATCH = ($x <= $y ?1:0) }
elsif ($op eq '>' ) { $MATCH = ($x > $y ?1:0) }
elsif ($op eq '>=' ) { $MATCH = ($x >= $y ?1:0) }
elsif ($op eq 'lt' ) { $MATCH = ($x lt $y ?1:0) }
elsif ($op eq 'gt' ) { $MATCH = ($x gt $y ?1:0) }
elsif ($op eq 'le' ) { $MATCH = ($x le $y ?1:0) }
elsif ($op eq 'ge' ) { $MATCH = ($x ge $y ?1:0) }
})
# precedence level 7: left << >>
# \x3c = "<", \x3e = ">"
<[X=Add]> ** <[Op=(\x3c\x3c|\x3e\x3e)]>
(?{ $MATCH = shift @{$MATCH{X}};
for my $term (@{$MATCH{X}}) {
my $op = shift @{$MATCH{Op}//=[]};
if ($op eq '>>') { $MATCH >>= $term }
elsif ($op eq '<<') { $MATCH <<= $term }
}
})
# precedence level 6: left + - .
<[X=Mult]> ** <[Op=(\+|-|\.)]>
(?{ $MATCH = shift @{$MATCH{X}};
for my $term (@{$MATCH{X}}) {
my $op = shift @{$MATCH{Op}//=[]};
if ($op eq '+') { $MATCH += $term }
elsif ($op eq '-') { $MATCH -= $term }
elsif ($op eq '.') { $MATCH .= $term }
}
})
# precedence level 5: left * / % x
<[X=Unary]> ** <[Op=(\*|/|%|x)]>
(?{ $MATCH = shift @{$MATCH{X}};
for my $term (@{$MATCH{X}}) {
my $op = shift @{$MATCH{Op}//=[]};
if ($op eq '*') { $MATCH *= $term }
elsif ($op eq '/') { $MATCH /= $term }
elsif ($op eq '%') { $MATCH %= $term }
elsif ($op eq 'x') { $MATCH x= $term }
}
})
# precedence level 4: right ! ~ unary+ unary-
<[Op=(!|~|\+|-)]>*
(?{ $MATCH = $MATCH{X};
if ($MATCH{Op}) {
for my $op (reverse @{$MATCH{Op}}) {
if ($op eq '!') { $MATCH = !$MATCH }
elsif ($op eq '-') { $MATCH = -$MATCH }
elsif ($op eq '~') { $MATCH = ~($MATCH+0) }
}
}
})
# precedence level 3: right **
<[X=Subscripting]> **
(?{ $MATCH = reduce { $b ** $a } reverse @{$MATCH{X}} })
# precedence level 2: left hash[s], array[i]
<[X=Term]> <[Subscript]>*
(?{ $MATCH = shift @{$MATCH{X}};
for my $i (@{$MATCH{Subscript}}) {
if (ref($MATCH) eq 'ARRAY' ) { $MATCH = $MATCH->[$i] }
elsif (ref($MATCH) eq 'HASH') { $MATCH = $MATCH->{$i} }
else { $MATCH = "error: invalid hash subscripting"; last }
}
})
\[ \]
# precedence level 1: left term (variable, str/num literals, func(), (paren))
|
|
|
|
|
|
| \( \)
\[ \]
(?{ $MATCH = [] })
| \[ <[X=Expr]> ** (,) \]
(?{ $MATCH = $MATCH{X} })
\{ \}
(?{ $MATCH = {} })
| \{ <[X=Pair]> ** (,) \}
(?{ $MATCH = { map { $_->[0] => $_->[1] } @{ $MATCH{X} } } })
|
undef
(?{ $MATCH = undef })
# XXX support escapes
(?{ $MATCH = substr($MATCH{X}, 1, length($MATCH{X})-2); })
\$
(?{ $MATCH = $vars->{ $MATCH{X} } })
\( <[Args=Expr]> ** (,) \)
(?{
my $f = $MATCH{FuncName};
my $args = $MATCH{Args};
if ($f eq 'length') { $MATCH = length($args->[0]) }
elsif ($f eq 'ceil' ) { $MATCH = POSIX::ceil($args->[0]) }
elsif ($f eq 'floor' ) { $MATCH = POSIX::floor($args->[0]) }
elsif ($f eq 'rand' ) { $MATCH = rand() }
else { $MATCH = "undef function $f" }
})
}xms
};
for (;;) {
print "> ";
defined( my $input = <> ) or last;
if ($input =~ $grammar) {
say '--> ', pp($/{Expr});
} else {
say 'PARSE FAILURE';
}
}