/* data_parser.cc */

#include "parser.h"
#include <stdio.h>
#include <LEDA/queue.h>
#include "data_classes.h"
#include "shape.h"
#include <ctype.h>
#include "root.h"
#include <math.h>

dc_data *parse_data( token_queue &Q, dc_label *owner, 
		     dc_label *search_origin = nil/*, dc_type rtype = Data_t*/ )
{
  /* get type tag */
  token *t = Q.peek();
  if( ( t == nil ) ) {
    return nil;
  }

  if( !t->is_tag() ) { /* if no type tag assume real */
    string s = ( ( string_token * )t )->get();
    if( dequote( s ) ) {
      Q.pop();
      return new dc_string( s );
    }

    double d;
    if( !parse_real( Q, d ) ) {
      dc_real *Real = new dc_real( d );
      if( parse_uv( Q, ( dc_udata * )Real ) == uv_fail ) {
	delete( Real ); return nil; 
      }
      return Real;
    }

    dc_symbol_tag s_tag;
    dc_svec_tag e_tag;
    if( parse_symbol( Q, s_tag, e_tag ) ) return nil;
    return new dc_symbol( s_tag, e_tag );
  }

  bool b;
  if( *t == False_Tag || *t == True_Tag && !parse_bool( Q, b ) ) {
    return new dc_boolean( b );
  }

  long int i;
  ColumnVector V;
  Matrix M;
  double r;
  dc_data *Data;
  dc_real *Real; dc_int *Int; dc_triple *Triple; dc_vector *Vector; 
  dc_matrix *Matrix; dc_distrib *Distrib; dc_shape *shape;
  string str;
  dc_symbol_tag s_tag;
  dc_svec_tag e_tag;
  triple scale;

  switch( ( ( tag_token * )t )->get() ) {
  case Boolean_Tag :
    Q.pop();
    if( parse_bool( Q, b ) ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "parse_data -- could not parse boolean near " << t->pos_string()
	     << "\n";
      }
      return nil;
    }
    return new dc_boolean( b );
    break;
  case Distrib_Tag :
    Distrib = parse_distribution( Q );
    if( !Distrib ) return nil;
    if( parse_uv( Q, ( dc_udata * )Distrib ) == uv_fail ) {
      delete( Distrib );
      return nil;
    }
    return Distrib;
    break;
  case Int_Tag :
    Q.pop();
    if( parse_int( Q, i ) ) return nil;
    Int = new dc_int( i );
    if( parse_uv( Q, ( dc_udata * )Int ) == uv_fail ) {
      delete( Int );
      return nil;
    }
    return Int;
    break;
  case Matrix_Tag :
    Q.pop();
    if( parse_matrix( Q, M ) ) return nil;
    Matrix = new dc_rect_matrix( M );
    if( parse_uv( Q, ( dc_udata * )Matrix ) == uv_fail ) {
      delete( Matrix );
      return nil;
    }
    return Matrix;
    break;
  case Ampersand_Tag :
    Data = parse_pointer( Q, search_origin );
    return Data;
    break;
  case Real_Tag :
    Q.pop();
    if( parse_real( Q, r ) ) return nil;
    Real = new dc_real( r );
    if( parse_uv( Q, ( dc_udata * )Real ) == uv_fail ) {
      delete( Real );
      return nil;
    }
    return Real;
    break;
  case Set_Tag :
    Q.pop();
    if( expect_tag( Q, L_Paren_Tag, "parse_data" ) ) return nil;
    if( ( Data = parse_set( Q, owner, search_origin ) ) == nil ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_data -- error parsing set near " 
	     << Q.pos_string() << "\n";
      }
      delete( Data );
      return nil;
    }
    if( expect_tag( Q, R_Paren_Tag, "parse_data" ) ) {
      delete( Data );
      return nil;
    }
    return Data;
  case Shape_Tag :
    Q.pop();
    t = Q.peek();
    if( !t || t->is_tag() ) {
      return nil;
    }
    str = ( ( string_token * )t )->get();
    dequote( str );
    Q.pop();
    scale = triple( 1, 1, 1 );
    if( !check_tag( Q, Product_Tag ) ) {
      if( parse_triple( Q, scale ) ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "parse_data -- error reading scale for shape using file \"" 
	       << str << "\" near " << Q.pos_string() << "\n";
	}
      }
    }
    shape = new dc_shape( str, scale );
    if( !shape->is_valid() ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "parse_data -- invalid shape file \"" << str << "\" near "
	     << Q.pos_string() << "\n";
      }
      delete( shape );
      return nil;
    }
    return shape;
  case String_Tag :
    Q.pop();
    if( parse_string( Q, str ) ) return nil;
    return new dc_string( str );
    break;
  case Symbol_Tag :
    if( parse_symbol( Q, s_tag, e_tag ) ) return nil;
    return new dc_symbol( s_tag, e_tag );
    break;
  case Triple_Tag :
    Q.pop();
    if( parse_triple( Q, V ) ) return nil;
    Triple =  new dc_triple( V );
    if( parse_uv( Q, ( dc_udata * )Triple ) == uv_fail ) {
      delete( Triple );
      return nil;
    }
    return Triple;
    break;
  case Vector_Tag :
    Q.pop();
    if( parse_vector( Q, V ) ) return nil;
    if( V.Nrows() == 3 ) {
      Triple = new dc_triple( V );
      if( parse_uv( Q, ( dc_udata * )Triple ) == uv_fail ) {
	delete( Triple );
	return nil;
      }
      return Triple;
    } else {
      Vector = new dc_vector( V );
      if( parse_uv( Q, ( dc_udata * )Vector ) == uv_fail ) {
	delete( Vector );
	return nil;
      }
      return Vector;
    }
    break;
  default :
    dc_trace( TRACE_ERROR ) {
      cerr << "parse_data -- invalid data type tag near " << t->pos_string() 
	   << "\n";
    }
    return nil;
  }
  return nil;
}

uv_result parse_uv( token_queue &Q, dc_udata *D,
		    const bool need_brackets = true ) {
  bool bracketed;
  if( need_brackets ) {
    bracketed = !check_tag( Q, L_SqBracket_Tag );
  } else {
    bracketed = true;
  }

  token *t = Q.peek();

  if( !t || t->is_tag() ) {
    if_trc( bracketed, TRACE_ERROR ) {
      cerr << "parse_uv -- expected unit label at " << Q.pos_string() << "\n";
    }
    return bracketed ? uv_fail : uv_none;
  }

  unit_vec *uv = &D->get_units();
  for( int i = 0 ; i < num_basic_units ; ( *uv )[i++] = 0 );

  double *d_arr;
  double d;
  int size;
  switch( D->type() ) {    
  case Int_t :
    size = 1; d_arr = &d;
    d = ( ( dc_int * )D )->get();
    break;
  case Real_t : 
    size = 1; d_arr = &d;
    d = ( ( dc_real * )D )->get();
    break;
  case Matrix_t :
    size = ( ( dc_matrix * )D )->get_storage();
    d_arr = ( ( dc_matrix * )D )->get_store();
    break;
  default : return uv_fail;
  }

  int pow_mod = 1;
  double coeff = 1;
  string uname = ( ( string_token * )t )->get();
  if( !ub.parse_and_convert( uname, d_arr, size, *uv, coeff, pow_mod ) ) {
    Q.pop();

    if( bracketed ) {
      while( 1 ) {
	t = Q.peek();
	if( !t ) break;
	token *last;
	if( *t == Product_Tag || *t == Inv_Prod_Tag ) {
	  if( *t == Inv_Prod_Tag )
	    pow_mod = -1;
	  else pow_mod = 1;
	  last = Q.extract();
	  t = Q.peek();
	  if( t && !t->is_tag() ) {
	    if( ub.parse_and_convert( ( ( string_token * )t )->get(), 
				      d_arr, size, *uv, coeff, pow_mod ) ) {
	      Q.push( last ); break;
	    } else { 
	      Q.push_used( last ); 
	      Q.pop(); 
	    }
	  } else {
	    Q.push( last );
	    break;
	  }
	} else break;
      }

      if( need_brackets ) {
	if( expect_tag( Q, R_SqBracket_Tag, "parse_uv" ) ) return uv_fail;
      } else return uv_pass;
    }
    switch( D->type() ) {
    case Int_t :
      ( ( dc_int * )D )->set( ( long int )rint( d * coeff ) );
      break;
    case Real_t :
      ( ( dc_real * )D )->set( d * coeff );
      break;
    case Matrix_t :
      for( int i = 0 ; i < size ; i++ ) {
	d_arr[i] *= coeff;
      }
      break;
    default :;
    }
    return uv_pass;
  }
  if_trc( bracketed, TRACE_ERROR ) {
    cerr << "parse_uv -- error parsing units at " << Q.pos_string() << "\n";
  }
  
  return bracketed ? uv_fail : uv_none;
}

bool parse_bool( token_queue &Q, bool &b ) {
  token *t = Q.peek();
  if( *t == True_Tag ) {
    b = true;
    Q.pop();
    return false;
  } else if( *t == False_Tag ) {
    b = false;
    Q.pop();
    return false;
  }
  return true;
}

bool parse_int( token_queue &Q, long int &i) {
  token *t = Q.peek();
  if( !t || t->is_tag() ) return true;
  if( sscanf( ( ( string_token * )t )->get(), "%ld", &i ) ) {
    Q.pop();
    return false;
  } else {
    return true;
  }
}

bool parse_real( token_queue &Q, double &d ) {
  token *t = Q.peek();
  if( !t || t->is_tag() ) return true;
  if( sscanf( ( ( string_token * )t )->get(), "%lf", &d ) ) {
    Q.pop();
    return false;
  } else {
    return true;
  }
}

int parse_vrow( token_queue &Q, double *&d_arr, int size ) {
  string pos = Q.pos_string();
  token *t = Q.peek();
  
  if( !t || *t != L_Bracket_Tag ) return -1;
  d_arr = new double[ size ];
  Q.pop();
  
  if( parse_real( Q, d_arr[0] ) ) {
    delete( d_arr );
    return -1;
  }
  int loc = 1;
  while( loc < size ) {
    t = Q.peek();
    if( !t ) {
      delete( d_arr );
      return -1;
    }
    if( *t != Comma_Tag ) break;
    Q.pop();
    if( parse_real( Q, d_arr[loc++] ) ) {
      delete( d_arr );
      return -1;
    }
  }
  
  if( loc < size ) {
    dc_trace( TRACE_WARNING ) {
      cerr << "parse_vrow -- vector starting at " << pos << " only has " 
	   << loc << " out of " << size << " values.  zeroing rest\n";
    }
    for( int n = loc ; n < size ; d_arr[ n++ ] = 0 );
  }
  t = Q.pop();
  if( !t || *t != R_Bracket_Tag ) { 
    delete( d_arr );
    return -1;
  }

  return loc;
}

int parse_vrow( token_queue &Q, queue<double> &dbl_q ) {
  string pos = Q.pos_string();
  token *t = Q.peek();

  /* check open bracket */
  if( !t || *t != L_Bracket_Tag ) { 
    return -1;
  }
  Q.pop();
  
  /* get first element */
  double d;
  if( parse_real( Q, d ) ) return -1;
  dbl_q.append( d );
  int n = 1;

  while( 1 ) {
    /* check comma */
    t = Q.pop();
    if( !t ) {
      dbl_q.clear();
      cerr << "parse_vrow -- parse failed on vrow starting near " << pos
	   << " since input ended\n";
      return -1;
    }
    if( *t != Comma_Tag ) break;
    
    /* get element */
    if( parse_real( Q, d ) ) { dbl_q.clear(); return -1; }
    dbl_q.append( d );
    n++;
  }

  /* check closing bracket */
  if( *t != R_Bracket_Tag ) { 
    dbl_q.clear();
    dc_trace( TRACE_ERROR ) {
      cerr << "parse_vrow -- parse failed on vrow starting near " << pos 
	   << ". '}' expected\n";
    }
    return -1;
  }
  
  return n;
}

bool parse_vector( token_queue &Q, ColumnVector &V ) {
  string pos = Q.pos_string();

  token *t;
  double *d_arr;
  long int size;
  t = Q.peek();
  if( !t ) return true;
  if( *t == L_Paren_Tag ) {
    Q.pop();
    /* get length */
    if( parse_int( Q, size ) || size <= 0 ) {
      dc_trace( TRACE_WARNING ) {
	cerr << "parse_vector -- could not parse vector starting at " << pos
	     << " because of invlaid length specification\n";
      }
      return true;
    }
    t = Q.pop();
    if( !t || *t != R_Paren_Tag ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "parse_vector -- '}' expected near " << t->pos_string() << "\n";
      }
      return true;
    }
    if( parse_vrow( Q, d_arr, size ) < 0 ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "parse_vector -- could not parse vector starting at " << pos
	     << " because of invlaid element list\n";
      }
      return true;
    }
  } else {
    queue<double> dbl_q;
    if( ( size = parse_vrow( Q, dbl_q ) ) < 0 ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "parse_vector -- could not parse vector starting at " << pos
	     << " because of invlaid element list\n";
      }
      return true;
    }
    d_arr = new double[ dbl_q.size() ];
    for( size = 0 ; !dbl_q.empty() ; size++ ) {
      d_arr[size] = dbl_q.pop();
    }
  }
  
  /* set vector */
  V.ReDimension( size );
  V << d_arr;
  return false;
}

bool parse_matrix( token_queue &Q, Matrix &M ) {
  string pos = Q.pos_string();

  token *t = Q.peek();
  if( !t ) return true;

  double *d_arr;
  long int m, n;
  
  if( *t == L_Paren_Tag ) {
    n = m = -1;
    Q.pop();
    /* get n */
    if( parse_int( Q, n ) || n <= 0 ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "parse_matrix -- could not parse matrix starting at " << pos
	     << " because of missing dimension.\n";
      }
      return true;
    }
    t = Q.pop();
    if( !t ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "parse_matrix -- could not parse matrix starting at " << pos
	     << " because of interrupted size specification.\n";
      }
      return true;
    }
    /* if , get m */
    if( *t == Comma_Tag ) {
      if( parse_int( Q, m ) || m <= 0 ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "parse_matrix -- could not parse matrix starting at " << pos
	       << " because of missing width.\n";
	}
	return true;
      }
      t = Q.pop();
    }
    /* check ) */
    if( !t || *t != R_Paren_Tag ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "parse_matrix -- could not parse matrix starting at " << pos
	     << " because expected ')' after size specification.\n";
      }
      return true;
    }
    /*     get values */
    if( m == -1 ) {
      queue<double> dbl_q;
      int l;
      if( ( l = parse_vrow( Q, dbl_q ) ) < 0 ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "parse_matrix -- could not parse matrix starting at " << pos
	       << " because of invlaid element list\n";
	}
	return true;
      }
      m = n; /* if one arg given then arg is width */
      n = ( l + m - 1 ) / m;
      int area = m * n;
      d_arr = new double[ area ];
      int i = 0;
      for( ; !dbl_q.empty() ; i++ ) {
	d_arr[i] = dbl_q.pop();
      }
      if( i < area ) {
	dc_trace( TRACE_WARNING ) {
	  cerr << "parse_matrix -- only " << l << " elements given for ( " << n 
	       << " x " << m << " ) matrix starting at " << pos
	       << ". remaining elements zeroed.\n";
	}
	for( ; i < area ; i++ ) {
	  d_arr[i] = 0;
	}
      }
    } else {
      if( parse_vrow( Q, d_arr, m * n ) < 0 ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "parse_matrix -- could not parse matrix starting at " << pos
	       << " because of invlaid element list\n";
	}
	return true;
      }
    }
  } else if( *t == L_Bracket_Tag ) {
    m = 0;
    Q.pop();
    queue< queue<double> *> dbl_q_list;
    do {
      queue<double> *dbl_q = new queue<double>;
      int this_w;
      if( ( this_w = parse_vrow( Q, *dbl_q ) ) < 0 || !( t = Q.pop() ) ) {
	delete( dbl_q );
	while( !dbl_q_list.empty() ) {
	  delete( dbl_q_list.pop() );
	}
	dc_trace( TRACE_ERROR ) {
	  cerr << "parse_matrix -- could not parse matrix starting at " << pos
	       << " because of invlaid element list. error near " 
	       << Q.pos_string() << "\n";
	}
	return true;
      }
      dbl_q_list.append( dbl_q );
      if( m < this_w ) m = this_w;

      /* check ',' */
      if( *t != Comma_Tag ) break;
    } while( 1 );
    
    if( *t != R_Bracket_Tag ) {
      while( !dbl_q_list.empty() ) {
	delete( dbl_q_list.pop() );
      }
      dc_trace( TRACE_ERROR ) {
	cerr << "parse_matrix -- missing '}' near " << t->pos_string() << "\n";
      }
      return true;
    }

    n = dbl_q_list.size();
    int area = m * n;
    d_arr = new double[ area ];
    int k = 0;
    for( int j = 0 ; !dbl_q_list.empty() ; j++ ) {
      queue<double> *dbl_q = dbl_q_list.pop();
      int i = 0;
      for( ; !dbl_q->empty() ; i++, k++ ) {
	d_arr[k] = dbl_q->pop();
      } 
      delete( dbl_q );
      for( ; i < m ; i++, k++ ) {
	d_arr[k] = 0;
      }
    }
  } else return true;

  M.ReDimension( n, m );
  M << d_arr;

  return false;
}

bool parse_triple( token_queue &Q, ColumnVector &V ) {
  double *d_arr = new double[3];
  bool paren_type = false; /* triple can be enclosed in either curly brackets or
			      parentheses.  true means opened with curly 
			      brackets */

  if( check_tag( Q, L_Paren_Tag ) ) {
    if( check_tag( Q, L_Bracket_Tag ) ) {
      return true;
    }
    paren_type = true;
  }
  
  if( parse_real( Q, d_arr[0] ) ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "parse_triple -- failed to parse first arg of triple near "
	   << Q.pos_string() << "\n";
    }
    delete( d_arr );
    return true;
  }

  if( expect_tag( Q, Comma_Tag, "parse_triple" ) ) {
    delete( d_arr );
    return true;
  }
  
  if( parse_real( Q, d_arr[1] ) ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "parse_triple -- failed to parse second arg of triple near "
	   << Q.pos_string() << "\n";
    }
    delete( d_arr );
    return true;
  }

  if( check_tag( Q, Comma_Tag ) ) {
    d_arr[2] = 0;
  } else {
    if( parse_real( Q, d_arr[2] ) ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "parse_triple -- failed to parse third arg of triple near "
	     << Q.pos_string() << "\n";
      }
      delete( d_arr );
      return true;
    }
  }

  if( paren_type ) {
    if( expect_tag( Q, R_Bracket_Tag, "parse_triple" ) ) {
      delete( d_arr );
      return true;
    }
  } else if( expect_tag( Q, R_Paren_Tag, "parse_triple" ) ) {
    delete( d_arr );
    return true;
  }
  
  V.ReDimension( 3 );
  V << d_arr;
  
  return false;
}

bool parse_triple( token_queue &Q, triple &t ) {
  bool paren_type = false; /* triple can be enclosed in either curly brackets or
			      parentheses.  true means opened with curly 
			      brackets */

  double x, y, z;
  if( check_tag( Q, L_Paren_Tag ) ) {
    if( check_tag( Q, L_Bracket_Tag ) ) {
      return true;
    }
    paren_type = true;
  }
  
  if( parse_real( Q, x ) ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "parse_triple -- failed to parse first arg of triple near "
	   << Q.pos_string() << "\n";
    }
    return true;
  }

  if( expect_tag( Q, Comma_Tag, "parse_triple" ) ) {
    return true;
  }
  
  if( parse_real( Q, y ) ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "parse_triple -- failed to parse second arg of triple near "
	   << Q.pos_string() << "\n";
    }
    return true;
  }

  if( check_tag( Q, Comma_Tag ) ) {
    z = 0;
  } else {
    if( parse_real( Q, z ) ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "parse_triple -- failed to parse third arg of triple near "
	     << Q.pos_string() << "\n";
      }
      return true;
    }
  }

  if( paren_type ) {
    if( expect_tag( Q, R_Bracket_Tag, "parse_triple" ) ) {
      return true;
    }
  } else if( expect_tag( Q, R_Paren_Tag, "parse_triple" ) ) {
    return true;
  }
  
  t = triple( x, y, z );
  
  return false;
}

dc_pointer *parse_pointer( token_queue &Q, dc_label *search_origin ) {
  if( expect_tag( Q, Ampersand_Tag, "parse_pointer" ) ) return nil;
  
  string path;
  if( expect_path( Q, path, "parse_pointer" ) ) return nil;

  return new dc_pointer( path, Label_t, search_origin );
}

bool parse_quaternion( token_queue &Q, quaternion &q ) {
  bool paren_type = false; /* triple can be enclosed in either curly brackets or
			      parentheses.  true means opened with curly 
			      brackets */

  double r, i, j, k;
  if( check_tag( Q, L_Paren_Tag ) ) {
    if( check_tag( Q, L_Bracket_Tag ) ) {
      return true;
    }
    paren_type = true;
  }
  
  if( parse_real( Q, r ) ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "parse_triple -- failed to parse first arg of triple near "
	   << Q.pos_string() << "\n";
    }
    return true;
  }

  if( expect_tag( Q, Comma_Tag, "parse_triple" ) ) {
    return true;
  }
  
  if( parse_real( Q, i ) ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "parse_triple -- failed to parse second arg of triple near "
	   << Q.pos_string() << "\n";
    }
    return true;
  }

  if( expect_tag( Q, Comma_Tag, "parse_triple" ) ) {
    return true;
  }
  
  if( parse_real( Q, j ) ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "parse_triple -- failed to parse second arg of triple near "
	   << Q.pos_string() << "\n";
    }
    return true;
  }

  if( expect_tag( Q, Comma_Tag, "parse_triple" ) ) {
    return true;
  }
  
  if( parse_real( Q, k ) ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "parse_triple -- failed to parse second arg of triple near "
	   << Q.pos_string() << "\n";
    }
    return true;
  }

  if( paren_type ) {
    if( expect_tag( Q, R_Bracket_Tag, "parse_triple" ) ) {
      return true;
    }
  } else if( expect_tag( Q, R_Paren_Tag, "parse_triple" ) ) {
    return true;
  }
  
  q = quaternion( r, i, j, k );
  
  return false;
}

dc_distrib *parse_distribution( token_queue &Q ) {
  if( check_tag( Q, Distrib_Tag ) ) {
    return nil;
  }
  
  if( expect_tag( Q, L_Paren_Tag, "parse_distribution" ) ) {
    return nil;
  }
  
  double Min, Max, Mean, Stddev;
  bool Min_Def = false, Max_Def = false, Mean_Def = false, Stddev_Def = false;
  
  do {
    token *t = Q.peek();
    if( !t ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "parse_distribution -- stream ended prematurely\n";
      }
      return nil;
    }
    if( !t->is_tag() ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "parse_distribution -- parse error near " << t->pos_string() 
	     << "\n";
      }
      return nil;
    }
    double *obj = nil;
    bool *obj_def = nil;
    switch( ( ( tag_token * )t )->get() ) {
    case Min_Tag :
      obj = &Min;
      obj_def = &Min_Def;
      break;
    case Max_Tag :
      obj = &Max;
      obj_def = &Max_Def;
      break;
    case Mean_Tag :
      obj = &Mean;
      obj_def = &Mean_Def;
      break;
    case Stddev_Tag :
      obj = &Stddev;
      obj_def = &Stddev_Def;
      break;
    default :
      break;
    }
    if( obj == nil ) {
      break;
    }
    Q.pop();
    if( expect_tag( Q, Equal_Tag, "parse_distribution" ) ) {
      return nil;
    }
    if( parse_real( Q, *obj ) ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "parse_distribution -- parse error near " << Q.pos_string() 
	     << "\n";
      }
      return nil;
    }
    if( *obj_def ) {
      dc_trace( TRACE_WARNING ) {
	cerr << "parse_distribution -- redefining parameter near "
	     << Q.pos_string() << "\n";
      }
    } else {
      *obj_def = true;
    }
  } while( !check_tag( Q, Comma_Tag ) );
  
  if( expect_tag( Q, R_Paren_Tag, "parse_distribution" ) ) return nil;
  
  /* error if !majority( Min_Def, Max_Def, Mean_Def ) && 
     !( Mean_Def && Stddev_Def ) */
  if( !( ( Min_Def ? ( Max_Def || Mean_Def ) : ( Max_Def && Mean_Def ) )
	 || ( Mean_Def && Stddev_Def ) ) ) {
    dc_trace( TRACE_ERROR ) {
    cerr << "parse_distribution -- Insufficient args near " << Q.pos_string()
	 << "\n";
    }
    return nil;
  }

  bool type_bounded = Min_Def || Max_Def;

  /* warning if ambiguous type.  defaults to bounded */
  if( type_bounded && Stddev_Def ) {
    dc_trace( TRACE_WARNING ) {
      cerr << "parse_distribution - ambiguous arg set.  "
	   << "min/max and stddev supplied near " << Q.pos_string() << "\n";
    }
  }

  if( type_bounded ) {
    if( !Min_Def ) {
      Min = ( 2 * Mean ) - Max;
    } else if( !Max_Def ) {
      Max = ( 2 * Mean ) - Min;
    } else if( !Mean_Def ) {
      Mean = ( Min + Max ) / 2;
    }
    if( Min > Mean ) {
      dc_trace( TRACE_WARNING ) {
	cerr << "parse_distribution -- max " << Max << " < min " << Min 
	     << ".  swapping\n";
      }
      double t = Min;
      Min = Max; Max = t;
    }
    if( Mean < Min ) {
      dc_trace( TRACE_WARNING ) {
	cerr << "parse_distribution -- min " << Min << " > mean " << Mean
	     << ".  bounding\n";
      }
      Mean = Min;
    } else if( Mean > Max ) {
      dc_trace( TRACE_WARNING ) {
	cerr << "parse_distribution -- max " << Max << " < mean " << Mean 
	     << ".  bounding\n";
      }
      Mean = Max;
    }
    return new dc_distrib( Mean, Min, Max );
  } else {
    if( Stddev < 0 ) {
      dc_trace( TRACE_WARNING ) {
	cerr << "parse_distribution -- negative stddev " << Stddev 
	     << ".  Usinge absolute value\n";
      }
      Stddev = -Stddev;
    }
    return new dc_distrib( Mean, Stddev );
  }
}

bool parse_string( token_queue &Q, string &S ) {
  token *t = Q.peek();
  if( !t || t->is_tag() ) return true;
  S = ( ( string_token * )t )->get();
  if( S[0] == '\"' && S[S.length() - 1] == '\"' ) {
    S = S( 1, S.length() - 2 );
  }
  Q.pop();
  return false;
}

bool parse_symbol( token_queue &Q, dc_symbol_tag &s_tag, dc_svec_tag &e_tag ) {
  if( check_tag( Q, Symbol_Tag ) ) {
    token *t = Q.peek();
    if( !t || t->is_tag() ) return true;
    if( ( e_tag = sb.lookup_svec( ( ( string_token * )t )->get() ) ) 
	!= undef_svec ) {
      Q.pop();
    }
  } else e_tag = undef_svec;

  token *t = Q.peek();
  if( !t || t->is_tag() ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "parse_symbol::expected symbol string, not " << t << "\n";
    }
    return true;
  }
  if( ( s_tag = sb.lookup_symbol( ( ( string_token * )t )->get() ) )
      == undef_symbol ) return true;
  Q.pop();
  return false;
}
