-
-
Save zehnpaard/124a9c6df632839d01b4fede8684ddd8 to your computer and use it in GitHub Desktop.
OCaml template for menhir/ocamllex/dune indentation-aware parser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(menhir | |
(modules parser)) | |
(ocamllex lexer) | |
(executable | |
(name ex)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type t = Int of int | |
| Add of t * t |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
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 } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%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 } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
+ | |
1 | |
2 | |
+ | |
3 | |
4 | |
5 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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