#
/*
 *
 *	UNIX debugger - part 1
 *
 */

#include "adb.h"

int	wtflag;
int	fcor;
int	fsym;
long	maxfile;
long	maxstor;
long	txtsiz;
long	datsiz;
long	stksiz;
INT	outfile 1;
int	errflg;
int	exitflg;
int	magic;
long	symbas;
long	symnum;
long	localval;
int	entrypt;
char	isymbol[8];

int	signo;
char	lastc EOR;
INT	eof;
char	eqformat[128] "o";
char	stformat[128] "o\"= \"^i";
int	regbuf[512];
int	*uregs;

long	dot;
long	ditto;
int	dotinc;
int	lastcom '=';
long	var[36];
long	locval;
long	locmsk;
char	*symfil	"a.out";
char	*corfil	"core";
int	pid;
long	expv;
long	adrval;
int	adrflg;
long	cntval;
int	cntflg;
char	printbuf[];
char	*printptr;

char * errmsg[] {
	"",
	"bad modifier",
	"bad command",
	"symbol not found",
	"c routine not found",
	"cannot locate value",
	"no breakpoint set",
	"unexpected ')'",
	"address expected",
	"no process",
	"bad variable",
	"text address not found",
	"data address not found",
	"odd address",
	"too many breakpoints",
	"bad a68 frame",
	"bad a68 link",
	"address wrap around",
	"unexpected `='",
	"wait error: process disappeared!",
	"process terminated",
	"try again",
	"syntax error",
	"newline expected",
	"bkpt: command too long",
	"bad file format",
	"not enough space for symbols",
	"filename too long",
	"cannot open",
};

long round(a,b) long a; long b;
{
	long w;
	w = (a/b)*b;
	IF a>0 THEN w =+ b; FI
	return(w);
}

/* error handling */

error(n)
{
	errflg=n;
	iclose(); oclose();
	reset();
}

fault(a)
{
	signal(a,fault);
	printptr=printbuf;
	seek(infile,0,2);
	mkfault++;
}

/* set up files and initial address mappings */
int argcount;
int devmem, devswap;

main(argc, argv)
char **argv; int argc;
{
	maxfile=1; maxfile =<< 24;
	maxstor=1; maxstor =<< 16;

	WHILE argc>1
	DO	IF eqstr("-w",argv[1])
		THEN	wtflag=2; argc--; argv++;
		ELSE	break;
		FI
	OD

	IF argc>1 THEN symfil = argv[1]; FI
	IF argc>2 THEN corfil = argv[2]; FI
	argcount=argc;
	setsym(); setcor(); setproc();

	/* set up variables for user */
	maxoff=MAXOFF; maxpos=MAXPOS;
	var[VARB] = datmap.b1;
	var[VARD] = datsiz;
	var[VARE] = leng(entrypt);
	var[VARM] = magic;
	var[VARS] = stksiz;
	var[VART] = txtsiz;

	IF (sigint=signal(SIGINT,fault))==01
	THEN signal(SIGINT,1);
	ELSE	sigint=fault;
	FI
	sigqit=signal(SIGQIT,1);
	setexit();
	IF executing THEN delbp(); FI
	executing=FALSE;

	LOOP	flushbuf();
		IF errflg
		THEN printf("%s\n",errmsg[errflg]);
		     exitflg=errflg;
		     errflg=0;
		ELIF mkfault
		THEN	mkfault=0; prints("\nadb\n");
		FI
		lp=0; rdc(); lp--;
		IF eof
		THEN	IF infile
			THEN	iclose(); eof=0; reset();
			ELSE	done();
			FI
		ELSE	exitflg=0;
		FI
		command(0,lastcom);
		IF lp ANDF lastc!=EOR THEN error(NOEOR); FI
	POOL
}

done()
{
	endpcs();
	exit(exitflg);
}

setsym()
{
	int relflg;
	INT symval, symflg; SYMSLAVE *symptr; SYMTAB *symp;
	IF !eqstr("-",symfil)
	THEN	fsym=open(symfil,wtflag);
		IF wtflag ANDF fsym<0
		THEN	fsym=create(symfil);
		FI
		IF fsym<0 ANDF argcount>1
		THEN printf("cannot open `%s'\n", symfil);
		FI
	ELSE	fsym = -1;
	FI
	txtmap.ufd=fsym;
	IF read(fsym, regbuf, TXTHDR)==TXTHDR
	THEN	magic=regbuf[0];
		IF magic!=0411 ANDF magic!=0410 ANDF magic!=0407 ANDF magic!=0405
		THEN	magic=0;
		ELSE	symnum=leng(regbuf[4])/12;
			txtsiz=leng(regbuf[1]);
			datsiz=leng(regbuf[2]);
			symbas=txtsiz+datsiz;
			txtmap.b1=0;
			txtmap.e1=(magic==0407?symbas:txtsiz);
			txtmap.f1 = TXTHDR;
			txtmap.b2=(magic==0410?round(txtsiz,leng(8192)):0);
			txtmap.e2=txtmap.b2+(magic==0407?symbas:datsiz);
			txtmap.f2 = TXTHDR+(magic==0407?0:txtmap.e1);
			entrypt=regbuf[5];
			relflg=regbuf[7];
			IF relflg!=1 THEN symbas =<< 1; FI
			symbas =+ TXTHDR;

			/* set up symvec */
			freecell(symvec);
			symvec=getcell(shorten((1+symnum))*sizeof *symptr);
			IF (symptr=symvec)==0
			THEN	error(BADNAM);
			FI
			symset();
			WHILE (symp=symget()) ANDF errflg==0
			DO  symval=symp->symv; symflg=symp->symf;
			    symptr->valslave=symval;
			    symptr->typslave=((symflg&070)==(symflg&040)
						?  ((symflg&07)>=3 ? DSYM : (symflg&07))
						: NSYM
					      );
			    symptr++;
			OD
			symptr->typslave=ESYM;
		FI
	FI
	IF magic==0 THEN txtmap.e1=maxfile; FI
}

setcor()
{
	IF !eqstr("-",corfil)
	THEN	fcor=open(corfil,wtflag);
		IF fcor<0 ANDF wtflag
		THEN	fcor=create(corfil);
		FI
		IF fcor<0 ANDF argcount>2
		THEN printf("cannot open `%s'\n", corfil);
		FI
	ELSE	fcor = -1;
	FI
	datmap.ufd=fcor;
	IF read(fcor, regbuf, CORHDR)==CORHDR
	   ANDF (regbuf[0]&0170000)==COREMAGIC
	   ANDF (regbuf[1]&0170000)==COREMAGIC
	THEN	signo = regbuf[0].u_arg[0]&017;
		txtsiz = leng(regbuf->u_tsize << 6);
		datsiz = leng(regbuf->u_dsize << 6);
		stksiz = leng(regbuf->u_ssize << 6);
		datmap.b1=(magic==0410?round(txtsiz,leng(8192)):0);
		datmap.e1=(magic==0407?txtsiz:datmap.b1)+datsiz;
		datmap.f1 = CORHDR;
		datmap.b2 = maxstor-stksiz;
		datmap.e2 = maxstor;
		datmap.f2 = CORHDR+(magic==0410?datsiz:datmap.e1);
	ELSE	datmap.e1 = maxfile;
	FI
}

create(f)
char *f;
{	int fd;
	IF (fd=creat(f,0644))>=0
	THEN close(fd); return(open(f,wtflag));
	ELSE return(-1);
	FI
}

/* input routines */

eol(c)
char c;
{
	return(c==EOR ORF c==';');
}

rdc()
{	REP	readchar();
	PER	lastc==SP ORF lastc==TB
	DONE
	return(lastc);
}

readchar()
{
	IF eof
	THEN	lastc=EOF;
	ELSE	IF lp==0
		THEN	lp=line;
			REP eof = read(infile,lp,1)==0;
			    IF mkfault THEN error(0); FI
			PER eof==0 ANDF *lp++!=EOR DONE
			*lp=0; lp=line;
		FI
		IF lastc = *lp THEN lp++; FI
	FI
	return(lastc);
}

nextchar()
{
	IF eol(rdc())
	THEN lp--; return(0);
	ELSE return(lastc);
	FI
}

quotchar()
{
	IF readchar()=='\\'
	THEN	return(readchar());
	ELIF lastc=='\''
	THEN	return(0);
	ELSE	return(lastc);
	FI
}

getformat(deformat)
{
	register char *fptr, quote;
	fptr=deformat; quote=FALSE;
	WHILE (quote ? readchar()!=EOR : !eol(readchar()))
	DO  IF (*fptr++ = lastc)=='"'
	    THEN quote = ~quote;
	    FI
	OD
	lp--;
	IF fptr!=deformat THEN *fptr++ = '\0'; FI
}


/* command decoding */

long inkdot(incr)
{
	long newdot; newdot=dot+incr;
	IF (dot NEQ newdot) >> 24 THEN error(ADRWRAP); FI
	return(newdot);
}

long dekdot(decr)
{
	long newdot; newdot=dot-decr;
	IF (dot NEQ newdot) >> 24 THEN error(ADRWRAP); FI
	return(newdot);
}

endline()
{
	IF charpos()>=maxpos
	THEN printf("\n");
	FI
}

command(buf,defcom)
char *buf, defcom;
{
 	INT itype, ptype, modifier, regptr;
	    INT	fcount;
	BOOL longpr, eqcom; char wformat[1]; CHAR savc;
	long *amap, *smap, w, savdot;
	char *savlp; savlp=lp;
	IF buf
	THEN IF *buf==EOR
	     THEN return(FALSE);
	     ELSE lp=buf;
	     FI
	FI

	REP
	IF adrflg=expr(0)
	THEN dot=expv; ditto=dot;
	FI
	adrval=dot;
	IF rdc()==',' ANDF expr(0)
	THEN cntflg=TRUE; cntval=expv;
	ELSE cntflg=FALSE; cntval=1; lp--;
	FI

	IF !eol(rdc())
	THEN lastcom=lastc;
	ELSE IF adrflg==0 THEN dot=inkdot(dotinc); FI
	     lp--; lastcom=defcom;
	FI

	switch(lastcom&STRIP) {

	    case '/':
		itype=DSP; ptype=DSYM;
		goto trystar;

	    case '=':
		itype=NSP; ptype=ASYM;
		goto trypr;

	    case '?':
		itype=ISP; ptype=ISYM;
		goto trystar;

	    trystar:
		IF rdc()=='*' THEN lastcom =| QUOTE; ELSE lp--; FI
		IF lastcom&QUOTE
		THEN itype =| STAR; ptype = (DSYM+ISYM)-ptype;
		FI

	    trypr:
		longpr=FALSE; eqcom=lastcom=='=';
		switch (rdc()) {

			case 'm':
			    {/*reset map data*/
			    IF eqcom THEN error(BADEQ); FI
			    amap=(itype&DSP?&datmap:&txtmap);
			    smap=amap; fcount=3;
			    IF itype&STAR
			    THEN amap =+ 3;
			    FI
			    WHILE fcount-- ANDF expr(0)
			    DO *amap++ = expv; OD
			    IF rdc()=='?' THEN smap->ufd=fsym;
			    ELIF lastc == '/' THEN smap->ufd=fcor;
			    ELSE lp--;
			    FI
			    printmap("new map",smap);
			    }
			    EXITSW;

			case 'L':
			    longpr=TRUE;
			case 'l':
			    /*search for exp*/
			    IF eqcom THEN error(BADEQ); FI
			    dotinc=2; savdot=dot;
			    expr(1); locval=expv;
			    IF expr(0) THEN locmsk=expv; ELSE locmsk = (longpr?-1:leng(-1)); FI
			    LOOP w=leng(get(dot,itype));
				 IF longpr
				 THEN w=itol(w,get(inkdot(2),itype));
				 FI
				 IF errflg ORF (w&locmsk)==locval THEN break; FI
				 dot=inkdot(dotinc);
			    POOL
			    IF errflg
			    THEN dot=savdot; errflg=NOMATCH;
			    FI
			    psymoff(dot,ptype,"");
			    EXITSW;

			case 'W':
			    longpr=TRUE;
			case 'w':
			    IF eqcom THEN error(BADEQ); FI
			    wformat[0]=lastc; expr(1);
			    LOOP savdot=dot; psymoff(dot,ptype,":%16t"); exform(1,wformat,itype,ptype);
				 errflg=0; dot=savdot;
				 IF longpr
				 THEN put(dot,itype,expv);
				 FI
				 put((longpr?inkdot(2):dot),itype,shorten(expv));
				 savdot=dot;
				 printf("=%8t"); exform(1,wformat,itype,ptype);
				 IF expr(0)==0 ORF errflg THEN break; FI
			    POOL
			    dot=savdot;
			    EXITSW;

			default:
			    lp--;
			    getformat(eqcom ? eqformat : stformat);
			    IF !eqcom
			    THEN psymoff(dot,ptype,":%16t");
			    FI
			    scanform(cntval,(eqcom?eqformat:stformat),itype,ptype,1);
		}
		EXITSW;

	    case '>':
		lastcom=0; savc=rdc();
		IF regptr=getreg(savc)
		THEN uregs[regptr]=shorten(dot);
		     ptrace(WUREGS,pid,2*(512+regptr),uregs[regptr]);
		ELIF (modifier=varchk(savc)) != -1
		THEN	var[modifier]=dot;
		ELSE	error(BADVAR);
		FI
		EXITSW;

	    case '!':
		lastcom=0;
		unix(); EXITSW;

	    case '$':
		lastcom=0;
		printtrace(nextchar()); EXITSW;

	    case ':':
		IF !executing
		THEN executing=TRUE;
		     subpcs(nextchar());
		     executing=FALSE;
		     lastcom=0;
		FI
		EXITSW;

	    case 0:
		prints("adb");
		EXITSW;

	    default: error(BADCOM);
	}

	flushbuf();
	PER rdc()==';' DONE
	IF buf THEN lp=savlp; ELSE lp--; FI
	return(adrflg ANDF dot!=0);
}

scanform(icount,ifp,itype,ptype,init)
long int icount;
{
	CHAR		*fp, modifier;
	INT		fcount;
	long		savdot;
	WHILE icount
	DO  fp=ifp;
	    IF init==0 ANDF findsym(shorten(dot),ptype)==0 ANDF maxoff
	    THEN printf("\n%.8s:%16t",symbol.symc);
	    FI
	    savdot=dot; init=0;

	    /*now loop over format*/
	    WHILE *fp ANDF errflg==0
	    DO  IF digit(modifier = *fp)
		THEN fcount=0;
		     WHILE digit(modifier = *fp++)
		     DO fcount =* 10;
			fcount =+ modifier-'0';
		     OD
		     fp--;
		ELSE fcount=1;
		FI

		IF *fp==0 THEN break; FI
		fp=exform(fcount,fp,itype,ptype);
	    OD
	    dotinc=dot-savdot;
	    dot=savdot;

	    IF errflg
	    THEN IF icount<0
		 THEN errflg=0; break;
		 ELSE error(errflg);
		 FI
	    FI
	    IF --icount
	    THEN dot=inkdot(dotinc);
	    FI
	    IF mkfault THEN error(0); FI
	OD
}

exform(fcount,ifp,itype,ptype)
INT fcount; char *ifp; int itype, ptype;
{
	/* execute single format item `fcount' times
	 * sets `dotinc' and moves `dot'
	 * returns address of next format item
	 */
	int w;
	long savdot, wx;
	char *fp; char c, modifier, longpr;
	double fw; struct{long sa; int sb, sc;};

	WHILE fcount>0
	DO	fp = ifp; c = *fp;
		longpr=(c>='A')&(c<='Z')|(c=='f');
		IF itype==NSP ORF *fp=='a'
		THEN wx=dot; w=shorten(dot);
		ELSE w=get(dot,itype);
		     IF longpr
		     THEN wx=itol(w,get(inkdot(2),itype));
		     ELSE wx=leng(w);
		     FI
		FI
		IF c=='F'
		THEN fw.sb=get(inkdot(4),itype);
		     fw.sc=get(inkdot(6),itype);
		FI
		IF errflg THEN return(fp); FI
		IF mkfault THEN error(0); FI
		var[0]=wx;
		modifier = *fp++;
		dotinc=(longpr?4:2);;

		IF charpos()==0 ANDF modifier!='a' THEN printf("%16m"); FI

		switch(modifier) {

		    case SP: case TB:
			EXITSW;

		    case 't': case 'T':
			printf("%T",fcount); return(fp);

		    case 'r': case 'R':
			printf("%M",fcount); return(fp);

		    case 'a':
			psymoff(dot,ptype,":%16t"); dotinc=0; EXITSW;

		    case 'p':
			psymoff(var[0],ptype,"%16t"); EXITSW;

		    case 'u':
			printf("%-8u",w); EXITSW;

		    case 'U':
			printf("%-16U",wx); EXITSW;

		    case 'c': case 'C':
			IF modifier=='C'
			THEN printesc(w&LOBYTE);
			ELSE printc(w&LOBYTE);
			FI
			dotinc=1; EXITSW;

		    case 'b': case 'B':
			printf("%-8o", w&LOBYTE); dotinc=1; EXITSW;

		    case 's': case 'S':
			savdot=dot; dotinc=1;
			WHILE (c=get(dot,itype)&LOBYTE) ANDF errflg==0
			DO dot=inkdot(1);
			   IF modifier == 'S'
			   THEN printesc(c);
			   ELSE printc(c);
			   FI
			   endline();
			OD
			dotinc=dot-savdot+1; dot=savdot; EXITSW;

		    case 'x':
			printf("%-8x",w); EXITSW;

		    case 'X':
			printf("%-16X", wx); EXITSW;

		    case 'Y':
			printf("%-24Y", wx); EXITSW;

		    case 'q':
			printf("%-8q", w); EXITSW;

		    case 'Q':
			printf("%-16Q", wx); EXITSW;

		    case 'o':
		    case 'w':
			printf("%-8o", w); EXITSW;

		    case 'O':
		    case 'W':
			printf("%-16O", wx); EXITSW;

		    case 'i': case 'I':
			dotinc=printins(0,itype,w); printc(EOR); EXITSW;

		    case 'd':
			printf("%-8d", w); EXITSW;

		    case 'D':
			printf("%-16D", wx); EXITSW;

		    case 'f':
			fw = 0;
			fw.sa = wx;
			printf("%-16.7f", fw);
			dotinc=4; EXITSW;

		    case 'F':
			fw.sa = wx;
			printf("%-32.14F", fw);
			dotinc=8; EXITSW;

		    case 'n': case 'N':
			printc('\n'); dotinc=0; EXITSW;

		    case '"':
			dotinc=0;
			WHILE *fp != '"' ANDF *fp
			DO printc(*fp++); OD
			IF *fp THEN fp++; FI
			EXITSW;

		    case '^':
			dot=dekdot(dotinc*fcount); return(fp);

		    case '+':
			dot=inkdot(fcount); return(fp);

		    case '-':
			dot=dekdot(fcount); return(fp);

		    default: error(BADFMT);
		}
		dot=inkdot(dotinc);
		fcount--; endline();
	OD

	return(fp);
}

unix()
{
	int rc, status, unixpid;
	char *argp; argp=lp;
	WHILE lastc!=EOR DO rdc(); OD
	IF (unixpid=fork())==0
	THEN signal(SIGINT,sigint); signal(SIGQIT,sigqit);
	     close(devmem); close(devswap);
	     *lp=0; execl("/bin/sh", "-sh", "-c", argp, 0);
	     exit(16);
	ELIF unixpid == -1
	THEN error(NOFORK);
	ELSE signal(SIGINT,1);
	     WHILE (rc = wait(&status)) != unixpid ANDF rc != -1 DONE
	     signal(SIGINT,sigint);
	     prints("!"); lp--;
	FI
}


printesc(c)
{
	c =& STRIP;
	IF c<SP ORF c>'~' ORF c=='@'
	THEN printf("@%c",(c=='@' ? '@' : c^0140));
	ELSE printc(c);
	FI
}

/* expression reading */

expr(a)
{	/* term | term dyadic expr |  */
	int rc; long lhs;

	rdc(); lp--; rc=term(a);

	WHILE rc
	DO  lhs = expv;

	    switch (readchar()) {

		    case '+':
			term(a|1); expv =+ lhs; EXITSW;

		    case '-':
			term(a|1); expv = lhs - expv; EXITSW;

		    case '#':
			term(a|1); expv = round(lhs,expv); EXITSW;

		    case '*':
			term(a|1); expv =* lhs; EXITSW;

		    case '%':
			term(a|1); expv = lhs/expv; EXITSW;

		    case '&':
			term(a|1); expv =& lhs; EXITSW;

		    case '|':
			term(a|1); expv =| lhs; EXITSW;

		    case ')':
			IF (a&2)==0 THEN error(BADKET); FI

		    default:
			lp--;
			return(rc);
	    }
	OD
	return(rc);
}

term(a)
{	/* item | monadic item | (expr) | */

	switch (readchar()) {

		    case '*':
			term(a|1); expv=leng(chkget(expv,DSP)); return(1);

		    case '@':
			term(a|1); expv=leng(chkget(expv,ISP)); return(1);

		    case '-':
			term(a|1); expv = -expv; return(1);

		    case '~':
			term(a|1); expv = ~expv; return(1);

		    case '(':
			expr(2);
			IF *lp!=')'
			THEN	error(BADSYN);
			ELSE	lp++; return(1);
			FI

		    default:
			lp--;
			return(item(a));
	}
}

item(a)
{	/* name [ . local ] | number | . | ^ | <var | <register | 'x | | */
	INT base, d, frpt, regptr; CHAR savc; BOOL hex;
	long frame;
	double real;
	struct symtab *symp;
	hex=FALSE;

	readchar();
	IF symchar(0)
	THEN	readsym();
		IF lastc=='.'
		THEN	frame=leng(uregs[r5])&EVEN; lastframe=0; callpc=uregs[pc];
			WHILE errflg==0
			DO  findroutine(frame);
			    IF  eqstr(symbol.symc,isymbol)
			    THEN break;
			    FI
			    lastframe=frame;
			    frame=leng(get(frame,DSP))&EVEN;
			    IF frame==0
			    THEN error(NOCRTN);
			    FI
			OD
			expv=frame; readchar();
			IF symchar(0)
			THEN	readsym();
				REP IF localsym(frame)==0 THEN error(BADSYM); FI
				    expv=localval;
				PER !eqstr(symbol.symc,isymbol) DONE
			FI
		ELIF (symp=lookupsym(isymbol))==0 THEN error(BADSYM);
		ELSE expv = leng(symp->symv);
		FI
		lp--;


	ELIF digit(lastc) ORF (hex=TRUE, lastc=='#' ANDF hexdigit(readchar()))
	THEN	expv = 0;
		base = (lastc == '0' ORF octal ? 8 : (hex ? 16 : 10));
		WHILE (hex ? hexdigit(lastc) : digit(lastc))
		DO  expv =* base;
		    IF (d=convdig(lastc))>=base THEN error(BADSYN); FI
		    expv =+ d; readchar();
		OD
		IF lastc=='.' ANDF (base==10 ORF expv==0) ANDF !hex
		THEN	real=expv; frpt=0; base=10;
			WHILE digit(readchar())
			DO	real =* base; frpt++;
				real =+ lastc-'0';
			OD
			WHILE frpt--
			DO	real =/ base; OD
			expv=ltor(real);
		FI
		lp--;

	ELIF lastc=='.'
	THEN	expv=dot;

	ELIF lastc=='"'
	THEN	expv=ditto;

	ELIF lastc=='+'
	THEN	expv=inkdot(dotinc);

	ELIF lastc=='^'
	THEN	expv=dekdot(dotinc);

	ELIF lastc=='<'
	THEN	savc=rdc();
		IF regptr=getreg(savc)
		THEN	expv=leng(uregs[regptr]);
		ELIF (base=varchk(savc)) != -1
		THEN	expv=var[base];
		ELSE	error(BADVAR);
		FI

	ELIF lastc=='\''
	THEN	d=4; expv=0;
		WHILE quotchar()
		DO  IF d--
		    THEN IF d==1 THEN expv =<<16; FI
			 expv =| ((d&1)?lastc:lastc<<8);
		    ELSE error(BADSYN);
		    FI
		OD

	ELIF a
	THEN	error(NOADR);
	ELSE	lp--; return(0);
	FI
	return(1);
}

/* service routines for expression reading */

readsym()
{
	register char *p;

	p = isymbol;
	REP IF p < &isymbol[8]
	    THEN *p++ = lastc;
	    FI
	    readchar();
	PER symchar(1) DONE
	WHILE p < &isymbol[8] DO *p++ = 0; OD
}

lookupsym(symstr)
char *symstr;
{
	struct symtab *symp;
	symset();
	WHILE symp=symget()
	DO  IF eqstr(symp->symc, symstr)
	    THEN return(symp);
	    FI
	OD
	return(0);
}

hexdigit(c)
CHAR c;
{	return((c>='0' ANDF c<='9') ORF (c>='a' ANDF c<='f'));
}

convdig(c)
CHAR c;
{
	IF digit(c)
	THEN	return(c-'0');
	ELIF hexdigit(c)
	THEN	return(c-'a'+10);
	ELSE	return(17);
	FI
}

digit(c) char c;	{return(c>='0' ANDF c<='9');}

letter(c) char c;	{return(c>='a' ANDF c<='z' ORF c>='A' ANDF c<='Z');}

symchar(dig)
{
	IF lastc=='\\' THEN readchar(); return(TRUE); FI
	return( letter(lastc) ORF lastc=='_' ORF dig ANDF digit(lastc) );
}

varchk(name)
{
	IF digit(name) THEN return(name-'0'); FI
	IF letter(name) THEN return((name&037)-1+10); FI
	return(-1);
}

