/***   declaration.c   ***/

#include "algol.h"
#include "declaration.h"
#include "coercion.h"
#include "declarer.h"
#include "unit.h"
	  /***  ERRORS: 411-2,421-5,431-4,441-4,451-5,461-2,471-3,552-4  ***/

static bool mode_definition(int), mode_declaration(int);
static bool priority_definition(int), priority_declaration(int);
static bool operator_definition(bool,int,int),operator_declaration(int);
static bool routine_id_definition(int), routine_var_definition(int);
static bool id_definition(int), var_definition(int);


#define decl(x)	(mode_declaration(x) || priority_declaration(x) || \
	operator_declaration(x) || routine_id_definition(x) || \
	routine_var_definition(x) || id_definition(x) || \
	var_definition(x))

bool declaration(Q) int Q;
{int Pold,jold;
	Pold=P; jold=J;
#if DEBUG
	fprintf(O,"declaration, Q=%c, P=%d\n",Q==G?'G':Q==H?'H':'F',P);
#endif
	if(decl(Q)){
	    do{Pold=P;}while(inp(COMMA) && decl(Q));
	    if(Q==G){more_instance(Z=1); unmask(jold);}
	    P=Pold; return(TRUE);
	} P=Pold; return(FALSE);
}

static bool mode_definition(Q) int Q;
{int v,el,PP;
	if(inp_ind(&el) && inp(EQ)){
	    PP=P; must(declarer(ACTUAL,&dummy,F,TRUE),462);
	    if(Q==H){v=ask(); A[v]=MODE; B[v]= -1;C[v]=PP;possess(el,v);}
	    return(TRUE);
	} return(FALSE);
}

static bool mode_declaration(Q) int Q;
{int Pold;
	if(!inp(MODE))return(FALSE);
	must(mode_definition(Q),461);
	do{Pold=P;}while(inp(COMMA) && mode_definition(Q));
	P=Pold; return(TRUE);
}

static bool priority_definition(Q) int Q;
{int v,el,d; inta prio;
	if(inp_ind(&el) && inp(EQ)){
	    must(inp_denoter(&d),441);
	    if(Q==G){
		put_denoter(d); must(A[Z]==INT,442); prio=get_int(Z); emp();
		must(0<prio && prio<10,443);
		v=ask(); A[v]=PRIO; B[v]=(int)prio; possess(el,v);
	    }
	    return(TRUE);
	} return(FALSE);
}

static bool priority_declaration(Q) int Q;
{int Pold;
	if(!inp(PRIO))return(FALSE);
	must(priority_definition(Q),444);
	do{Pold=P;}while(inp(COMMA) && priority_definition(Q));
	P=Pold; return(TRUE);
}

static bool operator_definition(rx,t,Q) bool rx; int t,Q;
{int Q0,v,w,el,i,jj;
	if(inp_ind(&el) && inp(EQ)){
	    Q0=Q;
	    if(!rx){ must(routine_text(Q),452); A[B[Z]]=JGLOB;}
	       else{ must(unit(&Q),453);}
	    if(Q0==G){
		if(rx){must(strong_coercion(t,&Q),554); must(Q==G,473);}
		v=ask(); A[v]=OP; B[v]=w=askn(i=C[Z]+1); copyn(B[Z],w,i);
		if(i==2){C[v]=10;}else{
		    must(i==3,451); more_instance(A[w+1]=B[w+2]); jj=J;
		    C[v]=further_search(el,TRUE,&jj,&i)?i:1;
		}
		possess(el,v);
		more_instance(B[w]); more_instance(B[w+1]); emp();
	    }
	    return(TRUE);
	} return(FALSE);
}

static bool operator_declaration(Q) int Q;
{int t,Pold; bool rx;
	if(!inp(OP))return(FALSE);
	if((rx=spy(OPEN))!=0){must(plan(FORMAL,&t,Q),454);}
	must(operator_definition(rx,t,Q),455);
	do{Pold=P;}while(inp(COMMA) && operator_definition(rx,t,Q));
	P=Pold; if(rx && Q==G)relax(t); return(TRUE);
}

static bool routine_id_definition(Q) int Q;
{int Pold,el;
	Pold=P;
	if(inp(PROC) && inp_tag(&el) && inp(EQ)){
	    do{ must(routine_text(Q),411);
		if(Q==G){ A[B[Z]]=JGLOB; possess(mask(el),Z);}
		Pold=P;
	    }while(inp(COMMA) && inp_tag(&el) && inp(EQ));
	    P=Pold; return(TRUE);
	}
	P=Pold; return(FALSE);
}

static bool routine_var_definition(Q) int Q;
{int Pold,el,v;
	Pold=P;
	if(inp(PROC) && inp_tag(&el) && inp(BECOMES)){
	    do{ must(routine_text(Q),412);
	        if(Q==G){
		    v=ask(); A[v]=REF; B[v]=Z; C[v]=1; A[B[Z]]=JGLOB;
		    possess(mask(el),v);
		}
		Pold=P;
	    }while(inp(COMMA) && inp_tag(&el) && inp(BECOMES));
	    P=Pold; return(TRUE);
	} P=Pold; return(FALSE);
}

static bool id_definition(Q) int Q;
{int Pold,t,el;
	Pold=P;
	if(declarer(FORMAL,&t,F,FALSE) && inp_tag(&dummy) && inp(EQ)){
	    if(Q!=G){
		do{ must(unit(&F),421);Pold=P;
		}while(inp(COMMA) && inp_tag(&dummy) && inp(EQ));
	    }else{
		P=Pold; must(declarer(FORMAL,&t,Q,TRUE),422);
		must(inp_tag(&el),423); must(inp(EQ),424);
		do{ must(unit(&Q),425);
		    must(strong_coercion(t,&Q),552); must(Q==G,471);
		    possess(mask(el),Z); Pold=P;
		}while(inp(COMMA) && inp_tag(&el) && inp(EQ));
		relax(t);
	    } P=Pold; return(TRUE);
	} P=Pold; return(FALSE);
}

static bool var_definition(Q) int Q;
{int Pold,P1,t,el,v,w;
	Pold=P; bummy=inp(LOC) || inp(HEAP); P1=P;
	if(declarer(FORMAL,&t,F,FALSE) && inp_tag(&dummy)){
	    P=P1; must(declarer(ACTUAL,&t,Q,TRUE),431);must(inp_tag(&el),432);
	    do{ if(Q==G){
			v=actual_instance(t); w=new_reference(v); relax(v);
			if(inp(BECOMES)){
			   must(unit(&Q),433);must(strong_coercion(t,&Q),553);
			   must(Q==G,472); replace(Z,v);
			}
			possess(mask(el),w);
		}else if(inp(BECOMES)){must(unit(&Q),434);}
		Pold=P;
	    }while(inp(COMMA) && inp_tag(&el));
	    if(Q==G)relax(t); P=Pold; return(TRUE);
	} P=Pold; return(FALSE);
}

