def p_r_genera_escribe_string(p):
    'r_genera_escribe_string : '
    global constant_string

    insertion = const_table.insert_constant(p[-1], 'string', constant_string)

    if insertion != constant_string:
        cuad = Quadruple("write", None, None, insertion)

    else:
        cuad = Quadruple("write", None, None, constant_string)
        constant_string += 1

    cuadruplos.append(cuad)
def p_r_pop_comp(p):
    'r_pop_comp : '
    if len(pila_operadores) > 0:
        if (pila_operadores[len(pila_operadores) - 1] in comp_set):
            operando_der = pila_operandos.pop()
            operando_izq = pila_operandos.pop()
            tipo_der = pila_tipos.pop()
            tipo_izq = pila_tipos.pop()
            operator = pila_operadores.pop()
            print(operator)
            print(tipo_izq)
            print(tipo_der)
            res_type = semantic_cube[tipo_izq][tipo_der][operator]
            print(res_type)
            if res_type != "Error":
                global temporal_float
                global temporal_int
                global temporal_bool

                #verifica que el tipo se tal (ESTE TIPO,-1)
                if res_type == 'float':
                    cuad = Quadruple(operator, operando_izq, operando_der,
                                     temporal_float)
                    pila_operandos.append(temporal_float)
                    temporal_float += 1
                    fun_dict.curr_function.temporal_float_spaces += 1

                elif res_type == 'int':
                    cuad = Quadruple(operator, operando_izq, operando_der,
                                     temporal_int)
                    pila_operandos.append(temporal_int)
                    temporal_int += 1
                    fun_dict.curr_function.temporal_int_spaces += 1

                elif res_type == 'bool':
                    cuad = Quadruple(operator, operando_izq, operando_der,
                                     temporal_bool)
                    pila_operandos.append(temporal_bool)
                    temporal_bool += 1
                    fun_dict.curr_function.temporal_bool_spaces += 1

                pila_tipos.append(res_type)
                tabla_temporales.append((-1, -1))
                cuadruplos.append(cuad)

            else:
                raise Exception("La combinación de tipos no es compatible " +
                                tipo_izq + ' ' + operator + ' ' + tipo_der)
def p_r_if_paso_2(p):
    'r_if_paso_2 : '
    cuad = Quadruple('goto', None, None, None)
    cuadruplos.append(cuad)
    salto = pila_saltos.pop()
    pila_saltos.append(len(cuadruplos) - 1)
    cuadruplos[salto].modificar_resultado(len(cuadruplos))
def p_r_while_paso_2(p):
    'r_while_paso_2 : '
    #preguntar el tipo si el operando es boolano
    resultado = pila_operandos.pop()
    cuad = Quadruple('gotof', resultado, None, None)
    pila_saltos.append(len(cuadruplos))
    cuadruplos.append(cuad)
def p_r_if_paso_1(p):
    'r_if_paso_1 : '
    #preguntar el tipo si el operando es boolano
    result = pila_operandos.pop()
    cuad = Quadruple('gotof', result, None, None)
    cuadruplos.append(cuad)
    pila_saltos.append(len(cuadruplos) - 1)
def p_r_while_paso_3(p):
    'r_while_paso_3 : '
    #preguntar el tipo si el operando es boolano
    salto_al_final = pila_saltos.pop()
    salto_al_regreso = pila_saltos.pop()
    cuad = Quadruple('goto', None, None, salto_al_regreso)
    cuadruplos.append(cuad)
    cuadruplos[salto_al_final].modificar_resultado(len(cuadruplos))
def p_r_for_paso_1(p):
    'r_for_paso_1 : '
    global temporal_bool
    valor_limite = pila_operandos.pop()
    valor_de_comp = pila_operandos.pop()
    #verificar que valor limite sea int
    pila_saltos.append(len(cuadruplos))
    cuad = Quadruple('<', valor_de_comp, valor_limite, temporal_bool)
    pila_operandos.append(valor_de_comp)
    pila_tipos.append('int')
    #pila_operandos.append((0,len(tabla_temporales)))
    #tabla_temporales.append((-1,-1))
    cuadruplos.append(cuad)
    #guardar salto del gotof
    pila_saltos.append(len(cuadruplos))
    #resultado_gotof = pila_operandos.pop()
    cuad2 = Quadruple('gotof', temporal_bool, None, None)
    temporal_bool += 1
    cuadruplos.append(cuad2)
def p_r_verifica_arrexp_dos(p):
    'r_verifica_arrexp_dos : '
    global pointers
    global temporal_int
    global constant_int
    pila_operadores.pop()
    verifica = pila_guardar_variable.pop()
    if (verifica == "tipo arreglo"):
        raise Exception("La variable  no es una matriz")
    name_var = pila_guardar_variable.pop()
    var = fun_dict.get_variable(name_var)
    if ("dim_uno" in var
            and var["dim_uno"] != None) and ("dim_dos" in var
                                             and var["dim_dos"] != None):
        pila_guardar_variable.append("tipo arreglo")
        index = pila_operandos.pop()
        tipo_var = pila_tipos.pop()
        if tipo_var != "int":
            raise Exception("La expresion tiene que ser de tipo entero")

        l_limit = const_table.insert_constant(0, "int", constant_int)
        if l_limit == constant_int:
            constant_int += 1

        u_limit = const_table.insert_constant(var["dim_dos"], "int",
                                              constant_int)
        if u_limit == constant_int:
            constant_int += 1

        quad = Quadruple('ver', index, l_limit, u_limit)
        cuadruplos.append(quad)
        temporal_index = pila_operandos.pop()
        pila_tipos.pop()
        quad = Quadruple('+', temporal_index, index, temporal_int)
        cuadruplos.append(quad)
        quad = Quadruple('+_', temporal_int, var["virtual_address"], pointers)
        cuadruplos.append(quad)
        temporal_int += 1
        pila_tipos.append(var["type"])
        pila_operandos.append(pointers)
        pointers += 1
def p_r_pila_operandos_push(p):
    'r_pila_operandos_push : '
    global temporal_float
    global temporal_int

    oper = pila_guardar_variable.pop()
    if oper != "tipo matriz":
        if oper != "tipo arreglo":
            var = fun_dict.get_variable(oper)
            if var:
                if ("dim_uno" in var and var["dim_uno"] == None) and (
                        "dim_dos" in var and var["dim_dos"] == None):
                    pila_operandos.append(var['virtual_address'])
                    pila_tipos.append(var["type"])
                else:
                    raise Exception("La variable tiene dimensiones")
            else:
                funcion = fun_dict.search_function(oper)
                if not funcion:
                    raise Exception("El identificador " + oper + " no existe")

                else:
                    return_type = funcion.type
                    if return_type == "float":
                        new_quad = Quadruple('=', oper, None, temporal_float)
                        pila_operandos.append(temporal_float)
                        pila_tipos.append("float")
                        temporal_float += 1

                    else:
                        func = fun_dict.search_global(oper + "_func")
                        new_quad = Quadruple('=', func["virtual_address"],
                                             None, temporal_int)
                        pila_operandos.append(temporal_int)
                        pila_tipos.append("int")
                        temporal_int += 1

                    cuadruplos.append(new_quad)

    else:
        raise Exception("La variable debe ser matriz")
def p_r_extraer_parametro(p):
    'r_extraer_parametro : '
    global apuntador_argumento
    print(apuntador_argumento)
    print(tipos_argumentos)
    if apuntador_argumento < len(tipos_argumentos) and len(
            tipos_argumentos) > 0:
        resultado = pila_operandos.pop()
        if tipos_argumentos[apuntador_argumento] == 'int':
            cuad = Quadruple('parameter', resultado, None,
                             "parameter" + str(apuntador_argumento))
            cuadruplos.append(cuad)
            apuntador_argumento += 1
        elif tipos_argumentos[apuntador_argumento] == 'float':
            cuad = Quadruple('parameter', resultado, None,
                             "parameter" + str(apuntador_argumento))
            cuadruplos.append(cuad)
            apuntador_argumento += 1
        else:
            raise Exception(
                "el tipo de argumento no es del tipo del parametro")
    else:
        raise Exception("La funcion no tiene ese numero de parametros")
def p_r_for_paso_2(p):
    'r_for_paso_2 : '
    resultado = pila_operandos.pop()
    #guardar constante 1
    global constant_int
    global temporal_int
    insertion = const_table.insert_constant(1, 'int', constant_int)
    if insertion != constant_int:
        cuad = Quadruple('+', insertion, resultado, temporal_int)

    else:
        cuad = Quadruple('+', constant_int, resultado, temporal_int)
        constant_int += 1

    cuadruplos.append(cuad)
    cuadasignacion = Quadruple('=', temporal_int, None, resultado)
    temporal_int += 1
    cuadruplos.append(cuadasignacion)
    gotof = pila_saltos.pop()
    retorno = pila_saltos.pop()
    cuadgoto = Quadruple('goto', None, None, retorno)
    cuadruplos.append(cuadgoto)
    cuadruplos[gotof].modificar_resultado(len(cuadruplos))
def p_r_return_func(p):
    'r_return_func : '
    global flag_return
    flag_return = True
    result = pila_operandos.pop()
    tipo = pila_tipos.pop()
    if tipo == fun_dict.curr_function.type:
        space = fun_dict.search_global(fun_dict.curr_function.name +
                                       '_func')["virtual_address"]
        cuad = Quadruple('return', space, None, result)
        cuadruplos.append(cuad)

    else:
        curr_func = fun_dict.curr_function
        raise Exception("Error, la función " + curr_func.name +
                        " es de tipo " + curr_func.type +
                        " y el retorno de tipo " + tipo)
def p_r_pop_igu_for(p):
    'r_pop_igu_for : '
    operando_der = pila_operandos.pop()
    operando_izq = pila_operandos.pop()
    tipo_der = pila_tipos.pop()
    tipo_izq = pila_tipos.pop()
    operator = pila_operadores.pop()
    res_type = semantic_cube[tipo_izq][tipo_der][operator]
    if tipo_der == "int" and tipo_izq == "int":
        cuad = Quadruple(operator, operando_der, None, operando_izq)
        #verifica que el tipo se tal (ESTE TIPO,-1)
        #verifica que sea del tipo igual a
        pila_operandos.append(operando_izq)
        pila_tipos.append('int')
        cuadruplos.append(cuad)

    else:
        raise Exception("Los dos operandos deben ser enteros")
def p_r_pop_igu(p):
    'r_pop_igu : '
    if len(pila_operadores) > 0:
        if (pila_operadores[len(pila_operadores) - 1] == '='):
            operando_der = pila_operandos.pop()
            operando_izq = pila_operandos.pop()
            tipo_der = pila_tipos.pop()
            tipo_izq = pila_tipos.pop()
            operator = pila_operadores.pop()
            res_type = semantic_cube[tipo_izq][tipo_der][operator]

            if res_type != "Error":
                cuad = Quadruple(operator, operando_der, None, operando_izq)
                cuadruplos.append(cuad)

            else:
                raise Exception("La combinación de tipos no es compatible " +
                                tipo_izq + ' ' + operator + ' ' + tipo_der)
def p_r_era_funcion_retorno(p):
    'r_era_funcion_retorno : '
    # guardar nombre de la función llamada
    pila_operadores.append("FUNC")
    nombre_func = pila_guardar_variable[-1]
    pila_nombre_func.append(nombre_func)
    func = fun_dict.search_function(nombre_func)
    if func:
        if func.type != "void":
            global apuntador_argumento
            cuad = Quadruple('era', None, None, nombre_func)
            cuadruplos.append(cuad)
            if apuntador_argumento > -1:
                pila_apuntador_argumentos.append(apuntador_argumento)
            if len(tipos_argumentos) > 0:
                apuntador_argumento = 0
        else:
            raise Exception("La función " + nombre_func + " es de tipo void")

    else:
        raise Exception("La función " + nombre_func + " no ha sido declarada")
def p_r_terminar_parametro_void(p):
    'r_terminar_parametro_void : '
    global apuntador_argumento
    global tipos_argumentos
    global temporal_int
    pila_operadores.pop()
    nombrefunc = pila_nombre_func.pop()
    num_quad = fun_dict.search_quad(nombrefunc)
    cuad = Quadruple('gosub', None, None, num_quad)
    cuadruplos.append(cuad)
    if apuntador_argumento != -1:
        if apuntador_argumento < len(tipos_argumentos):
            raise Exception("Faltaron argumentos a la llamada de funcion")
        else:
            if len(pila_apuntador_argumentos) > 0:
                apuntador_argumento = pila_apuntador_argumentos.pop()
            else:
                apuntador_argumento = -1
            if len(pila_tipos_argumentos) > 0:
                tipos_argumentos = pila_tipos_argumentos.pop()
            else:
                tipos_argumentos = []
def p_r_endfunc(p):
    'r_endfunc : '
    cuad = Quadruple('endfunc', None, None, None)
    cuadruplos.append(cuad)
def p_r_genera_lectura(p):
    'r_genera_lectura : '
    cuad = Quadruple("read", None, None, pila_operandos.pop())
    pila_tipos.pop()
    cuadruplos.append(cuad)
def p_r_register_gotomain(p):
    'r_register_gotomain : '
    cuad = Quadruple('goto', None, None, None)
    cuadruplos.append(cuad)
    pila_saltos.append(len(cuadruplos) - 1)
def p_r_verifica_arrexp_uno(p):
    'r_verifica_arrexp_uno : '
    global pointers
    global temporal_int
    global constant_int
    name_var = pila_guardar_variable.pop()
    var = fun_dict.get_variable(name_var)

    pila_operadores.pop()
    if var["dim_uno"] == None:
        raise Exception("La variable " + name_var + " no es un arreglo")
    elif ("dim_uno" in var
          and var["dim_uno"] != None) and ("dim_dos" in var
                                           and var["dim_dos"] == None):
        print("Entra")
        index = pila_operandos.pop()
        tipo_var = pila_tipos.pop()
        if tipo_var != "int":
            raise Exception("La expresion tiene que ser de tipo entero")

        l_limit = const_table.insert_constant(0, "int", constant_int)
        if l_limit == constant_int:
            constant_int += 1

        u_limit = const_table.insert_constant(var["dim_uno"], "int",
                                              constant_int)
        if u_limit == constant_int:
            constant_int += 1

        quad = Quadruple('ver', index, l_limit, u_limit)

        cuadruplos.append(quad)
        quad = Quadruple('+_', index, var["virtual_address"], pointers)
        cuadruplos.append(quad)
        pila_tipos.append(var["type"])
        pila_operandos.append(pointers)
        pila_guardar_variable.append("tipo arreglo")
        pointers += 1
    elif ("dim_uno" in var
          and var["dim_uno"] != None) and ("dim_dos" in var
                                           and var["dim_dos"] != None):
        pila_guardar_variable.append(name_var)
        pila_guardar_variable.append("tipo matriz")

        index = pila_operandos.pop()
        tipo_var = pila_tipos.pop()
        if tipo_var != "int":
            raise Exception("La expresion tiene que ser de tipo entero")

        l_limit = const_table.insert_constant(0, "int", constant_int)
        if l_limit == constant_int:
            constant_int += 1

        u_limit = const_table.insert_constant(var["dim_uno"], "int",
                                              constant_int)
        if u_limit == constant_int:
            constant_int += 1

        quad = Quadruple('ver', index, l_limit, u_limit)
        cuadruplos.append(quad)
        print("La dimension dos es:")
        print(var["dim_dos"])
        quad = Quadruple('*_', index, var["dim_dos"], temporal_int)
        cuadruplos.append(quad)
        pila_tipos.append("int")
        pila_operandos.append(temporal_int)
        temporal_int += 1
def p_r_genera_escribe(p):
    'r_genera_escribe : '
    cuad = Quadruple("write", None, None, pila_operandos.pop())
    pila_tipos.pop()
    cuadruplos.append(cuad)