{"id":16613324,"url":"https://github.com/yallop/ocaml-re-nfa","last_synced_at":"2025-09-28T17:31:04.510Z","repository":{"id":150610127,"uuid":"156515315","full_name":"yallop/ocaml-re-nfa","owner":"yallop","description":"OCaml code to construct an NFA from a regular expression","archived":false,"fork":false,"pushed_at":"2020-08-05T18:23:31.000Z","size":106,"stargazers_count":50,"open_issues_count":2,"forks_count":7,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-01-13T09:01:54.581Z","etag":null,"topics":["graphviz","graphviz-dot","nfa","ocaml","regex"],"latest_commit_sha":null,"homepage":"","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yallop.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-11-07T08:36:59.000Z","updated_at":"2025-01-07T13:25:24.000Z","dependencies_parsed_at":"2023-04-14T09:32:01.849Z","dependency_job_id":null,"html_url":"https://github.com/yallop/ocaml-re-nfa","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yallop%2Focaml-re-nfa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yallop%2Focaml-re-nfa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yallop%2Focaml-re-nfa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yallop%2Focaml-re-nfa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yallop","download_url":"https://codeload.github.com/yallop/ocaml-re-nfa/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234542468,"owners_count":18849808,"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":["graphviz","graphviz-dot","nfa","ocaml","regex"],"created_at":"2024-10-12T01:46:49.003Z","updated_at":"2025-09-28T17:31:04.140Z","avatar_url":"https://github.com/yallop.png","language":"OCaml","funding_links":[],"categories":[],"sub_categories":[],"readme":"## re-nfa: convert regular expressions to NFAs\n\n[![Travis build Status](https://travis-ci.org/yallop/ocaml-re-nfa.svg?branch=master)](https://travis-ci.org/yallop/ocaml-re-nfa)\n\nThis repository provides a library and executable for converting\nregular expressions into nondeterministic finite automata (NFAs) using\n[Glushkov's construction][glushkov], for converting NFAs into DFAs\nusing the [powerset construction][powerset], for minimizing DFAs using\n[Brzozowski's algorithm][brzozowski] and for formatting the NFAs using\n[DOT][DOT] so that they can be displayed using [graphviz][graphviz].\n\n### Online demo\n\nThe easiest way to try the code is to use the [web UI][web-ui] written\nby [Joel Jakobsson][joelonsql].\n\n### The `re-nfa` executable\n\nThe `re-nfa` executable accepts a single regular expression argument\nand prints a [DOT][DOT] graph for the corresponding NFA or DFA to standard\noutput.  For example, the following command\n\n```\nre-nfa \"a*b\"\n```\n\nproduces the following output.\n\n```dot\ndigraph {\n  \"rankdir\" = \"LR\";\n  node [ \"shape\" = \"none\";] \"\"\n  node [ \"shape\" = \"circle\";] \"1\"\n  node [ \"shape\" = \"doublecircle\";] \"2\"\n  node [ \"shape\" = \"circle\";] \"0\"\n  \"\" -\u003e \"0\" \n  \"1\" -\u003e \"2\" [ \"label\" = \"b\";]\n  \"0\" -\u003e \"2\" [ \"label\" = \"b\";]\n  \"1\" -\u003e \"1\" [ \"label\" = \"a\";]\n  \"0\" -\u003e \"1\" [ \"label\" = \"a\";]\n}\n```\n\nTo display the corresponding DFA or minimized DFA, pass the `-type` argument:\n\n```\nre-nfa -type dfa \"a*b\"\n```\n\n```\nre-nfa -type dfa-minimized \"a*b\"\n```\n\nOn a Unix system you might pipe the output directly to `dot`, and then\non to [`display`][display], like this:\n\n```bash\nre-nfa \"a*b\" | dot -Tpng | display\n```\n\nto display the following graph:\n\n![a*b](/images/astarb.png)\n\nHere is the minimized version:\n\n![a*b](/images/astarb-minimized.png)\n\nHere is a more complex graph constructed from the regex `a?a?a?aaa` that causes pathological backtracking behaviour in some engines, as described in Russ Cox's article [Regular Expression Matching Can Be Simple And Fast][simple-and-fast]:\n\n![a?a?a?aaa](/images/aqaqaqaaa.png)\n\nand here is the corresponding DFA:\n\n![a?a?a?aaa](/images/aqaqaqaaa-dfa.png)\n\n### Library\n\nThis repository also provides a library interface.  The [`Regex`][regex] module provides an [`ocaml-re`][ocaml-re]-style combinator interface for constructing regular expressions\n\n```ocaml\nseq (star (chr 'a')) (chr 'b')     (* a*b *)\n```\n\nas well as functions `parse` and `compile` for building a regular\nexpression from a string and for turning a regular expression into an\nNFA.\n\n\n```ocaml\nval parse : string -\u003e t\nval compile : t -\u003e Nfa.nfa\n```\n\n\nThe [`Nfa`][nfa] module provides a function for testing whether an NFA\naccepts a string (represented as a list of characters):\n\n```ocaml\nval accept : Nfa.t -\u003e char list -\u003e bool\n```\n\nThe [`Nfa_dot`][nfa_dot] module provides functions for converting NFAs\nto DOT directed graphs and for pretty-printing the graphs:\n\n\n```ocaml\nval digraph_of_nfa : Nfa.nfa -\u003e digraph\nval format_digraph : Format.formatter -\u003e digraph -\u003e unit\n```\n\nThe [`Dfa`][dfa] module provides functions for converting between NFAs and DFAs,\na DFA minimization function, and and an `accept` function for DFAs\n\n```ocaml\nval determinize : Nfa.nfa -\u003e dfa\nval inject : dfa -\u003e Nfa.nfa\nval minimize : dfa -\u003e dfa\nval accept : dfa -\u003e char list -\u003e bool\n```\n\n\n### Rationale\n\nThe code in this repository is an extracted and extended portion of\nan exercise from a 2018 [advanced functional programming course][afp-exercises].\nIf you're interested in learning MetaOCaml then you may enjoy\ncompleting the original exercise, perhaps after reading the\n[course notes][afp-notes].\n\nKnowing the provenance of the code helps in understanding some of the\nchoices made.\n\nFor example, there are several algorithms for constructing NFAs, but\nGlushkov's has a property that turns out to be convenient for the\nexercise: it constructs an automaton without ε-transitions.\n\nAdditionally, the code here is not especially efficient; the remainder\nof the original exercise involves using multi-stage programming to\nturn the rather inefficient NFA interpreter into a compiler that\nproduces rather efficient code --- typically more efficient than\nproduction regex engines.  (Similar transformations using\n[Scala LMS][lms] are also described in the literature: see\n[Optimizing data structures in high-level programs: New directions for extensible compilers based on staging][rompf2013] (Rompf et al. 2013))\n\n### Installation\n\nThe `re-nfa` library and executable can be installed via [`OPAM`][opam] by\npinning this repository:\n\n```\nopam pin add re-nfa https://github.com/yallop/ocaml-re-nfa.git\n```\n\n### ReasonML port\n\nA [ReasonML port of this project][reason-port] is available.\n\n[glushkov]: https://en.wikipedia.org/wiki/Glushkov%27s_construction_algorithm\n[DOT]: https://en.wikipedia.org/wiki/DOT_(graph_description_language)\n[graphviz]: https://graphviz.org/\n[ocaml-re]: https://github.com/ocaml/ocaml-re\n[display]: http://imagemagick.sourceforge.net/http/www/display.html\n[simple-and-fast]: https://swtch.com/~rsc/regexp/regexp1.html\n[afp-exercises]: https://www.cl.cam.ac.uk/teaching/1718/L28/assessment.html\n[afp-notes]: https://www.cl.cam.ac.uk/teaching/1718/L28/materials.html\n[lms]: https://scala-lms.github.io/\n[rompf2013]: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.301.2782\n[opam]: https://opam.ocaml.org/\n[regex]: https://github.com/yallop/ocaml-re-nfa/blob/master/lib/regex.mli\n[ocaml-re]: https://github.com/ocaml/ocaml-re\n[nfa]: https://github.com/yallop/ocaml-re-nfa/blob/master/lib/nfa.mli\n[nfa_dot]: https://github.com/yallop/ocaml-re-nfa/blob/master/lib/nfa_dot.mli\n[dfa]: https://github.com/yallop/ocaml-re-nfa/blob/master/lib/dfa.mli\n[web-ui]: https://compiler.org/reason-re-nfa/src/index.html\n[reason-port]: https://github.com/joelonsql/reason-re-nfa\n[joelonsql]: https://github.com/joelonsql\n[powerset]: https://en.wikipedia.org/wiki/Powerset_construction\n[brzozowski]: https://dl.acm.org/citation.cfm?id=2526104\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyallop%2Focaml-re-nfa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyallop%2Focaml-re-nfa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyallop%2Focaml-re-nfa/lists"}