Skip to content

Instantly share code, notes, and snippets.

@zehnpaard
Created June 10, 2019 09:31
Show Gist options
  • Save zehnpaard/124a9c6df632839d01b4fede8684ddd8 to your computer and use it in GitHub Desktop.
Save zehnpaard/124a9c6df632839d01b4fede8684ddd8 to your computer and use it in GitHub Desktop.
OCaml template for menhir/ocamllex/dune indentation-aware parser
(menhir
(modules parser))
(ocamllex lexer)
(executable
(name ex))
let rec eval = function
| Exp.Int n -> n
| Exp.Add ns -> List.map eval ns |> List.fold_left (+) 0
let _ =
Lexing.from_channel stdin
|> Parser.f Indenter.f
|> eval
|> string_of_int
|> print_endline
type t = Int of int
| Add of t * t
module P = Parser
let convert_space_to_indent width f =
let indent = ref 0 in
let make_indent _ = [P.BR; P.INDENT] in
let make_dedent _ = [P.BR; P.DEDENT] in
let g h a b = List.init (a - b) h |> List.concat in
fun lexbuf -> match f lexbuf with
| P.SPACE n ->
let m = n / width in
let k = !indent in
if m > k then (indent := m; g make_indent m k)
else if m < k then (indent := m; g make_dedent k m)
else [P.BR]
| P.EOF ->
let k = !indent in
(indent := 0; g make_dedent k 0 @ [P.EOF])
| e -> [e]
let flatten f =
let xs = ref [] in
fun lexbuf -> match !xs with
| x::xs' -> xs := xs'; x
| [] -> (match f lexbuf with
| x::xs' -> xs := xs'; x
| [] -> failwith "Lexer did nto return EOF token")
let f = Lexer.f |> convert_space_to_indent 2 |> flatten
{
open Parser
}
let digit = ['0'-'9']
let num = (digit | ['1'-'9'] digit*)
let indent = '\n' ' '*
let whitespace = [' ' '\t']
rule f = parse
| indent as s { SPACE (String.length s - 1) }
| whitespace+ { f lexbuf }
| num as n { INT (int_of_string n) }
| "+" { ADD }
| eof { EOF }
%token <int> INT
%token ADD
%token EOF
%token <int> SPACE
%token INDENT
%token DEDENT
%token BR
%start f <Exp.t>
%%
f : e = expr; EOF { e }
expr :
| n = INT; BR { Exp.Int n }
| ADD; BR; INDENT; es = list(expr); DEDENT { Exp.Add es }
+
1
2
+
3
4
5
@shonfeder
Copy link

There are a number of helpful examples from the menhir project, showing how to use dune. Here's a simple one: https://gitlab.inria.fr/fpottier/menhir/-/tree/master/demos/calc-ast

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment