/***********************************
  (C) Copyright 1992-1993; dit/upm
   Distributed under the conditions stated in the
   TOPO General Public License (see file LICENSE)
 ***********************************
 * $Log: lex.c,v $
 * Revision 2.10  1994/11/15  13:56:55  lotos
 * index -> strchr, for portability
 *
 * Revision 2.9  1994/11/14  11:33:42  lotos
 * avoid name collisions
 *
 * Revision 2.8  1994/11/08  16:52:59  lotos
 * bug fixing
 *
 * Revision 2.7  1994/07/18  18:33:06  lotos
 *  segregated LDI library (interpreter)
 *
 * Revision 2.6  1993/10/19  18:33:13  lotos
 * ported to BSD/386
 *
 * Revision 2.5  1993/10/08  18:41:48  lotos
 * He corregido la liberaci'on de expresiones reescritas
 * He modificado el tratamiento del caracter especial '='
 *
 * Revision 2.4  1993/09/20  12:39:05  lotos
 * synchronized with kaos development
 * adpated to kdatum
 * udatum are not expected to be used
 * reduce number of reserved words: new user lexicon
 *
 * Revision 2.3  1993/06/29  10:55:35  lotos
 * fix rewriting of expressions in IF clauses
 *
 * Revision 2.2  1993/06/22  08:49:38  lotos
 * fix variable redeclaration
 * fix standard input reading (batch mode)
 *
 * Revision 2.1  1993/06/10  13:37:30  lotos
 * completely remade
 *
 ***********************************/

/* KJT 28/09/10: getline -> getLine for compatibility with recent versions */

#ifndef lint
static char rcsid[]= "$Id: lex.c,v 2.10 1994/11/15 13:56:55 lotos Exp $";
#endif

# include <stdio.h>

# define lexana_IMP

# include <string.h>
# include <ctype.h>
# include "swbus.h"

/* KJT 20/01/23: added function prototypes */
PUBLIC	int yyerror (char* mess);

/* 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

typedef struct Predefined {
	char*	keyword;
	char*	realkeyword;
	int	type;
} predef;

PRIVATE predef prdw [] = {
	"rename",	"rename",	RENAME,
	"check",	"check",	CHECK,
	"display",	"display",	DISPLAY,
	"eqns",		"eqns",		EQNS,
	"exec",		"exec",		EXEC,
	"free",		"free",		FREE,
	"help",		"help",		HELP,
	"if",		"if",		IF,
	"is",		"is",		IS,
	"load",		"load",		LOAD,
	"let",		"let",		LET,
	"of",		"of",		OF,
	"opns",		"opns",		OPNS,
	"quit",		"quit",		QUIT,
	"reset",	"reset",	RESET,
	"resetvar",	"resetvar",	RESETVAR,
	"rewrite",	"rewrite",	XEWRITE,
	"setdeb",	"setdeb",	SETDEB,
	"sorts",	"sorts",	SORTS,
	"stat",		"stat",		STAT,
	"trace",	"trace",	TRACE,
	"var",		"var",		VAR,
	"vars",		"vars",		VARS,
	"write",	"write",	WRITE,
	"::",		"::",		ELSE,
	";",		";",		FI,
	NULL, NULL, 0
	};

PRIVATE token   tttt;
PRIVATE token*  tt= &tttt;
int     lineno= 1;

static int isfile=FALSE;
static int iscmd=FALSE;
static int inif=0;
static int afor=1;
char sbuf[100];
char *p;
void  gl_init();
char* getLine();

int c;

int pos=0;/* controlling position in the palabra */
PUBLIC void
initline ()
{
  if (palabra == NULL){
    palabra = malloc (BUFSIZ * sizeof (char));
    if (palabra == NULL) {
      (void)fprintf(stderr,"ildi: not enough memory\n");
      exit(1);
    }
  }
  pos = 0;
  palabra[0]='\n';
  palabra[1]='\0';
}

PUBLIC void
readline ()
{
  int   i;
  char  rc;
  static char* pront=NULL;

  if (pront == NULL){
    pront = malloc (BUFSIZ * sizeof (char));
    if (pront == NULL) {
      (void)fprintf(stderr,"ildi: not enough memory\n");
      exit(1);
    }
  }
  (void) sprintf (pront, "ildi(%d):%s> ",lineno,filename);
  if (fin != stdin){
    if (trace != 0){
      (void) printf ("%s",pront);
      (void) fflush (stdout);
    }
    for (i=0, rc= getc(fin);
	 (rc!='\n') && (rc!=EOF) && (i<BUFSIZ-2);
	 i++,rc= getc(fin)){
      palabra[i]= rc;
    }
    palabra [i] = rc;
    if (i==BUFSIZ-2){
      (void)fprintf(stderr,"ildi: command to long\n");
      palabra[BUFSIZ-2]='\n';
    }
    palabra[i+1]='\0';
  } else {
    if (trace > 1){
      (void) printf ("%s",pront);
      (void) fflush (stdout);
    }
    gl_init(80);
    if (trace != 0)
      palabra = getLine(pront);
    else
      palabra = getLine("");
  }
  if ((fin != stdin) && (trace != 0 )){
    if (!((strlen(palabra) == 1) && (palabra[0] == EOF)))
      (void)printf ("%s",palabra);
  }
  if ((fin == stdin) && (trace > 1 )){
    if (!((strlen(palabra) == 1) && (palabra[0] == EOF)))
      (void)printf ("%s",palabra);
  }
}


PRIVATE char
mget (file)
	FILE* file;
{

  if (palabra[pos] == '\n'){
    readline ();
    if (strlen(palabra) == 0)
      return EOF;
    else{
      pos = 0;
      return palabra[0];
    }
  } else
    return palabra[++pos];

}

PRIVATE void
munget (mc,file)
	char mc;
	FILE* file;
{
  assert (pos != 0);
  assert (palabra[pos]==mc);
  pos--;
}
PRIVATE int
cmp (cms, s2)
  char* cms;
  char* s2;
{
  int i;
  int lcms, ls2;

  lcms = strlen (cms);
  ls2  = strlen (s2);

  if (ls2 > lcms)
    return 1;

  for (i=0; (i<lcms) && (i<ls2); i++){
    if (cms[i]!= s2[i])
      break;
  }
  if ((i==lcms+1) || (i==ls2))
    return 0;
  else
    return 1;
}


PRIVATE void
cleanline ()
{
  if (c != '\n'){
    while (c != '\n'){
      c= mget (fin);
    }
    munget (c, fin);
  }
}

PRIVATE void
ptoken (tk)
  int	tk;
{
  int i;
  for (i=0; prdw[i].keyword != NULL; i++){
    if (prdw[i].type == tk){
      (void) fprintf (stderr, ">>%s\n", prdw[i].keyword);
    }
  }
  (void) fprintf (stderr, ">>%d\n", tk);
}

PRIVATE int
ispred (str)
  char*	str;
{
  int i;

  for (i=0; prdw[i].keyword != NULL; i++){
    if (strcmp (prdw[i].keyword, str) == 0){
      switch (prdw[i].type){
	case IF:
	  inif++;
	  break;
	case HELP:
	case RENAME:
	  iscmd=TRUE;
	  break;
	case LOAD:
	case EXEC:
	  isfile = TRUE;
	  break;
      }
      return prdw[i].type;
    }
  }
  return 0;
}

PRIVATE   char
backslash (chr)
  char  chr;
{
  static char transtab [] = "b\bf\fn\nr\rt\t";

  if (chr != '\\')
    return chr;
  chr = mget (fin);
  if (islower (chr) && strchr (transtab,chr))
    return  strchr (transtab,chr)[1];
  return chr;
}

PRIVATE int
isspecial (chr)
  /* KJT 20/01/23: added "chr" declaration */
  char chr;
{
 switch (chr){
   case '#' :
   case '%' :
   case '&' :
   case '*' :
   case '+' :
   case '-' :
   case '.' :
   case '/' :
   case '<' :
   case '=' :
   case '>' :
   case '@' :
   case '\\':
   case '^' :
   case '~' :
   case '{' :
   case '}' :
	 return TRUE;
 }
 return FALSE;
}
void
saltacom()
{
  while ((c != '\n') && (c != EOF)) {
    c = mget (fin);
  }
  lineno++;
}

/* KJT 20/01/23: added "int" type */
int yylex()
{
  int c2;
  int prd;

  while ((c = mget(fin)) == ' ' || c == '\t' || ((c == '\n') && (inif >0)))
    if (c == '\n'){
      lineno ++;
    }

  switch  (c) {
    case '=':
      c2 = mget (fin);
      if (c2 == ' '){
	iscmd = FALSE;
	isfile = FALSE;
	return c;
      } else {
	(void) munget (c2, fin);
      }
      break;
    case '\n':
      lineno ++;
      assert (inif==0);
      iscmd = FALSE;
      isfile = FALSE;
      return EOF;
    case EOF:
      quit = TRUE;
      iscmd = FALSE;
      isfile = FALSE;
      return EOF;
    case '-':
      c2 = mget (fin);
      if (c2 == '-') {
	c = mget (fin);
	saltacom ();
	iscmd = FALSE;
	isfile = FALSE;
	return EOF;
      } else {
	(void) munget (c2, fin);
      }
      break;
    case '"': {
      p = sbuf;
      for ( p = sbuf; (c=mget (fin)) != '"'; p++){
	if  (c == '\n' || c == EOF )
	  yyerror ("missing quote");
	if (p >= sbuf  + sizeof (sbuf) -1){
	  *p ='\0';
	  yyerror ("string too long");
	}
	*p = backslash (c);
      }
      *p = 0;
      iscmd = FALSE;
      isfile = FALSE;
      return  STRING;
      }
      break;
    case ':':{
      c2 = mget (fin);
      if (c2 == ':'){
	c = mget (fin);
	iscmd = FALSE;
	isfile = FALSE;
	return  ELSE;
      } else {
	(void) munget (c2, fin);
      }
      }
      break;
    case ';':{
      iscmd = FALSE;
      isfile = FALSE;
      if (inif > 0)
	inif--;
      return  FI;
      }
      break;
  }

  if ((isfile) && (isalnum (c) || (c == '\\') || (c == '.') )){
    p = sbuf;
    do {
      if (p >= sbuf + sizeof(sbuf)-1){
	* p = '\0';
	yyerror("name too long");
      }
      * p ++ = c;
    } while (((c = mget(fin)) != EOF) &&
	     ((isalnum (c) || (c == '/') || (c == '.') )));
    (void) munget (c,fin);
    *p = '\0';
    iscmd = FALSE;
    isfile = FALSE;
    return FILEID;
  }
  if (isalpha(c)) {
    p = sbuf;
    do {
      if (p >= sbuf + sizeof(sbuf)-1){
	* p = '\0';
	yyerror("name too long");
      }
      * p ++ = c;
    } while ((c = mget(fin)) != EOF && (isalnum (c) || (c == '_')));
    (void) munget (c,fin);
    *p = '\0';
    isfile = FALSE;
    if (iscmd){
      iscmd = FALSE;
      return IDENTIFIER;
    } else if ((prd = ispred (sbuf)) != 0){
      return  prd;
    }  else{
      return IDENTIFIER;
    }
  }
  if (isdigit (c)) {
    p = sbuf;
    do {
      if (p >= sbuf + sizeof(sbuf)-1){
	* p = '\0';
	yyerror("name too long");
      }
      * p ++ = c;
    } while ((c = mget(fin)) != EOF && (isalnum (c) || (c == '_')));
    (void) munget (c,fin);
    *p = '\0';
    iscmd = FALSE;
    isfile = FALSE;
    return SPECIAL;
  }
  if (isspecial(c)){
    p = sbuf;
    do {
      if (p >= sbuf + sizeof(sbuf)-1){
	* p = '\0';
	yyerror("name too long");
      }
      * p ++ = c;
    } while ((c = mget(fin)) != EOF && isspecial(c));
    (void) munget (c,fin);
    *p = '\0';
    iscmd = FALSE;
    isfile = FALSE;
    return SPECIAL;
  }
  iscmd = FALSE;
  isfile = FALSE;
  return c;
}
/* end of yylex */

PUBLIC	token*
gtk	()
{
   tt->type = yylex();
   if(lexdebug>0)
     ptoken (tt->type);
   tt->yylval.name= STHadd (sbuf, SymbolTable, hidtbl, FALSE);
   tt->yylval.line= newI2 (lineno, nfname);
   return tt;
}

PUBLIC	int
yyerror	(mess)
	char*	mess;
{
   (void) printf ("ildi(%d):%s\n", lineno, mess);
   inif = 0;
   (void) printf ("      -- try help\n");
   ++errorcount;
   cleanline();
}

PUBLIC void
xrename (old, new)
	char* old;
	char* new;
{
  int i;
  for (i=0; prdw[i].realkeyword != NULL; i++)
    if (strcmp (prdw[i].realkeyword, old) == 0){
      prdw[i].keyword = strdup (new);
      break;
  }
  if (prdw[i].realkeyword == NULL){
    (void) printf ("rename: \"%s\" command not defined\n", old);
  }
}

PUBLIC void
displayrename ()
{
  int i;
  for (i=0; prdw[i].keyword != NULL; i++)
    if (strcmp (prdw[i].realkeyword, prdw[i].keyword) != 0){
      (void) printf ("\t%s\t-> %s\n", prdw[i].keyword,prdw[i].realkeyword);
  }

}

