_precSpec:
    IDENTIFIER
    {
        $$(IDENTIFIER);
    }
|
    QUOTE
    {
        $$(QUOTE);
    }
;

_productionElement:
    QUOTE
    {
        $$ = useTerminal();
    }
|
    IDENTIFIER
    {
        $$ = useSymbol();
    }
|
    BLOCK
    {
        $$ = d_scanner.block();
    }
|
    PREC
    _precSpec
    {
        $$ = setPrecedence($2);
    }
;

_productionElements:
    _productionElements _productionElement
    {
        $$ = handleProductionElements($1, $2);
            // process the first element, return the second
            // if the 1st element is a block, handle it as a nested block
    }
|
    _productionElement
    {
        $$ = $1;
    }
;

_production:
    _productionElements
    {
        handleProductionElement($1);
        // process the returned element: if it's a block, it becomes the
        // production's action block
    }
|
    {
        // nothing to do for this empty production. But do check for a typed
        // nonterminal. 
        checkEmptyBlocktype();
    }
;

_productionSeparator:
    '|'
    {
        d_rules.addProduction(d_scanner.lineNr());
    }
;

_productionList:
    _productionList _productionSeparator _production
|
    _production
;

_ruleName:
    identifier
    ':'
    {
        openRule($1);
    }
;

_rule:
    _ruleName
    _productionList
    ';'
    {
        updateDefaultActionLineNr();
    }
;

rules:
    rules _rule
|
    // empty
;

