>
> I am working with a grammar that I would like to have operate in two
> different modes. In both modes the rules are identical, but the methods
> should behave differently.

...

> As an illustration (not the actual problem), say we want to proces
> arithmetical expressions in two modes: normally we just copy the input, but
> within a pair of braces we directly calculate the result.


My first thought was to subclass the grammar, and re-use the parsing while
overriding some actions. But I didn't look into it, and saw you had an
answer that keeps track of parsing depth.

Still I wanted to try this by having different actions on the top-level vs
inner parsing. To work with the example, I started with a grammar with no
actions.

grammar Sums {
  rule TOP { <any-expr> }
  token any-expr { <operand>+ % <op> }
  token operand { <int> | <bracketed-expr> }
  token bracketed-expr { '{' <any-expr> '}' }
  token op { <[-+]> }
  token int { \d+ }
}

and I realized that the differing actions can be hung on the different
parts of the tree. "bracketed-expr" computes "any-expr", while "TOP" simply
converts it to a string.

class do-sums {
  method TOP($/) {
    make $<any-expr>.caps.map: { ($_<op> || $_<operand>.made).Str }
  }
  method operand($/)  { make $<int> // $<bracketed-expr>.made }
  method bracketed-expr($/) { make evaluate( $/<any-expr> ) }

  sub evaluate($expr) {
    if $expr.caps.elems > 1 {
      return ($expr.caps).reduce: -> $left is rw, (:value(:$op),|), $right
is rw {
        $left = evaluate($left<operand>) unless $left ~~ Numeric;
        $right= evaluate($right<operand>);
        given $op {
          when '+' { $left + $right }
          when '-' { $left - $right }
        }
      }
    }

    return $expr<bracketed-expr> ?? evaluate($expr<bracketed-expr><any-expr>)
!! $expr;
  }

}

# Try it out
say Sums.parse('5', actions => do-sums.new).made; # 5
say Sums.parse('{6}+{8-{9+1+2}}-5', actions => do-sums.new).made; # 6 + -4
- 5

Which is a solution to "how do I keep one grammar, but do different things
when the same token matches in different contexts." Not quite Theo's
original question of "how to make a method behave differently at different
parse depths" still it was a fun way to spend all morning...

I'd like to simplify "sub evaluate"-  in particular the deconstructed
argument $op. That positional parameter is a Pair keyed on 'op', is there a
clearer way of assigning it to $op?

-y

Reply via email to