use strict; use warnings; sub is_valid_expr { use re 'eval'; local our ($skip, $term, $expr); $skip = qr! \s* !x; $term = qr! $skip [a-zA-Z]+ | $skip [1-9][0-9]* | $skip \( (??{ $expr }) $skip \) !x; $expr = qr! $term (?: $skip [-+*/] $term )* !x; return $_[0] =~ / ^ $expr $skip \z /x; } foreach ( '(a + 3)', '(3 * 4)+(b + x)', '(5 - a)*z', '3 + 2', '!3 + 2', '3 + 2!', '3 a', '3 3', '3 * * 3', '2 - 3 * 4', # Preceedence test. '2 - 3 + 4', # Associativity test. ) { print(is_valid_expr($_) ? "$_ is valid\n" : "$_ is not valid\n" ); } #### sub is_valid_expr { local our $expr; $expr = qr!(?:\s*[a-zA-Z]+|\s*[1-9][0-9]*|\s*\((??{$expr})\s*\))(?:\s*[-+*/](?:\s*[a-zA-Z]+|\s*[1-9][0-9]*|\s*\((??{$expr})\s*\)))*!; return $_[0] =~ /^$expr\s*\z/; }