text: /*
     ============================================================================
     NAME : yacc_read.c
  
     PURPOSE : translation of lp-problem and storage in sparse matrix
  
     SHORT : Subroutines for yacc program to store the input in an intermediate
     data-structure. The yacc and lex programs translate the input.  First the
     problemsize is determined and the date is read into an intermediate
     structure, then readinput fills the sparse matrix.
  
     USAGE : call yyparse(); to start reading the input.  call readinput(); to
     fill the sparse matrix.
     ============================================================================
     Rows : contains the amount of rows + 1. Rows-1 is the amount of constraints
     (no bounds) Rows also contains the rownr 0 which is the objective function
  
     Columns : contains the amount of columns (different variable names found in
     the constraints)
  
     Nonnuls : contains the amount of nonnuls = sum of different entries of all
     columns in the constraints and in the objectfunction
  
     Hash_tab : contains all columnnames on the first level of the structure the
     row information is kept under each column structure in a linked list (also
     the objective funtion is in this structure) Bound information is also
     stored under under the column name
  
     First_rside : points to a linked list containing all relational operators
     and the righthandside values of the constraints the linked list is in
     reversed order with respect to the rownumbers
     ============================================================================ */
  #include <string.h>
  #include <limits.h>
  #include <setjmp.h>
  #include "lpkit.h"
  #include "yacc_read.h"
  
  #ifdef FORTIFY
  # include "lp_fortify.h"
  #endif
  
  #define tol 1.0e-10
  #define coldatastep 100
  
  #define HASHSIZE       10007  /* A prime number! */
  
  struct structSOSvars {
    char                 *name;
    int                  col;
    REAL                 weight;
    struct structSOSvars *next;
  };
  
  struct structSOS {
    char                 *name;
    short                type;
    int                  Nvars;
    int                  weight;
    struct structSOSvars *SOSvars, *LastSOSvars;
    struct structSOS     *next;
  };
  
  struct SOSrow {
    int  col;
    REAL value;
    struct SOSrow *next;
  };
  
  struct SOSrowdata {
    short type;
    char *name;
    struct SOSrow *SOSrow;
  };
  
  struct rside /* contains relational operator and rhs value */
  {
    int           row;
    REAL          value;
    REAL          range_value;
    struct rside  *next;
    short         relat;
    short         range_relat;
    char          negate;
    short         SOStype;
  };
  
  struct column
  {
    int            row;
    REAL           value;
    struct  column *next;
    struct  column *prev;
  };
  
  struct structcoldata {
    int               must_be_int;
    int               must_be_sec;
    int               must_be_free;
    REAL              upbo;
    REAL              lowbo;
    struct  column   *firstcol;
    struct  column   *col;
  };
  
  static void error(parse_parm *pp, int verbose, char *string)
  {
    if(pp == NULL)
      report(NULL, CRITICAL, string);
    else if(pp->Verbose >= verbose)
      report(NULL, verbose, "%s on line %d\n", string, pp->lineno);
  }
  
  /*
   * error handling routine for yyparse()
   */
  void read_error(parse_parm *pp, void *scanner, char *string)
  {
    error(pp, CRITICAL, string);
  }
  
  /* called when lex gets a fatal error */
  void lex_fatal_error(parse_parm *pp, void *scanner, char *msg)
  {
    read_error(pp, scanner, msg);
    longjmp(pp->jump_buf, 1);
  }
  
  void add_row(parse_parm *pp)
  {
    pp->Rows++;
    pp->rs = NULL;
    pp->Lin_term_count = 0;
  }
  
  void add_sos_row(parse_parm *pp, short SOStype)
  {
    if (pp->rs != NULL)
      pp->rs->SOStype = SOStype;
    pp->Rows++;
    pp->rs = NULL;
    pp->Lin_term_count = 0;
  }
  
  void check_int_sec_sos_free_decl(parse_parm *pp, int within_int_decl, int within_sec_decl, int sos_decl0, int within_free_decl)
  {
    pp->Ignore_int_decl = TRUE;
    pp->Ignore_sec_decl = TRUE;
    pp->Ignore_free_decl = TRUE;
    pp->sos_decl = 0;
    if(within_int_decl) {
      pp->Ignore_int_decl = FALSE;
      pp->int_decl = (char) within_int_decl;
      if(within_sec_decl)
        pp->Ignore_sec_decl = FALSE;
    }
    else if(within_sec_decl) {
      pp->Ignore_sec_decl = FALSE;
    }
    else if(sos_decl0) {
      pp->sos_decl = (char) sos_decl0;
    }
    else if(within_free_decl) {
      pp->Ignore_free_decl = FALSE;
    }
  }
  
  static void add_int_var(parse_parm *pp, char *name, short int_decl)
  {
    hashelem *hp;
  
    if((hp = findhash(name, pp->Hash_tab)) == NULL) {
      char buf[256];
  
      sprintf(buf, "Unknown variable %s declared integer, ignored", name);
      error(pp, IMPORTANT, buf);
    }
    else if(pp->coldata[hp->index].must_be_int) {
      char buf[256];
  
      sprintf(buf, "Variable %s declared integer more than once, ignored", name);
      error(pp, IMPORTANT, buf);
    }
    else {
      pp->coldata[hp->index].must_be_int = TRUE;
      if(int_decl == 2) {
        if(pp->coldata[hp->index].lowbo != -DEF_INFINITE * (REAL) 10.0) {
          char buf[256];
  
          sprintf(buf, "Variable %s: lower bound on variable redefined", name);
          error(pp, IMPORTANT, buf);
        }
        pp->coldata[hp->index].lowbo = 0;
        if(pp->coldata[hp->index].upbo < DEF_INFINITE) {
          char buf[256];
  
          sprintf(buf, "Variable %s: upper bound on variable redefined", name);
          error(pp, IMPORTANT, buf);
        }
        pp->coldata[hp->index].upbo = 1;
      }
      else if(int_decl == 3) {
        if(pp->coldata[hp->index].upbo == DEF_INFINITE * (REAL) 10.0)
          pp->coldata[hp->index].upbo = 1.0;
      }
    }
  }
  
  static void add_sec_var(parse_parm *pp, char *name)
  {
    hashelem *hp;
  
    if((hp = findhash(name, pp->Hash_tab)) == NULL) {
      char buf[256];
  
      sprintf(buf, "Unknown variable %s declared semi-continuous, ignored", name);
      error(pp, IMPORTANT, buf);
    }
    else if(pp->coldata[hp->index].must_be_sec) {
      char buf[256];
  
      sprintf(buf, "Variable %s declared semi-continuous more than once, ignored", name);
      error(pp, IMPORTANT, buf);
    }
    else
      pp->coldata[hp->index].must_be_sec = TRUE;
  }
  
  int set_sec_threshold(parse_parm *pp, char *name, REAL threshold)
  {
    hashelem *hp;
  
    if((hp = findhash(name, pp->Hash_tab)) == NULL) {
      char buf[256];
  
      sprintf(buf, "Unknown variable %s declared semi-continuous, ignored", name);
      error(pp, IMPORTANT, buf);
      return(FALSE);
    }
  
    if ((pp->coldata[hp->index].lowbo > 0.0) && (threshold > 0.0)) {
      char buf[256];
  
      pp->coldata[hp->index].must_be_sec = FALSE;
      sprintf(buf, "Variable %s declared semi-continuous, but it has a non-negative lower bound (%f), ignored", name, pp->coldata[hp->index].lowbo);
      error(pp, IMPORTANT, buf);
    }
    if (threshold > pp->coldata[hp->index].lowbo)
      pp->coldata[hp->index].lowbo = threshold;
  
    return(pp->coldata[hp->index].must_be_sec);
  }
  
  static void add_free_var(parse_parm *pp, char *name)
  {
    hashelem *hp;
  
    if((hp = findhash(name, pp->Hash_tab)) == NULL) {
      char buf[256];
  
      sprintf(buf, "Unknown variable %s declared free, ignored", name);
      error(pp, IMPORTANT, buf);
    }
    else if(pp->coldata[hp->index].must_be_free) {
      char buf[256];
  
      sprintf(buf, "Variable %s declared free more than once, ignored", name);
      error(pp, IMPORTANT, buf);
    }
    else
    {
      if(pp->coldata[hp->index].lowbo != -DEF_INFINITE * (REAL) 10.0) {
        char buf[256];
  
        sprintf(buf, "Variable %s: lower bound on variable redefined", name);
        error(pp, IMPORTANT, buf);
      }
  
      if(pp->coldata[hp->index].upbo < DEF_INFINITE) {
        char buf[256];
  
        sprintf(buf, "Variable %s: upper bound on variable redefined", name);
        error(pp, IMPORTANT, buf);
      }
  
      pp->coldata[hp->index].must_be_free = TRUE;
    }
  }
  
  static int add_sos_name(parse_parm *pp, char *name)
  {
    struct structSOS *SOS;
  
    if(CALLOC(SOS, 1, struct structSOS) == NULL)
      return(FALSE);
  
    if(MALLOC(SOS->name, strlen(name) + 1, char) == NULL)
    {
      FREE(SOS);
      return(FALSE);
    }
    strcpy(SOS->name, name);
    SOS->type = 0;
  
    if(pp->FirstSOS == NULL)
      pp->FirstSOS = SOS;
    else
      pp->LastSOS->next = SOS;
    pp->LastSOS = SOS;
  
    return(TRUE);
  }
  
  static int add_sos_var(parse_parm *pp, char *name)
  {
    struct structSOSvars *SOSvar;
  
    if(name != NULL) {
      if(CALLOC(SOSvar, 1, struct structSOSvars) == NULL)
        return(FALSE);
  
      if(MALLOC(SOSvar->name, strlen(name) + 1, char) == NULL)
      {
        FREE(SOSvar);
        return(FALSE);
      }
      strcpy(SOSvar->name, name);
  
      if(pp->LastSOS->SOSvars == NULL)
        pp->LastSOS->SOSvars = SOSvar;
      else
        pp->LastSOS->LastSOSvars->next = SOSvar;
      pp->LastSOS->LastSOSvars = SOSvar;
      pp->LastSOS->Nvars = pp->LastSOS->Nvars + 1;
    }
    pp->LastSOS->LastSOSvars->weight = 0;
  
    return(TRUE);
  }
  
  void storevarandweight(parse_parm *pp, char *name)
  {
    if(!pp->Ignore_int_decl) {
      add_int_var(pp, name, pp->int_decl);
      if(!pp->Ignore_sec_decl)
        add_sec_var(pp, name);
    }
    else if(!pp->Ignore_sec_decl)
      add_sec_var(pp, name);
    else if(pp->sos_decl==1)
      add_sos_name(pp, name);
    else if(pp->sos_decl==2)
      add_sos_var(pp, name);
    else if(!pp->Ignore_free_decl)
      add_free_var(pp, name);
  }
  
  int set_sos_type(parse_parm *pp, int SOStype)
  {
    if(pp->LastSOS != NULL)
      pp->LastSOS->type = (short) SOStype;
    return(TRUE);
  }
  
  int set_sos_weight(parse_parm *pp, double weight, int sos_decl)
  {
    if(pp->LastSOS != NULL) {
      if(sos_decl==1)
        pp->LastSOS->weight = (int) (weight+.1);
      else
        pp->LastSOS->LastSOSvars->weight = weight;
    }
    return(TRUE);
  }
  
  static int inccoldata(parse_parm *pp)
  {
    long Columns = pp->Columns;
  
    if(Columns == 0)
      CALLOC(pp->coldata, coldatastep, struct structcoldata);
    else if((Columns%coldatastep) == 0)
      REALLOC(pp->coldata, Columns + coldatastep, struct structcoldata);
  
    if(pp->coldata != NULL) {
      pp->coldata[Columns].upbo = (REAL) DEF_INFINITE * (REAL) 10.0;
      pp->coldata[Columns].lowbo = (REAL) -DEF_INFINITE * (REAL) 10.0; /* temporary. If still this value then 0 will be taken */
      pp->coldata[Columns].col = NULL;
      pp->coldata[Columns].firstcol = NULL;
      pp->coldata[Columns].must_be_int = FALSE;
      pp->coldata[Columns].must_be_sec = FALSE;
      pp->coldata[Columns].must_be_free = FALSE;
    }
  
    return(pp->coldata != NULL);
  }
  
  /*
   * initialisation of hashstruct and globals.
   */
  static int init_read(parse_parm *pp, int verbose)
  {
    int ok = FALSE;
  
    pp->Verbose = verbose;
    set_obj_dir(pp, TRUE);
    pp->Rows = 0;
    pp->Non_zeros = 0;
    pp->Columns = 0;
    pp->FirstSOS = pp->LastSOS = NULL;
    pp->Lin_term_count = 0;
    if (CALLOC(pp->First_rside, 1, struct rside) != NULL) {
      pp->rs = pp->First_rside;
      pp->rs->value = pp->rs->range_value = 0;
      /* first row (nr 0) is always the objective function */
      pp->rs->relat = OF;
      pp->rs->range_relat = -1;
      pp->rs->SOStype = 0;
      pp->Hash_tab = NULL;
      pp->Hash_constraints = NULL;
      if (((pp->Hash_tab = create_hash_table(HASHSIZE, 0)) == NULL) ||
          ((pp->Hash_constraints = create_hash_table(HASHSIZE, 0)) == NULL)){
        FREE(pp->First_rside);
        FREE(pp->Hash_tab);
        FREE(pp->Hash_constraints);
      }
      else
        ok = TRUE;
    }
    return(ok);
  } /* init */
  
  /*
   * clears the tmp_store variable after all information has been copied
   */
  void null_tmp_store(parse_parm *pp, int init_Lin_term_count)
  {
    pp->tmp_store.value = 0;
    pp->tmp_store.rhs_value = 0;
    FREE(pp->tmp_store.name);
    if(init_Lin_term_count)
      pp->Lin_term_count = 0;
  }
  
  /*
   * variable : pointer to text array with name of variable
   * row      : the rownumber of the constraint
   * value    : value of matrixelement
   *            A(row, variable).
   * Sign     : (global)  determines the sign of value.
   * store()  : stores value in matrix
   *            A(row, variable). If A(row, variable) already contains data,
   *            value is added to the existing value.
   */
  static int store(parse_parm *pp, char *variable,
                   int row,
                   REAL value)
  {
    hashelem *h_tab_p;
    struct column *col_p;
  
    if(value == 0) {
      char buf[256];
  
      sprintf(buf, "(store) Warning, variable %s has an effective coefficient of 0, Ignored", variable);
      error(pp, NORMAL, buf);
      /* return(TRUE); */
    }
  
    if((h_tab_p = findhash(variable, pp->Hash_tab)) == NULL) {
      if (((h_tab_p = puthash(variable, pp->Columns, NULL, pp->Hash_tab)) == NULL)
         ) return(FALSE);
      inccoldata(pp);
      pp->Columns++; /* counter for calloc of final array */
      if(value) {
        if (CALLOC(col_p, 1, struct column) == NULL)
          return(FALSE);
        pp->Non_zeros++; /* for calloc of final arrays */
        col_p->row = row;
        col_p->value = value;
        pp->coldata[h_tab_p->index].firstcol = pp->coldata[h_tab_p->index].col = col_p;
      }
    }
    else if((pp->coldata[h_tab_p->index].col == NULL) || (pp->coldata[h_tab_p->index].col->row != row)) {
      if(value) {
        if (CALLOC(col_p, 1, struct column) == NULL)
          return(FALSE);
        pp->Non_zeros++; /* for calloc of final arrays */
        if(pp->coldata[h_tab_p->index].col != NULL)
          pp->coldata[h_tab_p->index].col->prev = col_p;
        else
          pp->coldata[h_tab_p->index].firstcol = col_p;
        col_p->value = value;
        col_p->row = row;
        col_p->next = pp->coldata[h_tab_p->index].col;
        pp->coldata[h_tab_p->index].col = col_p;
      }
    }
    else if(value) {
      pp->coldata[h_tab_p->index].col->value += value;
      if(fabs(pp->coldata[h_tab_p->index].col->value) < tol) /* eliminitate rounding errors */
        pp->coldata[h_tab_p->index].col->value = 0;
    }
    return(TRUE);
  } /* store */
  
  static int storefirst(parse_parm *pp)
  {
      struct rside *rp;
  
      if ((pp->rs != NULL) && (pp->rs->row == pp->tmp_store.row))
        return(TRUE);
  
      /* make space for the rhs information */
      if (CALLOC(rp, 1, struct rside) == NULL)
        return(FALSE);
      rp->next = pp->First_rside;
      pp->First_rside = pp->rs = rp;
      pp->rs->row = /* row */ pp->tmp_store.row;
      pp->rs->value = pp->tmp_store.rhs_value;
      pp->rs->relat = pp->tmp_store.relat;
      pp->rs->range_relat = -1;
      pp->rs->SOStype = 0;
  
      if(pp->tmp_store.name != NULL) {
        if(pp->tmp_store.value != 0) {
          if (!store(pp, pp->tmp_store.name, pp->tmp_store.row, pp->tmp_store.value))
            return(FALSE);
        }
        else {
          char buf[256];
  
          sprintf(buf, "Warning, variable %s has an effective coefficient of 0, ignored", pp->tmp_store.name);
          error(pp, NORMAL, buf);
        }
      }
      null_tmp_store(pp, FALSE);
      return(TRUE);
  }
  
  /*
   * store relational operator given in yylex[0] in the rightside list.
   * Also checks if it constraint was a bound and if so stores it in the
   * boundslist
   */
  int store_re_op(parse_parm *pp, char OP, int HadConstraint, int HadVar, int Had_lineair_sum)
  {
    short tmp_relat;
  
    switch(OP) {
  
    case '=':
      tmp_relat = EQ;
      break;
  
    case '>':
      tmp_relat = GE;
      break;
  
    case '<':
      tmp_relat = LE;
      break;
  
    case 0:
      if(pp->rs != NULL)
        tmp_relat = pp->rs->relat;
      else
        tmp_relat = pp->tmp_store.relat;
      break;
  
    default:
      {
        char buf[256];
  
        sprintf(buf, "Error: unknown relational operator %c", OP);
        error(pp, CRITICAL, buf);
      }
      return(FALSE);
      break;
    }
  
    if(/* pp->Lin_term_count > 1 */ HadConstraint && HadVar) {/* it is not a bound */
      if(pp->Lin_term_count <= 1)
        if(!storefirst(pp))
          return(FALSE);
      pp->rs->relat = tmp_relat;
    }
    else if(/* pp->Lin_term_count == 0 */ HadConstraint && !Had_lineair_sum /* HadVar */ /* && (pp->rs != NULL) */) { /* it is a range */
      if(pp->Lin_term_count == 1)
        if(!storefirst(pp))
          return(FALSE);
      if(pp->rs == NULL) { /* range before row, already reported */
        error(pp, CRITICAL, "Error: range for undefined row");
        return(FALSE);
      }
  
      if(pp->rs->negate)
        switch (tmp_relat) {
        case LE:
          tmp_relat = GE;
          break;
        case GE:
          tmp_relat = LE;
          break;
        }
  
      if(pp->rs->range_relat != -1) {
        error(pp, CRITICAL, "Error: There was already a range for this row");
        return(FALSE);
      }
      else if(tmp_relat == pp->rs->relat) {
        error(pp, CRITICAL, "Error: relational operator for range is the same as relation operator for equation");
        return(FALSE);
      }
      else
        pp->rs->range_relat = tmp_relat;
    }
    else /* could be a bound */
      pp->tmp_store.relat = tmp_relat;
  
    return(TRUE);
  } /* store_re_op */
  
  int negate_constraint(parse_parm *pp)
  {
      if(pp->rs != NULL)
        pp->rs->negate = TRUE;
  
      return(TRUE);
  }
  
  /*
   * store RHS value in the rightside structure
   * if type = true then
   */
  int rhs_store(parse_parm *pp, REAL value, int HadConstraint, int HadVar, int Had_lineair_sum)
  {
    if(/* pp->Lin_term_count > 1 */ (HadConstraint && HadVar) || (pp->Rows == 0)){ /* not a bound */
      if (pp->Rows == 0)
        value = -value;
      /* if(pp->Lin_term_count < 2) */
      if(pp->rs == NULL)
        pp->tmp_store.rhs_value += value;
      else
  
      if(pp->rs == NULL) {
        error(pp, CRITICAL, "Error: No variable specified");
        return(FALSE);
      }
      else
        pp->rs->value += value;
    }
    else if(/* pp->Lin_term_count == 0 */ HadConstraint && !HadVar) { /* a range */
      if(pp->rs == NULL) /* if range before row, already reported */
        pp->tmp_store.rhs_value += value;
      else if(pp->rs->range_relat < 0) /* was a bad range; ignore */;
      else {
        if(pp->rs->negate)
          value = -value;
        if(((pp->rs->relat == LE) && (pp->rs->range_relat == GE) &&
           (pp->rs->value < value)) ||
          ((pp->rs->relat == GE) && (pp->rs->range_relat == LE) &&
           (pp->rs->value > value)) ||
          ((pp->rs->relat == EQ) || (pp->rs->range_relat == EQ))) {
          pp->rs->range_relat = -2;
          error(pp, CRITICAL, "Error: range restriction conflicts");
          return(FALSE);
        }
        else
          pp->rs->range_value += value;
      }
    }
    else /* a bound */
      pp->tmp_store.rhs_value += value;
    return(TRUE);
  } /* RHS_store */
  
  /*
   * store all data in the right place
   * count the amount of lineair terms in a constraint
   * only store in data-structure if the constraint is not a bound
   */
  int var_store(parse_parm *pp, char *var, REAL value, int HadConstraint, int HadVar, int Had_lineair_sum)
  {
    int row;
  
    row = pp->Rows;
  
    /* also in a bound the same var name can occur more than once. Check for
       this. Don't increment Lin_term_count */
  
    if(pp->Lin_term_count != 1 || pp->tmp_store.name == NULL || strcmp(pp->tmp_store.name, var) != 0)
      pp->Lin_term_count++;
  
    /* always store objective function with rownr == 0. */
    if(row == 0)
      return(store(pp, var,  row,  value));
  
    if(pp->Lin_term_count == 1) { /* don't store yet. could be a bound */
      if(MALLOC(pp->tmp_store.name, strlen(var) + 1, char) != NULL)
        strcpy(pp->tmp_store.name, var);
      pp->tmp_store.row = row;
      pp->tmp_store.value += value;
      return(TRUE);
    }
  
    if(pp->Lin_term_count == 2) { /* now you can also store the first variable */
      if(!storefirst(pp))
        return(FALSE);
      /* null_tmp_store(pp, FALSE); */
    }
  
    return(store(pp, var, row, value));
  } /* var_store */
  
  
  
  /*
   * store the information in tmp_store because it is a bound
   */
  int store_bounds(parse_parm *pp, int warn)
  {
    if(pp->tmp_store.value != 0) {
      hashelem *h_tab_p;
      REAL boundvalue;
  
      if((h_tab_p = findhash(pp->tmp_store.name, pp->Hash_tab)) == NULL) {
        /* a new columnname is found, create an entry in the hashlist */
        if ((h_tab_p = puthash(pp->tmp_store.name, pp->Columns, NULL, pp->Hash_tab)) == NULL) {
          error(pp, CRITICAL, "Not enough memory");
          return(FALSE);
        }
        inccoldata(pp);
        pp->Columns++; /* counter for calloc of final array */
      }
  
      if(pp->tmp_store.value < 0) { /* divide by negative number, */
        /* relational operator may change */
        if(pp->tmp_store.relat == GE)
          pp->tmp_store.relat = LE;
        else if(pp->tmp_store.relat == LE)
          pp->tmp_store.relat = GE;
      }
  
      boundvalue = pp->tmp_store.rhs_value / pp->tmp_store.value;
  
  #if FALSE
      /* Check sanity of bound; all variables should be positive */
      if(   ((pp->tmp_store.relat == EQ) && (boundvalue < 0))
         || ((pp->tmp_store.relat == LE) && (boundvalue < 0))) { /* Error */
        error(pp, CRITICAL, "Error: variables must always be non-negative");
        return(FALSE);
      }
  #endif
  
  #if FALSE
      if((pp->tmp_store.relat == GE) && (boundvalue <= 0)) /* Warning */
        error(pp, NORMAL, "Warning: useless bound; variables are always >= 0");
  #endif
  
      /* bound seems to be sane, add it */
      if((pp->tmp_store.relat == GE) || (pp->tmp_store.relat == EQ)) {
        if(boundvalue > pp->coldata[h_tab_p->index].lowbo - tol)
          pp->coldata[h_tab_p->index].lowbo = boundvalue;
        else if(warn)
          error(pp, NORMAL, "Ineffective lower bound, ignored");
      }
      if((pp->tmp_store.relat == LE) || (pp->tmp_store.relat == EQ)) {
        if(boundvalue < pp->coldata[h_tab_p->index].upbo + tol)
          pp->coldata[h_tab_p->index].upbo  = boundvalue;
        else if (warn)
          error(pp, NORMAL, "Ineffective upper bound, ignored");
      }
  
      /* check for empty range */
      /*
      if((warn) && (pp->coldata[h_tab_p->index].upbo + tol < pp->coldata[h_tab_p->index].lowbo)) {
        error(pp, CRITICAL, "Error: bound contradicts earlier bounds");
        return(FALSE);
      }
      */
    }
    else /* pp->tmp_store.value = 0 ! */ {
      char buf[256];
  
      if((pp->tmp_store.rhs_value == 0) ||
         ((pp->tmp_store.rhs_value > 0) && (pp->tmp_store.relat == LE)) ||
         ((pp->tmp_store.rhs_value < 0) && (pp->tmp_store.relat == GE))) {
        sprintf(buf, "Variable %s has an effective coefficient of 0 in bound, ignored",
                pp->tmp_store.name);
        if(warn)
          error(pp, NORMAL, buf);
      }
      else {
        sprintf(buf, "Error, variable %s has an effective coefficient of 0 in bound",
                pp->tmp_store.name);
        error(pp, CRITICAL, buf);
        return(FALSE);
      }
    }
  
    /* null_tmp_store(pp, FALSE); */
    pp->tmp_store.rhs_value = 0;
  
    return(TRUE);
  } /* store_bounds */
  
  int set_title(parse_parm *pp, char *name)
  {
    pp->title = strdup(name);
    return(TRUE);
  }
  
  int add_constraint_name(parse_parm *pp, char *name)
  {
    int row;
    hashelem *hp;
  
    if((hp = findhash(name, pp->Hash_constraints)) != NULL) {
      row = hp->index;
      pp->rs = pp->First_rside;
      while ((pp->rs != NULL) && (pp->rs->row != row))
        pp->rs = pp->rs->next;
    }
    else {
      row = pp->Rows;
      if (((hp = puthash(name, row, NULL, pp->Hash_constraints)) == NULL)
         ) return(FALSE);
      if(row)
        pp->rs = NULL;
    }
  
    return(TRUE);
  }
  
  /*
   * transport the data from the intermediate structure to the sparse matrix
   * and free the intermediate structure
   */
  static int readinput(parse_parm *pp, lprec *lp)
  {
    int    i, i1, count, index, col;
    struct column *cp, *tcp;
    hashelem *hp;
    struct rside *rp;
    signed char *negateAndSOS = NULL;
    REAL *row = NULL, a;
    int *rowno = NULL;
    MYBOOL SOSinMatrix = FALSE;
    struct SOSrowdata *SOSrowdata = NULL;
    struct SOSrow *SOSrow, *SOSrow1;
  
    if(lp != NULL) {
      if (CALLOC(negateAndSOS, 1 + pp->Rows, signed char) == NULL)
        return(FALSE);
  
      rp = pp->First_rside;
      for(i = pp->Rows; (i >= 0) && (rp != NULL); i--) {
        if(rp->SOStype == 0)
          negateAndSOS[i] = (rp->negate ? -1 : 0);
        else
          negateAndSOS[i] = (signed char) rp->SOStype;
  
        rp = rp->next;
      }
  
      /* fill names with the rownames */
      hp = pp->Hash_constraints->first;
      while(hp != NULL) {
        if (/* (negateAndSOS[hp->index] <= 0) && */ (!set_row_name(lp, hp->index, hp->name)))
          return(FALSE);
        hp = hp->nextelem;
      }
    }
  
    for(i = pp->Rows; i >= 0; i--) {
      rp = pp->First_rside;
      if((lp != NULL) && (rp != NULL)) {
        if(rp->SOStype == 0) {
          if (rp->negate) {
            switch (rp->relat) {
            case LE:
              rp->relat = GE;
              break;
            case GE:
              rp->relat = LE;
              break;
            }
            switch (rp->range_relat) {
            case LE:
              rp->range_relat = GE;
              break;
            case GE:
              rp->range_relat = LE;
              break;
            }
            rp->range_value = -rp->range_value;
            rp->value = -rp->value;
          }
  
          if((rp->range_relat >= 0) && (rp->value == lp->infinite)) {
            rp->value = rp->range_value;
            rp->relat = rp->range_relat;
            rp->range_relat = -1;
          }
          else if((rp->range_relat >= 0) && (rp->value == -lp->infinite)) {
            rp->value = rp->range_value;
            rp->relat = rp->range_relat;
            rp->range_relat = -1;
          }
          if ((rp->range_relat >= 0) && (rp->range_value == rp->value)) {
            rp->relat = EQ;
            rp->range_relat = EQ;
          }
          if(i) {
            set_constr_type(lp, i, rp->relat);
            pp->relat[i] = rp->relat;
          }
          set_rh(lp, i, rp->value);
          if (rp->range_relat >= 0)
            set_rh_range(lp, i, rp->range_value - rp->value);
        }
        else {
          SOSinMatrix = TRUE;
          if(i)
            pp->relat[i] = rp->relat;
        }
      }
      if(rp != NULL) {
        pp->First_rside = rp->next;
        free(rp); /* free memory when data has been read */
      }
      else
        pp->First_rside = NULL;
    }
  
    while(pp->First_rside != NULL) {
      rp = pp->First_rside;
      pp->First_rside = rp->next;
      free(rp); /* free memory when data has been read */
    }
  
    /* start reading the Hash_list structure */
    index = 0;
  
    if((SOSinMatrix) && (CALLOC(SOSrowdata, 1 + pp->Rows, struct SOSrowdata) == NULL)) {
      FREE(negateAndSOS);
      FREE(row);
      FREE(rowno);
      return(FALSE);
    }
  
    if((lp != NULL) &&
       ((MALLOC(row, 1 + pp->Rows, REAL) == NULL) || (MALLOC(rowno, 1 + pp->Rows, int) == NULL))) {
      FREE(SOSrowdata);
      FREE(negateAndSOS);
      FREE(row);
      FREE(rowno);
      return(FALSE);
    }
  
    /* for(i = 0; i < pp->Hash_tab->size; i++) {
      hp = pp->Hash_tab->table[i]; */
      hp = pp->Hash_tab->first;
      while(hp != NULL) {
        count = 0;
        index++;
        cp = pp->coldata[hp->index].firstcol;
        col = hp->index + 1;
        while(cp != NULL) {
          if(lp != NULL) {
            if (negateAndSOS[cp->row] <= 0) {
              rowno[count] = cp->row;
                a = cp->value;
                if (negateAndSOS[cp->row])
                  a = -a;
              row[count++] = a;
            }
            else {
              if (MALLOC(SOSrow, 1, struct SOSrow) == NULL) {
                FREE(SOSrowdata);
                FREE(negateAndSOS);
                FREE(row);
                FREE(rowno);
                return(FALSE);
              }
              if(SOSrowdata[cp->row].SOSrow == NULL)
                SOSrowdata[cp->row].name = strdup(get_row_name(lp, cp->row));
              SOSrow->next = SOSrowdata[cp->row].SOSrow;
              SOSrowdata[cp->row].SOSrow = SOSrow;
              SOSrowdata[cp->row].type = negateAndSOS[cp->row];
              SOSrow->col = col;
              SOSrow->value = cp->value;
            }
          }
          tcp = cp;
          /* cp = cp->next; */
          cp = cp->prev;
          free(tcp); /* free memory when data has been read */
        }
  
        if(lp != NULL) {
          if((!pp->coldata[hp->index].must_be_sec) && (pp->coldata[hp->index].upbo + tol < pp->coldata[hp->index].lowbo)) {
            char buf[256];
  
            FREE(SOSrowdata);
            FREE(negateAndSOS);
            FREE(row);
            FREE(rowno);
            sprintf(buf, "Error: variable %s: bound contradicts earlier bounds\n", hp->name);
            error(NULL, CRITICAL, buf);
            return(FALSE);
          }
  
          add_columnex(lp, count, row, rowno);
          /* check for bound */
          if(pp->coldata[hp->index].lowbo == -DEF_INFINITE * 10.0)
            /* lp->orig_lowbo[pp->Rows+index] = 0.0; */
            set_lowbo(lp, index, 0);
          else
            /* lp->orig_lowbo[pp->Rows+index] = pp->coldata[hp->index].lowbo; */
            set_lowbo(lp, index, pp->coldata[hp->index].lowbo);
          /* lp->orig_upbo[pp->Rows+index] = pp->coldata[hp->index].upbo; */
          if(pp->coldata[hp->index].upbo >= DEF_INFINITE)
            set_upbo(lp, index, DEF_INFINITE);
          else
            set_upbo(lp, index, pp->coldata[hp->index].upbo);
  
          /* check if it must be an integer variable */
          if(pp->coldata[hp->index].must_be_int) {
            /* lp->must_be_int[pp->Rows + index]=TRUE; */
            set_int(lp, index, TRUE);
          }
          if(pp->coldata[hp->index].must_be_sec) {
            set_semicont(lp, index, TRUE);
          }
          if(pp->coldata[hp->index].must_be_free) {
            set_unbounded(lp, index);
          }
  
          /* copy name of column variable */
          if (!set_col_name(lp, index, hp->name)) {
            FREE(SOSrowdata);
            FREE(negateAndSOS);
            FREE(row);
            FREE(rowno);
            return(FALSE);
          }
  
          /* put matrix values in intermediate row */
          /* cp = hp->col; */
          /* cp = hp->firstcol; */
        }
  
        /* thp = hp; */
        /* hp = hp->next; */
        /* free(thp->name); */
        /* free(thp); */ /* free memory when data has been read */
  
        hp = hp->nextelem;
  
      }
      /* pp->Hash_tab->table[i] = NULL; */
  
    FREE(pp->coldata);
  
    if(SOSrowdata != NULL) {
      struct structSOS *structSOS;
      struct structSOSvars *SOSvars, *SOSvars1;
      int SOSweight = 0;
  
      for(i = 1; i <= pp->Rows; i++) {
        SOSrow = SOSrowdata[i].SOSrow;
        if(SOSrow != NULL) {
          if(MALLOC(structSOS, 1, struct structSOS) == NULL) {
            FREE(SOSrowdata);
            FREE(negateAndSOS);
            FREE(row);
            FREE(rowno);
            return(FALSE);
          }
          structSOS->Nvars = 0;
          structSOS->type = SOSrowdata[i].type;
          structSOS->weight = ++SOSweight;
          structSOS->name = strdup(SOSrowdata[i].name);
          structSOS->LastSOSvars = NULL;
          structSOS->next = pp->FirstSOS;
          pp->FirstSOS = structSOS;
          SOSvars = NULL;
          while(SOSrow != NULL) {
            SOSvars1 = SOSvars;
            MALLOC(SOSvars, 1, struct structSOSvars);
            SOSvars->next = SOSvars1;
            SOSvars->col = SOSrow->col;
            SOSvars->weight = SOSrow->value;
            SOSvars->name = NULL;
            structSOS->Nvars++;
            SOSrow1 = SOSrow->next;
            FREE(SOSrow);
            SOSrow = SOSrow1;
          }
          structSOS->SOSvars = SOSvars;
        }
      }
      FREE(SOSrowdata);
    }
  
    while(pp->FirstSOS != NULL)
    {
      struct structSOSvars *SOSvars, *SOSvars1;
      int *sosvars, n, col;
      REAL *weights;
      hashelem *hp;
  
      pp->LastSOS = pp->FirstSOS;
      pp->FirstSOS = pp->FirstSOS->next;
      SOSvars = pp->LastSOS->SOSvars;
      if(lp != NULL) {
        MALLOC(sosvars, pp->LastSOS->Nvars, int);
        MALLOC(weights, pp->LastSOS->Nvars, double);
      }
      else {
        sosvars = NULL;
        weights = NULL;
      }
      n = 0;
      while(SOSvars != NULL)
      {
        SOSvars1 = SOSvars;
        SOSvars = SOSvars->next;
        if(lp != NULL) {
          col = SOSvars1->col;
          if(col == 0)
            if((hp = findhash(SOSvars1->name, lp->colname_hashtab)) != NULL)
              col = hp->index;
          if (col) {
            sosvars[n] = col;
            weights[n++] = SOSvars1->weight;
          }
        }
        FREE(SOSvars1->name);
        FREE(SOSvars1);
      }
      if(lp != NULL) {
        add_SOS(lp, pp->LastSOS->name, pp->LastSOS->type, pp->LastSOS->weight, n, sosvars, weights);
        FREE(weights);
        FREE(sosvars);
      }
      FREE(pp->LastSOS->name);
      FREE(pp->LastSOS);
    }
  
    if(negateAndSOS != NULL) {
      for(i1 = 0, i = 1; i <= pp->Rows; i++)
        if(negateAndSOS[i] <= 0)
          pp->relat[++i1] = pp->relat[i];
  
  #if 01
      for(i = pp->Rows; i > 0; i--)
        if(negateAndSOS[i] > 0) {
          del_constraint(lp, i);
          pp->Rows--;
        }
  #endif
    }
  
    /* the following should be replaced by a call to the MPS print routine MB */
  
  #if 0
    if(pp->Verbose) {
      int j;
  
      printf("\n");
      printf("**********Data read**********\n");
      printf("Rows    : %d\n", pp->Rows);
      printf("Columns : %d\n", pp->Columns);
      printf("Nonnuls : %d\n", pp->Non_zeros);
      printf("NAME          LPPROB\n");
      printf("ROWS\n");
      for(i = 0; i <= pp->Rows; i++) {
        if(pp->relat[i] == LE)
          printf(" L  ");
        else if(pp->relat[i] == EQ)
          printf(" E  ");
        else if(pp->relat[i] == GE)
          printf(" G  ");
        else if(pp->relat[i] == OF)
          printf(" N  ");
        printf("%s\n", get_row_name(lp, i));
      }
  
      printf("COLUMNS\n");
      j = 0;
      for(i = 0; i < pp->Non_zeros; i++) {
        if(i == lp->col_end[j])
          j++;
        printf("    %-8s  %-8s  %g\n", get_col_name(lp, j),
               get_row_name(lp, lp->mat[i].row_nr), (double)lp->mat[i].value);
      }
  
      printf("RHS\n");
      for(i = 0; i <= pp->Rows; i++) {
        printf("    RHS       %-8s  %g\n", get_row_name(lp, i),
               (double)lp->orig_rhs[i]);
      }
  
      printf("RANGES\n");
      for(i = 1; i <= pp->Rows; i++)
        if((lp->orig_upbo[i] != lp->infinite) && (lp->orig_upbo[i] != 0)) {
          printf("    RGS       %-8s  %g\n", get_row_name(lp, i),
                 (double)lp->orig_upbo[i]);
        }
        else if((lp->orig_lowbo[i] != 0)) {
          printf("    RGS       %-8s  %g\n", get_row_name(lp, i),
                 (double)-lp->orig_lowbo[i]);
        }
  
      printf("BOUNDS\n");
      for(i = pp->Rows + 1; i <= pp->Rows + pp->Columns; i++) {
        if((lp->orig_lowbo[i] != 0) && (lp->orig_upbo[i] < lp->infinite) &&
           (lp->orig_lowbo[i] == lp->orig_upbo[i])) {
          printf(" FX BND       %-8s  %g\n", get_col_name(lp, i - pp->Rows),
                 (double)lp->orig_upbo[i]);
        }
        else {
          if(lp->orig_upbo[i] < lp->infinite)
              printf(" UP BND       %-8s  %g\n", get_col_name(lp, i - pp->Rows),
                     (double)lp->orig_upbo[i]);
          if(lp->orig_lowbo[i] > 0)
              printf(" LO BND       %-8s  %g\n", get_col_name(lp, i - pp->Rows),
                     (double)lp->orig_lowbo[i]);
        }
      }
  
      printf("ENDATA\n");
    }
  #endif
  
    FREE(row);
    FREE(rowno);
    FREE(negateAndSOS);
    return(TRUE);
  } /* readinput */
  
  lprec *yacc_read(lprec *lp, int verbose, char *lp_name, int (*parse) (parse_parm *pp), parse_parm *pp, void (*delete_allocated_memory) (parse_parm *pp))
  {
    REAL *orig_upbo;
    int stat = -1;
    lprec *lp0 = lp;
  
    pp->title = lp_name;
  
    if(!init_read(pp, verbose))
      error(pp, CRITICAL, "init_read failed");
    else if (setjmp(pp->jump_buf) == 0)
      stat = parse(pp);
  
    delete_allocated_memory(pp);
  
    pp->Rows--;
  
    pp->relat = NULL;
    if((stat != 0) || (CALLOC(pp->relat, pp->Rows + 1, short) != NULL)) {
      if(stat == 0) {
        if(lp == NULL) {
          lp = make_lp(pp->Rows, 0);
        }
        else {
          int NRows;
  
          for(NRows = get_Nrows(lp); NRows < pp->Rows; NRows++)
            add_constraintex(lp, 0, NULL, NULL, LE, 0);
        }
      }
      else
        lp = NULL;
      if ((stat != 0) || (lp != NULL)) {
        if(lp != NULL) {
          set_verbose(lp, pp->Verbose);
        }
  
        if (!readinput(pp, lp)) {
          if((lp != NULL) && (lp0 == NULL))
            delete_lp(lp);
          lp = NULL;
        }
  
        if(lp != NULL) {
          set_lp_name(lp, pp->title);
          if(pp->Maximise)
            set_maxim(lp);
  
          if(pp->Rows) {
            int row;
  
            MALLOCCPY(orig_upbo, lp->orig_upbo, 1 + pp->Rows, REAL);
            for(row = 1; row <= pp->Rows; row++)
              set_constr_type(lp, row, pp->relat[row]);
  
            memcpy(lp->orig_upbo, orig_upbo, (1 + pp->Rows) * sizeof(*orig_upbo)); /* restore upper bounds (range) */
            FREE(orig_upbo);
          }
        }
        if((pp->title != NULL) && (pp->title != lp_name))
          free(pp->title);
  
        free_hash_table(pp->Hash_tab);
        free_hash_table(pp->Hash_constraints);
      }
      FREE(pp->relat);
    }
    null_tmp_store(pp, FALSE);
    return(lp);
  }
  