1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
//! bnf, a library for parsing Backus–Naur form context-free grammars //! //! Inspired by the JavaScript library [prettybnf](https://github.com/dhconnelly/prettybnf) //! //! //! The code is available on [Github](https://github.com/snewt/bnf) //! //! ## What does a parsable BNF grammar look like? //! //! The following grammar from the [Wikipedia page on Backus-Naur form] //! (https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form#Example) //! exemplifies a compatible grammar. (*Note: parser allows for an optional ';' //! to indicate the end of a producion) //! //! ```text //! <postal-address> ::= <name-part> <street-address> <zip-part> //! //! <name-part> ::= <personal-part> <last-name> <opt-suffix-part> <EOL> //! | <personal-part> <name-part> //! //! <personal-part> ::= <initial> "." | <first-name> //! //! <street-address> ::= <house-num> <street-name> <opt-apt-num> <EOL> //! //! <zip-part> ::= <town-name> "," <state-code> <ZIP-code> <EOL> //! //! <opt-suffix-part> ::= "Sr." | "Jr." | <roman-numeral> | "" //! <opt-apt-num> ::= <apt-num> | "" //! ``` //! //! ## Output //! Take the following grammar for DNA sequences to be input to this library's //! `parse` function. //! ```text //! <dna> ::= <base> | <base> <dna> //! <base> ::= "A" | "C" | "G" | "T" //! ``` //! //! The output is a `Grammar` object representing a tree that looks like this: //! ```text //! Grammar { //! productions: [ //! Production { //! lhs: Nonterminal( //! "dna" //! ), //! rhs: [ //! Expression { //! terms: [ //! Nonterminal( //! "base" //! ) //! ] //! }, //! Expression { //! terms: [ //! Nonterminal( //! "base" //! ), //! Nonterminal( //! "dna" //! ) //! ] //! } //! ] //! }, //! Production { //! lhs: Nonterminal( //! "base" //! ), //! rhs: [ //! Expression { //! terms: [ //! Terminal( //! "A" //! ) //! ] //! }, //! Expression { //! terms: [ //! Terminal( //! "C" //! ) //! ] //! }, //! Expression { //! terms: [ //! Terminal( //! "G" //! ) //! ] //! }, //! Expression { //! terms: [ //! Terminal( //! "T" //! ) //! ] //! } //! ] //! } //! ] //! } //! ``` //! //! Once the `Grammar` object is populated you can generate a random sentence //! from it by calling the object's generate function. `grammar.generate()`. //! For the above grammar you could expect something like "T" "TGGC" or "AG". //! //! If the generate function can't find a production for a nonterminal it tries //! to evaluate it will produce the identifer as is, i.e. `<identifier>`. //! //! The generate function will return an error if it detects an infinite loop //! caused by a production such as `<PATTERN> ::= <PATTERN>`. //! //! ## Parse Example //! //! ```rust //! extern crate bnf; //! use bnf::Grammar; //! //! fn main() { //! let input = //! "<postal-address> ::= <name-part> <street-address> <zip-part> //! //! <name-part> ::= <personal-part> <last-name> <opt-suffix-part> <EOL> //! | <personal-part> <name-part> //! //! <personal-part> ::= <initial> \".\" | <first-name> //! //! <street-address> ::= <house-num> <street-name> <opt-apt-num> <EOL> //! //! <zip-part> ::= <town-name> \",\" <state-code> <ZIP-code> <EOL> //! //! <opt-suffix-part> ::= \"Sr.\" | \"Jr.\" | <roman-numeral> | \"\" //! <opt-apt-num> ::= <apt-num> | \"\""; //! //! let grammar = Grammar::from_str(input); //! match grammar { //! Ok(g) => println!("{:#?}", g), //! Err(e) => println!("Failed to make grammar from String: {}", e), //! } //! } //! ``` //! //! ## Generate Example //! //! ```rust //! extern crate bnf; //! use bnf::Grammar; //! //! fn main() { //! let input = //! "<dna> ::= <base> | <base> <dna> //! <base> ::= \"A\" | \"C\" | \"G\" | \"T\""; //! let grammar = Grammar::from_str(input).unwrap(); //! let sentence = grammar.generate(); //! match sentence { //! Ok(s) => println!("random sentence: {}", s), //! Err(e) => println!("something went wrong: {}!", e) //! } //! } //! ``` //! #[macro_use] extern crate nom; extern crate rand; extern crate stacker; mod parsers; mod error; mod term; mod expression; mod production; mod grammar; pub use term::Term; pub use expression::Expression; pub use production::Production; pub use grammar::Grammar; pub use error::Error;