/******************************************************
 *      transform.c: Lambda Beta to Ada compiler
 ******************************************************/
/***********************************
   (C) Copyright 1992-1993; dit/upm
   Distributed under the conditions stated in the
   TOPO General Public License (see file LICENSE)
 ***********************************
 $Log: transform.c,v $
 * Revision 2.11  1994/01/10  09:24:30  lotos
 * removed unused function mk_value_list
 *
 * Revision 2.10  1993/12/03  15:29:39  lotos
 * Corregido error en el bitmap de nodos (campo value1)
 * uando hay anotacion asociada a operador masivo.
 * Eliminada la duplicacion de anotationes
 * en caso de operadores masivos.
 *
 * Revision 2.9  1993/11/08  17:10:49  lotos
 * corregido error en busqueda de declaraciones de variables para
 *   procesos ligeros en construcction
 *   ENABLING. Ahora se comprueba que existe ACCEPT.
 * En el nodo call se anyaden las purtas y variables
 *   declaradas en el momento de instanciar el proceso ligero
 * Corregido erro en busqueda de declaraciones (puertas y
 *   variables). Ahora se empieza a buscar por el padre, no por
 *   el mismo nodo.
 *
 * Revision 2.8  1993/09/07  15:05:03  lotos
 * adapted to ILshare & SLshare & INTnth (get_gte replaced)
 * casting fixed: everything is INTlist rather than CDL_TYPE
 *
 * Revision 2.7  1993/07/08  16:01:24  lotos
 * no rag call, when transformation option is ON
 * bug fixed: light coroutines parameters
 *
 * Revision 2.6  1993/07/06  15:12:32  lotos
 * bug fixing
 *
 * Revision 2.5  1993/06/28  18:29:35  lotos
 * add father to _gate_domain_list
 * default in gate declaration collecting
 * light coroutines have vars and gates (new)
 *
 * Revision 2.4  1993/06/23  18:50:41  lotos
 * corrected max_var calculation.
 * fix unique names generation
 *
 * Revision 2.3  1993/06/16  14:11:11  lotos
 * colours c_light y c_from become public
 * remove option -i
 * add #line (and option -l to inhibit it)
 * transformation phase becomes independent: no global variables
 * data names pay attention to annotation CALL
 *
 * Revision 2.2  1993/01/18  18:14:46  lotos
 * distribution issues
 *
 * Revision 2.1  1992/11/17  17:37:29  lotos
 * variables are compacted per sort
 * split generated code into several files
 * generates *.hh
 * admit option to change basename
 * adapted to use c_cui's
 * modify sort tables
 * code generation is more rational (needs further polishing ...)
 * adapted to new data type conventions
 * adopt new naming convention
 * include var declaration list in light BUTs
 *
 * Revision 1.2  1992/11/17  17:14:02  lotos
 * Treatment of choice on variables
 *
 * Revision 1.1  1992/09/02  16:58:07  lotos
 * Initial revision
 *
 ***********************************/

#ifndef lint
static char rcsid[]= "$Id: transform.c,v 2.11 1994/01/10 09:24:30 lotos Exp lotos $";
#endif

# include "counter.h"
# include "swbus.h"

#define initgl    myGL->size = 0
#define putgrn(n) (void)ITadd (n, myGL)

/* KJT 11/03/98: added for NS/OS */

#ifdef __NeXT__
char *strdup(s) register char *s; {
 
  register char *ns;
 
  return(((ns=malloc(strlen(s)+1))==0)?0:strcpy(ns,s)); }
#endif

PRIVATE IT    *myGL;
PRIVATE TNODE *myLBMroot;
PRIVATE AT    *myATable;
PRIVATE ST    *mySymbolTable;
PRIVATE int   mylastBUTnumber;
PRIVATE IAT   *mygrnl;

PRIVATE TNODE*
do_node (type, class)
  int type, class;
{
  TNODE *anode = NULL;

  anode = new_node (type);
  anode->value0 = (CLR_TYPE)IAT_IT_add (myGL, mygrnl);   /* grn */
  anode->value1 = (CLR_TYPE)class;                       /* class */
  return anode;
}

PRIVATE void
insert_but_def (nb)
  TNODE *nb;
{
  TNODE *r;

  if ((int)myLBMroot->value1 & 1)
                  /* myLBMroot has annotations as its first son */
    r = myLBMroot->sons->brothers;
  else
    r = myLBMroot->sons;
  assert (r->type == tBUT_definition_list);
  r = gt_ls (r);     /* Now, r is the last BUT_definition */
  assert (r->type == tBUT_definition);
  r->brothers = nb; /* Insert nb as the new BUT_definition in the list */
  nb->father = r->father; /* nb needs to know who is its father */
}

PRIVATE TNODE*
mk_var_domain_list (domains)
  TNODE *domains;
{
  TNODE *aux = NULL;

  initgl;
  putgrn (_var_domain_list_1);                   /* grnl for this node */
  aux = do_node (tvar_domain_list, 1);
  aux->sons = domains;
  for (; domains != NULL; domains = domains->brothers)
    domains->father = aux;
  return aux;
}

PRIVATE TNODE*
mk_gate_domain_list (domains)
  TNODE *domains;
{
  TNODE   *aux = NULL;

  initgl;
  putgrn (_gate_domain_list_1);                  /* grnl for this node */
  aux = do_node (tgate_domain_list, 1);
  aux->sons = domains;
  for (; domains != NULL; domains = domains->brothers)
    domains->father = aux;
  return aux;
}

PRIVATE TNODE*
mk_relabel (gte_decl, gte_list, state)
  INTlist gte_decl;
  INTlist gte_list;
  TNODE *state;
{
  TNODE *aux = NULL;
  INTlist gte_ed = NULL;
  int i;

  initgl;
  putgrn (_relabel_1);                       /* grnl for this node */
  putgrn (state_20);                  /* it depends on LB_grph.spe */
  aux = do_node (trelabel, 1);

  /* Oh, well, we have to calculate which gates will conform the  */
  /* relabeling. Each digit of the counter indicates which is the */
  /* gate which will do the relabeling. In fact, it indicates the */
  /* position into the gte_list. Rather tricky, isn't it?         */
  for (i = 0; i < INTlength ((INTlist)gte_decl); i++)
    gte_ed = INTcons (INTnth (counter->data[i]+1, (INTlist)gte_list),
		      gte_ed);

  set_attr (c_gate_list, aux, (CLR_TYPE)INTrev (gte_ed));
  set_attr (c_gate_decl, aux, ILshare ((CLR_TYPE)gte_decl));

  /* Uff, done!. Let us insert the state and we are over. */
  if (!lnsons (aux, state))
      fatal_error ("cannot link sons", __FILE__, __LINE__);

  return aux;
}

PRIVATE TNODE*
mk_choice_exp (fstate, sstate)
  TNODE *fstate, *sstate;
{
  TNODE *aux = NULL;

  initgl;
  putgrn (_choice_exp_1);                    /* grnl for this node */
  putgrn (state_13);                  /* it depends on LB_grph.spe */
  aux = do_node (tchoice_exp, 3);

  if (!lnsons (aux, fstate))
      fatal_error ("cannot link sons", __FILE__, __LINE__);
  if (!lnsons (aux, sstate))
      fatal_error ("cannot link sons", __FILE__, __LINE__);

  return aux;
}

PRIVATE TNODE*
mk_parallel_full_synch (fstate, sstate)
  TNODE *fstate, *sstate;
{
  TNODE *aux = NULL;

  initgl;
  putgrn (_parallel_full_synch_1);           /* grnl for this node */
  putgrn (state_10);                  /* it depends on LB_grph.spe */
  aux = do_node (tparallel_full_synch, 3);

  if (!lnsons (aux, fstate))
      fatal_error ("cannot link sons", __FILE__, __LINE__);
  if (!lnsons (aux, sstate))
      fatal_error ("cannot link sons", __FILE__, __LINE__);

  return aux;
}

PRIVATE TNODE*
mk_parallel_interleaving (fstate, sstate)
  TNODE *fstate, *sstate;
{
  TNODE *aux = NULL;

  initgl;
  putgrn (_parallel_interleaving_1);         /* grnl for this node */
  putgrn (state_11);                  /* it depends on LB_grph.spe */
  aux = do_node (tparallel_interleaving, 3);

  if (!lnsons (aux, fstate))
      fatal_error ("cannot link sons", __FILE__, __LINE__);
  if (!lnsons (aux, sstate))
      fatal_error ("cannot link sons", __FILE__, __LINE__);

  return aux;
}

PRIVATE TNODE*
mk_parallel_explicit (fstate, sstate, gtel)
  TNODE *fstate, *sstate;
  INTlist gtel;
{
  TNODE *aux = NULL;

  initgl;
  putgrn (_parallel_explicit_1);             /* grnl for this node */
  putgrn (state_12);                  /* it depends on LB_grph.spe */
  aux = do_node (tparallel_explicit, 3);

  if (!lnsons (aux, fstate))
      fatal_error ("cannot link sons", __FILE__, __LINE__);
  if (!lnsons (aux, sstate))
      fatal_error ("cannot link sons", __FILE__, __LINE__);

  set_attr (c_gate_list, aux, ILshare ((CLR_TYPE)gtel));

  return aux;
}

PRIVATE TNODE*
mk_hulk_node (domains, state, nar)
  TNODE *domains, *state;
  int nar;
{
  TNODE  *aux = NULL;

  assert (domains != NULL);
  assert (state != NULL);
  initgl;
  putgrn (nar);                                    /* grnl for this node */
  switch (nar) {
  case _var_choice_exp_1:
    putgrn (state_2);                       /* it depends on LB_grph.spe */
    aux = do_node (tvar_choice_exp, 3);
    break;
  case _gate_choice_exp_1:
    putgrn (state_3);                       /* it depends on LB_grph.spe */
    aux = do_node (tgate_choice_exp, 3);
    break;
  case  _par_exp_full_synch_1 :
    putgrn (state_4);                       /* it depends on LB_grph.spe */
    aux = do_node (tpar_exp_full_synch, 3); 
    break;
  case _par_exp_inter_1 :
    putgrn (state_5);                       /* it depends on LB_grph.spe */
    aux = do_node (tpar_exp_inter, 3);
    break;
  case _par_exp_expli_1 :
    putgrn (state_6);                       /* it depends on LB_grph.spe */
    aux = do_node (tpar_exp_expli, 3);
    break;
  }
                                        /* Create and insert the domains */
  if (nar == _var_choice_exp_1)
    aux->sons = mk_var_domain_list (domains);
  else
    aux->sons = mk_gate_domain_list (domains);
  aux->sons->brothers = state;                       /* Insert the state */
  aux->sons->father = aux;
  state->father = aux;              /* set the new father for this state */
  return aux;
}

/* Normalizes the sum_expression or par_expression.                      */
/* Transforms (using choice as example, the same for par):               */
/* choice k1,...,kn in [g1,...,gm],...,p1,...,pr in [h1,...,hs] [] B     */
/* into choice k1,...,kn in [g1,...,gn] []                               */
/*       choice t1,...,tu in [..] []                                     */
/*         ...                                                           */
/*           choice p1,...,pr in [h1,...,hs] [] B                        */
/* This is done recursively, exploding in each step one domain.          */
PRIVATE void
normalize (r, nar)
  TNODE *r;
  int nar;
{
  TNODE *domain_list = NULL, *more_domain = NULL,
        *state = NULL, *newstate = NULL, *annotation_list = NULL;

  assert ((r->type == tvar_choice_exp) ||
	  (r->type == tgate_choice_exp) ||
	  (r->type == tpar_exp_full_synch) ||
	  (r->type == tpar_exp_inter) ||
	  (r->type == tpar_exp_expli));
  domain_list = r->sons;
  more_domain = domain_list->sons->brothers;
  state = domain_list->brothers;
  annotation_list = state->brothers;

                                 /* If the domain_list contains only one */
                                 /* domain no normalization is needed.   */
  if (more_domain != NULL) {
    /* First, unchaining of annotation_list */
    state->brothers = NULL;

    /* The first domain is unchained from its brothers */
    domain_list->sons->brothers = NULL;

                    /* Create the new _sum_expression or _par_expression */
    newstate = mk_hulk_node (more_domain, state, nar);
    domain_list->brothers = newstate;        /* Insert as the second son */
    newstate->father = r;            /* newstate knows who is its father */
    newstate->brothers = annotation_list;             /* and its brother */

            /* Do not forget the gate_list if it is an explicit parallel */
    if (nar == _par_exp_expli_1)
      set_attr (c_gate_list, newstate, ILshare (takeclr (c_gate_list, r)));
    normalize (newstate, nar);
  }
}

/* Expands the sum_expressions (on gates only) or par_expressions        */
/* Using choice as an example:                                           */
/* choice k1,...,kn in [g1,...,gm] [] B                                  */
/* is expanded into:                                                     */
/*       [g1/k1, ..., g1/kn] B                                           */
/*   []  [g1/k1, ..., g2/kn] B                                           */
/*   []                                                                  */
/*   ...                                                                 */
/*   []  [gm/k1, ..., g1/kn] B                                           */
/*   []                                                                  */
/*   ...                                                                 */
/*   []  [gm/k1, ..., gm/kn] B                                           */

PRIVATE TNODE*
expand_hulk_op (r, nar)
  TNODE *r;
  int nar;
{
  INTlist gte_decl = NULL;
  INTlist gte_list = NULL;
  INTlist gte_to_synch = NULL;
  TNODE   *annot_list = NULL, *fstate = NULL,
          *lstate = NULL, *nstate = NULL, *left_brother = NULL;
  TNODE   *(*mk_node) ();

  annot_list = r->sons->brothers->brothers; /* could be NULL */
  r->sons->brothers->brothers = NULL;       /* to simplify   */
  fstate = r->sons->brothers;
  r->sons->brothers = NULL;    /* to simplify and to kill it */

  assert ((fstate->type == tBUT_instantiation) ||
	  (fstate->type == tstop_exp) ||
	  (fstate->type == texit_exp) ||
	  (fstate->type == tcall) ||
	  (INTlength ((INTlist)takeclr (c_gate_list, r->sons->sons)) == 1));
  switch (nar) {
  case _gate_choice_exp_1 :
    mk_node = mk_choice_exp; break;
  case _par_exp_full_synch_1 :
    mk_node = mk_parallel_full_synch; break;
  case _par_exp_inter_1 :
    mk_node = mk_parallel_interleaving; break;
  case _par_exp_expli_1 :
    mk_node = mk_parallel_explicit; break;
  }

  /* We will take and remove the colours from the domain */
  /* in order to kill r */
                                            /*  gate_domain_list  */
                                            /*  |     domain      */
                                            /*  v     v           */
  gte_decl = (INTlist)(take_attr (c_gate_decl, r->sons->sons)->value);
  gte_list = (INTlist)(take_attr (c_gate_list, r->sons->sons)->value);
  /* also the gates to synchronize if parallel explicit */
  if (nar == _par_exp_expli_1)
    gte_to_synch = (INTlist)(take_attr (c_gate_list, r)->value);

  Init_Counter (INTlength (gte_decl), INTlength (gte_list));

  lstate = mk_relabel (gte_decl, gte_list, fstate);
  while (Increment ()) {
    nstate = mk_relabel (gte_decl, gte_list, cp_tree (fstate, TRUE));
    if (nar == _par_exp_expli_1)
      nstate = mk_node (nstate, lstate, gte_to_synch);
    else
      nstate = mk_node (nstate, lstate);
    lstate = nstate;
  };

  if (annot_list != NULL) {     /* annot_list in the first choice */
    if (!lnsons (lstate, annot_list))
      fatal_error ("cannot link sons", __FILE__, __LINE__);
    lstate->value1 = (CLR_TYPE)((int)lstate->value1 + 4);
  }

  /* Ok, we have built the expansion of the sum_expression or  */
  /* par_expression. Now, we have to substitute r by lstate,   */
  /* taking into account right brothers, left brothers and     */
  /* father. Then, r can be killed, so lstate takes its place. */
  lstate->brothers = r->brothers;
  r->brothers = NULL;
  left_brother = gt_lb (r);
  if (left_brother != NULL)
    left_brother->brothers = lstate;
  else
    r->father->sons = lstate;
  lstate->father = r->father;
  kill_tree (r);
  return lstate;
}

/* It goes a tree up to a BUT_definition node, searching */
/* all gate declarations, in order to build a gate_list  */
/* usually in order to set a "gate_list" declarations in */
/* a new -light- BUT.                                    */
PRIVATE INTlist
search_gate_list (r)
  TNODE *r;
{
  int nar;
  INTlist gtel = NULL;

  assert (r->father != NULL);

  nar = *(mygrnl->data[(int)(r->value0)]);
  switch (nar) {
  case _BUT_definition_1 :
    if (find_attr (c_gate_decl, r) != NULL)
      return (INTlist)takeclr (c_gate_decl, r);
    else
      return NULL;
  case _hiding_exp_1 :
    return INTappend (search_gate_list (r->father),
		      (INTlist)takeclr (c_gate_decl, r));
  case _gate_choice_exp_1 :
  case _par_exp_full_synch_1 :
  case _par_exp_inter_1 :
  case _par_exp_expli_1 :
    return INTappend (search_gate_list (r->father),
		      search_gate_list (r->sons)); /* _gate_domain_list */
  case _gate_domain_list_1 :
    for (r = gt_fs (r); r != NULL; r = gt_rb (r))
      gtel = INTappend (gtel, (INTlist)takeclr (c_gate_decl, r));
    return gtel;
  default :
    return search_gate_list (r->father);
  }
}


/* It goes a tree up to a BUT_definition node, searching   */
/* all variable declarations, in order to build a var_list */
/* usually in order to set a "var_list" declarations in    */
/* a new -light- BUT.                                      */
PRIVATE INTlist
search_var_list (r)
  TNODE *r;
{
  int nar;
  INTlist varl = NULL;

  assert (r->father != NULL);

  nar = *(mygrnl->data[(int)(r->value0)]);
  switch (nar) {
  case _BUT_definition_1 :
    if (find_attr (c_var_list, r) != NULL)
      return (INTlist)takeclr (c_var_list, r);
    else
      return NULL;
  case _let_exp_1 :
    return INTappend (search_var_list (r->father),
		      search_var_list (r->sons)); /* _ident_equation_list */
  case _var_choice_exp_1 :
    return INTappend (search_var_list (r->father),
		      search_var_list (r->sons)); /* _var_domain_list */
  case _enable_exp_1 :
    if (find_attr (c_var_list, r) != NULL)
      return INTappend (search_var_list (r->father),
			(INTlist)takeclr (c_var_list, r));
    else
      return search_var_list (r->father);
  case _external_offer_1 :
    nar = *(mygrnl->data[(int)(r->sons->value0)]); /* FROM SON !! */
    if (nar == _experiment_list_1)          /* existe _experiment_list */
      return INTappend (search_var_list (r->father),
			search_var_list (r->sons));
    else
      return search_var_list (r->father);
  case _var_domain_list_1 :
    for (r = gt_fs (r); r != NULL; r = gt_rb (r))
      varl = INTcons ((int)takeclr (c_var_id, r), varl);
    return INTrev (varl);
  case _ident_equation_list_1 :
    for (r = gt_fs (r); r != NULL; r = gt_rb (r))
      varl = INTappend (varl, (INTlist)takeclr (c_var_list, r));
    return INTrev (varl);
  case _experiment_list_1 :       /* sons can be _var_id or _value_exp */
    for (r = gt_fs (r); r != NULL; r = gt_rb (r))
      if (find_attr (c_var_id, r) != NULL)           /* it's a _var_id */
	varl = INTcons ((int)takeclr (c_var_id, r), varl);
    return INTrev (varl);
  case _ident_equation_1 :
    return (INTlist)takeclr (c_var_list, r);
  case _value_exp_1 :
    /* we can reach this, because _experiment_list are list of */
    /* "experiment", a false node which derives into _var_id   */
    /* (which means that a variable is created) or into a      */
    /* "value_exp", which corresponds to an offer "!".         */
    return NULL;
  case _var_id_1 :
    return INTcons ((int)takeclr (c_var_id, r), (INTlist)NULL);
  default :
    return search_var_list (r->father);
  }
}

PRIVATE TNODE*
mk_BUT_definition (fstate)
  TNODE *fstate;
{
  TNODE *aux = NULL;
  INTlist gate_parameters = NULL;
  INTlist var_parameters = NULL;
  int id;
  char s[BUFSIZ];

  /* Looking for parameters before making changes */
  /* gate declarations */
  gate_parameters = search_gate_list (gt_ft (fstate));
  /* variable declarations */
  var_parameters = search_var_list (gt_ft (fstate));

  initgl;
  putgrn (_BUT_definition_1);                    /* grnl for this node */
  aux = do_node (tBUT_definition, 1);
               /* insert in the ATable the unique identifier for class */
  id = ATinc (myATable);
  myATable->data[id].value0 = (CLR_TYPE)TPROC;
  (void)sprintf (s, "_proc%d", id);          /* <_proc> isn't valid id */
  myATable->data[id].value1 = (CLR_TYPE)STadd (strdup(s),
					       mySymbolTable, 1);  /* lexv */
  ATset (myATable, id, c_ui, (CLR_TYPE)mylastBUTnumber++);
  set_attr (c_BUT_number, aux, (CLR_TYPE)id);
  set_attr (c_light, aux, (CLR_TYPE)1);   /* marked as light coroutine */
  /* let put the gate declaration */
  if (gate_parameters != NULL)
    set_attr (c_gate_decl, aux, (CLR_TYPE)gate_parameters);
  /* let put the variable declaration */
  if (var_parameters != NULL)
    set_attr (c_var_list, aux, (CLR_TYPE)var_parameters);

  if (!lnsons (aux, fstate))
    fatal_error ("cannot link sons", __FILE__, __LINE__);

  return aux;
}

PRIVATE TNODE*
mk_call (butn, glist, vlist)
  CLR_TYPE butn;
  CLR_TYPE glist;
  CLR_TYPE vlist;
{
  TNODE *aux = NULL;

  initgl;
  putgrn (_call_1);                          /* grnl for this node */
  putgrn (state_21);                  /* it depends on LB_grph.spe */
  aux = do_node (tcall, 0);
  set_attr (c_BUT_number, aux, butn);
  if (glist != NULL)
    set_attr (c_gate_decl, aux, glist);
  if (vlist != NULL)
    set_attr (c_var_list, aux, vlist);
                            /* marked as call to a light coroutine */
  set_attr (c_light, aux, (CLR_TYPE)1);

  return aux;
}

/* new_coroutine makes the following transformation: It expects a */
/* sum_expression or a par_expression, as an example,             */
/* choice domain [] B. It takes the behaviour B and creates a new */
/* coroutine (as it was a process definition) and substitutes B   */
/* by the appropiate but_instantiation. Of course, this is NOT    */
/* done if B is actually a process instantiation.                 */
/* In order to improve performance, it is also avoid when a stop, */
/* exit or call expression are found. Expansion is avoid even if  */
/* domain list over GATES only result in one relabel, i.e.,       */
/* choice/par [k1,..., kn] in [a] op B is not expanded.           */
PRIVATE void
new_coroutine (r, nar)
  TNODE *r;
  int nar;
{
  TNODE    *nbut = NULL, *oldstate = NULL,
           *nstate = NULL, *annotation_list = NULL;
  CLR_TYPE glist = NULL;
  CLR_TYPE vlist = NULL;
  int      try = FALSE;

  switch (nar) {
  case _var_choice_exp_1 :
    try = (r->sons->brothers->type != tBUT_instantiation &&
	   r->sons->brothers->type != tstop_exp &&
	   r->sons->brothers->type != texit_exp &&
	   r->sons->brothers->type != tcall);
    break;
  case _gate_choice_exp_1 :
  case _par_exp_full_synch_1 :
  case _par_exp_inter_1 :
  case _par_exp_expli_1 :
    try = (r->sons->brothers->type != tBUT_instantiation &&
	   r->sons->brothers->type != tstop_exp &&
	   r->sons->brothers->type != texit_exp &&
	   r->sons->brothers->type != tcall &&
	   INTlength ((INTlist)takeclr (c_gate_list, r->sons->sons)) > 1);
    break;
  }

  if (try) {
    oldstate = r->sons->brothers;
                                     /* To avoid losing it when unchained */
    annotation_list = oldstate->brothers;
    oldstate->brothers = NULL;      /* The reason to save annotation_list */

    nbut = mk_BUT_definition (oldstate);
    insert_but_def (nbut);   /* Now, it becomes a 'normal' BUT_definition */

    /* Well, we have created the new BUT_definition */
    /* Now, we have to create a _call as the state of r */

    if (find_attr (c_gate_decl, nbut) != NULL)
      glist = takeclr (c_gate_decl, nbut);
    if (find_attr (c_var_list, nbut) != NULL)
      vlist = takeclr (c_var_list, nbut);
    nstate = mk_call (takeclr (c_BUT_number, nbut), glist, vlist);
    /* nstate needs all colours as other states */

             /* Do not forget the gate_list if it is an explicit parallel */
    if (nar == _par_exp_expli_1)
      set_attr (c_gate_list, nstate, ILshare (takeclr (c_gate_list, r)));
    /* ok, the _call is built. Let us chain it to r */
    r->sons->brothers = NULL;                 /* Unchaining the old state */
    if (!lnsons (r, nstate))
      fatal_error ("cannot link sons", __FILE__, __LINE__);
    nstate->brothers = annotation_list;
  }
}

/* Eliminates the sum_expression and par_expression, by means */
/* of expanding such operators in [] and ||, respectively.    */
PRIVATE void
transform (r)
  TNODE *r;
{
  int nar;

  for (; r != NULL; r = gt_rb (r)) {
    nar = *(mygrnl->data[(int)(r->value0)]);
    switch (nar) {

    case _var_choice_exp_1 :
      normalize (r, nar);
      new_coroutine (r, nar);
      break;

    case _gate_choice_exp_1 :
      normalize (r, nar);
      new_coroutine (r, nar);
      r = expand_hulk_op (r, nar);
      break;

    case _par_exp_full_synch_1 :
      normalize (r, nar);
      new_coroutine (r, nar);
      r = expand_hulk_op (r, nar);
      break;

    case _par_exp_inter_1 :
      normalize (r, nar);
      new_coroutine (r, nar);
      r = expand_hulk_op (r, nar);
      break;

    case _par_exp_expli_1 :
      normalize (r, nar);
      new_coroutine (r, nar);
      r = expand_hulk_op (r, nar);

      break;
    }
    if (r->sons != NULL)
      transform (r->sons);
  }
}

/* In order to make this file autocontained, a function    */
/* called "do_transform" is provided. It sets some global  */
/* variables (but only visibe inside this module, if such  */
/* is possible in C), and calls the real transformator.    */
/* As it is possible an increasing of the BUTs, it returns */
/* the new lastBUTnumber. It cannot be ignored.            */
PUBLIC int
do_transform (r, a, s, x, g)
  TNODE *r;
  AT    *a;
  ST    *s;
  int   x;
  IAT   *g;
{
  myLBMroot = r;
  myATable  = a;
  mySymbolTable = s;
  mylastBUTnumber = x;
  myGL = ITcreate (4, 2, 1);
  mygrnl = g;

  transform (r);

  return mylastBUTnumber;
}
