/***********************************
  (C) Copyright 1994; dit/upm
   Distributed under the conditions stated in the
   TOPO General Public License (see file LICENSE)
 ***********************************
 * $Log: elib.c,v $
 * Revision 1.2  1994/11/08  16:52:49  lotos
 * fix call to sprintf for portability
 *
 * Revision 1.1  1994/11/08  15:46:55  lotos
 * Initial revision
 *
 ***********************************/

#ifndef lint
static char rcsid[]= "$Id: elib.c,v 1.2 1994/11/08 16:52:49 lotos Exp $";
#endif

#define elib_IMP

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "swbus.h"

/* KJT 20/01/23: added function prototypes */

PUBLIC int _xd_v_sort(char *snm);

/******* private variables ******/

/******* private functions ******/

PRIVATE FILE*
efopen(file, mode)
     char* file;
     char* mode;
{
  FILE* fp;
  FILE* fopen();

  if ((fp= fopen (file, mode)) == NULL) {
    (void) fprintf (stderr,
		    "cannot open file %s mode %s\n",
		    file, mode);
    return NULL;
  }
  return fp;
} /* end of efopen */


PRIVATE int
isinlist (element, list)
     int     element;
     INTlist list;
{
  for (;list != NULL; list= INTtail (list))
      if (element == INThead (list))
	return TRUE;

  return FALSE;
} /* end of isinlist */

/*
------------------------- PTEXT ------------------------------------

     PARAMETERS:
		 - fd: file where text is going to be written
		 - text: text to be written

     DESCRIPTION:
		 - It wirttes to file "fd"
		   the string of array "text".
---------------------------------------------------------------------
*/

PRIVATE void
ptext   ( fd, text)
  FILE* fd;
  char* text[];
{
	int     i;

	for (i= 0; text[i] != NULL; i++)
		(void) fprintf (fd, "%s\n", text[i]);
}

/*
-------------------------  ILDIMSG ------------------------------------

     PARAMETERS:
		 - msg: msg to inform
     DESCRIPTION:
		 - It produces an information message
---------------------------------------------------------------------
*/
PUBLIC void
ildimsg (msg)
	char*	msg;
{
  (void) printf ("%s(%d): %s\n", prog_name, lineno, msg);
}

/*
-------------------------  ILDIREPORT ------------------------------------

     PARAMETERS:
		 - msg: msg to report
     DESCRIPTION:
		 - It produces a report
---------------------------------------------------------------------
*/
PUBLIC void
ildireport (msg)
	char*	msg;
{
  (void) printf ("%s(%d): %s\n", prog_name, lineno-1, msg);
  (void) printf ("      -- try help\n");
  ++errorcount;
}

/*
----------------------------------------------------------
help messages
----------------------------------------------------------
*/

PRIVATE char *texthelp [] = {
      "  LOAD file_name",
      "  EXEC file_name",
      "  RENAME [ identifier IS identifier ]",
      "  REWRITE expression",
      "  CHECK expression '=' expression",
      "  VAR variable_declaration",
      "  LET identifier '=' expression",
      "  FREE _identifier_free_list [ ':' _sort_identifier ]",
      "  RESET _identifier_reset_list [ ':' _sort_identifier ]",
      "  IF '(' expression '=' expression ')' cmdl [ '::' cmdl ] ';'",
      "  DISPLAY [ item ]",
      "  SETDEB [deb]",
      "  TRACE [ON/OFF]",
      "  STAT stat",
      "  WRITE string",
      "  RESET",
      "  QUIT",
      "  HELP",
      "",
      "  use \"help help\" for more information",
      NULL
};

PRIVATE char *textchelp [] = {
      "  HELP [CMD]",
      "    it shows help information",
      "    HELP     = show command list",
      "    HELP CMD = shows information about CMD command",
      NULL
};

PRIVATE char *textload [] = {
      "  LOAD file",
      "   It loads the file <file>.ldi",
      "",
      NULL
};

PRIVATE char *textexec [] = {
      "  EXEC file",
      "   use <file> as command input",
      NULL
};

PRIVATE char *textrename [] = {
      "  RENAME di1 IS id2",
      "    uses <id2> as new name for command <id1>",
      "    It may be used to avoid name colision with LOTOS operations",
      "",
      "  RENAME",
      "    shows the current list of renaming",
      NULL
};

PRIVATE char *textrewrite [] = {
      "  REWRITE expression",
      "    rewrite the <expresion>, and shows the result",
      NULL
};

PRIVATE char *textcheck [] = {
      "  CHECK exp1 '=' exp2",
      "   rewrite <exp1> and <exp2>",
      "   if the resulting expressions are equal says: OK",
      "   if not says: NOK",
      NULL
};

PRIVATE char *textvar [] = {
      "  VAR variable_declaration",
      "   declares a list of variables according with the next syntax:",
      "     variable_declaration ::= [ identifier_declaration + ',' ]",
      "     identifier_declaration ::= identifier_declaration_list ':' sort_identifier",
      "     identifier_declaration_list ::= [ identifier + ',' ]",
      NULL
};

PRIVATE char *textlet [] = {
      "  LET identifier '=' expression",
      "     assign to \"identifier\" the result of evaluate the \"expression\"",
      NULL
};

PRIVATE char *textfree [] = {
      "  FREE _identifier_free_list [ ':' _sort_identifier ]",
      "   free the variables previously declared",
      "     _identifier_free_list ::= [ identifier + ',' ]",
      NULL
};

PRIVATE char *textrest [] = {
      "  RESET _identifier_reset_list [ ':' _sort_identifier ]",
      "   it set the variables ready to be freed",
      "     _identifier_reset_list ::= [ identifier + ',' ]",
      NULL
};

PRIVATE char *textif [] = {
      "  IF '(' exp1 '=' exp2 ')' cmdl1 [ ':' cmdl2 ] ';'",
      "   it rewrites <exp1> and <exp2>",
      "   if <exp1> = <exp2> executes cmdl1",
      "   if not executes cmdl2 if exist",
      NULL
};

PRIVATE char *textdisplay [] = {
      "  DISPLAY [ item ]",
      "   item = SORTS | OPNS | EQNS | VARS",
      "   if not item display current specification",
      "   if not, the specified item is displayed",
      NULL
};

PRIVATE char *textsetdeb [] = {
      "  SETDEB [deb]",
      "    set debug level",
      "    deb = 0 | 1 | 2 ",
      "      0 = no debug",
      "      1 = shows rewritte rules being applied",
      "      2 = shows rewritte rules and expression being rewritten",
      "    if not debug level is specified, it shows curren debug level",
      NULL
};

PRIVATE char *texttrace [] = {
      "  TRACE [ON/OFF]",
      "    TRACE = shows current trave level",
      "    TRACE ON = echo input commands",
      "    TRACE OFF= does not echo input commands",
      "    TRACE ECHO= echo input commands using stdin",
      NULL
};

PRIVATE char *textstat [] = {
      "  STAT stat",
      "    shows information about the number of rewriting rules applied",
      "    STAT 0 = Shows total number of rules applied",
      "    STAT 1 = Shows total and partial number of rules applied",
      NULL
};

PRIVATE char *textwrite [] = {
      "  WRITE string",
      "   writes on the output the <string>",
      "   string = \"list_of_characters\"",
      NULL
};

PRIVATE char *textreset [] = {
      "  RESET",
      "   reset counter for stat information",
      NULL
};
PRIVATE char *textquit [] = {
      "  QUIT",
      "   exit ildi",
      NULL
};

PUBLIC void
usrbreak()
{
  (void) signal (SIGINT, usrbreak);
  usrb = TRUE;
  return;
}

PUBLIC void
chelp (cmd)
  char* cmd;
{
  if (0 == strcmp(cmd, ""))
	  ptext (stdout, texthelp);
  else if (0 == strcmp(cmd, "load"))
	  ptext (stdout, textload);
  else if (0 == strcmp(cmd, "exec"))
	  ptext (stdout, textexec);
  else if (0 == strcmp(cmd, "rename"))
	  ptext (stdout, textrename);
  else if (0 == strcmp(cmd, "rewrite"))
	  ptext (stdout, textrewrite);
  else if (0 == strcmp(cmd, "check"))
	  ptext (stdout, textcheck);
  else if (0 == strcmp(cmd, "var"))
	  ptext (stdout, textvar);
  else if (0 == strcmp(cmd, "let"))
	  ptext (stdout, textlet);
  else if (0 == strcmp(cmd, "free"))
	  ptext (stdout, textfree);
  else if (0 == strcmp(cmd, "if"))
	  ptext (stdout, textif);
  else if (0 == strcmp(cmd, "display"))
	  ptext (stdout, textdisplay);
  else if (0 == strcmp(cmd, "trace"))
	  ptext (stdout, texttrace);
  else if (0 == strcmp(cmd, "setdeb"))
	  ptext (stdout, textsetdeb);
  else if (0 == strcmp(cmd, "stat"))
	  ptext (stdout, textstat);
  else if (0 == strcmp(cmd, "reset"))
	  ptext (stdout, textreset);
  else if (0 == strcmp(cmd, "write"))
	  ptext (stdout, textwrite);
  else if (0 == strcmp(cmd, "reset"))
	  ptext (stdout, textreset);
  else if (0 == strcmp(cmd, "quit"))
	  ptext (stdout, textquit);
  else if (0 == strcmp(cmd, "help"))
	  ptext (stdout, textchelp);
  else
	  ptext (stdout, texthelp);
}

PUBLIC void
cwrite (str)
	char*	str;
{

  (void) printf ("%s\n", str);
}

PUBLIC int
exec (file)
	char*	file;
{
  int   res;
  TNODE* tree;
  FILE* oldfin;
  int   oldfname;
  char* oldfilename;
  int   oldlineno;
  int   oldtrace;

  oldtrace = trace;
  oldfin = fin;
  oldfname= nfname;
  oldfilename= filename;
  oldlineno= lineno;

  if (strlen (file) == 0){
    fin = stdin;
    nfname= STHadd ("stdin", SymbolTable, hidtbl, FALSE);
    filename="";
  } else {
    fin = efopen (file, "r");
    if (fin == NULL){
      trace = oldtrace;
      fin = oldfin;
      nfname = oldfname;
      filename = oldfilename;
      lineno = oldlineno;
      return 0;
    }
    nfname= STHadd (file, SymbolTable, hidtbl, FALSE);
    filename=file;
    lineno = 1;
    trace =0;
  }

  res = 0;
  quit = FALSE;
  do {
    ragerrors =0;
    errorcount = 0;
    tree= bast();
    if (errorcount == 0){
      rag (tree);
      if (ragerrors == 0){
	visit (tree);
	kill_tree (tree);
      }
    }
    (void) printf ("\n");
    if ((fin != stdin) && ((errorcount != 0) || (ragerrors != 0))){
      res  = -1;
      break;
    }
  } while (quit == FALSE);

  if (fin != stdin){
    (void)fclose (fin);
  }
  lineno = oldlineno;
  trace = oldtrace;
  fin = oldfin;
  nfname = oldfname;
  filename = oldfilename;
  quit = FALSE;
  return res;
}


PUBLIC int
lksort (lexv)
	int	lexv;
{
  return kd_sort (SymbolTable->data[lexv]);
}

PUBLIC int
lkvsort (lexv)
	int	lexv;
{
  return kd_v_sort (SymbolTable->data[lexv]);
}

PUBLIC int
nson (son)
  TNODE* son;
{
  TNODE* aux;
  int    i;
  for (aux = gt_fs(gt_ft(son)), i=1; aux != son; aux = gt_rb(aux), i++);
  return i;
}

PUBLIC int
cload (fn)
  char*	fn;
{
  char* msg;

  if (0 == ldi_init(fn)){
    msg = (char*) malloc (126);
    lineno--;
    (void) sprintf (msg, "File '%s.ldi' loaded successfully", fn);
    ildimsg (msg);
    lineno++;
    return 0;
  }
  return -1;
}

/******** semantic analysis *******/
/*
------------------------- GETARGS ------------------------------------

     PARAMETERS:
		 - poss:list of rposs fo the arguments
		 - nar:number of arguments
		 - pos: prefix/infix
		 - node: node been analyzed

     DESCRIPTION:
		 - It makes the list of args fo the poss opuids
---------------------------------------------------------------------
*/
PRIVATE INTlist*
getargs (poss, nar, pos, node)
  INTlist poss;
  int nar;
  int pos;
  TNODE* node;
{
  INTlist* args;
  TNODE*   aux;
  int      i;

  args = (INTlist*) malloc ((unsigned) nar * sizeof (INTlist));
  if (args == NULL) {
    (void)fprintf(stderr,"ildi: not enough memory\n");
    exit(1);
  }
  if (pos == prefix){
    for (i = 0, aux = gt_fs (gt_rb(node));
       i < nar ;
       i++, aux = gt_rb (aux))
    args [i]= (INTlist) fdclr (c_rposs,aux,1000+__LINE__ );
  }else{
    aux = gt_fs(gt_ft(node));
    args[0] = (INTlist) fdclr (c_rposs,aux,1000+__LINE__ );
    aux = gt_rb(gt_rb(aux));
    args[1] = (INTlist) fdclr (c_rposs,aux,1000+__LINE__ );
  }
  return args;
}

PUBLIC int
getnar (root)
	TNODE*	root;
{
  int	n;
  TNODE* aux;

  for (n=0, aux = gt_fs(root); aux != NULL; aux = gt_rb(aux), n++);

  return n;
}


/*
-----------------   FUNCTION GETOID ------------------------------

    PARAMETERS:
		- poss: list of possible operations
		- ffath: list of sorts fo tha father node.

    DESCRIPTION:
		- obtains unique operation identifier of the
		  a sort in ffath of list poss.

-----------------------------------------------------------------
*/
PUBLIC int
getoid (poss, ffath)
	INTlist poss;
	INTlist ffath;
{
  INTlist aux;
  int   res=0;
  int   i;

  for (aux = poss; aux != NULL; aux = INTtail (aux)){
    i = INThead(aux);
    if (i >0){
      if ((ffath == NULL) || (isinlist (getopsort(i), ffath))){
	if (res != 0)
	  return 0;
	res = i;
      }
    } else {
      if ((ffath == NULL) || (isinlist (getvsort(i), ffath))){
	if (res != 0)
	  return 0;
	res = i;
      }
    }
  }

  return res;
}
/*
-----------------   FUNCTION GETPOSS ------------------------------

    PARAMETERS:
		- lexv: name of the operation to search.
		- pos:  position : prefix or infix.
		- nar:  number of arguments.
		- sort: sort of the operation.

    DESCRIPTION:
		- obtains unique operation identifiers of the
		  given name, pos, nar and sort.

-----------------------------------------------------------------
*/
PUBLIC INTlist
getposs (lexv, pos, nar, sort, node)
	int     lexv;
	int     pos;
	int     nar;
	int     sort;
	TNODE*  node;
{
  INTlist  poss= (INTlist)NULL;
  INTlist  argposs= (INTlist)NULL;
  INTlist  aux;
  INTlist* args;
  int*     arglist;
  char*    name;
  int      res;
  int      opsize, vsize, n;

  assert (lexv > 0);
  assert (nar  >= 0);

  if (sort == -1)
    return poss;

  name = SymbolTable->data[lexv];
  opsize = get_opn_size ();
  for (n = 0; n < opsize; n++){
    if ((getopname(n)!=NULL) &&(cstrcmp(name, getopname(n)) == 0)){
      if (((sort == 0) || (sort == getopsort(n))) &&
	  (nar == getopnar(n)) &&
	  (isinfix(n) == pos)
	 ){
	poss = INTcons (n, poss);
      }
    }
  }
  if (nar == 0){
    vsize = get_var_size ();
    for (n=0;n<vsize;n++){
      if ((getvname(-n)!=NULL) && (cstrcmp(name,getvname(-n))==0)){
	if ((sort == 0) || (sort==getvsort(-n)))
	  poss = INTcons (-n, poss);
      }
    }
    argposs = poss;
  } else {
    if (poss != NULL){
      args = getargs (poss, nar, pos, node);

      for (argposs=NULL,aux = poss; aux != NULL; aux = INTtail (aux)){
	arglist = getopargs(INThead(aux));
	res = TRUE;
	for ( n = 1 ; n <= nar ; n++ ){
	  if (! isinlist (arglist[n-1], args[n-1])){
	    res = FALSE;
	    break;
	  }
	}
	if (res == TRUE)
	  argposs = INTcons (INThead(aux), argposs);
      }
    } else
      argposs = poss;
  }
  return argposs;
}

/*
-----------------   FUNCTION GETNF  ------------------------------

    PARAMETERS:
		- poss: list of father idref
		- n: position of the argument

    DESCRIPTION:
		- obtains the list of sorts of the n-esimo
		  argument for each operation of poss
-----------------------------------------------------------------
*/
PUBLIC INTlist
getnf (poss, n)
	int	poss;
	int     n;
{
  INTlist res=(INTlist)NULL;

  if (poss > 0)
    res = INTcons (getop_sarg(poss,n-1),res);

  return res;
}

/* getrpos -- get the set of possible sorts as result */
PUBLIC INTlist
getrpos (poss)
	INTlist poss;
{
  INTlist       result= NULL;
  int           value;

  for (; poss != NULL ; poss = INTtail (poss))
    if ((value = INThead (poss)) > 0)
      result = INTcons (getopsort(value), result);
    else
      result = INTcons (getvsort(value), result);

  return result;
} /* end of getrpos */

/********** colours functions  ************/

PUBLIC void
dr_kdatum (fp, val)
	FILE* fp;
	CLR_TYPE val;
{
  kdatum n;
  klink s;

  n = (kdatum) val;

  if (n->opn > 0)
    (void) fprintf (fp,"{operation %d of sort %d: ",
		    n->opn, getopsort(n->opn));
  else
    (void) fprintf (fp,"{operation %d of sort %d: ",
		    n->opn, getvsort(n->opn));
  for (s= n->lnk; s!= NULL; s= s->next)
    dr_kdatum (fp, (CLR_TYPE) s->arg);
  (void) fprintf (fp, "}");

}
PUBLIC void
dr_klink (fp, val)
	FILE* fp;
	CLR_TYPE val;
{
  klink s;
  kdatum n;
  s = (klink) val;
  n = s->arg;

  dr_kdatum (fp,(CLR_TYPE)n);
}

