/*------------------------------------------------------------------*/
/*								    */
/*		      MC68000 Cross Assembler			    */
/*								    */
/*	      Copyright	(c) 1985 by Brian R. Anderson		    */
/*								    */
/*	    Miscellaneous routines - September 8, 1987		    */
/*								    */
/*   This program may be copied	for personal, non-commercial use    */
/*   only, provided that the above copyright notice is included	    */
/*   on	all copies of the source code.	Copying	for any	other use   */
/*   without the consent of the	author is prohibited.		    */
/*								    */
/*------------------------------------------------------------------*/
/*								    */
/*		Originally published (in Modula-2) in		    */
/*	    Dr.	Dobb's Journal, April, May, and June 1986.          */
/*								    */
/*	AmigaDOS conversion copyright (c) 1987 by Charlie Gibbs.    */
/*								    */
/*------------------------------------------------------------------*/

#include <stdio.h>
#include "a68kdef.h"
#include "a68kglb.h"

char Sdata[MAXSREC];	/* S-record data */
int  Sindex;		/* Index for Sdata */
int  NumRExt, NumR32, NumR16, NumR8;

static char *errmsg[] =	{
    "--- Unknown error code ---",
    "Identifier too long -- Truncated!",
    "No such op-code.",
    "Duplicate Symbol.",
    "Undefined Symbol.",
    "Addressing mode not allowed here.",
    "Error in operand format.",
    "Error in relative branch.",
    "Address mode error.",
    "Operand size error.",
    "END statement is missing.",
    "Value must be absolute.",
    "Relocatability error.",
    "Too many nested INCLUDEs.",
    "INCLUDE file cannot be opened.",
    "Illegal forward reference.",
    "Not supported in S-format.",
    "This instruction needs a label.",
    "Pass 1 / Pass 2 phase error.",
    "ENDM statement is missing.",
    "Too much DC data.",
    "Too many SECTIONs.",
    "Section may not be unnamed.",
    "Wrong type in continuation.",
    "Duplicate macro definition.",
    ""};

/* Functions */
extern int  LineParts(), GetField(), Instructions(), ObjDir();
extern int  GetSize(), GetInstModeSize(), GetMultReg();
extern int  ReadSymTab(), GetArgs(), GetAReg(),	OpenIncl();
extern long GetValue(),	CalcValue();
extern char *malloc();
extern FILE *fopen();

long AddrBndW(), AddrBndL();



long AddrBndW (v) long v;
/* Advances "v" to the next word boundary */
{
    if (v & 1L)	{
	AppendSdata (Srec, 0L, 1);
	v++;
    }
    return (v);
}



long AddrBndL (v) long v;
/* Advances "v" to the next long-word boundary */
{
    long templong;

    v =	AddrBndW (v);		/* Bump	to word	boundary first */
    if (v & 2L)	{		/* If still not	aligned, */
	templong = NOP;		/*  generate a NOP */
	AppendSdata (Srec, templong, 2);
	v += 2;
    }
    return (v);
}



WriteListLine (f) FILE *f;
/* Writes one line to the Listing file,	including Object Code */
{
    register int i, j;
    long templong;
    char macflag;

    if (errlim == 0)
	if ((Dir == Page) || (Dir == Space) || (Dir == Title)
	|| (Dir	== DoList) || (Dir == NoList) || (ListOff))
	    return;		/* Don't print unless they have errors */

    CheckPage (f, FALSE);	/* Print headings if necessary */

    if (PrntAddr) {
	if ((Dir == Equ) || (Dir == Set))
	    LongPut (f,	ObjSrc,	3);	/* Equated value */
	else
	    LongPut (f,	AddrCnt, 3);	/* Current location */
	fprintf	(f, "  ");
    } else
	fprintf	(f, "        ");        /* Don't print location */
    LongPut (f,	ObjOp, nO);		/* Generated code */
    if (nS != 0) {
	fprintf	(f, " ");
	LongPut	(f, ObjSrc, nS);
    }
    if (nD != 0) {
	fprintf	(f, " ");
	LongPut	(f, ObjDest, nD);
    }
    if ((j = nX) > 0) {				/* String data */
	if ((j + nO + nS + nD) > 12)
	    j =	12 - nO	- nS - nD;
	for (i = 0; i <	j; i++)	{
	    templong = ObjString[i];
	    LongPut (f,	templong, 1);
	}
    }
    i =	6 + (nO	+ nS + nD + j) * 2;	/* Hex digits printed */
    if (nS != 0) i++;			/* Space between operands */
    if (nD != 0) i++;
    while (i < ObjMAX) {
	fprintf	(f, " ");
	i++;
    }
    if ((InFNum	== 0) || (OuterMac == 0))
	macflag	= ' ';                  /* Open code */
    else if (InFNum > OuterMac)
	macflag	= '+';                  /* Inner macro */
    else if ((InFNum ==	OuterMac) && (Dir != MacCall))
	macflag	= '+';                  /* Outermost macro */
    else
	macflag	= ' ';                  /* We're outside macros */

    fprintf (f,	" %4d%c%s\n", LineCount, macflag, Line);

    for	(i = 0;	i < errlim; i++) {	/* Write error messages. */
	CheckPage (f, FALSE);
	fprintf	(f, "%s", errmsg[errcode[i]]);
	for (j=strlen(errmsg[errcode[i]]); j<ObjMAX+8+errpos[i]; j++)
	    fprintf (f,	" ");
	fprintf	(f, "^ ");              /* Error flag */
	if (i == 0) {
	    if (InF->UPtr == 0)
		fprintf	(f, "%s", InF->NPtr);       /* Module name */
	    else
		fprintf	(f, "(user macro)");        /* In a user macro */
	    fprintf (f,	" line %d", InF->Line);     /* Line number */
	}
	fprintf	(f, "\n");
    }
}



WriteSymTab (f)	FILE *f;
/* Lists symbol	table in alphabetical order */
{
    int	 printhunk, i;
    char *p;
    register int j, k;
    struct SymTab *sym;
    struct Ref	  *ref;

    LnCnt = 999;			/* Skip	to a new page. */
    for	(i = 0,	sym = SymStart;	i < NumSyms; i++, sym++) {
	CheckPage (f, TRUE);

	p = sym->Nam;			/* Pointer to symbol */
	while (*p == ' ')               /* Skip leading blanks, if any */
	    p++;
	fprintf	(f, "%-11s ", p);       /* Symbol or macro name */
	if (strlen (p) > 11)		/* Long	symbol - go to new line	*/
	    fprintf (f,	"\n            ");

	printhunk = FALSE;		/* Assume no hunk no. to print */
	if (sym->Defn == 0)
	    fprintf (f,	"  *** UNDEFINED *** ");
	else if	(sym->Flags & 4)
	    fprintf (f,	"  -- SET Symbol --  ");
	else if	(sym->Flags & 8)
	    fprintf (f,	" +++ MACRO +++  %4d", sym->Defn);
	else if	(sym->Flags & 0x10) {
	    fprintf (f,	" SECTION  ");
	    printhunk =	TRUE;
	} else if (sym->Flags &	0x20) {
	    fprintf (f,	"      %c", (sym->Val & 8) ? 'A' : 'D');
	    fprintf (f,	"%d  ", sym->Val & 7);
	    printhunk =	TRUE;
	} else {
	    LongPut (f,	sym->Val, 4);		/* Value */
	    fprintf (f,	"  ");
	    printhunk =	TRUE;
	}
	if (printhunk) {
	    j =	sym->Hunk & 0x00007FFFL;	/* Hunk	number */
	    if (sym->Flags & 0x60)
		fprintf	(f, " Reg");            /* Register or list */
	    else if (sym->Hunk & 0x00008000L)
		fprintf	(f, " Ext");            /* External */
	    else if (j == ABSHUNK)
		fprintf	(f, " Abs");            /* Absolute */
	    else
		fprintf	(f, "%4d", j);          /* Hunk number */
	    fprintf (f,	"  %4d", sym->Defn);    /* Statement no. */
	}
	if (XrefList) {
	    fprintf (f,	"  ");
	    if (sym->Ref1 == 0)
		fprintf	(f, " *** UNREFERENCED ***");
	    else {
		ref = sym->Ref1;
		j = k =	0;
		while (1) {
		    if (ref->RefNum[j] == 0)
			break;
		    if (k >= 9)	{
			fprintf	(f, "\n");              /* New line */
			for (k = 0; k <	34; k++)
			    fprintf (f,	" ");
			k = 0;
		    }
		    fprintf (f,	" %4d", ref->RefNum[j]);
		    j++;
		    k++;
		    if (j < MAXREF)
			continue;		/* Get the next	slot */
		    if ((ref = ref->NextRef) ==	0)
			break;			/* End of last entry */
		    j =	0;			/* Start the next entry	*/
		}
	    }
	}
	fprintf	(f, "\n");
    }
}



CheckPage (f, xhdr) FILE *f; int xhdr;
/* Checks if end of page reached yet --	if so, advances	to next	page. */
{
    LnCnt++;
    if (LnCnt >= LnMax)	{
	PgCnt++;
	if (PgCnt > 1)
	    fprintf (f,	"\f");                  /* Skip to new page */
	fprintf	(f, "%-50s", TTLstring);        /* Title */
	fprintf	(f, "  %s        ", SourceFN);  /* File name */
	fprintf	(f, "Page %d\n\n\n", PgCnt);    /* Page number */
	LnCnt =	3;
	if (xhdr) {
	    fprintf (f,	"Symbol       Value    Hunk  Line");
	    if (XrefList)
		fprintf	(f, "   References");   /* Cross-reference */
	    fprintf (f,	"\n\n");
	    LnCnt += 2;
	}
    }
}



StartSrec (f, idntname)	FILE *f; char idntname[];
/* Writes object header	record */
{
    register int i;
    long CheckSum, templong;

    if (SFormat) {
	fprintf	(f, "S0");
	templong = strlen (idntname) + 3; /* extra for addr. & checksum	*/
	LongPut	(f, templong, 1);
	CheckSum = templong;

	fprintf	(f, "0000");  /* Address is 4 digits, all zero, for S0 */

	for (i = 0; idntname[i]	!= '\0'; i++) {
	    templong = toupper (idntname[i]);
	    LongPut (f,	templong, 1);
	    CheckSum +=	templong;
	}
	CheckSum = ~CheckSum;		/* Complement checksum */
	LongPut	(f, CheckSum, 1);
	fprintf	(f, "\n");
    } else {
	templong = HunkUnit;
	putl (f, templong);
	DumpName (f, idntname, 0L);
    }
    StartAddr =	TempAddr = Sindex = 0;
    NumRExt = NumR32 = NumR16 =	NumR8 =	0;
}



WriteSrecLine (f) FILE *f;
/* Transfers object code components to output buffer. */
/* Moves long words or portions	thereof. */
{
    register int i;
    long templong;

    if (HunkType == HunkBSS)
	return;				/* No code in BSS hunk */

    if (nO + nS	+ nD + nX) {		/* If we have object code */
	if (AddrCnt < TempAddr)	{	/*  and	location counter jumped	*/
	    if (SFormat)		/*  and	we're making S-format, */
		DumpSdata (f);		/*  get	rid of what we have */
	    StartAddr =	TempAddr = AddrCnt;	/*  and	start afresh. */
	}
	while (AddrCnt >= (TempAddr + 4))	/* It jumped forward - */
	    AppendSdata	(f, 0L,	4);		/*  fill with zeros    */
	if (AddrCnt > TempAddr)	{
	    i =	AddrCnt	- TempAddr;
	    AppendSdata	(f, 0L,	i);
	}
	AppendSdata (f,	ObjOp, nO);		/* Op code */
	AppendSdata (f,	ObjSrc,	nS);		/* Source */
	AppendSdata (f,	ObjDest, nD);		/* Destination */
	for (i = 0; i <	nX; i++) {		/* String data */
	    templong = ObjString[i];
	    AppendSdata	(f, templong, 1);
	}
    }
}



AppendSdata (f,	Data, n) FILE *f; long Data; int n;
/* If we are producing S-format	records:
     Transfers "n" low-order bytes from "Data" to the output buffer.
     If	the buffer becomes full, DumpSdata will	be called to flush it.
     S-records will also be broken on 16-byte boundaries.
   If we are producing AmigaDOS	format,	data will be written
     directly to Srec -	we'll go back and fill in the hunk length
     at	the end	of the hunk.					*/
{
    register int  i;
    register char byte;
    long templong;

    if (!Pass2)
	return;			/* Pass	2 only */
    if (HunkType == HunkBSS)
	return;			/* No data in BSS hunks! */

    if (HunkType == HunkNone) {	/* We're not in a hunk yet - */
	ReadSymTab ("  ");      /*  set up pointer */
	Sect = Sym;		/*  to the first section */
	HunkType = HunkCode;	/*  (start a code hunk)	*/
	SectLine = LineCount;
	if (!SFormat) {
	    templong = HunkName;
	    putl (f, templong);
	    DumpName (f, " ", 0L);
	    putl (f, HunkType);
	    LenPos = ftell (f);	/* Hunk	length goes here when we get it	*/
	    putl (f, 0L);	/* For now, set	it to zero */
	}
    }

    Data <<= (4	- n) * 8;	/* Left-justify	data */

    for	(i = 0;	i < n; i++) {
	byte = (Data >>	((3 - i) * 8)) & 0x00FF;
	TempAddr++;
	if (!SFormat)
	    putc (byte,	f);
	else {
	    Sdata[Sindex++] = byte;
	    if (((TempAddr & 0x0F) == 0) || (Sindex >= MAXSREC))
		DumpSdata (f);		/* Break S-record */
	}
    }
}



DumpSdata (f) FILE *f;
/* Writes an object code record	*/
{
    register int  i;
    register long CheckSum, templong;

    if (!SFormat) {
	AddrCnt	= AddrBndL (AddrCnt);	/* Finish last long word */
	fseek (f, LenPos, 0);	/* Hunk	length field is	here */
	putl (f, ((AddrCnt - SectStart)	>> 2) |	HunkFlags);
	fseek (f, 0L, 2);	/* Back	to end of file */
	DumpRel	(f);		/* Write relocation information	*/
	TempAddr = AddrCnt;
	return;
    }

    if (Sindex == 0)
	 return;		/* There's nothing to dump */

    fprintf (f,	"S2");
    templong = Sindex +	4;	/* Record length */
    LongPut (f,	templong, 1);
    CheckSum = templong;	/* Initialize CheckSum */

    LongPut (f,	StartAddr, 3);	/* Address */
    CheckSum +=	(StartAddr >> 16) & 0x00FF;
    CheckSum +=	(StartAddr >> 8) & 0x00FF;
    CheckSum +=	StartAddr & 0x00FF;

    for	(i = 0;	i < Sindex; i++) {
	templong = Sdata[i];
	LongPut	(f, templong, 1);	/* Object code */
	CheckSum += templong;
    }
    CheckSum = ~CheckSum;	/* Complement checksum */
    LongPut (f,	CheckSum, 1);
    fprintf (f,	"\n");

    StartAddr += Sindex;
    TempAddr = StartAddr;
    Sindex = 0;
}



PutRel (f, addr, hunk, size) FILE *f; long addr, hunk; int size;
/* Build a relocation entry if necessary */
{
    struct RelTab *rel;

    if (!Pass2)	return;			/* Pass	2 only */
    if (SFormat) return;		/* Not for S-format! */
    if (hunk ==	ABSHUNK) return;	/* Absolute */
    if (HunkType == HunkBSS) return;	/* Not for BSS hunks! */

    HeapSpace (sizeof(struct RelTab));	/* Make	sure we	have room */
    rel	= (struct RelTab *) HeapLim;	/* Pointer to new entry	*/
    rel->Offset	= addr;			/* Offset */
    rel->Hunk =	hunk;			/* Hunk	number */
    rel->Size =	size;			/* Size	*/
    HeapLim += sizeof(struct RelTab);	/* Bump	heap limit pointer */

    if (hunk < 0)			/* Count entries by type */
	NumRExt++;
    else if (size == Long)
	NumR32++;
    else if (size == Word)
	NumR16++;
    else
	NumR8++;
}



DumpRel	(f) FILE *f;
/* Dump	relocation information to the object file. */
{
    register struct SymTab *sym;
    register struct RelTab *rel, *rel2;
    int	 i, j, size, num, donexhdr, secthlin;
    long currhunk, nexthunk, templong;
    char *p;

    if (SFormat)
	return;				/* S-format is absolute! */

    secthlin = LineCount;		/* Current section ends	here */
    if (strcmp (OpCode,"SECTION") == 0) /*   unless we're starting   */
	secthlin--;			/*	a new section.	     */

    while (1) {
	if ((num = NumR32) != 0) {
	    size = Long;		/* Do 32-bit fields */
	    templong = HunkR32;
	    NumR32 = 0;			/* ...but only once */
	} else if ((num	= NumR16) != 0)	{
	    size = Word;		/* Then	do 16-bit fields */
	    templong = HunkR16;
	    NumR16 = 0;
	} else if ((num	= NumR8) != 0) {
	    size = Byte;		/* Finally do 8-bit fields */
	    templong = HunkR8;
	    NumR8 = 0;
	} else
	    break;			/* We're all done */

	putl (f, templong);		/* Record type */

	currhunk = 32767;
	num = 0;
	for (rel = RelStart; rel < (struct RelTab *) HeapLim; rel++) {
	    if ((rel->Size == size) && (rel->Hunk >= 0)) {
		if (rel->Hunk <	currhunk) {
		    currhunk = rel->Hunk;	/* Lowest hunk number */
		    num	= 1;			/* Reset counter */
		} else if (rel->Hunk ==	currhunk) {
		    num++;			/* Count entries */
		}
	    }
	}
	while (num > 0)	{	/* Repeat for all hunk references */
	    templong = num;
	    putl (f, templong);		/* Number of entries */
	    putl (f, currhunk);		/* Hunk	number */
	    nexthunk = 32767;
	    num	= 0;			/* Count for next hunk */
	    for	(rel = RelStart; rel < (struct RelTab *) HeapLim; rel++) {
		if ((rel->Size == size)	&& (rel->Hunk >= 0)) {
		    if (rel->Hunk < currhunk)
			continue;		/* Already wrote it */
		    else if (rel->Hunk == currhunk)
			putl (f, rel->Offset - Sect->Val);
		    else if (rel->Hunk < nexthunk) {
			nexthunk = rel->Hunk;	/* Next	hunk number */
			num = 1;		/* Reset counter */
		    } else if (rel->Hunk == nexthunk) {
			num++;			/* Count entries */
		    }
		}
	    }
	    currhunk = nexthunk;	/* Get ready for next hunk */
	}
	putl (f, 0L);		/* End of relocation information */
    }

    donexhdr = FALSE;		/* Haven't written hunk_ext yet */

    for	(i = 0,	sym = SymStart;	i < NumSyms; i++, sym++) {
	if (sym->Flags & 2) {		/* Scan	for XDEF symbols */
	    j =	sym->Defn;	/* Defined in current section? */
	    if ((j >= SectLine)	&& (j <= secthlin)) {
		if (!donexhdr) {
		    templong = HunkExt;	/* Haven't done header yet */
		    putl (f, templong);
		    donexhdr = TRUE;
		}
		if ((sym->Hunk & 0x0000FFFFL) == ABSHUNK)
		    templong = 0x02000000;
		else
		    templong = 0x01000000;		/* Flags */
		DumpName (f, sym->Nam, templong);	/* Symbol */
		putl (f, sym->Val - Sect->Val);		/* Offset */
	    }
	}
    }

    if (NumRExt	!= 0) {			/* External references (XREF) */
	if (!donexhdr) {
	    templong = HunkExt;		/* Haven't done header yet */
	    putl (f, templong);
	    donexhdr = TRUE;
	}
	for (rel = RelStart; rel < (struct RelTab *) HeapLim; rel++) {
	    if (rel->Hunk < 0) {
		p = Heap + ~rel->Hunk;
		if (rel->Size == Long)
		    templong = 0x81000000;	/* ext_ref32 */
		else if	(rel->Size == Word)
		    templong = 0x83000000;	/* ext_ref16 */
		else
		    templong = 0x84000000;	/* ext_ref8 */
		DumpName (f, p,	templong);	/* Flags and symbol */
		templong = 1;
		for (rel2 = rel	+ 1; rel2 < (struct RelTab *) HeapLim; rel2++)
		    if (rel2->Hunk == rel->Hunk)
			templong++;		/* Number of times */
		putl (f, templong);		/*  symbol occurs  */
		for (rel2 = rel; rel2 <	(struct	RelTab *) HeapLim; rel2++) {
		    if (rel2->Hunk == rel->Hunk) {
			putl (f, rel2->Offset -	Sect->Val); /* Offset */
			if (rel2 != rel)	/* Kill	hunk so	we    */
			    rel2->Hunk = 0;	/*  don't do it again */
		    }				/*  (we're done with  */
		}				/*  the	table anyway) */
	    }
	}
	NumRExt	= 0;
    }
    if (donexhdr)
	putl (f, 0L);			/* End of external information */

    if (DumpSym) {			/* Dump	the symbol table */
	donexhdr = FALSE;
	for (i = 0, sym	= SymStart; i <	NumSyms; i++, sym++) {
	    if ((sym->Hunk == CurrHunk)
	    && ((sym->Flags == 0) || (sym->Flags == 2))) {
		j = sym->Defn;		/* Defined in current section? */
		if ((j >= SectLine) && (j <= secthlin))	{
		    if (!donexhdr) {
			templong = HunkSym;		/* Header */
			putl (f, templong);
			donexhdr = TRUE;
		    }
		    DumpName (f, sym->Nam, 0L);		/* Symbol */
		    putl (f, sym->Val -	Sect->Val);	/* Offset */
		}
	    }
	}
	if (donexhdr)
	    putl (f, 0L);		/* End of symbol table dump */
    }

    if (HeapLim	> HighHeap)
	HighHeap = HeapLim;		/* High-water mark */
    HeapLim = (char *) RelStart;	/* Reset heap limit */
}



EndSdata (f, addr) FILE	*f; long addr;
/* Write end record to object file */
{
    register long checksum, templong;

    if (SFormat) {
	DumpSdata (Srec);		/* Write any remaining data */
	fprintf	(f, "S804");            /* Record header */
	checksum = 4;
	LongPut	(f, addr, 3);		/* Transfer address */
	checksum += (addr >> 16) & 0x00FF;
	checksum += (addr >> 8)	& 0x00FF;
	checksum += addr & 0x00FF;
	checksum = ~checksum;
	LongPut	(f, checksum, 1);	/* Checksum */
	fprintf	(f, "\n");
    } else {
	if (HunkType !=	HunkNone) {
	    DumpSdata (Srec);		/* Last	hunk's data */
	    templong = HunkEnd;		/* End the last	hunk */
	    putl (f, templong);
	}
    }
}



DumpName (f, name, flags) FILE *f; char	name[];	long flags;
/* Writes a name preceded by a long word containing the
    length of the name in long words.  The length word has
    the	contents of "flags" ORed into it.  The name is padded
    with binary	zeros to the next long word boundary. */
{
    register int  i;
    register long templong;

    templong = (strlen (name) +	3) >> 2;	/* Length (long	words) */
    templong |=	flags;				/* Add flag bits */
    putl (f, templong);
    i =	0;
    while (name[i])
	putc (name[i++], f);			/* Write a byte	*/
    while (i & 3) {
	putc ('\0', f);                         /* Pad the last word */
	i++;
    }
}



LongPut	(f, data, length) FILE *f; long	data; int length;
/* Writes to file "f" the hexadecimal interpretation of
    the	bytes in "data".  The number of bytes written
    (two hex digits per	byte) is given in "length" -
    if less than 4, only low-order bytes are written. */
{
    register int  i, j,	k;

    for	(i = length - 1; i >= 0; i--) {
	j = (data >> (i	* 8)) &	0x00FF;
	k = j >> 4;
	fprintf	(f, "%c", k>9 ? k-10+'A' : k+'0');
	k = j &	0x0F;
	fprintf	(f, "%c", k>9 ? k-10+'A' : k+'0');
    }
}



putl (f, data) FILE *f;	long data;
/* Writes to file "f" the binary contents of "data" */
{
    register int  i;
    register char byte;

    for	(i = 0;	i < 4; i++) {
	byte = (data >>	((3 - i) * 8)) & 0x00FF;
	putc (byte, f);
    }
}



Error (pos, errornum) int pos, errornum;
/* Displays error #errornum, then waits	for any	key to continue	*/
{
    register int i;

    if (!Pass2)
	return;				/* Active during pass 2	only */

    if (errlim < ERRMAX) {		/* Save	error data */
	errcode[errlim]	= errornum;
	errpos[errlim] = pos;
	errlim++;
    }
    printf ("    \n%4d   %s\n", LineCount, Line);   /* Line in error */
    for	(i = 0;	i < pos+7; i++)
	printf(" ");
    printf ("^ ");                              /* Error flag */
    if (errlim == 1) {
	if (InF->UPtr == 0)
	    printf ("%s", InF->NPtr);           /* Module name */
	else
	    printf ("(user macro)");            /* In a user macro */
	printf (" line %d", InF->Line);         /* Line number in module */
    }
    printf ("\n%s\n", errmsg[errornum]);        /* Error message */
    ErrorCount++;				/* Count errors	*/
}
