/* ga_parser.cc */

#include "ga_iface.h"
#include "ga_optimizer.h"
#include "ga_nnet.h"
#include "preparser.h"
#include "ga_input.h"

ga_optimizer *preparse_ga_optimizer( token_queue &Q, dc_node *parent );
ga_nnet      *preparse_ga_nnet     ( token_queue &Q, dc_node *parent );

bool parse_ga_optimizer( token_queue &Q, dc_node *parent );
bool parse_ga_nnet     ( token_queue &Q, dc_node *parent );


static const string NBITS_STR = string( "nbits" );
static const string RESOLUTION_STR = string( "resolution" );

enum ga_param { pCrossover = 0, pMut, mutVar, timeStep, intAccuracy, nGens,
		nHidden, tau, NPARAMS };

static const char *const ga_params[NPARAMS] = { "pcrossover", "pmut", "mutvar",
						"timestep", "intaccuracy",
						"ngens", "nhidden", "tau" };

static dictionary<string,ga_param> ga_param_dict;

void init_params( void );

ga_input *parse_ga_input( token_queue & );
bool pass_ga_input( token_queue & );

ga *preparse_ga( token_queue &Q, dc_node *parent ) {
  token *t = Q.peek();
  if( t == nil ) return nil;
  if( *t == GA_Tag ) {
    token *first = Q.extract();

    t = Q.peek();
    if( !t ) {
      Q.push( first );
      return nil;
    }

    if( *t == Optimizer_Tag ) {
      Q.push( first );
      return preparse_ga_optimizer( Q, parent );
    } else if( *t == NNet_Tag ) {
      Q.push( first );
      return preparse_ga_nnet( Q, parent );
    }

    Q.push( first );
    return nil;
  }
  return nil;
}

bool parse_ga( token_queue &Q, dc_node *parent ) {
  token *t = Q.peek();
  if( t == nil ) return true;
  if( *t == GA_Tag ) {
    token *first = Q.extract();

    t = Q.peek();
    if( !t ) {
      Q.push( first );
      return true;
    }

    if( *t == Optimizer_Tag ) {
      Q.push( first );
      return parse_ga_optimizer( Q, parent );
    } else if( *t == NNet_Tag ) {
      Q.push( first );
      return parse_ga_nnet( Q, parent );
    }

    Q.push( first );
    return true;
  }
  return true;
}

ga_optimizer *preparse_ga_optimizer( token_queue &Q, dc_node *parent ) {
  init_params();

  token *t = Q.peek();

  if( !t || *t != GA_Tag ) return nil;
  unsigned int cpos = t->cnum();
  tag previous_tag = Q.get_previous_tag();
  Q.pop();

  if( expect_tag( Q, Optimizer_Tag, "preparse_ga_optimizer" ) )
    return nil;
  
  string label;
  if( expect_label( Q, label, "preparse_ga_optimizer" ) ) return nil;
  if( expect_tag( Q, L_Paren_Tag, "preparse_ga_optimizer" ) ) return nil;

  ga_optimizer *ga = new ga_optimizer;
  ga->set_both( label, parent );
  
  if( preparse_function( Q, ga ) ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "preparse_ga_optimizer -- error preparsing fitness function for "
	   << ga->full_type() << " near " << Q.pos_string() << "\n";
    }
    delete( ga );
    return nil;
  }

  if( expect_tag( Q, R_Paren_Tag, "preparse_ga_optimizer" ) || 
      expect_tag( Q, L_Bracket_Tag, "preparse_ga_optimizer" ) ) {
    delete( ga );
    return nil;
  }

  Q.set_previous_tag( ga->get_tag() );  
  /* get children */
  while( ( t = Q.peek() ) != nil && *t != R_Bracket_Tag ) {
    if( !check_tag( Q, Input_Tag ) ) {
      ga_input *input;
      if( ( input = parse_ga_input( Q ) ) == nil ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "preparse_ga_optimizer -- error parsing ga input near " 
	       << Q.pos_string() << "\n";
	}
	delete( ga );
	return nil;
      }
      if( expect_tag( Q, Semicolon_Tag, "parse_ga_optimizer" ) ) {
	delete( ga );
	delete( input );
	return nil;
      }
      ga->add_input( *input );
    } else {
      dic_item di;
      if( !t->is_tag() && ( ( di = ga_param_dict.lookup( ( ( string_token * )t )
							 ->get() ) ) != nil ) ){
	Q.pop();
	double d;
	if( expect_tag( Q, Equal_Tag, "preparse_ga_optimizer" ) || 
	    parse_real( Q, d ) ||
	    expect_tag( Q, Semicolon_Tag, "preparse_ga_optimizer" ) ) {
	  delete( ga );
	  return nil;
	}
	
	switch( ga_param_dict.inf( di ) ) {
	case pCrossover :
	  if( ga->set_pCrossover( d ) ) {
	    dc_trace( TRACE_ERROR ) {
	      cerr << "preparse_ga_optimizer -- error setting param \"" 
		   << ga_params[ ga_param_dict.inf( di ) ] << " near " 
		   << Q.pos_string() << "\n";
	    }
	    delete( ga );
	    return nil;
	  }
	  break;
	case pMut :
	  if( ga->set_pMut( d ) ) {
	    dc_trace( TRACE_ERROR ) {
	      cerr << "preparse_ga_optimizer -- error setting param \"" 
		   << ga_params[ ga_param_dict.inf( di ) ] << " near " 
		   << Q.pos_string() << "\n";
	    }
	    delete( ga );
	    return nil;
	  }
	  break;
	case mutVar :
	  if( ga->set_mutVar( d ) ) {
	    dc_trace( TRACE_ERROR ) {
	      cerr << "preparse_ga_optimizer -- error setting param \"" 
		   << ga_params[ ga_param_dict.inf( di ) ] << " near " 
		   << Q.pos_string() << "\n";
	    }
	    delete( ga );
	    return nil;
	  }
	  break;
	case timeStep :
	  if( ga->set_time_step( d ) ) {
	    dc_trace( TRACE_ERROR ) {
	      cerr << "preparse_ga_optimizer -- error setting param \"" 
		   << ga_params[ ga_param_dict.inf( di ) ] << " near " 
		   << Q.pos_string() << "\n";
	    }
	    delete( ga );
	    return nil;
	  }
	  break;
	case intAccuracy :
	  if( ga->set_int_accuracy( d ) ) {
	    dc_trace( TRACE_ERROR ) {
	      cerr << "preparse_ga_optimizer -- error setting param \"" 
		   << ga_params[ ga_param_dict.inf( di ) ] << " near " 
		   << Q.pos_string() << "\n";
	    }
	    delete( ga );
	    return nil;
	  }
	  break;
	case nGens :
	  if( ga->set_nGens( ( int )d ) ) {
	    dc_trace( TRACE_ERROR ) {
	      cerr << "preparse_ga_optimizer -- error setting param \"" 
		   << ga_params[ ga_param_dict.inf( di ) ] << " near " 
		   << Q.pos_string() << "\n";
	    }
	    delete( ga );
	    return nil;
	  }
	  break;
	default :
	  dc_trace( TRACE_ERROR ) {
	    cerr << "preparse_ga_optimizer -- error setting param \"" 
		 << ga_params[ ga_param_dict.inf( di ) ] << " near " 
		 << Q.pos_string() << "\n";
	  }
	  delete( ga );
	  return nil;
	}
      } else if( preparse_block( Q, ga ) ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "preparse_ga_optimizer -- error parsing contents of ga \"" 
	       << label << "\" starting at " << Q.pos_string() 
	       << ". block starts at " << t->pos_string() << "\n";
	}
	delete( ga );
	return nil;
      }
    }
  }
  
  t = Q.peek();
  /* test for end */
  if( !t || *t != R_Bracket_Tag ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "preparse_ga_optimizer -- expected '}' near " << t->pos_string() 
	   << ". found " << *t << " instead\n";
    }
    delete( ga );
    return nil;
  }
  ( ga->buffer_info() ).set( label, cpos, t->cnum() - cpos, previous_tag, 0 );
  Q.pop();

  return ga;
}

bool parse_ga_optimizer( token_queue &Q, dc_node *parent ) {
  init_params();

  if( expect_tag( Q, GA_Tag, "parse_ga_optimizer" ) || 
      expect_tag( Q, Optimizer_Tag, "parse_ga_optimizer" ) )
    return true;
  
  string label;
  if( expect_label( Q, label, "parse_ga_optimizer" ) ) return true;
  if( expect_tag( Q, L_Paren_Tag, "parse_ga_optimizer" ) ) return true;

  ga_optimizer *ga = ( ga_optimizer * )restricted_lookup( label, parent );

  dc_func *fitness;
  if( ( fitness = parse_function( Q, ga, ga ) ) == nil ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "parse_ga_optimizer -- error preparsing fitness function for " 
	   << ga->full_type() << " near " << Q.pos_string() << "\n";
    }
    return true;
  }

  ga->set_fitness_fn( fitness );

  if( expect_tag( Q, R_Paren_Tag, "parse_ga_optimizer" ) || 
      expect_tag( Q, L_Bracket_Tag, "parse_ga_optimizer" ) ) {
    return true;
  }

  token *t;
  while( ( t = Q.peek() ) != nil && *t != R_Bracket_Tag ) {
    if( !check_tag( Q, Input_Tag ) ) {
      if( pass_ga_input( Q ) ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "parse_ga_optimizer -- error parsing ga input near " 
	       << Q.pos_string() << "\n";
	}
	return true;
      }
      if( expect_tag( Q, Semicolon_Tag, "parse_ga_optimizer" ) ) return true;
    } else {
      if( !t->is_tag() && ( ga_param_dict.lookup( ( ( string_token * )t )->get()
						  ) ) ) { 
	Q.pop();
	double d;
	if( expect_tag( Q, Equal_Tag, "parse_ga_optimizer" ) || 
	    parse_real( Q, d ) ||
	    expect_tag( Q, Semicolon_Tag, "parse_ga_optimizer" ) ) {
	  return true;
	}
      } else if( parse_block( Q, ga ) ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "parse_ga_optimizer -- error parsing contents of ga \"" 
	       << label << "\" starting at " << Q.pos_string() 
	       << ". block starts at " << t->pos_string() << "\n";
	}
	return true;
      }
    }
  }
  
  if( expect_tag( Q, R_Bracket_Tag, "parse_ga_optimizer" ) ) {
    return true;
  }
  
  return false;
}

bool parse_ga_nnet( token_queue &Q, dc_node *parent ) {
  init_params();

  if( expect_tag( Q, GA_Tag, "parse_ga_nnet" ) || 
      expect_tag( Q, NNet_Tag, "parse_ga_nnet" ) )
    return true;
  
  string label;
  if( expect_label( Q, label, "parse_ga_nnet" ) ) return true;
  if( expect_tag( Q, L_Paren_Tag, "parse_ga_nnet" ) ) return true;

  ga_nnet *ga = ( ga_nnet * )restricted_lookup( label, parent );

  dc_func *fitness;
  if( ( fitness = parse_function( Q, ga, ga ) ) == nil ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "parse_ga_nnet -- error preparsing fitness function for " 
	   << ga->full_type() << " near " << Q.pos_string() << "\n";
    }
    return true;
  }

  ga->set_fitness_fn( fitness );

  if( expect_tag( Q, R_Paren_Tag, "parse_ga_nnet" ) || 
      expect_tag( Q, L_Bracket_Tag, "parse_ga_nnet" ) ) {
    return true;
  }

  token *t;
  while( ( t = Q.peek() ) != nil && *t != R_Bracket_Tag ) {
    if( !check_tag( Q, Input_Tag ) || !check_tag( Q, Output_Tag ) ) {
      if( pass_ga_input( Q ) ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "parse_ga_nnet -- error parsing ga input near " 
	       << Q.pos_string() << "\n";
	}
	return true;
      }
      if( expect_tag( Q, Semicolon_Tag, "parse_ga_nnet" ) ) return true;
    } else {
      if( !t->is_tag() && ( ga_param_dict.lookup( ( ( string_token * )t )->get()
						  ) ) ) { 
	Q.pop();
	double d;
	if( expect_tag( Q, Equal_Tag, "parse_ga_nnet" ) || 
	    parse_real( Q, d ) ||
	    expect_tag( Q, Semicolon_Tag, "parse_ga_nnet" ) ) {
	  return true;
	}
      } else if( parse_block( Q, ga ) ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "parse_ga_nnet -- error parsing contents of ga \"" 
	       << label << "\" starting at " << Q.pos_string() 
	       << ". block starts at " << t->pos_string() << "\n";
	}
	return true;
      }
    }
  }
  
  if( expect_tag( Q, R_Bracket_Tag, "parse_ga_nnet" ) ) {
    return true;
  }
  
  return false;
}

ga_input *parse_ga_input( token_queue &Q ) {
  dc_type T;

  token *t = Q.peek();
  ga_input *I;
  if( t != nil && t->is_tag() ) {
    switch( ( ( tag_token * )t )->get() ) {
    case Boolean_Tag :
      T = Boolean_t;
      I = new ga_bool_input;
      break;
    case Int_Tag :
      T = Int_t;
      I = new ga_int_input;
      break;
    case Real_Tag :
      T = Real_t;
      I = new ga_real_input;
      break;
    default :
      dc_trace( TRACE_ERROR ) {
	cerr << "parse_ga_input -- error parsing input at " << *t << " near " 
	     << t->pos_string() << "\n";
      }
      return nil;
    }
    Q.pop();
  } else {
    T = Real_t;
    I = new ga_real_input;
  }
  
  string path;
  if( expect_path( Q, path, "parse_ga_input" ) ) {
    delete( I );
    return nil;
  }
  I ->set_path( path );

  if( T == Boolean_Tag ) {
    if( expect_tag( Q, Semicolon_Tag, "parse_ga_input" ) ) {
      delete( I );
      return nil;
    }
    return I;
  }

  if( expect_tag( Q, L_Paren_Tag, "parse_ga_input" ) ) {
    delete( I );
    return nil;
  }

  double min = 0, max = 255, res = 1, nbits = 0;
  bool min_set = false, max_set = false, res_set = false, nbits_set = false;

  do {
    t = Q.pop();
    if( t == nil ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "parse_ga_input -- error parsing input at " << *t << " near " 
	     << t->pos_string() << "\n";
      }
      return nil;
    }

    double *param = nil;
    bool *param_status = nil;

    if( t->is_tag() ) {
      switch( ( ( tag_token * )t )->get() ) {
      case Min_Tag :
	param = &min;
	param_status = &min_set;
	break;
      case Max_Tag :
	param = &max;
	param_status = &max_set;
	break;
      default :;
      }
    } else if( T == Real_t ) {
      if( *t == NBITS_STR ) {
	param = &nbits;
	param_status = &nbits_set;	
      } else if( *t == RESOLUTION_STR ) {
	param = &res;
	param_status = &res_set;
      }
    }

    if( param == nil ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "parse_ga_input -- failed to match " << *t 
	     << " to a range paramater near " << t->pos_string() << "\n";
      }
      delete( I );
      return nil;
    }

    if( *param_status ) {
      dc_trace( TRACE_WARNING ) {
	cerr << "parse_ga_input -- " << *t << " seen before " << Q.pos_string()
	     << "\n";
      }
    }

    if( expect_tag( Q, Equal_Tag, "parse_ga_input" ) ) {
      delete( I );
      return nil;
    }

    if( parse_real( Q, *param ) ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "parse_ga_input -- error parsing range near " 
	     << t->pos_string() << "\n";
      }
      delete( I );
      return nil;
    }    
    *param_status = true;
  } while( ( Q.peek() != nil ) && !check_tag( Q, Comma_Tag ) );

  if( expect_tag( Q, R_Paren_Tag, "parse_ga_input" ) ) {
    delete( I );
    return nil;
  }

  bool range_error = false;
  switch( T ) {
  case Real_t :
    if( res_set ) {
      range_error = ( ( ga_real_input * )I )->set_range( min, max, res );
    } else {
      range_error = ( ( ga_real_input * )I )->set_range( min, max, (int)nbits );
    }
    break;
  case Int_t :
    range_error = ( ( ga_int_input * )I )->set_range( (long)min, (long)max );
    break;
  default :;
  }
  if( range_error ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "parse_ga_input -- illegal range for \"" << path << "\" near "
	   << Q.pos_string() << "\n";
    }
    delete( I );
    return nil;
  }

  return I;
}

bool pass_ga_input( token_queue &Q ) {
  token *t = Q.peek();
  dc_type T = Real_t;
  if( t != nil && t->is_tag() ) {
    switch( ( ( tag_token * )t )->get() ) {
    case Boolean_Tag :
      T = Boolean_t;
      break;
    case Int_Tag :
      T = Int_t;
      break;
    case Real_Tag :
      T = Real_t;
      break;
    default :
      dc_trace( TRACE_ERROR ) {
	cerr << "pass_ga_input -- error parsing input at " << *t << " near " 
	     << t->pos_string() << "\n";
      }
      return true;
    }
    Q.pop();
  }
  
  string path;
  if( expect_path( Q, path, "pass_ga_input" ) ) {
    return true;
  }

  if( T == Boolean_Tag ) {
    return expect_tag( Q, Semicolon_Tag, "pass_ga_input" );
  }

  if( expect_tag( Q, L_Paren_Tag, "pass_ga_input" ) ) {
    return true;
  }

  do {
    t = Q.pop();
    if( t == nil ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "pass_ga_input -- error parsing input at " << *t << " near " 
	     << t->pos_string() << "\n";
      }
      return true;
    }

    if( t->is_tag() ) {
      switch( ( ( tag_token * )t )->get() ) {
      case Min_Tag :
      case Max_Tag :
	break;
      default :
	dc_trace( TRACE_ERROR ) {
	  cerr << "pass_ga_input -- failed to match " << *t 
	       << " to a range paramater near " << t->pos_string() << "\n";
	}
	return true;;
      }
    } else if( T != Real_t || ( *t != NBITS_STR && *t != RESOLUTION_STR ) ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "pass_ga_input -- failed to match " << *t 
	     << " to a range paramater near " << t->pos_string() << "\n";
      }
      return true;
    }

    if( expect_tag( Q, Equal_Tag, "pass_ga_input" ) ) {
      return true;
    }

    double d;
    if( parse_real( Q, d ) ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "pass_ga_input -- error parsing range near " 
	     << t->pos_string() << "\n";
      }
      return true;
    }
  } while( ( Q.peek() != nil ) && !check_tag( Q, Comma_Tag ) );

  if( expect_tag( Q, R_Paren_Tag, "pass_ga_input" ) ) {
    return true;
  }

  return false;
}

ga_nnet *preparse_ga_nnet( token_queue &Q, dc_node *parent ) {
  init_params();

  token *t = Q.peek();

  if( !t || *t != GA_Tag ) return nil;
  unsigned int cpos = t->cnum();
  tag previous_tag = Q.get_previous_tag();
  Q.pop();

  if( expect_tag( Q, NNet_Tag, "preparse_ga_nnet" ) )
    return nil;
  
  string label;
  if( expect_label( Q, label, "preparse_ga_nnet" ) ) return nil;
  if( expect_tag( Q, L_Paren_Tag, "preparse_ga_nnet" ) ) return nil;

  ga_nnet *ga = new ga_nnet;
  ga->set_both( label, parent );
  
  if( preparse_function( Q, ga ) ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "preparse_ga_nnet -- error preparsing fitness function for "
	   << ga->full_type() << " near " << Q.pos_string() << "\n";
    }
    delete( ga );
    return nil;
  }

  if( expect_tag( Q, R_Paren_Tag, "preparse_ga_nnet" ) || 
      expect_tag( Q, L_Bracket_Tag, "preparse_ga_nnet" ) ) {
    delete( ga );
    return nil;
  }

  Q.set_previous_tag( ga->get_tag() );  
  /* get children */
  while( ( t = Q.peek() ) != nil && *t != R_Bracket_Tag ) {
    if( !check_tag( Q, Input_Tag ) ) {
      ga_real_input *input;
      if( ( input = ( ga_real_input * )parse_ga_input( Q ) ) == nil ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "preparse_ga_nnet -- error parsing ga input near " 
	       << Q.pos_string() << "\n";
	}
	delete( ga );
	return nil;
      }
      if( expect_tag( Q, Semicolon_Tag, "parse_ga_nnet" ) ) {
	delete( ga );
	delete( input );
	return nil;
      }
      if( input->type() != Real_t ) {
	cerr << "preparse_ga_nnet -- nnet inputs must be real.\n";
	delete( ga ); delete( input );
	return nil;
      }
      ga->add_input( *input );
    } else if( !check_tag( Q, Output_Tag ) ) {
      ga_real_input *input;
      if( ( input = ( ga_real_input * )parse_ga_input( Q ) ) == nil ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "preparse_ga_nnet -- error parsing ga input near " 
	       << Q.pos_string() << "\n";
	}
	delete( ga );
	return nil;
      }
      if( expect_tag( Q, Semicolon_Tag, "parse_ga_nnet" ) ) {
	delete( ga );
	delete( input );
	return nil;
      }
      if( input->type() != Real_t ) {
	cerr << "preparse_ga_nnet -- nnet inputs must be real.\n";
	delete( ga ); delete( input );
	return nil;
      }
      ga->add_output( *input );
    } else {
      dic_item di;
      if( !t->is_tag() && ( ( di = ga_param_dict.lookup( ( ( string_token * )t )
							 ->get() ) ) != nil ) ){
	Q.pop();
	double d;
	if( expect_tag( Q, Equal_Tag, "preparse_ga_nnet" ) || 
	    parse_real( Q, d ) ||
	    expect_tag( Q, Semicolon_Tag, "preparse_ga_nnet" ) ) {
	  delete( ga );
	  return nil;
	}
	
	switch( ga_param_dict.inf( di ) ) {
	case pCrossover :
	  if( ga->set_pCrossover( d ) ) {
	    dc_trace( TRACE_ERROR ) {
	      cerr << "preparse_ga_nnet -- error setting param \"" 
		   << ga_params[ ga_param_dict.inf( di ) ] << " near " 
		   << Q.pos_string() << "\n";
	    }
	    delete( ga );
	    return nil;
	  }
	  break;
	case pMut :
	  if( ga->set_pMut( d ) ) {
	    dc_trace( TRACE_ERROR ) {
	      cerr << "preparse_ga_nnet -- error setting param \"" 
		   << ga_params[ ga_param_dict.inf( di ) ] << " near " 
		   << Q.pos_string() << "\n";
	    }
	    delete( ga );
	    return nil;
	  }
	  break;
	case mutVar :
	  if( ga->set_mutVar( d ) ) {
	    dc_trace( TRACE_ERROR ) {
	      cerr << "preparse_ga_nnet -- error setting param \"" 
		   << ga_params[ ga_param_dict.inf( di ) ] << " near " 
		   << Q.pos_string() << "\n";
	    }
	    delete( ga );
	    return nil;
	  }
	  break;
	case timeStep :
	  if( ga->set_time_step( d ) ) {
	    dc_trace( TRACE_ERROR ) {
	      cerr << "preparse_ga_nnet -- error setting param \"" 
		   << ga_params[ ga_param_dict.inf( di ) ] << " near " 
		   << Q.pos_string() << "\n";
	    }
	    delete( ga );
	    return nil;
	  }
	  break;
	case intAccuracy :
	  if( ga->set_int_accuracy( d ) ) {
	    dc_trace( TRACE_ERROR ) {
	      cerr << "preparse_ga_nnet -- error setting param \"" 
		   << ga_params[ ga_param_dict.inf( di ) ] << " near " 
		   << Q.pos_string() << "\n";
	    }
	    delete( ga );
	    return nil;
	  }
	  break;
	case nGens :
	  if( ga->set_nGens( ( int )d ) ) {
	    dc_trace( TRACE_ERROR ) {
	      cerr << "preparse_ga_nnet -- error setting param \"" 
		   << ga_params[ ga_param_dict.inf( di ) ] << " near " 
		   << Q.pos_string() << "\n";
	    }
	    delete( ga );
	    return nil;
	  }
	  break;
	case nHidden :
	  if( ga->set_nHidden( ( int )d ) ) {
	    dc_trace( TRACE_ERROR ) {
	      cerr << "preparse_ga_nnet -- error setting param \"" 
		   << ga_params[ ga_param_dict.inf( di ) ] << " near " 
		   << Q.pos_string() << "\n";
	    }
	    delete( ga );
	    return nil;
	  }
	  break;
	case tau :
	  if( ga->set_tau( d ) ) {
	    dc_trace( TRACE_ERROR ) {
	      cerr << "preparse_ga_nnet -- error setting param \"" 
		   << ga_params[ ga_param_dict.inf( di ) ] << " near " 
		   << Q.pos_string() << "\n";
	    }
	    delete( ga );
	    return nil;
	  }
	  break;
	case NPARAMS :
	  exit( 1 );
	}
      } else if( preparse_block( Q, ga ) ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "preparse_ga_nnet -- error parsing contents of ga \"" 
	       << label << "\" starting at " << Q.pos_string() 
	       << ". block starts at " << t->pos_string() << "\n";
	}
	delete( ga );
	return nil;
      }
    }
  }
  
  t = Q.peek();
  /* test for end */
  if( !t || *t != R_Bracket_Tag ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "preparse_ga_nnet -- expected '}' near " << t->pos_string() 
	   << ". found " << *t << " instead\n";
    }
    delete( ga );
    return nil;
  }
  ( ga->buffer_info() ).set( label, cpos, t->cnum() - cpos, previous_tag, 0 );
  Q.pop();

  return ga;
}


void init_params( void ) {
  static bool inited = false;
  if( !inited ) {
    inited = true;
    for( int i = 0 ; i < NPARAMS ; i++ ) {
      ga_param_dict.insert( string( ga_params[i] ), ( ga_param )i );
    }
  }
}
