user
Create a program which parses and evaluates arithmetic expressions.

Requirements

* An abstract-syntax tree (AST) for the expression must be created from parsing the input.
* The AST must be used in evaluation, also, so the input may not be directly evaluated (e.g. by calling eval or a similar language feature.)
* The expression will be a string or list of symbols like "(1+3)\*7".
* The four symbols + - \* / must be supported as binary operators with conventional precedence rules.
* Precedence-control parentheses must also be supported.

Note

For those who don't remember, mathematical precedence is as follows:

* Parentheses
* Multiplication/Division (left to right)
* Addition/Subtraction (left to right)

C.f

* 24 game Player.
* Parsing/RPN calculator algorithm.
* Parsing/RPN to infix conversion.
assistant
(formerly Perl 6)

**Works with**: rakudo version 2018.03

```
sub ev (Str $s --> Numeric) {

    grammar expr {
        token TOP { ^ <sum> $ }
        token sum { <product> (('+' || '-') <product>)* }
        token product { <factor> (('*' || '/') <factor>)* }
        token factor { <unary_minus>? [ <parens> || <literal> ] }
        token unary_minus { '-' }
        token parens { '(' <sum> ')' }
        token literal { \d+ ['.' \d+]? || '.' \d+ }
    }
    
    my sub minus ($b) { $b ?? -1 !! +1 }

    my sub sum ($x) {
        [+] flat product($x<product>), map
            { minus($^y[0] eq '-') * product $^y<product> },
            |($x[0] or [])
    }
    
    my sub product ($x) {
        [*] flat factor($x<factor>), map
            { factor($^y<factor>) ** minus($^y[0] eq '/') },
            |($x[0] or [])
    }
    
    my sub factor ($x) {
        minus($x<unary_minus>) * ($x<parens>
          ?? sum $x<parens><sum>
          !! $x<literal>)
    }

    expr.parse([~] split /\s+/, $s);
    $/ or fail 'No parse.';
    sum $/<sum>;

}

# Testing:

say ev '5';                                    #   5
say ev '1 + 2 - 3 * 4 / 5';                    #   0.6
say ev '1 + 5*3.4 - .5  -4 / -2 * (3+4) -6';   #  25.5
say ev '((11+15)*15)* 2 + (3) * -4 *1';        # 768

```