_m_contents:
    {
        d_expect = "character class";
    }
;

_cc_start:
    CC_START
    _m_contents
    {
        $$ = CharClass(d_matched, 1);   // skips the opening bracket
    }
;

_cc_negated:
    CC_NEGATED
    _m_contents
    {                                   // skips bracked and negation caret
        $$ = CharClass(d_matched, 2); 
    }
;

_cc_end:
    ']'
    {
        d_expect = "pattern or action block";
    }
;

    // characters handled identically within a character-set
_cc_literal:
    '/'
|
    '|'
|
    '('
|
    ')'
|
    '*'
|
    '+'
|
    '?'
|
    '{'
|
    '}'
|
    '<'
|
    '>'
|
    '['
|
    '.'
|
    '^'
|
    '$'
|
    DOLLAR
|
    DECIMAL
|
    IDENTIFIER
|
    CHAR
|
    STRING
|
    combi_chars
;

_cc_escape:
    ESCAPE_SEQUENCE
|
    QUOTES
;

_cc_element:
    _cc_escape
    {
        $$ = CharClass::chars(d_matched);
    }
|
    PREDEFINED_CLASS
    {
       $$ = CharClass::predefined(d_matched);
    }
|
    _cc_literal
    {
        $$ = CharClass::chars(d_matched);
    }
;

_cc_contents:
    _cc_contents _cc_element
    {
        $<VECTOR>1.push_back($2);
    }
|
    _cc_element
    {
        $$ = vector<string>(1, $1);
    }
;

_cc_set:
    _cc_start _cc_end
|
    _cc_negated _cc_end
    {
        $<CHARCLASS>1.negate();
    }
|    
    _cc_start _cc_contents _cc_end
    {
        $<CHARCLASS>1.append($2);
    }
|
    _cc_negated _cc_contents _cc_end
    {
        $<CHARCLASS>1.negate($2);
    }
;

characterclass:
    characterclass CC_PLUS characterclass
    {
        $$ = CharClass::unite($1, $3);
    }
|
    characterclass CC_MINUS characterclass
    {
        $$ = CharClass::difference($1, $3);
    }
|
    _cc_set
;

