#include "ast.h"
#include "verify.h"

int checkPromotion_PLUS(Exp *a, Exp *b, int type)
{
  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_int)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_real)) {
    Promote(a, type); 
    return 1;
  }

  return 1;
}

int checkPromotion_MINUS(Exp *a, Exp *b, int type)
{
  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_int)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_real)) {
    Promote(a, type); 
    return 1;
  }

  return 1;
}

int checkPromotion_MUL(Exp *a, Exp *b, int type)
{
  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_int)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_real)) {
    Promote(a, type); 
    return 1;
  }

  return 1;
}

int checkPromotion_DIV(Exp *a, Exp *b, int type)
{
  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_int)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_real)) {
    Promote(a, type); 
    return 1;
  }

  return 1;
}

int checkPromotion_REM(Exp *a, Exp *b, int type)
{
  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_int)) {
    Promote(a, type); 
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_real)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_real)) {
    Promote(a, type); 
    Promote(b, type); 
    return 1;
  }

  return 1;
}

int checkPromotion_EQ(Exp *a, Exp *b, int type)
{
  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_int)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_int)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_real)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_real)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_string)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_realA) &&
      (b->_type == TYPE_intA)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_boolA) &&
      (b->_type == TYPE_intA)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_intA) &&
      (b->_type == TYPE_realA)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_boolA) &&
      (b->_type == TYPE_realA)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_boolA) &&
      (b->_type == TYPE_stringA)) {
    Promote(b, type); 
    return 1;
  }

  return 1;
}

int checkPromotion_OR(Exp *a, Exp *b, int type)
{
  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_int)) {
    Promote(a, type); 
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_int)) {
    Promote(a, type); 
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_int)) {
    Promote(a, type); 
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_int)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_real)) {
    Promote(a, type); 
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_real)) {
    Promote(a, type); 
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_real)) {
    Promote(a, type); 
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_real)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_string)) {
    Promote(a, type); 
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_string)) {
    Promote(a, type); 
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_string)) {
    Promote(a, type); 
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_string)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_bool)) {
    Promote(a, type); 
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_bool)) {
    Promote(a, type); 
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_bool)) {
    Promote(a, type); 
    return 1;
  }

  return 1;
}

int checkPromotion_AND(Exp *a, Exp *b, int type)
{
  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_int)) {
    Promote(a, type); 
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_int)) {
    Promote(a, type); 
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_int)) {
    Promote(a, type); 
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_int)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_real)) {
    Promote(a, type); 
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_real)) {
    Promote(a, type); 
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_real)) {
    Promote(a, type); 
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_real)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_string)) {
    Promote(a, type); 
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_string)) {
    Promote(a, type); 
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_string)) {
    Promote(a, type); 
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_string)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_bool)) {
    Promote(a, type); 
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_bool)) {
    Promote(a, type); 
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_bool)) {
    Promote(a, type); 
    return 1;
  }

  return 1;
}

int checkPromotion_CONV(Exp *a, Exp *b, int type)
{
  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_int)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_int)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_real)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_real)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_string)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_realA) &&
      (b->_type == TYPE_intA)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_boolA) &&
      (b->_type == TYPE_intA)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_intA) &&
      (b->_type == TYPE_realA)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_boolA) &&
      (b->_type == TYPE_realA)) {
    Promote(b, type); 
    return 1;
  }

  if ((a->_type == TYPE_boolA) &&
      (b->_type == TYPE_stringA)) {
    Promote(b, type); 
    return 1;
  }

  return 1;
}

int checkValidExp_PLUS(Exp *a, Exp *b, ArithExp *z)
{
  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_int;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_PLUS(a, b, TYPE_int);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_real;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_PLUS(a, b, TYPE_real);
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_real;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_PLUS(a, b, TYPE_real);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_real;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_PLUS(a, b, TYPE_real);
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_string)) {
    z->_type = TYPE_string;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_PLUS(a, b, TYPE_string);
    return 1;
  }

  if ((a->_type == TYPE_stringA) &&
      (b->_type == TYPE_string)) {
    z->_type = TYPE_stringA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_PLUS(a, b, TYPE_stringA);
    return 1;
  }

  if ((a->_type == TYPE_intA) &&
      (b->_type == TYPE_intA)) {
    z->_type = TYPE_intA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_PLUS(a, b, TYPE_intA);
    return 1;
  }

  if ((a->_type == TYPE_realA) &&
      (b->_type == TYPE_realA)) {
    z->_type = TYPE_realA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_PLUS(a, b, TYPE_realA);
    return 1;
  }

  if ((a->_type == TYPE_stringA) &&
      (b->_type == TYPE_stringA)) {
    z->_type = TYPE_stringA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_PLUS(a, b, TYPE_stringA);
    return 1;
  }

  if ((a->_type == TYPE_boolA) &&
      (b->_type == TYPE_boolA)) {
    z->_type = TYPE_boolA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_PLUS(a, b, TYPE_boolA);
    return 1;
  }

  semantic_prelude();
  printf("%s, %s bad operands to PLUS.\n", a ? typeMap(a->_type) : "(nil)", b ? typeMap(b->_type) : "(nil)");
  blankError();
  return 0;
}

int checkValidExp_MINUS(Exp *a, Exp *b, ArithExp *z)
{
  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_int;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_MINUS(a, b, TYPE_int);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_real;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_MINUS(a, b, TYPE_real);
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_string;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_MINUS(a, b, TYPE_string);
    return 1;
  }

  if ((a->_type == TYPE_stringA) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_stringA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_MINUS(a, b, TYPE_stringA);
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_real;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_MINUS(a, b, TYPE_real);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_real;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_MINUS(a, b, TYPE_real);
    return 1;
  }

  if ((a->_type == TYPE_intA) &&
      (b->_type == TYPE_intA)) {
    z->_type = TYPE_intA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_MINUS(a, b, TYPE_intA);
    return 1;
  }

  if ((a->_type == TYPE_stringA) &&
      (b->_type == TYPE_intA)) {
    z->_type = TYPE_stringA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_MINUS(a, b, TYPE_stringA);
    return 1;
  }

  if ((a->_type == TYPE_realA) &&
      (b->_type == TYPE_realA)) {
    z->_type = TYPE_realA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_MINUS(a, b, TYPE_realA);
    return 1;
  }

  semantic_prelude();
  printf("%s, %s bad operands to MINUS.\n", a ? typeMap(a->_type) : "(nil)", b ? typeMap(b->_type) : "(nil)");
  blankError();
  return 0;
}

int checkValidExp_MUL(Exp *a, Exp *b, ArithExp *z)
{
  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_int;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_MUL(a, b, TYPE_int);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_real;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_MUL(a, b, TYPE_real);
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_string;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_MUL(a, b, TYPE_string);
    return 1;
  }

  if ((a->_type == TYPE_stringA) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_stringA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_MUL(a, b, TYPE_stringA);
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_real;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_MUL(a, b, TYPE_real);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_real;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_MUL(a, b, TYPE_real);
    return 1;
  }

  if ((a->_type == TYPE_stringA) &&
      (b->_type == TYPE_intA)) {
    z->_type = TYPE_stringA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_MUL(a, b, TYPE_stringA);
    return 1;
  }

  semantic_prelude();
  printf("%s, %s bad operands to MUL.\n", a ? typeMap(a->_type) : "(nil)", b ? typeMap(b->_type) : "(nil)");
  blankError();
  return 0;
}

int checkValidExp_DIV(Exp *a, Exp *b, ArithExp *z)
{
  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_int;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_DIV(a, b, TYPE_int);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_real;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_DIV(a, b, TYPE_real);
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_string;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_DIV(a, b, TYPE_string);
    return 1;
  }

  if ((a->_type == TYPE_stringA) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_stringA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_DIV(a, b, TYPE_stringA);
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_real;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_DIV(a, b, TYPE_real);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_real;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_DIV(a, b, TYPE_real);
    return 1;
  }

  if ((a->_type == TYPE_stringA) &&
      (b->_type == TYPE_intA)) {
    z->_type = TYPE_stringA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_DIV(a, b, TYPE_stringA);
    return 1;
  }

  semantic_prelude();
  printf("%s, %s bad operands to DIV.\n", a ? typeMap(a->_type) : "(nil)", b ? typeMap(b->_type) : "(nil)");
  blankError();
  return 0;
}

int checkValidExp_REM(Exp *a, Exp *b, ArithExp *z)
{
  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_int;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_REM(a, b, TYPE_int);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_int;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_REM(a, b, TYPE_int);
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_int;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_REM(a, b, TYPE_int);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_int;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_REM(a, b, TYPE_int);
    return 1;
  }

  semantic_prelude();
  printf("%s, %s bad operands to REM.\n", a ? typeMap(a->_type) : "(nil)", b ? typeMap(b->_type) : "(nil)");
  blankError();
  return 0;
}

int checkValidExp_EQ(Exp *a, Exp *b, Exp *z)
{
  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_int;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_EQ(a, b, TYPE_int);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_real;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_EQ(a, b, TYPE_real);
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_EQ(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_int;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_EQ(a, b, TYPE_int);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_real;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_EQ(a, b, TYPE_real);
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_EQ(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_string)) {
    z->_type = TYPE_string;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_EQ(a, b, TYPE_string);
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_string)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_EQ(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_bool)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_EQ(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_intA) &&
      (b->_type == TYPE_intA)) {
    z->_type = TYPE_intA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_EQ(a, b, TYPE_intA);
    return 1;
  }

  if ((a->_type == TYPE_realA) &&
      (b->_type == TYPE_intA)) {
    z->_type = TYPE_realA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_EQ(a, b, TYPE_realA);
    return 1;
  }

  if ((a->_type == TYPE_boolA) &&
      (b->_type == TYPE_intA)) {
    z->_type = TYPE_boolA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_EQ(a, b, TYPE_boolA);
    return 1;
  }

  if ((a->_type == TYPE_intA) &&
      (b->_type == TYPE_realA)) {
    z->_type = TYPE_intA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_EQ(a, b, TYPE_intA);
    return 1;
  }

  if ((a->_type == TYPE_realA) &&
      (b->_type == TYPE_realA)) {
    z->_type = TYPE_realA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_EQ(a, b, TYPE_realA);
    return 1;
  }

  if ((a->_type == TYPE_boolA) &&
      (b->_type == TYPE_realA)) {
    z->_type = TYPE_boolA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_EQ(a, b, TYPE_boolA);
    return 1;
  }

  if ((a->_type == TYPE_stringA) &&
      (b->_type == TYPE_stringA)) {
    z->_type = TYPE_stringA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_EQ(a, b, TYPE_stringA);
    return 1;
  }

  if ((a->_type == TYPE_boolA) &&
      (b->_type == TYPE_stringA)) {
    z->_type = TYPE_boolA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_EQ(a, b, TYPE_boolA);
    return 1;
  }

  if ((a->_type == TYPE_boolA) &&
      (b->_type == TYPE_boolA)) {
    z->_type = TYPE_boolA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_EQ(a, b, TYPE_boolA);
    return 1;
  }

  semantic_prelude();
  printf("%s, %s bad operands to EQ.\n", a ? typeMap(a->_type) : "(nil)", b ? typeMap(b->_type) : "(nil)");
  blankError();
  return 0;
}

int checkValidExp_OR(Exp *a, Exp *b, LogicExp *z)
{
  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_OR(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_OR(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_OR(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_OR(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_OR(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_OR(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_OR(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_OR(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_string)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_OR(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_string)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_OR(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_string)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_OR(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_string)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_OR(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_bool)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_OR(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_bool)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_OR(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_bool)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_OR(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_bool)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_OR(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_boolA) &&
      (b->_type == TYPE_boolA)) {
    z->_type = TYPE_boolA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_OR(a, b, TYPE_boolA);
    return 1;
  }

  semantic_prelude();
  printf("%s, %s bad operands to OR.\n", a ? typeMap(a->_type) : "(nil)", b ? typeMap(b->_type) : "(nil)");
  blankError();
  return 0;
}

int checkValidExp_AND(Exp *a, Exp *b, LogicExp *z)
{
  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_AND(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_AND(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_AND(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_AND(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_AND(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_AND(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_AND(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_AND(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_string)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_AND(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_string)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_AND(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_string)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_AND(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_string)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_AND(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_bool)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_AND(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_bool)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_AND(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_bool)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_AND(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_bool)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_AND(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_boolA) &&
      (b->_type == TYPE_boolA)) {
    z->_type = TYPE_boolA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_AND(a, b, TYPE_boolA);
    return 1;
  }

  semantic_prelude();
  printf("%s, %s bad operands to AND.\n", a ? typeMap(a->_type) : "(nil)", b ? typeMap(b->_type) : "(nil)");
  blankError();
  return 0;
}

int checkValidExp_CONV(Exp *a, Exp *b, Exp *z)
{
  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_int;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_CONV(a, b, TYPE_int);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_real;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_CONV(a, b, TYPE_real);
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_int)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_CONV(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_int) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_int;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_CONV(a, b, TYPE_int);
    return 1;
  }

  if ((a->_type == TYPE_real) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_real;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_CONV(a, b, TYPE_real);
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_real)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_CONV(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_string) &&
      (b->_type == TYPE_string)) {
    z->_type = TYPE_string;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_CONV(a, b, TYPE_string);
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_string)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_CONV(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_bool) &&
      (b->_type == TYPE_bool)) {
    z->_type = TYPE_bool;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_CONV(a, b, TYPE_bool);
    return 1;
  }

  if ((a->_type == TYPE_intA) &&
      (b->_type == TYPE_intA)) {
    z->_type = TYPE_intA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_CONV(a, b, TYPE_intA);
    return 1;
  }

  if ((a->_type == TYPE_realA) &&
      (b->_type == TYPE_intA)) {
    z->_type = TYPE_realA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_CONV(a, b, TYPE_realA);
    return 1;
  }

  if ((a->_type == TYPE_boolA) &&
      (b->_type == TYPE_intA)) {
    z->_type = TYPE_boolA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_CONV(a, b, TYPE_boolA);
    return 1;
  }

  if ((a->_type == TYPE_intA) &&
      (b->_type == TYPE_realA)) {
    z->_type = TYPE_intA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_CONV(a, b, TYPE_intA);
    return 1;
  }

  if ((a->_type == TYPE_realA) &&
      (b->_type == TYPE_realA)) {
    z->_type = TYPE_realA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_CONV(a, b, TYPE_realA);
    return 1;
  }

  if ((a->_type == TYPE_boolA) &&
      (b->_type == TYPE_realA)) {
    z->_type = TYPE_boolA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_CONV(a, b, TYPE_boolA);
    return 1;
  }

  if ((a->_type == TYPE_stringA) &&
      (b->_type == TYPE_stringA)) {
    z->_type = TYPE_stringA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_CONV(a, b, TYPE_stringA);
    return 1;
  }

  if ((a->_type == TYPE_boolA) &&
      (b->_type == TYPE_stringA)) {
    z->_type = TYPE_boolA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_CONV(a, b, TYPE_boolA);
    return 1;
  }

  if ((a->_type == TYPE_boolA) &&
      (b->_type == TYPE_boolA)) {
    z->_type = TYPE_boolA;
    z->_arraybounds = a->_arraybounds; 
    checkPromotion_CONV(a, b, TYPE_boolA);
    return 1;
  }

  semantic_prelude();
  printf("%s, %s bad operands to CONV.\n", a ? typeMap(a->_type) : "(nil)", b ? typeMap(b->_type) : "(nil)");
  blankError();
  return 0;
}

