This might form a useful starting point. It seems reasonably accurate, flexible and efficient.
Update: Improved error handling a little and added XLATE option.
Update2: Apparently there is something wrong with this code. Would someone care to tell me what that is?
#! perl slw
use strict;
use List::Util qw[ reduce ]; $a=$b;
our $XLATE = 0;
sub nestedOk{
index( $_[ 0 ], '(' ) <= index( $_[ 0 ], ')' ) and
0 == reduce{
$a + ( $b eq '(' )  ( $b eq ')' )
} 0, split'[^()]*', $_[ 0 ]
}
my $re_var = qr[ [azAZ]\w* ]x;
my $re_subex = qr[ \{\d+\} ]x;
my $re_func = qr[ $re_var $re_subex ]x;
my $re_num = qr[ ? \d+ (?: \. \d+ )? (?: [Ee] [+]? \d+ )? ]x;
my $re_term = qr[ $re_func  $re_subex  $re_var  $re_num ]x;
my $re_op = qr[[,%+*/^]];
my %ops = ( qw[ % MOD + ADD * MULT / DIV ^ POW  SUBT ] );
sub exp2rpn {
my( $exp, $aStack, $aBits ) = @_;
die "Unbalanced parens: '$exp'" unless nestedOk $exp;
{
my( $left, $op, $right, $rest ) = $exp =~ m[
^ ( $re_term )? ( $re_op )? ( $re_term ) ( .* ) $
]x or die "malformed (sub)expression '$exp'";
for ( $left, $right ) {
next unless $_;
if( my( $func, $subex ) = m[^ ( $re_var )? \{ ( \d+ ) \} $
+]x ) {
exp2rpn( $aBits>[ $subex ], $aStack, $aBits );
push @$aStack, $func if $func
}
else{
push( @$aStack, $_ );
}
}
push @$aStack, $XLATE ? $ops{ $op } : $op
if $op and $op ne ',';
$exp = $rest, redo if $rest;
}
return $aStack;
}
sub parseExp {
local $_ = $_[ 0 ];
s[\s+][]g;
my( $bit, @bits ) = 0;
s[\( ( [^()]+ ) \)]{ push @bits, $1; "{${ \( $bit++ ) }}"; }ex
while m[[()]];
my $toplvl = $_;
return @{ exp2rpn $toplvl, [], \@bits };
}
die "No expression given\n" unless @ARGV;
print join', ', parseExp $ARGV[ 0 ];
__END__
P:\test>4233052 "2*(somevar+other) + max(this, that)"
2, somevar, other, +, *, this, that, max, +
P:\test>4233052 "5^((2+x)*sin(p+4)/fred)"
5, 2, x, +, p, 4, +, sin, *, fred, /, ^
P:\test>4233052 "A+(B*CD)/E"
A, B, C, *, D, , +, E, /
P:\test>4233052 "max( a, b, c, d ) * atan( pi*4, 1 )"
a, b, c, d, max, pi, 4, *, 1, atan, *
P:\test>423305 XLATE "5^((2+x)*sin(p+4)/fred)"
5, 2, x, ADD, p, 4, ADD, sin, MULT, fred, DIV, POW
You may need to tweak the named regex at the top to match your definition of variable names, function names and acceptable numeric forms.
Functions are assumed to have fixed numbers of arguments and know how to unstack the correct number. I don't know how (or if) functions with variable numbers of arguments are handle in RPN?
Examine what is said, not who speaks.
Silence betokens consent.
Love the truth but pardon error.
