IronBNF is a context-sensitive derivate of the original BNF notation.
The BNF syntax describe a grammar by defining rules, and each rule may be a block that may contain blocks.
precedence | delimiter | mandatory | description |
---|---|---|---|
1 | : |
yes | Rule delimiter, separate the rule name from the rule definition |
2 | {} |
no | Context delimiter, specify the direct preceding block context (see context addition) |
3 | () |
no | Block delimiter, define a nested block that support multiline definition |
3 | [] |
no | Block delimiter, define a nested block |
4 | [?*+] |
no | Block quantifiers, affects the direct preceding block (see quantification) |
5 | |
no | Block delimiter, behaves like a regular and operator (see concatenation) |
6 | | |
no | Block delimiter, behaves like a regular or operator (see alternation) |
This is a simple example illustrating it:
rule_name: other_rule
other_rule: (
[ 'a' | 'z' ]+
[ 'A' | 'Z' ]+
)
The entry point of any BNF grammar is the only rule that is not required by other rules. It is the top level of the grammar tree and must be named bnf
as follow:
bnf: line [ eol line ]*
line: [:digit:] '-' [:alnum:]+
eol: ';' | '\n'
Chained blocks without delimiters are concatened by default. Concatenation behaves like a regular and
operator.
If the left operand is valid, the right operand is never checked.
Alternation behaves like a regular or
operator.
If the left operand is not valid, the right operand is never checked.
The quantifier operator specifies how often any preceding block is allowed to occur.
operator | description |
---|---|
? |
Indicates zero or one occurrences |
* |
Indicates zero or more occurrences |
+ |
Indicates one or more occurrences |
This section is the real addition to the original BNF specification. It allows any defined rule to add elements to other rules. The context delimitor may contain a context action following this syntax:
name | syntax | description |
---|---|---|
alternation add | block{|rule} |
The matching block content will be added by alternation to the rule |
concatenation add | block{+rule} |
The matching block content will be added by concatenation to the rule |
If the refered rule does not exist, it is created.
class | regex posix | ASCII range | description |
---|---|---|---|
[:ascii:] |
no | [\x00-\x7F] |
ASCII characters |
[:alnum:] |
yes | [A-Za-z0-9] |
Alphanumeric characters |
[:word:] |
no | [A-Za-z0-9_] |
Alphanumeric characters plus _ |
[:alpha:] |
yes | [A-Za-z] |
Alphabetic characters |
[:blank:] |
yes | [ \t] |
Space and tab |
[:cntrl:] |
yes | [\x00-\x1F\x7F] |
Control characters |
[:digit:] |
yes | [0-9] |
Digits |
[:graph:] |
yes | [\x21-\x7E] |
Visible characters |
[:lower:] |
yes | [a-z] |
Lowercase letters |
[:print:] |
yes | [\x20-\x7E] |
Visible characters and the space character |
[:punct:] |
yes | [!-/:-@\x5B-\x60{-~] |
Punctuation characters |
[:space:] |
yes | [ \t\r\n\v\f] |
Whitespace characters |
[:upper:] |
yes | [A-Z] |
Uppercase letters |
[:xdigit:] |
yes | [A-Fa-f0-9] |
Hexadecimal digits |
This is a simple INI file BNF:
bnf: ini ( eol eol ini )*
ini: section entry+
section: '[' wordspecial ']' eol
entry: word [:blank:]* '=' [:blank:]* wordspecial eol
eol: '\n\r' | '\n' | '\r'
word: [:alpha:] [:alnum:]*
wordspecial: [:alpha:] ( [:alnum:] | '-' )*
A much further example considering this pseudo language code:
alias meh print
define a Hello
print a
alias a world!
meh a
Result: Hello world!
This code defines a variable a
and two aliases meh
and a
. We have the following BNF:
bnf: line ( eol line )*
line: var_decl | alias_decl | print
var_decl: [ alias | keyword ] [:word:]{|var} [ alias | var | value ]
alias_decl: [ alias | keyword ] [:word:]{|alias} [ alias | keyword | var | value ]
print: [ alias | keyword ] [ alias | var | value ]
keyword: 'alias' | 'define' | 'print'
value: [:ascii:]+