{"id":13508474,"url":"https://github.com/marcelog/ex_abnf","last_synced_at":"2025-03-16T16:31:07.290Z","repository":{"id":29882193,"uuid":"33427548","full_name":"marcelog/ex_abnf","owner":"marcelog","description":"Parser for ABNF Grammars","archived":false,"fork":false,"pushed_at":"2019-05-30T00:45:36.000Z","size":126,"stargazers_count":61,"open_issues_count":8,"forks_count":12,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-10-12T04:32:07.577Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/marcelog.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}},"created_at":"2015-04-05T02:17:58.000Z","updated_at":"2024-03-08T18:16:58.000Z","dependencies_parsed_at":"2022-07-24T16:47:02.568Z","dependency_job_id":null,"html_url":"https://github.com/marcelog/ex_abnf","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcelog%2Fex_abnf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcelog%2Fex_abnf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcelog%2Fex_abnf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcelog%2Fex_abnf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marcelog","download_url":"https://codeload.github.com/marcelog/ex_abnf/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221665864,"owners_count":16860321,"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":[],"created_at":"2024-08-01T02:00:53.515Z","updated_at":"2024-10-27T10:54:59.831Z","avatar_url":"https://github.com/marcelog.png","language":"Elixir","funding_links":[],"categories":["Lexical analysis"],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/marcelog/ex_abnf.svg)](https://travis-ci.org/marcelog/ex_abnf)\n\n## About\n\nA parser and interpreter written in [Elixir](http://elixir-lang.org/) for [ABNF grammars](https://en.wikipedia.org/wiki/Augmented_Backus%E2%80%93Naur_Form).\n\nABNF is defined in the [RFC2234](https://tools.ietf.org/html/rfc2234), which is\nobsoleted by [RFC4234](https://tools.ietf.org/html/rfc4234), which in turn is\nobsoleted by the [RFC5234](https://tools.ietf.org/html/rfc5234). There's also an update\nin the [RFC7405](https://tools.ietf.org/html/rfc7405).\n\nThis library implements the latest definition (RFC5234) (with erratas #3076, and #2968), and RFC7405.\n\n## Use example\n\n    iex(1)\u003e grammar = ABNF.load_file \"test/resources/ipv4.abnf\"\n    iex(2)\u003e initial_state = %{}\n    iex(2)\u003e ABNF.apply grammar, \"ipv4address\", '250.246.192.34', initial_state\n    %ABNF.CaptureResult{\n      input: '250.246.192.34',\n      rest: '',\n      state: %{ipv4address: '250.246.192.34'},\n      string_text: '250.246.192.34',\n      string_tokens: ['250', '.', '246', '.', '192', '.', '34'],\n      values: [\"Your ip address is: 250.246.192.34\"]\n    }\n\nThe result can be read as an [%ABNF.CaptureResult{}](https://github.com/marcelog/ex_abnf/blob/master/lib/ex_abnf/capture_result.ex)\nwhere:\n * **input**: The original input\n * **rest**: The part of the input that **didn't** match.\n * **state**: The state after running all the rules applied to the input.\n * **string_text**: The rule value as a string (this might or might not be the same  as the rule value, since you can return custom values when adding a reduce code to the rule).\n * **string_tokens**: Each one of the values that compose the string (in this case, [octet, dot, octet, dot, octet, dot, octet]).\n * **values**: The rule value. In this case the value comes from the reduce code in the [grammar itself](https://github.com/marcelog/ex_abnf/blob/master/test/resources/ipv4.abnf#L6).\n\n## More complex examples\n\n* There's a small sample application at [https://github.com/marcelog/ex_abnf_example](https://github.com/marcelog/ex_abnf_example). An article\ndescribing this application is located at [http://marcelog.github.io/articles/abnf_grammars_in_elixir.html](http://marcelog.github.io/articles/abnf_grammars_in_elixir.html).\n\n* The [unit tests](https://github.com/marcelog/ex_abnf/blob/master/test/ex_abnf_test.exs)\nuse different [sample RFCs](https://github.com/marcelog/ex_abnf/tree/master/test/resources) to\ntest the [grammar parser](https://github.com/marcelog/ex_abnf/blob/master/lib/ex_abnf/grammar.ex)\nand [the interpreter](https://github.com/marcelog/ex_abnf/blob/master/lib/ex_abnf/interpreter.ex)\n\n## How it works\nThis is not a parser generator, but an interpreter. It will load up an ABNF\ngrammar, and generate an (kind of) [AST](http://en.wikipedia.org/wiki/Abstract_syntax_tree)\nfor it. Then you can apply any of the rules to an input and the interpreter\nwill parse the input according to the rule.\n\n## Using it with Mix\n\nTo use it in your Mix projects, first add it as a dependency:\n\n```elixir\ndef deps do\n  [{:ex_abnf, \"~\u003e 0.2.8\"}]\nend\n```\nThen run mix deps.get to install it.\n\n## Adding custom code to reduce rules\nAfter a rule, you can add your own code, for example:\n```\nuserinfo      = *( unreserved / pct-encoded / sub-delims / \":\" ) !!!\n  state = Map.put state, :userinfo, rule\n  {:ok, state}\n!!!\n```\n\nThe code in question will be packed together into a module that is created in\nruntime to speed up execution later on.\n\nYour code can return:\n * **{:ok, state}**: The match continues, and the new state is used for\n future calls.\n\n * **{:ok, state, rule_value}**: Returns a new state but also the **rule_value**\n is used as the result of the match. In YACC terms, rule_value would be the\n equivalent of $$ = ...\n\n * **{:error, error}**: The whole match is aborted and this error is thrown.\n\nAnd your code will be called with the following bindings:\n\n * **state**: This is the state that you can pass when calling the initial\n **ABNF.apply** function, and is a way to keep state through the whole match,\n it can be whatever you like and can mutate through calls as long as your code\n can handle it.\n\n * **values**: When a rule is composed of different tokens\n (e.g: path = SEGMENT \"/\" SEGMENT) this contains a list with all the values of\n those tokens in order. In YACC terms, this would be the equivalent of using\n $1, $2, $3, etc. Note that a value here can be a reduced value returned by\n your own code in a previous rule.\n\n * **string_values**: Just like `values` but each value is a nested list of\n lists with all the characters that matched (you will usually want to flatten\n the list to get each one of the full strings).\n\n## Adding helper code\nYou can also start your grammar with code to write your own helper functions and\nmodule additions. For example:\n```\n!!!\nrequire Logger\ndef return_value(ip) do\n  Logger.debug \"Hello world\"\n  \"Your ip address is: #{ip}\"\nend\n!!!\n\nIPv4address =\n  dec-octet \".\"\n  dec-octet \".\"\n  dec-octet \".\"\n  dec-octet !!!\n    state = Map.put state, :ipv4address, rule\n    {:ok, state, return_value(rule)}\n  !!!\n\ndec-octet = DIGIT         ; 0-9\n  / %x31-39 DIGIT         ; 10-99\n  / \"1\" 2DIGIT            ; 100-199\n  / \"2\" %x30-34 DIGIT     ; 200-249\n  / \"25\" %x30-35          ; 250-255\n\nDIGIT = %x30-39\n```\n\nNote how the result of the `IPv4address` rule is the result of a call to the\nfunction `return_value`.\n\n## Changes from 0.1.x to 0.2.x\n * In the reduce code the rule value is no longer the rule name, but the\n variable `rule`.\n * The grammar text no longer supports `cr` as the newline, one should always\n use `crlf`.\n * In the reduce code there are now available the following variables:\n  * `rule`: The rule value\n  * `string_values`: Like the old `tokens` variable, but contains a nested list\n  of lists with the parsed strings.\n  * `values`: Like the old `tokens` variable, but with the reduced values\n  (could be a mixed nested list of lists containing char_lists and/or other\n  kind of values).\n * Original rule names are now preserverd and only downcased, no replacements\n are done to chars (i.e: `-` to `_`).\n\n## License\nThe source code is released under Apache 2 License.\n\nCheck [LICENSE](https://github.com/marcelog/ex_abnf/blob/master/LICENSE) file\nfor more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcelog%2Fex_abnf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarcelog%2Fex_abnf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcelog%2Fex_abnf/lists"}