/* preparser.cc */

#include "preparser.h"
#include "root.h"
#include <stdio.h>
#include <ctype.h>
#include "cor_syn_iface.h"
#include "cor_pipe.h"
#include "clock.h"

//static list<dc_component *> template_list;/* list of components with templates
//					       to be expanded */
list<dc_modification *> modify_list; /* list of modifications.
				        declared extern.
					deleted at beginning of preparse and at
					end of parse */

/* if tag pT is on top of Q then it extracts it returning false.
   otherwise returns true */
bool extract_tag( token_queue &Q, parseTag pT ) {
  token *t = Q.peek();
  if( t && *t == pT ) {
    delete( Q.extract() );
    return false;
  }
  return true;
}

bool preparse( token_queue &Q, dc_component *parent,
	       slist<dc_label *> &objs_defined ) {
  modify_list.clear();
  //template_list.clear();
  token *t;
  bool test = false;

  dc_label *result = nil;;

  while( ( t = Q.peek() ) != nil ) {
    result = nil;
    if( t->is_tag() ) {
      switch( ( ( tag_token * ) t )->get() ) {
      case Component_Tag : 
	test = ( result = preparse_component( Q, parent ) ) == nil;
	break;
      case Clock_Tag :
	test = ( result = preparse_clock( Q, parent ) ) == nil;
	break;
      case Modify_Tag :
	test = preparse_modify( Q, parent );
	break;
      case GA_Tag :
	test = ( result = preparse_ga( Q, parent ) ) == nil;
	break;
      default :
	if( preparse_global_def( Q, parent ) && 
	    ( result = preparse_element( Q, parent ) ) == nil )
	  test = true;
      }
    } else {
      test = ( result = preparse_element( Q, parent ) ) == nil;
    }
    if( test ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse -- failed to parse block starting at " 
	     << t->pos_string() << "\n";
      }
      dc_label *id;
      forall( id, objs_defined ) {
	cerr << "deleting " << id->full_type() << "\n";
	delete( id );
      }
      objs_defined.clear();
      //template_list.clear();

      dc_modification *mod;
      forall( mod, modify_list ) {
	delete( mod );
      }
      modify_list.clear();
      return true;
    } else {
      if( result ) {
	objs_defined.append( result );
      }
    }
  }

  /* fill out templates */
  int nerrs;
  if( ( nerrs = rehash_templates() ) != 0 ) {
    cerr << "REHASHING TEMPLATES\n";
    dc_trace( TRACE_ERROR ) {
      cerr << nerrs << "template_rehashing errors\n";
    }
    return true;
  }
  
  return false;
}

dc_component *preparse_component( token_queue &Q, dc_component *parent ) {
  string pos = Q.pos_string();

  token *t = Q.peek();
  /* get component tag */
  if( !t )
    return nil;

  /* used to set buffer info block */
  string fname = t->fname();
  unsigned int cpos = t->cnum();
  tag previous_tag = Q.get_previous_tag();

  if( check_tag( Q, Component_Tag ) ) {
    return nil;
  }
  
  /* get label */
  t = Q.pop();
  if( !valid_label( t ) ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "preparse_component -- bad label for component at " << pos
	   << "\n";
    }
    return nil;
  }
  string label = ( ( string_token * )t )->get();

  dc_component *c = new dc_component( label, parent );
  root.iter_counter->add( *c );

  /* check for [':' <template_label>] */
  if( !check_tag( Q, Colon_Tag ) ) {
    string template_path;
    if( expect_path( Q, template_path, "preparse_component" ) ) {
      delete( c );
      return nil;
    }
    c->set_template( template_path );
    //template_list.push( c );
  }
  
  /* get { */  
  if( expect_tag( Q, L_Bracket_Tag, "preparse_component" ) ) {
    delete( c );
    return nil;
  }
      
  /* get type */
  if( preparse_utypes( Q ) ) {
    dc_trace( TRACE_ERROR ) {
	cerr << "preparse_component -- error parsing user-defined types for \""
	     << label << "\" starting at " << pos << ".\n";
    }
    delete( c );
    return nil;
  }
  
  Q.set_previous_tag( c->get_tag() );

  /* status flags */
  bool dormant = false;
  bool frozen = false;
  /* get children */
  while( ( t = Q.peek() ) != nil && *t != R_Bracket_Tag ) {
    if( *t == Frozen_Tag || *t == Dormant_Tag ) {
      if( preparse_cstatus( Q, dormant, frozen ) ) {
	delete( c );
	return nil;
      }
    } else if( preparse_block( Q, c ) ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_component -- error parsing contents of component \"" 
	     << label << "\" starting at " << pos << ". block starts at " 
	     << t->pos_string() << "\n";
      }
      delete( c );
      return nil;
    }
  }

  if( dormant ) c->set_dormant( true );
  if( frozen ) c->set_frozen( true );
  
  t = Q.peek();
  /* test for end */
  if( !t || *t != R_Bracket_Tag ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "preparse_component -- expected '}' near " << t->pos_string() 
	   << ". found " << *t << " instead\n";
    }
    delete( c );
    return nil;
  }
  ( c->buffer_info() ).set( fname, cpos, t->cnum() - cpos, previous_tag, 0 );
  Q.pop();
  return c;
}

bool preparse_cstatus( token_queue &Q, bool &dormant, bool &frozen ) {
  if( !check_tag( Q, Dormant_Tag ) ) {
    if( expect_tag( Q, Equal_Tag, "preparse_cstatus" ) ) {
      return true;
    }
    if( parse_bool( Q, dormant ) ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_cstatus -- expected status boolean near "
	  << Q.pos_string() << "\n";
      }
      return true;
    }
    return expect_tag( Q, Semicolon_Tag, "preparse_cstatus" );
  } else if( !check_tag( Q, Frozen_Tag ) ) {
    if( expect_tag( Q, Equal_Tag, "preparse_cstatus" ) ) {
      return true;
    }
    if( parse_bool( Q, frozen ) ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_cstatus -- expected status boolean near "
	  << Q.pos_string() << "\n";
      }
      return true;
    }
    return expect_tag( Q, Semicolon_Tag, "preparse_cstatus" );
  }
  return false;
}

dc_element *alloc_element( cstring label, dc_component *parent ) {
  dc_pipe *P;
  if( ( P = alloc_pipe( label, parent ) ) != nil ) {
    /*cerr << "preparse_element -- creating pipe \"" << label << "\" to "
	 << ( parent ? parent->full_type() : string( "root" ) ) << "\n"; */
    //    root.iter_counter->add_secondary( *E );
    return P;
  }
  dc_element *E =  new dc_element( label, parent );
  root.iter_counter->add( *E );
  return E;
}

dc_element *preparse_element( token_queue &Q, dc_component *parent ) {
  string pos = Q.pos_string();
  bool is_constraint = false;
  string label;
  dc_element *e;
  bool type_set = false;

  token *t = Q.peek();
  /* used to set buffer info block */
  string fname = t->fname();
  unsigned int cpos = t->cnum();
  tag previous_tag = Q.get_previous_tag();
  
  if( !t ) return nil;

  bool transparent = false;
  if( *t == Transparent_Tag ) {
    transparent = true;
    Q.pop();
    t = Q.peek();
    if( !t ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_element -- premature end of stream\n";
      }
      return nil;
    }
  }

  /* CHANGED */
  dc_type T = default_type;

  /* optional data type */
  if( t->is_tag() ) {
    if( ( T = get_dtype( ( ( tag_token * )t )->get() ) ) != Undef_t ) {
      type_set = true;
      Q.pop();
    }
  } else { /* check for symbolic type */
    dc_svec_tag e_tag = sb.lookup_svec( ( ( string_token * )t )->get() );
    if( e_tag != undef_svec ) {
      Q.pop();
      T = Symbol_t;
    }
    /* NEED TO ENFORCE SYMBOLIC TYPING SOMEHOW -- dc_xtype? */
  }
  
  if( !check_tag( Q, Constraint_Tag ) ) {
    is_constraint = true;
  } else {
    check_tag( Q, Element_Tag );
  }

  t = Q.peek();
  if( valid_label( t ) ) {
    label = ( ( string_token * )t )->get();
    token *lbl_token = Q.extract();
    t = Q.peek();
    if( !t ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_element -- premature end of stream\n";
      }
      return nil;
    }

    if( *t == Equal_Tag ) {
      Q.push_used( lbl_token );
      if( is_constraint )
	e = add_constraint( label, parent );
      else {
	e = alloc_element( label, parent );
      }
      Q.pop(); /* pop '=' */
    } else if( *t == L_Paren_Tag ) {
      /* determine if call of function in implied constraint or element def */
      list<token *> arg_Q;
      arg_Q.append( lbl_token );
      while( *t != R_Paren_Tag ) {
	t = Q.extract();
	if( !t ) {
	  dc_trace( TRACE_ERROR ) {
	    cerr << "preparse_element -- error parsing paren contents near " 
		 << pos << "\n";
	  }
	  while( !arg_Q.empty() ) Q.push_used( arg_Q.pop() );
	  return nil;
	}
	arg_Q.append( t );
      }
      t = Q.peek();
      if( *t == Equal_Tag ) { /* is element.  treat paren contents as args */
	Q.push_used( arg_Q.pop() ); /* remove label */
	Q.push_used( arg_Q.pop() ); /* remove left paren */
	while( !arg_Q.empty() ) Q.push( arg_Q.Pop() );

	if( is_constraint )
	  e = add_constraint( label, parent );
	else
	  e = alloc_element( label, parent );
	
	if( check_tag( Q, R_Paren_Tag ) ) { /* pass over zero arg functions */
	  int n = 0;
	  /* parse args */
	  while( 1 ) {
	    dc_type arg_t;
	    t = Q.peek();
	    if( t->is_tag() ) {
	      if( ( arg_t = get_dtype( ( ( tag_token * )t )->get() ) ) 
		  != Undef_t ) {
		Q.pop();
	      } else {
		arg_t = default_type;
	      }
	    } else arg_t = default_type;

	    if( !valid_label( t = Q.pop() ) ) {
	      delete( e );
	      dc_trace( TRACE_ERROR ) {
		cerr << "preparse_element -- error parsing label for arg " << n
		     << " of " << e->full_type() << " near " << t->pos_string() 
		     << "\n";
	      }
	      return nil;
	    }
	    string name = ( ( string_token * )t )->get();
	    if( !check_tag( Q, Equal_Tag ) ) {
	      if( preparse_function( Q, e ) ) {
		dc_trace( TRACE_ERROR ) {
		  cerr << "preparse_element -- error parsing default of arg "
		       << n << " of " << e->full_type() << " near " 
		       << Q.pos_string() << "\n";
		  delete( e );
		  return nil;
		}
	      }
	    }
	    dc_arg *a = new dc_arg( name, arg_t );
	    e->add_arg( *a );
	    if( check_tag( Q, Comma_Tag ) ) {
	      break;
	    }
	    
	    n++;
	  }
	}
	if( expect_tag( Q, R_Paren_Tag ) || expect_tag( Q, Equal_Tag ) ) {
	  delete( e );
	  return nil;
	}
      } else { /* is implicit constraint. */
	e = add_constraint( parent );  
	/* push label info on so that element parser 
	   will see it as a constraint */
	Q.push_used( Constraint_Tag );
	Q.push_used( e->local_label(), false );
	Q.push_used( Equal_Tag );
	is_constraint = true;	
	/* push arq_Q back onto queue in reverse order */
	while( !arg_Q.empty() ) {
	  Q.push( arg_Q.Pop() );
	}
      }
    } else { /* is implicit constraint */
      e = add_constraint( parent );
      /* push label info on so that element parser will see it as a 
	 constraint */
      Q.push_used( Constraint_Tag );
      Q.push_used( e->local_label(), false );
      Q.push_used( Equal_Tag );
      is_constraint = true;
      Q.push( lbl_token );
    }
  } else { /* if not valid label */
    e = add_constraint( parent );
    /* push label info on so that element parser will see it as a 
       constraint */
    Q.push_used( Constraint_Tag );
    Q.push_used( e->local_label(), false );
    Q.push_used( Equal_Tag );
    is_constraint = true;
  }
 
  /* get function */
  if( check_tag( Q, Nil_Tag ) && preparse_function( Q, e ) ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "preparse_element -- error parsing evaluation function"
	   << " for element \"" << label << "\" starting at " << pos << "\n";
    }
    delete( e );
    return nil;
  }
  
  /* get optional initial value */
  if( !check_tag( Q, Colon_Tag ) ) {
    if( preparse_data( Q ) ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_element -- error parsing initial value"
	     << " for element \"" << e->full_type() << "\" starting at " 
	       << pos << "\n";
      }
      delete( e );
      return nil;
    }
  }

  /* get optional clock -- overrides any default clock attachment */
  if( !check_tag( Q, Comma_Tag ) ) {
    if( expect_tag( Q, Clock_Tag, "preparse_element" ) ) {
      delete( e );
      return nil;
    }
    string clock_path;
    if( expect_path( Q, clock_path, "preparse_element" ) ) {
      delete( e );
      return nil;
    }
    e->set_clock_str( clock_path, parent );

    /* add secondary clocks */
    while( !check_tag( Q, Comma_Tag ) ) {
      if( expect_path( Q, clock_path, "preparse_element" ) ) {
	delete( e );
	return nil;
      }
    }
  }

  /* check ';' */
  t = Q.peek();
  if( !t || *t != Semicolon_Tag ) {
    dc_trace( TRACE_ERROR )
      cerr << "preparse_element -- expected ';' at end of declaration of "
	   << e->full_type() << " near " << Q.pos_string() << "\n";
    delete( e );
    return nil;
  }

  Q.set_previous_tag( e->get_tag() );
  ( e->buffer_info() ).set( fname, cpos, t->cnum() - cpos, previous_tag, 0 );
  Q.pop();

  if( is_constraint ) {
    if( type_set && T != Data_t && T != Boolean_t ) {
      dc_trace( TRACE_WARNING ) {
	cerr << "preparse_element -- constraint " << e->full_type() 
	     << " specified with non boolean_type near " << pos << "\n";
      }
    }
    T = Boolean_t;
  }

  e->set_type( T );
  e->set_transparent( transparent );
  return e;
}

dc_clock *preparse_clock( token_queue &Q, dc_component *parent ) {
  if( expect_tag( Q, Clock_Tag, "preparse_clock" ) ) return nil;

  string label;
  if( expect_label( Q, label, "preparse_clock" ) ) return nil;
  dc_clock *clk = new dc_clock( label, parent );

  root.iter_counter->add( *clk );

  return clk;
}

//ga_optimizer *preparse_ga( token_queue &Q, dc_node *parent ) {

//}

bool preparse_modify( token_queue &Q, dc_node *parent ) {
  token *t = Q.peek();

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

  check_tag( Q, Component_Tag );

  string path;
  if( expect_path( Q, path, "preparse_modify" ) ) return true;

  dc_modification *mod = new dc_modification( path, parent );

  if( !check_tag( Q, Colon_Tag ) ) {
    string replacement_template;
    if( expect_path( Q, replacement_template, "preparse_modify" ) ) {
      delete( mod );
      return true;
    }
    mod->set_replacement_template( replacement_template );
  }

  /* push label onto token queue so that later parsing passes can locate it */
  Q.push_used( mod->local_label(), false );

  if( expect_tag( Q, L_Bracket_Tag, "preparse_modify" ) ) return true;

  Q.set_previous_tag( mod->get_tag() );
  while( ( ( t = Q.peek() ) != nil ) && ( *t != R_Bracket_Tag ) ) {
    
    if( t == nil ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_modify -- unexpected end of input\n";
      }
      delete( mod );
      return true;
    }
    bool test = false;
    dc_element *e; dc_component *c; dc_clock *l;
    if( t->is_tag() ) {
      switch( ( ( tag_token * ) t )->get() ) {
      case Component_Tag : 
	c = preparse_component( Q, mod );
       	if( c ) {
	  c->set_dormant( true );
	} else test = true;
	break;
      case Clock_Tag :
        l = preparse_clock( Q, mod );
	if( l ) l->set_visible( true );
	else test = true;
	break;
      case Modify_Tag :
	test = preparse_modify( Q, mod );
	l = nil;
	break;
      default :
	e = preparse_element( Q, mod );
	if( e ) {
	  e->set_dormant( true );
	}
	else test = true;
      }
    } else {
      e = preparse_element( Q, mod );
      if( e ) { 
	e->set_dormant( true );
      } else test = true;
    }
    if( test ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_modify -- failed to parse modification block\n";
      }
      delete( mod );
      return true;
    }
  }

  t = Q.peek();
  /* test for end */
  if( !t || *t != R_Bracket_Tag ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "preparse_modify -- expected '}' near " << t->pos_string() 
	   << ". found " << *t << " instead\n";
    }
    delete( mod );
    return nil;
  }
  ( mod->buffer_info() ).set( mod->local_label(), cpos, t->cnum() - cpos, 
			      previous_tag, 0 );
  Q.pop();

  modify_list.append( mod );

  return false;
}

bool preparse_block( token_queue &Q, dc_component *parent ) {
  token *t = Q.peek();
  if( t == nil ) return true;
  if( t->is_tag() ) {
    switch( ( ( tag_token * )t )->get() ) {
    case Component_Tag : 
      return preparse_component( Q, parent ) == nil;
      break;
    case Clock_Tag :
      return preparse_clock( Q, parent ) == nil;
      break;
    case Modify_Tag :
      return preparse_modify( Q, parent );
      break;
    default :
      return preparse_global_def( Q, parent ) && 
	( preparse_element( Q, parent ) == nil );
    }
  }

  return preparse_element( Q, parent ) == nil;
}

bool preparse_arg( token_queue &Q, dc_label *owner ) {
  token *t = Q.peek();
  if( t == nil ) return false;

  if( t->is_tag() ) {
    parseTag pT = ( ( tag_token * )t )->get();
    if( get_dtype( pT ) != Undef_t )
      return preparse_data( Q );

    token *t1;
    bool implicit;
    switch( pT ) {
    case Ampersand_Tag :
      return preparse_data( Q );
      break;
    case Self_Tag :
      Q.pop();
      if( owner && owner->type() != Element_t ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "preparse_arg -- self_ref used outside of element "
	       << "definition\n";
	}
	return true;
      }
      return false;
      break;
    case L_Paren_Tag :
      Q.pop();

      t = Q.peek();
      if( t->is_tag() && get_dtype( ( ( tag_token * )t )->get() ) != Undef_t ) {
	token *dtag_tkn = Q.extract();
	t = Q.peek();
	if( t && *t == R_Paren_Tag ) { /* is type cast of form '(' dtag ')' */
	  Q.push_used( dtag_tkn );
	  Q.pop(); /* pop R_Paren_Tag */
	  return preparse_arg( Q, owner );
	} else {
	  Q.push( dtag_tkn );
	}
      }

      /* eat paren and recurse */
      if( preparse_function( Q, owner ) ) {
	return true;
      }
      return expect_tag( Q, R_Paren_Tag, "preparse_arg" );
      break;
    case Old_Tag :
      Q.pop();
      t = Q.peek();
      break;
    case Time_Tag : case Delta_Time_Tag :
      Q.pop();
      return false;
      break;
    case For_Tag :
      return preparse_iter_loop( Q, owner );
      break;
    case L_SqBracket_Tag :
      /* check for unit cast */
      
      /* check for cast.  if no cast it is an implicit multiplication of 
	 previous arg so insert ('*' '1') before ('[' <units> ']') onto Q */
      t1 = Q.extract();
      
      t = Q.peek();
      if( t && *t == Cast_Tag ) {
	Q.push_used( t1 );
	Q.pop();
	implicit = false;
      } else {
	Q.push_used( Product_Tag );
	Q.push_used( string( "1" ), false );
	Q.push_used( t1 );
	implicit = true;
      }
      
      if( preparse_uv( Q, false ) ||
	  expect_tag( Q, R_SqBracket_Tag, "preparse_arg -- unit cast" ) ) {
	return true;
      }

      if( !implicit && preparse_arg( Q, owner ) ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "preparse_arg -- error parsing arg after unit cast near "
	       << Q.pos_string() << "\n";
	}
	return true;
      }
      return false;
      break;
    default : 
      /* check for unary op */
      int index;
      if( !get_fn_of_type( pT, index, UNARY_OP ) ) {
	Q.pop();
	return preparse_arg( Q, owner );
      }

      /* preparse func */
      return preparse_func( Q, owner );
    }
  }

  /* preparse pathname */
  if( !preparse_data( Q ) ) {
    return false;
  } else {
    if( !valid_path( t ) ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_arg -- invalid label near " << t->pos_string() 
	     << "\n";
      }
      return true;
    }
    string label = ( ( string_token * )t )->get();
    /* see if function argument matching */
    if( owner && owner->type() == Element_t ) {
      if( ( ( dc_element * )owner )->is_arg( label ) ) {
	Q.pop();
	return false;
      }
    }

    dc_label *l = nt_search( label, Component_t, owner );
    if( l == nil ) { /* undefined reference */
      token *label_tkn = Q.extract();
      t = Q.peek();
      if( t && *t == L_Paren_Tag ) { /* undefined Function_Call Reference */
	Q.push( label_tkn );
	dc_trace( TRACE_MANY ) {
	  cerr << "preparse_arg -- assuming call undefined element \"" 
	       << label << "\"\n";
	}
	return preparse_fcall( Q, owner );
      } 
      /* else Undefined Element/Data Reference or symbol */
      Q.push_used( label_tkn );
      dc_trace( TRACE_MANY ) {
	cerr << "preparse_arg -- assuming \"" << label << "\"is undefined "
	     << "element/symbol \n"; 
      }
      return false;
    }

    token *label_tkn;
    if( l->type() == Element_t ) {
      label_tkn = Q.extract();
      t = Q.peek();
      if( t && *t == L_Paren_Tag ) {
	Q.push( label_tkn );
	return preparse_fcall( Q, owner );
      } 
      Q.push_used( label_tkn );
      return false;
    } else if( l->is_data() ) {
      Q.pop(); /* pop label */
      return false;
    } else {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_arg -- invalid reference to " << l->full_type() 
	     << " near " << Q.pos_string() 
	     << " in function.  must be data, element or function type\n";
      }
      return true;
    }
  }
}

// bool preparse_unit_cast( token_queue &Q ) {
//   token *t;
//   list<token *>t_list;
//   bool fail = false;

//   if( !t || *t != L_Paren_Tag ) return true;
//   t_list.append( Q.extract() );
  
//   token *t = Q.peek();
//   if( !t || t->is_tag() ) {
//     fail = true;
//   } else {
//     string uname = ( ( string_token * )t )->get();
//     if( !ub.preparse_units( uname ) ) {
//       t_list.append( Q.extract() );
//       while( 1 ) {
// 	t = Q.peek();
// 	if( !t ) break;
// 	token *last;
// 	if( *t == Product_Tag || *t == Inv_Prod_Tag ) {
// 	  last = Q.extract();
// 	  t = Q.peek();
// 	  if( t && !t->is_tag() ) {
// 	    if( ub.preparse_units( ( ( string_token * )t )->get() ) ) {
// 	      Q.push( last );
// 	      break;
// 	    } else { 
// 	      t_list.append( last );
// 	      t_list.append( Q.extract() );
// 	    }
// 	  } else {
// 	    Q.push( last );
// 	    break;
// 	  }
// 	} else break;
//       }
//     }
//   }
  
//   if( fail || ( t = Q.peek() ) == nil || *t != R_Paren_Tag ) {
//     while( !t_list.empty() ) {
//       Q.push( t_list.Pop() );
//     }
//     return true;
//   }
//   forall( t, t_list ) {
//     while( !t_list.empty() ) {
//       Q.push_used( t_list.pop() );
//     }
//   }
//   Q.pop(); /* pop R_Paren_Tag */
//   return false;
// }

bool preparse_func( token_queue &Q, dc_label *owner ) {
  token *t = Q.peek();
  if( !t || !t->is_tag() ) return true;

  /* get function */
  int index;
  if( get_fn_of_type( ( ( tag_token * )t )->get(), index, FUNC ) ) {
    return true;
  }
  Q.pop();

  /* check lparen */
  if( expect_tag( Q, L_Paren_Tag, "preparse_func" ) ) {
    return true;
  }

  t = Q.peek();
  if( !t ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "preparse_func -- unexpected end of stream near " 
	   << Q.pos_string() << "\n";
    }
    return true;
  }
  
  if( preparse_set( Q ) ) {
    if( preparse_f_list( Q, owner ) ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_func -- error parsing argument list near " 
	     << Q.pos_string() << "\n";
      }
      return true;
    }
  }  

  /* check rparen */
  return expect_tag( Q, R_Paren_Tag, "preparse_func" );
}

bool preparse_fcall( token_queue &Q, dc_label *owner ) {
  token *t = Q.peek();

  /* get label */
  if( !valid_path( t ) ) return nil;
  string label = ( ( string_token * )t )->get();
  dc_label *e = search( label, owner );
  if( e && e->type() != Element_t ) {
    return true;
  }
  Q.pop();

  /* check lparen */
  if( expect_tag( Q, L_Paren_Tag, "preparse_fcall" ) ) return true;

  /* get args */
  int n = 0;
  if( check_tag( Q, R_Paren_Tag ) ) {
    while( 1 ) {
      /* check optional name */
      t = Q.peek();
      if( t && !t->is_tag() ) {
	string label = ( ( string_token * )t )->get();
	token *arg_lbl = Q.extract();
	t = Q.peek();
	if( t && *t == Equal_Tag ) {
	  Q.push_used( arg_lbl );
	  Q.pop();
	} else {
	  Q.push( arg_lbl );
	}
      }
   
      if( preparse_function( Q, owner, nil ) ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "preparse_fcall -- error parsing argument " << n 
	       << " near " << Q.pos_string() << "\n";
	}
	return true;
      }
      if( check_tag( Q, Comma_Tag ) ) break;
      n++;
    }
  } else {
    return false; /* zero args passed */
  }

  /* check rparen */
  return expect_tag( Q, R_Paren_Tag, "preparse_fcall" );
}

bool preparse_iter_loop( token_queue &Q, dc_label *owner ) {
  string label;
  if( check_tag( Q, For_Tag ) ||
      expect_tag( Q, L_Paren_Tag, "preparse_iter_loop" ) ) 
    return true;

  token *t = Q.peek();
  if( t->is_tag() && get_dtype( ( ( tag_token * )t )->get() ) != Undef_t ) {
    Q.pop();
  }

  if( expect_label( Q, label, "preparse_iter_loop" ) ||
      expect_tag( Q, Comma_Tag, "preparse_iter_loop" ) ) 
    return true;
  if( ( check_label( Q, label ) && preparse_set( Q ) ) ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "preparse_iter_loop -- failed to find label or parse set near " 
	   << Q.pos_string() << "\n";
    }
    return true;
  }
  if( expect_tag( Q, R_Paren_Tag, "preparse_iter_loop" ) ||
      expect_tag( Q, L_Bracket_Tag, "preparse_iter_loop" ) ) 
    return true;
  if( preparse_function( Q, owner ) ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "preparse_iter_loop -- failed to parse loop function near "
	   << Q.pos_string() << "\n";
    }
    return true;
  }
  return expect_tag( Q, R_Bracket_Tag, "preparse_iter_loop" );
}

bool preparse_f_list( token_queue &Q, dc_label *owner ) {
  /* get first arg */
  if( preparse_function( Q, owner ) ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "preparse_f_list -- function expected before " << Q.pos_string()
	   << "\n";
    }
    return true;
  }
  
  while( 1 ) {
    /* check comma */
    if( check_tag( Q, Comma_Tag ) ) return false;

    /* preparse next arg */
    if( preparse_function( Q, owner ) ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_f_list -- function expected before " << Q.pos_string()
	     << "\n";
      }
      return true;
    }
  }
}

bool preparse_default( token_queue &Q, dc_node *parent ) {
  string pos = Q.pos_string();
  
  /* check default tag */
  if( check_tag( Q, Default_Tag ) ) return true;

  dc_type T;
  token *t = Q.peek();
  /* optional data type */
  if( t->is_tag() ) {
    if( ( T = get_dtype( ( ( tag_token * )t )->get() ) ) != Undef_t ) {
      Q.pop();
    } else {
      T = default_type;
    }
  } else T = default_type;
  
  /* get label */
  t = Q.peek();
  if( !valid_label( t ) ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "preparse_default -- could not parse default value label "
	   << "starting at " << pos << "\n";
    }
    return true;
  }
  string label = ( ( string_token * )t )->get();
  Q.pop();
  
  /* check '=' */
  if( expect_tag( Q, Equal_Tag, "preparse_default" ) ) {
    return true;
  }

  /* parse value */
  dc_data *value = parse_data( Q, nil, nil/*, T*/ );
  if( value == nil ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "preparse default -- could not parse default value definition "
	   << "starting at " << pos << " since value could not be parsed\n";
    }
    delete( value );
    return true;
  }
  dc_type value_t = value->sub_type();
  if( T != value_t ) {
    if( castable( value_t, T ) ) {
      value = cast( *value, T );
    } else {
      delete( value );
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_default -- invalid type returned for default of "
	     << label << " at " 
	     << ( ( parent == nil ) ? string( "root" ) : parent->label() )
	     << "\n";
      }
      return true;
    }
  }
  dc_default *deflt = value->has_units() ? 
    new dc_udefault( label, ( dc_component * )parent ) :
    new dc_default( label, ( dc_component * )parent );
  
  deflt->set_type( T );

  deflt->init( *value );
  //  deflt->set_func( *( new dc_const( *value ) ) );

  /* if( set_default( label, *value ) ) {
     dc_trace( TRACE_ERROR ) {
     cerr << "preparse default -- failed default value definition at " << pos 
     << "\n";
     }
     delete( value );
     return true;
     }
     */

  /* check ';' */
  if( expect_tag( Q, Semicolon_Tag, "preparse_default" ) ) {
    return true;
  }
  return false;
}

bool preparse_utypes( token_queue &Q ) {
  if( check_tag( Q, Type_Tag ) ) return false; /* types optional */

  do {
    if( check_tag( Q, Inherited_Tag ) ) {
      check_tag( Q, Local_Tag ); /* local by default */
    }

    token *t = Q.pop();
    if( !valid_label( t ) ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_type -- type label near " << t->pos_string() 
	     << " was not a valid label\n";
      }
      return true;
    }
    string u_name = ( ( string_token * )t )->get();
    if( parse_u_type( u_name ) == Undefined_Type ) {
      dc_trace( TRACE_MANY ) {
	cerr << "preparse_type -- implicit declaration of type " << u_name
	     << " at " << t->pos_string() << "\n";
      }
      define_u_type( u_name );
    }
  } while( !check_tag( Q, Comma_Tag ) );
  
  return expect_tag( Q, Semicolon_Tag, "preparse_type" );
}

bool preparse_global_def( token_queue &Q, dc_component *parent ) {
  token *t = Q.peek();
  if( t && t->is_tag() ) {
    token *tmp_tkn;
    switch( ( ( tag_token * )t )->get() ) {
    case Define_Tag :
      tmp_tkn = Q.extract();
      t = Q.peek();
      Q.push( tmp_tkn );
      if( t ) {
	if( *t == Symbol_Tag ) return preparse_symbol_def( Q );
	return parse_typedef( Q );
      }
    case Enum_Tag :
      return preparse_enum_def( Q );
    case Default_Tag :
      return preparse_default( Q, parent );
    case Link_Tag :
      return preparse_link( Q );
    default :;
    }
  }
  return true;
}

bool preparse_enum_def( token_queue &Q ) {
  if( expect_tag( Q, Enum_Tag, "preparse_enum_def" ) ) return true;

  string enum_str;
  if( expect_label( Q, enum_str, "preparse_enum_def" ) ) return true;
  dc_svec_tag e_tag = sb.define_svec( enum_str );
  if( e_tag == undef_svec ) return true;

  if( expect_tag( Q, L_Bracket_Tag, "preparse_enum_def" ) ) return true;

  do {
    string symbol_str;
    if( expect_label( Q, symbol_str, "preparse_enum_def" ) ) return true;
    dc_symbol_tag s_tag = sb.define_symbol( symbol_str );
    sb.add_symbol( s_tag, e_tag );
  } while( !check_tag( Q, Comma_Tag ) );

  if( expect_tag( Q, R_Bracket_Tag, "preparse_enum_def" ) ) return true;
  return expect_tag( Q, Semicolon_Tag, "preparse_enum_def" );
}

bool preparse_symbol_def( token_queue &Q ) {
  if( expect_tag( Q, Define_Tag, "preparse_symbol_def" ) ) return true;
  if( expect_tag( Q, Symbol_Tag, "preparse_symbol_def" ) ) return true;
  string symbol_str;
  if( expect_label( Q, symbol_str, "preparse_symbol_def" ) ) return true;
  sb.define_symbol( symbol_str );
  return expect_tag( Q, Semicolon_Tag, "preparse_symbol_def" );
}

dc_link_type parse_link_type( token_queue &Q ) {
  token *t = Q.peek();
  if( t && t->is_tag() ) {
    switch( ( ( tag_token * )t )->get() ) {
    case Distance_Tag : 
      Q.pop(); 
      return Distance_lt;
    case Axial_Tag :
      Q.pop(); 
      return Axial_lt;
    case Attachment_Tag :
      Q.pop();
      return Attachment_lt;
    case Force_Tag :
      Q.pop();
      return Force_lt;
    default :;
    }
  }
  return Undef_lt;
}

bool preparse_link( token_queue &Q ) {
  string label;
  if( expect_tag( Q, Link_Tag, "preparse_link" ) ) return true;

  if( expect_path( Q, label, "preparse_link" ) ) return true;
  
  bool targeted = false;
  if( !( check_tag( Q, Dir_Link_Tag ) && check_tag( Q, Comma_Tag ) ) ) {
    targeted = true;
    if( expect_path( Q, label, "preparse_link" ) ) return true;
  }

  if( !check_tag( Q, Colon_Tag ) ) {
    dc_link_type lt = parse_link_type( Q );
    switch( lt ) {
    case Distance_lt :
      if( preparse_triple( Q ) || expect_tag( Q, Comma_Tag, "preparse_link" ) ||
	  preparse_triple( Q ) || ( !check_tag( Q, Comma_Tag ) &&
				    preparse_real( Q ) ) ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "preparse_link -- error parsing distance link specs near "
	       << Q.pos_string() << "\n";
	}
	return true;
      }
      break;
    case Axial_lt :
      if( preparse_triple( Q ) || expect_tag( Q, Comma_Tag, "preparse_link" ) ||
	  preparse_triple( Q ) || expect_tag( Q, Comma_Tag, "preparse_link" ) ||
	  preparse_triple( Q ) || expect_tag( Q, Comma_Tag, "preparse_link" ) ||
	  preparse_triple( Q ) ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "preparse_link -- error parsing axial link specs near "
	       << Q.pos_string() << "\n";
	}
	return true;
      }
      break;
    case Force_lt :
      if( preparse_function( Q, nil ) || 
	  expect_tag( Q, Comma_Tag, "preparse_link" ) || 
	  preparse_function( Q, nil ) ||
	  ( targeted && ( expect_tag( Q, Comma_Tag, "preparse_link" ) || 
			  preparse_function( Q, nil ) ) ) ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "preparse_link -- error parsing force link specs near "
	       << Q.pos_string() << "\n";
	}
	return true;
      }
      break;
    case Attachment_lt : case Base_lt :
      break;
    default :
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_link -- unsupported link type near " << Q.pos_string()
	     << "\n";
      }
      return true;
    }
  }

  return expect_tag( Q, Semicolon_Tag, "preparse_link" );
}

bool preparse_finite_set( token_queue &Q ) {
  token *t = Q.peek();

  if( !t || !t->is_tag() ) return true;
  
  parseTag pT = ( ( tag_token * )t )->get();
  if( pT == Descendent_Tag || pT == Type_Tag || pT == Key_Tag ) {
    while( 1 ) {
      if( *t == Key_Tag ) {
	Q.pop();
	t = Q.peek();
	if( !t || t->is_tag() ) {
	  dc_trace( TRACE_ERROR ) {
	    cerr << "preparse_finite_set -- expected pattern at " 
		 << t->pos_string() << " but found " << *t << "\n";
	    return true;
	  }
	}
	Q.pop();
      } else if( *t == Type_Tag ) {
	Q.pop();
	t = Q.peek();
	if( valid_label( t ) ) {
	  string type_name = ( ( string_token * )t )->get();
	  user_type ut = parse_u_type( type_name );
	  if( ut == Undefined_Type ) {
	    dc_trace( TRACE_MANY ) {
	      cerr << "preparse_finite_set -- implicit declaration of type \"" 
		   << type_name << "\" at " << t->pos_string() << "\n";
	    }
	    define_u_type( type_name );
	  }
	  Q.pop();
	} else {
	  dc_trace( TRACE_ERROR ) {
	    cerr << "preparse_finite_set -- error parsing type at " 
		 << t->pos_string() << "\n";;
	  }
	  return true;
	}
      } else {
	if( *t == Descendent_Tag ) {
	  Q.pop(); check_tag( Q, Of_Tag );
	  t = Q.peek();
	}
	if( valid_path( t ) ) {
	  Q.pop();
	} else {
	  dc_trace( TRACE_ERROR ) {
	    cerr << "preparse_finite_set -- error parsing set at " 
		 << t->pos_string() << "\n";;
	  }
	  return true;
	}
      }
      if( check_tag( Q, Of_Tag ) && check_tag( Q, Comma_Tag ) ) break;
      t = Q.peek();
      if( !t ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "preparse_finite_set -- premature end of file\n";
	}
	return true;
      }
    }
  } else if( pT == Set_Tag ) {
    Q.pop();
    if( expect_tag( Q, L_Paren_Tag, "preparse_finite_set" ) ) return true;
    do {
      string label;
      if( expect_path( Q, label, "preparse_finite_set" ) ) {
	return true;
      }
    } while( !check_tag( Q, Comma_Tag ) );
    
    if( expect_tag( Q, R_Paren_Tag, "preparse_finite_set" ) ) return true;
  /* } else if( pT == All_Tag ) {
     Q.pop();
     } else if( pT == None_Tag ) {
     Q.pop(); */
  } else if( pT == Self_Tag ) {
    Q.pop();
  } else return true;

  return false;
}

bool preparse_set( token_queue &Q ) {
  if( preparse_finite_set( Q ) ) return true;

  while( !check_tag( Q, Ampersand_Tag ) ) {
    if( preparse_finite_set( Q ) ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_set -- error parsing set near " << Q.pos_string() 
	     << "\n";
      }
      return true;
    }
  } 
  
  if( !check_tag( Q, Exception_Tag ) ) {
    do {
      if( preparse_finite_set( Q ) ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "preparse_set -- error parsing exception near " 
	       << Q.pos_string() << "\n";
	}
	return true;
      }
    } while( !check_tag( Q, Ampersand_Tag ) );
  }

  return false;
}

bool preparse_data( token_queue &Q ) {
  /* get type tag */
  token *t = Q.peek();
  if( ( t == nil ) ) {
    return true;
  }

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

    bool b;
    if( !parse_bool( Q, b ) ) {
      return false;
    }

    /* combine split negative exponent if necessary */
    if( !preparse_real( Q ) ) {
      return preparse_uv(Q);
    }

    if( sb.lookup_svec( s ) != undef_svec ) Q.pop();

    if( sb.lookup_symbol( s ) == undef_symbol ) return true;
    Q.pop(); return false;
  }

  bool b;
  
  switch( ( ( tag_token * )t )->get() ) {
  case Boolean_Tag :
    Q.pop();
    return parse_bool( Q, b );
    break;
  case Distrib_Tag :
    if( preparse_distribution( Q ) ) return true;
    return preparse_uv(Q);
    break;
  case Int_Tag :
    Q.pop();
    if( preparse_int( Q ) ) return true;
    return preparse_uv(Q);
    break;
  case Matrix_Tag :
    Q.pop();
    if( preparse_matrix( Q ) ) return true;
    return preparse_uv(Q);
    break;
  case Ampersand_Tag :
    return preparse_pointer( Q );
    break;
  case Real_Tag :
    Q.pop();
    if( preparse_real( Q ) ) return true;
    return preparse_uv(Q);
    break;
  case Set_Tag :
    Q.pop();
    if( expect_tag( Q, L_Paren_Tag, "preparse_data" ) ) return true;
    if( preparse_set( Q ) ) return true;
    return expect_tag( Q, R_Paren_Tag, "preparse_data" );
  case Shape_Tag :
    Q.pop();
    t = Q.peek();
    if( !t || t->is_tag() ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_data -- expected filename but found " << *t 
	     << " near " << Q.pos_string() << "\n";
      }
      return true;
    }
    Q.pop();
    /* optional scale */
    if( check_tag( Q, Product_Tag ) ) return false;
    if( preparse_triple( Q ) ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_data -- error parsing scale near " << Q.pos_string()
	     << "\n";
      }
      return true;
    }
    return false;
    break;
  case String_Tag :
    Q.pop();
    t = Q.peek();
    if( !t || t->is_tag() ) return true;
    Q.pop();
    return false;
    break;
  case Symbol_Tag :
    Q.pop();
    t = Q.peek();
    if( !t || t->is_tag() ) return true;
    Q.pop();
    return false;
    break;
  case Triple_Tag :
    Q.pop();
    if( preparse_triple( Q ) ) return true;
    return preparse_uv(Q);
    break;
  case Vector_Tag :
    Q.pop();
    if( preparse_vector( Q ) ) return true;
    return preparse_uv(Q);
    break;
  default :
    dc_trace( TRACE_ERROR ) {
      cerr << "preparse_data -- invalid data type tag near " << t->pos_string() 
	   << "\n";
    }
    return true;
  }
}

/* returns true if illegal units parsed */
bool preparse_uv( token_queue &Q, 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 << "preparse_uv -- expected unit label at " << Q.pos_string() 
	   << "\n";
    }
    return bracketed;
  }

  string uname = ( ( string_token * )t )->get();
  if( !ub.preparse_units( uname ) ) {
    Q.pop();
    if( bracketed ) {
      while( 1 ) {
	t = Q.peek();
	if( !t ) break;
	token *last;
	if( *t == Product_Tag || *t == Inv_Prod_Tag ) {
	  last = Q.extract();
	  t = Q.peek();
	  if( t && !t->is_tag() ) {
	    if( ub.preparse_units( ( ( string_token * )t )->get() ) ) {
	      Q.push( last );
	      break;
	    } else { 
	      Q.push_used( last ); Q.pop(); 
	    }
	  } else {
	    Q.push( last );
	    break;
	  }
	} else break;
      }
      if( need_brackets ) {
	return expect_tag( Q, R_SqBracket_Tag, "preparse_uv" );
      } else {
	return false;
      }
    }
    return false;
  }
  
  if_trc( bracketed, TRACE_ERROR ) {
    cerr << "parse_uv -- error parsing units at " << Q.pos_string() << "\n";
  }

  return bracketed;
}

bool preparse_int( token_queue &Q ) {
  long int I;
  return preparse_int( Q, I );
}

bool preparse_int( token_queue &Q, long int &I ) {
  token *t = Q.peek();
  if( t == nil || t->is_tag() ) return true;
  string *str = &( ( string_token * )t )->get();

  char c; /* used to test if anyrhing left in string */
  int n = sscanf( *str, "%ld%c", &I, &c );
  if( n == 0 ) 
    return true;

  if( n != 1 ) {
    cerr << "preparse_real -- warning. extra characters in " << *t << " at "
	 << t->pos_string() << "\n";
  }

  Q.pop();
  return false;
}

bool preparse_real( token_queue &Q ) {
   token *t = Q.peek();
   if( t == nil || t->is_tag() ) return true;
   string *str = &( ( string_token * )t )->get();

   double d;
   char c1, c2;
   int n = sscanf( *str, "%lf%c%c", &d, &c1, &c2 );
   if( !n ) return true;

   if( n == 2 && ( c1 == 'e' || c1 == 'E' ) ) {
     token *h = Q.extract();
     t = Q.peek();
     if( t && !t->is_tag() &&
	 ( sscanf( ( ( string_token * )t )->get(), "-%lf%c", &d, &c1 ) ==1 ) ) {
       Q.push_used( *str + ( ( string_token * )t )->get(), false );
       delete( h );
       delete( Q.extract() );
       return false;
     } else {
       Q.push( h );
     }

   }

     if( n != 1 ) {
     cerr << "preparse_real -- warning. extra characters in " << *t << " at "
	  << t->pos_string() << "\n";
   }

   Q.pop();
   return false;
}

int preparse_vrow( token_queue &Q, int size ) {
  string pos = Q.pos_string();
  token *t = Q.peek();

    if( !t || *t != L_Bracket_Tag ) return -1;
  Q.pop();
  
  if( preparse_real( Q ) ) {
    return -1;
  }
  int loc = 1;
  while( loc < size ) {
    t = Q.peek();
    if( !t ) {
      return -1;
    }
    if( *t != Comma_Tag ) break;
    Q.pop();
    if( preparse_real( Q ) ) {
      return -1;
    }
  }
  
  if( loc < size ) {
    dc_trace( TRACE_WARNING ) {
      cerr << "preparse_vrow -- vector starting at " << pos << " only has " 
	   << loc << " out of " << size << " values.\n";
    }
  }
  t = Q.pop();
  if( !t || *t != R_Bracket_Tag ) {
    return -1;
  }

  return loc;
}

int preparse_vrow( token_queue &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 */
  if( preparse_real( Q ) ) return -1;
  int n = 1;

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

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

bool preparse_vector( token_queue &Q ) {
  string pos = Q.pos_string();

  token *t;
  long int size;
  t = Q.peek();
  if( !t ) return true;
  if( *t == L_Paren_Tag ) {
    Q.pop();
    /* get length */
    if( preparse_int( Q, size ) || size <= 0 ) {
      dc_trace( TRACE_WARNING ) {
	cerr << "preparse_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 << "preparse_vextor -- '}' expected near " 
	     << t->pos_string() << "\n";
      }
      return true;
    }
    if( preparse_vrow( Q, size ) < 0 ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_vector -- could not parse vector starting at " << pos
	     << " because of invlaid element list\n";
      }
      return true;
    }
  } else {
    queue<double> dbl_q;
    if( ( size = preparse_vrow( Q ) ) < 0 ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_vector -- could not parse vector starting at " << pos
	     << " because of invlaid element list\n";
      }
      return true;
    }
  }
  
  /* set vector */
  return false;
}

bool preparse_matrix( token_queue &Q ) {
  string pos = Q.pos_string();

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

  long int m, n;
  
  if( *t == L_Paren_Tag ) {
    n = m = -1;
    Q.pop();
    /* get n */
    if( preparse_int( Q, n ) || n <= 0 ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_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 << "preparse_matrix -- could not parse matrix starting at " << pos
	     << " because of interrupted size specification.\n";
      }
      return true;
    }
    /* if , get m */
    if( *t == Comma_Tag ) {
      if( preparse_int( Q, m ) || m <= 0 ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "preparse_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 << "preparse_matrix -- could not parse matrix starting at " << pos
	     << " because expected ')' after size specification.\n";
      }
      return true;
    }
    /* get values */
    if( m == -1 ) {
      int l;
      if( ( l = preparse_vrow( Q ) ) < 0 ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "preparse_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;
      if( l < area ) {
	dc_trace( TRACE_WARNING ) {
	  cerr << "preparse_matrix -- only " << l << " elements given for ( "
	       << n << " x " << m << " ) matrix starting at " << pos
	       << ". remaining elements zeroed.\n";
	}
      }
    } else {
      if( preparse_vrow( Q, m * n ) < 0 ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "preparse_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();
    do {
      int this_w;
      if( ( this_w = preparse_vrow( Q ) ) < 0 || !( t = Q.pop() ) ) {
	dc_trace( TRACE_ERROR ) {
	  cerr << "preparse_matrix -- could not parse matrix starting at " 
	       << pos << " because of invlaid element list. error near " 
	       << Q.pos_string() << "\n";
	}
	return true;
      }
      if( m < this_w ) m = this_w;

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

  } else return true;

  return false;
}

bool preparse_triple( token_queue &Q ) {
  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( preparse_real( Q ) ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "preparse_triple -- failed to parse first arg of triple near "
	   << Q.pos_string() << "\n";
    }
    return true;
  }

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

  if( !check_tag( Q, Comma_Tag ) ) {
    if( preparse_real( Q ) ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_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, "preparse_triple" ) ) {
      return true;
    }
  } else if( expect_tag( Q, R_Paren_Tag, "preparse_triple" ) ) {
    return true;
  }
  
  return false;
}

bool preparse_distribution( token_queue &Q ) {
  if( check_tag( Q, Distrib_Tag ) ) {
    return true;
  }
  
  if( expect_tag( Q, L_Paren_Tag, "preparse_distribution" ) ) {
    return true;
  }
  
  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 << "preparse_distribution -- stream ended prematurely\n";
      }
      return true;
    }
    if( !t->is_tag() ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_distribution -- parse error near " << t->pos_string() 
	     << "\n";
      }
      return true;
    }
    bool *obj_def = nil;
    switch( ( ( tag_token * )t )->get() ) {
    case Min_Tag :
      obj_def = &Min_Def;
      break;
    case Max_Tag :
      obj_def = &Max_Def;
      break;
    case Mean_Tag :
      obj_def = &Mean_Def;
      break;
    case Stddev_Tag :
      obj_def = &Stddev_Def;
      break;
    default :
      break;
    }
    if( obj_def == nil ) {
      break;
    }
    Q.pop();
    if( expect_tag( Q, Equal_Tag, "preparse_distribution" ) ) {
      return true;
    }
    if( preparse_real( Q ) ) {
      dc_trace( TRACE_ERROR ) {
	cerr << "preparse_distribution -- parse error near " << Q.pos_string() 
	     << "\n";
      }
      return true;
    }
    *obj_def = true;
  } while( !check_tag( Q, Comma_Tag ) );
  
  if( expect_tag( Q, R_Paren_Tag, "preparse_distribution" ) ) return true;
  
  /* 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 << "preparse_distribution -- Insufficient args near " << Q.pos_string()
	 << "\n";
    }
    return true;
  }

  return false;
}

bool preparse_pointer( token_queue &Q ) {
  if( expect_tag( Q, Ampersand_Tag, "preparse_pointer" ) ) return true;
  string path;
  return expect_path( Q, path, "preparse_pointer" );
}

bool ppf_is_op( token_queue &Q ) {
  token *t = Q.peek();
  if( t == nil ) { 
    return false;
  }

  if( !t->is_tag() ) {
    /* check for leading '-' */
    string *s = &( ( string_token * )t )->get();
    if( s->pos( parse_lbl[Neg_Sum_Tag] ) == 0 ) {
      *s = ( *s )( 1, s->length() - 1 );
      Q.push( Neg_Sum_Tag );
      return true;
    } 
    return false;
  }
  parseTag pT = ( ( tag_token * )t )->get();
  
  return is_fn_of_type( pT, OP );
}

bool preparse_function( token_queue &Q, dc_label *owner, bool first = false ) {
  if( !first )
    if( preparse_arg( Q, owner ) ) return true;

  token *t = Q.peek();
  /* rule out possibility of implicit unit post cast */
  if( !t || *t != L_SqBracket_Tag ) {  
    if( !ppf_is_op( Q ) ) 
      return false;

    Q.pop();
  }
  
  while( 1 ) {
    if( preparse_arg( Q, owner ) ) {
      return true;
    }

    t = Q.peek();
    /* rule out possibility of implicit unit post cast */
    if( !t || *t != L_SqBracket_Tag ) {
      if( !ppf_is_op( Q ) ) {
	return false;
      }
      
      Q.pop();
    }
  }
}
