in reply to Re: Dice calcs?
in thread Dice calcs?

Hmmmm.... I hadn't thought about in-place substitutions. My original assignment was an infix-to-postfix calculator, and the precedence order I listed was required for that algorithm to work.

I did find a few bugs in your solution. I realize your code was just an example, and I appreciate the insight, I just want to make sure anyone that downloads it realizes there are issues. For example, your code wouldn't allow for multiple @[] operators at the same level (i.e. &3>4@[1d6]+&1>4@[1d100]). Division should be integer. Negative numbers (and thus unary -) need to be implemented. There's no general syntax checking.

I went ahead with the in-place substitution idea and should have some code ready to post soon. I've addressed all of the above issues and a few more. There are still issues with precedence lists, though.... with this method it is impossible/difficult for operators to share the same precedence. For example, normally something like 5*20/3*3 should equal 99, but in this case it comes up 11 (100/9). That's not a problem as long as it's documented.

Replies are listed 'Best First'.
Re: Re: Re: Dice calcs?
by BigLug (Chaplain) on Sep 19, 2002 at 04:17 UTC
    Oh, good bug-find. Here's a couple of fixes that you've prolly already done

    1. To get it to do the multiple @ operators at the same level you need to

    use Regexp::Common
    Then replace the 'Precedence 5' regexp with:
    $term=~s/(\d+)@($RE{balanced}{-parens=>'[]'})/rpt($1,$2)/eg;

    2.To get it to do the * and / from left to right, change 'Precedence 3' to this single regexp:

    $term=~s/(\d+)([\*\/])(\d+)/int(eval("$1$2$3"))/eg;
    and change 'Precedence 4' to
    $term=~s/(\d+)([+-])(\d+)/eval("$1$2$3")/eg;

    Hope these help you with your efforts. There is still no syntax checking but I figure you can handle stopping people from putting 3*+/4. Oh, and you probably want to handle negative numbers before 'Precedence 4'

      I handled the matching parens in the subroutine.

      Your fix to precedence 3 still isn't going to work:

      my $x = '20*5/3*3'; $x =~ s/(\d+)([\*\/])(\d+)/int(eval("$1$2$3"))/eg; print "$x\n"; Output: 100/9

      I'm okay for the moment with non-shared precedence. That's what parens are for. :-)

      I also changed some of the logic in the determine sub, because as you can see from above, one s/// pass isn't always enough. I didn't want lower-precedence operators being evaluated before all of the higher-precedences had been taken care of. That helped with the unary - problem... I made - a higher precedence than + and tweaked the rx's slightly.

      The only bit I have left to do (when I can find time) is to add a pre-parser similar to my infix-to-postfix program that will go a long way to validating syntax (but this isn't exactly a mission-critical module either :-)

      Thanx!
      Matt Stum