I want to create parser/lexer for simplified version of LISP. Here is bison/lexer specs:
/* Lexer file */
"(" {return OP;}
")" {return CP;}
[0-9]+ {return NUM;}
["][a-zA-Z]*["] { return STR; }
[ \n\r\f] { /*do nothing*/}
. {return INVALID_TOKEN;}
/* Bison file */
start_expr: components_list
components_list : /*nothing*/
| components_list component
component : OP STR NUM CP
Such string conforms to grammar ("f" 1) ("f"1)( "f" 1)( "f" 1 ). But expression ("f"1) looks pretty awful for me, I decided to add explitily delimiters to grammar (usage of WHITESPACE token of kind [ \n\r\f]+). Something like that:
opt_wspace : /*nothing*/
| WHITESPACE
start_expr: components_list
components_list : /*nothing*/
| components_list component
component : OP opt_wspace STR WHITESPACE NUM opt_wspace CP
But now (as for me) grammar looks terrible, but expressions of kind ("f"1) are disallowed. Another moment is that now I can easyly make mistake in grammar. For example such expressions will not be parsed ("f" 1) ("f" 1) (I forgot to add usage of opt_wspace in components_list).
So my basic question is how to work with delimiters/whitespaces in grammar? I looked grammar of python (https://github.com/python/cpython/blob/master/Grammar/Grammar) but it seems like it has no mention of whitespace expressions/tokens. Here is minor quote:
stmt: simple_stmt | compound_stmt
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | nonlocal_stmt | assert_stmt)
expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) | [('=' (yield_expr|testlist_star_expr))+ [TYPE_COMMENT]] )