def p_ExprSwitchStmt(p):
    '''ExprSwitchStmt : SWITCH SimpleStmt SEMICOLON LCURLY ExprCaseClauseList RCURLY
                 | SWITCH SimpleStmt SEMICOLON Expression LCURLY ExprCaseClauseList RCURLY
                 | SWITCH LCURLY ExprCaseClauseList RCURLY
                 | SWITCH Expression LCURLY ExprCaseClauseList RCURLY
    '''
    global current_scope
    if len(p) == 6:
        l1 = labelGen()
        l2 = labelGen()
        p[0] = TreeNode('ExprSwitchStmt', 0, 'INT')
        p[0].TAC.append_TAC(p[2].TAC)
        t1 = tempGen()
        node = symboltable_node()
        node.name = t1
        node.scope = current_scope
        node.value = p[2].data
        node.type = insertType(p[2].data)
        SymbolTable.add_node(node)
        p[0].TAC.add_line(['=', t1, p[2].data, ''])
        p[0].TAC.append_TAC(p[4].data)
        for i in range(len(p[4].children)):
            p[0].TAC.add_line(
                ['ifgotoeq', t1, p[4].children[i][0], p[4].children[i][1]])
        for i in range(p[4].TAC.length()):
            if i in p[4].TAC.leaders[1:]:
                p[0].TAC.add_line(['goto', l2, '', ''])
            p[0].TAC.add_line(p[4].TAC.code[i])
        p[0].TAC.add_line([l2])
    return
def p_Expression(p):
    '''Expression : UnaryExpr
                 | Expression OR_OR Expression
                 | Expression AMP_AMP Expression
                 | Expression EQ_EQ Expression
                 | Expression NOT_EQ Expression
                 | Expression LT Expression
                 | Expression LT_EQ Expression
                 | Expression GT Expression
                 | Expression GT_EQ Expression
                 | Expression PLUS Expression
                 | Expression MINUS Expression
                 | Expression OR Expression
                 | Expression CARET Expression
                 | Expression STAR Expression
                 | Expression DIVIDE Expression
                 | Expression MODULO Expression
                 | Expression LS Expression
                 | Expression RS Expression
                 | Expression AMP Expression
                 | Expression AND_OR Expression
    '''
    global current_scope
    if len(p) == 2:
        p[0] = p[1]
    elif len(p) == 4:
        expression = p[1].data + p[2] + p[3].data
        expr_node = SymbolTable.search_expr(expression)
        if not expr_node:
            temp = tempGen()
            node = symboltable_node()
            node.name = temp
            node.value = p[1].data + p[2] + p[3].data
            node.expr = p[1].data + p[2] + p[3].data
            node.type = p[1].input_type
            node.scope = current_scope
            SymbolTable.add_node(node)
            #print(f"Evaluating expression {node.value}")
            node.value = evalExpr(p[1], p[2], p[3])
            #SymbolTable.print_symbol_table()
            #print(node.value, node.name)
            p[0] = TreeNode('IDENTIFIER', temp, 'INT', 1, [], p[1].TAC)
            node.exprnode = p[0]
            p[0].TAC.append_TAC(p[3].TAC)
            p[0].TAC.add_line([p[2], p[0].data, p[1].data, p[3].data])
        else:
            p[0] = expr_node.exprnode
    p[0].name = 'Expression'
    return
def p_ShortVarDecl(p):
    '''ShortVarDecl : ExpressionList ASSIGN_OP ExpressionList
                 | Expression ASSIGN_OP Expression
    '''
    global current_scope
    p[0] = TreeNode('ShortVarDecl', 0, 'INT')
    if p[1].name == 'ExpressionList':
        l1 = len(p[1].children)
        l2 = len(p[3].children)
        p[0].TAC.append_TAC(p[3].TAC)
        p[0].TAC.append_TAC(p[1].TAC)
        if l1 == l2:
            for i in range(l1):
                if p[1].children[i].isLvalue == 0:
                    print("*** Error: Cannot assign to constant ***",
                          p.lineno(1))
                else:
                    if SymbolTable.search_node(p[1].children[i].data) == []:
                        node = symboltable_node()
                        node.name = p[1].children[i].data
                        node.type = insertType(p[3].children[i].data)
                        node.scope = current_scope
                        node.value = p[3].children[i].data
                        SymbolTable.add_node(node)
                    p[0].TAC.add_line([
                        p[2], p[1].children[i].data, p[3].children[i].data, ''
                    ])
        else:
            print("*** Error: Assignment mismatch:", l1, "identifier(s) but",
                  l2, "value(s)! ***")
            print(p.lineno(1))

    elif p[1].name == 'Expression':
        if p[1].isLvalue == 0:
            print("*** Error: Cannot declare and assign to constant ***")
            return
        else:
            p[0].TAC.append_TAC(p[3].TAC)
            p[0].TAC.append_TAC(p[1].TAC)
            p[0].TAC.add_line([p[2], p[1].data, p[3].data, ''])
            if SymbolTable.search_node(p[1].data) == []:
                node = symboltable_node()
                node.name = p[1].data
                node.type = insertType(p[3].data)
                node.scope = current_scope
                node.value = p[3].data
                SymbolTable.add_node(node)
            return
def p_UnaryExpr(p):
    '''UnaryExpr : PrimaryExpr
                 | unary_op UnaryExpr
    '''
    global current_scope
    if len(p) == 2:
        p[0] = p[1]
    elif len(p) == 3:
        temp = tempGen()
        node = symboltable_node()
        node.name = temp
        node.value = p[2].data
        node.scope = current_scope
        SymbolTable.add_node(node)
        p[0] = TreeNode('IDENTIFIER', temp, 'INT', 1)
        p[0].TAC.add_line([p[1].data, p[0].data, p[2].data])
    p[0].name = 'UnaryExpr'
    return
def p_VarSpec(p):
    '''VarSpec : IDENTIFIER Type
               | IDENTIFIER EQ Expression
               | IDENTIFIER Type EQ Expression
               | IdentifierList Type
               | IdentifierList EQ ExpressionList
               | IdentifierList Type EQ ExpressionList
    '''
    # Insert into symbol table
    p[0] = TreeNode('VarSpec', 0, 'NONE')
    if hasattr(p[1], 'name') and p[1].name == 'IdentifierList':
        zero_val = TreeNode('decimal_lit', 0, 'INT')
    else:
        p[1] = TreeNode('IDENTIFIER', p[1], 'INT', 1)
        if p[2].input_type != 'NONE':
            node = symboltable_node()
            node.name = p[1].data
            node.value = None
            node.scope = current_scope
            node.type = p[1].input_type
            SymbolTable.add_node(node)
        p[0] = TreeNode('VarSpec', p[1].data, 'INT')
    return
def p_Assignment(p):
    '''Assignment : ExpressionList assign_op ExpressionList
                | Expression assign_op Expression
    '''
    global current_scope
    p[0] = TreeNode('Assignment', 0, 'INT')
    if p[1].name == 'ExpressionList':
        l1 = len(p[1].children)
        l2 = len(p[3].children)
        p[0].TAC.append_TAC(p[3].TAC)
        p[0].TAC.append_TAC(p[1].TAC)
        if l1 == l2:
            for i in range(l1):
                if p[1].children[i].isLvalue == 0:
                    print("*** Error: Cannot assign to constant ***")
                else:
                    #print("Looking for: ", p[1].children[i].data)
                    if SymbolTable.search_node(p[1].children[i].data) == []:
                        node = symboltable_node()
                        node.name = p[1].children[i].data
                        node.type = insertType(p[3].children[i].data)
                        node.scope = current_scope
                        node.value = p[3].children[i].data
                        SymbolTable.add_node(node)

                    if SymbolTable.search_node(
                            p[3].children[i].data
                    ) == [] and p[3].children[i].isLvalue == 1:
                        #print("Looking for: ", p[3].children[i].data)
                        node = symboltable_node()
                        node.name = p[3].children[i].data
                        node.type = insertType(p[3].children[i].data)
                        node.scope = current_scope
                        node.value = p[3].children[i].data
                        SymbolTable.add_node(node)
                    p[0].TAC.add_line([
                        p[2].data, p[1].children[i].data,
                        p[3].children[i].data, ''
                    ])
        else:
            print("*** Error: Assignment mismatch:", l1, "identifier(s) but",
                  l2, "value(s)! ***")

    elif p[1].name == 'Expression':
        # p[0] = TreeNode('Assignment', 0, 'INT', 0, p[1].children + p[3].children, p[1].TAC.append_TAC(p[3].TAC))
        if p[1].isLvalue == 0:
            print("*** Error: Cannot assign to constant ***")
            return
        else:
            p[0].TAC.append_TAC(p[3].TAC)
            p[0].TAC.append_TAC(p[1].TAC)
            p[0].TAC.add_line([p[2].data, p[1].data, p[3].data, ''])
            # and p[1].children[i].isLvalue ==1:
            if SymbolTable.search_node(p[1].data) == []:
                print("*** Error: Variable not declared: ", p[1].data)
            if SymbolTable.search_node(p[3].data) == [] and p[3].isLvalue == 1:
                node = symboltable_node()
                node.name = p[3].data
                node.type = insertType(p[3].data)
                node.scope = current_scope
                node.value = p[3].data
                SymbolTable.add_node(node)
            return