miller/cmd/experiments/dsl_parser/two/semi3.bnf
2022-01-23 23:22:55 -05:00

93 lines
2.8 KiB
BNF

// ================================================================
// LEXER
!whitespace : ' ' | '\t' | '\n' | '\r' ;
// ================================================================
// IMPORT
<< import "two/src/dsl" >>
// ================================================================
// PARSER
// ----------------------------------------------------------------
Root
: StatementBlock
<< dsl.NewAST($0) >>
;
// ================================================================
StatementBlock
// Empty statement. This allows for 'mlr put ""', as well as repeated semicolons.
: empty
<< dsl.NewASTNodeZary(nil, dsl.NodeTypeStatementBlock) >>
| NonEmptyStatementBlock
<< dsl.Wrap($0) >>
;
// ----------------------------------------------------------------
NonEmptyStatementBlock
// ---------------------- Terminal rules
// Things not ending in a curly brace, like assignments -- and also do-while.
: BracelessStatement
<< dsl.NewASTNodeUnary(nil, $0, dsl.NodeTypeStatementBlock) >>
// Things ending in a curly brace, like for/do/while, begin/end, and pattern-action blocks
| BracefulStatement
<< dsl.NewASTNodeUnary(nil, $0, dsl.NodeTypeStatementBlock) >>
// ---------------------- Recursive rules
// So statements can start with a semicolon
| ";" StatementBlock
<< dsl.Wrap($1) >>
// Normal case for sequential statements like '$x=1; $y=2'
| BracelessStatement ";" StatementBlock
<<dsl.PrependChild($2, $0) >>
// For 'begin {...} ; $x=1'
| BracefulStatement ";" StatementBlock
<<dsl.PrependChild($2, $0) >>
// These are for things like 'begin {...} begin {...} ...' -- where people
// shouldn't have to put semicolons after the closing curly braces.
//
// We get LR-1 conflicts with the following, so we need a pair of more
// explicit lookahead-by-more production rules instead. (By using ternaries
// we are effectively getting lookahead-by-two.)
//
// | BracefulStatement StatementBlock
// <<dsl.PrependChild($1, $0) >>
// E.g. 'begin {...} begin {...} $x=1'
| BracefulStatement BracefulStatement StatementBlock
<<dsl.PrependTwoChildren($2, $0, $1) >>
// E.g. 'begin {...} $x=1'
| BracefulStatement BracelessStatement
<< dsl.NewASTNodeBinary(nil, $0, $1, dsl.NodeTypeStatementBlock) >>
// E.g. 'begin {...} $x=1 ;'
| BracefulStatement BracelessStatement ";"
<< dsl.NewASTNodeBinary(nil, $0, $1, dsl.NodeTypeStatementBlock) >>
| BracefulStatement BracelessStatement ";" NonEmptyStatementBlock
<<dsl.PrependTwoChildren($3, $0, $1) >>
;
// ----------------------------------------------------------------
BracelessStatement
: "x"
<< dsl.NewASTNodeZary($0, dsl.NodeTypeBareBoolean) >>
;
// ----------------------------------------------------------------
BracefulStatement
: "{" StatementBlock "}"
<< dsl.Wrap($1) >>
;