%{
  /***********************************
    (C) Copyright 1992-1993; dit/upm
    Distributed under the conditions stated in the
    TOPO General Public License (see file LICENSE)
    ***********************************/

  /***********************************

    Santiago Pavon Gomez

    25-07-1990

    Command Interpreter
    Parser of value expressions
    main program

    ************************************/


#include "inparser.h"
#include "listdh.h"
#include "listdout.h"
#include "ligetlin.h"
#include "limisc.h"
#include "batables.h"
#include "bainit.h"
#include "bamove.h"
#include "inhelp.h"
#include "batransl.h"
#include "badefca.h"
#include "incomm.h"
#include "ststep.h"
#include "ie_vc.h"
#include "ie_nrec.h"
#include "ie_k.h"
#include "baprint.h"
#include "basust_v.h"

/* KJT 22/01/23: added function prototypes */
int yylex();

  /******************************************************************
   *
   *      Types to specify movements
   *
   ******************************************************************/


  /* Types of movements */
#define POSITION 1
#define STRING 2
#define CHAR 3


  /* mvrelTyp
   * Position structure like 1b, 3u, etc...
   */
  typedef struct { int  num;
		   char mov;
		 } mvrelTyp ;


  /* mvTyp
   * Structure for the three diferents kinds of hight level
   * movements.
   */
  typedef union { char     *proc;
		  mvrelTyp  mvrel;
		  char      root;
		} mvTyp;


  /* moveTyp
   * Structure for the three diferents kinds of hight level
   * movements with its type in each case.
   */
  typedef struct { mvTyp mv;
		   int   mvType;
		 } moveTyp;



  /******************************************************************
   *
   *  Syntactical and lexical analyser
   *
   *******************************************************************/

  /* MAX_LINE
   * Maximum characters number of a commands input line and a string type.
   */
#define MAX_LINE BUF_SIZE

  /* YYMAXDEPTH
   * Maximum parsing depth. ( yacc default = 150 )
   * The memory requested by the parser is YYMAXDEPTH x MAXLINE
   */
#define YYMAXDEPTH 300

  /* MAX_ARGS
   * Maximum number of elements in a list.
   */
#define MAX_ARGS MAX_GATE_TABLE

  /* MAX_OPTS
   * Maximum number of options in a command.
   */
#define MAX_OPTS 128

  /* MAX_MOVE
   * Maximum number of move commands in a command line.
   */
#define MAX_MOVE 32


  /* PRINT_DEPTH
   * Default print depth is:
   *     1 in STEP mode
   *     UNDEFINED otherwise
   */
#define PRINT_DEPTH (lex_mode==STEPLEXMODE ? 1 : UNDEFINED)


  /* InputLineIsEmpty
   * This variable is set to true when the input line is only '\n'.
   * This variable must be set to FALSE before calling to yyparse.
   */
  static boolean InputLineIsEmpty;


  static int numMove;
  static int numOpc;
  static int numGate;

  static char str_empty[1] = { '\0' };

  static ListTyp createdExpCell = NULL;
  static DescriptorTyp expectedSort = 0;

  /*----------------------------------------------------------------*/

  /* KJT 21/08/07: moved from earlier */

  /* lex_mode
   * mode of lex: CMDLEXMODE, NUMLEXMODE, EXPLEXMODE, STEPLEXMODE
   */
  #define CMDLEXMODE  0
  #define NUMLEXMODE  1
  #define EXPLEXMODE  2
  #define STEPLEXMODE 3
  static int lex_mode;

  /* KJT 21/08/07: moved from earlier */
  static boolean ResError,changes;
  static char ResErrorMsg[100];

  /******************************************************************
   *
   *  Values set by parser. They are used by Code()
   *
   *******************************************************************/

  typedef struct { char          *name;
		   ListTyp       pos_dname;
		   boolean       infix;
		   DescriptorTyp dsort;
		   ListTyp       argl;
		 } ExpCellTyp,*PExpCellTyp;

  /*----------------------------------------------------------------*/

  /* KJT 21/08/07: function prototype definitions */
  static PExpCellTyp NewExpCell();
  static ExprTyp ResExpr(PExpCellTyp c);
  static void FreeExpCell();

  /******************************************************************
   *
   *  Values sets by parser. They are used by Code()
   *
   *******************************************************************/

  static ExprTyp expr_rw;

  static char *success_event, *process_name, *expected_response;

  static boolean default_success_event;

  static char *env_variable, *env_value;

  static int branch;

  static char *command_name;

  static char *outfile_name;

  static char option;
  static int  low_limit, high_limit;

  static char *optionList;
  static int  lengthOpcList;

  static int depth;
  static int seed;
  static int one_execs;
  static int verbose_level;
  static int undos_num;

  static int bhsize, percentage;

  static moveTyp movement_tab[MAX_MOVE];
  static int     num_mov;

  static char *gate_list1[MAX_ARGS];
  static int  numGate1;
  static char *gate_list2[MAX_ARGS];
  static int  numGate2;

  static char *cmd_file;
  static int command_token;

  static ListTyp number_list;

  /*----------------------------------------------------------------*/

#define OPT_ERR  1
#define CMD_ERR  2
#define EXPR_ERR 3

  static int what_error = 0;

/* KJT 22/01/23: added "void" type */
void yyerror(msg)
    char* msg;
  {
    msg = msg; /* "syntax error" */
    /*
       switch ( what_error ){
       case OPT_ERR:
       printError("      Invalid option.\n\n");
       break;
       case CMD_ERR:
       printError("      Command error.\n\n");
       break;
       case EXPR_ERR:
       printError("      Expression: ");
       printError(msg);
       printError("\n\n");
       break;
       }
       */
    return ;
  }

  /******************************************************************
   *
   *  Functions to fill the variables defined above with the values parsed.
   *
   *******************************************************************/

  /* Reset_values_parsed
   * Reset all the variables defined above to store the values parsed.
   */
  static void Reset_values_parsed()
    {
      expr_rw               = NULL;
      success_event         = CopyString(str_empty);
      default_success_event = (((char*)Default("success_event"))[0]!='\0');
      process_name          = CopyString(str_empty);
      expected_response     = CopyString(str_empty);
      env_variable          = CopyString(str_empty);
      env_value             = CopyString(str_empty);
      branch                = 0;
      command_name          = CopyString(str_empty);
      outfile_name          = CopyString(str_empty);
      option                = '\0';
      low_limit             = 0;
      high_limit            = 0;
      optionList            = CopyString(str_empty);
      lengthOpcList         = 0;
      depth                 = UNDEFINED;
      seed                  = 0;
      bhsize                = UNDEFINED;
      percentage            = 100; /* % */
      one_execs             = 1;
      verbose_level         = 0;
      undos_num             = -1;
      /* movement_tab[MAX_MOVE] */
      num_mov               = 0;
      /* gate_list1[MAX_ARGS]   */
      numGate1              = 0;
      /* gate_list2[MAX_ARGS]   */
      numGate2              = 0;
      command_token         = 0;
      number_list           = Create_list();
    }

  /*----------------------------------------------------------------*/

  /* Fill_mov_list
   * Fill the variables to store the movement list parsed.
   */
  static void Fill_mov_list( contmove, move_lst )
    int      contmove;
  moveTyp *move_lst;
  {
    int i;

    num_mov = contmove;
    if (contmove!=0) {
      for (i = 0 ; i < contmove ; i++)
	if (move_lst[i].mvType == POSITION) {
	  movement_tab[i].mv.mvrel.num = move_lst[i].mv.mvrel.num;
	  movement_tab[i].mv.mvrel.mov = move_lst[i].mv.mvrel.mov;
	  movement_tab[i].mvType = POSITION;
	}
	else if (move_lst[i].mvType == STRING) {
	  movement_tab[i].mv.proc = CopyString(move_lst[i].mv.proc);
	  movement_tab[i].mvType = STRING;
	}
	else if (move_lst[i].mvType == CHAR) {
	  movement_tab[i].mv.root = move_lst[i].mv.root;
	  movement_tab[i].mvType = CHAR;
	}
    }
  }

  /*----------------------------------------------------------------*/

  /* Fill_gate_list1
   * Fill the variables to store the first gate list parsed.
   */
  static void Fill_gate_list1(lgl1,gl1)
    int   lgl1;
  char *gl1[];
  {
    int i;

    numGate1 = lgl1;
    for (i=0 ; i<lgl1 ; i++)
      gate_list1[i] = gl1[i];
  }

  /*----------------------------------------------------------------*/

  /* Fill_gate_list2
   * Fill the variables to store the second gate list parsed.
   */
  static void Fill_gate_list2(lgl2,gl2)
    int lgl2;
  char *gl2[];
  {
    int i;

    numGate2 = lgl2;
    for (i=0 ; i<lgl2 ; i++)
      gate_list2[i] = gl2[i];
  }

  /*----------------------------------------------------------------*/

  /* Fill_option_list
   * Fill the variables to store the option list parsed.
   */
  static void Fill_option_list(optlist,numopt)
    int   numopt;
  char *optlist;
  {
    lengthOpcList   = numopt;
    optlist[numOpc] = '\0';
    optionList      = CopyString(optlist);
  }


  static boolean StoreOption(c,opts)
    char c;
  char *opts;
  {
    if (numOpc < MAX_OPTS){
      opts[numOpc++] = c;
      return TRUE;
    }
    else {
      (void)printf("      WARNING : option <-%c> ignored\n",c);
      return FALSE;
    }
  }

  %}

%union { int            branch;
	 int            num;
	 char           option;
	 char           opt_lst[MAX_OPTS];
	 char           *ident_lst[MAX_ARGS];
	 char           *string;
	 mvrelTyp       posic;
	 moveTyp        tab_move[MAX_MOVE];
	 PExpCellTyp    expc;
	 ListTyp        le;
	 DescriptorTyp  descr;
	 ExprTyp        expr;
	 ListTyp        nl;
       }

%token           ERROR
%token <num>     NUM
%token <num>     BRANCH
%token <posic>   POSIC
%token           ROOT
%token <string>  REWRITE
%token <string>  PRINT
%token <string>  LOAD
%token <string>  IDENT
%token <string>  SAVE
%token <string>  DATA
%token <string>  STAT
%token <string>  EXPAND
%token <string>  FREE
%token <string>  VAR
%token <string>  TEST
%token <string>  ONE
%token <string>  IT
%token <string>  MOVE
%token <string>  STEP
%token <string>  QUIT
%token <string>  HELP
%token <string>  SET
%token <string>  CMD
%token <string>  PI
%token <string>  VCNR
%token <string>  K
%token <string>  VC
%token           OF
%token <string>  EXIT
%token <string>  MENU
%token <string>  UNDO
%token <string>  TRACE
%token <string>  SYNC
%token <string>  STEPHELP
%token <string>  REFUSED
%token <string>  SELECT
%token <option>  OPT_A
%token <option>  OPT_B
%token <option>  OPT_C
%token <option>  OPT_D
%token <option>  OPT_E
%token <option>  OPT_G
%token <option>  OPT_I
%token <option>  OPT_O
%token <option>  OPT_P
%token <option>  OPT_Q
%token <option>  OPT_S
%token <option>  OPT_T
%token <option>  OPT_U
%token <option>  OPT_V
%token <option>  OPT_X
%token <option>  OPT_Y


%type <option>      dt_option
%type <opt_lst>     test_option_lst
%type <opt_lst>     step_option_lst
%type <opt_lst>     print_option_lst
%type <opt_lst>     exp_option_lst
%type <opt_lst>     iexp_option_lst
%type <tab_move>    move_lst
%type <ident_lst>   gate_lst
%type <expc>        value_expression
%type <expc>        simple_expression
%type <expc>        term_expression
%type <le>          value_expression_list
%type <descr>       sort_indication
%type <le>          value_expression_seq
%type <expr>        expression
%type <nl>          num_lst



%start inter

%%
 inter:                   { InputLineIsEmpty=TRUE;}
| command
| expression
| NUM
;

expression :   value_expression
{  if (ResError) {
  printError(ResErrorMsg);
  $$ = NULL;
}
else {
  if ( $1->dsort == 0 )
    $1->dsort = expectedSort;
  $$ = ResExpr($1);
  if (ResError) {
    printError(ResErrorMsg);
  }
}
   FreeExpCell();
 }

value_expression :   simple_expression
{ $$ = $1; }
| value_expression IDENT simple_expression
{ $$ = NewExpCell();
  $$->name = CopyString($2);
  $$->argl = Insert_list((DataListTyp)$1,
			 Insert_list((DataListTyp)$3,
				     Create_list()));
  $$->infix = TRUE;
}
;


simple_expression :    term_expression  sort_indication
{ $$ = $1;
  $$->dsort = $2;
}
;


term_expression :   IDENT  value_expression_list
{ $$ = NewExpCell();
  $$->name = CopyString($1);
  $$->argl = $2;
}
| '(' value_expression ')'
{ $$ = $2; }
;


value_expression_list :     /* empty */
{ $$ = NULL; }
| '(' value_expression_seq ')'
{ $$ = $2; }
;


sort_indication :   /* empty */    { $$ = 0; }
| OF IDENT
{ $$ = FindS($2);
  if ($$==0) {
    ResError = TRUE;
    (void)sprintf(ResErrorMsg,
		  "\n     ERROR: sort %s unknown.\n\n",
		  $2);
  }
}
;

value_expression_seq :    value_expression
{ $$ = Insert_list((DataListTyp)$1,
		   Create_list());
}
| value_expression_seq ',' value_expression
{ $$ = Add_list((DataListTyp)$3,$1);
}
;


 command:
REWRITE {lex_mode=EXPLEXMODE;} expression {expr_rw       = $3;
					   command_token = REWRITE;}

| STEP step_option_lst     { command_token = STEP;
			     Fill_option_list($2,numOpc);}
| STEP IDENT step_option_lst { process_name  = CopyString($2);
			       command_token = STEP;
			       Fill_option_list($3,numOpc);}
| STEP IDENT IDENT step_option_lst      { success_event = CopyString($2);
					  process_name  = CopyString($3);
					  command_token = STEP;
					  Fill_option_list($4,numOpc);}

| EXIT   {command_token = EXIT;}

| MENU   {command_token = MENU;}

| TRACE  {command_token = TRACE;}

| UNDO   {command_token = UNDO;}

| BRANCH {branch = $1;
	  command_token = BRANCH;}

| SYNC NUM       {branch = $2;
		  command_token = SYNC;}

| SYNC NUM IDENT {branch = $2;
		  process_name = CopyString($3);
		  command_token = SYNC;}

| STEPHELP {command_token = STEPHELP;}

| REFUSED  {command_token = REFUSED;}

| SELECT num_lst {command_token = SELECT;}

| HELP       { command_token = HELP;}
| HELP IDENT { command_name  = CopyString($2);
	       command_token = HELP;}

| SAVE        { command_token = SAVE;}
| SAVE IDENT  { outfile_name  = CopyString($2);
		command_token = SAVE;}

| DATA dt_option          {option        = $2;
			   low_limit     = 0;
			   high_limit    = 0;
			   command_token = DATA;}
| DATA dt_option NUM      {option        = $2;
			   low_limit     = $3;
			   high_limit    = 0;
			   command_token = DATA;}
| DATA dt_option NUM NUM  {option        = $2;
			   low_limit     = $3;
			   high_limit    = $4;
			   command_token = DATA;}

| EXPAND exp_option_lst      {Fill_option_list($2,numOpc);
			      command_token = EXPAND;}
| EXPAND NUM exp_option_lst  {depth = $2;
			      Fill_option_list($3,numOpc);
			      command_token = EXPAND;}

| VAR exp_option_lst       {Fill_option_list($2,numOpc);
			    command_token = VAR;}
| VAR NUM exp_option_lst   {depth = $2;
			    Fill_option_list($3,numOpc);
			    command_token = VAR;}

| FREE exp_option_lst      {Fill_option_list($2,numOpc);
			    command_token = FREE;}
| FREE NUM exp_option_lst  {depth = $2;
			    Fill_option_list($3,numOpc);
			    command_token = FREE;}

| ONE NUM            exp_option_lst      {depth = $2;
					  Fill_option_list($3,numOpc);
					  command_token = ONE;}
| ONE NUM IDENT      exp_option_lst      {depth = $2;
					  process_name  = CopyString($3);
					  Fill_option_list($4,numOpc);
					  command_token = ONE;}
| ONE NUM IDENT  NUM exp_option_lst      {depth = $2;
					  seed  = $4;
					  process_name  = CopyString($3);
					  Fill_option_list($5,numOpc);
					  command_token = ONE;}
| ONE NUM IDENT NUM NUM exp_option_lst   {depth        = $2;
					  seed         = $4;
					  one_execs    = $5;
					  process_name = CopyString($3);
					  Fill_option_list($6,numOpc);
					  command_token = ONE;}
| ONE NUM IDENT IDENT exp_option_lst     {depth = $2;
					  success_event = CopyString($3);
					  process_name  = CopyString($4);
					  Fill_option_list($5,numOpc);
					  command_token = ONE;}
| ONE NUM       NUM     exp_option_lst   {depth = $2;
					  seed  = $3;
					  Fill_option_list($4,numOpc);
					  command_token = ONE;}
| ONE NUM       NUM NUM exp_option_lst   {depth     = $2;
					  seed      = $3;
					  one_execs = $4;
					  Fill_option_list($5,numOpc);
					  command_token = ONE;}
| ONE NUM IDENT IDENT NUM exp_option_lst {depth = $2;
					  seed  = $5;
					  success_event = CopyString($3);
					  process_name  = CopyString($4);
					  Fill_option_list($6,numOpc);
					  command_token = ONE;}
| ONE NUM IDENT IDENT NUM NUM exp_option_lst {depth = $2;
					      seed  = $5;
					      one_execs = $6;
					      success_event = CopyString($3);
					      process_name  = CopyString($4);
					      Fill_option_list($7,numOpc);
					      command_token = ONE;}

| IT                 iexp_option_lst {Fill_option_list($2,numOpc);
				      command_token = IT;}
| IT NUM             iexp_option_lst {depth = $2;
				      Fill_option_list($3,numOpc);
				      command_token = IT;}
| IT NUM IDENT       iexp_option_lst {depth = $2;
				      if ( default_success_event )
					process_name  = CopyString($3);
				      else
					success_event = CopyString($3);
				      Fill_option_list($4,numOpc);
				      command_token = IT;}
| IT     IDENT       iexp_option_lst {if ( default_success_event )
					process_name  = CopyString($2);
else
  success_event = CopyString($2);
				      Fill_option_list($3,numOpc);
				      command_token = IT;}
| IT     IDENT IDENT iexp_option_lst {success_event = CopyString($2);
				      process_name  = CopyString($3);
				      Fill_option_list($4,numOpc);
				      command_token = IT;}
| IT NUM IDENT IDENT iexp_option_lst {depth = $2;
				      success_event = CopyString($3);
				      process_name  = CopyString($4);
				      Fill_option_list($5,numOpc);
				      command_token = IT;}

| STAT   {command_token = STAT;}

| QUIT   {command_token = QUIT;}

| LOAD   {command_token = LOAD;}


| PRINT                            {depth = PRINT_DEPTH;
				    command_token = PRINT;}
| PRINT print_option_lst           {depth = PRINT_DEPTH;
				    Fill_option_list($2,numOpc);
				    command_token = PRINT;}
| PRINT NUM                        {depth = $2;
				    command_token = PRINT;}
| PRINT IDENT                      {depth = PRINT_DEPTH;
				    outfile_name = CopyString($2);
				    command_token = PRINT;}
| PRINT print_option_lst NUM       {depth = $3;
				    Fill_option_list($2,numOpc);
				    command_token = PRINT;}
| PRINT print_option_lst IDENT     {depth = PRINT_DEPTH;
				    Fill_option_list($2,numOpc);
				    outfile_name = CopyString($3);
				    command_token = PRINT;}
| PRINT NUM IDENT                  {depth = $2;
				    outfile_name = CopyString($3);
				    command_token = PRINT;}
| PRINT NUM print_option_lst       {depth = $2;
				    Fill_option_list($3,numOpc);
				    command_token = PRINT;}
| PRINT IDENT NUM                  {depth = $3;
				    outfile_name = CopyString($2);
				    command_token = PRINT;}
| PRINT IDENT print_option_lst     {depth = PRINT_DEPTH;
				    Fill_option_list($3,numOpc);
				    outfile_name = CopyString($2);
				    command_token = PRINT;}
| PRINT print_option_lst NUM IDENT {depth = $3;
				    Fill_option_list($2,numOpc);
				    outfile_name = CopyString($4);
				    command_token = PRINT;}
| PRINT print_option_lst IDENT NUM {depth = $4;
				    Fill_option_list($2,numOpc);
				    outfile_name = CopyString($3);
				    command_token = PRINT;}
| PRINT NUM print_option_lst IDENT {depth = $2;
				    Fill_option_list($3,numOpc);
				    outfile_name = CopyString($4);
				    command_token = PRINT;}
| PRINT NUM IDENT print_option_lst {depth = $2;
				    Fill_option_list($4,numOpc);
				    outfile_name = CopyString($3);
				    command_token = PRINT;}
| PRINT IDENT NUM print_option_lst {depth = $3;
				    Fill_option_list($4,numOpc);
				    outfile_name = CopyString($2);
				    command_token = PRINT;}
| PRINT IDENT print_option_lst NUM {depth = $4;
				    Fill_option_list($3,numOpc);
				    outfile_name = CopyString($2);
				    command_token = PRINT;}


| TEST  test_option_lst                {Fill_option_list($2,numOpc);
					command_token = TEST;}
| TEST IDENT  test_option_lst          {if ( default_success_event )
					  process_name  = CopyString($2);
else
  success_event = CopyString($2);
					Fill_option_list($3,numOpc);
					command_token = TEST;}
| TEST IDENT IDENT test_option_lst    {success_event = CopyString($2);
				       process_name  = CopyString($3);
				       Fill_option_list($4,numOpc);
				       command_token = TEST;}
| TEST NUM IDENT  test_option_lst      {depth = $2;
					if ( default_success_event )
					  process_name  = CopyString($3);
					else
					  success_event = CopyString($3);
					Fill_option_list($4,numOpc);
					command_token = TEST;}
| TEST NUM IDENT IDENT test_option_lst {depth = $2;
					success_event = CopyString($3);
					process_name  = CopyString($4);
					Fill_option_list($5,numOpc);
					command_token = TEST;}

| SET                            {command_token = SET;}
| SET IDENT                      {env_variable  = CopyString($2);
				  env_value     = "\0";
				  command_token = SET;}
| SET IDENT IDENT                {env_variable  = CopyString($2);
				  env_value     = CopyString($3);
				  command_token = SET;}
| SET IDENT NUM                  {env_variable  = CopyString($2);
				  env_value     = IntToString($3);
				  command_token = SET;}

| CMD IDENT                      {cmd_file      = CopyString($2);
				  command_token = CMD;}

| MOVE move_lst   { Fill_mov_list(numMove,$2);
		    command_token = MOVE;}

| VCNR {numGate=0;} gate_lst ',' {numGate1 = numGate;
				  Fill_gate_list1(numGate1,$3);
				  numGate=0;}
gate_lst     {numGate2 = numGate;
	      Fill_gate_list2(numGate2,$6);
	      command_token = VCNR;}
| VC   {numGate=0;} gate_lst ',' {numGate1 = numGate;
				  Fill_gate_list1(numGate1,$3);
				  numGate=0;}
gate_lst     {numGate2 = numGate;
	      Fill_gate_list2(numGate2,$6);
	      command_token = VC;}
| K    {numGate=0;} gate_lst ',' {numGate1 = numGate;
				  Fill_gate_list1(numGate1,$3);
				  numGate=0;}
gate_lst     {numGate2 = numGate;
	      Fill_gate_list2(numGate2,$6);
	      command_token = K;}
| PI   {numGate=0;} gate_lst     {numGate1 = numGate;
				  Fill_gate_list1(numGate1,$3);
				  command_token = PI;}
;

 move_lst:                         { /* empty */ }
| move_lst POSIC        { if (numMove < MAX_MOVE) {
  $$[numMove].mv.mvrel.num = $2.num;
  $$[numMove].mv.mvrel.mov = $2.mov;
  $$[numMove].mvType = POSITION;
  ++numMove;
}
else
  (void)printf("      WARNING : movement <%d%c> ignored\n",$2.num,$2.mov);
			}
| move_lst NUM          { if (numMove < MAX_MOVE) {
  $$[numMove].mv.mvrel.num = $2;
  $$[numMove].mv.mvrel.mov = 'l';
  $$[numMove].mvType = POSITION;
  ++numMove;
}
else
  (void)printf("      WARNING : movement <%dl> ignored\n",$2);
			}
| move_lst IDENT        { if (numMove < MAX_MOVE) {
  $$[numMove].mv.proc = $2;
  $$[numMove].mvType = STRING;
  ++numMove;
}
else
  (void)printf("      WARNING : movement <%s> ignored\n",$2);
			}
| move_lst ROOT         { if (numMove < MAX_MOVE) {
  $$[numMove].mv.root = '^';
  $$[numMove].mvType = CHAR;
  ++numMove;
}
else
  (void)printf("      WARNING : movement <^> ignored\n");
			}
;

 dt_option:     OPT_S
| OPT_V
| OPT_O
| OPT_P
| OPT_G
| error       { /* no error is raised by now */
  what_error = OPT_ERR;
}
;

 test_option_lst:                         { /* empty */ }
| test_option_lst OPT_T             { (void)StoreOption($2,$$); }
| test_option_lst OPT_A             { (void)StoreOption($2,$$); }
| test_option_lst OPT_S             { (void)StoreOption($2,$$); }
| test_option_lst OPT_E             { (void)StoreOption($2,$$); }
| test_option_lst OPT_D             { (void)StoreOption($2,$$); }
| test_option_lst OPT_V             { (void)StoreOption($2,$$); }
| test_option_lst OPT_V NUM         { (void)StoreOption($2,$$);
				      verbose_level = $3;
				    }
| test_option_lst OPT_I             { (void)StoreOption($2,$$); }
| test_option_lst OPT_Y             { (void)StoreOption($2,$$); }
| test_option_lst OPT_X IDENT       { if (StoreOption($2,$$))
					expected_response = CopyString($3);
				    }
| test_option_lst OPT_X IDENT OPT_Q { if (StoreOption($2,$$)){
  expected_response = CopyString($3);
  (void)StoreOption($4,$$);
}
				    }
/*
 * partial test expansion options :
 *
 */
| test_option_lst OPT_B NUM         { (void)StoreOption($2,$$);
				      bhsize = $3; }
| test_option_lst OPT_P NUM         { (void)StoreOption($2,$$);
				      percentage = $3; }
| test_option_lst OPT_P NUM NUM     { (void)StoreOption($2,$$);
				      seed       = $4;
				      percentage = $3; }
| test_option_lst OPT_P NUM OPT_G   { (void)StoreOption($2,$$);
				      (void)StoreOption($4,$$);
				      percentage = $3; }
| test_option_lst OPT_P NUM NUM OPT_G { (void)StoreOption($2,$$);
					(void)StoreOption($5,$$);
					seed       = $4;
					percentage = $3; }
| test_option_lst error             { /* no error is raised by now */
  what_error = OPT_ERR;
}
;

 step_option_lst:                   { /* empty */ }
| step_option_lst OPT_T             { (void)StoreOption($2,$$); }
| step_option_lst OPT_D             { (void)StoreOption($2,$$); }
| step_option_lst OPT_U NUM         { (void)StoreOption($2,$$);
				      undos_num = $3;
				    }


 print_option_lst:  OPT_P                        { (void)StoreOption($1,$$); }
| OPT_T                        { (void)StoreOption($1,$$); }
| OPT_A                        { (void)StoreOption($1,$$); }
| OPT_C                        { (void)StoreOption($1,$$); }
| print_option_lst OPT_P       { (void)StoreOption($2,$$); }
| print_option_lst OPT_T       { (void)StoreOption($2,$$); }
| print_option_lst OPT_A       { (void)StoreOption($2,$$); }
| print_option_lst OPT_C       { (void)StoreOption($2,$$); }
| print_option_lst error       {
  /* no error is raised by now */
  what_error = OPT_ERR;
}
;

 exp_option_lst:                          { /* empty */ }
| exp_option_lst OPT_V       { (void)StoreOption($2,$$); }
| exp_option_lst OPT_I       { (void)StoreOption($2,$$); }
| exp_option_lst error       { /* no error is raised by now */
  what_error = OPT_ERR;
}
;


 iexp_option_lst:                         { /* empty */ }
| iexp_option_lst OPT_D       { (void)StoreOption($2,$$); }
| iexp_option_lst OPT_P       { (void)StoreOption($2,$$); }
| iexp_option_lst OPT_V       { (void)StoreOption($2,$$); }
| iexp_option_lst error       { /* no error is raised by now */
  what_error = OPT_ERR;
}
;

 gate_lst:   IDENT           {if (numGate < MAX_ARGS)
				$$[numGate++] = $1;
 else
   (void)printf("      WARNING : gate <%s> ignored\n",$1);
			    }
| gate_lst IDENT {if (numGate < MAX_ARGS)
		    $$[numGate++] = $2;
else
  (void)printf("      WARNING : gate <%s> ignored\n",$2);
		}
;

 num_lst:                     { /* empty */ }
| num_lst NUM     { number_list = Add_list($2,number_list); }
;

%%


/******************************************************************
 *
 *      Lexical analyser.
 *
 *******************************************************************/

#define    isspecchar(c) (c=='#')||(c=='%')||(c=='&')||(c=='*')||(c=='+')||\
(c=='-')||(c=='.')||(c=='/')||(c=='<')||(c=='=')||\
(c=='>')||(c=='@')||(c=='\\')||(c=='^')||(c=='~')||\
(c=='{')||(c=='}')

#ifdef unix
# define ischar2(c) isalpha(c)||(c=='.')||(c=='_')||(c=='/')
#else
# define ischar2(c) isalpha(c)||(c=='.')||(c=='_')||(c=='\\')
#endif
#define    iscomma(c)      (c==',')
#define    isleftpar(c)  (c=='(')
#define    isrightpar(c) (c==')')
#define    isexclam(c)      (c=='!')
#define    isgreater(c)  (c=='>')
#define    iscomment(c)  (c=='%')
#define    isnull(c)      (c=='\0')

/* line
 * The input line is stored in this array.
 */
static char line[MAX_LINE];


/* pos_line
 * The value of this variable gives the next character of the input line.
 */
static int pos_line = -1;



/* ctoken
 * Current token.
 */
static char ctoken[MAX_LINE];


/* pos_ctoken
 * Position in ctoken.
 */
static int pos_ctoken;


/* gtchar
 * It returns the next character of the commands input line.
 * If there are no more characters, it requests one command line
 * input.
 */
static char gtchar()
{
  pos_line++;
  return(line[pos_line]);
}


/* ungtc
 * It decrements pos_line.
 */
static int ungtc()
{
  --pos_line;
}


static void ReadLine( s )
     char *s;
{
  int i=0;
  pos_line = -1;
  while ((line[i++]=*s++)!='\n')
    ;
  line[i]='\0';
}

/*----------------------------------------------------------------*/


/* TokenNameTyp
 * Pairs token name and token code.
 */
typedef struct Cell_Tokns { char *comand;
			    int tokns;
			  } TokenNameTyp;


/* CmdTokenNameTable
 * The equivalence between commands names and tokens are stored in this array.
 */
static TokenNameTyp CmdTokenNameTable[] = {
#ifdef INVEXP
  "vc*"           , VC,
  "vcnr*"         , VCNR,
  "pi*"           , PI,
  "k*"            , K,
#endif /* INVEXP */
  "r*ewrite"      , REWRITE,
  "p*rint"        , PRINT,
  "l*oad"         , LOAD,
  "d*atatable"    , DATA,
  "e*xpand"       , EXPAND,
  "f*reeexpand"   , FREE,
  "h*elp"         , HELP,
  "v*arexpand"    , VAR,
  "t*estexpand"   , TEST,
  "o*neexpand"    , ONE,
  "s*tep"         , STEP,
  "m*ove"         , MOVE,
  "q*uit"         , QUIT,
  "se*t"          , SET,
  "c*ommand"      , CMD,
#if defined(sun) || defined(MSDOS)
  "sta*tistics"    , STAT,
#endif
#ifdef SDEBUG
  "sa*ve"         , SAVE,
#endif
  "i*nterexpand"  , IT
};


/* StepTokenNameTable
 * The equivalence between commands names and tokens are store in this array.
 */
static TokenNameTyp StepTokenNameTable[] = {
  "p*rint"     ,PRINT,
  "e*xit"      ,EXIT,
  "m*enu"      ,MENU,
  "u*ndo"      ,UNDO,
  "t*race"     ,TRACE,
  "s*ync"      ,SYNC,
  "r*efused"   ,REFUSED,
  "?*"         ,STEPHELP,
  "sel*ect"    ,SELECT
};


/* cont_cmd
 * Number of commands stored in the CmdTokenNameTable
 */
static int cont_cmd=sizeof(CmdTokenNameTable)/sizeof(CmdTokenNameTable[0]);


/* cont_step
 * Number of commands stored in the StepTokenNameTable
 */
static int cont_step=sizeof(StepTokenNameTable)/sizeof(StepTokenNameTable[0]);



/* strcomp
 * It returns TRUE if "s1" is equal to "s2" until the character "*",
 * and a prefix of "s2" after the character "*".
 */
static boolean strcomp(s1,s2)
     char *s1;
     char *s2;
{ int i;

  for (i = 0 ; ; i++) {
    LASSERT(s2[i]!='\0');
    if (s2[i]=='*') break;
    if (s1[i]=='\0') return FALSE;
    if (s1[i]!= s2[i]) return FALSE;
  }
  for ( ; ; i++) {
    if (s1[i]=='\0') return TRUE;
    if (s2[i+1]=='\0') return FALSE;
    if (s1[i]!= s2[i+1]) return FALSE;
  }
}



/* Search_In_CmdTable
 * It searches in the commands table if string is a command. If
 * it is one command, it returns this position, otherwise -1.
 */
/* KJT 22/01/23: added 2int" type */
int Search_In_CmdTable(string)
     char *string;
{
  int aux;

  aux = 0;
  while (aux != cont_cmd) {
    if (strcomp(string,CmdTokenNameTable[aux].comand))
      return aux;
    else ++aux;
  }
  return(-1);
}

/* Search_In_StepTable
 * It searches in the step commands table if string is a command. If
 * it is one command, it returns this position, otherwise -1.
 */
/* KJT 22/01/23: added "int" type */
int Search_In_StepTable(string)
     char *string;
{
  int aux;

  aux = 0;
  while (aux != cont_step) {
    if (strcomp(string,StepTokenNameTable[aux].comand))
      return aux;
    else ++aux;
  }
  return(-1);
}


/* Get_CmdCommand
 * It returns the token of the command which commands table
 * position is pos.
 */
/* KJT 22/01/23: added 2int" type */
int Get_CmdCommand(pos)
     int pos;
{
  return(CmdTokenNameTable[pos].tokns);
}

/* Get_StepCommand
 * It returns the token of the command which commands table
 * position is pos.
 */
/* KJT 22/01/23: added 2int" type */
int Get_StepCommand(pos)
     int pos;
{
  return(StepTokenNameTable[pos].tokns);
}


/* Is_Cmd_Command
 * It returns the commands table position of the command string.
 * If string is not a command, it returns -1.
 */
static int Is_Cmd_Command(string)
     char *string;
{ int pos;

  LowerString(string);
  if ((pos = Search_In_CmdTable(string)) != -1)
    return(Get_CmdCommand(pos));
  return -1;
}

/* Is_Step_Command
 * It returns the commands table position of the command string.
 * If string is not a command, it returns -1.
 */
static int Is_Step_Command(string)
     char *string;
{ int pos;

  LowerString(string);
  if ((pos = Search_In_StepTable(string)) != -1)
    return(Get_StepCommand(pos));
  return -1;
}



/*----------------------------------------------------------------*/

/* WhichOption
 * return the option token related to char c
 */
int WhichOption( c )
     char c;
{
  /* char cs[2]; */

  switch (c){
  case 'a':
    return OPT_A;
  case 'b':
    return OPT_B;
  case 'c':
    return OPT_C;
  case 'd':
    return OPT_D;
  case 'e':
    return OPT_E;
  case 'g':
    return OPT_G;
  case 'i':
    return OPT_I;
  case 'o':
    return OPT_O;
  case 'p':
    return OPT_P;
  case 'q':
    return OPT_Q;
  case 's':
    return OPT_S;
  case 't':
    return OPT_T;
  case 'u':
    return OPT_U;
  case 'v':
    return OPT_V;
  case 'x':
    return OPT_X;
  case 'y':
    return OPT_Y;
  default :
    what_error = OPT_ERR;
    return ERROR;
  }
}

/*----------------------------------------------------------------*/



/* first_token
 * When first_token is TRUE:
 *    - identifiers in the input line are treated as command names.
 *    - numbers indicates a branch for Step mode (BRANCH token).
 * If first_token is FALSE:
 *    - identifiers in the input line are treated as IDENT tokens.
 *    - numbers are numbers *NUM token).
 */
static boolean first_token;


static int yylex_cmd(), yylex_step(), yylex_num(), yylex_expr();


/* yylex
 * This function provides the lexical analysis.
 */
int yylex()
{
  switch(lex_mode)
    { case CMDLEXMODE:
	return yylex_cmd();
      case NUMLEXMODE:
	return yylex_num();
      case EXPLEXMODE:
	return yylex_expr();
      case STEPLEXMODE:
	return yylex_step();
      default:
	Error("Unknown lex mode.");
      }
  return -1;
}


/* yylex_cmd
 * This function provides the lexical analysis.
 */
static int yylex_cmd()
{
  int c,aux,numb;

  pos_ctoken = 0;

  while ((c = gtchar()) == ' ' || c == '\t') ;

  if (c == '^')
    return ROOT;

  if (c == '\0') {
    return QUIT;
  }

  if (c == ',') {
    return c;
  }

  if (c == '\n') {
    return (int)NULL;
  }

  if (ischar2(c)) {
    while (isdigit(c) || ischar2(c) || (c=='-') || (c==':')) {
      ctoken[pos_ctoken++] = c;
      c = gtchar();
    }
    ungtc();
    ctoken[pos_ctoken] = '\0';
    LowerString(ctoken);
    if (first_token) {
      first_token = FALSE;
      if ( (aux = Is_Cmd_Command(ctoken)) != -1) {
	yylval.string = CopyString(ctoken);
	return aux;
      }
      else {
	return ERROR;
      }
    }
    else   {
      yylval.string = CopyString(ctoken);
      return IDENT;
    }
  }

  if (isdigit(c)) {
    while (isdigit(c)) {
      ctoken[pos_ctoken++] = c;
      c = gtchar();
    }
    ctoken[pos_ctoken] = '\0';
    numb = StringToInt(ctoken);
    if (isalpha(c)) {
      yylval.posic.num = numb;
      yylval.posic.mov = c;
      return POSIC;
    }
    else {
      ungtc();
      if (first_token)
	return ERROR;
      else {
	yylval.num = numb;
	return NUM;
      }
    }
  }

  if (c == '-')
    { c = gtchar();
      if (isalpha(c) != 0)
	{ yylval.option = c;
	  return WhichOption(c);
	}

      if (isdigit(c))
	{ ctoken[pos_ctoken++] = '-';
	  while (isdigit(c))
	    { ctoken[pos_ctoken++] = c;
	      c = gtchar();
	    }
	  ctoken[pos_ctoken] = '\0';
	  yylval.num = StringToInt(ctoken);
	  if (isalpha(c) == 0)
	    { ungtc();
	      return NUM;
	    }
	  else  { yylval.posic.num = yylval.num;
		  yylval.posic.mov = c;
		  return POSIC;
		}
	}
      ungtc();
      c = '-';
    }

  if (c == '+')
    { c = gtchar();
      if (isdigit(c))
	{ while (isdigit(c) != 0)
	    { ctoken[pos_ctoken++] = c;
	      c = gtchar();
	    }
	  ctoken[pos_ctoken] = '\0';
	  yylval.num = StringToInt(ctoken);
	  if (isalpha(c) == 0)  /* c no es letra */
	    { ungtc();
	      return NUM;
	    }
	  else  { yylval.posic.num = yylval.num;
		  yylval.posic.mov = c;
		  return POSIC;
		}
	}
      else { ungtc();
	     c = '+';
	   }
    }

  return ERROR;
}


/* yylex_step
 * This function provides the lexical analysis for the STEP mode.
 */
static int yylex_step()
{
  int c,aux,numb;

  pos_ctoken = 0;

  while ((c = gtchar()) == ' ' || c == '\t') ;

  if (c == '\0') {
    return QUIT;
  }

  if (c == '\n') {
    return (int)NULL;
  }

  if (ischar2(c) || (c=='?')) {
    while (isdigit(c) || ischar2(c) || (c=='-') || (c==':') || (c=='?')) {
      ctoken[pos_ctoken++] = c;
      c = gtchar();
    }
    ungtc();
    ctoken[pos_ctoken] = '\0';
    LowerString(ctoken);
    if (first_token) {
      first_token = FALSE;
      if ( (aux = Is_Step_Command(ctoken)) != -1) {
	yylval.string = CopyString(ctoken);
	return aux;
      }
      else
	return ERROR;
    }
    else   {
      yylval.string = CopyString(ctoken);
      return IDENT;
    }
  }

  if (isdigit(c)) {
    while (isdigit(c)) {
      ctoken[pos_ctoken++] = c;
      c = gtchar();
    }
    ungtc();
    ctoken[pos_ctoken] = '\0';
    numb = StringToInt(ctoken);
    if (first_token) {
      first_token = FALSE;
      yylval.num = numb;
      return BRANCH;
    }
    else   {
      yylval.num = numb;
      return NUM;
    }
  }


  if (c == '-') {
    c = gtchar();
    if (isalpha(c) != 0) {
      yylval.option = c;
      return WhichOption(c);
    }
    if (isdigit(c)) {
      ctoken[pos_ctoken++] = '-';
      while (isdigit(c)) {
	ctoken[pos_ctoken++] = c;
	c = gtchar();
      }
      ctoken[pos_ctoken] = '\0';
      yylval.num = StringToInt(ctoken);
      if (isalpha(c) == 0) {
	ungtc();
	if (first_token) {
	  first_token = FALSE;
	  return BRANCH;
	}
	else {
	  return NUM;
	}
      }
      else
	return ERROR;
    }
    ungtc();
    c = '-';
  }

  if (c == '+')
    { c = gtchar();
      if (isdigit(c))
	{ while (isdigit(c) != 0)
	    { ctoken[pos_ctoken++] = c;
	      c = gtchar();
	    }
	  ctoken[pos_ctoken] = '\0';
	  yylval.num = StringToInt(ctoken);
	  if (isalpha(c) == 0)  /* c no es letra */
	    { ungtc();
	      return NUM;
	    }
	  else
	    return ERROR;
	}
      else { ungtc();
	     c = '+';
	   }
    }

  return ERROR;
}



/* yylex_num
 * This function provides the lexical analysis for natural numbers.
 */
static int yylex_num()
{
  int c,numb;

  pos_ctoken = 0;

  while ((c = gtchar()) == ' ' || c == '\t') ;

  if (c == '\0') return (int)NULL;

  if (c == '\n') return (int)NULL;

  if (isdigit(c)) {
    while (isdigit(c)) {
      ctoken[pos_ctoken++] = c;
      c = gtchar();
    }
    ctoken[pos_ctoken] = '\0';
    numb = StringToInt(ctoken);
    if (isalpha(c))
      return ERROR;
    else {
      ungtc();
      yylval.num = numb;
      return NUM;
    }
  }
  else
    return NUM;
}



/* yylex_expr
 * This function provides the lexical analysis.
 */
static int yylex_expr()
{
  int c;

  pos_ctoken = 0;

  while (isspace(c=gtchar())) ;

  if (c == EOF)
    return 0;

  if (c == '\0')
    return (int)NULL;

  if (c == '\n')
    return c;

  if (iscomma(c)||isleftpar(c)||isrightpar(c))
    return c;

  if (isalnum(c)) {
    while (isalnum(c) || (c == '_')) {
      ctoken[pos_ctoken++] = c;
      c = gtchar();
    }
    ungtc();
    ctoken[pos_ctoken] = '\0';
    LowerString(ctoken);
    yylval.string = CopyString(ctoken);
    if (strcmp(ctoken,"of") == 0)
      return OF;
    else if (ctoken[pos_ctoken] == '_')
      return ERROR;
    else
      return IDENT;
  }

  if (isspecchar(c)) {
    while (isspecchar(c)) {
      ctoken[pos_ctoken++] = c;
      c = gtchar();
    }
    ungtc();
    ctoken[pos_ctoken] = '\0';
    yylval.string = CopyString(ctoken);
    return IDENT;
  }

  return ERROR;
}



/******************************************************************
 *
 *
 *
 *******************************************************************/


/* InitInterpreter
 * Inits the module.
 */
/*
   void InitInterpreter()
   {
   lex_mode = CMDLEXMODE;
   }
   */


/******************************************************************
 *
 *   Command: Move.
 *
 *******************************************************************/

/* ECmove
 * Execute the command move.
 * contmove is the number of movements and move_lst is the list
 * of movements.
 */
static void ECmove(contmove,move_lst)
     int contmove;
     moveTyp *move_lst;
{ int i;

  if (GetCursor() != NULL)
    { for (i = 0;i<contmove;i++)
	if (move_lst[i].mvType == POSITION)
	  {(void)printf("move %d%c\n",move_lst[i].mv.mvrel.num,
			move_lst[i].mv.mvrel.mov);
	   (void)Move(move_lst[i].mv.mvrel.num,move_lst[i].mv.mvrel.mov);
	 }
	else if (move_lst[i].mvType == STRING)
	  {(void)printf("move %s\n",move_lst[i].mv.proc);
	   (void)MoveProc(move_lst[i].mv.proc);
	 }
	else if (move_lst[i].mvType == CHAR)
	  {(void)printf("move %c\n",move_lst[i].mv.root);
	   (void)MoveRoot();
	 }
    }
  else
    (void)printf("There is not any tree to move.\n");
  (void)printf("\n");
}


/*----------------------------------------------------------------*/

/* HelpComm
 * It writes the sinopsis of the command which token is its
 * parameter, token.
 * If h id TRUE then a explication is given.
 */
static void HelpComm(token,h)
     int token;
     boolean h;
{
  switch (token)
    { case REWRITE:
	Rewrite_Help(h);
	break;
      case LOAD :
	Load_Help(h);
	break;
      case PRINT :
	Print_Help(h);
	break;
      case SAVE :
	Save_Help(h);
	break;
      case DATA :
	Data_Help(h);
	break;
      case EXPAND :
	Expand_Help(h);
	break;
      case FREE :
	Free_Help(h);
	break;
      case VAR :
	Var_Help(h);
	break;
      case TEST :
	Test_Help(h);
	break;
      case ONE :
	One_Help(h);
	break;
      case IT:
	IT_Help(h);
	break;
      case SET:
	Set_Help(h);
	break;
      case CMD:
	Cmd_Help(h);
	break;
      case STAT:
	Stat_Help(h);
	break;
      case STEP :
	Step_Help(h);
	break;
      case MOVE :
	Move_Help(h);
	break;
      case QUIT :
	Quit_Help(h);
	break;
      case HELP :
	Help_Help(h);
	break;
#ifdef INVEXP
      case PI :
	PI_Help(h);
	break;
      case VC :
	VC_Help(h);
	break;
      case VCNR:
	VCNR_Help(h);
	break;
      case K:
	K_Help(h);
	break;
#endif /* INVEXP */

      default:
	(void)printf("  No help entry.\n");
      }
}


/*----------------------------------------------------------------*/

/* EChelp
 * Executes the command help.
 * cmd is the name of a command.
 */
static void EChelp(cmd)
     char *cmd;
{
  int aux;

  (void)printf("help ");
  if (cmd[0]!='\0') {
    (void)printf("%s\n\n",cmd);
    if ((aux = Is_Cmd_Command(cmd)) != -1)
      HelpComm(aux,TRUE);
    else
      (void)printf("%s: Unknown command\n",cmd);
  }
  else {
    (void)printf("\n\n");
    HelpComm(HELP,FALSE);
    HelpComm(LOAD,FALSE);
    HelpComm(SET,FALSE);
    HelpComm(CMD,FALSE);
    HelpComm(PRINT,FALSE);
#ifdef SDEBUG
    HelpComm(SAVE,FALSE);
#endif
    HelpComm(DATA,FALSE);
#if defined(sun) || defined(MSDOS)
    HelpComm(STAT,FALSE);
#endif
    HelpComm(MOVE,FALSE);
    HelpComm(QUIT,FALSE);
    (void)printf("  -------------- EXPANSION ---------------\n");
    HelpComm(FREE,FALSE);
    HelpComm(EXPAND,FALSE);
    HelpComm(VAR,FALSE);
    HelpComm(IT,FALSE);

    (void)printf("  ---------- TESTING EXPANSION -----------\n");
    HelpComm(TEST,FALSE);
    HelpComm(ONE,FALSE);


#ifdef INVEXP
    (void)printf("  ---------- INVERSE EXPANSION -----------\n");
    HelpComm(VC,FALSE);
    HelpComm(VCNR,FALSE);
    HelpComm(K,FALSE);
    HelpComm(PI,FALSE);
#endif /* INVEXP */

    (void)printf("  -------------- SIMULATION --------------\n");
    HelpComm(STEP,FALSE);
    HelpComm(REWRITE,FALSE);
  }
  (void)printf("\n");
}


/*----------------------------------------------------------------*/


/* code
 * It executes the command line input getting all commands with their
 * arguments of the internal stack.
 */
void code()
{
  switch (command_token)
    {
#ifdef INVEXP
    case VC:
      ECvis_com(numGate1,gate_list1,numGate2,gate_list2);
      CleanLinesMovements();
      break;
    case VCNR:
      ECvc_nrec(numGate1,gate_list1,numGate2,gate_list2);
      CleanLinesMovements();
      break;
    case K:
      ECk(numGate1,gate_list1,numGate2,gate_list2);
      CleanLinesMovements();
      break;
    case PI:
      ECpure_int(numGate1,gate_list1);
      CleanLinesMovements();
      break;
#endif /* INVEXP */
    case HELP:
      EChelp(command_name);
      break;
    case QUIT:
      ECquit();
      break;
    case REWRITE :
      ECrewrite(expr_rw);
      lex_mode = CMDLEXMODE;
      break;
    case LOAD :
      (void)ECload(CopyString(str_empty),CopyString(str_empty));
      break;
    case PRINT :
      switch(lex_mode) {
      case CMDLEXMODE:
	ECprint(lengthOpcList,optionList,depth,outfile_name,PrintString);
	break;
      case STEPLEXMODE:
	ECstep_print(lengthOpcList,optionList,depth,outfile_name,PrintString);
	break;
      default:
	(void)printf("     Lex mode error.\n\n");
      }
      break;
    case SAVE :
      ECsave(outfile_name,PrintString);
      break;
    case DATA :
      ECdata(option,low_limit,high_limit);
      break;
    case EXPAND :
      ECexpand(depth,lengthOpcList,optionList);
      CleanLinesMovements();
      break;
    case FREE :
      ECfree(depth,lengthOpcList,optionList);
      CleanLinesMovements();
      break;
    case VAR :
      ECvar(depth,lengthOpcList,optionList);
      CleanLinesMovements();
      break;
    case TEST :
      ECtest(lengthOpcList,depth,success_event,process_name,optionList,
	     expected_response,bhsize,seed,percentage,verbose_level);
      CleanLinesMovements();
      break;
    case SET :
      ECset( env_variable, env_value );
      break;
    case CMD :
      ECcmd( cmd_file );
      break;
    case ONE :
      for ( ; one_execs>0; one_execs-- )
	seed = ECone(depth,success_event,process_name,seed,
		     lengthOpcList,optionList,one_execs);
      CleanLinesMovements();
      break;
    case IT :
      ECit(lengthOpcList,depth,success_event,process_name,optionList);
      CleanLinesMovements();
      break;
    case STAT :
      ECstat();
      break;
    case MENU :
      ECstep_menu();
      break;
    case STEP :
      { BehTyp b,b_test;
	ListTyp dvl;
	DescriptorTyp sed, proc;
	SVdescriptorTyp sv;

	lex_mode = STEPLEXMODE;

	if (ECstep_start_CheckBehEventTest(success_event, process_name,
					   &sed, &proc,
					   lengthOpcList, optionList,
					   undos_num )) {
	  dvl = ECstep_start_GetUnassignedVars();
	  sv = CreateSV();
	  ECstep_start_ReadParameters(dvl,&sv);
	  Disp_list(dvl);
	  b = ECstep_start_Behaviour(&sv);
	  FreeSV(&sv);

	  b_test = ECstep_start_ComposeWithTest( b, sed, proc );
	  if (b_test == NULL) {
	    lex_mode = CMDLEXMODE;
	  }
	  else {
	    ECstep_start_Expan(b_test,undos_num);
	    ECstep_menu();
	  }
	}
	else
	  lex_mode = CMDLEXMODE;
	CleanLinesMovements();
	break;
      }
    case EXIT:
      ECstep_exit();
      lex_mode = CMDLEXMODE;
      break;
    case TRACE :
      ECstep_trace();
      break;
    case UNDO :
      (void)ECstep_undo();
      break;
    case BRANCH :
      ECstep_branch(branch);
      ECstep_menu();
      break;
    case SYNC :
      ECstep_sync(branch, process_name);
      break;
    case SELECT :
      ECstep_select(number_list);
      Disp_list(number_list);
      break;
    case STEPHELP :
      ECstep_help();
      break;
    case REFUSED :
      (void)ECstep_refused();
      break;
    case MOVE:
      if (num_mov!=0) {
	ECmove(num_mov,movement_tab);
	CleanLinesMovements();
      }
      else {
	(void)printf("\n");
	PrintMoves(PrintString,GetCursor(),0,TRUE);
	(void)printf("\n");
      }
      break;
    }
}


/******************************************************************
 *
 *  Resolving expression. (ExpCell to ExprTyp).
 *
 *******************************************************************/

/* NewExpCell
 * Get memory for a new cell
 */
static PExpCellTyp NewExpCell()
{
  PExpCellTyp c;

  c = (PExpCellTyp) emalloc(sizeof(ExpCellTyp));
  createdExpCell = Insert_list((DataListTyp)c,createdExpCell);
  c->name = NULL;
  c->pos_dname = NULL;
  c->infix = FALSE;
  c->dsort = 0;
  c->argl = NULL;
  return c;
}


/* DispExpCell
 * Free memory of a cell
 */
static void DispExpCell( c )
     PExpCellTyp    c;
{
  Disp_list(c->pos_dname);
  Disp_list(c->argl);
  free((char*)c);
}


/* FreeExpCell
 * Free the memory allocated by the ExpCell structs.
 */
static void FreeExpCell()
{
  Free_list(createdExpCell,DispExpCell);
  createdExpCell = NULL;
}


/* PrintExpCell
 * Prints ExpCell structs.
 * "pstr" is the function used to print strings.
 * Note: IntToString loss memory.
 */
static void PrintExpCell(c,pstr)
     PExpCellTyp    c;
     void (*pstr)();
{
  ListTyp al;

  if (c!=NULL) {
    pstr(" ");
    pstr(c->name);
    pstr(".");
    PrintInt(pstr,c->dsort);
    pstr("{");
    Print_list(c->pos_dname,IntToString,pstr);
    pstr("} (");
    for (al=c->argl ; al!=NULL ; al=Next_list(al))
      PrintExpCell((PExpCellTyp)LookInfo_list(al),pstr);
    pstr(")");
  }
}

/*----------------------------------------------------------------*/

/* SortArg_Fix_SortFather
 * Checks that the sort of the arguments are possible according
 * with the sort of the father operation.
 * Impossible arguments are deleted.
 */
static void SortArg_Fix_SortFather(c)
     PExpCellTyp c;
{
  ListTyp al,ldc,lsa,s,nexts;
  ListTyp lscai; /* list of sorts of c. Argument i. */
  int n,i;
  PExpCellTyp a;

  for (al=c->argl,n=0 ; (al!=NULL) && (!ResError) ; al=Next_list(al),n++) {

    lscai = Create_list();
    for (ldc = c->pos_dname ; ldc!=NULL ; ldc=Next_list(ldc)) {
      lsa = GetO_argl((DescriptorTyp)LookInfo_list(ldc));
      for (i=1 ; i<=n ; i++)
	lsa = Next_list(lsa);
      lscai = Insert_list(LookInfo_list(lsa),lscai);
    }

    a= (PExpCellTyp) LookInfo_list(al);
    lsa = a->pos_dname;
    for (s=lsa ; s!=NULL ; s=nexts) {
      nexts = Next_list(s);
      if (!In_list((DataListTyp)GetO_sort((DescriptorTyp)LookInfo_list(s)),
		   lscai,EqInt)) {
	lsa = DeleteNode_list(s,lsa);
	changes = TRUE;
      }
    }
    a->pos_dname = lsa;
    Disp_list(lscai);

    if (a->pos_dname==NULL) {
      ResError = TRUE;
      if (c->infix)
	(void)sprintf(ResErrorMsg,
		      "\n      ERROR: _%s_ %s\n\n",
		      c->name,"operation undefined.");
      else
	(void)sprintf(ResErrorMsg,
		      "\n      ERROR: %s %s\n\n",
		      c->name,"operation undefined.");
    }
  }
  for (al=c->argl; (al!=NULL) && (!ResError) ; al=Next_list(al))
    SortArg_Fix_SortFather((PExpCellTyp) LookInfo_list(al));
}

/*----------------------------------------------------------------*/

/* SortFather_Fix_SortArg
 * Checks that the fathers are possible according with the sort of
 * the arguments.
 * Impossible fathers are deleted.
 */
static void SortFather_Fix_SortArg(c)
     PExpCellTyp c;
{
  ListTyp al,lds,ldc,d,nextd,lda;
  PExpCellTyp a;
  int n,i;
  boolean found;

  ldc = c->pos_dname;
  for (d=ldc ; (d!=NULL) && (!ResError) ; d=nextd) {
    nextd = Next_list(d);
    lds = GetO_argl((DescriptorTyp)LookInfo_list(d));
    n = 0;
    while(lds!=NULL) {
      al = c->argl;
      for (i=1 ; i<=n ; i++)
	al = Next_list(al);
      a = (PExpCellTyp) LookInfo_list(al);

      found = FALSE;
      for (lda=a->pos_dname ; (lda!=NULL)&&(!found) ; lda=Next_list(lda))
	if ((DescriptorTyp)LookInfo_list(lds) ==
	    GetO_sort((DescriptorTyp)LookInfo_list(lda)))
	  found = TRUE;

      if (!found) {
	ldc = DeleteNode_list(d,ldc);
	changes = TRUE;
	break;
      }

      lds=Next_list(lds);
      n++;
    }
    c->pos_dname = ldc;

    if (c->pos_dname==NULL) {
      ResError = TRUE;
      if (c->infix)
	(void)sprintf(ResErrorMsg,"\n      ERROR: _%s_ %s\n\n",
		      c->name,"operation undefined.");
      else
	(void)sprintf(ResErrorMsg,"\n      ERROR: %s %s\n\n",
		      c->name,"operation undefined.");
    }
  }
  for (al=c->argl; (al!=NULL) && (!ResError) ; al=Next_list(al))
    SortFather_Fix_SortArg((PExpCellTyp)LookInfo_list(al));
}

/*----------------------------------------------------------------*/

/* CheckNumArg
 * Checks the number of arguments of the operations.
 * Wrong operations are deleted.
 */
static void CheckNumArg(c)
     PExpCellTyp c;
{
  int nson;
  ListTyp ld,i,nexti;

  nson = Length_list(c->argl);
  ld = c->pos_dname;
  for (i=ld ; i!=NULL ; i=nexti) {
    nexti = Next_list(i);
    if (Length_list(GetO_argl((DescriptorTyp)LookInfo_list(i)))!=nson)
      ld = DeleteNode_list(i,ld);
  }
  c->pos_dname=ld;
  if (c->pos_dname==NULL) {
    ResError = TRUE;
    if (c->infix)
      (void)sprintf(ResErrorMsg,"\n      ERROR: _%s_ %s\n\n",
		    c->name,"operation undefined.");
    else
      (void)sprintf(ResErrorMsg,"\n      ERROR: %s %s\n\n",
		    c->name,"operation undefined.");
  }

  for (i=c->argl; (i!=NULL) && (!ResError) ; i=Next_list(i))
    CheckNumArg((PExpCellTyp)LookInfo_list(i));
}

/*----------------------------------------------------------------*/

/* Get_possibles
 * Returns a list with the possible descriptors.
 */
static ListTyp Get_possibles(name,dsort,infix)
     char          *name;
     DescriptorTyp dsort;
     boolean       infix;
{
  ListTyp lp;
  int i;

  lp = Create_list();
  for (i=LastTableO() ; i>0 ; i--)
    if (dsort==0) {
      if ((strcmp(GetO_name(i),name)==0) && (GetO_infix(i)==infix))
	lp = Insert_list((DataListTyp)i,lp);
    }
    else
      if ((strcmp(GetO_name(i),name)==0) && (GetO_sort(i)==dsort)
	  && (GetO_infix(i)==infix))
	lp = Insert_list((DataListTyp)i,lp);
  return lp;
}


/* Possibles
 * Calculates the possible descriptors for all the ExpCell.
 */
static boolean Possibles( c )
     PExpCellTyp c;
{
  ListTyp al;

  if (c!=NULL) {
    c->pos_dname = Get_possibles(c->name,c->dsort,c->infix);
    if (c->pos_dname==NULL) {
      ResError = TRUE;
      if (c->infix)
	(void)sprintf(ResErrorMsg,
		      "\n      ERROR: _%s_ %s\n\n",
		      c->name,"operation undefined.");
      else
	(void)sprintf(ResErrorMsg,
		      "\n      ERROR: %s %s\n\n",
		      c->name,"operation undefined.");
    }
    for (al=c->argl ; (al!=NULL) && (!ResError) ; al=Next_list(al))
      Possibles( (PExpCellTyp)LookInfo_list(al) );
  }
}

/*----------------------------------------------------------------*/

/* ExamResult
 * Examines the result seachching ExpCell with zero or more than
 * one possible descriptors.
 */
static void ExamResult(c)
     PExpCellTyp    c;
{
  ListTyp al;
  int l;

  if (!ResError) {
    l = Length_list(c->pos_dname);
    if (l==0) {
      ResError = TRUE;
      if (c->infix)
	(void)sprintf(ResErrorMsg,
		      "\n      ERROR: _%s_ %s\n\n",
		      c->name,"operation undefined.");
      else
	(void)sprintf(ResErrorMsg,
		      "\n      ERROR: %s %s\n\n",
		      c->name,"operation undefined.");
    }
    else if (l>1) {
      ResError = TRUE;
      if (c->infix)
	(void)sprintf(ResErrorMsg,
		      "\n      ERROR: _%s_ %s\n\n",
		      c->name,"operation ambiguous.");
      else
	(void)sprintf(ResErrorMsg,
		      "\n      ERROR: %s %s\n\n",
		      c->name,"operation ambiguous.");
    }
  }
  for (al=c->argl ; al!=NULL ; al=Next_list(al))
    ExamResult((PExpCellTyp)LookInfo_list(al));
}

/*----------------------------------------------------------------*/

/* ExpCellToExpr
 * Translation: ExpCellTyp to ExprTyp.
 */
static ExprTyp ExpCellToExpr( c )
     PExpCellTyp    c;
{
  ExprTyp e;
  ListTyp al;

  e = MakeE((DescriptorTyp)LookInfo_list(c->pos_dname),OperationC);
  for (al=c->argl ; al!=NULL ; al=Next_list(al))
    AddArgE(e,ExpCellToExpr((PExpCellTyp)LookInfo_list(al)));
  return e;
}

/*----------------------------------------------------------------*/

/* ResExpr
 * Transforms the PExpCellTyp "c" into a ExprTyp if the expression
 * can exist, or return NULL.
 */
static ExprTyp ResExpr(c)
     PExpCellTyp c;
{
  ExprTyp e;

  ResError = FALSE;
  Possibles(c);
  CheckNumArg(c);
  do {
    changes = FALSE;
    SortArg_Fix_SortFather(c);
    SortFather_Fix_SortArg(c);
  } while (changes);
  ExamResult(c);
  if (!ResError)
    e = ExpCellToExpr(c);
  else
    e = NULL;
  return e;
}

/*----------------------------------------------------------------*/

/* ReadNum
 * Reads a natural number form the keyboard.
 */
int ReadNum()
{
  int r, old_lex_mode;

  /*
     getline(line);
     */
  ReadLine(getline(""));

  InputLineIsEmpty = FALSE;
  old_lex_mode = lex_mode;
  lex_mode = NUMLEXMODE;
  Reset_values_parsed();
  if(yyparse()) {
    (void)printf("   Number: Syntax error.\n");
    r = -1;
  }
  else
    r = yyval.num;
  lex_mode = old_lex_mode;
  return r;
}

/*----------------------------------------------------------------*/

/* ReadExpr
 * Reads an expression from the keyboard and returns its associated
 * ExprTyp in "*pe".
 * If there is an error FALSE if returned.
 * prompt is the prompt.
 * expSort is the expected sort.
 */
boolean ReadExpr( prompt, pe, expSort )
     char          * prompt;
     ExprTyp       * pe;
     DescriptorTyp expSort;
{
  boolean result;
  int old_lex_mode;

  InputLineIsEmpty = FALSE;
  ResError         = FALSE;
  ReadLine(getline(prompt));
  old_lex_mode = lex_mode;
  lex_mode     = EXPLEXMODE;
  expectedSort = expSort;
  Reset_values_parsed();
  if(yyparse()) {
    (void)printf("\n      Expression: Syntax error.\n\n");
    *pe = NULL;
    result = FALSE;
  }
  else {
    FreeExpCell();
    if (InputLineIsEmpty) {
      *pe = NULL;
      result = TRUE;
    }
    else {
      *pe = yyval.expr;
      result = !ResError;
    }
  }
  lex_mode = old_lex_mode;
  expectedSort = 0;
  return result;
}


/*----------------------------------------------------------------*/

/* StringToExpr
 * Takes the string "s" and returns its associated ExprTyp in "*pe".
 * If there is an error FALSE if returned.
 * "expSort" is the expected sort.
 */
boolean StringToExpr( s, pe, expSort )
     char          * s;
     ExprTyp       * pe;
     DescriptorTyp expSort;
{
  boolean result;
  int old_lex_mode;

  if (strlen(s)>=MAX_LINE) {
    printError("\n      Error: Expression too long.\n\n");
    *pe = NULL;
    result = FALSE;
  }

  InputLineIsEmpty = FALSE;
  ResError         = FALSE;
  (void)sprintf(line,"%s",s);
  pos_line = -1;
  old_lex_mode = lex_mode;
  lex_mode     = EXPLEXMODE;
  expectedSort = expSort;
  Reset_values_parsed();
  if(yyparse()) {
    printError("\n      Expression: Syntax error.\n\n");
    *pe = NULL;
    result = FALSE;
  }
  else {
    FreeExpCell();
    if (InputLineIsEmpty) {
      *pe = NULL;
      result = TRUE;
    }
    else {
      *pe = yyval.expr;
      result = !ResError;
    }
  }
  lex_mode = old_lex_mode;
  expectedSort = 0;
  return result;
}


/*----------------------------------------------------------------*/

/* ParseLine
 * interprets the command line placed in line[]
 */
static void ParseLine()
{
  int old_mode;

  what_error       = 0;
  ResError         = FALSE;
  InputLineIsEmpty = FALSE;
  numMove          = 0;
  numOpc           = 0;
  old_mode         = lex_mode;
  first_token      = TRUE;
  FreeExpCell();
  Reset_values_parsed();
  if ( yyparse() || what_error ) {
    switch(lex_mode)
      { case CMDLEXMODE:
	case STEPLEXMODE:
	  switch ( what_error ){
	  case OPT_ERR:
	    printTarget("      Option error.\n\n");
	    break;
	  default:
	    printTarget("      Command error.\n\n");
	    break;
	  }
	  break;
	case EXPLEXMODE:
	  printTarget("      Expression: Syntax error.\n\n");
	  break;
	default:
	  Error("Lex mode error.");
	}
    lex_mode = old_mode;
  }
  else {
    code();
  }
}


/* CommandInt
 * Command Interpreter.
 */
void CommandInt()
{
  lex_mode = CMDLEXMODE;
  while (TRUE) {
    switch(lex_mode)
      { case CMDLEXMODE:
	  ReadLine(getline("lola> "));
	  break;
	case EXPLEXMODE:
	  ReadLine(getline("expr> "));
	  break;
	case STEPLEXMODE:
	  ReadLine(getline("<n>,Undo,Menu,Refused,Sync,Print,Trace,Exit,?> "));
	  break;
	default:
	  Error("Lex mode error.");
	}
    ParseLine();
  }
}

/*----------------------------------------------------------------*/

/* CommandLineInt
 * Command Line Interpreter.
 * Take a command line as input, execute it and return.
 * Leave the LEX MODE unchanged.
 */
void CommandLineInt( input_line )
     char * input_line;
{
  ReadLine( input_line );
  ParseLine();
}

/*----------------------------------------------------------------*/

















