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;