experimental new parser:
 - no separate tokenizer
 - builds a concrete parse tree which includes position information
 - then converts the concrete parse tree into an abstract syntax tree.
   This step implements the context-sensitive grammar rules, such as:
   no duplicate keys or save frame names

rationale for moving context-sensitive rule checking out of parser:
 - this allows data which breaks the context-sensitive rules to
   nevertheless be successfully parsed and programatically analyzed.
   The rules are poorly specified -- if someone has data which breaks
   the rules, they will still be able to use this parser on their data
 - simplifies parser, as it is now only responsible for context-free
   parsing and context-free error-reporting

rationale for lack of separate tokenizer:
 - less total code
 - easier to use and test parsers:  no need to mock tokens, which is
   obnoxious and verbose
 - one less interface (between tokenization and ast-parsing stage)
   to worry about
decent error reporting for context-sensitive rules, including position, in tokenless parser's concrete parse tree to AST conversion phase