/*	@(#)main.c	2.1		*/
/*	3.0 SID #	1.2	*/
static char xxxvers[ ] = "\n@(#)EFL VERSION 1.14,  19 AUGUST 1980";

/* Compiler for the EFL Programming Language.  
*/


/* Flags:
	-d	EFL debugging output
	-v	verbose (print out Pass numbers and memory limits)
	-w	supress warning messages
	-f	put Fortran output on appropriate .f files
	-F	put Fortran code for input file x onto x.F
	-e	divert diagnostic output to next argument
	-#	do not pass comments through to output
*/


#include "defs"

int sysflag;

int nerrs	= 0;
int nbad	= 0;
int nwarns	= 0;
int stnos[MAXSTNO];
int nxtstno	= 0;
int constno	= 0;
int labno	= 0;

int dumpic	= NO;
int memdump	= NO;
int dbgflag	= NO;
int nowarnflag	= NO;
int nocommentflag	= NO;
int verbose	= NO;
int dumpcore	= NO;
char msg[200];

struct fileblock fcb[4];
struct fileblock *iifilep;
struct fileblock *ibfile	= &fcb[0];
struct fileblock *icfile	= &fcb[1];
struct fileblock *idfile	= &fcb[2];
struct fileblock *iefile	= &fcb[3];

FILE *diagfile	= {stderr};
FILE *codefile	= {stdout};
FILE *fileptrs[MAXINCLUDEDEPTH];
char *filenames[MAXINCLUDEDEPTH];
char *basefile;
int filelines[MAXINCLUDEDEPTH];
int filedepth	= 0;
char *efmacp	= NULL;
char *filemacs[MAXINCLUDEDEPTH];
int pushchars[MAXINCLUDEDEPTH];
int ateof	= NO;

int igeol	= NO;
int pushlex	= NO;
int eofneed	= NO;
int forcerr	 = NO;
int defneed	 = NO;
int prevbg	 = NO;
int comneed	 = NO;
int optneed	 = NO;
int lettneed	= NO;
int iobrlevel	= 0;

ptr comments	= NULL;
ptr prevcomments	= NULL;
ptr genequivs	= NULL;
ptr arrays	= NULL;
ptr generlist	= NULL;
ptr knownlist	= NULL;

ptr thisexec;
ptr thisctl;
chainp tempvarlist	= CHNULL;
chainp temptypelist	= CHNULL;
chainp hidlist	= CHNULL;
chainp commonlist	= CHNULL;
chainp gonelist	= CHNULL;
int blklevel	= 0;
int ctllevel	= 0;
int dclsect	= 0;
int instruct	= 0;
int inbound	= 0;
int inproc	= 0;
int ncases	= 0;

int graal	= 0;
ptr procname	= NULL;
int procclass	= 0;
ptr thisargs	= NULL;

int nhid[MAXBLOCKDEPTH];
int ndecl[MAXBLOCKDEPTH];

char ftnames[MAXFTNAMES][7];


int neflnames	= 0;

int nftnames;
int nftnm0;
int impltype[26];

int ftnefl[NFTNTYPES]	= { TYINT, TYREAL, TYLOG, TYCOMPLEX, TYLREAL,
				TYCHAR, TYLCOMPLEX };
int eflftn[NEFLTYPES];
int ftnmask[NFTNTYPES] 	= { 1, 2, 4, 8, 16, 32, 64 };
struct tailoring tailor;
struct system systab[] =
	{
		{ "portable", 0,	1, 10, 7, 15},
		{ "unix", UNIX,	4, 10, 7, 15 },
		{ "gcos", GCOS,	4, 10, 7, 15 },
		{ "gcosbcd", GCOSBCD,	6, 10, 7, 15},
		{ "cray", CRAY,	8, 10, 7, 15},
		{ "ibm", IBM,	4, 10, 7, 15 },
		{ NULL }
	};

double fieldmax	= FIELDMAX;

int langopt	= 2;
int dotsopt	= 0;
int dbgopt	= 0;
int dbglevel	= 0;

int nftnch;
int nftncont;
int indifs[MAXINDIFS];
int nxtindif;
int afterif	= 0;

#ifdef	gcos
#	define BIT(n)	(1 << (36 - 1 - n) )
#	define FORTRAN	BIT(1)
#	define FDS	BIT(4)
#	define EXEC	BIT(5)
#	define FORM	BIT(14)
#	define LNO	BIT(15)
#	define BCD	BIT(16)
#	define OPTZ	BIT(17)
	int	compile	= FORTRAN | FDS;
#endif


main(argc,argv)
register int argc;
register char **argv;
{
FILE *fd;
register char *p;
int neflnm0;

#ifdef unix
	int intrupt();
	sysflag = UNIX;

/*
	meter();
*/
	if( (signal(2,1) & 01) == 0)
		signal(2, intrupt);
#endif

#ifdef gcos
/*
	meter();
*/
	sysflag = (intss() ? GCOS : GCOSBCD);
#endif


crii();
--argc;
++argv;
tailinit(systab + sysflag);

while(argc>0 && ( (argv[0][0]=='-' && argv[0][1]!='\0') || eqlstrng(argv[0]) ))
	{
	if(argv[0][0] == '-')
	    for(p = argv[0]+1 ; *p ; ++p) switch(*p)
		{
		case ' ':
			break;

		case 'd':
		case 'D':
			switch( *++p)
				{
				case '1':
					dbgflag = YES;
					break;
				case '2':
					setyydeb();
					break;
				case '3':
					dumpcore = YES;
					break;
				case '4':
					dumpic = YES;
					break;
				case 'm':
				case 'M':
					memdump = YES;
					break;

				default:
					dbgflag = YES;
					--p;
					break;
				}
			break;

		case 'w':
		case 'W':
			nowarnflag = YES;
			break;

		case 'v':
		case 'V':
			verbose = YES;
			break;

		case '#':
			nocommentflag = YES;
			break;

		case 'C':
		case 'c':
			nocommentflag = NO;
			break;

#ifdef gcos
		case 'O':
		case 'o':
			compile |= OPTZ;
			break;

		case 'E':
		case 'e':
			compile = 0;
			break;
#endif

		default:
			fprintf(diagfile, "Illegal EFL flag %c\n", *p);
			exit(1);
		}
	--argc;
	++argv;
	}

kwinit();
geninit();
knowninit();
init();
implinit();
neflnm0 = neflnames;

#ifdef gcos
	if( intss() )
		compile = 0;
	else
		gcoutf();
#endif

/*	fprintf(diagfile, "EFL 1.10\n");	*/

if(argc==0)
	{
	filenames[0] = "-";
	dofile(stdin);
	}
else
	while(argc>0)
		{
		if( eqlstrng(argv[0]) )
			{
			--argc;
			++argv;
			continue;
			}
		if(argv[0][0]=='-' && argv[0][1]=='\0')
			{
			basefile = "";
			fd = stdin;
			}
		else	{
			basefile = argv[0];
			fd = fopen(argv[0], "r");
			}
		if(fd == NULL)
			{
			sprintf(msg, "Cannot open file %s", argv[0]);
			fprintf(diagfile, "%s.  Stop\n", msg);
			done(2);
			}
		filenames[0] = argv[0];
		filedepth = 0;

		nftnames = 0;
		nftnm0 = 0;
		neflnames = neflnm0;

		dofile(fd);
		if(fd != stdin)
			fclose(fd);
		--argc;
		++argv;
		}
p2flush();
if(verbose)
	fprintf(diagfile, "End of compilation\n");
/*
prhisto();
/* */
rmiis();

#ifdef gcos
	gccomp();
#endif

done(nbad);
}


dofile(fd)
FILE *fd;
{
int k;

fprintf(diagfile, "File %s:\n", filenames[0]);

#ifdef gcos
	if( fd==stdin && intss() && inquire(stdin, _TTY) )
		freopen("*src", "rt", stdin);
#endif

yyin = fileptrs[0] = fd;
yylineno = filelines[0] = 1;
filedepth = 0;
ateof = 0;

do	{
	nerrs = 0;
	nwarns = 0;
	eofneed = 0;
	forcerr = 0;
	comneed = 0;
	optneed = 0;
	defneed = 0;
	lettneed = 0;
	iobrlevel = 0;
	prevbg = 0;

	constno = 0;
	labno = 0;
	nxtstno = 0;
	afterif = 0;
	thisexec = 0;
	thisctl = 0;
	nxtindif = 0;
	inproc = 0;
	blklevel = 0;

	implinit();

	opiis();
	swii(icfile);

	if(k = yyparse())
		fprintf(diagfile, "Error in source file.\n");
	else  switch(graal)
		{
		case PARSERR:
			/*
			fprintf(diagfile, "error\n");
			*/
			break;

		case PARSEOF:
			break;

		case PARSOPT:
			propts();
			break;

		case PARSDCL:
			fprintf(diagfile, "external declaration\n");
			break;

		case PARSPROC:
			/* work already done in endproc */
			break;

		case PARSDEF:
			break;
		}

	cliis();
	if(nerrs) ++nbad;

	} while(graal!=PARSEOF && !ateof);
}

ptr bgnproc()
{
ptr bgnexec();

if(blklevel > 0)
	{
	execerr("procedure %s terminated prematurely", procnm() );
	endproc();
	}
ctllevel = 0;
procname = 0;
procclass = 0;
thisargs = 0;
dclsect = 0;
blklevel = 1;
nftnm0 = nftnames;
dclsect = 1;
ndecl[1] = 0;
nhid[1] = 0;

thisctl = allexcblock();
thisctl->tag = TCONTROL;
thisctl->subtype = STPROC;
inproc = 1;
return( bgnexec() );
}


endproc()
{
char comline[50], *concat();
ptr p;

inproc = 0;

if(nerrs == 0)
	{
	pass2();
	unhide();
	cleanst();
	if(dumpic)
		system( concat("od ", icfile->filename, comline) );
	if(memdump)
		prmem();
	}
else	{
	fprintf(diagfile, "**Procedure %s not generated\n", procnm());
	for( ; blklevel > 0 ; --blklevel)
		unhide();
	cleanst();
	}

if(nerrs==0 && nwarns>0)
	if(nwarns == 1)
		fprintf(diagfile,"*1 warning\n");
	else	fprintf(diagfile, "*%d warnings\n", nwarns);

blklevel = 0;
thisargs = 0;
procname = 0;
procclass = 0;
while(thisctl)
	{
	p = thisctl;
	thisctl = thisctl->prevctl;
	frexcblock(p);
	}

while(thisexec)
	{
	p = thisexec;
	thisexec = thisexec->prevexec;
	frexcblock(p);
	}

nftnames = nftnm0;
if(verbose)
	{
	fprintf(diagfile, "Highwater mark %d words. ", nmemused);
	fprintf(diagfile, "%ld words left over\n", totalloc-totfreed);
	}
}




implinit()
{
setimpl(TYREAL, 'a', 'z');
setimpl(TYINT,  'i', 'n');
}



init()
{
eflftn[TYINT] = FTNINT;
eflftn[TYREAL] = FTNREAL;
eflftn[TYLREAL] = FTNDOUBLE;
eflftn[TYLOG] = FTNLOG;
eflftn[TYCOMPLEX] = FTNCOMPLEX;
eflftn[TYCHAR] = FTNINT;
eflftn[TYFIELD] = FTNINT;
eflftn[TYLCOMPLEX] = FTNDOUBLE;
}




#ifdef gcos
meter()
{
FILE *mout;
char *cuserid(), *datime(), *s;
if(equals(s = cuserid(), "efl")) return;
mout = fopen("efl/eflmeter", "a");
if(mout == NULL)
	fprintf(diagfile,"cannot open meter file");

else	{
	fprintf(mout, "%s user %s at %s\n",
		( rutss()? "tss  " : "batch"), s, datime() );
	fclose(mout);
	}
}
#endif



#ifdef unix
meter()	/* temporary metering of non-SIF usage */
{
FILE *mout;
int tvec[2];
int uid;
char *ctime(), *p;

uid = getuid() & 0377;
if(uid == 91) return;	/* ignore sif uses */
mout = fopen("/usr/sif/efl/Meter", "a");
if(mout == NULL)
	fprintf(diagfile, "cannot open meter file");
else	{
	time(tvec);
	p = ctime(tvec);
	p[16] = '\0';
	fprintf(mout,"User %d, %s\n",  uid, p+4);
	fclose(mout);
	}
}

intrupt()
{
done(0);
}
#endif


done(k)
int k;
{
rmiis();
exit(k);
}





/* if string has an embedded equal sign, set option with it*/
eqlstrng(s)
char *s;
{
register char *t;

for(t = s; *t; ++t)
	if(*t == '=')
		{
		*t = '\0';
		while( *++t == ' ' )
			;
		setopt(s, t);
		return(YES);
		}

return(NO);
}

#ifdef gcos

/* redirect output unit */

gcoutf()
{
if (!intss())
	{
	fputs("\t\t    Version 2.10 : read INFO/EFL (03/27/80)\n", stderr);
	if (compile)
		{
		static char name[80] = "s*", opts[20] = "yw";
		char *opt = (char *)inquire(stdout, _OPTIONS);
		if (!strchr(opt, 't'))
			{ /* if stdout is diverted */
			sprintf(name, "%s\"s*\"",
				(char *)inquire(stdout, _FILENAME));
			strcpy(&opts[1], opt);
			}
		if (freopen(name, opts, stdout) == NULL)
			cant(name);
		}
	}
}



/* call in fortran compiler if necessary */

gccomp()
{
if (compile)
	{
	if (nbad > 0)	/* abort */
		cretsw(EXEC);

	else	{ /* good: call forty */
		FILE *dstar; /* to intercept "gosys" action */

		if ((dstar = fopen("d*", "wv")) == NULL)
			cant("d*");
		fputs("$\tforty\tascii", dstar);
		if (fopen("*1", "o") == NULL)
			cant("*1");
		fclose(stdout, "rl");
		cretsw(FORM | LNO | BCD);
		if (! tailor.ftncontnu)
			compile |= FORM;
		csetsw(compile);
		gosys("forty");
		}
	}
}


cant(s)
char *s;
{
ffiler(s);
done(1);
}
#endif
