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