#include  "defns.i"
#include  "extern.i"

#define	Space(s)	(s == ' ' || s == '\t')
#define	SkipComment	while ( ( c = getchar() ) != '\n' )
#define EndLine		while ( getchar() != '\n' )


Boolean ReadType()
/*      --------  */
{
    char Delim;
    TypeInfo T;

    Delim = ReadName(Name);
    if ( ! *Name ) return false;
    else
    if ( Delim != ':' ) Error(1, Name);

    T = (TypeInfo) malloc(sizeof(struct _type_rec));
    T->Name = CopyString(Name);
    T->NValues = 0;
    T->Value = Nil;

    do
    {
	while ( (Delim = ReadName(Name)) == '\n' )
	    ;

	if ( T->NValues % 100 == 0 )
	{
	    T->Value = (Const *) Resize(T->Value, (T->NValues + 100) * sizeof(Const));
	}

	T->Value[ T->NValues++ ] = FindConstant(Name, false);
    }
    while ( Delim == ',' );

    if ( Delim != '.' ) Error(2, Name, T->Name);
    EndLine;

    Type[++MaxType] = T;
    return true;
}


    ReadTypes()
/*  ---------  */
{
    int i, j;
    TypeInfo T;

    while ( ReadType() )
	;

    ForEach(i, 1, MaxType)
    {
	T = Type[i];

	T->CollSeq = (short *) malloc((MaxConst+1) * sizeof(short));
	ForEach(j, 0, MaxConst)
	{
	    T->CollSeq[j] = 0;
	}

	ForEach(j, 0, T->NValues-1)
	{
	    T->CollSeq[T->Value[j]] = j+1;
	}
    }
}



Tuple ReadTuple(R)
/*    ---------  */
    Relation R;
{
    char c;
    int N, i;
    Tuple T;

    N = R->Arity;

    if ( (c = ReadName(Name)) == '.' || c == ';' ) return Nil;

    T = (Tuple) malloc((N+1) * sizeof(Const));
    T[1] = FindConstant(Name, true);

    ForEach(i, 2, N)
    {
	c = ReadName(Name);
	T[i] = FindConstant(Name, true);
    }

    if ( c != ':' && c != '\n' ) ReadToEOLN;

    ForEach(i, 1, N)
    {
	if ( ! Type[R->Type[i]]->CollSeq[T[i]] ) Error(4, ConstName[T[i]], Type[R->Type[i]]->Name);
    }

    return T;
}


Tuple *ReadTuples(R, Plus)
/*     ----------  */
    Relation R;
    Boolean Plus;
{
    Tuple T, D[MAXTUPLES], *TheTuples;
    char c;
    int i, ND = 0;

    while ( T = ReadTuple(R) )
    {
	if ( ND >= MAXTUPLES )
	{
	    printf("ERROR: more than %d %s tuples\nRecompile with larger MAXTUPLES\n",
		MAXTUPLES, Plus ? "positive" : "negative");
	    exit();
	}

	T[0] = Plus ? PosMark : 0;
	D[ND++] = T;
    }

    TheTuples = (Tuple *) malloc((ND+1) * sizeof(Tuple));
    ForEach(i, 0, ND-1)
    {
	TheTuples[i] = D[i];
    }
    TheTuples[ND] = Nil;

    return TheTuples;
}



Relation ReadRelation()
/*       ------------  */
{
    Relation R;
    char Delim, c;
    int Key[100], NKeys = 0, i;

    if ( ReadName(Name) != '(' ) return Nil;

    R = (Relation) malloc(sizeof(struct _rel_rec));
    R->Name = CopyString(Name);

    R->Arity = 0;
    do
    {
	Delim = ReadName(Name);
	R->Type[++R->Arity] = FindType(Name);
    }
    while ( Delim != ')' );

    /*  Read and store access keys  */

    do
    {
	do
	{
	    c = getchar();
	}
	while ( Space(c) ) ;

	if ( c != '\n' )
	{
	    Key[NKeys] = 0;
	    ForEach(i, 1, R->Arity)
	    {
		if ( c == '-' ) Key[NKeys] |= (1 << i);
		c = getchar();
	    }
	    NKeys++;
	}
    }
    while ( c == '/');


    R->NKeys = NKeys;
    if ( NKeys )
    {
	R->Key   = (int *) malloc(NKeys * sizeof(int));
	memcpy(R->Key, Key, NKeys * sizeof(int));
    }

    /*ReadToEOLN;*/

    R->Pos = ReadTuples(R, true);

    if ( SectionDelim == '.' )
    {
	R->Neg = R->Opt = Nil;
    }
    else
    {
	R->Neg = ReadTuples(R, false);
    }

    return R;
}


/******************************************************************/
/*								  */
/*  Read a name into string s, returning terminating delimiter.	  */ 
/*  - Embedded spaces are permitted, but multiple spaces are	  */
/*    replaced by a single space.				  */
/*  - Any character after a \ is a valid character.		  */
/*  - The remainder of a line following '|' is ignored.		  */
/*								  */
/******************************************************************/

char ReadName(s)
/*   ---------  */
    char *s;
{
    register char *Sp = s;
    register int c;

    /*  Skip to first non-space character  */

    while ( ( c = getchar() ) == '|' || Space(c) )
	if ( c == '|' ) SkipComment;

    /*  Return period if no names to read  */

    if ( c == EOF )
    {
	return (SectionDelim = '.');
    }
    else
    if ( c == ';' || c == '.' )
    {
	getchar();
	return (SectionDelim = c);
    }

    /*  Read in characters up to the next delimiter  */

    while ( c != ',' && c != '\n' && c != '|' && c != EOF &&
	    c != '(' && c != ')'  && c != ':' && c != '.' )
    {
	if ( c == '\\' ) c = getchar();

	*Sp++ = c;
	if ( c == ' ' )
	    while ( ( c = getchar() ) == ' ' );
	else
	    c = getchar();
    }

    if ( c == '|' )
    {
	SkipComment;
	c = '\n';
    }

    /*  Strip trailing spaces  */

    while ( Space(*(Sp-1)) ) Sp--;
    *Sp++ = '\0';

    return c;
}



	/*  Find a constant in the list of constants, using
	    binary chop search  */

Const FindConstant(N, MustBeThere)
/*    ------------  */
    char *N;
    Boolean MustBeThere;
{
    int i, Hi=MaxConst+1, Lo=0, Differ=1;

    while ( Lo < Hi-1 )
    {
	Differ = strcmp(N, ConstName[SortedConst[i = (Hi + Lo)/2]]);

	if ( ! Differ )		return SortedConst[i];
	else
	if ( Differ > 0 )	Lo = i;
	else			Hi = i;
    }

    if ( MustBeThere ) Error(3, N);

    /*  This is a new constant -- record it  */

    if ( MaxConst % 1000 == 0 )
    {
	ConstName = (char **) Resize(ConstName, (MaxConst + 1000) * sizeof(char *));
	SortedConst = (Const *) Resize(SortedConst, (MaxConst + 1000) * sizeof(int));
    }

    MaxConst++;
    Lo++;
    for ( i = MaxConst ; i > Lo ; i-- )
    {
	SortedConst[i] = SortedConst[i-1];
    }
    SortedConst[Lo] = MaxConst;
    ConstName[MaxConst] = CopyString(N);
    return MaxConst;
}


	/*  Find a type by name  */

int FindType(N)
/*  --------  */
    char *N;
{
    int i;
    TypeInfo T;

    ForEach(i, 1, MaxType)
    {
	if ( ! strcmp(N, Type[i]->Name) ) return i;
    }

    Error(5, N);
}


    
    PrintTuples(N, TT, ShowClass)
/*  -----------  */
    int N;
    Tuples TT;
    Boolean ShowClass;
{
    if ( ! TT ) return;

    while ( *TT )
    {
	printf("\t\t");

	PrintTuple(*TT, N);

	if ( ShowClass )
	{
	    printf(": %c", (Positive(*TT) ? '+' : '-') );
	}

	putchar('\n');
	TT++;
    }
}



    PrintTuple(C, N)
/*  ----------  */
    Tuple C;
    int N;
{
    int i;

    ForEach(i, 1, N)
    {
	printf("%s", ConstName[C[i]]);
	if ( i < N ) putchar(',');
    }
}



    PrintLiteral(R, RSign, A)
/*  --------------  */
    Relation R;
    Boolean RSign;
    Vars A;
{
    int i, v;

    if ( ! RSign ) printf("~");

    printf("%s", R->Name);
    ForEach(i, 1, R->Arity)
    {
	v = A[i];
	printf("%c%c", (i > 1 ? ',' : '('), (v ? Variable[v] : '*'));
    }
    printf(")");
}



    PrintClause(R, C)
/*  ---------------  */
    Relation R;
    Clause C;
{
    int Lit;
    Literal L;

    PrintLiteral(R, true, DefVars);

    for ( Lit = 0 ; (L = C[Lit]) ; Lit++ )
    {
	if ( Lit == 0 )
	{
	    printf(" :- ");
	}
	else
	{
	    printf(", ");
	}

	PrintLiteral(L->Rel, L->Sign, L->Args);
    }

    newline;
}



    PrintDefinition(R)
/*  ---------------  */
    Relation R;
{
    int Cl;
    Literal L;

    newline;
    for ( Cl = 0 ; R->Def[Cl] ; Cl++ )
    {
	PrintClause(R, R->Def[Cl]);
    }
}


    Number(T)
/*  ------  */
    Tuple *T;
{
    int Count = 0;

    if ( ! T ) return 0;

    while ( *T++ )
    {
	Count++;
    }

    return Count;
}


    /*  Free up a bunch of tuples  */

    Discard(TT, TuplesToo)
/*  -------  */
    Tuples TT;
    Boolean TuplesToo;
{
    Tuple *P;

    if ( TuplesToo )
    {
	for ( P = TT ; *P ; P++ )
	{
	    free(*P);
	}
    }

    free(TT);
}


char *CopyString(s)
/*    ----------  */
    char *s;
{
    char *new;
    int l;

    l = strlen(s) + 1;
    new = malloc(l);
    memcpy(new, s, l);

    return new;
}



    Error(n, s1, s2)
/*  -----  */
    int n;
    char *s1, *s2;
{
    switch ( n )
    {
        case 1:	printf("Illegal delimiter after %s\n", s1);
		exit();

	case 2:	printf("Something wrong after %s in type %s\n", s1, s2);
		exit();

	case 3: printf("Undeclared constant %s\n", s1);
		exit();

	case 4: printf("Constant %s is not of type %s\n", s1, s2);
		exit();

	case 5: printf("Undeclared type %s\n", s1);
		exit();
    }
}