in reply to Generic RPN Translator available?
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[ [a-zA-Z]\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>423305-2 "2*(somevar+other) + max(this, that)" 2, somevar, other, +, *, this, that, max, + P:\test>423305-2 "5^((-2+x)*sin(p+4)/fred)" 5, -2, x, +, p, 4, +, sin, *, fred, /, ^ P:\test>423305-2 "A+(B*C-D)/E" A, B, C, *, D, -, +, E, / P:\test>423305-2 "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?
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: Generic RPN Translator available?
by dfaure (Chaplain) on Jan 20, 2005 at 22:22 UTC | |
by saintmike (Vicar) on Jan 21, 2005 at 03:37 UTC | |
by BrowserUk (Patriarch) on Jan 21, 2005 at 06:15 UTC | |
by BrowserUk (Patriarch) on Jan 21, 2005 at 08:50 UTC | |
by saintmike (Vicar) on Jan 22, 2005 at 04:37 UTC | |
| |
by BrowserUk (Patriarch) on Jan 20, 2005 at 22:33 UTC | |
by dfaure (Chaplain) on Jan 20, 2005 at 23:50 UTC |