expr := number
| expr ws unary_op
| expr ws expr ws binary_op
number := digit {digit} [ '.' {digit} ]
| '.' digit {digit}
digit := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
unary_op := "chs" | "abs" | "sqr" | "sqrt" | "sin" | "cos" | "tan"
binary_op := '+' | '-' | '*' | '/' | '^'
ws := ' ' | '\t' | '\r' | '\n'
####
Infinite recursion in regex
####
expr := number
| expr ws unary_op
| expr ws expr ws binary_op
####
expr := number expr_
expr_ := ws expr ws binary_op expr_
| ws unary_op expr_
|
####
qr{
(?(DEFINE)
(?
(?&number) (?&expr_)
)
(?
(?:
\s++
(?:
(?&expr) \s++ (?&binary_op) (?&expr_)
|
(?&unary_op) (?&expr_)
)
)?
)
(?
( (?&NUMBER) )
(?{
local @stack = @stack;
push @stack, $^N;
})
)
(?
( (?&IDENT) )
(?(?{ !exists($unary_ops{$^N}) }) (*FAIL) )
(?{
local @stack = @stack;
$unary_ops{$^N}->($stack[-1]);
})
)
(?
( [-+/*^] )
(?{
local @stack = @stack;
$binary_ops{$^N}->($stack[-2], pop(@stack));
})
)
# Tokens.
# Backtracking can't cause a token
# rule to return something different.
(? \d++ (?: [.] \d*+ )?+ | [.] \d++ )
(? [_A-Za-z][_A-Za-z0-9]*+ )
)
(?{ local @stack = (); })
\A \s* (?&expr) \s* \z
(?{ $result = pop(@stack) })
}sx;
####
#!/usr/bin/perl
use 5.010_000; # re features
use warnings;
use strict;
our @stack;
our $result;
my %unary_ops = (
chs => sub { $_[0] = -$_[0] },
abs => sub { $_[0] = abs $_[0] },
sqr => sub { $_[0] *= $_[0] },
sqrt => sub { $_[0] = sqrt $_[0] },
sin => sub { $_[0] = sin $_[0] },
cos => sub { $_[0] = cos $_[0] },
tan => sub { $_[0] = sin $_[0] / cos $_[0] },
);
my %binary_ops = (
'+' => sub { $_[0] += $_[1] },
'-' => sub { $_[0] -= $_[1] },
'/' => sub { $_[0] /= $_[1] },
'*' => sub { $_[0] *= $_[1] },
'^' => sub { $_[0]**= $_[1] },
);
my $RPN = qr{
...
};
my %input = (
...
);
foreach my $line ( keys %input ) {
local $result;
my ($expression) = $line =~ /($RPN)/;
...
}
####
OK: .456 = .456
OK: 123. = 123.
OK: 4 2 + = 6
OK: 123 / is invalid, got no result
OK: 24 abs = 24
OK: 1 24 abs + sqrt = 5
OK: 12 34 is invalid, got no result
OK: 123 34 * chs = -4182
OK: 4 2 - = 2
OK: 34 2 / 2 ^ = 289
OK: 24 4 + chs sqr = 784
OK: 123.456 + is invalid, got no result
OK: 123 chs 34 * = -4182
OK: fail is invalid, got no result
OK: 24 chs abs = 24
OK: 25 abs sqrt = 5
OK: 12 34+ is invalid, got no result
OK: 12 34 + + is invalid, got no result
OK: 123 chs chs chs = -123
OK: 1 24abs+sqrt is invalid, got no result
OK: 12 34 + 56 + = 102
OK: 123 chs = -123
OK: 24 = 24
OK: 1 fail is invalid, got no result
OK: 12 34 56 + + = 102
OK: 4 2 ^ = 16
OK: 123 chs chs chs chs = 123
OK: 3 34 2 / 2 ^ * = 867
OK: 25 chs abs sqrt = 5
OK: 123.456 = 123.456
OK: 123 = 123
OK: 123 chs chs = 123
OK: 24 chs = -24
OK: 123 = 123
OK: 24abs is invalid, got no result
OK: 4 2 / = 2
OK: 24abssqrt is invalid, got no result
OK: 4 2 * = 8