/*------------------------------------------------------------------*/
/*								    */
/*		      MC68000 Cross Assembler			    */
/*								    */
/*	      Copyright	(c) 1985 by Brian R. Anderson		    */
/*								    */
/*	  Assembler directive processing - January 6, 1989	    */
/*								    */
/*   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 1989 by Charlie Gibbs.	    */
/*								    */
/*------------------------------------------------------------------*/

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

/* Functions */
extern int  LineParts(), Instructions();
extern int  GetInstModeSize(), GetMultReg(), CountNest();
extern int  ReadSymTab(), GetArgs(), GetAReg(),	OpenIncl();
extern long AddrBndW(),	AddrBndL(), GetValue(),	CalcValue();
extern char *AddName(),	*GetField();
extern struct SymTab *NextSym();
extern struct SymTab **HashIt();



int ObjDir (dummy) int dummy;
/* Generates Object Code for Assembler Directives */
{
    register char *s, *t;
    register int i, j;
    int	 oploc;
    long templong;
    char tempop[MAXLINE], delim;
    struct SetFixup *sf;

    switch (Dir) {

    case Org:						/* ORG */
	PrntAddr = MakeHunk = TRUE;
	templong = GetValue (SrcOp, SrcLoc);
	if (DefLine2 >=	LineCount) {
	    Error (SrcLoc, FwdRef);	/* Illegal forward reference */
	    break;
	}
	if (OpCode[0] == 'R') {                         /* RORG */
	    if (Hunk2 != ABSHUNK) {
		Error (SrcLoc, RelErr);	/* RORG	needs absolute value */
		break;
	    }
	} else if (Hunk2 != CurrHunk) {
	    Error (SrcLoc, RelErr);	/* Can't ORG out of hunk */
	    break;
	}

	if ((!Pass2 || (HunkType == HunkBSS))
	&& (templong < AddrCnt)	/* If we're ORGing to a lower address  */
	&& (AddrCnt > OrgHigh))	/*  and	this is	the highest we've been */
	    OrgHigh = AddrCnt;	/*  remember how far we	got.	       */

	AddrCnt	= templong;	/* Update the location counter */
	OrgFlag	= TRUE;		/* Indicate object fixups are needed */
	break;

    case Equ:						/* EQU */
	if (Label[0] ==	'\0')
	    Error (0, NeedLab);		/* Need	a label	*/
	ObjSrc = GetValue (SrcOp, SrcLoc);
	if (DefLine2 >=	LineCount)
	    Error (SrcLoc, FwdRef);	/* Illegal forward reference */
	Src.Hunk = Hunk2;
	PrntAddr = MakeHunk = TRUE;
	break;

    case DC:						/* DC */
	if ((Size == Word) || (Size == Long))
	    AddrCnt = AddrBndW (AddrCnt);
	s = Line + SrcLoc;
	while (!isspace(*s) && (*s != '\0') && (*s != ';')) {
	    oploc = s -	Line;
	    if (((*s ==	'\'') || (*s == '"'))   /* String */
	    && (Size ==	Byte)) {
		delim =	*s++;			/* Get the delimiter */
		while (1) {
		    if (*s == '\0') {           /* No closing delimiter */
			Error (s-Line, NoStrEnd);
			break;
		    }
		    if (*s == delim) {		/* End of string? */
			if (*(++s) != delim)	/* Check next character	*/
			    break;		/* End of string */
		    }	/* Otherwise it's an apostrophe in the string */
		    Src.Hunk = ABSHUNK;		/* Absolute value */
		    ObjString[nX++] = *s++;	/* Current character */
		}
	    } else {			/* Not a string	constant */
		s = GetField (s, SrcOp);
		ObjSrc = GetValue (SrcOp, oploc);	/* Value */
		if ((Src.Hunk =	Hunk2) != ABSHUNK) {	/* Hunk	no. */
		    templong = AddrCnt + nX;		/* Relocatable */
		    PutRel (templong, Hunk2, Size);
		}
		if (Size == 4) {
		    ObjString[nX++] = (ObjSrc >> 24) & 0x00FF;
		    ObjString[nX++] = (ObjSrc >> 16) & 0x00FF;
		}
		if (Size >= 2)
		    ObjString[nX++] = (ObjSrc >> 8) & 0x00FF;
		ObjString[nX++]	= ObjSrc & 0x00FF;
		if (Size == 2)
		    templong = 0xFFFF0000L;
		else if	(Size == 1)
		    templong = 0xFFFFFF00L;
		if (Size < 4)
		    if (((ObjSrc & templong) !=	0)
		    && ((ObjSrc	& templong) != templong))
			Error (s-Line, SizeErr);
	    }
	    if (*s == ',')
		s++;			/* Skip	over separator */
	}
	if (!isspace(*s) && (*s	!= '\0') && (*s != ';'))
	    Error (s-Line, OperErr);	/* Didn't end properly */
	AddrAdv	= InstSize = nX;
	PrntAddr = MakeHunk = TRUE;
	break;

    case DS:						/* DS */
	if (DestLoc != 0) {
	    Error (DestLoc, OperErr);	/* Only	one operand is allowed */
	    PrntAddr = MakeHunk	= TRUE;
	    break;
	}
	AddrAdv	= GetValue (SrcOp, SrcLoc);
	if (DefLine2 >=	LineCount) {
	    Error (SrcLoc, FwdRef);	/* Illegal forward reference */
	    AddrAdv = 0;
	}
	if (Hunk2 != ABSHUNK)
	    Error (SrcLoc, AbsReq);	/* Count must be absolute */

	if (Size == Word) {		/* Words */
	    AddrCnt = AddrBndW (AddrCnt);
	    AddrAdv <<=	1;
	}
	if (Size == Long) {		/* Long	words */
	    AddrCnt = AddrBndW (AddrCnt);
	    AddrAdv <<=	2;
	}
	if (Pass2 && (HunkType != HunkBSS)) {	/* If this isn't     */
	    templong = AddrAdv;			/*  a BSS hunk,	     */
	    while (templong >= 4) {		/*  generate zeros   */
		AppendSdata (0L, 4);		/*  to fill the	area */
		templong -= 4;
	    }
	    if (templong > 0) {
		i = templong;
		AppendSdata (0L, i);
	    }
	}
	PrntAddr = MakeHunk = TRUE;
	break;

    case Even:						/* EVEN	*/
	AddrCnt	= AddrBndW (AddrCnt);
	PrntAddr = MakeHunk = TRUE;
	break;

    case End:						/* END */
	if (Pass2)
	    if (SrcOp[0] != '\0')
		EndAddr	= GetValue (SrcOp, SrcLoc);
	    else
		EndAddr	= 0;
	PrntAddr = MakeHunk = TRUE;
	break;

    case Xdef:						/* XDEF	*/
    case Public:					/* PUBLIC */
	if (SFormat)
	    Error (OpLoc, NotSFmt);		/* Not in S-format */
	s = Line + SrcLoc;
	while (!isspace(*s) && (*s != '\0')) {
	    oploc = s -	Line;
	    s =	GetField (s, SrcOp);		/* Get a symbol	*/
	    if (ReadSymTab (SrcOp)) {
		if (!Pass2) {
		    if ((Sym->Flags & 0x61) == 0) {
			Sym->Flags |= 2;	/* Set XDEF flag */
			if (OpCode[0] == 'P') {
			    Sym->Flags |= 0x80;	/* Defined as PUBLIC */
			}
		    }
		} else {
		    if (Sym->Defn != LineCount)	/* If not PUBLIC->XREF */
			AddRef (LineCount);	/*  it's a reference  */
		    if (Sym->Defn == NODEF)
			Error (oploc, Undef);	/* Never got defined */
		    else if (Sym->Flags	& 0x60)
			Error (oploc, AddrErr);	/* Can't XDEF a register */
		}
	    } else if (!Pass2) {		/* Not yet defined */
		if (OpCode[0] == 'P') {         /* Treat PUBLIC as XREF */
		    AddSymTab (SrcOp, 0L, 0L ,LineCount, 0x81);
		    Sym->Hunk =	~((long) Sym->Nam);
		} else {
		    AddSymTab (SrcOp, 0L, CurrHunk, NODEF, 2);	/* XDEF	*/
		}
	    }
	    if (*s == ',')
		s++;				/* Skip	over separator */
	}
	break;

    case Xref:						/* XREF	*/
	if (SFormat)
	    Error (OpLoc, NotSFmt);		/* Not in S-format */
	s = Line + SrcLoc;
	while (!isspace(*s) && (*s != '\0')) {
	    oploc = s -	Line;
	    s =	GetField (s, SrcOp);
	    if (Pass2) {
		if (ReadSymTab (SrcOp))	{
		    if (Sym->Defn != LineCount)	{
			AddRef (LineCount); /* Ignore extraneous XREF */
		    }
		}
	    } else {
		if (!ReadSymTab	(SrcOp)) {	/* Only	if not defined */
		    AddSymTab (SrcOp, 0L, 0L, LineCount, 1);
		    Sym->Hunk =	~((long) Sym->Nam);
		}
	    }
	    if (*s == ',')
		s++;			/* Skip	over separator */
	}
	break;

    case Page:						/* PAGE	*/
	if (Pass2 && (LineCount	> 1))	/* Ignore PAGE at start	of file	*/
	    LnCnt = LnMax;		/* Resume on a new page	*/
	break;

    case DoList:					/* LIST	*/
	ListOff	= FALSE;
	if (!Pass2 && !SuppList	&& (IncStart !=	0)) {
	    IncStart = 0;			/* We can't      */
	    if (SkipLim->Set1 != NULL) {	/*  skip this	 */
		SetFixLim = SkipLim->Set1;	/*  INCLUDE file */
		SetFixLim++;			/*  in pass 2	 */
	    }					/*  (we	must	 */
	}					/*  list it).	 */
	break;

    case NoList:					/* NOLIST */
	ListOff	= TRUE;
	break;

    case Space:						/* SPC */
	if (Pass2 && !ListOff && !SuppList) {
	    if (SrcOp[0] != '\0')
		j = GetValue (SrcOp, SrcLoc);	/* Amount to space */
	    else
		j = 1;				/* Default to one line */
	    for	(i = 0;	i < j; i++) {
		if (LnCnt >= LnMax)
		    break;			/* Page	overflow */
		xputs (&List, "\n");            /* Space one line */
	    }
	}
	break;

    case Title:						/* TTL */
	s = Line + SrcLoc;
	t = TTLstring;
	while (*s && (s	< (TTLstring+MAXLINE)))
	    *t++ = *s++;		/* Get title string */
	*t = '\0';
	if (LineCount >	1) {
	    LnCnt = LnMax;		/* Skip	to a new page */
	} else {
	    if (Pass2) {
		xputs (&List, TTLstring);
		xputs (&List, "\n\n");
	    }
	    LnCnt += 2;			/* Don't skip at start of file */
	}
	break;

    case Cnop:						/* CNOP	*/
	i = TRUE;			/* "Error-free" flag */

	ObjSrc = GetValue (SrcOp, SrcLoc);
	if (DefLine2 >=	LineCount) {
	    Error (SrcLoc, FwdRef);	/* Illegal forward reference */
	    i =	FALSE;
	}
	if (Hunk2 != ABSHUNK) {
	    Error (SrcLoc, AbsReq);	/* Must	be absolute! */
	    i =	FALSE;
	}

	ObjDest	= GetValue (DestOp, DestLoc);
	if (DefLine2 >=	LineCount) {
	    Error (DestLoc, FwdRef);	/* Illegal forward reference */
	    i =	FALSE;
	}
	if (Hunk2 != ABSHUNK) {
	    Error (DestLoc, AbsReq);	/* Must	be absolute! */
	    i =	FALSE;
	}

	templong = ObjDest;
	while ((templong > 0) && ((templong & 1) == 0))
	    templong >>= 1;		/* Shift out low-order zeros */
	if ((templong != 1) || (ObjDest	== 1)) {
	    Error (DestLoc, OperErr);	/* DestOp must be a power of 2 */
	    i =	FALSE;
	}
	if ((ObjSrc & 1) || (ObjSrc >= ObjDest)) {
	    Error (SrcLoc, OperErr);	/* SrcOp is odd	or out of range	*/
	    i =	FALSE;
	}

	if (i) {			/* If no errors	so far */
	    AddrCnt = AddrBndW (AddrCnt);
	    templong = (AddrCnt	& ~(ObjDest-1))	+ ObjSrc;
	    if (templong < AddrCnt)
		templong += ObjDest;	/* We must advance to here */
	    if ((templong - AddrCnt) < MAXLINE)	{
		nX = templong -	AddrCnt;
		for (j = 0; j <	nX; ) {
		    ObjString[j++] = NOP / 256;
		    ObjString[j++] = NOP & 255;
		}
		AddrAdv	= InstSize = nX;	/* generate NOPs */
		PrntAddr = MakeHunk = TRUE;
	    } else {
		Error (DestLoc,	OperErr);	/* Too many NOPs */
	    }
	}
	break;

    case Include:					/* INCLUDE */
	if (Pass2				/* If we can skip */
	&& (SkipIdx < SkipLim)			/*  this INCLUDE  */
	&& (LineCount == SkipIdx->Start)) {	/*  file in pass  */
	    LineCount =	SkipIdx->Finish;	/*  2, do so.	  */
	    MacCount = SkipIdx->MCount;
	    if ((sf = SkipIdx->Set1) !=	NULL) {
		while ((sf >= SetFixLim) && (sf->Sym !=	NULL)) {
		    (sf->Sym)->Val  = sf->Val;	/* Fix up SET symbols */
		    (sf->Sym)->Hunk = sf->Hunk;
		    sf--;
		}
	    }
	    SkipIdx++;
	    break;
	}
	if ((Quiet < 0)	&& (InF->UPtr == 0))
	    ShowLine (InF->Line);	/* Show	where we are */
	s = Line + SrcLoc;
	if ((*s	== '"') || (*s == '\''))
	    s++;			/* Ignore quotes */
	t = tempop;
	while (!isspace(*s)
	&& (*s != '"')
	&& (*s != '\'')
	&& (*s != '\0'))
	    *t++ = *s++;
	*t = '\0';
	if (InF->UPtr == 0) {
	    InF->Pos = lseek (In.fd, 0L, 1);
	    InF->Pos -=	In.Lim-In.Ptr;	/* Position in outer file */
	}
	if (!OpenIncl (tempop, InclList)) {
	    Error (SrcLoc, NoIncl);	/* Couldn't open file */
	    InclErrs = TRUE;
	    if (InF->UPtr == 0)	{
		In.fd =	open (InF->NPtr, 0);
		lseek (In.fd, InF->Pos,	0);
		In.Ptr = In.Lim	= In.Buf;
	    }
	    break;			/* Return to outer file	*/
	}
	InFNum++;			/* Bump	nesting	level */
	if (--InF < LowInF)
	    LowInF = InF;
	Heap2Space (strlen(tempop)+1);	/* Check for space */
	InF->UPtr = 0;			/* Not a user macro */
	InF->NPtr = NextFNS;		/* New stack pointer */
	strcpy (NextFNS, tempop);	/* File	name */
	NextFNS	+= strlen (tempop) + 1;	/* Next	available space	*/
	if (NextFNS > High2)
	    High2 = NextFNS;		/* Set high-water mark */
	InF->NArg = -1;			/* Indicate it's not a macro */
	InF->Line = 0;			/* Clear line counter */
	InF->MCnt = MacCount;

	if (!Pass2 && (SuppList	|| ListOff) && (IncStart == 0))	{
	    s =	(char *) SkipLim + sizeof (struct SkipEnt);
	    if (s <= (char *) SetFixLim) {
		SkipLim->Set1 =	NULL;	/* Save	starting position */
		IncStart = LineCount;	/*  in case we can skip	  */
		IncPtr = InF;		/*  this file in pass 2.  */
	    }
	}
	break;

    case Set:						/* SET */
	if (Label[0] ==	'\0')
	    Error (0, NeedLab);		/* Need	a label	*/
	ObjSrc = GetValue (SrcOp, SrcLoc);
	if (DefLine2 >=	LineCount)
	    Error (SrcLoc, FwdRef);	/* Illegal forward reference */
	Src.Hunk = Hunk2;
	if (!ReadSymTab	(Label))		/* Make	a new entry */
	    AddSymTab (Label, ObjSrc, Src.Hunk,	LineCount, 4);
	else if	(Sym->Flags & 4) {		/* Re-SET the symbol */
	    Sym->Val = ObjSrc;			/* SET value */
	    Sym->Hunk =	Src.Hunk;		/* Hunk	number */
	    Sym->Defn =	LineCount;		/* Statement number */
	}
	PrntAddr = MakeHunk = TRUE;

	if (!Pass2 && (IncStart	!= 0)) {
	    if ((sf = SkipLim->Set1) !=	NULL) {
		while (sf >= SetFixLim)	{
		    if (sf->Sym	!= Sym)	{
			sf--;
		    } else {
			sf->Val	 = Sym->Val;	/* Update an	    */
			sf->Hunk = Sym->Hunk;	/*  existing entry. */
			return (Set);
		    }
		}
	    }
	    sf = SetFixLim;
	    sf--;
	    s =	(char *) SkipLim + sizeof (struct SkipEnt);
	    if (s > (char *) sf) {
		IncStart = 0;		/* No room for set symbol */
		if (SkipLim->Set1 != NULL) {
		    SetFixLim =	SkipLim->Set1;
		    SetFixLim++;
		}
	    } else {
		if (SkipLim->Set1 == NULL)
		    SkipLim->Set1 = sf;	/* First SET symbol in INCLUDE */
		sf->Sym	 = Sym;
		sf->Val	 = Sym->Val;	/* Save	SET symbol value */
		sf->Hunk = Sym->Hunk;	/*  and	hunk.		 */
		SetFixLim = sf;
	    }
	}
	break;

    case Macro:						/* MACRO */
	if (Label[0] ==	'\0')
	    Error (0, NeedLab);		/* Need	a label	*/

	s = Label;
	t = tempop;
	*t++ = ' ';                     /* Prepend name with a */
	while (*s)			/*  blank and convert  */
	    *t++ = toupper (*s++);	/*  it to upper	case.  */
	*t = '\0';

	if (!Pass2) {			/* Pass	1 */
	    if (!ReadSymTab (tempop))		/* Save	MACRO name */
		AddSymTab (tempop, 0L, 0L, LineCount, 8);
	    Sym->Hunk =	(long) AddName(Line,1);	/* Save	MACRO stmt. */
	} else {			/* Pass	2 */
	    ReadSymTab (tempop);
	    if (Sym->Defn != LineCount)	{
		Error (LabLoc, DupMac);		/* Duplicate MACRO */
		AddRef (LineCount);
	    }
	    WriteListLine (&List);		/* Echo	MACRO */
	}

	i = 0;				/* IF nest counter */
	while (1) {			/* Process macro body */
	    if (LineParts (dummy)) {
		Error (OpLoc, NoENDM);	/* Premature EOF */
		i = 0;
		break;
	    }
	    if ((i += CountNest	(OpCode)) < 0) {
		Error (OpLoc,ManyENDC);	/* Unmatched ENDC */
		i = 0;
	    }
	    if (!Pass2)
		AddName	(Line, 2);	/* Store a line	*/
	    if (strcmp (OpCode,	"ENDM") == 0)
		break;			/* Main	program	echoes ENDM */
	    if (Pass2)
		WriteListLine (&List);	/* Echo	a line */
	}
	if (i >	0)
	    Error (OpLoc, NoENDC);	/* ENDC	is missing */

	break;

    case IfEQ:						/* IFEQ	*/
	ObjSrc = GetValue (SrcOp, SrcLoc);
	if (ObjSrc != 0)
	    SkipNest++;			/* Skip	to the next ENDC */
	break;

    case IfNE:						/* IFNE	*/
	ObjSrc = GetValue (SrcOp, SrcLoc);
	if (ObjSrc == 0)
	    SkipNest++;
	break;

    case IfGT:						/* IFGT	*/
	ObjSrc = GetValue (SrcOp, SrcLoc);
	if (ObjSrc <= 0)
	    SkipNest++;
	break;

    case IfGE:						/* IFGE	*/
	ObjSrc = GetValue (SrcOp, SrcLoc);
	if (ObjSrc < 0)
	    SkipNest++;
	break;

    case IfLT:						/* IFLT	*/
	ObjSrc = GetValue (SrcOp, SrcLoc);
	if (ObjSrc >= 0)
	    SkipNest++;
	break;

    case IfLE:						/* IFLE	*/
	ObjSrc = GetValue (SrcOp, SrcLoc);
	if (ObjSrc > 0)
	    SkipNest++;
	break;

    case IfC:						/* IFC */
	if (strcmp (SrcOp, DestOp) != 0)
	    SkipNest++;
	break;

    case IfNC:						/* IFNC	*/
	if (strcmp (SrcOp, DestOp) == 0)
	    SkipNest++;
	break;

    case IfD:						/* IFD */
	if (ReadSymTab (SrcOp))
	    AddRef (LineCount);
	if (DefLine2 > LineCount)
	    SkipNest++;
	break;

    case IfND:						/* IFND	*/
	if (ReadSymTab (SrcOp))
	    AddRef (LineCount);
	if (DefLine2 <=	LineCount)
	    SkipNest++;
	break;

    case EndC:						/* ENDC	*/
	break;				/* LineParts will take care of it */

    case Section:					/* SECTION */
	if (SFormat)
	    Error (OpLoc, NotSFmt);	/* Not in S-format */
	tempop[0] = '\0';
	s = Line + DestLoc + strlen (DestOp);	/* Check for flags */
	if (*s == ',') {
	    s++;
	    GetField (s, tempop);	/* Get specification */
	}
	DoSection (SrcOp, SrcLoc, DestOp, DestLoc, tempop, j);
	break;

    case CSeg:						/* CODE	*/
	if (SFormat)
	    Error (OpLoc, NotSFmt);	/* Not in S-format */
	DoSection (SrcOp, SrcLoc, "CODE", OpLoc, DestOp, DestLoc);
	break;				/* Treat as SECTION */

    case DSeg:						/* DATA	*/
	if (SFormat)
	    Error (OpLoc, NotSFmt);	/* Not in S-format */
	DoSection (SrcOp, SrcLoc, "DATA", OpLoc, DestOp, DestLoc);
	break;				/* Treat as SECTION */

    case BSS:						/* BSS */
	if (SFormat)
	    Error (OpLoc, NotSFmt);	/* Not in S-format */
	DoSection (SrcOp, SrcLoc, "BSS", OpLoc, DestOp, DestLoc);
	break;				/* Treat as SECTION */

    case Idnt:						/* IDNT	*/
	s = Line + SrcLoc;
	if ((*s	== '"') || (*s == '\''))
	    s++;			/* Ignore quotes */
	t = IdntName;
	while (!isspace(*s)
	&& (*s != '"')
	&& (*s != '\'')
	&& (*s != '\0'))
	    *t++ = *s++;
	*t = '\0';
	break;

    case DCB:						/* DCB */
	if ((Size == Word) || (Size == Long))
	    AddrCnt = AddrBndW (AddrCnt);
	ObjSrc = GetValue (SrcOp, SrcLoc);	/* Replication factor */
	if (DefLine2 >=	LineCount) {
	    Error (SrcLoc, FwdRef);	/* Illegal forward reference */
	    ObjSrc = 0;
	}
	if (Hunk2 != ABSHUNK) {
	    Error (SrcLoc, AbsReq);	/* Must	be absolute! */
	    ObjSrc = 0;
	}
	ObjDest	= GetValue (DestOp, DestLoc);	/* Value to replicate */
	Dest.Hunk = Hunk2;
	for (i = 0; i <	ObjSrc;	i++) {
	    if (nX >= MAXLINE) {
		Error (SrcLoc, DCOflo);		/* ObjString overflowed	*/
		break;
	    }
	    if (Dest.Hunk != ABSHUNK) {
		templong = AddrCnt + nX;	/* Relocatable */
		PutRel (templong, Hunk2, Size);
	    }
	    if (Size ==	4) {
		ObjString[nX++]	= (ObjDest >> 24) & 0x00FF;
		ObjString[nX++]	= (ObjDest >> 16) & 0x00FF;
	    }
	    if (Size >=	2)
		ObjString[nX++]	= (ObjDest >> 8) & 0x00FF;
	    ObjString[nX++] = ObjDest &	0x00FF;
	}
	AddrAdv	= InstSize = nX;
	PrntAddr = MakeHunk = TRUE;
	break;

    case Equr:						/* EQUR	*/
	if ((i = IsRegister (SrcOp, strlen (SrcOp))) < 0)
	    Error (SrcLoc, AddrErr);	/* Not a valid register	*/
	if (Label[0] ==	'\0')
	    Error (0, NeedLab);		/* Need	a label	*/
	else {
	    if (!ReadSymTab (Label))	/* Make	a new entry */
		AddSymTab (Label, (long) i, 0L,	LineCount, 0x20);
	    GotEqur = TRUE;		/* We have at least one	EQUR */
	}
	break;

    case Reg:						/* REG */
	if (Label[0] ==	'\0')
	    Error (0, NeedLab);		/* Need	a label	*/
	else {
	    if ((i = GetMultReg	(SrcOp,	SrcLoc)) == 0) {
		Error (SrcLoc, OperErr);
	    } else {
		if (!ReadSymTab	(Label)) {  /* Make a new entry	*/
		    AddSymTab (Label, (long) i,	0L, LineCount, 0x40);
		    GotEqur = TRUE;	    /* We have at least	one EQUR */
		}
	    }
	}
	break;

    case Near:						/* NEAR	*/
	SmallData = TRUE;	/* Set small-data model	flag */
	AnyNear	= TRUE;		/* Remember that we use	it somewhere */
	break;

    case Far:						/* FAR */
	SmallData = FALSE;	/* Reset small-data model flag */
	break;

    default:
	break;
    }

    return (Dir);
}



DoSection (name, nameloc, type,	typeloc, flags,	flagloc)
char *name, *type, *flags;
int nameloc, typeloc, flagloc;
/* Processes SECTION directive or equivalent */
{
    static long	HunkPos;	/* Seek	address	of start of section */
    register char *s, *t;
    long newflags, templong;
    char tempop[MAXLINE];

    PrntAddr = TRUE;

    for	(s = type; *s; s++)		/* Convert section type	*/
	*s = toupper (*s);		/*  to upper case */
    if ((type[0] == '\0') || (strcmp (type, "CODE") == 0))
	newflags = HunkCode;		/* Code	section	*/
    else if (strcmp (type, "DATA") == 0)
	newflags = HunkData;		/* Data	section	*/
    else if (strcmp (type, "BSS") == 0)
	newflags = HunkBSS;		/* BSS section */
    else {
	Error (typeloc,	OperErr);	/* Invalid type	*/
	strcpy (type, "CODE");
	newflags = HunkCode;		/* Make	it CODE	*/
    }
    newflags <<= 16;	/* Shift to high-order 16 bits */

    if (flags[0]) {
	for (s = flags;	*s; s++)		/* Convert flags */
	    *s = toupper (*s);			/*  to upper case */
	if (strcmp (flags, "CHIP") == 0)
	    newflags |=	MEMF_CHIP;		/* CHIP	memory */
	else if	(strcmp	(flags,	"FAST") == 0)
	    newflags |=	MEMF_FAST;		/* FAST	memory */
	else
	    Error (flagloc, OperErr);		/* Invalid - ignore */
    }

    templong = (newflags & 0xFFFF0000) >> 16;
    sprintf (tempop,"  %4x",HunkSeq++); /* Make section name unique */
    s =	name;
    if ((*s == '"') || (*s == '\''))
	s++;				/* Ignore quotes */
    t =	tempop + 6;
    while (!isspace(*s)
    && (*s != '"')
    && (*s != '\'')
    && (*s != '\0'))
	*t++ = *s++;			/* Concatenate section name */
    *t = '\0';

    if (ReadSymTab (tempop)) {		/* Scan	for section name */
	if (HunkType ==	HunkNone) {
	    SectLine = 1;		/* Start of first section */
	} else {
	    if (Pass2) {
		AddRef (LineCount);
		DumpSdata (&Srec);	/* Finish the previous hunk */
		if (!MakeHunk) {	/* If it was a null hunk,   */
		    if (Srec.Ptr > Srec.Buf)	/* overwrite it.    */
			write (Srec.fd,	Srec.Buf, Srec.Ptr - Srec.Buf);
		    lseek (Srec.fd, HunkPos, 0);
		    Srec.Ptr = Srec.Buf;
		}
	    } else {
		AddrCnt	= AddrBndL (AddrCnt);	/* Finish on long word */
	    }
	    if (AddrCnt	> OrgHigh)
		Sect->Val = AddrCnt;	/* End of old section */
	    else
		Sect->Val = OrgHigh;	/* We've ORGed higher */
	    SectLine = LineCount;	/* Start of new	section	*/
	}
	Sect = Sym;			/* Point to new	section	*/
	AddrCnt	= SectStart = Sym->Val;	/* Continuation	*/
	OrgHigh	= 0L;
	OrgFlag	= FALSE;
	TempAddr = StartAddr = AddrCnt;
	CurrHunk = Sym->Hunk & 0x0000FFFFL;	    /* Hunk no.	*/
	HunkType = (Sym->Hunk &	0x3FFF0000L) >>	16; /* Type */
	HunkFlags = Sym->Hunk &	0xC0000000L;	    /* Flags */
	if (Pass2 && !SFormat) {		/* Start a new hunk */
	    HunkPos = lseek (Srec.fd, 0L, 1);
	    HunkPos += Srec.Ptr	- Srec.Buf;	/* It starts here */
	    templong = HunkName;
	    xputl (&Srec, templong);
	    if (tempop[6])
		DumpName (&Srec, &tempop[6], 0L);   /* Hunk name */
	    else
		DumpName (&Srec, " ", 0L);
	    xputl (&Srec, HunkType);	/* Hunk	type */
	    LenPtr = Srec.Ptr;		/* Pointer to hunk length */
	    LenPos = lseek (Srec.fd, 0L, 1);
	    LenPos += LenPtr-Srec.Buf;	/* Hunk	length goes here */
	    xputl (&Srec, 0L);		/* For now, set	it to zero */
	}
	MakeHunk = FALSE;		/* We don't have anything yet */
	if (AnyNear && (CurrHunk > 1))
	    Error (OpLoc, ManySect);	/* Too many hunks for small data */
	return;
    }

    AddrCnt = AddrBndL (AddrCnt);	/* Finish on long word bounary */

    if (Pass2) {
	Error (OpLoc, ManySect);	/* Table overflowed in pass 1 */
	return;
    }
    if (NextHunk >= ABSHUNK)		/* Set up a new	table entry */
	return;				/* Section table overflow */

    if (HunkType != HunkNone) {
	if (AddrCnt > OrgHigh)
	    Sect->Val =	AddrCnt;	/* End of old section */
	else
	    Sect->Val =	OrgHigh;	/* We've ORGed higher */
	SectLine = LineCount;		/* Starting line number	*/
    } else {
	SectLine = 1;			/* Start of first section */
    }
    AddrCnt = SectStart	= OrgHigh = 0L;	/* Reset location counter */
    OrgFlag = FALSE;
    TempAddr = StartAddr = AddrCnt;
    HunkType = (newflags & 0x3FFF0000L)	>> 16;	/* Type	*/
    HunkFlags =	newflags & 0xC0000000L;		/* Flags */
    CurrHunk = NextHunk++;		/* Bump	next hunk number */
    newflags |=	CurrHunk;		/* Add hunk number */
    AddSymTab (tempop, 0L, newflags, LineCount,	16);	/* New entry */
    Sect = Sym;				/* Pointer to new entry	*/
    MakeHunk = FALSE;			/* We don't have anything yet */
    if (AnyNear	&& (CurrHunk > 1))
	Error (OpLoc, ManySect);	/* Too many hunks for small data */
    return;
}
