def p_postfix_expression(p):
    '''
    postfix_expression : primary_expression
                       | postfix_expression INCREMENT
                       | postfix_expression DECREMENT

    '''
    if len(p) == 2:
        p[0] = p[1]
    else:
        allowed_base = {'int', 'float', 'double', 'char', 'long'}
        allowed_class = {'PointerType'}
        if p[1].type == 'error':
            p[0] = p[1]
        elif p[1].type.class_type == 'BasicType' and p[
                1].type.type in allowed_base:
            p[0] = Node(name="unary_op",
                        value=str(p[1].type) + ': p' + p[2],
                        children=[p[1]],
                        type=p[1].type)
        elif p[1].type.class_type in allowed_class:
            p[0] = Node(name="unary_op",
                        value=str(p[1].type) + ': p' + p[2],
                        children=[p[1]],
                        type=p[1].type)
        else:
            p[0] = p[1]
            p[0].type = 'error'
            Errors(errorType='TypeError',
                   errorText='increment/decrement not possible',
                   token_object=p.slice[-1])
def p_pointer(p):
    '''
    pointer : MULTIPLY
            | pointer MULTIPLY
    '''
    # | MULTIPLY type_qualifier_list
    # | MULTIPLY type_qualifier_list pointer
    # p[0] = [Node("pointer_ref",p[1])]
    # for i in range(2,len(p)):
    #     p[0] += p[i]
    if len(p) == 2:
        type_specifier_symbol = None
        for symbol in reversed(p.stack):
            if symbol.type in ['type_specifier', 'pointer', 'no_pointer']:
                type_specifier_symbol = symbol
                break
        if type_specifier_symbol.value.type == "error":
            p[0] = Node(type="error")
        else:
            p[0] = Node(type=PointerType(
                type=type_specifier_symbol.value.type))
        #p[0] = Node(PointerType(type = p.stack[-1].value.type))
    else:
        p[0] = p[1]
        if p[0].type != "error":
            p[0].type = PointerType(type=p[1].type)

    assert isinstance(p[0], Node), "return object is not Node"
    assert p[0].type == 'error' or isinstance(
        p[0].type, Type), "unexpected type attribute of return object"
def p_direct_declarator(p):
    '''
    direct_declarator : IDENTIFIER
                      | L_PAREN declarator R_PAREN
                      | direct_declarator L_SQBR INT_CONSTANT R_SQBR
    '''
    # | direct_declarator L_SQBR R_SQBR

    if len(p) == 2:
        p[0] = Node(value=p[1], type=p.stack[-1].value.type)
        p[0].data['token'] = p.slice[-1]
    elif p[1] == '(':
        p[0] = p[2]
    else:
        p[0] = p[1]
        if p[0].type == "error":
            return
        if p[0].type.class_type != "PointerType" or len(
                p[0].type.array_size) == 0:
            p[0].type = PointerType(type=p[0].type,
                                    array_size=[p[3]],
                                    array_type=p[0].type)
        else:
            p[0].type = PointerType(type=p[0].type,
                                    array_size=p[0].type.array_size + [p[3]],
                                    array_type=p[0].type.array_type)
        # else:
        #     if p[0].type.class_type == "PointerType" and len(p[0].type.array_size) != 0:
        #         Errors(
        #             errorType='DeclarationError',
        #             errorText="left side size cannot be empty in array",
        #             token_object= p.slice[2]
        #         )
        #         p[0] = Node(type="error")
        #     else:
        #         p[0].type = PointerType(type = p[0].type,array_size=[float('inf')],array_type=p[0].type)

    assert isinstance(p[0], Node), "return object is not Node"
    assert p[0].type == 'error' or isinstance(
        p[0].type, Type), "unexpected type attribute of return object"