{"id":21173461,"url":"https://github.com/rlepigre/ocaml-earley","last_synced_at":"2025-07-09T21:30:28.814Z","repository":{"id":70502815,"uuid":"101325193","full_name":"rlepigre/ocaml-earley","owner":"rlepigre","description":"Parsing library based on Earley Algorithm","archived":false,"fork":false,"pushed_at":"2021-03-27T14:39:42.000Z","size":8906,"stargazers_count":17,"open_issues_count":1,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2023-12-28T00:57:11.440Z","etag":null,"topics":["earley-parser","extensible-parsing","parser-combinators"],"latest_commit_sha":null,"homepage":"https://rlepigre.github.io/ocaml-earley/","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rlepigre.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-08-24T18:22:00.000Z","updated_at":"2023-12-28T00:57:15.171Z","dependencies_parsed_at":"2023-03-25T15:35:19.590Z","dependency_job_id":null,"html_url":"https://github.com/rlepigre/ocaml-earley","commit_stats":null,"previous_names":[],"tags_count":6,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rlepigre%2Focaml-earley","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rlepigre%2Focaml-earley/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rlepigre%2Focaml-earley/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rlepigre%2Focaml-earley/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rlepigre","download_url":"https://codeload.github.com/rlepigre/ocaml-earley/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225592934,"owners_count":17493541,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["earley-parser","extensible-parsing","parser-combinators"],"created_at":"2024-11-20T16:37:28.473Z","updated_at":"2024-11-20T16:37:29.526Z","avatar_url":"https://github.com/rlepigre.png","language":"OCaml","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/rlepigre/ocaml-earley.svg?branch=master)](https://travis-ci.org/rlepigre/ocaml-earley)\n\n# Dependencies\n\n * OCaml (at least 4.07.0)\n * Dune (at least 2.7)\n * stdlib-shims (at least 0.1)\n * GNU Make\n\n# Installation procedure\n\nYou can either pin the repository using Opam with\n```bash\nopam pin add earley https://github.com/rlepigre/ocaml-earley.git\n```\nor clone an install manually with\n```bash\ngit clone https://github.com/rlepigre/ocaml-earley.git\ncd ocaml-earley\nmake\nsudo make install\n```\n\n**Note:** the `make` command will compile `pa_ocaml` from an ascii OCaml files\nin directory `boot` (generated by `pa_ocaml` before distribution). It the does\na second compilation pass using the newly generated `pa_ocaml` binary as the\npreprocessor directly.\n\n# Getting started writing parser with Earley\n\nThe Earley library (`lib` folder), which provides a set of parser combinators,\nis not intended to be used directly (although it can be). Indeed, calls to\nthese combinators can be automatically generated from a BNF-like syntax,\naccessed through a very natural syntax extension for the OCaml language\n(documented bellow).\n\n## Compilation example (single file)\n\nAssuming a project with a single file `my_project.ml`, and no other dependency\nthan Earley, a binary could be produced with the following command.\n```bash\nocamlfind ocamlopt -pp pa_ocaml -package earley -linkpkg -o my_project my_project.ml\n```\n\n## Merlin support\n\nFor Merlin to (roughly) recognise our syntax extension, you can add the\nfollowing line to the `.merlin` file of your project.\n```\nFLG -pp pa_ocaml\n```\n\n# Syntax extension\n\n## Parser expression\n\nA parser expression, corresponding to a value of type `'a Earley.grammar`\n(where `'a` is the type of object the parser produces), can be constructed\nusing:\n```ocaml\nparser\n| RULE1\n| ...\n| RULEN\n```\n\n**Note:** the syntax is similar to `match ... with ...`. The first `|` can be\nomitted, and parentheses are often required around parser expressions. In\nparticular, `parser` is a keyword.\n\n## Parser declaration at the top level\n\nDeclaration of a simple parser:\n```ocaml\nlet parser p1 = (* Here, \"parser\" is a keyword, like \"rec\" in \"let rec\". *)\n  | RULE11\n  | RULE12\n  | ...\n  | RULE1N\n```\n\n**Note:** this syntax is equivalent to:\n```ocaml\nlet p1 =\n  parser\n  | RULE11\n  | RULE12\n  | ...\n  | RULE1N\n```\n\nParsers can be defined mutually recursive with other parsers (and functions):\n```ocaml\nlet parser p1 =\n  | RULE11\n  | RULE12\n  | ...\n  | RULE1N\n\nand f x1 ... xk =\n  ...\n\nand parser p2 =\n  | RULE21\n  | ...\n  | RULE2M\n\nand f x y z ... =\n  ...\n\n...\n\nand parser pK arg =\n  | RULEK1\n  | ...\n  | RULEKM\n```\n\n**Note:** parsers can take arguments (see `pK`).\n\n## Parsing rule\n\nA parsing rule is formed of a sequence of atoms, followed by an action.\n```OCaml\nx1:ATOM1 x2:ATOM2 ... xN:ATOMN -\u003e ACTION\n```\nHere, the parsed input corresponding to `ATOM1` is put in variable `x1`,\nwhich is bound in `ACTION`, and similarly for other atoms. If no labels\nis given in front of an atom, then the parsed input is not recorded.\n\nIf no action is given, the value of the atoms are gathered in a tuple. As\na consequence, the following three rules are equivalent.\n```OCaml\nx1:ATOM1 x2:ATOM2 ... xN:ATOMN -\u003e (x1, ..., xN)\nx1:ATOM1 x2:ATOM2 ... xN:ATOMN\nATOM1 ATOM2 ... ATOMN\n```\n\n**Note:** in fact, in the last rule, only the atoms which value is really\nmeaningful are added to the couple (e.g., atoms corresponding to regexps,\nbut not atoms that only accept a single input string). It is possible to\nprevent a meaningful atom from being added to the couple using the syntax\n`_:ATOM`.\n\n## Positions\n\nFlexible support for positions is provided. It is enabled using a line of\nthe following form, involving a `locate` function. It should be in scope\nand have type `Earley.input -\u003e int -\u003e Earley.input -\u003e int -\u003e t`, where `t`\nis a type of your choice for representing a position.\n```\n#define LOCATE locate\n```\n\nOnce positions have been enabled, position variables of the form `_loc_x`\nare automatically created for each atom label `x`. They are available in\nthe corresponding action. Note that a `_loc` variable is also provided. It\ncorresponds to the full rule.\n\n## Parsing atoms\n\nWe provide atoms of the following form:\n```ocaml\nANY         (* Accepts any character, and returns it. *)\nEOF         (* Accepts only the end of file. *)\nEMPTY       (* Does not accept anything. *)\n'a'         (* Accepts only the character 'a'. *)\nCHR('a')    (* Same as above. *)\n\"ab\"        (* Accepts only the string \"ab\". *)\nSTR(\"ab\")   (* Same as above. *)\n''[ab]+''   (* Accepts the input matching the given regexp, and returns it. *)\nRE(\"[ab]+\") (* Same as above, but needs escaping as with usual Str regexp. *)\n```\n\nMore complex atoms can be built from OCaml expressions or other atoms:\n```ocaml\n(expr)      (* Any OCaml expression corresponding to a parser. *)\nATOM?       (* Optionally accept an ATOM, returns option type. *)\nATOM?[v]    (* Optionally accept an ATOM, returns v as default value. *)\nATOM*       (* Accepts a list of ATOM, returns a list. *)\nATOM+       (* Accepts a non-empty list of ATOM, returns a list. *)\n```\n\nFinally, a parser can be used as an atom with the following syntax:\n```ocaml\n{ RULE1 | RULE2 | ... | RULEN }\n```\n\n## Scanner-less parsing\n\nEarley parsers do not require a lexer. Non-significant parts of the input\n(blank characters, comments, ...) are ignored using a `blank` function,\nwhich is called between every atom. The top level `blank` function is\nprovided when calling a parsing function (see `Earley.parse_file` for\nexample).\n\n**Note:** the current `blank` function can be changed at any time (see the\n`Earley.change_layout` function).\n\n**Note:** blanks can be temporarily disabled between two atoms with the\nsyntax `ATOM1 - ATOM2`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frlepigre%2Focaml-earley","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frlepigre%2Focaml-earley","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frlepigre%2Focaml-earley/lists"}