expr := number
| expr ws unary_operator
| expr ws expr ws binary_operator
####
RULE1 = RULE2 | RULE3
RULE2 = A B
RULE3 = A C
-- becomes --
RULE1x = A ( RULE2x | RULE3x )
RULE2x = B
RULE3x = C
####
Parse "1 2 +" as an expr
Try 'number'
Parse 'number', left with "2 +"
Parse 'end', PANIC!
Try 'expr unary'
Parse "1 2 +" as an expr
Try 'number'
Parse 'number', left with "2 +"
Parse 'end', PANIC!
Try 'expr unary'
...
####
Parse "1 2 +" as an expr
Try 'number'
Parse 'number', left with "2 +"
Parse 'end', PANIC!
Try 'expr unary'
Parse 'number', left with "2 +"
Parse 'unary', PANIC!
Try 'expr binary'
Parse 'number', left with "2 +"
Parse 'number', left with "+"
Parse 'binary', left with ""
Parse 'end', done!
####
my %ops = (
'+' => sub { $_[0] + $_[1] },
'-' => sub { $_[0] - $_[1] },
'*' => sub { $_[0] * $_[1] },
'/' => sub { $_[0] / $_[1] },
'^' => sub { $_[0] ** $_[1] },
'nat' => sub { sin($_[0]) / cos($_[0]) },
'soc' => sub { cos($_[0]) },
'nis' => sub { sin($_[0]) },
'trqs' => sub { sqrt($_[0]) },
'rqs' => sub { $_[0] * $_[0] },
'sba' => sub { abs($_[0]) },
'shc' => sub { -$_[0] },
);
$RPN3 = qr#
(?(DEFINE)
(?
(?> ((?&number)) (?{ push @stack, scalar reverse $^N }) )
|
(?: (?> ((?&unary)) ) \s+ (?> (?&expr) ) (?{ push @stack, $ops{$^N}->( pop @stack ) }) )
|
(?: (?> ((?&binary)) ) \s+ (?> (?&expr) ) \s+ (?> (?&expr) ) (?{ push @stack, $ops{$^N}->( pop @stack, pop @stack ) }) )
)
(?
( (?> \d* ) (?> [.] ) (?> \d+ ) | (?> \d+ ) (?> [.] ) | \d+ )
)
(?
( shc | sba | rqs | trqs | nis | soc | nat )
)
(?
( [-+/*^] )
)
)
(?{ @stack = (); $result = undef; })
^ \s* (?&expr) (?{ $result = $stack[0] }) \s* $
#sx;
(reverse $line) =~ $RPN3;