/***********************************
  (C) Copyright 1992-1993; dit/upm
   Distributed under the conditions stated in the
   TOPO General Public License (see file LICENSE)
 ***********************************
 $Log: lexana.c,v $
 * Revision 1.4  1993/01/21  20:25:19  lotos
 * code generation for ildi
 *
 * Revision 1.3  1993/01/18  17:52:52  lotos
 * distribution issues
 *
 * Revision 1.2  1993/01/12  14:40:39  lotos
 * fix details to port to pc
 *
 * Revision 1.1  1992/11/19  18:22:55  lotos
 * Initial revision
 *
 * Revision 2.6  91/05/03  18:50:21  lotos
 * special identifiers may have _*, but not ending it
 *
 * Revision 2.4  91/04/08  09:17:57  lotos
 * allow for /bin/cpp processed specs as input
 * fix bug in trailing '_' in identifiers
 *
 ***********************************/

#ifndef lint
static char rcsid[]= "$Id: lexana.c,v 1.4 1993/01/21 20:25:19 lotos Exp $";
#endif

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

PUBLIC	char*	comm;
PUBLIC HT       hidtbl;

# define ch	inbuf[ibp]
# define next	inbuf[ibp+1]
# define nnext	inbuf[ibp+2]

PRIVATE	int	ibp= 0;
PRIVATE	char	inbuf[BUFSIZ]= "\n";
PRIVATE int	tstart= 0;
PRIVATE int	tend= 0;
PRIVATE int	lineno= 0;

PRIVATE	int	kwsize= 38;
PRIVATE struct {
	char*	kw;
	int	tk;
} kwtable [] = {
"accept",       ACCEPT,
"actualizedby", ACTUALIZEDBY,
"any",          ANY,
"behavior",     BEHAVIOUR,
"behaviour",    BEHAVIOUR,
"choice",       CHOICE,
"endlib",       ENDLIB,
"endproc",      ENDPROC,
"endspec",      ENDSPEC,
"endtype",      ENDTYPE,
"eqns",         EQNS,
"exit",         EXIT,
"for",          FOR,
"forall",       FORALL,
"formaleqns",   FORMALEQNS,
"formalopns",   FORMALOPNS,
"formalsorts",  FORMALSORTS,
"hide",         HIDE,
"i",            I,
"in",           IN,
"is",           IS,
"let",          LET,
"library",      LIBRARY,
"noexit",       NOEXIT,
"of",           OF,
"ofsort",       OFSORT,
"opnnames",     OPNNAMES,
"opns",         OPNS,
"par",          PAR,
"process",      PROCESS,
"renamedby",    RENAMEDBY,
"sortnames",    SORTNAMES,
"sorts",        SORTS,
"specification",SPECIFICATION,
"stop",         STOP,
"type",         STYPE,
"using",        USING,
"where",        WHERE
};

/*--------------------------------------------------------------------*/
PRIVATE void	get     ();
PRIVATE int	lookfkw ();
PRIVATE int	isspec	();
PRIVATE void	eatcomment ();
PRIVATE void	eatexc	();
/*--------------------------------------------------------------------*/

PRIVATE	void
get ()
{
  if (ch == '\n') {
    ibp= 0;
    if (fgets (inbuf, BUFSIZ, sfp) == NULL) {
      inbuf[0]= EOF;
      return;
    }
    lineno++;
    if (inbuf[0] == '#') {
      if (strncmp (inbuf, "# line", 6) == 0) {
	(void)sscanf(inbuf, "# line %d \"%s\"\n",
		     &lineno,
		     TtsFileName);
	lineno--;
	TtsFileName[strlen(TtsFileName)-1]= '\0';
	nfname= STHadd(TtsFileName, SymbolTable, hidtbl, FALSE);
	inbuf[0]= '\n';
	get ();
      }
      else if (strncmp (inbuf, "#line", 5) == 0) {
	(void)sscanf(inbuf, "#line %d \"%s\"\n",
		     &lineno,
		     TtsFileName);
	lineno--;
	TtsFileName[strlen(TtsFileName)-1]= '\0';
	nfname= STHadd(TtsFileName, SymbolTable, hidtbl, FALSE);
	inbuf[0]= '\n';
	get ();
      }
      else if (sscanf (inbuf, "#%d \"%s\"\n", &lineno, TtsFileName) == 2) {
	lineno--;
	TtsFileName[strlen(TtsFileName)-1]= '\0';
	nfname= STHadd(TtsFileName, SymbolTable, hidtbl, FALSE);
	inbuf[0]= '\n';
	get ();
      }
    }
  }
  else ibp++;
  tend= ibp;
}

PRIVATE int
lookfkw	(key)
	char*	key;
{
  /* KJT 20/01/23: added "int" type */
  register int loweri= 0;
  register int upperi= kwsize-1;
  register int idx;
  register int cmp;

  for (;;){
    idx= (loweri + upperi) / 2;
    cmp= strcmp(key, kwtable[idx].kw);
    if (cmp == 0)
	 return kwtable[idx].tk;	/* found */
    else if (cmp < 0){
	 if (idx == loweri) return 0;	/* not found */
	 upperi= --idx;
    }
    else{
	 if (idx == upperi) return 0;	/* not found */
	 loweri= ++idx;
    }
  }
}


PRIVATE	int
isspec	(c)
	char	c;
{
	switch (c) {
	  case '#' :
	  case '%' :
	  case '&' :
	  case '*' :
	  case '+' :
	  case '-' :
	  case '.' :
	  case '/' :
	  case '<' :
	  case '=' :
	  case '>' :
	  case '@' :
	  case '\\' :
	  case '^' :
	  case '~' :
	  case '{' :
	  case '}' :
		return TRUE ;
	}
	return FALSE ;
}

PRIVATE	void
eatcomment ()
{
  int comment;
  int abslin;

  abslin= lineno;
  get ();
  comment= 1;
  while (comment != 0) {
    get ();
    if ((ch == '(') && (next == '*')) {
      get ();
      get ();
    }
    else if ((ch == '*') && (next == ')')) {
      comment--;
      get ();
      get ();
    }
    else if (ch == EOF) {
      (void) fprintf (stderr, "%s:%d:", TtsFileName, abslin);
      (void) fprintf (stderr, "EOF found while scanning comment\n");
      exit (1);
    }
  }
}

PRIVATE	void
eatexc	(tok)
     token*	tok;
{
  char*	key;
  char*	pval;
  char*	val;
  unsigned vsize;
  char c;

  tok->yylval.line= newI2(lineno,nfname);
  get ();
  get ();
  get ();
  while (isspace (ch))
    get ();
  key= &ch;
  while (!isspace (ch))
    get ();
  c= inbuf[ibp];
  inbuf[ibp]= '\0';
  tok->yylval.ckey= str_alloc(key);
  inbuf[ibp]= c;
  get ();
  while (isspace (ch))
    get ();
  pval= &ch;
  vsize= BUFSIZ;
  val= malloc(vsize);
  *val= '\0';
  for (;;) {
    switch (ch) {
    case '|':
      if (next == '*' && nnext == ')') {
	inbuf[ibp]= 0;
	while (strlen (val) + strlen (pval) >= vsize) {
	  vsize+= BUFSIZ;
	  val= realloc (val, vsize);
	}
	(void) strcat (val, pval);
	key= val+strlen(val)-1;
	while (key != val && isspace (*key))
	  key--;
	*(key+1)= 0;
	tok->yylval.cval= str_alloc(val);
	free (val);
	ibp+= 3;
	return;
      }
      get ();
      break;
    case '\n':
      while (strlen(val) + strlen(pval) >= vsize){
	vsize+= BUFSIZ;
	val= realloc (val, vsize);
      }
      (void) strcat (val, pval);
      get ();
      pval= &ch;
      break;
    default:
      get ();
      break;
    }
  }
}

/******** Public Functions *********************************************/

PUBLIC  int
yyerror (mess)
     char* mess;
{
  (void) fprintf (stderr, "%s:%d: %s at %.*s\n",
		  TtsFileName, lineno, mess,
		  tend-tstart, inbuf+tstart);
  ++errorcount;
}

PUBLIC token*
gtk ()
{
  /* KJT 14/02/12: Changed
  token	tkvar;
  token*	tk= &tkvar;
  */
  token* tk = (token*) malloc(sizeof(token));
  int chend;

  while (isspace(ch))
    get ();

  tstart= ibp;
  if (isalpha(ch)){
    do{
      if (isupper(ch))
	ch= tolower(ch);
      tend= ++ibp;
    } while (isalnum(ch) || ch == '_');
    /*
      Still, previous loop may read too many '_',
      that are allowed within an identifier,
      but the trailing character must be alphanumeric.
      */
    while (inbuf[ibp-1] == '_')
      tend= --ibp;
    chend= ch;
    ch= '\0';
    tk->type= lookfkw (&inbuf[tstart]);
    if (tk->type == 0)
      {
	tk->type= IDENTIFIER;
	tk->yylval.name= STHadd (&inbuf[tstart], SymbolTable, hidtbl, FALSE);
	tk->yylval.line= newI2(lineno,nfname);
      }
    ch= chend;
    return tk;
  }
  if (isdigit(ch)){
    do{
      tend= ++ibp;
    } while (isalnum(ch) || ch == '_' );
    /*
      Still, previous loop may read too many '_',
      that are allowed within an identifier,
      but the trailing character must be alphanumeric.
      */
    while (inbuf[ibp-1] == '_')
      tend= --ibp;
    chend= ch;
    ch= '\0';
    tk->type= SPECIAL;
    tk->yylval.name= STHadd (&inbuf[tstart], SymbolTable, hidtbl, FALSE);
    tk->yylval.line= newI2(lineno,nfname);
    ch= chend;
    return tk;
  }
  switch (ch){
  case '#' :
  case '%' :
  case '&' :
  case '*' :
  case '+' :
  case '-' :
  case '.' :
  case '/' :
  case '<' :
  case '=' :
  case '>' :
  case '@' :
  case '\\' :
  case '^' :
  case '~' :
  case '{' :
  case '}' :
    switch (ch){
    case '-' : if (next == '>' && (isspec(nnext) == FALSE)){
      tk->type= ARROW;
      get ();
      get ();
      return tk;
    }
      break;
    case '>' : if (next == '>' && (isspec(nnext) == FALSE)){
      tk->type= ENABLE;
      get ();
      get ();
      return tk;
    }
      break;
    case '=' : if (isspec(next) == FALSE){
      tk->type= '=';
      get ();
      return tk;
    }
    else if (next == '>' && (isspec(nnext) == FALSE)){
      tk->type= IMPLICATION;
      get ();
      get ();
      return tk;
    }
      break;
    }
    do{
      get ();
    } while (isspec(ch));
    chend= ch;
    ch= '\0';
    tk->type= SPECIAL;
    tk->yylval.name= STHadd (&inbuf[tstart], SymbolTable, hidtbl, FALSE);
    tk->yylval.line= newI2(lineno,nfname);
    ch= chend;
    return tk;
  case '|' : if (next == '['){
    get ();
    get ();
    tk->type= LEFT_PAR;
    return tk;
  }
    if (next == '|'){
      get ();
      get ();
      if (ch == '|'){
	get ();
	tk->type= INTERLEAVING;
	return tk;
      }
      tk->type= SYNCHRONIZATION;
      return tk;
    }
    break;
  case '[' : if (next == ']') {
    get ();
    get ();
    tk->type= FAT_BAR;
    return tk;
  }
    if (next == '>') {
      get ();
      get ();
      tk->type= DISABLE;
      return tk;
    }
    break;
  case ':' : if (next == '=') {
    get ();
    get ();
    tk->type= DEFINITION;
    return tk;
  }
    break;
  case ']' : if (next == '|') {
    get ();
    get ();
    tk->type= RIGHT_PAR;
    return tk;
  }
    break;
  case '(' : if (next == '*'){
    if (nnext == '|'){
      tk->type= EXCOMM;
      eatexc (tk);
      return tk;
    }
    else{
      eatcomment ();
      return gtk ();
    }
  }
    break;
  case EOF : tk->type= 0;
    return tk;
  case '\n': get ();
    return gtk ();
  }
  tk->type= ch;
  get ();
  return tk;
}
