Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Using overload to parse arithmetic terms

by esskar (Deacon)
on Feb 07, 2006 at 12:01 UTC ( #528475=perlquestion: print w/ replies, xml ) Need Help??
esskar has asked for the wisdom of the Perl Monks concerning the following question:

hi,

i wrote a package Foo::Expression::Arithmetic, a package Foo::Number and a package Foo::Variable. I used overload to be able to do the following:
my $x1 = Foo::Number->new()->value( 10 ); my $x2 = Foo::Number->new()->value( 20 ); my $x3 = Foo::Number->new()->value( 30 ); my $x4 = Foo::Number->new()->value( 40 ); my $v1 = Foo::Variable->new()->name( 'a' )->value( 50 ); my $c1 = $v1 - $x1 + $x2 + $x3 - $x4; my $c2 = $c1 * $v1;
$c1 and $c2 are now objects of type Foo::Expression::Arithmetic. Foo::Expression::Arithmetic has a output function, so outputing $c1 and $c2 gives me the following:
a - 10 + 20 + 30 - 40      # $c1
a - 10 + 20 + 30 - 40 * a  # $c2
Now i want to be able to do the following:
my $c3 = ( $x1 + $x2 ) * $v1;
not achieve the following output:
( 10 + 20 ) * a   # $c3
use overload '(' => \&left_parenthesis, ')' => \&right_parenthesis,
is not working. :-( Any ideas?

2006-02-07 Retitled by Arunbear, as per Monastery guidelines
Original title: 'overload'

Comment on Using overload to parse arithmetic terms
Select or Download Code
Re: Using overload to parse arithmetic terms
by Tomte (Priest) on Feb 07, 2006 at 12:30 UTC

    I may be completely mistaken, but IMHO parenthesis aren't things overload can overload - they're at least not mentioned in overload

    To get better qualified help you should specify the code you wrote and mention what exactly "didn't work" in which way- your post is almost in the worst form you can ask such a question: state at least what you did, what you expected and what you got.

    regards,
    tomte


    An intellectual is someone whose mind watches itself.
    -- Albert Camus

      well i, did that:
      use overload '+' => \&add, '-' => \&sub, '*' => \&mul;
      so, i'm able to build a expression that uses +, - and * . Now, i want to be able to detect when the user uses parenthesis as shown above. I know that overload does not support parenthesis, but i hope that somebody has a idea how i can detect those parenthesis.

        Hmm, how do you store the expressions? If you store them as a tree, you already have the information necessary, because you can always generate parenthesis for an <+|->-Node with to children on the fly - that's what I meant with showing relevant code - do you store the expression as a tree - otherwise this is a useless info on my part *g*?


        regards,
        tomte


        An intellectual is someone whose mind watches itself.
        -- Albert Camus

Re: Using overload to parse arithmetic terms
by japhy (Canon) on Feb 07, 2006 at 12:52 UTC
    If you want to output a properly parenthesized mathematical expression, you'll have to do so on the fly, examining the tree that I assume you have in your Arithmetic object. For example, if you have $x = ($a + $b) * $c;, then you probably have a tree like:
    Arithmetic::Multiply( Arithmetic::Add( Variable('a'), Variable('b') ), Variable('c') )
    When you're walking that tree, when you get to a Multiply or Divide node, you have to check to see if its children are Add or Subtract nodes; if they are, those child nodes need to be surrounded by parentheses when output.

    Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
    How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
      To expand (and generalize) on this a bit, let each type of operation have a precedence. Then as you walk the expression tree, you need to parenthesize operations that have a lower precedence than the expression they appear within.

      A good way to do this is via OO, representing your operation types as subclasses:

      package Op; sub new { my $pkg = shift; bless [@_], $pkg; } sub children { @{ $_[0] } } sub display { my ($self, $precedence) = @_; $precedence = 0 if not defined $precedence; my $s = join $self->op, map { $_->display($self->precedence) } $self->children; $s = "($s)" if $precedence > $self->precedence; return $s; } package Op::Addition; @ISA = qw[Op]; sub precedence { 10 } sub op { " + " } package Op::Multiplication; @ISA = qw[Op]; sub precedence { 20 } sub op { " * " } # ... package Op::Term; @ISA = qw[Op]; sub precedence { 100 } sub display { $_[0][0] }
      Then you just call the display method on an Op tree. For example,
      Op::Multiplication->new( Op::Term->new(5), Op::Addition->new( Op::Term->new(6), Op::Term->new(7) ) )->display; # 5 * (6 + 7) Op::Addition->new( Op::Term->new(5), Op::Multiplication->new( Op::Term->new(6), Op::Term->new(7) ) )->display; # 5 + 6 * 7
      And you can see how easy it would be to add new types of operations, due to the beauty of subclassing.

      blokhead

        That is a beautiful approach and technique. ++ well deserved.

        Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
        How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
        perfect ... thanks.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://528475]
Approved by Tomte
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (8)
As of 2014-12-20 15:06 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (96 votes), past polls