0

There is a very small calculator in Sedlex and Menhir. Now, I would like to make the calculator to be able to parse expressions like 1+. So I modified parser.mly to

... ...
main:
    expr EOL                { $1 }
;
expr [@recovery (E_int 0)]:
    INT                     { E_int $1 }
  | BOOL                    { E_bool $1 }
... ...

But evaluating 1+ still returned an error Fatal error: exception Parser.MenhirBasics.Error.

Could anyone help?

SoftTimur
  • 5,630
  • 38
  • 140
  • 292
  • [Also asked on discuss](https://discuss.ocaml.org/t/try-partial-parsing-and-recovery-of-menhir/9310). Please also cross-link when you cross-post, to prevent people from spending a lot of time trying to help you solve a problem that's already been solved elsewhere. – glennsl Feb 12 '22 at 10:17
  • It looks like the line you added is missing here, no? The code you put is the one already existing in sedlex-menhir – Lhooq Feb 12 '22 at 11:54
  • @Lhooq The repository contains already the line with `[@recovery (E_int 0)]`, which raises an error for `1+`. – SoftTimur Feb 12 '22 at 12:23
  • And where does this `[@recovery (E_int 0)]` come from? Couldn't find it in menhir's manual – Lhooq Feb 12 '22 at 15:45
  • For instance, Merlin uses `recovery`, see [here](https://github.com/ocaml/merlin/blob/master/src/ocaml/preprocess/parser_raw.mly) and [here](https://arxiv.org/pdf/1807.06702.pdf). – SoftTimur Feb 12 '22 at 15:48
  • 1
    It looks like they defined their own preprocessing for this. recovery is not a keyword in Menhir. Try using the old fashion way with the last token being error and returning `E_int 0` (you'll need to enable the legacy strategy and for this you need to enable --table I think) – Lhooq Feb 12 '22 at 16:00
  • And it would be a good thing to create a proper dune file to build with dune and put your flags for menhir in it – Lhooq Feb 12 '22 at 16:02
  • Thank you... I did a quick search... do you have any example of "the last token being error and returning..."? – SoftTimur Feb 12 '22 at 16:08
  • 1
    http://gallium.inria.fr/~fpottier/menhir/manual.html#sec65 Just write `| error { E_int 0 }` as the last rule for `expr` – Lhooq Feb 12 '22 at 16:10
  • `| error { E_int 0 }` does work with my code. Thank you. – SoftTimur Feb 12 '22 at 16:18

1 Answers1

1

Augmented summary of my comments:

  • [@recovery ...] is a construct specific to Merlin
  • As of now (13/02/2022) it is still possible to define your own error recovery by using the special error token like this:
main:
    expr EOL                { $1 }
;
expr [@recovery (E_int 0)]:
    INT                     { E_int $1 }
  | BOOL                    { E_bool $1 }
  | error                   { E_int 0 }

From menhir's manual:

  • If the error token is used to survive an error and continue parsing, then the legacy strategy should be selected.

  • --strategy strategy.   This switch selects an error-handling strategy, to be used by the code back-end, the table back-end, and the reference interpreter. The available strategies are legacy and simplified.

From OCaml weekly news:

  • Grammars that make more complex use of the error token, and therefore need the legacy strategy, cannot be compiled by the new code back-end. As a workaround, it is possible to switch to the table back-end (using --table --strategy legacy) or to the ancient code back-end (using --code-ancient). In the long run, we recommend abandoning the use of the error token. Support for the error token may be removed entirely at some point in the future.

This way of doing will most likely not work in a near future but it does for now and it appeared to be the simplest way of doing what OP asked.

Lhooq
  • 4,281
  • 1
  • 18
  • 37