# -*- cperl -*- %{ use Parse::Lex; our @tokens; our $lexer; BEGIN { @tokens = ( "BLOCK", "BLOCK", "PAGE", "PAGE", "END", "END", "NUMBER", "[0-9]+", "ID", "[a-zA-Z_]+", "STRING", '"[^"]+"', "LEFT_RECT", '\[', "RIGHT_RECT", '\]', "COLON", ',', "SEMICOLON", ';', "TIMES", '\*'); $lexer = Parse::Lex->new(@tokens); $lexer->from(\*STDIN); $lexer->skip("[ \t\n]+"); } sub lex { my $token = $lexer->next(); return ("", undef) unless defined $token; return ($token->name, $token->text); } %} %% FILE: PAGES END { return $_[1] } ; PAGES: PAGE_DEF PAGES { return [$_[1],@{$_[2]}] } | PAGE_DEF { return [$_[1]] } ; PAGE_DEF: PAGE BLOCKS { return $_[2] } ; BLOCKS: BLOCKS BLOCK_DEF SEMICOLON { return [ @{$_[1]}, $_[2]] } | BLOCKS ENTRY SEMICOLON { return [ @{$_[1]}, $_[2]] } | BLOCK_DEF SEMICOLON { return [ $_[1] ] } | ENTRY SEMICOLON { return [ $_[1] ] } ; BLOCK_DEF: BLOCK BLOCKS END { return +{type=>'block', block=>$_[2]} } | BLOCK BLOCKS END TIMES_DEF { return +{type=>'block', block=>$_[2], times=>$_[4]} } ; TIMES_DEF: TIMES ID { return $_[2] } | TIMES NUMBER { return $_[2] } ; ENTRY: ENTRY_DEF { return $_[1] } | ENTRY_DEF TIMES_DEF { $_[1]{times} = $_[2]; return $_[1] } ; ENTRY_DEF: STRING ID LEFT_RECT LOS RIGHT_RECT { return +{type=>'entry',title=>$_[1],ops=>$_[5],id=>$_[2]} } | STRING ID { return +{type=>'entry',title=>$_[1],id=>$_[2]} } | ID LEFT_RECT LOS RIGHT_RECT { return +{type=>'entry',title=>$_[1],ops=>$_[3],id=>$_[1]} } | ID { return +{type=>'entry',title=>$_[1],id=>$_[1]} } ; LOS: STRING { return [$_[1]] } | LOS COLON STRING { return [@{$_[1]}, $_[3]] } ; %%