_precSpec:
    IDENTIFIER
    {
        $$ = new Semantic<Tag::SIZE_T>(IDENTIFIER);
    }
|
    QUOTE
    {
        $$ = new Semantic<Tag::SIZE_T>(QUOTE);
    }
;

_productionElement:
    QUOTE
    {
        $$ = new Semantic<Tag::TERMINAL>(useTerminal());
    }
|
    IDENTIFIER
    {
        $$ = new Semantic<Tag::SYMBOL>(useSymbol());
    }
|
    BLOCK
    {
        $$ = new Semantic<Tag::BLOCK>(d_scanner.block());
    }
|
    PREC
    _precSpec
    {
        setPrecedence($2->as<Tag::SIZE_T>());
        $$ = spSemBase();   // a 0-ptr spSemBase indicates 
                            // that a %prec has been handled
    }
;

_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
;

_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();
    }
;

_productionList:
    _productionList _productionSeparator _production
|
    _production
;


_ruleName:
    identifier
    ':'
    {
        openRule($1->as<Tag::STRING>());
    }
;

_rule:
    _ruleName
    _productionList
    ';'
;

rules:
    rules _rule
|
    // empty
;

