/* parser.h */

#ifndef PARSER__H
#define PARSER__H

#include <LEDA/basic.h>
#include <LEDA/dictionary.h>
#include <LEDA/slist.h>
#include <LEDA/stack.h>
#include <LEDA/queue.h>
#include "component.h"
#include "data_classes.h"
#include "element.h"
#include "function.h"
#include "set.h"
#include "link.h"
#include "coriolis/kernel.h"
#include "modification.h"

/* #define PARSER_CASE_SENSITIVE */

enum parseTag { Invalid_Tag = -1,
		/* main class types */
		Component_Tag = 0, Element_Tag, Constraint_Tag,
		/* data class types */
		Boolean_Tag, Int_Tag, Matrix_Tag, Pointer_Tag, Real_Tag, 
		Distrib_Tag, Triple_Tag, Vector_Tag, Symbol_Tag, String_Tag,
		Enum_Tag, Clock_Tag, Self_Tag, Time_Tag, Delta_Time_Tag,
		/* element/data flags */
		Old_Tag, Transparent_Tag, Nil_Tag, True_Tag, False_Tag,
		Dormant_Tag, Frozen_Tag,
		/* misc */
		L_Bracket_Tag, R_Bracket_Tag, L_SqBracket_Tag, R_SqBracket_Tag,
		Semicolon_Tag, L_Paren_Tag, R_Paren_Tag, Comma_Tag, 
		Quote_Tag, Colon_Tag, Ampersand_Tag,
		Open_Comment_Tag, Close_Comment_Tag, Line_Comment_Tag,
		Default_Tag, Descendent_Tag, Include_Tag, Member_Tag,
		Of_Tag, Set_Tag, Inherited_Tag, Local_Tag, Query_Tag, Over_Tag,
		Stddev_Tag, Type_Tag, All_Tag, None_Tag ,
		Exception_Tag, Implies_Tag, Define_Tag, Key_Tag, Shape_Tag,
		Link_Tag, Dir_Link_Tag, Distance_Tag, Attachment_Tag, Axial_Tag,
		Force_Tag,
		For_Tag,
		Modify_Tag,
		Cast_Tag,

		/* ga tags */
		GA_Tag, NNet_Tag, Optimizer_Tag,
		Sigmoid_Tag, Linear_Tag,
		Input_Tag, Output_Tag,

		/* operators -- arranged in order from high priority to low */
		FN_START,
		Pow_Tag, Modulus_Tag, Inv_Prod_Tag,
		Int_Div_Tag, Product_Tag, Neg_Sum_Tag, 
		Sum_Tag, Not_Tag, Equality_Tag,
		Not_Equal_Tag, LessThan_Tag, GreaterThan_Tag,
		LessEqual_Tag, GreaterEqual_Tag,
		Log_And_Tag, Log_Or_Tag, Equal_Tag,
		/* functions */
		FSum_Tag, FProduct_Tag, FDot_Prod_Tag, FNot_Tag,
		FMagnitude_Tag, FConditional_Tag,
		FSin_Tag, FCos_Tag, FTan_Tag,
		FArcsin_Tag, FArccos_Tag, FArctan_Tag,
		FArctan2_Tag, FHypot_Tag,
		Min_Tag, Max_Tag, Mean_Tag, FGDistrib_Tag, FGVec_Tag,
		FCount_Tag, FPoly_Tag, FRMS_Tag,
		FExp_Tag, FExpm1_Tag, FLog_Tag, FLog1p_Tag,
		FLog10_Tag, FPow_Tag, FSqrt_Tag, FCbrt_Tag,
		FCeil_Tag, FFloor_Tag, FRound_Tag,
		FDistMin_Tag, FDistMax_Tag, FDistMean_Tag,
		FDistStddev_Tag, FDistSample_Tag, FN_END };

const int ntg = FN_END; /* number of tags */

/* constant tags.  parseTags are direct indices into this array */
const char *const parse_lbl[ntg] = { "component", "element", "constraint",
				     "boolean", "int", "matrix", "pointer", 
				     "real", "distrib", "triple", "vector", 
				     "symbol", "string", "enum", "clock", 
				     "self",
				     "time", "delta_time",
				     "old", "transparent", "<nil>", 
				     "true", "false",
				     "dormant", "frozen",
				     "{", "}", "[", "]", ";",
				     "(", ")", ",", "\"", ":", "&",
				     "/*", "*/", "//",
				     "default", "desc",
				     "#include", "member", "of", "set",
				     "inherited", "local", "query",
				     "over", "stddev",
				     "type", "all", "none", "except", "implies",
				     "define", "key", "shape",
				     "link", "->",
				     "dist", "attachment", "axial", "force",
				     "for", "modify", "cast",

				     "ga", "nnet", "optimizer", 
				     "sigmoid", "linear",
				     "input", "output",
				     
				     nil,
				     "^", "%", "/", "\\", "*", "-", "+", "!",
				     "==", "!=", "<", ">", "<=", ">=",
				     "&&", "||", "=",
				     "sum", "product", "dot", "not", "mag", 
				     "if", "sin", "cos", "tan", "asin", "acos",
				     "atan", "atan2", "hypot", "min", "max",
				     "mean", "gdistrib", "gvec", "count", 
				     "poly", "rms",
				     "exp", "expm1", "log", "log1p", "log10",
				     "pow", "sqrt", "cbrt", 
				     "ceil", "floor", "round",
				     "get_min", "get_max", "get_mean",
				     "get_stddev", "sample" };

struct synonym {
  const char *const syn_string;
  const parseTag pT;
  synonym( const char *const Syn_String, const parseTag PT ) :
    syn_string( Syn_String ), pT( PT ) {}
};

const int nsyms = 15;
const synonym syn_list[nsyms] = { synonym( "typical", Mean_Tag ),
				  synonym( "avg", Mean_Tag ),
				  synonym( "distribution", Distrib_Tag ),
				  synonym( "system", Component_Tag ),
				  synonym( "hierarchy", Component_Tag ),
				  synonym( "get_typical", FDistMean_Tag ),
				  synonym( "get_avg", FDistMean_Tag ),
				  synonym( "arcsin", FArcsin_Tag ),
				  synonym( "arccos", FArccos_Tag ),
				  synonym( "arctan", FArctan_Tag ),
				  synonym( "arctan2", FArctan2_Tag ),
				  synonym( "magnitude", FMagnitude_Tag ),
				  synonym( "bool", Boolean_Tag ),
				  synonym( "integer", Int_Tag ),
				  synonym( "this", Self_Tag ) };

/* op tags must be in block of length nops starting at index op_start */
const int nfns = FN_END - FN_START - 1; /* number of operators defined 
					   for use in functions */

/* punctuation strings returned as strings regardless of whitespace.
   all other strings/tags must be seperated by whitespace. must be ordered
   from longest to shortest. Neg_Sum_Tag included, but must be handled 
   seperately since -.3 should be one string. */
const int npunc = 32;
const parseTag punc_s[npunc] = { Comma_Tag, L_Paren_Tag, R_Paren_Tag,
				 Semicolon_Tag, L_SqBracket_Tag,
				 R_SqBracket_Tag, L_Bracket_Tag,
				 R_Bracket_Tag, Colon_Tag, Open_Comment_Tag,
				 Close_Comment_Tag, Line_Comment_Tag, Nil_Tag,
				 Equality_Tag, Not_Equal_Tag, LessEqual_Tag, 
				 GreaterEqual_Tag, Log_And_Tag, Log_Or_Tag,
				 Dir_Link_Tag,
				 Pow_Tag, Product_Tag, Inv_Prod_Tag, 
				 Int_Div_Tag, Sum_Tag, Neg_Sum_Tag, Modulus_Tag,
				 Not_Tag, LessThan_Tag, GreaterThan_Tag,
				 Equal_Tag, Ampersand_Tag };

/* UNARY_OPs take one arg and appear before their arg.
      UNARY_OP arg.
   OPS take any number of args each separated by the OP.
      arg1 OP arg2 OP ... OP argn-1 OP argn.
   U_OPs can be either a UNARY_OP or a normal OP depending on whether they
      precede a single argument or seperate two or more arguments.
      U_OP arg, or arg1 U_OP arg2 U_OP ... U_OP argn-1 U_OP argn.
   FUNCs take any number of ARGS in parens after the FUNC, separated by commas.
      FUNC( arg1, arg2, ... , argn-1, argn ) */
enum fntype { UNARY_OP, U_OP, OP, FUNC };

struct fn_info {
  const parseTag pT;
  const fn op;
  const t_fn t_op;
  const set_t_fn st_op;
  const fntype type;
  fn_info( const parseTag PT, const fn OP, const t_fn T_OP, 
	   const set_t_fn ST_OP, const fntype TYPE ) :
    pT( PT ), op( OP ), t_op( T_OP ), st_op( ST_OP ), type( TYPE ) {}
};

/* all tags in table must be between FN_START and FN_END */
const fn_info fn_list[nfns] = 
{ fn_info( Pow_Tag,          Pow,           t_2rl,        st_fail,    OP      ),
  fn_info( Modulus_Tag,      mod,           t_mod,        st_fail,    OP      ),
  fn_info( Inv_Prod_Tag,     inv_prod,      t_inv_prod,   st_fail,    OP      ),
  fn_info( Int_Div_Tag,      int_div,       t_int_div,    st_fail,    OP      ),
  fn_info( Product_Tag,      product,       t_prod,       st_fail,    OP      ),
  fn_info( Neg_Sum_Tag,      neg_sum,       t_same,       st_fail,    U_OP    ),
  fn_info( Sum_Tag,          sum,           t_sum,        st_fail,    OP      ),
  fn_info( Not_Tag,          not,           t_not,        st_fail,    UNARY_OP),
  fn_info( Equality_Tag,     equal,         t_equal,      st_fail,    OP      ),
  fn_info( Not_Equal_Tag,    not_equal,     t_equal,      st_fail,    OP      ),
  fn_info( LessThan_Tag,     less_than,     t_comp,       st_fail,    OP      ),
  fn_info( GreaterThan_Tag,  greater_than,  t_comp,       st_fail,    OP      ),
  fn_info( LessEqual_Tag,    less_equal,    t_comp,       st_fail,    OP      ),
  fn_info( GreaterEqual_Tag, greater_equal, t_comp,       st_fail,    OP      ),
  fn_info( Log_And_Tag,      and,           t_andor,      st_fail,    OP      ),
  fn_info( Log_Or_Tag,       or,            t_andor,      st_fail,    OP      ),
  fn_info( Equal_Tag,        assignment,    t_assignment, st_fail,    OP      ),
  fn_info( FSum_Tag,         sum,           t_sum,        st_sum,     FUNC    ),
  fn_info( FProduct_Tag,     product,       t_prod,       st_prod,    FUNC    ),
  fn_info( FDot_Prod_Tag,    dot_product,   t_dot_prod,   st_fail,    FUNC    ),
  fn_info( FNot_Tag,         not,           t_not,        st_fail,    FUNC    ),
  fn_info( FMagnitude_Tag,   magnitude,     t_mag,        st_fail,    FUNC    ),
  fn_info( FConditional_Tag, conditional,   t_cond,       st_fail,    FUNC    ),
  fn_info( FSin_Tag,         Sin,           t_rl,         st_fail,    FUNC    ),
  fn_info( FCos_Tag,         Cos,           t_rl,         st_fail,    FUNC    ),
  fn_info( FTan_Tag,         Tan,           t_rl,         st_fail,    FUNC    ),
  fn_info( FArcsin_Tag,      Asin,          t_rl,         st_fail,    FUNC    ),
  fn_info( FArccos_Tag,      Acos,          t_rl,         st_fail,    FUNC    ),
  fn_info( FArctan_Tag,      Atan,          t_rl,         st_fail,    FUNC    ),
  fn_info( FArctan2_Tag,     Atan2,         t_2rl,        st_fail,    FUNC    ),
  fn_info( FHypot_Tag,       Hypot,         t_2rl,        st_fail,    FUNC    ),
  fn_info( Min_Tag,          Min,           t_mnmx,       st_mnmx,    FUNC    ),
  fn_info( Max_Tag,          Max,           t_mnmx,       st_mnmx,    FUNC    ),
  fn_info( Mean_Tag,         mean,          t_sclr2rl,    st_sclr2rl, FUNC    ),
  fn_info( FGDistrib_Tag,    gdistrib,      t_gdistrib,   st_fail,    FUNC    ),
  fn_info( FGVec_Tag,        gvec,          t_gvec,       st_fail,    FUNC    ),
  fn_info( FCount_Tag,       count,         t_int,        st_int,     FUNC    ),
  fn_info( FPoly_Tag,        poly,          t_sclr2rl,    st_fail,    FUNC    ),
  fn_info( FRMS_Tag,         rms,           t_sclr2rl,    st_fail,    FUNC    ),
  fn_info( FExp_Tag,         Exp,           t_rl,         st_fail,    FUNC    ),
  fn_info( FExpm1_Tag,       Expm1,         t_rl,         st_fail,    FUNC    ),
  fn_info( FLog_Tag,         Log,           t_rl,         st_fail,    FUNC    ),
  fn_info( FLog1p_Tag,       Log1p,         t_rl,         st_fail,    FUNC    ),
  fn_info( FLog10_Tag,       Log10,         t_rl,         st_fail,    FUNC    ),
  fn_info( FPow_Tag,         Pow,           t_2rl,        st_fail,    FUNC    ),
  fn_info( FSqrt_Tag,        Sqrt,          t_rl,         st_fail,    FUNC    ),
  fn_info( FCbrt_Tag,        Cbrt,          t_rl,         st_fail,    FUNC    ),
  fn_info( FCeil_Tag,        Ceil,          t_rl2int,     st_fail,    FUNC    ),
  fn_info( FFloor_Tag,       Floor,         t_rl2int,     st_fail,    FUNC    ),
  fn_info( FRound_Tag,       Round,         t_rl2int,     st_fail,    FUNC    ),
  fn_info( FDistMin_Tag,     dist_min,      t_distop,     st_fail,    FUNC    ),
  fn_info( FDistMax_Tag,     dist_max,      t_distop,     st_fail,    FUNC    ),
  fn_info( FDistMean_Tag,    dist_mean,     t_distop,     st_fail,    FUNC    ),
  fn_info( FDistStddev_Tag,  dist_stddev,   t_distop,     st_fail,    FUNC    ),
  fn_info( FDistSample_Tag,  dist_sample,   t_distop,     st_fail,    FUNC    )
};

class token { 
protected:
  int char_num;
  int line_num;
  string filename;
public:
  virtual const bool is_tag( void ) const = 0; 
  virtual bool operator==( cstring ) const { return false; }
  virtual bool operator==( const parseTag ) const { return false; }
  bool operator!=( cstring s ) const { return !( *this == s ); }
  bool operator!=( parseTag p ) const { return !( *this == p ); }

  int cnum() const { return char_num; }
  int lnum() const { return line_num; }
  string fname() const { return filename; }
  string pos_string() const;

  friend ostream &operator<<( ostream &stream, const token &t );
};

class tag_token : public token { 
private: 
  parseTag P;
public: 
  tag_token( parseTag p, int cn = -1, int ln = -1, string fn = "" ) 
    { P = p; char_num = cn; line_num = ln; filename = fn; }
  const bool is_tag( void ) const { return true; } 
  bool operator==( const parseTag p ) const { return ( p == P ); }
  parseTag get( void ) const { return P; }
};

class string_token : public token {
private: 
  string S;
  //  bool quoted; /* true iff string contained in quotation marks which were
  //                  removed */
public: 
  string_token( string s, bool, int cn = -1, int ln = -1, string fn = "" )
    { S = s; char_num = cn; line_num = ln; filename = fn; /*quoted = q;*/ }
  const bool is_tag( void ) const { return false; }
  //  const bool is_quoted( void ) const { return quoted; }
  bool operator==( cstring s ) const { return ( S == s ); }
  string &get( void ) { return S; }
};

enum stream_status { STR_GOOD, STR_EMPTY, STR_BREAK };
class stream_state {
  istream *stream;
  bool owned;

  int char_num;
  int char_in_line;
  int line_num;
  string filename;
  tag previous_tag;

  bool valid; /* true if stream is valid */
public:
  stream_state( istream & );
  stream_state( string );
  ~stream_state( void );

  stream_status pop( string & ); /* returns status of stream and next string */
  void putback( char c ) { stream->putback( c ); }
  int get_char_pos( void ) { return char_num; }
  int get_char_in_line( void ) { return char_in_line; }
  int get_line_num( void ) { return line_num; }
  string get_filename( void ) { return filename; }
  string pos_string( void ); /* <file "%s":line %d char %d> */
  tag get_previous_tag( void ) { return previous_tag; }
  void set_previous_tag( tag );

  bool remove_space( void );

  bool is_valid() { return valid; }
};

extern bool flush_on_death;

class token_queue {
private:
  slist< token * >Q;
  queue< token * >waitQ;

  slist< token * >used_Q;

  int token_num;
  stack<stream_state *> state_stack;
  stream_state *c_state;

  bool get_token( void ); /* token added to queue */
  bool decompose_string( void ); /* returns true if end of file reached.
				    if return value is true then string may
				    or may not be empty. */

  bool openfile( string filename );
  bool closefile( void ); /* returns true if no files left */
public:
  token_queue( string filename );
  token_queue( istream & );
  ~token_queue( void ); /* does not close stream */
  token *pop( void ); /* removes and returns top of Q and pushes onto used_Q */
  token *peek( void ); /* peeks at top of Q */
  token *extract( void ); /* reomoves and returns top of Q 
			     without pushing onto used_Q */
  /* next 3 fns push a token onto front of Q */
  /* do not push zero length strings onto queue */
  /* for first two, new token assumes file position of head of Q */
  void push( cstring, bool );
  void push( const parseTag );
  void push( token * );

  /* next 3 fns push a token onto tail of used_Q */
  /* do not push zero length strings onto queue */
  /* for first two, new token assumes file position of head of Q */
  void push_used( cstring, bool );
  void push_used( const parseTag );
  void push_used( token * );

  void rewind( void );
  void clear( void );
  void flush( void );
  
  int token_number( void ) { return token_num; }

  void flush_out( void ); /* parses until stream empty, dumps to stderr */
  int char_pos( void ) { return c_state->get_char_pos(); }
  int char_in_line( void ) { return c_state->get_char_in_line(); }
  int line_num( void ) { return c_state->get_line_num(); }
  string filename( void ) { return c_state->get_filename(); }
  tag get_previous_tag( void ) { return c_state->get_previous_tag(); }
  void set_previous_tag( tag T ) { c_state->set_previous_tag( T ); }
  string pos_string( void );
};

/* must be called before any parsing done */
void init_parse( void );

dc_label *restricted_lookup( string label, dc_node *parent );

/* returns number of objects parsed at parent */
int parse( istream &stream, dc_component *parent = nil );
int parse( string filename, dc_component *parent = nil );
int parse( token_queue &, dc_component *parent = nil );

/* all return true or nil on error */
bool parse_component( token_queue &, dc_component * );
bool parse_element( token_queue &, dc_component * );
dc_func *parse_function( token_queue &, dc_label *owner, dc_label *search_origin
		       , dc_func * = nil );
dc_link *parse_link( token_queue &, dc_label *owner );
bool parse_clock( token_queue &, dc_label *owner );
bool parse_ga( token_queue &, dc_node *parent );

bool parse_modify( token_queue &, dc_node *parent );

/* simplifies and checks type of function. will not attempt to cast if type is
   Data_t */
dc_func *fn_postparse( dc_func */*, dc_type*/ );
dc_data *parse_data( token_queue &, dc_label *owner,
		     dc_label *search_origin = nil/*, dc_type = Data_t*/ );

bool parse_bool( token_queue &, bool & );
bool parse_int( token_queue &, long int & );
bool parse_real( token_queue &, double & );
bool parse_vector( token_queue &, ColumnVector & );
bool parse_matrix( token_queue &, Matrix & );
bool parse_triple( token_queue &, ColumnVector & );
bool parse_triple( token_queue &, triple & );
dc_pointer *parse_pointer( token_queue &, dc_label * );
bool parse_quaternion( token_queue &, quaternion & );
bool parse_string( token_queue &, string & );
bool parse_symbol( token_queue &, dc_symbol_tag &, dc_svec_tag & );
bool parse_svec( token_queue &, dc_svec_tag & );
dc_distrib *parse_distribution( token_queue & );

bool parse_block( token_queue &, dc_component * );

enum uv_result { uv_fail = 0, uv_none, uv_pass };
uv_result parse_uv( token_queue &, dc_udata *, const bool = true );

bool pass_default( token_queue & );

dc_link_type parse_link_type( token_queue & );

bool valid_label( cstring );
bool valid_label( token *t );
bool valid_path( cstring );
bool valid_path( token *t );

/* dequote removes leading and trailing quotes if any from string. 
   true if string was surrounded by double quotes ( '\"' ) */
bool dequote( string & );

bool quoted( cstring ); /* true iff string is surrounded by double quotes */

/* if tag matches pt removes it and returns false */
bool check_tag( token_queue &Q, const parseTag pt ); 
/* returns true and prints warning if removed token does not match pt */
bool expect_tag( token_queue &Q, const parseTag pt, 
		 const char *fname = "parser" );
/* returns true if next token is not a valid label.
   if next token is a valid label, it removes it from Q and stores in label */
bool check_label( token_queue &Q, string &label );
/* paths are same as labels, except that non-adjacent '.'s are allowed */
bool check_path( token_queue &Q, string &path );
/* expect_path/label fns are same as check_label/function except that an error
   message is automatically printed when true is returned and token is popped
   regardless of whether or not it is a legal path/label */
bool expect_label( token_queue &Q, string &label, 
		   const char *fname = "parser" );
bool expect_path( token_queue &Q, string &path, 
		  const char *fname = "parser" );

/* defined new type if necessary */
//bool parse_type( token_queue &Q, user_type &, bool & );
bool parse_utypes( token_queue &Q, dc_component &target );
bool parse_typedef( token_queue &Q );

dc_finite_set *parse_finite_set( token_queue &Q, dc_label *owner, 
				 dc_label *search_origin );
dc_set *parse_set( token_queue &Q, dc_label *owner, dc_label *search_origin );

/* true on error */
bool parse_arg( token_queue &, dc_func *&, dc_label *owner, 
		dc_label *search_origin );

/* if top of Q is a tag corresponding to an op then it returns true.  else if
   top of Q starts with '-' then it removes - from string, pushes Neg_Sum_Tag
   onto Q, and returns true.  otherwise returns false. */
bool is_fn_of_type( const parseTag pT, const fntype );
/* maps parseTg's to ops of form dc_data &fn( f_list &args ) */
bool get_fn_of_type( const parseTag pT, int &index, const fntype );

/* returns dc_type Reak_t, Int_t, ... corresponding to Real_Tag, Int_Tag, ... .
   Undef_t if no match */
dc_type get_dtype( const parseTag pT );

/* true on error -- called by parse */
bool preparse( token_queue &Q, dc_component *parent, slist<dc_label *> & );

/* la_stack -- stack of local args
   searched by parse_arg for label match before trying to match label to
   hierarchy. tries to match most recently pushed first
   in parse_element, elements push their args onto stack before parsing arg
   default_value functions or evaluation functions
   iteration loops also use args */
extern inline void la_stack_pop( int n ); /* pops n from stack */
extern inline void la_stack_push( dc_arg & );
extern inline dc_arg *la_stack_match( cstring ); /* nil on no match */

#endif

/* PARSING GRAMMAR
   parse_block  <- <component> [<parse_block>]
                 | <element> [<parse_block>]
		 | <global_def> [<parse_block>]
		 | <clock> [<parse_block>]
		 | <modify> [<parse_block>]
		 | <ga> [<parse_block>]
   
   label        <- <alphabet_character>|'_' [<label2>]
   label2       <- <alphanumeric_character>|'_' [<label2>]

   component    <- 'component' <label> [':' <template_label>] 
                   '{' [type <utypes>] [<parse_block>|<status_change>] '}'

		// constraints must be of type bool.  
		// transparent means that sets should exlude this element
   element      <- ['transparent'] [<dtag>|<symbolic_type>]
                   [['element'|'constraint'] <label>['('<args>')']'=']
		   <function>|'<nil>'[':'<data>][','<e_clocks>]';'	  
   dtag         <- 'bool' | 'int' | 'matrix' | 'real' | 'triple' | 'vector'

   args         <- [<dtag>] <label> ['=' <function>][',' <args>]

                //         main clock  secondary clocks
   e_clocks     <- 'clock' <label>[',' <label_list>]

   function     <- <arg> [<op_tag> <function>]
   arg          <- '('<function')'
                 | '('<dtag>')'<arg>
		 | '[' 'cast' <unit> ']'
		 | <unary_op> <arg>
                 | <data>
                 | <data path>
	         | <element path>
	         | 'old' <element path>
	         | 'self'
	         | 'fcall'
		 | 'iter_loop'
   fcall        <- <func_tag> '(' <f_list> ')'
	         | <func_tag> '(' <set> [<exception>] ')'
		 | <label> '(' <arg_lbl_list> ')'
   arg_lbl_list <- [<label>'='] <function>[','<arg_lbl_list>]   
   f_list       <- <function1>
                 | <function1> ',' <f_list>
   iter_loop    <- 'for''(' <label>',' (<set>|<label>) ')''{' <function> '}'

   op_tag       <- ( see op_tag_list )
   func_tag     <- ( see func_tag_list )

   data         <- ['bool'] 'true'|'false'
                 | ['int'] <int> [<units>]
		 | <distribution> [<units>]
	         | 'matrix' <matrix> [<units>]
		 | '&'<path>
	         | ['real'] <real> [<units>]
		 | 'set''('<set>'}'
		 | 'shape' <filename> ['*' <triple>]
		 | 'string' ['"']<string>['"']
		 | '"'<string>'"'
		 | ['symbol'] <symbol_name>
	         | 'triple' <triple> [<units>]
	         | 'vector' <vector> [<units>]
   triple       <- '('<real>','<real>[','<real>]')'
		 | '{'<real>','<real>[','<real>]'}'
   quaternion   <- '('<real>','<real>','<real>','<real>')'
		 | '{'<real>','<real>','<real>','<real>'}'
   vector       <- <vrow>
                 | '(' <int> ')' <vrow>
   matrix       <- '(' <int> ')' '<vrow>                 ( w ) { elements }
                 | '(' <int> ',' <int> ')' <vrow>        ( h, w ) { elements }
	         | '{' <vrow_list> '}'
   vrow         <- '{' <real_list> '}'
   vrow_list    <- <vrow> [',' <vrow_list>]
   real_list    <- <real> [',' <real_list>]

   // distribution requires two of ( min, max, mean ) or both mean & stddev
   distribution <- 'distrib' '(' <distarg_list ')'
   distarg_list <- ('min'|'max'|'mean'|'avg'|'typical'|'stddev') '=' <real>
                   [',' <distarg_list>]

   utypes       <- <utype>[',' <utypes>]
   utype        <- [( 'inherited' | 'local' )] <type_name>
   user_type    <- 'type' <type_name>';'

   // an elements main clock is specified in the element def.  if an element is
   // specified in a clock's set it is a secondary clock for that element
   clock        <- 'clock' <label> [':' <set>]';'

   modify       <- 'modify' ['component'] <label> [':' <template_label>] 
                   '{' <types> <parse_block> '}'

   set          <- <set_list> ['except' <fset_list>]
   fset_list    <- <finite_set> ['&' <fset_list>]
   finite_set   <- 'key' <pattern> [ 'of'|',' <set_specs> ]
                 | 'type' <type_name> ['of'|',' <set_specs>]
		 | 'desc' ['of'] <label> ['of'|',' <set_specs>]
		 | 'set' '(' <label_list> ')'
		 | 'self'
   set_specs    <- ( ('desc' ['of'])|'of' )<label> ['of'|',' <set_specs>]
                 | 'key' ['of'] <pattern> ['of'|',' <set_specs>]
                 | 'type' <type_name> ['of'|',' <set_specs>]

   global_def   <- <default_def>
                 | <type_def>
		 | <enum_def>
		 | <symbol_def>
		 | <link_def>

   default_def  <- 'default' [<dtag>] <label> '=' <data>';'
   type_def     <- 'define' <user_type> ['implies' <type_list>]';'
   type_list    <- <type_name> [',' <type_list>]';'
   enum_def     <- 'enum' <symbolic_type_label> '{' <label_list> '}'';'
   symbol_def   <- 'define' 'symbol' <label>';'
   link_def     <- 'link' <label> ['->'|',' <label>][':'<link_specs>]';'
   link_specs   <- attachment
                 //       src_pt      tgt_pt      distance
                 | 'dist' <triple>',' <triple>',' <real>


		 //        src_pt1    src_pt2    tgt_pt1    tgt_pt2
		 | 'axial' <triple>','<triple>','<triple>','<triple>

		 //        force        src_pt     tgt_pt
		 | 'force' <function>','<function>'[,'<function>]

   label_list   <- <label> [',' <label>]

   status_change<- 'frozen' '=' ('true'|'false')';'
                 | 'dormant' '=' ('true'|'false')';'


   ga           <- 'ga' 'optimizer' <label> '(' <function> ')' '{'
                   <ga_contents> '}'
   ga_contents  <- <parse_block>
                 | 'pcrossover'  '=' <real> ';'
                 | 'pmut'        '=' <real> ';'
                 | 'mutvar'      '=' <real> ';'
                 | 'timestep'    '=' <real> ';'
                 | 'intaccuracy' '=' <real> ';'
                 | 'ngens'       '=' <int> ';'
		 | 'input' <ga_input> ';'
   ga_input     <- ['real'] <path> '(' 'min' '=' <real> ',' 'max' '=' <real> ','
                                       'nbits' '=' <int> ')'
                 | ['real'] <path> '(' 'min' '=' <real> ',' 'max' '=' <real> ','
		                       'resolution' '=' <real> ')'
                 | 'int'  <path> '(' 'min' '='<int> ',' 'max' '=' <int> ')'
		 | 'bool' <path> ';'

   fnodeType    <- 'sin' | 'cos' | 'sigmoid' | 'linear'
   input_block  <- 'real' '(' ['min''=']<real> ',' ['max''=']<real> ','
                              ['nbits''=']<int> ')'
                 | 'integer' '(' ['min''=']<real> ',' ['max''=']<real> ')'
		 | 'index' '(' ['base''=']<set> ')'
 */

/* TODO
   default matrix inertia = matrix ( 3, 3 ) { 1,0,0,0,1,0,0,0,1 };
   
   component C { matrix inertia [ 2, 1 ] = 10 }
   => C.inertia = ( 3, 3 ) { 1,0,0,0,1,0,0,10,1 }
   */

/* check defined */
/* check initial */
