AUSAM/source/S/cc.c

Compare this file to the similar file:
Show the results in this format:

#
/*
 *	IFEXPR:
 *
 *
 *	if[n]defs extended to handle expressions rather than the
 *	mention of a single name, binary operators supported are
 *	| (or) and & (and), ! (not) is only unary operator supported.
 *	Nested expressions are supported using ( and ).
 *	Precedence of evaluation is !(not) &(and) |(or).
 *	ifndef adopts an unusual convention with respect to ots effect
 *	i.e.
 *		#ifndef	a|b
 *	 is equivalent to
 *		#ifdef !(a|b)
 *
 *	#else added.
 *	i.e.
 *		#ifdef abc
 *			.....
 *		#endif
 *		#ifndef abc
 *			.....
 *		#endif
 *	is equivalent to
 *		#ifdef abc
 *			.....
 *		#else
 *			.....
 *		#endif
 *
 *			ANDREW HUME & IAN JOHNSTONE
 *			17-08-77
 *			 4-04-78
 *
 *	BETTER_FILES:
 *
 *	use 'mktemp' to create temporary files
 *	this solves duplicate tmp file problem.
 *			GREG ROSE
 *			30-03-78
 *
 *	LIST:
 *
 *	Produce line numbered listings of the source that C is actually
 *	going to compile - in other words take note of if[n]defs etc...
 *	Line numbers that appear on listing file (*.l) are actual line numbers
 *	in the file in which the line appears. Include files may also be listed.
 *	Of course characters in strings, character constants, defines,
 *	macros and comments are all handled as you would expect - PROPERLY
 *
 *	-L[O][I]
 *		L produce listing
 *		O listing only - no compilation, no .i file etc...
 *		I include included files in listing
 *		V list all lines not generating code
 *		   ( no line numbers/listing levels )
 *
 *	sample:
 *		0001 -- main()
 *		0002 0- {
 *		0003 -- 	int a;
 *		0004 -0 }
 *
 *	errors:
 *		too many '}'s (unmatched) give rise to an error
 *		message "too many '}'s"
 *	COMMENT:
 *	A SIDE EFFECT of this alteration is that comments are now handle
 *	in a more consistent way with respect to line numbering, e.g.
 *		0001 --     <<<error>>> ; /* a very
 *		0002 --			     long
 *		0003 --			     comment */
 *	under the old cc the error diagnostic for the above error would refer
 *	to line 3 (yes it did) under the new scheme it will refer to line 1
 *	(a little more sensible).
 *			IAN JOHNSTONE
 *			 3-04-78
 *
 *	OUTPUT:
 *
 *	For those of you who are sick and tired of " cc -o apple apple.c "
 *	then this mod is for you.  If -o is used then a quick check is made
 *	to determine if a output file has been specified if none is present
 *	then the name (no suffix) of the first mentioned file (*.s,*.o,*.c)
 *	appearing after the option is used as the output file. NOTE the entire
 *	pathname is not used only that portion appearing after the last '/'
 *	and before the . of the suffix. So "cc -o apple.c" is equivalent to
 *	the above.
 *			IAN JOHNSTONE
 *			 3-04-78
 *
 *	OPT:
 *
 *	IF you've always wanted to print out the stats from the C optimiser
 *	you now can ( yes virginia there is a santa claus ).
 *	All that need be done is to place any non-null char after '-O'
 *	and bingo as it were.
 *			IAN JOHNSTONE
 *			 4-04-78
 *
 */

#define IFEXPR			/***/
#define BETTER_FILES		/***/
#define LIST			/***/
#define OUTPUT			/***/
#define OPT			/***/
/*#define TEST	/* to include some test code - have a look if ya like */
#ifdef LIST
#define COMMENT
#endif


/* C command */

# define SBSIZE 10000
# define MAXINC 10
char	sbf[SBSIZE];
#ifdef	LIST
char	itoabuf[20];
#endif	LIST
char	*tmp0;
char	*tmp1;
char	*tmp2;
char	*tmp3;
char	*tmp4;
char	*tmp5;
char	*outfile;
# define CHSPACE 1000
char	ts[CHSPACE+50];
# define EXPSIZE 500
char	*tsa ts;
char	*tsp ts;
char	*av[50];
char	*clist[50];
char	*llist[50];
int	instring;
#ifdef	COMMENT
int	incomment;
#endif
int	pflag;
int	sflag;
#ifdef	LIST
int	llflag;		/* listing flag */
#define	LLLIS	01 	/* produce listing */
#define	LLINCL	02 	/* list includes too */
#define	LLONLY	04 	/* listing only */
#define	LLVERB	08	/* list all lines even those not gening code */
#endif	LIST
int	cflag;
int	eflag;
int	exflag;
int	oflag;
int	proflag;
int	depth;
int	*ibuf;
int	*ibufs[MAXINC];
int	ifno;
int	*obuf;
extern int	fout;
char	*lp;
char	*line;
char *predef;
char *sprefix "/usr/include";
int	lineno[MAXINC];
int	exfail;
struct symtab {
	char	name[8];
	char	*value;
} *symtab;
# define symsiz 400
struct symtab *defloc;
struct symtab *incloc;
struct symtab *eifloc;
struct symtab *ifdloc;
struct symtab *ifnloc;
struct symtab *unxloc;
struct symtab *lneloc;
struct symtab *prdloc;
#ifdef	IFEXPR
struct symtab *elsloc;
       /*
	* the following two variables values are altered by getline
	* in response to #ifdefs,#ifndefs,#endifs and #elses it may
	* encounter. The net effect of theses changes is to control
 	* the compilation of the desired program segments:
	*
	* if( flslvl != 0 ) then no compile - just flush input
	*		    until an appropriate #endif of #else
	*		    is encountered.
	*		    flslvl is in effect the number of FALSE
	*		    plus the number of subsequent TRUE
	*		    nested #ifdefs or #ifndefs
	* if( flslvl == 0 ) compile all input.
	*		    trulvl is in effect the number of TRUE
	*		    nested #ifdefs or #ifndefs before the
	*		    first FALSE #if
	*/
#endif	IFEXPR
int	trulvl;
int	flslvl;
char	*stringbuf;
char	*pass0 "/lib/c0";
char	*pass1 "/lib/c1";
char	*pass2 "/lib/c2";
char	*pref "/lib/crt0.o";

main(argc, argv)
char *argv[]; {
	char *t;
	char *savetsp;
	char *assource;
	int nc, nl, i, j, c, f20, nxo;
	int dexit();

	i = nc = nl = f20 = nxo = 0;
	while(++i < argc) {
		if(*argv[i] == '-') switch (argv[i][1]) {
			default:
				goto passa;
			case 'S':
				sflag++;
				cflag++;
				break;
#ifdef	LIST
			case 'L':
				llflag=LLLIS;
				t = &argv[i][2];
				while( c = *t++ ) {
					switch( c ) {
					case 'i':
					case 'I':
						llflag =| LLINCL;
						break;
					case 'o':
					case 'O':
						llflag =| LLONLY;
						pflag++;
						cflag++;
						break;
					case 'v':
					case 'V':
						llflag =| LLVERB;
						break;
					}
				}
				break;
#endif	LIST
			case 'o':
				if (++i < argc) {
					outfile = argv[i];
#ifndef	OUTPUT
					if ((t=getsuf(outfile))=='c'||t=='o') {
						error("Would overwrite %s", outfile);
						exit(8);
#endif	OUTPUT
#ifdef	OUTPUT
					if ((t=getsuf(outfile))=='c'||t=='o'||*argv[i]=='-') {
						i--;
						outfile = -1;
#endif	OUTPUT
					}
				}
				break;
			case 'O':
#ifndef	OPT
				oflag++;
#endif	OPT
#ifdef	OPT
				oflag=1;
				if( argv[i][2] != 0 ) oflag=2;
#endif	OPT
				break;
			case 'p':
				proflag++;
				pref = "/lib/mcrt0.o";
				break;
			case 'E':
				exflag++;
			case 'P':
					pflag++;
			case 'c':
				cflag++;
				break;

			case 'f':
				pref = "/lib/fcrt0.o";
				pass0 = "/lib/fc0";
				pass1 = "/lib/fc1";
				break;

			case 'D':
				predef = argv[i]+2;
				break;
			case 'I':
				sprefix=argv[i]+2;
				break;
#ifdef	TEST
			case '2':
				if(argv[i][2] == '\0')
					pref = "/lib/crt2.o";
				else {
					pref = "/lib/crt20.o";
					f20 = 1;
				}
				break;
			case 't':
				if (argv[i][2]=='0')
					pass0 = "/sys/c/c0";
				if (argv[i][2]=='1')
					pass1 = "/sys/c/c1";
				if (argv[i][2]=='2')
					pass2 = "/sys/c/c2";
				break;

			case 'B':
				pass0 = "/sys/c/oc0";
				pass1 = "/sys/c/oc1";
				break;
#endif	TEST
		} else {
		passa:
			t = argv[i];
#ifdef	LIST
			if( ((c=getsuf(t))=='h') && (llflag&LLONLY) ) {

				clist[nc++] = t;
			} else
#endif	LIST
			if((c=getsuf(t))=='c' || c=='s'|| exflag) {
				clist[nc++] = t;
				t = setsuf(t, 'o');
			}
			if (nodup(llist, t)) {
				llist[nl++] = t;
				if (getsuf(t)=='o') {
					nxo++;
#ifdef	OUTPUT
					if( outfile == -1 ) {
				/* no output file specified to this point
				   but '-o' specified so use filename of first
				   pathname encountered for output, regardless
				   of whether is was a .s or .c or .o pathname */
						t = outfile = setsuf( t , 0 );
						while( *t++ ) ;
						t[-2] = 0;
					}
#endif	OUTPUT
				}
			}
		}
	}
	if(nc==0)
		goto nocom;
	if (pflag==0) {
#ifndef	BETTER_FILES
		tmp0 = copy("/tmp/ctm0a");
#endif	BETTER_FILES
#ifdef	BETTER_FILES
		tmp0 = mktemp( copy("/tmp/ctm0.XXXXX"));
#endif	BETTER_FILES
		while((c=open(tmp0, 0))>=0) {
			close(c);
			tmp0[9]++;
		}
		while((creat(tmp0, 0400))<0)
			tmp0[9]++;
	}
	if ((signal(2, 1) & 01) == 0)	/* interrupt */
		signal(2, dexit);
	if ((signal(15, 1) & 01) == 0)	/* terminate */
		signal(15, dexit);
	(tmp1 = copy(tmp0))[8] = '1';
	(tmp2 = copy(tmp0))[8] = '2';
	(tmp3 = copy(tmp0))[8] = '3';
	if (oflag)
		(tmp5 = copy(tmp0))[8] = '5';
	if (pflag==0)
		(tmp4 = copy(tmp0))[8] = '4';
	for (i=0; i<nc; i++) {
		if (nc>1)
			printf("%s:\n", clist[i]);
		if (getsuf(clist[i])=='s') {
			assource = clist[i];
			goto assemble;
		} else
			assource = tmp3;
		av[0] = "c0";
#ifndef	LIST
		if (pflag)
#endif	LIST
#ifdef	LIST
		if( pflag && !(llflag&LLONLY) )
#endif	LIST
			tmp4 = setsuf(clist[i], 'i');
		savetsp = tsp;
		av[1] = expand(clist[i]);
		tsp = savetsp;
		if (pflag || exfail)
			continue;
		if (av[1] == 0) {
			cflag++;
			eflag++;
			continue;
		}
		av[2] = tmp1;
		av[3] = tmp2;
		if (proflag) {
			av[4] = "-P";
			av[5] = 0;
		} else
			av[4] = 0;
		if (callsys(pass0, av)) {
			cflag++;
			eflag++;
			continue;
		}
		av[0] = "c1";
		av[1] = tmp1;
		av[2] = tmp2;
		if (sflag)
			assource = tmp3 = setsuf(clist[i], 's');
		av[3] = tmp3;
		if (oflag)
			av[3] = tmp5;
		av[4] = 0;
		if(callsys(pass1, av)) {
			cflag++;
			eflag++;
			continue;
		}
		if (oflag) {
			av[0] = "c2";
#ifndef	OPT
			av[1] = tmp5;
			av[2] = tmp3;
			av[3] = 0;
#endif	OPT
#ifdef	OPT
			j = 1;
			if( oflag==2 ) av[j++] = "-";
			av[j++] = tmp5;
			av[j++] = tmp3;
			av[j++] = 0;

#endif	OPT
			if (callsys(pass2, av)) {
				cflag++;
				eflag++;
				continue;
			}
			unlink(tmp5);
		}
		if (sflag)
			continue;
	assemble:
		av[0] = "as";
		av[1] = "-o";
		av[2] = setsuf(clist[i], 'o');
		av[3] = "-u";
		av[4] = assource;
		av[5] = 0;
		cunlink(tmp1);
		cunlink(tmp2);
		cunlink(tmp4);
		if (callsys("/bin/as", av) > 1) {
			cflag++;
			eflag++;
			continue;
		}
	}
nocom:
	if (cflag==0 && nl!=0) {
		i = 0;
		av[0] = "ld";
		av[1] = "-X";
		av[2] = pref;
		j = 3;
		if (outfile) {
			av[j++] = "-o";
			av[j++] = outfile;
		}
		while(i<nl)
			av[j++] = llist[i++];
		if(f20)
			av[j++] = "-l2";
		else {
			av[j++] = "-lc";
			av[j++] = "-l";
		}
		av[j++] = 0;
		eflag =| callsys("/bin/ld", av);
		if (nc==1 && nxo==1 && eflag==0)
			cunlink(setsuf(clist[0], 'o'));
	}
	dexit();
}

dexit()
{
	if (!pflag) {
		cunlink(tmp1);
		cunlink(tmp2);
		if (sflag==0)
			cunlink(tmp3);
		cunlink(tmp4);
		cunlink(tmp5);
		cunlink(tmp0);
	}
	exit(eflag);
}

# define LINELEN 500
#ifdef	LIST
char lline[LINELEN+8] "nnnn --  ";
char *llinep;
int llevel 0;
#endif	LIST
char *fnames[MAXINC];

expand(file)
char *file;
{
	int ob[259];
	struct symtab stab[symsiz];
	char ln[LINELEN];
	register int c;
	register char *rlp;
#ifdef	LIST
	int llbuf[259];
#endif	LIST

	exfail = 0;
	ifno=0;
	if (ibufs[0]==0)
		ibufs[0] = sbrk(518);
	ibuf=ibufs[0];
	fnames[ifno] = file;
	if (fopen(file, ibuf)<0) {
		error("No file %s", file);
		return(file);
		}
	obuf = ob;
	symtab = stab;
	for (c=0; c<symsiz; c++) {
		stab[c].name[0] = '\0';
		stab[c].value = 0;
	}
	insym(&defloc, "define");
	insym(&incloc, "include");
	insym(&eifloc, "endif");
	insym(&ifdloc, "ifdef");
	insym(&ifnloc, "ifndef");
	insym(&unxloc, "unix");
	insym(&lneloc, "line");
#ifdef	IFEXPR
	insym(&elsloc, "else");
#endif	IFEXPR
	if (predef)
	insym(&prdloc, predef);
	stringbuf = sbf;
	trulvl = 0;
	flslvl = 0;
	line  = ln;
	lineno[0] = 1;
	if (exflag==0) {
#ifdef	LIST
		if( (llflag&LLONLY)==0 )  {
#endif	LIST
			if (fcreat(tmp4, obuf) < 0) {
				printf("Can't creat %s\n", tmp4);
				dexit();
			}
#ifdef	LIST
		} else obuf[0] = -1;	/* lets not bother with the i/o */
					/* a liitle kludgy but.... */
					/* about a zillion tests required otherwise */
#endif	LIST
	} else {
		obuf = &fout;
		fout = dup(1);
	}
#ifdef	LIST
	if( llflag ) {
		if( fcreat(setsuf(file,'l'),llbuf) < 0 ) {
			printf("Can't create %s\n",setsuf(file,'l'));
			dexit();
		}
	}
#endif	LIST
	puts("# 1 \"");
	puts(file);
	puts("\"\n");
#ifdef	LIST
	llinep = &lline[8];
	llevel = -1;
#endif	LIST
	while(getline()) {
#ifdef	LIST
		putline(llbuf);
#endif	LIST
		if (ln[0] != '#' && flslvl==0)
			for (rlp = line; c = *rlp++;)
				putc(c, obuf);
		putc('\n', obuf);
	}
	for(rlp=line; c = *rlp++;)
			putc(c,obuf);
#ifdef	LIST
	if( llflag ) {
		fflush(llbuf);
		close( llbuf[0] );
	}
#endif	LIST
#ifdef	IFEXPR
	if( flslvl || trulvl ) errexit("missing endif");
#endif	IFEXPR
	fflush(obuf);
	if (obuf != &fout)
	close(obuf[0]);
	close(ibuf[0]);
	return(tmp4);
}

#ifdef	LIST
putline(llbuf)
int *llbuf;
{
	static char levelchars[] "?0123456789abcdefghijklmnopqrstuvwxyz";
	register char *rlp;
	register int c;
	register int cs;
	int css;
	int blevel,elevel;
	int blflag,elflag;

	css = ifno;
	while( lineno[css]-1 == 0 ) css--;	/* cope with includes */
	if( (flslvl!=0) || (llflag==0) ) {
		if( llflag&LLVERB ) {
	verbose:	if( !(llflag&LLINCL) && ifno != 0)
				goto done;
			pfnm( css , llbuf );
			for( cs = 0 ; cs <8 ; cs ++ )
				putc( ' ' , llbuf);
			for (rlp = &lline[8]; rlp<llinep;)
				putc( *rlp++ , llbuf);
		}
		goto done;
	}
	if( ( (ifno!=0) && (lineno[ifno]>1) ) && !(llflag&LLINCL) ) goto done;
	blflag = elflag = 1;
	if( lline[8] == '#' ) {
		for( rlp = &lline[9]; *rlp == ' ' || *rlp == '\t'; rlp++ ) ;
		if( eq("include", rlp) || eq("define", rlp))
			goto skip;
		if( llflag&LLVERB )
			goto verbose;
		else
			goto done;
	}
	blevel = - (elevel = 32767) ;
	cs = 0;
	for (rlp = line; c = *rlp++;) {
	   if( cs ) {
		   if( cs == c ) cs=0;
		   else if( c == '\\' ) rlp++;
	   } else if( c=='\'' || c=='"' ) cs = c;
		  else if( c=='{' ) { blflag=0; if( ++llevel>blevel ) blevel=llevel; }
		       else if( c=='}' ) { elflag=0; if( --llevel<elevel ) elevel=llevel+1; }
	}
	if( elevel<0 )
		error("too many '}'s ");
 skip:
	pfnm( css , llbuf );
	itoa( lineno[css]-1 );
	lline[0] = itoabuf[15];
	lline[1] = itoabuf[16];
	lline[2] = itoabuf[17];
	lline[3] = itoabuf[18];
	lline[5] = blflag ? '-' : levelchars[(blevel<0)||(blevel>(sizeof levelchars-1)) ? 0 : blevel+1];
	lline[6] = elflag ? '-' : levelchars[(elevel<0)||(elevel>(sizeof levelchars-1)) ? 0 : elevel+1];
	for (rlp =lline; rlp<llinep;)
		putc( *rlp++ , llbuf);
 done:
	llinep = &lline[8];
}

pfnm( cs , llbuf )
register int cs;
int *llbuf;
{
	register char c,*rlp;
	if( llflag&LLINCL ) {
		/* the following is a triffle inefficient but 
		   it don't happen that often so forget it  	*/
		cs = rlp = fnames[cs];
		while( *rlp ) if( *rlp++ == '/' ) cs = rlp;
		rlp = cs;
		c = 0;
		while( *rlp ) { c++ ; putc( *rlp++ , llbuf ); }
		if( c<8 ) putc( '\t' , llbuf );
		putc( '\t' , llbuf );
	}
}

eq(s1,s2)
register char *s1,*s2;
{
	register char c;

	while( (c = *s1++) == *s2++ );
	return( c==0 );
}
#endif	LIST

getline()
{
	register int c, sc, state;
	struct symtab *np;
	char *namep, *filname, *cp;
#ifdef	IFEXPR
	int ifval[40];
	char ifop[40];
	int *ifv;
	char *ifo;

	ifv = ifval;
	*(ifo = ifop) = 0;
#endif	IFEXPR

	lp = line;
	*lp = '\0';
	state = 0;
	if ((c=getch()) == '#')
		state = 1;
	while (c!='\n' && c!='\0') {
		if ('a'<=c && c<='z' || 'A'<=c && c<='Z' || c=='_') {
			namep = lp;
			sch(c);
			while ('a'<=(c=getch()) && c<='z'
			      ||'A'<=c && c<='Z'
			      ||'0'<=c && c<='9' 
			      ||c=='_')
				sch(c);
			sch('\0');
			lp--;
			if (state>3) {
#ifndef	IFEXPR
				if (flslvl==0 &&(state+!lookup(namep,-1)->name[0])==5)
					trulvl++;
				else
					flslvl++;
		out:
				while (c!='\n' && c!= '\0')
					c = getch();
				return(c);
#endif	IFEXPR
#ifdef	IFEXPR
				*++ifv = lookup(namep,-1)->name[0] ? 1 : 0 ;
				if(*ifo == '!') {
					*ifv = !*ifv;
					ifo--;
				}
				if(*ifo == '&') {
					ifv--;	*ifv =& ifv[1];
					ifo--;
				}
				continue;
#endif	IFEXPR
			}
			if (state==3) /* include */
				if (*namep != '"' && *namep != '<')
					{
					error("Bad include syntax", 0);
					state=1;
					}
			if (state!=2 || flslvl==0)
				{
				ungetc(c);
				np = lookup(namep, state);
				c = getch();
				}
			if (state==1) {
				if (np==defloc)
					state = 2;
				else if (np==incloc)
					state = 3;
				else if (np==ifnloc)
					state = 4;
				else if (np==ifdloc)
					state = 5;
				else if (np==eifloc) {
					if (flslvl)
						--flslvl;
					else if (trulvl)
						--trulvl;
					else
					{
						errback("If-less #endif");
						dexit();
					}
					goto out;
				}
#ifdef	IFEXPR
				else if (np==elsloc)
				{
					switch(flslvl)
					{
				    case  0:
						if(trulvl == 0)
						{
							errback("If-less #else");
							dexit();
						}
						else
						{
							trulvl--;
							flslvl++;
						}
						break;
				    case  1:
						trulvl++;
						flslvl = 0;
				    default:
						break;
					}
					goto out;
				}
#endif	IFEXPR
				else if (np==lneloc)
					{
					puts("# ");
					lp=line;
					for(; c !='\n' && c != '\0'; c=getch())
						if (!pflag || exflag)
							sch(c);
					sch('\0');
					return(c);
					}
				else {
					errback("Undefined control");
#ifdef	IFEXPR
			out:
#endif	IFEXPR
					while (c!='\n' && c!='\0')
						c = getch();
					return(c);
				}
			} else if (state==2) {
				if (flslvl)
					goto out;
				np->value = stringbuf;
				if (c != '\n' && c != 0)
					{
					savch(c);
					while ((c=getch())!='\n' && c!='\0')
						savch(c);
					}
				savch('\0');
				return(1);
			}
			continue;
		} else if ((sc=c) == '\'' || sc== '"' || (state==3 && sc== '<')) {
			sch(sc);
			filname = lp;
			if (sc== '<')
				{
				sc= '>';
				for(cp=sprefix; *cp; cp++)
					*lp++ = *cp;
				*lp++= '/';
				}
			instring++;
			while ((c=getch())!=sc && c!='\n' && c!='\0') {
				sch(c);
				if (c=='\\')
					sch(getch());
			}
			instring = 0;
			if (flslvl)
				goto out;
			if (state==3) {
				if (flslvl)
					goto out;
				*lp = '\0';
				while ((c=getch())!='\n' && c!='\0');
				if (ifno+1 >=MAXINC)
					error("Unreasonable include nesting",0);
				if(ibufs[++ifno]==0)
					ibufs[ifno]=sbrk(518);
				if (fopen(filname, ibufs[ifno])<0) {
					ifno--;
					errback("Missing file %s", filname);
					dexit();
				} else
					ibuf = ibufs[ifno];
				puts("\n# 1 \"");
				puts(filname);
				puts("\"");
				lineno[ifno]=1;
				fnames[ifno] = copy(filname);
				return(c);
			}
		}
#ifdef	IFEXPR
			else if(state > 3) switch(c)
				{
				case '(':
				case '|':
				case '&':
				case '!':
						*++ifo = c;
						break;
				case ' ':
				case '\t':
						break;
				case ')':
						for(;*ifo == '|'; ifo--) {
							ifv--;	*ifv =| ifv[1];
						}
						if(*ifo == '(')
							ifo--;
						else errexit("'(' expected");
						if(*ifo == '!') {
							*ifv = !*ifv;
							ifo--;
						}
						if(*ifo == '&') {
							ifv--;	*ifv =& ifv[1];
							ifo--;
						}
						break;
				default:

						errexit("illegal char '%o' oct",c);
						break;
				}
#endif	IFEXPR
		sch(c);
		c = getch();
	}
	sch('\0');
#ifdef	IFEXPR
	for(;*ifo == '|'; ifo--) {
		ifv--;	*ifv =| ifv[1];
	}
	if(state == 4 || state == 5)
	if( (state + !(*ifv--)) == 5 && flslvl == 0)
		trulvl++;
	else
		flslvl++;
	if((ifv != ifval) || (ifo != ifop))
		{
		errexit("if%cdef expression error",state==4 ? 'n' : 0);
		}
	state = 0;
#endif	IFEXPR
	if (state>1)
		errback("Control syntax");
	return(c);
}
#ifdef	IFEXPR
errexit(s,x)
{
	lineno[ifno]--;
	error(s,x);
	dexit();
}
#endif	IFEXPR

insym(sp, namep)
struct symtab **sp;
char *namep;
{
	register struct symtab *np;

	*sp = np = lookup(namep, 1);
	np->value = np->name;
}

error(s, x)
{
	int olfout;
	olfout = fout;
	flush();
	if (exflag)
		fout=2;
	if (fnames[ifno])
		printf("%s: %d: ", fnames[ifno], lineno[ifno]);
	printf(s, x);
	putchar('\n');
	flush();
	fout=olfout;
	exfail++;
	cflag++;
	eflag++;
}
errback(s,x)
{
	lineno[ifno]--;
	error(s,x);
	lineno[ifno]++;
}

sch(c)
{
	register char *rlp;

	rlp = lp;
	if (rlp==line+LINELEN-2)
		error("Line overflow");
	*rlp++ = c;
	if (rlp>line+LINELEN-1)
		rlp = line+LINELEN-1;
	lp = rlp;
}

savch(c)
{
	*stringbuf++ = c;
	if (stringbuf-sbf < SBSIZE)
		return;
	error("Too much defining");
	dexit();
}

getch()
{
	register int c;

#ifdef	COMMENT
	if( incomment ) goto commentprocessing;
#endif	COMMENT
loop:
	if ((c=getc1())=='/' && !instring) {
		if ((c=getc1())!='*')
			{
			ungetc(c);
			return('/');
			}
		for(;;) {
			incomment++;
#ifdef	COMMENT
  commentprocessing:
#endif	COMMENT
			c = getc1();
		cloop:
			switch (c) {

			case '\0':
				return('\0');

			case '*':
				if ((c=getc1())=='/') {
#ifdef	COMMENT
					incomment = 0;
#endif	COMMENT
					goto loop;
				}
				goto cloop;

			case '\n':
#ifdef	COMMENT
				return('\n');
#endif	COMMENT
#ifndef	COMMENT
				putc('\n', obuf);
				continue;
#endif	COMMENT
			}
		}
	}
	return(c);
}
char pushbuff[EXPSIZE];
char *pushp pushbuff;
ungetc(c)
	{
	*++pushp = c;
	if (pushp>pushbuff+EXPSIZE) {
		error("too much backup");
		dexit(8);
		}
	}

getc1()
{
	register c;
	register flag = 0;

	if (*pushp !=0)
		return(*pushp--);
	depth=0;
	if ((c = getc(ibuf)) < 0 && ifno>0) {
		close(ibuf[0]);
		ibuf = ibufs[--ifno];
		puts("\n# ");
		puts(itoa(lineno[ifno]));
		puts(" \"");
		puts(fnames[ifno]);
		puts("\"\n");
		c = getc1();
		flag++;
		if (c=='\n') lineno[ifno]--;
	}
	if (c<0)
		return(0);
	if (c=='\n' )
		lineno[ifno]++;
#ifdef	LIST
	if( (llflag) && (flag==0) ) *llinep++ = c;
#endif	LIST
	return(c);
}

lookup(namep, enterf)
char *namep;
{
	register char *np, *snp;
	register struct symtab *sp;
	int i, c, around;
	np = namep;
	around = i = 0;
	while (c = *np++)
		i =+ c;
	i =% symsiz;
	sp = &symtab[i];
	while (sp->name[0]) {
		snp = sp;
		np = namep;
		while (*snp++ == *np)
			if (*np++ == '\0' || np==namep+8) {
				if (!enterf)
					subst(namep, sp);
				return(sp);
			}
		if (++sp >= &symtab[symsiz])
			if (around++)
				{
				error("too many defines");
				dexit();
				}
			else
			sp = symtab;
	}
	if (enterf>0) {
		snp = namep;
		for (np = &sp->name[0]; np < &sp->name[8];)
			if (*np++ = *snp)
				snp++;
	}
	return(sp);
}
char revbuff[200], *bp;
backsch(c)
	{
	if (bp-revbuff > 200)
		error("Excessive define looping", bp--);
	*bp++ = c;
	}

subst(np, sp)
char *np;
struct symtab *sp;
{
	register char *vp;
	int macflg;

	lp = np;
	bp = revbuff;
	if (depth++>100)
		{
		error("define recursion loop\n");
		return;
		}
	if ((vp = sp->value) == 0)
		return;
	macflg= (*vp == '(');
	/* arrange that define unix unix still
	has no effect, avoiding rescanning */
	while (blank(*vp))
		vp++;
	if (streq(sp->name,vp))
		{
		while (*vp)
			sch(*vp++);
		return;
		}
	if (macflg)
		expdef(vp);
	else
		while (*vp)
			backsch(*vp++);
	while (bp>revbuff)
		ungetc(*--bp);
}

getsuf(as)
char as[];
{
	register int c;
	register char *s;
	register int t;

	s = as;
	c = 0;
	while(t = *s++)
		if (t=='/')
			c = 0;
		else
			c++;
	s =- 3;
	if (c<=14 && c>2 && *s++=='.')
		return(*s);
	return(0);
}

setsuf(as, ch)
char as[];
{
	register char *s, *s1;

	s = s1 = copy(as);
	while(*s)
		if (*s++ == '/')
			s1 = s;
	s[-1] = ch;
	return(s1);
}

callsys(f, v)
char f[], *v[]; {
	int t, status;

	if ((t=fork())==0) {
		execv(f, v);
		printf("Can't find %s\n", f);
		exit(100);
	} else
		if (t == -1) {
			printf("Try again\n");
			return(100);
		}
	while(t!=wait(&status));
	if ((t=(status&0377)) != 0 && t!=14) {
		if (t!=2)		/* interrupt */
			{
			printf("Fatal error in %s\n", f);
			eflag = 8;
			}
		dexit();
	}
	return((status>>8) & 0377);
}

copy(as)
char as[];
{
	register char *otsp, *s;
	int i;

	otsp = tsp;
	s = as;
	while(*tsp++ = *s++);
	if (tsp >tsa+CHSPACE)
		{
		tsp = tsa = i = alloc(CHSPACE+50);
		if (i== -1){
			error("no space for file names");
			dexit(8);
			}
		}
	return(otsp);
}

nodup(l, os)
char **l, *os;
{
	register char *t, *s;
	register int c;

	s = os;
	if (getsuf(s) != 'o')
		return(1);
	while(t = *l++) {
		while(c = *s++)
			if (c != *t++)
				break;
		if (*t=='\0' && c=='\0')
			return(0);
		s = os;
	}
	return(1);
}

cunlink(f)
char *f;
{
	if (f==0)
		return(0);
	return(unlink(f));
}
expdef(proto)
char *proto;
{
	char buffer[EXPSIZE], *parg[20], *pval[20], name[20], *cspace, *wp;
	char protcop[EXPSIZE], *pr;
	int narg, k, c;
	pr = protcop;
	while (*pr++ = *proto++);
	if (pr>protcop+EXPSIZE){
		error("define prototype too big");
		dexit(8);
	}
	proto= protcop;
	for (narg=0; (parg[narg] = token(&proto)) != 0; narg++) ;
	/* now scan input */
	cspace = buffer;
	while ((c=getch()) == ' ');
	if (c != '(') {
		error("defined function requires arguments");
		return;
	}
	ungetc(c);
	for(k=0; pval[k] = coptok(&cspace, buffer+EXPSIZE); k++);
	if (k!=narg) {
		error("define argument mismatch");
		return;
	}
	while (c= *proto++) {
		if (!letter(c))
			backsch(c);
		else {
			wp = name;
			*wp++ = c;
			while (letnum(*proto))
			*wp++ = *proto++;
			*wp = 0;
			for (k=0; k<narg; k++)
			if(streq(name,parg[k]))
			break;
			wp = k <narg ? pval[k] : name;
			while (*wp) backsch(*wp++);
		}
	}
}

token(cpp)
char **cpp;
{
	char *val;
	int stc;

	stc = **cpp;
	*(*cpp)++ = '\0';
	if (stc==')') return(0);
	while (**cpp == ' ') (*cpp)++;
	for (val = *cpp; (stc= **cpp) != ',' && stc!= ')'; (*cpp)++) {
		if (!letnum(stc) || (val == *cpp && !letter(stc))) {
			error("define prototype argument error");
			return(0);
		}
	}
	return(val);
}

coptok (cpp, clim)
char **cpp, *clim;
{
	char *val;
	int stc, stop,paren;
	paren = stop = 0;
	val = *cpp;
	if (getch() == ')') return(0);
	while (((stc = getch()) != ',' && stc != ')' ) || paren > 0 || stop >0)  {
		if (stc == '\0') {
			error("non terminated macro call");
			val = 0;
			break;
		}
		if (stop == 0 && (stc == '"' || stc == '\'')) stop = stc;
		else if (stc==stop) stop = 0;
		if ( stc == '\\') {
			stc = getch();
			if (stop>0 || (stc != ',' && stc != '\\'))
				*(*cpp)++ = '\\';
				*(*cpp)++ = stc;
		} else {
			*(*cpp)++ = stc;
			if (stop==0) {
				if (stc == '(') paren++;
				if (stc == ')') paren--;
			}
		}
		if (*cpp >= clim) {
			error("define argument too long",0);
			dexit(8);
		}
	}
	*(*cpp)++ = 0;
	ungetc(stc);
	return(val);
}

letter(c)
{
	if ((c >= 'a' && c <= 'z') ||
	    (c >= 'A' && c <= 'Z') ||
	    (c == '_'))
	    return (1);
	else
	    return(0);
}

letnum(c)
{
	if (letter(c) || (c >= '0' && c <= '9'))
	  return(1);
	else
	  return(0);
}

streq(s,t)
char *s, *t;
{
	int c;
	while ( (c= *s++) == *t++)
		if (c==0) return(1);
	return(0);
}

puts(s)
char *s;
{
	int c;
	if (pflag && !exflag) return;
	while (c= *s++)
		putc(c, obuf);
}

itoa(n)
{
	char *sp;
#ifndef	LIST
	static char sb[20];
	sp = sb+19;
#endif	LIST
#ifdef	LIST
	sp = itoabuf;
	while( sp<itoabuf+19 ) *sp++ = '0';
#endif	LIST
	*sp=0;
	if (n<=0)
		*--sp = '0';
	else
	while (n) {
		*--sp = '0'+ n%10;
		n=n/10;
	}
	return(sp);
}

blank(c)
{
	return(c==' ' || c== '\t');
}