When you write a program in a language, the very first thing your interpreter/compiler must do in order to go from a sequence of characters to actual action is to translate that sequence of characters in a higher complexity structure. To do so, first it chunks up your program in a sequence of tokens expressing what each "word" represents. For example, the construct
if foo == 3: print 'hello'
will be converted into
1,0-1,2: NAME 'if'
1,3-1,6: NAME 'foo'
1,7-1,9: OP '=='
1,10-1,11: NUMBER '3'
1,11-1,12: OP ':'
1,13-1,18: NAME 'print'
1,19-1,26: STRING "'hello'"
2,0-2,0: ENDMARKER ''
But note that even something like "if if if if" is correctly made into tokens
1,0-1,2: NAME 'if'
1,3-1,5: NAME 'if'
1,6-1,8: NAME 'if'
1,9-1,11: NAME 'if'
2,0-2,0: ENDMARKER ''
What follows the tokenization is the parsing into a higher level structure that analyzes if the tokens actually make sense taken together, something that the latter example does not, but the first does. To do so, the parser must recognize the actual meaning of the tokens (e.g. the if is a keyword, and foo is a variable), then build a tree out of the tokens, organizing them in a hierarchy and see if this hierarchy actually makes sense. Here is where the grammar you are seeing comes in. That grammar is in BNF, which is a notation to express the constructs the language can recognize. That grammar is digested by a program (for example, bison) which has the magic property of taking that grammar and generate actual C code that does the heavy work for you, normally by recognizing the tokens, organizing them, returning you a parse tree, or tell you where there's a mistake.
Short version: developing a language is about defining tokens and how these tokens are put together to give something meaningful. This is done through the grammar, which you use to generate the actual "parser" code with automated tools.