{"id":33239337,"url":"https://github.com/Lelio-Brun/Obelisk","last_synced_at":"2025-11-21T13:02:16.426Z","repository":{"id":180684573,"uuid":"90158387","full_name":"Lelio-Brun/Obelisk","owner":"Lelio-Brun","description":"A simple multi-format pretty-printer for Menhir.","archived":false,"fork":false,"pushed_at":"2025-03-24T07:01:28.000Z","size":5494,"stargazers_count":57,"open_issues_count":0,"forks_count":4,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-24T07:42:52.803Z","etag":null,"topics":["latex","menhir","ocaml","parser","pretty-print"],"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/Lelio-Brun.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","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":"2017-05-03T14:30:07.000Z","updated_at":"2025-03-24T06:57:54.000Z","dependencies_parsed_at":null,"dependency_job_id":"9c6ea1a4-7ccf-486d-a008-534e49d9e8ea","html_url":"https://github.com/Lelio-Brun/Obelisk","commit_stats":null,"previous_names":["lelio-brun/obelisk"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/Lelio-Brun/Obelisk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lelio-Brun%2FObelisk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lelio-Brun%2FObelisk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lelio-Brun%2FObelisk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lelio-Brun%2FObelisk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Lelio-Brun","download_url":"https://codeload.github.com/Lelio-Brun/Obelisk/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lelio-Brun%2FObelisk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":285620632,"owners_count":27203062,"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","status":"online","status_checked_at":"2025-11-21T02:00:06.175Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["latex","menhir","ocaml","parser","pretty-print"],"created_at":"2025-11-16T19:00:41.512Z","updated_at":"2025-11-21T13:02:16.419Z","avatar_url":"https://github.com/Lelio-Brun.png","language":"OCaml","funding_links":[],"categories":["Compilers and Compiler Tools"],"sub_categories":[],"readme":"# Obelisk ![Build Status](https://github.com/Lelio-Brun/Obelisk/actions/workflows/main.yml/badge.svg?branch=master) [![Mentioned in Awesome OCaml](https://awesome.re/mentioned-badge.svg)](https://github.com/rizo/awesome-ocaml)\n\nObelisk is a simple tool that produces pretty-printed output from a [Menhir] parser file (_.mly_).\n\nIt is inspired by [yacc2latex] and is also written in [OCaml] but is aimed at supporting features from Menhir instead of only those of [ocamlyacc].\n\n## Installation\n### Dependencies\n- [OCaml] ≥ 4.08\n- [Dune] ≥ 2.7\n- [Menhir] ≥ 20190613\n- [Re] ≥ 1.7.2\n\nThe Makefile also uses [imagemagick] and [wkhtmltopdf] to build documentation images.\n\nIn addition to the package [xparse], which is used to define starred commands, here is a summary of package dependencies for the different LaTeX modes: \n\n- `-tabular`: [tabu]\n- `-simplebnf`: [simplebnf]\n- `-syntax`: [syntax] from the bundle [mdwtools] \n- `-backnaur`: [backnaur]\n\n### OPAM\nIf you use [OPAM], simply type:\n```\nopam install obelisk\n```\n\n### Manual installation\n`git clone` to clone the Obelisk repository,y, then type:\n```\ndune build\n```\n\nThis will provide you with an executable which you can feed _.mly_ files with: `dune exec src/main.exe -- \u003coptions\u003e \u003cfile.mly\u003e`.\n\nIf you want to install Obelisk, you can type:\n```\ndune install [--prefix \u003cthe destination directory\u003e]\n```\n\n## Usage\n```\nobelisk [ebnf|latex|html] [options] \u003cfiles\u003e\n```\n\nIf multiple files are specified, Obelisk will output a concatenated result without consistency checks. \nThe user is responsible for avoiding, e.g., name clashes between the several files.\n\nBy default, Obelisk defaults to standard output; use `-o \u003cfile\u003e` to specify an output file.\n\n### Pattern recognition\nObelisk can infer some common patterns (possibly parameterized):\n- options\n- lists and non-empty lists\n- separated lists and non-empty separated lists\n\nOnce recognized, if the `-i` switch is specified, the rules are deleted, and their instances are replaced with default constructions (e.g., *\\_\\**, *\\_+*, *[\\_]*).\nWithout the `-i` flag, only the productions of the recognized rules are replaced, and the total number of rules remains the same.\n\nFor example, on these simple rules (from this [file](misc/reco.mly)):\n```\nmy_option(X, Y):\n  |     {}\n  | Y X {}\n\nmy_list(A):\n  |              {}\n  | A my_list(A) {}\n\nmy_nonempty_list(C):\n  | C                     {}\n  | C my_nonempty_list(C) {}\n\nmy_separated_nonempty_list(X,Y):\n  | X                                   {}\n  | X Y my_separated_nonempty_list(X,Y) {}\n\nmy_separated_list(X,S):\n  |                                 {}\n  | my_separated_nonempty_list(X,S) {}\n\nmy_rule:\n  | my_option(E, F)                    {}\n  | my_list(E)                         {}\n  | my_nonempty_list(F)                {}\n  | my_separated_nonempty_list(E,S1)   {}\n  | my_separated_list(F,S2)            {}\n```\nObelisk (`obelisk misc/reco.mly`) outputs:\n```\n\u003cmy_option(X, Y)\u003e ::= [Y X]\n\n\u003cmy_list(A)\u003e ::= A*\n\n\u003cmy_nonempty_list(C)\u003e ::= C+\n\n\u003cmy_separated_nonempty_list(X, Y)\u003e ::= X (Y X)*\n\n\u003cmy_separated_list(X, S)\u003e ::= [X (S X)*]\n\n\u003cmy_rule\u003e ::= \u003cmy_option(E, F)\u003e\n            | \u003cmy_list(E)\u003e\n            | \u003cmy_nonempty_list(F)\u003e\n            | \u003cmy_separated_nonempty_list(E, S1)\u003e\n            | \u003cmy_separated_list(F, S2)\u003e\n```\nAnd with the `-i` switch (`obelisk -i misc/reco.mly`):\n```\n\u003cmy_rule\u003e ::= [F E]  \n            | E*\n            | F+\n            | E (S1 E)*\n            | [F (S2 F)*]\n```\n\n### Multi-format output\nBy default, the output format is a simple text format close to the BNF syntax.\nYou can use the subcommands `ebnf`, `latex` or `html` to get, respectively, an EBNF text output,  LaTeX output, or HTML output.\n\nIn default, EBNF, and HTML mode, the option `-noaliases` avoid printing token aliases in the output.\n\n#### EBNF \nIn EBNF mode, parameterized rules are specialized into dedicated regular rules. \nOn the example above (`obelisk ebnf misc/reco.mly`):\n\n```\nmy_rule ::= my_option_0\n          | my_list_0\n          | my_nonempty_list_0\n          | my_separated_nonempty_list_0\n          | my_separated_list_0\n\nmy_option_0 ::= (F E)?\n\nmy_nonempty_list_0 ::= F+\n\nmy_separated_nonempty_list_1 ::= F (S2 F)*\n\nmy_separated_list_0 ::= (F (S2 F)*)?\n\nmy_separated_nonempty_list_0 ::= E (S1 E)*\n\nmy_list_0 ::= E*\n```\nAnd with the `-i` switch (`obelisk ebnf -i misc/reco.mly`):\n\n```\nmy_rule ::= (F E)?   \n          | E*\n          | F+\n          | E (S1 E)*\n          | (F (S2 F)*)?\n```\n\n#### LaTeX\nUse the following options to tweak the LaTeX:\n- `-tabular`: a *tabular*-based format using the [tabu] package (default)\n- `-simplebnf`: use the [simplebnf] package\n- `-syntax`: use the [syntax] package\n- `-backnaur`: use the [backnaur] package (not recommended: manual line-wrapping through this [trick](https://tex.stackexchange.com/a/308753))\n\nEither way, the output may be customized using LaTeX commands that you can redefine to fit your needs.\nThe command names are auto-generated from the terminal names, and because of LaTeX limitations, underscores are removed, and numbers are converted into their Roman form.\n\nBy default, in LaTeX mode, the `-o \u003cgrammar.tex\u003e` switch will produce the standalone LaTeX file _\u003cgrammar.tex\u003e_ which you can directly compile (e.g. with _pdflatex_).\n\nBut in conjunction with `-o \u003cgrammar.tex\u003e`, you can use `-package \u003cdefinitions\u003e` to output two files:\n1. a LaTeX file _\u003cgrammar.tex\u003e_ containing only the grammar contents ;\n2. a package file _\u003cdefinitions.sty\u003e_ (the _.sty_ extension is added automatically) containing the necessary extra package requirements and command definitions.\n\nThese two files are then intended to be included in a user-provided main LaTeX file following this example skeleton:\n```latex\n\\documentclass[preview]{standalone}\n\n\\usepackage{definitions}\n\n\\begin{document}\n\n\\include{grammar}\n\n\\end{document}\n```\n\nTo avoid name clashes, in particular when using the `-package` option and, e.g., importing multiple grammars with the same LaTeX command names, or in the case where one of the syntax construction names matches one already defined LaTeX macro, you can specify a common prefix for the commands with the option `-prefix \u003cmyprefix\u003e`.\n\n\u003e [!WARNING]\n\u003e As `end`-beginning commands are forbidden in LaTeX, commands created from rules with names beginning with `end` are automatically prefixed with `zzz`.\n\n#### HTML\nThe HTML file uses an internal CSS stylesheet that allows customizing the output (in a poorer way than in the `latex` mode).\nThe stylesheet uses `content` properties for some parts of the grammar by default (`-css` option) to make it modular and easily modifiable. \nStill, some symbols are not treated as content and, for example, are not copy-pastable. \nUse the `-nocss` option to turn off the use of such properties.\n\n### Example\nHere are the outputs of the different formats obtained by Obelisk from its own [parser](src/parser. my).\n\n#### Default\n```\n\u003cspecification\u003e ::= \u003crule\u003e* EOF\n\n\u003crule\u003e ::= \u003cold_rule\u003e\n         | \u003cnew_rule\u003e\n\n\u003cold_rule\u003e ::= [\u003cflags\u003e] \u003cident\u003e ATTRIBUTE* \u003cparameters(\u003cident\u003e)\u003e COLON\n               \u003coptional_bar\u003e \u003cgroup\u003e (BAR \u003cgroup\u003e)* SEMICOLON*\n\n\u003cflags\u003e ::= PUBLIC\n          | INLINE\n          | PUBLIC INLINE\n          | INLINE PUBLIC\n\n\u003coptional_bar\u003e ::= [BAR]\n\n\u003cgroup\u003e ::= \u003cproduction\u003e (BAR \u003cproduction\u003e)* ACTION [\u003cprecedence\u003e]\n\n\u003cproduction\u003e ::= \u003cproducer\u003e* [\u003cprecedence\u003e]\n\n\u003cproducer\u003e ::= [LID EQ] \u003cactual\u003e ATTRIBUTE* SEMICOLON*\n\n\u003cgeneric_actual(A, B)\u003e ::= \u003cident\u003e \u003cparameters(A)\u003e\n                         | B \u003cmodifier\u003e\n\n\u003cactual\u003e ::= \u003cgeneric_actual(\u003clax_actual\u003e, \u003cactual\u003e)\u003e\n\n\u003clax_actual\u003e ::= \u003cgeneric_actual(\u003clax_actual\u003e, \u003cactual\u003e)\u003e\n               | \u003cgroup\u003e (BAR \u003cgroup\u003e)*\n\n\u003cnew_rule\u003e ::= [PUBLIC] LET LID ATTRIBUTE* \u003cparameters(\u003cident\u003e)\u003e \u003cbinder\u003e\n               \u003cexpression\u003e\n\n\u003cbinder\u003e ::= COLONEQ\n           | EQEQ\n\n\u003cexpression\u003e ::= \u003coptional_bar\u003e \u003cseq_expression\u003e (BAR \u003cseq_expression\u003e)*\n\n\u003cseq_expression\u003e ::= [\u003cpattern\u003e EQ] \u003csymbol_expression\u003e SEMICOLON\n                     \u003cseq_expression\u003e\n                   | \u003csymbol_expression\u003e\n                   | \u003caction_expression\u003e\n\n\u003csymbol_expression\u003e ::= \u003cident\u003e \u003cparameters(\u003cexpression\u003e)\u003e\n                      | \u003csymbol_expression\u003e \u003cmodifier\u003e\n\n\u003caction_expression\u003e ::= \u003caction\u003e\n                      | \u003caction\u003e \u003cprecedence\u003e\n                      | \u003cprecedence\u003e \u003caction\u003e\n\n\u003caction\u003e ::= ACTION\n           | POINTFREEACTION\n\n\u003cpattern\u003e ::= LID\n            | UNDERSCORE\n            | TILDE\n            | LPAR [\u003cpattern\u003e (COMMA \u003cpattern\u003e)*] RPAR\n\n\u003cmodifier\u003e ::= OPT\n             | PLUS\n             | STAR\n\n\u003cprecedence\u003e ::= PREC \u003cident\u003e\n\n\u003cparameters(X)\u003e ::= [LPAR [X (COMMA X)*] RPAR]\n\n\u003cident\u003e ::= UID\n          | LID\n          | QID\n```\n\n#### EBNF \n\n```\nspecification ::= rule* EOF\n\nrule ::= old_rule\n       | new_rule\n\nold_rule ::= flags? ident ATTRIBUTE* parameters_0 COLON optional_bar group\n             (BAR group)* SEMICOLON*\n\nflags ::= PUBLIC\n        | INLINE\n        | PUBLIC INLINE\n        | INLINE PUBLIC\n\noptional_bar ::= BAR?\n\ngroup ::= production (BAR production)* ACTION precedence?\n\nproduction ::= producer* precedence?\n\nproducer ::= (LID EQ)? actual ATTRIBUTE* SEMICOLON*\n\nactual ::= generic_actual_0\n\nlax_actual ::= generic_actual_0\n             | group (BAR group)*\n\nnew_rule ::= PUBLIC? LET LID ATTRIBUTE* parameters_0 binder expression\n\nbinder ::= COLONEQ\n         | EQEQ\n\nexpression ::= optional_bar seq_expression (BAR seq_expression)*\n\nseq_expression ::= (pattern EQ)? symbol_expression SEMICOLON seq_expression\n                 | symbol_expression\n                 | action_expression\n\nsymbol_expression ::= ident parameters_2\n                    | symbol_expression modifier\n\naction_expression ::= action\n                    | action precedence\n                    | precedence action\n\naction ::= ACTION\n         | POINTFREEACTION\n\npattern ::= LID\n          | UNDERSCORE\n          | TILDE\n          | LPAR (pattern (COMMA pattern)*)? RPAR\n\nmodifier ::= OPT\n           | PLUS\n           | STAR\n\nprecedence ::= PREC ident\n\nident ::= UID\n        | LID\n        | QID\n\ngeneric_actual_0 ::= ident parameters_1\n                   | actual modifier\n\nparameters_1 ::= (LPAR (lax_actual (COMMA lax_actual)*)? RPAR)?\n\nparameters_0 ::= (LPAR (ident (COMMA ident)*)? RPAR)?\n\nparameters_2 ::= (LPAR (expression (COMMA expression)*)? RPAR)?\n```\n\n#### LaTeX\n##### Tabular\n![Tabular](misc/tabular.png)\n\n##### Simplebnf\n![Simplebnf](misc/simplebnf.png)\n\n##### Syntax\n![Syntax](misc/syntax.png)\n\n##### Backnaur\n![Backnaur](misc/backnaur.png)\n\n#### HTML\n##### With CSS content properties\n![HTMLCSS](misc/htmlcss.png) \n\n##### Without CSS content properties\n![HTMLNOCSS](misc/html.png) \n\n[Menhir]: http://gallium.inria.fr/~fpottier/menhir/\n[Re]: https://github.com/ocaml/ocaml-re/\n[Dune]: https://github.com/ocaml/dune/\n[yacc2latex]: http://www-verimag.imag.fr/~raymond/index.php/yacc2latex/\n[ocamlyacc]: https://caml.inria.fr/pub/docs/manual-ocaml/lexyacc.html#sec307\n[OCaml]: http://ocaml.org/\n[OPAM]: http://opam.ocaml.org/\n[wkhtmltopdf]: https://wkhtmltopdf.org/\n[imagemagick]: http://www.imagemagick.org/script/index.php\n[xparse]: https://ctan.org/pkg/xparse\n[tabu]: https://www.ctan.org/pkg/tabu\n[mdwtools]: https://www.ctan.org/pkg/mdwtools\n[simplebnf]: https://www.ctan.org/pkg/simplebnf\n[syntax]: https://www.ctan.org/pkg/syntax-mdw\n[backnaur]: https://www.ctan.org/pkg/backnaur\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FLelio-Brun%2FObelisk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FLelio-Brun%2FObelisk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FLelio-Brun%2FObelisk/lists"}