instaparse

If you're not trampolining your parser, why bother getting up in the morning?
2017-07-10T15:52:21.468899Z

Hi! In Instaparse, how do I specify operator precedence... I tried ordered choice, but it doesn't do what I want. Simple example:

(def tp (insta/parser "
s = expression
<expression> = binop / integer
integer = #'[0-9]+'
<binop> = times / plus
times = expression <'*'> expression
plus = expression <'+'> expression"
                      :auto-whitespace whitespace))

parser> (tp "5 + 3 * 7")
[:s [:times [:plus [:integer "5"] [:integer "3"]] [:integer "7"]]]
I have seen solutions that distinguish between add-expression and mul-expression, but that doesn't scale very well for more operators

aengelberg 2017-07-10T15:54:22.542391Z

Ordered choice only works when considering parses available at a given position, not when ranking this parse here over another parse over there.

aengelberg 2017-07-10T15:55:19.577682Z

So in your example, your binop / integer was making it try 5 + 3 before 5

2017-07-10T16:26:34.677508Z

ah, so I can fix it by making expression unordered? Or what's the best way?

aengelberg 2017-07-10T16:30:05.794685Z

I don't think ordered choice is the best tool for "order of operations"... I'll send you another example in a sec

2017-07-10T16:32:24.871799Z

Thanks!

aengelberg 2017-07-10T16:36:39.009990Z

@mrchance check out the arithmetic expr parser in https://github.com/engelberg/instaparse#transforming-the-tree

2017-07-10T16:37:03.022937Z

Thanks, I'll check it out

aengelberg 2017-07-10T16:37:28.036028Z

notice how no ordered choice is necessary, because the grammar is structured so that the order of operations follows naturally

2017-07-10T16:54:56.594399Z

hm, ok, but my impression is that would get unwieldy when there is more operators. I'll give it a try though, I don't have that many πŸ˜‰

aengelberg 2017-07-10T16:55:33.614828Z

perhaps. not sure.

aengelberg 2017-07-10T16:57:55.692308Z

Here’s a potentially more elegant way of expressing it (not sure if this actually works):

expr = add-sub
add-sub = mul-div (('+' | '-') mul-div)*
mul-div = term (('*' | '/') term)*
term = number | <'('> add-sub <')'>

2017-07-10T17:32:44.832246Z

hmm, wouldn't this disallow top level multiplication terms?

2017-07-10T17:33:47.867084Z

I am already wishing I had given my own language a lisp syntax πŸ˜‰

aengelberg 2017-07-10T19:22:36.433864Z

@mrchance no, it would end up as [:expr [:add-sub [:mul-div "1" "*" "2"]]]

2017-07-10T23:09:06.226105Z

right πŸ™‚ It worked, btw. For the Moment it's still quite manageable too. Thanks for the fast replies!