/*
 * FILE : scanner.c - get and tokenize input theory
 *
 * programmer - Pawel Cholewinski
 *
 * date 10/28/92
 *
 * modified 11/15/93
 * modified 29 Apr 1999 by Neil Moore <neil@cs.uky.edu>
 * modified  9 Jul 1999 by Neil Moore <neil@cs.uky.edu>
 * modified 20 Aug 1999 by Neil Moore <neil@cs.uky.edu>
 * modified  4 Sep 1999 by Neil Moore <neil@cs.uky.edu>
 * modified 15 Oct 1999 by Neil Moore <neil@cs.uky.edu>
 *
 * Part of sderes.  See COPYRIGHT for copyright information.
 *
 */

#include <stdlib.h>
#include "proto.h"
#include "global.h"
#include "token.h"
#include "default.h"

#define LONGBUFOR 8192

/*
 * =========================================================================
 * getdata: call reading routine for current logic context
 * =========================================================================
 */
int getdata()
{
   char bufor[MAXBUFOR];
   char fdwbufor[MAXFILENAME];
   int lim, ok1=0, ok2=0;

   ff = 0; dffno=0; dttable[0]=ENDTH;
   lim= MAXBUFOR; err=0 ;

   insert("DeReS",hashkey("DeReS"),defhashtable);
   while (nextline(bufor, lim, finp) != 0) {
	   if (bufor[0] == '%' || bufor[0] == EOS) ;
	   else if ((bufor[0]=='w'|| bufor[0]=='d') && bufor[1]=='=') {
		   strcpy(fdwbufor, &bufor[2]);
		   if (bufor[0]=='w'){
			   strcat(fdwbufor,".thc");
			   ok1++; 
		   }
		   else {
			   strcat(fdwbufor,".dc");
			   ok2++;
		   }
		   fdw = fopen(fdwbufor, "r");
		   if (fdw == NULL) {
			   if(verbosity > 0)
				   fprintf(stderr,"cannot open file %s\n",fdwbufor);
			   err--;
		   }
		   else {
			   if (bufor[0]=='w') {
				 dttable[ff] = BOW; wbegin = ff++;
			   }
			   else { 
				dttable[ff] = BOD; dbegin = ff++;
			   }
			   get_input_text(fdw,dttable,&dno,defhashtable);
			   fclose(fdw);
			   if (bufor[0]=='w') {
				 if (dttable[ff-1]!=SEMI) dttable[ff++]=SEMI;
				 dttable[ff] = EOW ; wend = ff++;
			   }
			   else {
				if (dttable[ff-1]!=SEMI) dttable[ff++]=SEMI;
				dttable[ff] = EOD ; dend = ff++;
			   }
		   }
	  } /* else - description statement */
    }/* while */
   dttable[ff] = ENDTH;
   ff++;
   dttable[ff] = EOI;
   if (ok1!=1 || ok2!=1) {
	if (err==0) err--;
	if (ok1==0) error("no file for w.",0);
	else if (ok1 >1) error("ambiguous w file description.",0);
	if (ok2==0) error("no file for d.",0);
	else error("ambiguous d file descrioption.",0);
   }
   fclose(finp);
   if (err == 0) err = form_prover_structures();
   return !err;
}

/*
 * ========================================================================
 * get_input_text : read and save input text, return the number of input 
 *		    lines of length greater than 80
 *    -parameter: fileptr - file descriptor for input file
 *    -returned : number of too long lines in input
 * ========================================================================
 */
int get_input_text(fileptr, memory, counter, hashtable)
	FILE *fileptr;
	int memory[];
	int *counter;
	struct symbolbox *hashtable[];
{
	int longlines=0, m;
	char bufor[LONGBUFOR];
	int lim;

	lim = LONGBUFOR;
	*counter = 0;
	while ((m = nextline(bufor,lim,fileptr)) != 0)
		if (m<0) {
		  longlines++ ; /* too long line ignored */
		  if(verbosity > 0)
			  fprintf(stderr,"too long line - ignored (%d)\n",*counter);
		}
		else if (bufor[0] == '%') ;
		else {
			lexscan(bufor,memory, hashtable);
			if ((bufor[0]==EOS)&&(memory[ff-1]!=SEMI)){
				 memory[ff++]= SEMI; (*counter)++;
			}
		     }
	return longlines;
}


/*
 * ========================================================================
 * nextline : scans next input line, shrinks sequences of spaces/tabs
 *    - parameters : bufor- array to keep the line, lim- line length limit
 *    - returned   : line length or -1 if line is too long
 * ========================================================================
 */
int nextline(bufor,lim,fileptr)
	char bufor[];
	int  lim;
	FILE *fileptr;
{
	int c=0, j=0;

	while ((j<lim) && ((c=getc(fileptr)) != EOF) && (c!='\n')) {
		if (c=='\t') c=SPACE;
		if (c!=SPACE) {
			bufor[j]=c;
			j++;
		}
	}
	if (c=='\n') {
		bufor[j]=EOS;
		if ((j>0) && (bufor[j-1]==SPACE)) {
			bufor[j-1]=EOS ; 
			j--;
		}
		return ++j;
	}
	else if (c==EOF) return 0;
	else {
		while ((c!=EOF) && (c!='\n')) c=getc(fileptr);
		return -1;
	}
}


/*
 * ========================================================================
 * error : prints message and exits if code greater then 0
 * ========================================================================
 */
void error(char *message, int code)
{
	if(verbosity > 0)
		fprintf(stderr,"%s\n",message);
	if (code>0) exit(code);
}

/*
 * ======================================================================
 *  lexscan : analyze input file and recognize language tokens       
 * 	-performance : scans input file once and looks for tokens     
 * ======================================================================
 */ 
int lexscan(bufor,memory,hashtable) /* lexical analyzer ***/
	char bufor[];
	int memory[];
	struct symbolbox *hashtable[];
{
	int i=0, tt='$' , key, sigok=1;
	int token=BOT, varno=0, parcount;
	struct symbolbox *address;

	while (bufor[i]!=EOS) {
         	tt = bufor[i++];
         	if (tt == ' ' || tt == '\t')
                                     ; /* strip out white space */
		else if (tt == '1') token = TOP;
		else if (tt == '0') token = BOT;
         	else if (isalpha(tt) || tt == '_') {    /* tt is a letter */
              		int  b = 0 ;
			parcount = 0;
			/* 9 Jul 1999: allow underscores */
              		while (isalnum(tt) || tt == '_' || (parcount>0)) {
							/* tt is alphanumeric */
                     		lexbuf[b] = tt;
				if (tt==')') parcount--;
                     		tt = bufor[i++];
				if (tt=='(') parcount++;
                     		b = b+1;
                     		if (b >= BDRSSIZE)
                     		error("compiler error",0);
               		}
               		lexbuf[b]= EOS;
	       		i--;
	       		if (strcmp(lexbuf,"0")==0) token=BOT;
	       		else if (strcmp(lexbuf,"1")==0) token=TOP;
	       		else {
				token=VAR;
				key=hashkey(lexbuf);
				address=lookup(lexbuf,key,hashtable);
				if (address==NULL) 
				  address=insert(lexbuf,key,hashtable);
				varno=address->no;
	       		} 
			
	  	}
	  	else     /* tt is no a digit nor a letter */
       	     	if (tt == '!') token=NEG;
	     	else if (tt == ':') token=COLON;
	     	else if (tt == ',') token=COMMA;
		else if (tt == ';') token=SEMI;
	     	else if ((tt == '&') && (bufor[i]=='&')) {
			token=AND; i++;
	     	}
	     	else if ((tt== '-') && (bufor[i]=='>'))  {
			token=ENT; i++;
	     	}
	     	else token=UNKNOWN;
		if (token==UNKNOWN) {
			if(verbosity > 0)
				fprintf(stderr, "unknown token in %s (position %d)\n",bufor, i);
			sigok = -1;
	        }
		if (ff>=DTSIZE) error("unsufficient spelling table",1);
		if ((token!=SEMI)||(memory[ff-1]!=SEMI)) memory[ff++] = token;
		if (token==VAR) memory[ff++] = varno;
      	}
   return sigok;
}


/*
 * ====================================================================
 *  hashkey : form hash value for string s 			       
 *     -parameters  : 1. s : pointer to a word to be hashed           
 *     -performance : algorithm from Hansen's book                    
 *     -returns     : hash key of s				       
 * ===================================================================
 */
int hashkey(s)
      char *s ;
{
   unsigned hashval;

   for (hashval=0 ; *s != '\0' ; s++) hashval = (*s + hashval) % WSIZE ;
   hashval = hashval%HASHSIZE;
   return (int)hashval ;
}
 
/*
 * ===================================================================
 *  lookup : hash search for s in one hashtable block      	   
 *    -parameters : 1. s : pointer to a word to be checked        
 * 		     2. key : interger hashkey of s		   
 *    -performance : linear search of one list			   
 *    -returns     : address of s, NULL if s is new   		   
 * ===================================================================
 */
struct symbolbox *lookup(s, key, hashtable) 
      char *s ;
      int key ;
      struct symbolbox *hashtable[];
{ 
   struct symbolbox *sbx ;

   for(sbx =hashtable[key] ; sbx != NULL ; sbx = sbx->next)
      if (strcmp(s,sbx->id) == 0) return  sbx;
      return NULL ; /* s - new identifier */
}
 
/*
 * ===========================================================================
 *  insert : append new symbol to hashtable list	                   
 * 	-parameters : 1. s : pointer to a word to be inserted            
 * 		      3. key : int (hash key of s, negative to count it now
 *     -performance: appends new symbol to the top block hashtable list   
 *     -returns    : position of symbolbox for s            		   
 * ===========================================================================
 */
struct symbolbox *insert(s, key, hashtable) 
           char *s;
           int key;
           struct symbolbox *hashtable[];
{
   struct symbolbox *sbx;

   sbx = (struct symbolbox *)malloc((unsigned )sizeof(*sbx));
   if (sbx == NULL) error("no room for new symbol",1);
   sbx->id = (char *)malloc((unsigned)(strlen(s)+1));
   if ((sbx->id)==NULL) error("no room for new variable id",1);
   (void)strcpy(sbx->id,s);

   if (dffno>=2*MAXDSIZE) error("unfufficient defatomlex",1);
   defatomlex[dffno] = sbx->id;sbx->no = dffno++;

   sbx->next = hashtable[key];
   hashtable[key] = sbx;
   return sbx;
}

