An example of a grammar that generates arithmetic operations is specified as follows:
<expr> = NUMBER | '(' <expr> <expr> <expr> ')' <op> = '+' | '-' | '*' | '/'
The left hand side of equations in our grammar are called non-terminal symbols, which means that we can generate valid strings in this language's syntax by using the rules defined by the grammer to produce strings that do not contain non-terminal symbols.
Terminal symbols in the above example include
NUMBERwhich represents any numeric literal and anything surrounded by single quotes is also terminal (Note that we won't include the single quotes while substituting). The vertical bar symbols indicates the separation of different options for substitution, for example <op> can be any one of
+, -, *, /. Note that our grammar is recursive
Ironically we speak of formality, but we define our grammar meta syntax using the english language, if it was specified using another syntax then we'd require infinitely many syntax.
<stmt> = <print-stmt> | <if-stmt> <if-stmt> = if <boolean-expr> then <stmt> | if <boolean-expr> then <stmt> else <stmt>
Note that we can fix the above grammar by introducing delimiters like this:
<stmt> = <print-stmt> | <if-stmt> <if-stmt> = if <boolean-expr> then <stmt> fi | if <boolean-expr> then <stmt> else <stmt> fi