]> pd.if.org Git - mmurtl/commitdiff
autocommit for file dated 1995-01-31 08:28:28
authorRichard Burgess <>
Tue, 31 Jan 1995 08:28:28 +0000 (08:28 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Mon, 17 Oct 2016 14:03:48 +0000 (14:03 +0000)
dasm/source/dasm.c [new file with mode: 0644]

diff --git a/dasm/source/dasm.c b/dasm/source/dasm.c
new file mode 100644 (file)
index 0000000..98dd351
--- /dev/null
@@ -0,0 +1,3542 @@
+/*\r
+ * D-Group Assembler for MMURTL (DOS Version).\r
+ *\r
+ * Copyright 1991,1992,1993,1994 R.A. Burgess\r
+\r
+  Version 1.2 11/20/93 - major rewrite on instruction table\r
+  Version 1.3 8/28/94 - Clear macro buf on level 1 to 0 transition\r
+  Version 1.4 9/29/94 - Smashed bug in 66| prefix for string commands\r
+  Version 1.5 10/5/94 - Optimized a couple of commands and fixed\r
+                               bug in ENTER X,X instruction.  This version seems\r
+                               really stable ("yeaaaaa Right," he says...)\r
+                               Actually it is....\r
+               10/29/94 Fix problem with sign extending bytes on ADD\r
+  Version 1.6  12/31/94 - Removed temp files on succesful assemble\r
+ */\r
+\r
+#define U32 unsigned long\r
+#define S32 long\r
+#define U16 unsigned int\r
+#define S16 int\r
+#define U8 unsigned char\r
+#define S8 char\r
+\r
+\r
+#include <ctype.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <stdlib.h>\r
+#include "dasm.h"\r
+#include "runfile.h"\r
+\r
+/* variables */\r
+\r
+#define LEVELS 5\r
+U8 level = 0;                          /* current include level */\r
+U32 lineno[LEVELS];                    /* line number being parsed */\r
+U8 fContinue = 0;                      /* True if just returned from include */\r
+\r
+char srcname[LEVELS][40];      /* also active include filenames */\r
+char runname[40];\r
+char lstname[40];\r
+\r
+/* File handles for all files */\r
+\r
+FILE *src_fh[5] = {0,0,0,0,0}; /* Current source file */\r
+FILE *run_fh   = 0;            /* Current .RUN, .DLL, or .DDR (output) */\r
+FILE *ds_fh    = 0;            /* temp file for ALL DS strorage */\r
+FILE *cs_fh    = 0;            /* temp file for ALL CS code */\r
+FILE *lst_fh   = 0;            /* List file */\r
+FILE *sym_fh   = 0;            /* Symbol file for debugger */\r
+\r
+char *csname = "CS.TMP";\r
+char *dsname = "DS.TMP";\r
+\r
+U8 filetype = 1;               /* 1 = RUN, 2 = DLL, 3 = DDR */\r
+\r
+U8 fListA = 0;                 /* True if detailed list file */\r
+U8 fListE = 0;                 /* True if Error only list file */\r
+U8 fSymDump = 0;               /* True if we add symbols to the list file */\r
+U8 Column = 0;                 /* where are we on the LIST line */\r
+U16 error_count = 0;\r
+U16 warn_count = 0;\r
+\r
+\r
+ /* Max input line is 132, but 200 allows plenty for macro subs */\r
+S8 line_buf0[200];     /* Two buffers are swapped during macro substitution */\r
+S8 line_buf1[200];\r
+S8 *line_ptr;          /* pointer to next char on line */\r
+\r
+S8 list_buf[200];      /* Used to hold line string for list file */\r
+S8 fLineIn =0;         /* TRUE is list_buf has something to list */\r
+\r
+S8 TString[133];       /* all parsed tokens are placed here in text form */\r
+S16 CBString;          /* size of parsed token */\r
+S16  TSymnum;          /* Symbol table entry number, else 0 */\r
+U32  TNumber;          /* value of numeric token */\r
+S16  TInst;                    /* Instruction number, else 0 */\r
+S16  TReg;                     /* Register number, else 0 */\r
+S16  Token;                    /* Token type (also returned from parse) */\r
+S8   fPutBack = 0;  /* TRUE (non=zero) if last token was not used */\r
+\r
+S8   LTString[133];    /* Duplicates of Token storage for ReturnToken(); */\r
+S16  LCBString;\r
+S16  LTSymnum;\r
+U32  LTNumber;\r
+S16  LTInst;\r
+S16  LTReg;\r
+S16  LToken;\r
+\r
+S8 UString[31];        /* Place to save unknown labels for Forward Reference */\r
+S16 UCBString;         /* Size of Unknown label */\r
+\r
+/* The two Symbol tables have 5 entries;  Type, Size, Pointer to Name,\r
+   Segment Offset, and Line.\r
+   As each symbol is found, it's identifed by type, and the name\r
+   is moved to the packed symbol buffer. A pointer is added to the\r
+   table to point to the name in the buffer, while it's size, type,\r
+   segment offset, and line number are added to the table.\r
+   Macro names are also stored in the symbol table, but offset entry\r
+   for a macro indicates it's offset in the Macro buffer.\r
+*/\r
+\r
+/* Variables for symbol tables */\r
+\r
+/* Global Symbol Table */\r
+\r
+#define SYMSMAX 500\r
+#define SYMBUFMAX 10140        /* Avg of 10 byte per name, 700 Max */\r
+\r
+struct symtab {\r
+       U16  Type;              /* Token (e.g, CLabel) */\r
+       U16  Line;              /* Line symbol was declared on */\r
+       U8   Size;              /* Size of symbol name */\r
+       S8   *Ptr;              /* Pointer to name in packed buffer */\r
+       U32  Offs;              /* Offset in segment */\r
+       };\r
+\r
+struct symtab gst[SYMSMAX];    /* storage for the GST */\r
+\r
+/* S8  SymBuf[SYMBUFMAX];      */      /* Where names are stored. Will be Alloced */\r
+S8 *pSymBuf;                           /* ptr to allocated buffer */\r
+\r
+S8   *pSymNext;                /* ptr to next new entry in symbol buffer */\r
+S16 iSymNext = 1;      /* index to next new symbol table entry.  */\r
+                                       /* Starts at 1 - zero it reserved because */\r
+                                       /* Parse returns 0 for EOL */\r
+\r
+S8 fPublic = 0;\r
+S8 fExtern = 0;\r
+S8 fFarLabel = 0;\r
+\r
+/*********** Local Symbol Table *************/\r
+\r
+/* This is cleared after each include file from level 1 is closed */\r
+/* Clearing means we reset *pLSymNext to begining of buffer */\r
+/* and reset iLSymNext to 1. This "hides" local symbols. */\r
+\r
+#define LSYMSMAX 1800\r
+#define LSYMBUFMAX 16384                       /* Avg of 7 bytes per name */\r
+\r
+struct symtab lst[LSYMSMAX];   /* storage for the LST */\r
+\r
+/* S8  LSymBuf[LSYMBUFMAX]; */         /* Where names are stored.*/\r
+S8  *pLSymBuf;                                 /* for allocated buffer */\r
+\r
+S8   *pLSymNext;       /* ptr to next new entry in symbol buffer */\r
+S16 iLSymNext = 1;     /* index to next new symbol table entry.  */\r
+                                       /* Starts at 1 - zero it reserved because */\r
+                                       /* Parse returns 0 for EOL */\r
+\r
+/************* Forward Ref Table *********************************/\r
+/*\r
+   Labels that are encountered as forward references are\r
+   stored in this table.  When we run across a forward, we do\r
+   not know what segment they are refering to unless it is from\r
+   a jump, call, or loop instruction.  We will NOT know for many\r
+   items until they are actually declared.  After all the code\r
+   and data has been processed, we go through this table\r
+   and fix all the unknown references using the relative\r
+       The type of forward references are:\r
+\r
+               1) DSEG DWORD item refers to UNK item (?Seg MemRef)\r
+               2) CSEG DWORD item refers to UNK item (?Seg MemRef)\r
+               3) CSEG to CSEG relative 8  (Jump, Jc, or Loop)\r
+               4) CSEG to CSEG relative 32 (Jump or Call)\r
+\r
+       MOTE: If a calculation is made with the unknown reference, 0\r
+       is used in the calculation. We ALWAYS ADD the value we stored\r
+       with what is found when the reference is resolved.\r
+\r
+*/\r
+\r
+#define FREFSMAX   32768/12\r
+#define FREFTABMAX 32768\r
+#define FREFBUFMAX 16384\r
+\r
+/* Types of forward references. */\r
+\r
+#define DSEGREF   1            /* 32 bit Abs Ref in DSeg, to what is unknown! */\r
+#define CSEGREF   2            /* 32 bit Abs Ref in CSeg, to what is unknown! */\r
+#define CCR32REF  3            /* 32 bit Relative in CSeg */\r
+#define CCR8REF   4            /* 8 bit Relative in CSeg */\r
+\r
+struct forreftab {\r
+       U8   Type;      /* 1, 2, 3, or 4 */\r
+       U8   NameSz;    /* Size of ref name */\r
+       U16  Line;              /* Line reference was made on  (for error if not found) */\r
+       S8   *Ptr;              /* Pointer to name in packed buffer */\r
+       S32  Offs;              /* Offset in segment were it should go */\r
+       };\r
+\r
+struct forreftab *pfrt;        /* pointer to allocated table */\r
+\r
+S8   *pRefBuf;\r
+S8   *pRefNext;                /* ptr to next new entry in symbol buffer */\r
+S16  iRefNext = 0;     /* index to next new forward ref table entry.  */\r
+\r
+/************ External Reference table ************/\r
+\r
+/* External definitions that are encountered in a module are\r
+   first entered in the Global Symbol Table (GST) as externals\r
+   if they haven't already been defined (public) by the module\r
+   that owns them.\r
+   When a reference is made to an external, we see if the public has\r
+   already been defined. If so, we resolve it immediately. If not,\r
+   we make an entry in the External Reference Table (ERT).  The\r
+   entry has the following 4 pieces of information:\r
+     - Line where reference was made.\r
+     - Index to place holder entry in GST.\r
+        - Segment where reference was made (boolean - TRUE for code seg).\r
+        - Offset in that segment where the resolution will be made.\r
+   With this information we can reslove all the external references\r
+   before we write the code segment to the run file.\r
+*/\r
+\r
+#define EREFSMAX 400\r
+\r
+struct extreftab {\r
+       U8   Type;   /* Type of reference so we know how to apply it */\r
+       U16  iSym;       /* Index of gst entry. Hi bit seg if CSeg ref */\r
+       U32  Offs;       /* Offset in segment were ref needs 32 bit fixing */\r
+       };\r
+\r
+struct extreftab ert[FREFSMAX];\r
+\r
+S16  iERefNext = 0;    /* index to next external ref table entry.  */\r
+\r
+U16 nExtRef;\r
+\r
+/*********** Fix Up Table *********************/\r
+\r
+/* This table holds 6 types of fixups along with the offset\r
+   in the segment to be fixed up, and if applicable, an index\r
+   to the DLL public name in the GST (which should be defined\r
+   as EXTRNDLL):\r
+     - Fixup type\r
+         - Ref in CSEG to address in DSEG\r
+         - Ref in CSEG to address in CSEG\r
+         - Ref in DSEG to address in DSEG\r
+         - Ref in DSEG to address in CSEG\r
+         - CSEG DLL near 32 bit call used\r
+         - CSEG DLL near 32 bit call defined\r
+     - Offset of 32 bit reference to be resolved\r
+     - Index to DLL public name in GST (if applicable)\r
+\r
+   With this information we can supply the loader with the TAG entries\r
+   in the RUN file needed to resolve them.  Most of these entries will\r
+   be made as we parse the code, but many will also be added after\r
+   we fix the forward references because we won't know what segment\r
+   the reference is made to until then.\r
+*/\r
+\r
+#define FIXUPSMAX    32768/7\r
+#define FIXUPBUFMAX  32768\r
+\r
+struct futab {\r
+       U8   type;   /* Type of fixup C0, C1, C2, C3, C5, or C8 */\r
+       U32  Offs;       /* Offset in segment for 32 bit fixup */\r
+       U16  iSym;       /* index of DLL entry in gst, else 0 */\r
+       };\r
+\r
+struct futab *pfut;    /* pointer to allocated Fix Up Table */\r
+\r
+S16  iFUNext = 0;      /* index to next fix up table entry.  */\r
+                                       /* Starts at 0 */\r
+\r
+U16    nCDFix = 0;\r
+U16 nDDFix = 0;\r
+U16 nDCFix = 0;\r
+U16 nCCFix = 0;\r
+\r
+/********* Macro variables *******************/\r
+\r
+#define MACSMAX 200\r
+#define MACBUFMAX  3000\r
+\r
+S8   *rgMacPtr[MACSMAX];       /* pointer to simple macros */\r
+S8   *pMacBuf;\r
+S8   *pMacNext;                                /* ptr to next new entry in macro buffer */\r
+S16  iMacNext = 0;                     /* index to next new symbol entry */\r
+\r
+/* Variables for current segment address offset tracking */\r
+\r
+S8  fStart = 0;                        /* True if they gave a start address */\r
+S32 StartAddr = 0;             /* Filled in when .START is encountered */\r
+S32 oNextData = 0;             /* Tracks current DSEG offset */\r
+S32 oNextCode = 0;      /* Tracks current CSEG offset */\r
+S32 CodeOffset = 0;            /* From Virtual Command */\r
+S32 DataOffset = 0;            /* From Virtual Command */\r
+S32 *pNextAddr = 0;            /* Points to current segment offset counter */\r
+S8  fDataSeg = 0;              /* True if parsing DSEG, else parsing CSEG */\r
+S32 StackTotal = 0;            /* Total Stack Specified in Code segs */\r
+\r
+/******************************************************************\r
+   Variables for RAW operands in an instruction.\r
+   These are used when we read in and separate each part of the\r
+   operands so it can be evaluated.\r
+*/\r
+\r
+S16  rgToken[3][20]; /* Raw tokens in the operand (as many as 20) */\r
+S32  rgVal[3][20];   /* value if token is number/displacement */\r
+S16  rgTID[3][20];      /* Register ID if token is a register */\r
+S16  rgTCnt[3];                 /* total count of tokens in raw operand */\r
+\r
+/******************************************************************\r
+   These variables are filled in while parsing and evaluating\r
+   instructions that have been read in.\r
+   They have all the info needed to\r
+   encode the instruction into the object module and\r
+   produce FixUp Records if needed.\r
+*/\r
+\r
+/* These are used in the description of all OPERANDS for the current\r
+   instruction we are working on.\r
+*/\r
+S16  rgOpType[3];      /* Operand type for compare to instruction */\r
+S16  rgOpReg[3];    /* If reg only, this which one */\r
+S8   OpSize[3];     /* Operand size for first two (fByte, fWord, fFar etc.) */\r
+S8   OpSizeA;       /* Overall operand size for instruction */\r
+S8   OpPrefix;      /* Bit set for a segment prefix (fESp etc.) */\r
+S16  iInstEntry;       /* Which entry is it in rgINS */\r
+S16  CrntInst;         /* instruction we are working on        */\r
+S16  InstPfx;          /* Special Insturction prefix for crnt inst */\r
+S16  nOperands;                /* number of operands we found */\r
+S8   fForRef;       /* Crnt inst makes a Forward Reference */\r
+\r
+/* The following vars are used if we have a memory reference that is\r
+   encoded as part of the instruction.\r
+*/\r
+S8   OpMType;          /* Mem type (compared to rgM32). 0 if not mem type */\r
+S16  OpBase;        /* Base register if fBase is true */\r
+S16  OpIndx;        /* Index register if fIndx is true */\r
+S32  OpDisp;        /* Displacement if fDisp8 or fDisp32 is TRUE */\r
+S16  iMemEntry;                /* If mem operand, which entry in rgM32 */\r
+\r
+/* The following are used if we have immediate values to be encoded as\r
+part of the instruction.  Immediates can also be addresses such as\r
+those in Direct and Relative Jumps and Calls!\r
+*/\r
+S32  OpImm;         /* Immediate value if fOpImm is true */\r
+S8   fOpImm;           /* If OpImm has a value */\r
+S32  OpImm2;        /* Second Imm value for iSAD and other multi-Imm types */\r
+S8   fOpImm2;          /* If OpImm2 has a value */\r
+\r
+/* This is set for each type of fixup required after an instruction\r
+line.  Data fixups are done directly in the code that generates\r
+storage in DSeg. */\r
+\r
+U8   nFixUp;           /* Fixup number (Cx) */\r
+\r
+/*************************************************************************/\r
+\r
+/* In the final stages of building an instruction, these contain the\r
+   fragment bytes of encoded instructions (along with flags for\r
+   optional parts used).\r
+*/\r
+\r
+U8  bOpc1;             /* Zero if not used */\r
+U8  bOpc2;             /* Always used */\r
+U8  bModRM;            /* ModRM byte value if used */\r
+U8  bSIB;              /* SIB value if used */\r
+S8  fModRM;    /* True if bModRM is used */\r
+S8  fSIB;      /* True if bSIB is used */\r
+\r
+/*** These are used in the expression parser ******/\r
+\r
+U8  ExpType;           /* 0 = Forward, 1 = Local, 2 = Global, 3 = Current Addr */\r
+U8  ExpType0;\r
+S16 nExpSyms;          /* Used by the numeric expression evaluator */\r
+S16 iExpSym, iExpSym0; /* if a symbol value translates to a SYMOFF,\r
+                                          this holds the symbol table index. */\r
+S8  fOffset;           /* True if derived from an Offset */\r
+\r
+/* Variables for Storage allocation */\r
+\r
+\r
+S8  fMoreStorage = 0;   /* True when storage continues to next line */\r
+S16 StoreSize = 0;\r
+\r
+/****  Variables for building the RUN File (DLL or Device Driver) ********/\r
+\r
+/* Once we have the CS and DS tmp files run through to correct any external\r
+   variables or forward labels, we build the run file.  This is done\r
+   by building the tag records, sending them followed by the proper data\r
+   for each one.\r
+*/\r
+\r
+struct tagtype tag;\r
+\r
+\r
+/******************* END VARIABLES - BEGIN CODE ********************/\r
+\r
+/* ANSI prototypes for all functions are in DProtos.h */\r
+\r
+#include "DProtos.h"\r
+\r
+\r
+/***************************************************************/\r
+/* Write a DWord to the current segment and update the counter */\r
+/***************************************************************/\r
+\r
+void OutDWord(unsigned long Data)\r
+{\r
+unsigned char *pOut, b;\r
+int i;\r
+       pOut = &Data;\r
+       if (fDataSeg) {\r
+               for (i=0; i<4; i++) {\r
+                       b = *pOut++;\r
+                       fputc(b , ds_fh);\r
+               }\r
+           oNextData+=4;\r
+       }\r
+       else {\r
+               for (i=0; i<4; i++) {\r
+                       b = *pOut++;\r
+                       fputc(b , cs_fh);\r
+               }\r
+           oNextCode+=4;\r
+    }\r
+}\r
+\r
+/******************************************************************/\r
+/* Write a DWord to the current segment and DO NOT update counter */\r
+/******************************************************************/\r
+\r
+void OutDWordCS(unsigned long Data)\r
+{\r
+unsigned char *pOut, b;\r
+int i;\r
+       pOut = &Data;\r
+       for (i=0; i<4; i++) {\r
+               b = *pOut++;\r
+               fputc(b , cs_fh);\r
+       }\r
+}\r
+\r
+/******************************************************************/\r
+/* Write a DWord to the current segment and DO NOT update counter */\r
+/******************************************************************/\r
+\r
+void OutDWordDS(unsigned long Data)\r
+{\r
+unsigned char *pOut, b;\r
+int i;\r
+       pOut = &Data;\r
+       for (i=0; i<4; i++) {\r
+               b = *pOut++;\r
+               fputc(b , ds_fh);\r
+       }\r
+}\r
+\r
+/**************************************************************/\r
+/* Write a Word to the current segment and update the counter */\r
+/**************************************************************/\r
+\r
+void OutWord(unsigned int Data)\r
+{\r
+unsigned char *pOut, b;\r
+int i;\r
+       pOut = &Data;\r
+       b = *pOut++;\r
+       if (fDataSeg) {\r
+               fputc(b , ds_fh);\r
+               b = *pOut;\r
+               fputc(b , ds_fh);\r
+           oNextData+=2;\r
+       }\r
+       else {\r
+               fputc(b , cs_fh);\r
+               b = *pOut;\r
+               fputc(b , cs_fh);\r
+           oNextCode+=2;\r
+       }\r
+}\r
+\r
+/**************************************************************/\r
+/* Write a BYTE to the current segment and update the counter */\r
+/**************************************************************/\r
+\r
+void OutByte(unsigned char Data)\r
+{\r
+       if (fDataSeg) {\r
+               fputc(Data , ds_fh);\r
+           oNextData++;\r
+       }\r
+       else {\r
+               fputc(Data , cs_fh);\r
+           oNextCode++;\r
+       }\r
+}\r
+\r
+/*****************************************************************/\r
+/* Write a BYTE to the current segment and DO NOT update counter */\r
+/*****************************************************************/\r
+\r
+void OutByteCS(unsigned long Data)\r
+{\r
+char b;\r
+       b = Data;\r
+       fputc(b , cs_fh);\r
+}\r
+\r
+/* All the "grunt work" functions are in dasmq.c */\r
+\r
+#include "DASMq.c"\r
+\r
+/*********************************************\r
+This searches the Reference table for the name\r
+described by pb, cb. It only compares items that\r
+are the same length (cb == TRefSize[x]).\r
+It returns the number or 0 if not found.\r
+**********************************************/\r
+\r
+S16 findref(S8 *pb, S16 cb)  /* pointer to, and size of string */\r
+{\r
+S16 i;\r
+S8   name[132];\r
+\r
+strncpy(name, pb, cb);         /* move name local */\r
+name[cb] = 0;                                  /* null terminate */\r
+\r
+i = iRefNext;\r
+while (i>0) {                          /* backwards through forward ref table */\r
+       i--;\r
+                               /* Only compare if same size  */\r
+       if (pfrt[i].NameSz == cb) {\r
+               if (strncmp(name, pfrt[i].Ptr, cb) == 0) return(i);\r
+       }\r
+}\r
+return(0);\r
+}\r
+\r
+\r
+/*****************************************************\r
+   Evaluates only single token operands and sets up\r
+   globals so EvalOper can finish the job.\r
+   The actual value or register is left in\r
+   rgToken[op][0], and the type is placed\r
+   in rgTempl[op][0] for a memory operand.\r
+*****************************************************/\r
+S16 EvalOper1(S16 op)\r
+{\r
+S16 i;\r
+U16 symtype;\r
+\r
+       /* Set up symtype up front in case it's needed */\r
+\r
+       if (ExpType == 1)                               /* Local */\r
+               symtype = lst[iExpSym].Type;\r
+       else if (ExpType == 2) {                /* global */\r
+               if (gst[iExpSym].Type & tEXTRN)\r
+                       nExtRef = iExpSym;\r
+               symtype = gst[iExpSym].Type;\r
+       }\r
+       else symtype = 0;\r
+\r
+       switch (rgToken[op][0]) {\r
+               case REGIST:\r
+                       if (is_r32(rgTID[op][0]))  rgOpType[op] = r32;\r
+                       else if (is_r16(rgTID[op][0])) rgOpType[op] = r16;\r
+                       else if (is_r8(rgTID[op][0]))   rgOpType[op] = r8;\r
+                       else if (is_rCRG(rgTID[op][0])) rgOpType[op] = rCRG;\r
+                       else if (is_rDRG(rgTID[op][0])) rgOpType[op] = rDRG;\r
+                       else if (is_rTRG(rgTID[op][0])) rgOpType[op] = rTRG;\r
+                       else if (is_rSEG(rgTID[op][0])) rgOpType[op] = rSEG;\r
+                       rgOpReg[op] = rgTID[op][0];\r
+                       break;\r
+               case NUMBER:\r
+                       if ((rgVal[op][0] >= -128) && (rgVal[op][0] <= 127))\r
+                 rgOpType[op] = val8;\r
+                       else if ((rgVal[op][0] >= -32768) && (rgVal[op][0] <= 32767))\r
+                 rgOpType[op] = val16;\r
+                       else rgOpType[op] = val32;\r
+                       if (!fOpImm) {\r
+                   OpImm = rgVal[op][0];\r
+                   fOpImm = 1;\r
+                   }\r
+                       else {\r
+                   OpImm2 = rgVal[op][0];\r
+                   fOpImm2 = 1;\r
+                   }\r
+                       break;\r
+               case NUMOFF:            /* OFFSET var name. IMMEDIATE VALUE. */\r
+                       OpSize[op] = fDWord;\r
+                       rgOpType[op] = val32;\r
+            OpImm = rgVal[op][0];\r
+            fOpImm = 1;\r
+                       if (symtype & CLABEL)\r
+                               nFixUp = CCFIXTAG;\r
+                       else if (symtype & DLABEL)\r
+                               nFixUp = CDFIXTAG;\r
+                       if (!symtype)\r
+                               fForRef = 1;\r
+                       break;\r
+               case SYMOFF:   /* Check for ALL jump, call & Loop instructions */\r
+\r
+                       if (ExpType == 1)                               /* Local */\r
+                               symtype = lst[iExpSym].Type;\r
+                       else if (ExpType == 2) {                /* global */\r
+                               if (gst[iExpSym].Type & tEXTRN)\r
+                                       nExtRef = iExpSym;\r
+                               symtype = gst[iExpSym].Type;\r
+                       }\r
+                       else                                                    /* Unknown - Forward */\r
+                               symtype = 0;\r
+\r
+                       if (((CrntInst >= xJA) &&\r
+                            (CrntInst <= xJZ)) ||\r
+                 (CrntInst == xCALL)) {\r
+\r
+                               if (OpSize[op] & fShort)\r
+                                       rgOpType[op]  = rel8;\r
+                               else\r
+                                       rgOpType[op] = relW;\r
+                       OpImm = rgVal[op][0];\r
+                       fOpImm = 1;\r
+                       }\r
+\r
+                       else if ((CrntInst >= xLOOP) && (CrntInst <= xLOOPZ)) {\r
+                                       rgOpType[op] = rel8;\r
+                               OpImm = rgVal[op][0];\r
+                               fOpImm = 1;\r
+                       }\r
+                       else {\r
+                               rgOpType[op]  = mem;\r
+                   OpMType |= fDisp32;\r
+                   OpDisp = rgVal[op][0];\r
+                               if (symtype & CLABEL)\r
+                                       nFixUp = CCFIXTAG;\r
+                               else if (symtype & DLABEL)\r
+                                       nFixUp = CDFIXTAG;\r
+                       }\r
+                       if (!symtype)\r
+                               fForRef = 1;\r
+                       break;\r
+               default:\r
+                  line_error(15);\r
+                  return(0);\r
+       } /* switch */\r
+\r
+/*  print_Oper(op); Testing only... */\r
+\r
+return(1);\r
+}\r
+\r
+/***********  EvalOper *******************************\r
+   Evaluates the array of reserved words, registers,\r
+   numbers, etc. that should make up an operand.\r
+   For single token operands it's easy! BUT for memory\r
+   operands it gets a little more complicated.\r
+   For memory operands we look for key sequences of\r
+   tokens that make up the "effective address" as\r
+   described in the Intel documentation, then see if\r
+   we have all the pieces to make one (EA).\r
+   This returns 1 if we can classify the operand and\r
+   there were no errors.  The type of operand we find\r
+   (e.g., r8, r16, r32, val8, val16, val32, mem,\r
+   relW, etc.) is placed in rgOpType[op].\r
+   This calls EvalOper1() to handle single token\r
+   oprerands and evaluates multiple token operands\r
+   internally. The reason we break single token operands\r
+   out in a separate call is for speed and clarity\r
+   of the code.\r
+   Special handling is required for for JMP, Jcond,\r
+   and CALL instructions because they may be using\r
+   a forward reference not yet defined.  This is the\r
+   only case where such a reference is allowed.\r
+*****************************************************/\r
+\r
+S16 EvalOper(S16 op)\r
+{\r
+S16 i;\r
+S8   fDone, fOpenSQ, fError;\r
+U16 symtype;\r
+/*\r
+These are the Raw operands:\r
+S16  rgToken[3][20];  Raw tokens in the operand\r
+S32  rgVal[3][20];    value if token is number/displacement\r
+S16  rgTID[3][20];       Register ID if token is a register\r
+S16  rgTCnt[3];                  total count of tokens in raw operand\r
+\r
+ This is what is produced:\r
+*/\r
+\r
+rgOpType[op] = 0;      /* int - Operand type for compare to instruction */\r
+rgOpReg[op] = 0;    /* If reg only, this which one */\r
+\r
+i = 0;          /* index into raw tokens */\r
+fError = 0;  /* set true for invalid operand error */\r
+fDone = 0;   /* Set when no more tokens are expected in operand */\r
+fOpenSQ = 0; /* keep track of [] */\r
+\r
+/* flags for segment instruction prefix - NONE unless otherwise set */\r
+/* If it's a single token operand, take the fast, easy way out! */\r
+\r
+if (rgTCnt[op] == 1) {\r
+       return (EvalOper1(op));\r
+}\r
+\r
+else {         /* multiple tokens in operand */\r
+\r
+       /* with more than 1 token it is usually a memory reference\r
+          but not always.  We will default to mem and change those we\r
+          find that aren't.  */\r
+\r
+       rgOpType[op] = mem;\r
+\r
+       /* Segment prefix?  If so, set flag and eat 2 tokens */\r
+\r
+       if ((rgToken[op][0]==REGIST) && (is_rSEG(rgTID[op][0]))) {\r
+               if (rgToken[op][1] == COLON) {\r
+                       switch (rgToken[op][0]) {\r
+                               case rDS: OpPrefix |= fDSp; break;\r
+                               case rES: OpPrefix |= fESp; break;\r
+                               case rSS: OpPrefix |= fSSp; break;\r
+                               case rFS: OpPrefix |= fFSp; break;\r
+                               case rGS: OpPrefix |= fGSp; break;\r
+                               case rCS: OpPrefix |= fCSp; break;\r
+                               default:;\r
+                       }\r
+                       i += 2;         /* skip rSEG and colon */\r
+               }\r
+               else {\r
+                  line_error(16);\r
+                  return(0);\r
+          }\r
+       }\r
+\r
+/* Loop through the raw tokens looking for Base Reg, Index Reg,\r
+   Scale value, or displacement and setting varaibles as needed.\r
+*/\r
+\r
+       while ((i < rgTCnt[op]) &&\r
+                 (!fError) &&\r
+                 (!fDone)) {\r
+               switch (rgToken[op][i]) {\r
+\r
+               case REGIST:\r
+                       if (is_r32(rgTID[op][i])) {  /* check for Indx & Base Reg */\r
+                if (rgToken[op][i+1] == STAR) {                /* Index w/Scale */\r
+                                       if (!(OpMType & fIndx))  {      /* still OK */\r
+                        OpMType |= fIndx;\r
+                        OpIndx = rgTID[op][i];\r
+                                               if (rgToken[op][i+2] == NUMBER) {\r
+                                                       switch (rgVal[op][i+2]) {\r
+                                                       case 2: OpMType |= fScale2; break;\r
+                                                       case 4: OpMType |= fScale4; break;\r
+                                                       case 8: OpMType |= fScale8; break;\r
+                                                       default:\r
+                                                               line_error(17);\r
+                                                               fError = 1;\r
+                                                       }\r
+                                               }\r
+                                               else {\r
+                                                       line_error(18);\r
+                                                       fError = 1;\r
+                                               }\r
+                                       }\r
+                                       else {\r
+                                               line_error(19);\r
+                                               fError = 1;\r
+                                       }\r
+                                       i+=3;   /* get past *NUMBER */\r
+                }\r
+                /* Must be base, unless fBase true, then try Index */\r
+                else {\r
+                                       if (!(OpMType & fBase)) { /* Base for sure */\r
+                        OpMType |= fBase;\r
+                        OpBase = rgTID[op][i];\r
+                        i++;\r
+                                       }\r
+                                       else {  /* try Index */\r
+                                               if (!(OpMType & fIndx)) { /* It's free, use it */\r
+                               OpMType |= fIndx;\r
+                           OpIndx = rgTID[op][i];\r
+                               i++;\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+                       else { /* must be 32 bit general purpose register */\r
+                               line_error(20);\r
+                               fError = 1;\r
+                       }\r
+                       break;\r
+\r
+\r
+               case SYMOFF:  /* One symbol was used by itself or in an expression */\r
+                       if (ExpType == 1)                               /* Local */\r
+                               symtype = lst[iExpSym].Type;\r
+                       else if (ExpType == 2) {                /* global */\r
+                               if (gst[iExpSym].Type & tEXTRN)\r
+                                       nExtRef = iExpSym;\r
+                               symtype = gst[iExpSym].Type;\r
+                       }\r
+                       else                                                    /* Unknown - Forward */\r
+                               symtype = 0;\r
+\r
+                       if (OpMType & (fDisp32|fDisp8)) {   /* Already a disp! */\r
+                               line_error(21);\r
+                               fError = 1;\r
+                               }\r
+\r
+                       /* Check for conditional jumps. */\r
+\r
+                       else if ((CrntInst >= xJA) &&\r
+                                    (CrntInst <= xJZ) &&\r
+                                    (CrntInst != xJMP) &&\r
+                                    (!(fOpenSQ)))\r
+                       {\r
+                                       if (OpSize[op] & fShort)\r
+                                               rgOpType[op] = rel8;\r
+                                       else rgOpType[op] = relW;\r
+                                       if (fOpImm) {\r
+                                       OpImm2 = rgVal[op][i];\r
+                                       fOpImm2 = 1;\r
+                               }\r
+                                       else {\r
+                                       OpImm = rgVal[op][i];\r
+                                       fOpImm = 1;\r
+                                       }\r
+                                       if (!symtype)\r
+                                               fForRef = 1;\r
+                       }\r
+\r
+                               /* Check for JMP */\r
+\r
+                       else if (CrntInst == xJMP)  /* &&  (!(fOpenSQ))) */\r
+                       {\r
+                               if ((OpSize[op] & fFar) || (symtype & tFAR)) {\r
+                                       rgOpType[op] = iSAD;\r
+                                       if (fOpImm) {\r
+                                       OpImm2 = rgVal[op][i];\r
+                                       fOpImm2 = 1;\r
+                               }\r
+                                       else {\r
+                                       OpImm = rgVal[op][i];\r
+                                       fOpImm = 1;\r
+                                       }\r
+                               }\r
+                               else if (OpSize[op] & fShort) {\r
+                                       rgOpType[op] = rel8;\r
+                               OpImm = rgVal[op][i];\r
+                               fOpImm = 1;\r
+                                       if (!symtype)\r
+                                               fForRef = 1;\r
+                               }\r
+                               else if (OpSize[op] & fFWord) {\r
+                                       rgOpType[op]  = memF;  /* memF = 32 disp which has 16:32 */\r
+                           OpMType |= fDisp32;\r
+                           OpDisp = rgVal[op][i];\r
+                                       if (symtype & CLABEL)\r
+                                               nFixUp = CCFIXTAG;\r
+                                       else if (symtype & DLABEL)\r
+                                               nFixUp = CDFIXTAG;\r
+                                       if (!symtype)\r
+                                               fForRef = 1;\r
+                               }\r
+                               else {\r
+                                       rgOpType[op] = relW;\r
+                                   OpImm = rgVal[op][i];\r
+                                   fOpImm = 1;\r
+                                       if (!symtype)\r
+                                               fForRef = 1;\r
+                               }\r
+                       }\r
+\r
+                               /* Check for CALL */\r
+\r
+                       else if ((CrntInst == xCALL) && (!(fOpenSQ)))\r
+                       {\r
+                               if ((OpSize[op] & fFar) || (symtype & tFAR)) {\r
+                                       rgOpType[op] = iSAD;\r
+                                       if (fOpImm) {\r
+                                       OpImm2 = rgVal[op][i];\r
+                                       fOpImm2 = 1;\r
+                                   }\r
+                                       else {\r
+                                       OpImm = rgVal[op][i];\r
+                                       fOpImm = 1;\r
+                                       }\r
+                               }\r
+                               else if (OpSize[op] & fFWord) {\r
+                                       rgOpType[op]  = memF;  /* memF = 32 disp which has 16:32 */\r
+                           OpMType |= fDisp32;\r
+                           OpDisp = rgVal[op][i];\r
+                                       if (symtype & CLABEL)\r
+                                               nFixUp = CCFIXTAG;\r
+                                       else if (symtype & DLABEL)\r
+                                               nFixUp = CDFIXTAG;\r
+                                       if (!symtype)\r
+                                               fForRef = 1;\r
+                               }\r
+                               else {          /* Relative call */\r
+                                       rgOpType[op] = relW;\r
+                                       if (!symtype)\r
+                                               fForRef = 1;\r
+                               }\r
+                       }\r
+\r
+                               /* Check for SGDT SIDT */\r
+\r
+                       else if ((CrntInst == xSGDT) || (CrntInst == xSIDT))\r
+                       {\r
+                               if (OpSize[op] & fFWord) {\r
+                                       rgOpType[op]  = memF;  /* memF = 32 disp which has 16:32 */\r
+                           OpMType |= fDisp32;\r
+                           OpDisp = rgVal[op][i];\r
+                                       if (symtype & CLABEL)\r
+                                               nFixUp = CCFIXTAG;\r
+                                       else if (symtype & DLABEL)\r
+                                               nFixUp = CDFIXTAG;\r
+                                       if (!symtype)\r
+                                               fForRef = 1;\r
+                               }\r
+                       }\r
+\r
+                         /* Check for Loop */\r
+\r
+                       else if ((CrntInst >= xLOOP) && (CrntInst <= xLOOPZ))\r
+                       {\r
+                                       rgOpType[op] = rel8;\r
+                                   OpImm = rgVal[op][0];\r
+                                   fOpImm = 1;\r
+                                       if (!symtype)\r
+                                               fForRef = 1;\r
+                       }\r
+                       else {\r
+                                   OpDisp = rgVal[op][i];\r
+                                       OpMType |= fDisp32;\r
+                                       if (symtype & CLABEL)\r
+                                               nFixUp = CCFIXTAG;\r
+                                       else if (symtype & DLABEL)\r
+                                               nFixUp = CDFIXTAG;\r
+                                       if (!symtype)\r
+                                               fForRef = 1;\r
+                       }\r
+                       i++;\r
+                       break;\r
+\r
+               case NUMBER:  /* can be 8 or 32 bit disp, or hard address */\r
+               OpDisp = rgVal[op][i];\r
+                       if ((rgVal[op][i] >= -128) && (rgVal[op][i] <= 127))\r
+                               OpMType |= fDisp8;\r
+                       else\r
+                               OpMType |= fDisp32;\r
+                       i++;\r
+                       break;\r
+\r
+               case OPENSQR:\r
+                       if (fOpenSQ) {\r
+                               line_error(23);\r
+                               fError = 1;\r
+                               }\r
+                       else fOpenSQ = 1;\r
+                       i++;\r
+                       break;\r
+               case CLOSSQR:\r
+                       if (!fOpenSQ) {\r
+                               line_error(24);\r
+                               fError = 1;\r
+                               }\r
+                       else fOpenSQ = 0;\r
+                       i++;\r
+                       break;\r
+               case COLON:             /*  for far addresses */\r
+                       i++;\r
+                       break;\r
+               case PLUS:\r
+                       i++;\r
+                       break;\r
+           case rBYTE:\r
+               if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {\r
+                               OpSize[op] |= fByte;\r
+                               i+=2;\r
+                               }\r
+                       else {\r
+                               line_error(25);\r
+                               fError = 1;\r
+                               }\r
+                       break;\r
+           case rWORD:\r
+               if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {\r
+                               OpSize[op] |= fWord;\r
+                               i+=2;\r
+                               }\r
+                       else {\r
+                               line_error(25);\r
+                               fError = 1;\r
+                               }\r
+                       break;\r
+           case rDWORD:\r
+               if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {\r
+                               OpSize[op] |= fDWord;\r
+                               i+=2;\r
+                               }\r
+                       else {\r
+                               line_error(25);\r
+                               fError = 1;\r
+                               }\r
+                       break;\r
+           case rFWORD:\r
+               if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {\r
+                               OpSize[op] |= fFWord;\r
+                               i+=2;\r
+                               }\r
+                       else {\r
+                               line_error(25);\r
+                               fError = 1;\r
+                               }\r
+                       break;\r
+               case rNEAR:\r
+               if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {\r
+                               OpSize[op] |= fNear;\r
+                               i+=2;\r
+                               }\r
+                       else {\r
+                               line_error(25);\r
+                               fError = 1;\r
+                               }\r
+                       break;\r
+               case rFAR:\r
+               if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {\r
+                               OpSize[op] |= fFar;\r
+                               i+=2;\r
+                               }\r
+                       else {\r
+                               line_error(25);\r
+                               fError = 1;\r
+                               }\r
+                       break;\r
+               case rSHORT:\r
+               if (!OpSize[op]) {\r
+                               OpSize[op] |= fShort;\r
+                               i++;\r
+                               }\r
+                       else {\r
+                               line_error(25);\r
+                               fError = 1;\r
+                               }\r
+                       break;\r
+               default: {\r
+                       line_error(32);\r
+                       fprintf(lst_fh, "  %d  ", rgToken[op][i]);  /* TESTING */\r
+                       i++;\r
+                       }\r
+\r
+               } /* switch */\r
+       } /* while */\r
+}\r
+if (fError) return(0);\r
+if ((fDone) && (i< rgTCnt[op])) {\r
+       line_error(33);\r
+       return(0);\r
+       }\r
+\r
+return(1);\r
+\r
+}\r
+\r
+/********************************************\r
+  Adds ALL forward reference to the Ref table.\r
+  This holds references to all foward addresses\r
+  (unknown) in the current module.\r
+  This stores all Refs UPPER case.\r
+*********************************************/\r
+void ForRef(U8 type, S32 Offset)\r
+{\r
+S16 i;\r
+\r
+if (pRefNext >= (pRefBuf + FREFBUFMAX))\r
+       fatal_error("Forward Reference buffer overflow...");\r
+if (iRefNext >= FREFSMAX)\r
+       fatal_error("Forward Reference table overflow...");\r
+\r
+/* Make a forward reference table entry */\r
+\r
+strncpy(pRefNext, UString, UCBString);\r
+pfrt[iRefNext].NameSz = UCBString;     /* size of name */\r
+pfrt[iRefNext].Ptr = pRefNext;\r
+pfrt[iRefNext].Line = lineno[level];   /* for error reporting */\r
+pfrt[iRefNext].Type = type;                    /* type of ref */\r
+\r
+\r
+pfrt[iRefNext].Offs = Offset;          /* Offset to correction in CS or DS */\r
+\r
+/* update for next symbol */\r
+\r
+pRefNext += UCBString;\r
+iRefNext++;\r
+\r
+}\r
+\r
+/********************************************\r
+  Adds fixup table entries to be placed in\r
+  the run file.         This includes DLL entries.\r
+*********************************************/\r
+\r
+void FixUp(U8 typef, S32 Offset, U16 iSymbol)\r
+{\r
+\r
+if (typef == CDFIXTAG)\r
+       nCDFix++;\r
+else if (typef == DDFIXTAG)\r
+       nDDFix++;\r
+else if (typef == DCFIXTAG)\r
+       nDCFix++;\r
+else if (typef == CCFIXTAG)\r
+       nCCFix++;\r
+\r
+\r
+if (iFUNext >= FIXUPSMAX)\r
+       fatal_error("Fixup Table overflow...");\r
+pfut[iFUNext].type = typef;\r
+pfut[iFUNext].Offs = Offset;\r
+pfut[iFUNext].iSym = iSymbol;  /* global symbol entry for DLL */\r
+\r
+iFUNext++;\r
+\r
+}\r
+\r
+/********************************************\r
+  Adds External Reference to table.\r
+  This DOES NOT includes DLL Refs.\r
+  ETypes are the same as ForRef types\r
+  except there and no 8 bit externals.\r
+*********************************************/\r
+\r
+void ExtRef(U8 EType, U16 iSymbol)\r
+{\r
+\r
+if (iERefNext >= EREFSMAX)\r
+       fatal_error("External Reference Table overflow...");\r
+\r
+if (fDataSeg)\r
+       ert[iERefNext].Offs = oNextData;\r
+else {\r
+       ert[iERefNext].Offs = oNextCode;\r
+       }\r
+ert[iERefNext].iSym = iSymbol;  /* global symbol entry for external */\r
+ert[iERefNext].Type = EType;  /* global symbol entry for external */\r
+\r
+iERefNext++;\r
+}\r
+\r
+/*****************************************************\r
+   Reads in all of the reserved words, numbers, math\r
+   operators, etc. that make up one operand.  They are\r
+   read into one of 3 2D arrays as indicated by "op".\r
+   Integer rgTCnt[op] is number if items.  A special\r
+   case for jump and call instructions is tested if\r
+   we end up with an Unknown Symbol as and operand.\r
+   We Error out if we have an UNKSYM without a\r
+   jump or call.\r
+*****************************************************/\r
+\r
+S16 GetOper(S16 op)\r
+{\r
+S16 i, T;\r
+\r
+i = 0;\r
+while (1) {\r
+       T = Parse();\r
+       switch (T) {\r
+         case ZERO:\r
+                   rgTCnt[op] = i;\r
+                       if (i) return(1);\r
+                       else return(0);\r
+         case REGIST:\r
+               rgTID[op][i] = TReg;\r
+               rgToken[op][i] = T;\r
+               break;\r
+         case NUMBER:  /* check for special case of REG*2,*4,*8  */\r
+               if ((i > 1) &&\r
+                       (rgToken[op][i-1] == STAR) &&\r
+                       (rgToken[op][i-2] == REGIST)) {\r
+                               rgVal[op][i] = TNumber;\r
+                               rgToken[op][i] = T;\r
+                               break;  /* only break here if we find special case */\r
+                       }                       /* Else fall thru to Expression */\r
+         case LSYMBOL:\r
+         case SYMBOL:\r
+         case DOLLAR:          /* These should all evaluate to a number!! */\r
+         case OPENRND:\r
+         case MINUS:\r
+         case UNKSYM:\r
+         case rOFFSET:\r
+               if (Expression()) {\r
+                       rgVal[op][i] = TNumber;\r
+                       rgToken[op][i] = Token;         /* Token instead of T (From Expr)*/\r
+                       }\r
+               else {\r
+                       line_error(35);\r
+                       return(0);\r
+                       }\r
+\r
+               break;\r
+         case COMMA:\r
+                       if (!i) {\r
+                               line_error(36);\r
+                               return(0);\r
+                       }\r
+                   rgTCnt[op] = i;\r
+                       ReturnToken();\r
+                       return(1);\r
+         case OPENSQR:\r
+         case CLOSSQR:\r
+         case STAR:\r
+         case PLUS:\r
+         case SLASH:\r
+         case SEMI:\r
+         case COLON:\r
+         case rFAR:\r
+         case rBYTE:\r
+         case rWORD:\r
+         case rDWORD:\r
+         case rFWORD:\r
+         case rPTR:\r
+         case rSHORT:\r
+                       rgToken[op][i] = T;\r
+                       break;\r
+         default:\r
+                       line_error(38);\r
+                       return(0);\r
+       }\r
+ i++;\r
+} /* while */\r
+}\r
+\r
+/********************************************\r
+ This finds the first matching entry in rgINS\r
+ by first matching the instruction number,\r
+ then matching operands.  The table is indexed\r
+ with an array providing the first entry for\r
+ the instruction. This speed things up a bit.\r
+*********************************************/\r
+\r
+S16 INSEntry(S16 InsNum, S16 nOpers)\r
+{\r
+S16 i;\r
+\r
+       i = rgInsLookUp[InsNum];\r
+       while (i <= nrgINS) {\r
+\r
+               /* instruction entries of the same type\r
+               are all kept together. This is an early out.\r
+               */\r
+\r
+               if (rgINS[i][0] != InsNum)\r
+                 return(0);    /* couldn't find a match at all... */\r
+\r
+               /* See if all the operators match by calling is_Comp for each.\r
+               */\r
+\r
+               if ((is_Comp(i,0)) &&\r
+                   (is_Comp(i,1)) &&\r
+                   (is_Comp(i,2)))\r
+\r
+                       return(i);              /* yes, they all match! */\r
+\r
+               i++;    /* No, goto next entry */\r
+       }\r
+}\r
+\r
+\r
+/********************************************\r
+  EmitInst spits out the instruction bytes that\r
+  were encoded into variables by EncodeInst.\r
+  This handles output to the code segment\r
+  file as well as the text to the list file.\r
+  It updates the code segment address and\r
+  also adds fixup records as they are needed.\r
+\r
+The instruction  (up to 16 bytes) is ordered\r
+as follows:\r
+  Instruction Prefix   0 or 1 byte\r
+  Address Size Prefix  0 or 1 byte\r
+  Operand Prefix       0 or 1 byte\r
+  Segment Override     0 or 1 bytes\r
+  Opcode               1 or 2 bytes\r
+  MODR/M               0 or 1 bytes\r
+  SIB                  0 or 1 bytes\r
+  Displacement         0,1,2 or 4 bytes\r
+  Immediate            0,1,2, or 4 bytes\r
+**********************************************/\r
+\r
+void EmitInst(void)\r
+{\r
+U8   oppfx;\r
+S8   sbyte;\r
+S16  sword;\r
+U16  i;                /* used local to each section if needed */\r
+\r
+\r
+\r
+       /*\r
+    Instruction prefix: 0 or 1 byte (Lock, Rep, etc.)\r
+       */\r
+\r
+       if (InstPfx) {\r
+               if (InstPfx==xLOCK) {\r
+                       if (fListA) {\r
+                               Column += 2;\r
+                               put_hexb(0x0F, lst_fh);\r
+                               }\r
+                       OutByte(0xF0);\r
+                       }\r
+               else if ((InstPfx==xREPNE) || (InstPfx==xREPNZ)) {\r
+                       if (fListA) {\r
+                               Column += 2;\r
+                               put_hexb(0xF2, lst_fh);\r
+                               }\r
+                       OutByte(0xf2);\r
+                       }\r
+               else {  /* Must be REP... */\r
+                       if (fListA) {\r
+                               Column += 2;\r
+                               put_hexb(0xF3, lst_fh);\r
+                               }\r
+                       OutByte(0xf3);\r
+                       }\r
+               if (fListA)\r
+                       Column += fprintf(lst_fh, "| ");\r
+       }\r
+\r
+/*\r
+   Skip Address Size prefix: (67h)  cause we aren't\r
+   doing USE16, nor do we support 16 bit addressing modes!\r
+*/\r
+\r
+/* Operand Size prefix: 0 or 1 (66h)  */\r
+\r
+       if (OpSizeA & fWord) {\r
+               if (fListA) {\r
+                       Column += 2;\r
+                       put_hexb(0x66, lst_fh);\r
+                       Column += fprintf(lst_fh, "| ");\r
+                       }\r
+               OutByte(0x66);\r
+               }\r
+\r
+/* Segment Override prefix */\r
+\r
+       switch (OpPrefix) {\r
+               case fDSp: oppfx = 0x3e; break;\r
+               case fESp: oppfx = 0x26; break;\r
+               case fSSp: oppfx = 0x36; break;\r
+               case fFSp: oppfx = 0x64; break;\r
+               case fGSp: oppfx = 0x65; break;\r
+               case fCSp: oppfx = 0x2e; break;\r
+               default: oppfx = 0;\r
+       }\r
+       if (oppfx) {\r
+               if (fListA) {\r
+                       Column += 2;\r
+                       put_hexb(oppfx, lst_fh);\r
+                       Column += fprintf(lst_fh, "| ");\r
+                       }\r
+                       OutByte(oppfx);\r
+               }\r
+\r
+/*   OpCode byte 1 (optional)\r
+     bOpc1 was setup in        EncodeInst (either 0 or 0Fh)\r
+*/\r
+\r
+       if (bOpc1) {\r
+               if (fListA) {\r
+                       Column += 2;\r
+                       put_hexb(bOpc1, lst_fh);\r
+                       Column += fprintf(lst_fh, " ");\r
+                       }\r
+                       OutByte(bOpc1);\r
+               }\r
+\r
+/*   OpCode byte 2 (always sent) */\r
+\r
+       if (fListA) {\r
+                       Column += 2;\r
+                       put_hexb(bOpc2, lst_fh);\r
+                       Column += fprintf(lst_fh, " ");\r
+               }\r
+\r
+       OutByte(bOpc2);\r
+\r
+/*  ModR/M  (optional)  */\r
+\r
+       if (fModRM) {\r
+               if (fListA) {\r
+                       Column += 2;\r
+                       put_hexb(bModRM, lst_fh);\r
+                       Column += fprintf(lst_fh, " ");\r
+               }\r
+               OutByte(bModRM);\r
+       }\r
+\r
+/*  SIB  (optional) */\r
+\r
+       if (fSIB) {\r
+               if (fListA) {\r
+                       Column += 2;\r
+                       put_hexb(bSIB, lst_fh);\r
+                       Column += fprintf(lst_fh, " ");\r
+               }\r
+               OutByte(bSIB);\r
+       }\r
+\r
+/*\r
+   Disp: 0, 1, 2 or 4\r
+   A Displacement is a memory reference (an offset in a segment)\r
+   that is encoded as part of the instruction. The value to encode\r
+   is placed in OpDisp when the instruction is parsed and\r
+   evaluated.\r
+*/\r
+\r
+       if (OpMType & fDisp32) {\r
+\r
+               if (fListA) {\r
+                       Column += 8;\r
+                       put_hexd(OpDisp, lst_fh);\r
+                       if ((nExtRef) || (fForRef))\r
+                               Column += fprintf(lst_fh, "r ");\r
+                       else\r
+                               Column += fprintf(lst_fh, "  ");\r
+               }\r
+               if (nExtRef)\r
+                       ExtRef(CSEGREF, nExtRef);\r
+               else if (fForRef)\r
+                       ForRef(CSEGREF, oNextCode);\r
+               else if (nFixUp)\r
+                       FixUp(nFixUp, oNextCode, 0); /* Code ref to data */\r
+               OutDWord(OpDisp);\r
+       }\r
+\r
+       if (OpMType & fDisp8) {\r
+\r
+               if (fListA) {\r
+                       sbyte = OpDisp;\r
+                       Column += 2;\r
+                       put_hexb(sbyte, lst_fh);\r
+                       Column += fprintf(lst_fh, "  ");\r
+               }\r
+               OutByte(OpDisp);\r
+       }\r
+\r
+/*\r
+   Immediate: 0, 1, 2 or 4\r
+   The type of instruction operands tell us if we must encode\r
+   immediate values as part of the instruction.  All instructions\r
+   have only one immediate value except ENTER. We make a check here\r
+   to determine if it is this instruction.\r
+\r
+     imm8  = Immediate Byte in OpImm\r
+     imm16 = immediate 16 bit value in OpImm\r
+     immX  = immediate value matching OpSize in OpImm\r
+     rel8  = immediate Byte calculated from a label\r
+     relW  = immediate Word (16 or 32) calculated from a label\r
+     iSAD  = immediate DWORD:WORD from Far Pointer (OpImm & OpImm2)\r
+\r
+     immv1 is not encoded (implied by instruction)\r
+     immv3 is not encoded (also implied - INT 03 - Debug)\r
+   */\r
+       if (fOpImm) \r
+       {\r
+               if ((rgINS[iInstEntry][1] == immX) ||\r
+                   (rgINS[iInstEntry][2] == immX) ||\r
+            (rgINS[iInstEntry][3] == immX))\r
+        {\r
+                       if (OpSizeA & fByte)\r
+                       {\r
+                               if (fListA)\r
+                               {\r
+                                       sbyte = OpImm;\r
+                                       Column += 2;\r
+                                       put_hexb(sbyte, lst_fh);\r
+                                       Column += fprintf(lst_fh, "  ");\r
+                               }\r
+                               OutByte(OpImm);\r
+                       }\r
+                       else if (OpSizeA & fWord)\r
+                       {\r
+                               if (fListA) \r
+                               {\r
+                                       sword = OpImm;\r
+                                       Column += 4;\r
+                                       put_hexw(sword, lst_fh);\r
+                                       Column += fprintf(lst_fh, "  ");\r
+                               }\r
+                               OutWord(OpImm);\r
+                       }\r
+                       else {                                  /* MUST be a DWord */\r
+                               if (fListA) {\r
+                                       Column += 8;\r
+                                       put_hexd(OpImm, lst_fh);\r
+                                       if (nFixUp)\r
+                                               Column += fprintf(lst_fh, "r ");\r
+                                       else\r
+                                               Column += fprintf(lst_fh, "  ");\r
+                               }\r
+                               if (nExtRef)\r
+                                       ExtRef(CSEGREF, nExtRef);\r
+                               else if (fForRef)\r
+                                       ForRef(CSEGREF, oNextCode);\r
+                               else if (nFixUp)\r
+                                       FixUp(nFixUp, oNextCode, 0); /* Code ref to data */\r
+                               OutDWord(OpImm);\r
+                       }\r
+               }\r
+\r
+               if ((rgINS[iInstEntry][1] == imm16) ||\r
+                   (rgINS[iInstEntry][2] == imm16) ||\r
+            (rgINS[iInstEntry][3] == imm16))   {\r
+                       if (fListA) {\r
+                               Column += 4;\r
+                               sword = OpImm;\r
+                               put_hexw(sword, lst_fh);\r
+                               Column += fprintf(lst_fh, "  ");\r
+                               }\r
+                       OutWord(OpImm);\r
+               }\r
+               else if ((rgINS[iInstEntry][1] == imm8) ||\r
+                        (rgINS[iInstEntry][2] == imm8) ||\r
+                        (rgINS[iInstEntry][3] == imm8) ||\r
+                        (rgINS[iInstEntry][1] == ims8) ||\r
+                        (rgINS[iInstEntry][2] == ims8) ||\r
+                 (rgINS[iInstEntry][3] == ims8))\r
+        {\r
+                       if (fListA) {\r
+                               Column += 2;\r
+                               sbyte = OpImm;\r
+                               put_hexb(sbyte, lst_fh);\r
+                               Column += fprintf(lst_fh, "  ");\r
+                               }\r
+                       OutByte(OpImm);\r
+               }\r
+\r
+               /* Special check for Enter. It is only instructon with 2 Imms!*/\r
+\r
+               if (rgINS[iInstEntry][0] == xENTER)\r
+        {\r
+                       if (fListA) {\r
+                               Column += 2;\r
+                               sbyte = OpImm2;\r
+                               put_hexb(sbyte, lst_fh);\r
+                               Column += fprintf(lst_fh, "  ");\r
+                               }\r
+                       OutByte(OpImm2);\r
+               }\r
+\r
+\r
+               /* With relative values for immediates, OpImm comes in as\r
+                 the address of the target jump or call. We must take\r
+                  the current code offset (of the next instruction) and\r
+                  subtract it from the target (OpImm) to get the relative\r
+                  jump value. If it is an UNKSYM we will put the value\r
+                  of the target into the FRT to hold it and\r
+                  do the math on the second pass of the machine code.\r
+                  Math Example:\r
+\r
+                       oCode  = 100  (next instruction)\r
+                       Target =  50\r
+                       Jump = -50  (Target-Current)\r
+\r
+                       oCode  = 100  (next instruction)\r
+                       Target = 150\r
+                       Jump = 50  (Target-Current)\r
+\r
+                       Relative immediate values found in the GST as EXTERN\r
+                       require an ERT entry so they can be fixed up when\r
+                       the final code module is written to the run file.\r
+\r
+                       Relative immediate values found in the GST as PUBLICS\r
+                       can be fixed up NOW.\r
+\r
+                       Relative immediate values NOT found are assumed local\r
+                       and an entry is made in the FRT so they can be fixed\r
+                       up when this code module is written to the main\r
+                       temp code module.\r
+                  */\r
+\r
+               if (rgINS[iInstEntry][1] == relW) {\r
+                       if (nExtRef) {                                          /* list external */\r
+                               OpImm = 0;\r
+                               ExtRef(CCR32REF, nExtRef);\r
+                       }\r
+                       else if (fForRef) {                                     /* list Forward Relative */\r
+                               OpImm = 0;\r
+                               ForRef(CCR32REF, oNextCode);\r
+                       }\r
+                       else {                                                          /* Fix known ref */\r
+                               OpImm = OpImm - (oNextCode + 4);\r
+                       }\r
+\r
+                       if (fListA) {\r
+                               Column += 8;\r
+                               put_hexd(OpImm, lst_fh);\r
+                               if ((!fForRef) && (!nExtRef))\r
+                                       Column += fprintf(lst_fh, "  ");\r
+                               else\r
+                                       Column += fprintf(lst_fh, "R ");\r
+                       }\r
+                       OutDWord(OpImm);\r
+               }\r
+\r
+               if (rgINS[iInstEntry][1] == rel8) {\r
+                       if (!fForRef) {                                 /* Fix KNOWN Relative */\r
+                               OpImm = OpImm - (oNextCode + 1);\r
+                               if ((OpImm > 127) || (OpImm < -127))\r
+                                       line_error(39);\r
+                       }\r
+                       else {                                                  /* Else List Unknown */\r
+                               ForRef(CCR8REF, oNextCode);\r
+                               OpImm = 0;\r
+                               }\r
+\r
+                       if (fListA) {\r
+                               Column += 2;\r
+                               sbyte = OpImm;\r
+                               put_hexb(sbyte, lst_fh);\r
+                               if ((!fForRef) && (!nExtRef))\r
+                                       Column += fprintf(lst_fh, "  ");\r
+                               else\r
+                                       Column += fprintf(lst_fh, "R ");\r
+                       }\r
+                       OutByte(OpImm);\r
+               }\r
+\r
+               if (rgINS[iInstEntry][1] == iSAD) {\r
+                       if (fListA) {\r
+                               Column += 4;\r
+                               sword = OpImm;\r
+                               put_hexw(sword, lst_fh);\r
+                               Column += fprintf(lst_fh, ":");\r
+                               Column += 4;\r
+                               put_hexd(OpImm2, lst_fh);\r
+                               Column += fprintf(lst_fh, "  ");\r
+                       }\r
+                       OutWord(OpImm);\r
+                       OutDWord(OpImm2);\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/********************************************\r
+  This encodes the instructions into bytes\r
+  and calls EmitInst() to put them into the\r
+  current code segment.        The instruction can\r
+  be as long as 16 bytes if all options are used.\r
+  The order of the bytes and their possible\r
+  sizes are as follows:\r
+   Inst Prefix: 0 or 1 (Lock, Rep, etc.)\r
+   Address Size prefix: 0 or 1 (67h) - We don't use this\r
+   Operand Size prefix: 0 or 1 (66h)\r
+   Segment Override: 0 or 1\r
+   OpCode: 1 or 2\r
+   ModR/M: 0 or 1\r
+   SIB: 0 or 1\r
+   Disp: 0, 1, 2 or 4\r
+   Immediate: 0, 1, 2 or 4\r
+   This routine follows the guidance to build\r
+   instructions given in the rgINS table\r
+   (as bit flags). It calls    EmitInst() to\r
+   emit the code, list-file information and\r
+   fixups to the FUT.\r
+   **********************************************/\r
+void EncodeInst(void)\r
+{\r
+S8   fError;\r
+S16 i;\r
+U8 bTmp;\r
+\r
+/*\r
+U8 bOpc1;              Zero if not used   THESE ARE GLOBAL...\r
+U8 bOpc2;              Always used\r
+U8 bModRM;\r
+U8 bSIB;\r
+S8 fModRM;         Is bModRM set/used?\r
+S8 fSIB;               Is bSIB set/used?\r
+*/\r
+\r
+fModRM = 0;            /* not used by default */\r
+fSIB   = 0;\r
+\r
+\r
+/* SKIP the Address Size Prefix for now because we don't do 16 Bit\r
+   Effective addresses\r
+*/\r
+\r
+\r
+/*\r
+   Now we will build the instruction in (up to) 4 temporary bytes.\r
+   We do it in temporary byte vars so we can see if an Operand Prefix\r
+   and a possible address fixup record is required before we\r
+   actually put it into the code segment.\r
+*/\r
+\r
+/*\r
+  The WORD forms of string instructions require us\r
+  to force a WORD size. We set this in the instruction table\r
+  as qUW in byte [4],\r
+*/\r
+\r
+if (rgINS[iInstEntry][4] & qUW)\r
+  OpSizeA |= fWord;\r
+\r
+/* Put in the first byte of Opcode from table (if required). qP0F is\r
+   set in rgINS[iInstEntry][4] if a 0Fh prefix is required for this inst.\r
+   A 0 in bObc1 indicates that this byte is NOT to be used.\r
+*/\r
+\r
+if (rgINS[iInstEntry][4] & qP0F)\r
+    bOpc1 = 0x0F;\r
+else bOpc1 = 0;\r
+\r
+/* Get the Opcode from table into bOpc2 */\r
+\r
+bOpc2 = rgINS[iInstEntry][5];\r
+\r
+/* The flags zMR1, zMR2, zMOP, zAR1, and zAR2 all indicate that the\r
+   ModRM is needed. The following set of if-else statements checks these\r
+   flags and sets REG/OP field of MOD/RM byte if required.\r
+   OpSize should already be set. We also complete\r
+   the instruction encoding (with the exception of any immediate values)\r
+   if the other operand is a register.\r
+*/\r
+\r
+if (rgINS[iInstEntry][7] & zMR1) {\r
+       bModRM = rgINS[iInstEntry][6];\r
+       fModRM = 1;\r
+       if (is_Reg(rgOpType[0]))\r
+           EncodeRegBits(rgOpReg[0], &bModRM, 3);\r
+       if (is_Reg(rgOpType[1])) {\r
+           EncodeRegBits(rgOpReg[1], &bModRM, 0);\r
+           bModRM |= 0xC0;     /* indictes REG in RM field */\r
+               }\r
+       }\r
+else if (rgINS[iInstEntry][7] & zMR2) {\r
+       bModRM = rgINS[iInstEntry][6];\r
+       fModRM = 1;\r
+       if (is_Reg(rgOpType[1]))\r
+           EncodeRegBits(rgOpReg[1], &bModRM, 3);\r
+       if (is_Reg(rgOpType[0])) {\r
+           EncodeRegBits(rgOpReg[0], &bModRM, 0);\r
+           bModRM |= 0xC0;     /* indictes REG in RM field */\r
+               }\r
+       }\r
+else if (rgINS[iInstEntry][7] & zMOP) {\r
+       bModRM = rgINS[iInstEntry][6];\r
+       fModRM = 1;\r
+       if (is_Reg(rgOpType[0])) {\r
+           EncodeRegBits(rgOpReg[0], &bModRM, 0);\r
+           bModRM |= 0xC0;     /* indictes REG in RM field */\r
+               }\r
+       }\r
+else if (rgINS[iInstEntry][7] & zAR1) {\r
+       bTmp = 0;\r
+    EncodeRegBits(rgOpReg[0], &bTmp, 0);\r
+       bOpc2 += bTmp;\r
+       }\r
+else if (rgINS[iInstEntry][7] & zAR2) {\r
+       bTmp = 0;\r
+    EncodeRegBits(rgOpReg[1], &bTmp, 0);\r
+       bOpc2 += bTmp;\r
+       }\r
+else if ((rgINS[iInstEntry][7] & zRG1) && (rgOpType[0] != mem)) {\r
+       bModRM = rgINS[iInstEntry][6];\r
+       fModRM = 1;\r
+    EncodeRegBits(rgOpReg[0], &bModRM, 3);\r
+    bModRM |= 0xC0;    /* indictes REG in RM field */\r
+       }\r
+\r
+\r
+       /* OpSize may not be required for many instructions, but we know\r
+          for a fact it MUST be known for memory operands!\r
+       */\r
+\r
+       if ((rgOpType[0] == mem) ||\r
+               (rgOpType[1] == mem) ||\r
+               (rgOpType[0] == memF)) {\r
+                       if  (!(OpSizeA & (fByte|fWord|fDWord|fFWord))) {\r
+                               line_error(40);\r
+                               return;\r
+                               }\r
+       }\r
+\r
+       /*\r
+          If zORD, see if we have word or dword register and OR the Opcode\r
+          (Opc2) with 01 if so.\r
+       */\r
+\r
+       if (rgINS[iInstEntry][7] & zORD) {\r
+               if (OpSizeA & (fWord | fDWord))\r
+               bOpc2 |= 0x01;\r
+               }\r
+\r
+       /* Perform the following additonal steps if we have a memory reference\r
+          as determined by iMemEntry.\r
+       */\r
+\r
+       fSIB = 0;\r
+       if (iMemEntry) {\r
+\r
+       /* If SIB is needed (as determined from OpMType), get it and also\r
+        OR ModRM by required value from rgM32 table\r
+       */\r
+\r
+               bModRM |= rgM32[iMemEntry][2];  /* Use ModRM 'OR' value from table */\r
+               if (rgM32[iMemEntry][1]) {              /* is there an SIB byte? */\r
+                       bModRM &= 0x38;                                 /* 00111000 leaves Reg bit on */\r
+                       bModRM |= rgM32[iMemEntry][2];  /* 'OR' ModRM with table value */\r
+                       bSIB = rgM32[iMemEntry][3];\r
+                       fSIB = 1;\r
+               }\r
+\r
+\r
+               /* At this point we have our Opcode, ModRM, and SIB (if required).\r
+                  The MOD and SS bit are already filled in from the table.\r
+                  This means we just stick the register values or bits for Disp etc\r
+                  in the correct positions to complete it.\r
+                  If we didn't have an SIB, we either have a single displacement,\r
+                  a base or both.\r
+               */\r
+\r
+               if (!fSIB) {            /* only a base, disp, or both */\r
+                       if (OpMType & fBase)\r
+                           EncodeRegBits(OpBase, &bModRM, 0);\r
+                       else\r
+                           bModRM |= 0x05;             /* only a disp32 */\r
+                       }\r
+               else {\r
+                       if (OpMType & fBase)\r
+                           EncodeRegBits(OpBase, &bSIB, 0);\r
+                       else bModRM |= 0x20;                            /* else set [--][--] bits */\r
+                       if (OpMType & fIndx)\r
+                           EncodeRegBits(OpIndx, &bSIB, 3);\r
+                       }\r
+       }\r
+\r
+       EmitInst();\r
+\r
+}\r
+\r
+\r
+/********************************************\r
+  When the dispatcher detects an Instruction\r
+  it calls this code to read in (via parse)\r
+  the parametrs for the instruction and to\r
+  put together the opcodes.  First we loop thru\r
+  and get up to 3 operands, then we evaluate\r
+  them (classify by type). Next we look up\r
+  the instruction and find a match for the\r
+  operand types they have specified, and\r
+  finally, we encode the instruction into the\r
+  code segment updating the code segment offset\r
+  pointer.\r
+*********************************************/\r
+void Instruction(void)\r
+{\r
+S16 i;\r
+S8   fError;\r
+S8   OpSizeTmp;\r
+\r
+fError = 0;\r
+if (fDataSeg) {\r
+       line_error(41);\r
+       return;\r
+       }\r
+\r
+/* If the instruction is a prefix instruction, save it\r
+   and Parse again to get the real instruction */\r
+\r
+if ((TInst==xREP) || (TInst==xREPE) || (TInst==xREPZ) ||\r
+    (TInst==xREPNE) || (TInst==xREPNZ) || (TInst==xLOCK)) {\r
+    InstPfx = TInst;\r
+       i = Parse();\r
+       if (i != INSTRU) {\r
+               line_error(42);\r
+               return;\r
+       }\r
+} else InstPfx = 0;\r
+\r
+/* RESET all global instruction variables */\r
+\r
+CrntInst = TInst;      /* Save the instruction */\r
+nOperands = 0;         /* none yet... */\r
+rgOpType[0] = 0;\r
+rgOpType[1] = 0;\r
+rgOpType[2] = 0;\r
+OpMType = 0;       /* char - memory type (a byte to compare to rgM32) */\r
+OpSize[0] = 0;         /* char - Mem op size (fByte, fWord, fDword, fFword) */\r
+OpSize[1] = 0;         /* char - Mem op size (fByte, fWord, fDword, fFword) */\r
+OpSizeA = 0;           /* char - Mem op size (fByte, fWord, fDword, fFword) */\r
+OpSizeTmp = 0;         /* char - Mem op size (fByte, fWord, fDword, fFword) */\r
+OpPrefix = 0;          /* For Segment register prefix flags */\r
+OpDisp = 0;         /* long - Displacement if fDisp8 or fDisp32 is TRUE */\r
+OpBase = 0;         /* int - Base register if fBase is true */\r
+OpIndx = 0;         /* int - Index register if fIndx is true */\r
+fOpImm = 0;                    /* No Immediate value yet */\r
+OpImm = 0;                     /* Default to 0 */\r
+fOpImm2 = 0;           /* No second Immediate value yet */\r
+OpImm2 = 0;                    /* Default to 0 */\r
+nFixUp = 0;                    /* Fixup type if needed, else 0 */\r
+nExtRef = 0;           /* GST entry if external ref was made */\r
+fForRef = 0;           /* No Forward Ref in crnt inst yet */\r
+ExpType = 0;           /* Type of symbol used in instruction */\r
+ExpType0 = 0;          /* Type of symbol used in instruction */\r
+iExpSym = 0;           /* Index into symtab for symbol if used */\r
+iExpSym0 = 0;          /* Index into symtab for symbol if used */\r
+\r
+if (GetOper(0)) {\r
+       nOperands++;\r
+       ExpType0 = ExpType;\r
+       iExpSym0 = iExpSym;\r
+       if ((Parse()== COMMA)) {\r
+               if (GetOper(1)) {\r
+                       nOperands++;\r
+                       if ((Parse()== COMMA)) {\r
+                               if (GetOper(2)) {\r
+                                       nOperands++;\r
+                                       if (Parse()) {\r
+                                               line_error(33);\r
+                                               return;\r
+                                       }\r
+                               }\r
+                   }\r
+               }\r
+       }\r
+}\r
+\r
+/*\r
+At this point we have the instruction operands stored in\r
+tokenized form in arrays.  We now call EvalOper() which evaluates\r
+the operands and fills in several variables that will assist in\r
+building the instruction. EvalOper() returns 1 if it was a valid\r
+operand, else 0.\r
+*/\r
+\r
+if (nOperands) {                                                               /* at least one */\r
+       if (EvalOper(0)) {\r
+               if (nOperands > 1) {                                    /* a second operand */\r
+                       if (EvalOper(1)) {\r
+                               if (nOperands > 2) {                    /* a third??? - could be... */\r
+                                       if (!(EvalOper(2)))\r
+                                               fError = 1;\r
+                               }\r
+                       }\r
+                       else fError = 1;\r
+           }\r
+       }\r
+       else fError = 1;\r
+}\r
+\r
+if (fError) return;\r
+\r
+/*\r
+   We must check to see what the word size of the instruction is\r
+   by looking at register sizes if any are included in the instruction.\r
+   If there are memory references or immediates involved, OpSizeA\r
+   MUST be set properly else it's an error!     When there is a symbol involved\r
+   such as a move to a memory variable, we check the variable size and set\r
+   the OpSize to the variable size. If it's still not set, the line will\r
+   error out when we try to build the instruction because the caller\r
+   should have explicitly set the size (e.g., DWORD PTR ...).\r
+\r
+   If a register is one of the operands in a memory transfer\r
+   (e.g., MOV [mem], EAX) then the move obviously defaults to the size\r
+   of the register (no ifs, ands, or buts).\r
+\r
+   If there is no reg involved, we then look at 'OpSize[i]'\r
+   which may have been set by the size operators (e.g., DWORD PTR).\r
+   If it's zero we look at iExpSym which was set if there was a single\r
+   symbol involved in the memory reference. If there was, then we use it.\r
+   If it is blank, we error out cause we don't know what size memory\r
+   access we are doing!\r
+   This is done for each operand then the two are compared. If one is\r
+   zero we use the other, if both have something but are different\r
+   we error out!\r
+\r
+*/\r
+       /* Find the first operand size */\r
+\r
+       /* First, let's look to see if they forced it! */\r
+\r
+       if  (OpSize[0] & (fByte|fWord|fDWord|fFWord))\r
+\r
+       { /* do nothing */ }\r
+\r
+       /* If they didn't force it, we'll look for the register size! */\r
+\r
+    else if (rgOpType[0] == r32) OpSize[0] |= fDWord;\r
+    else if (rgOpType[0] == r16) OpSize[0] |= fWord;\r
+    else if (rgOpType[0] == rSEG) OpSize[0] |= fWord;\r
+    else if (rgOpType[0] == r8) OpSize[0] |= fByte;\r
+\r
+               /* Still nothing, so let's at symbols.  */\r
+\r
+       else if (ExpType0 == 1)\r
+       {       /* Local symbol */\r
+               if (lst[iExpSym0].Type & sBYTE) OpSize[0] |= fByte;\r
+               else if (lst[iExpSym0].Type & sWORD) OpSize[0]  |= fWord;\r
+               else if (lst[iExpSym0].Type & sDWORD) OpSize[0] |= fDWord;\r
+               else if (lst[iExpSym0].Type & sFWORD) OpSize[0] |= fFWord;\r
+       }\r
+    else if (ExpType0 == 2)\r
+       {   /* Global Symbol */\r
+               if (gst[iExpSym0].Type & sBYTE) OpSize[0] |= fByte;\r
+               else if (gst[iExpSym0].Type & sWORD) OpSize[0] |= fWord;\r
+               else if (gst[iExpSym0].Type & sDWORD) OpSize[0] |= fDWord;\r
+               else if (gst[iExpSym0].Type & sFWORD) OpSize[0] |= fFWord;\r
+       }\r
+       else if (ExpType0 == 3)\r
+               OpSize[0] |= fDWord;            /* $ defaults to DWord */\r
+\r
+\r
+       /* Find the second operand size. Check "forced fit" first */\r
+\r
+       if  (OpSize[1] & (fByte|fWord|fDWord|fFWord))\r
+       { /* do nothing */ }\r
+\r
+    else if (rgOpType[1] == r32) OpSize[1] |= fDWord;\r
+    else if (rgOpType[1] == r16) OpSize[1] |= fWord;\r
+    else if (rgOpType[1] == rSEG) OpSize[1] |= fWord;\r
+    else if (rgOpType[1] == r8) OpSize[1] |= fByte;\r
+\r
+               /* No registers, so let's look to see if they forced it! */\r
+\r
+               /* Still nothing, so let's at symbols.  */\r
+\r
+       else if (ExpType == 1)\r
+       {       /* Local symbol */\r
+               if (lst[iExpSym].Type & sBYTE) OpSize[1] |= fByte;\r
+               else if (lst[iExpSym].Type & sWORD) OpSize[1]  |= fWord;\r
+               else if (lst[iExpSym].Type & sDWORD) OpSize[1] |= fDWord;\r
+               else if (lst[iExpSym].Type & sFWORD) OpSize[1] |= fFWord;\r
+       }\r
+    else if (ExpType == 2)\r
+       {   /* Global Symbol */\r
+               if (gst[iExpSym].Type & sBYTE) OpSize[1] |= fByte;\r
+               else if (gst[iExpSym].Type & sWORD) OpSize[1] |= fWord;\r
+               else if (gst[iExpSym].Type & sDWORD) OpSize[1] |= fDWord;\r
+               else if (gst[iExpSym].Type & sFWORD) OpSize[1] |= fFWord;\r
+       }\r
+       else if (ExpType == 3)\r
+               OpSize[1] |= fDWord;            /* $ defaults to DWord */\r
+\r
+    /* Special cases for operand size matching. */\r
+\r
+       if (CrntInst == xOUT)\r
+               OpSize[0] = OpSize[1];\r
+\r
+\r
+/*\r
+   Now that have the operands, and we know the TYPE of data (fByte etc.)\r
+   we call INSEntry to find the matching\r
+   entry in the array that describes each instruction. If we don't\r
+   find one that matches we error out telling them they have bad\r
+   operands.\r
+*/\r
+\r
+/* find first matching entry in rgINS */\r
+\r
+    iInstEntry = INSEntry(CrntInst, nOperands);\r
+\r
+    if (!iInstEntry) {\r
+       line_error(44);\r
+       return;\r
+    }\r
+\r
+    /* Now we make sure that we have set all operand sizes\r
+       and check for special cases as defined in rgINS.\r
+       */\r
+\r
+       if (rgINS[iInstEntry][7] & zSIZ)\r
+        OpSize[1] = OpSize[0];\r
+\r
+    if (!OpSize[1])\r
+        OpSize[1] = OpSize[0];\r
+\r
+    if (!OpSize[0])\r
+        OpSize[0] = OpSize[1];\r
+\r
+    /* Give them an error if operand sizes don't match */\r
+\r
+    if (nOperands > 1)\r
+        if (OpSize[0] != OpSize[1]) {\r
+           line_error(43);\r
+              return;\r
+          }\r
+\r
+       OpSizeA = OpSize[0];   /* Set primary operand size */\r
+\r
+/* If either the first or second operand was memory, we have to find\r
+   which entry in rgM32 it matches before we can encode it. If none\r
+   matches it is an invalid memory operand.  If neither is a mem operand\r
+   we set iMemEntry to zero.  There is the special case of moffs type\r
+   which is a short form of displacmement when moving data to and from thew\r
+   accumulator (e.g., MOV EAX, VAR1).  We check for this and skip the\r
+   mem check if this is the instruction type we are on.\r
+*/\r
+\r
+       if ((rgINS[iInstEntry][1] == moff) || (rgINS[iInstEntry][2] == moff))\r
+               iMemEntry = 0;\r
+       else if ((rgOpType[0]==mem) ||\r
+                        (rgOpType[1]==mem) ||\r
+                        (rgOpType[0]==memF))\r
+       {\r
+\r
+               for (i=1; i<nrgM32; i++) {\r
+                       if (OpMType == rgM32[i][0]) break;\r
+               }\r
+\r
+               /* if i is off the end of the array we\r
+                  didn't find an entry that matched\r
+               */\r
+\r
+               if (i==nrgM32) {\r
+                       line_error(45);\r
+                       return;\r
+               }\r
+                       else iMemEntry = i;\r
+       }\r
+       else iMemEntry = 0;\r
+\r
+/*\r
+ At this point we should have all information we need to actually\r
+ encode the instruction (unless it's a forward ref). So we call EncodeInst.\r
+*/\r
+\r
+EncodeInst();\r
+\r
+\r
+}\r
+\r
+\r
+/********************************************\r
+   Create Storage in current segment. At this\r
+   point we should see a storage statement as\r
+   the current token followed by a number (or\r
+   string if DB). If string (DB) we insert\r
+   single byte values (one per char) into the\r
+   segment.\r
+*********************************************/\r
+void Storage(void)\r
+{\r
+S32 TSave, NSave, nDUP;\r
+S16 i, j, sword;\r
+S8   fColon, fExpectColon, fComma, fDUP;\r
+U16 symtype;\r
+\r
+fDUP = 0;\r
+nDUP = 1;              /* default duplicate value */\r
+fComma = 0;\r
+fColon = 0;\r
+fExpectColon = 0;\r
+\r
+if (!fMoreStorage) {           /* is it a continuation of previous line? */\r
+       switch(Token) {                 /* parse returns Token */\r
+               case rDB:\r
+                       StoreSize = 1;\r
+               break;\r
+           case rDW:\r
+               StoreSize = 2;\r
+               break;\r
+           case rDD:\r
+               StoreSize = 4;\r
+               break;\r
+               case rDF:\r
+               StoreSize = 6;\r
+               break;\r
+               default:;\r
+       }\r
+}\r
+\r
+/* Now we loop thru looking for strings and numbers taking into account\r
+   the special case of DF which should be DWORD:WORD, and OFFSET\r
+   which will be a DWORD.\r
+*/\r
+\r
+while (1) {\r
+       if (fMoreStorage) {\r
+               i = Token;\r
+               fMoreStorage = 0;\r
+       }\r
+       else i = Parse();\r
+\r
+       switch(i) {\r
+               case STRING:\r
+                       fComma=0;\r
+                       if (StoreSize==1) {\r
+                               for(j=0; j<CBString; j++) {\r
+                                       if (fListA) {\r
+                                               put_hexb(TString[j], lst_fh);\r
+                                               Column += 2;\r
+                                               Column += fprintf(lst_fh, "  ");\r
+                                               if (Column > 51) {\r
+                                                       fprintf(lst_fh, "\r\n                ");\r
+                                                       Column=16;\r
+                                               }\r
+                                       }\r
+                                       OutByte(TString[j]);\r
+                               }\r
+                       }\r
+                       else {\r
+                               line_error(46);\r
+                               return;\r
+                       }\r
+                       break;\r
+               case rOFFSET:\r
+                       if (StoreSize != 4) {\r
+                               line_error(50);\r
+                               return;\r
+                       }\r
+                       /* fall thru to evaluate & store value */\r
+               case NUMBER:\r
+               case DOLLAR:    /* These should all evaluate to a number. */\r
+               case OPENRND:   /* If it's SYMOFF, we do a fixup or Forward Ref */\r
+               case MINUS:\r
+               case SYMBOL:\r
+               case LSYMBOL:\r
+               case UNKSYM:\r
+                       fComma=0;\r
+                       if (!(Expression()))    /* 0 means error was emmited. */\r
+                               return;\r
+\r
+                       symtype = 0;            /* default to no symbol type */\r
+                       nExtRef = 0;            /* default to no external ref */\r
+\r
+                       if ((Token==SYMOFF) || (Token==NUMOFF))\r
+                       {\r
+                               if (ExpType == 1)                               /* Local */\r
+                                       symtype = lst[iExpSym].Type;\r
+                               else if (ExpType == 2) {                /* global */\r
+                                       symtype = gst[iExpSym].Type;\r
+                                       if (gst[iExpSym].Type & tEXTRN)\r
+                                               nExtRef = iExpSym;\r
+                               }\r
+                       }\r
+\r
+                       if (!fDUP) {\r
+                               NSave = TNumber;\r
+                               TSave = Token;\r
+                               if (Parse() == rDUP)\r
+                               {\r
+                                       nDUP = NSave;\r
+                                       fDUP = 1;\r
+                    Parse();\r
+                    if (Token == OPENRND) {\r
+                                               if (!(Expression()))    /* 0 means error was emitted.*/\r
+                                                       return;\r
+                                       }\r
+                                       else\r
+                                               line_error(47);\r
+                                       /* TNumber now has (VALUE) from DUP */\r
+                               }\r
+                               else {\r
+                                       ReturnToken();\r
+                                       TNumber = NSave;\r
+                                       Token = TSave;\r
+                               }\r
+                       }\r
+\r
+                       if (StoreSize==6)\r
+                       {\r
+                               if (fColon) {\r
+                                       fColon=0;               /* reset it */\r
+                                       if (fListA) {\r
+                                               sword = TNumber;\r
+                                               Column += 4;\r
+                                               put_hexw(sword, lst_fh);\r
+                                               Column += fprintf(lst_fh, " ");\r
+                                               }\r
+                                       OutWord(TNumber);\r
+                               }\r
+                               else {\r
+                                       fExpectColon = 1;\r
+                                       if (fListA) {\r
+                                               Column += 8;\r
+                                               put_hexd(TNumber, lst_fh);\r
+                                               Column += fprintf(lst_fh, " ");\r
+                                               }\r
+                                       OutDWord(TNumber);\r
+                               }\r
+                       }\r
+                       else if (StoreSize==4) {\r
+                               if (fDUP)\r
+                               {\r
+                                       if (fListA) {\r
+                                         if ((Token == SYMOFF) || (Token == NUMOFF))\r
+                                           Column += fprintf(lst_fh, "%08lX * (%08lXr)",nDUP,TNumber);\r
+                                         else\r
+                                           Column += fprintf(lst_fh, "%08lX * (%08lX)",nDUP,TNumber);\r
+                                       }\r
+                                       while (nDUP--)\r
+                                       {\r
+                                               if ((Token==SYMOFF) || (Token==NUMOFF))\r
+                                               {\r
+                                                       if (fDataSeg) {         /* Data Seg */\r
+                                                               if (nExtRef)\r
+                                                                       ExtRef(DSEGREF, iExpSym);\r
+                                                               else if (!symtype)\r
+                                                                       ForRef(DSEGREF, oNextData);\r
+                                                               else if (symtype & CLABEL)\r
+                                                                       FixUp(DCFIXTAG, oNextData, 0);\r
+                                                               else if (symtype & DLABEL)\r
+                                                                       FixUp(DDFIXTAG, oNextData, 0);\r
+                                                       }\r
+                                                       else {                          /* Code Seg */\r
+                                                               if (nExtRef)\r
+                                                                       ExtRef(CSEGREF, iExpSym);\r
+                                                               if (!symtype)\r
+                                                                       ForRef(CSEGREF, oNextCode);\r
+                                                               else if (symtype & CLABEL)\r
+                                                                       FixUp(CCFIXTAG, oNextCode, 0);\r
+                                                               else if (symtype & DLABEL)\r
+                                                                       FixUp(CDFIXTAG, oNextCode, 0);\r
+                                                       }\r
+                                               }\r
+                                               OutDWord(TNumber);\r
+                                   }\r
+                               }\r
+                               else {\r
+                                       if (fListA)\r
+                                       {\r
+                                         if ((Token == SYMOFF) || (Token == NUMOFF))\r
+                                           Column += fprintf(lst_fh, " %08lXr", TNumber);\r
+                                         else\r
+                                           Column += fprintf(lst_fh, " %08lX", TNumber);\r
+                                       }\r
+\r
+                                       /* Fixup & Forref here! */\r
+                                       if ((Token==SYMOFF) || (Token==NUMOFF))\r
+                                       {\r
+                                         if (fDataSeg)\r
+                                         {                                     /* Data Seg */\r
+                                               if (nExtRef)\r
+                                                       ExtRef(DSEGREF, iExpSym);\r
+                                               else if (!symtype)\r
+                                                       ForRef(DSEGREF, oNextData);\r
+                                               else if (symtype & CLABEL)\r
+                                                       FixUp(DCFIXTAG, oNextData, 0);\r
+                                               else if (symtype & DLABEL)\r
+                                                       FixUp(DDFIXTAG, oNextData, 0);\r
+                                         }\r
+                                         else\r
+                                         {                                     /* Code Seg */\r
+                                               if (nExtRef)\r
+                                                       ExtRef(CSEGREF, iExpSym);\r
+                                               else if (!symtype)\r
+                                                       ForRef(CSEGREF, oNextCode);\r
+                                               else if (symtype & CLABEL)\r
+                                                       FixUp(CCFIXTAG, oNextCode, 0);\r
+                                               else if (symtype & DLABEL)\r
+                                                       FixUp(CDFIXTAG, oNextCode, 0);\r
+                                         }\r
+                                       }\r
+                                       OutDWord(TNumber);\r
+                               }\r
+                       }\r
+                       else if (StoreSize==2) {\r
+                               if (fDUP) {\r
+                                       if (fListA)\r
+                                         Column += fprintf(lst_fh, "%08lX * (%04lX) ",nDUP,TNumber);\r
+                                       while (nDUP--)\r
+                                               OutWord(TNumber);\r
+                                       }\r
+                               else {\r
+                                       if (fListA)\r
+                                               Column += fprintf(lst_fh, "%04lX ", TNumber);\r
+                                       OutWord(TNumber);\r
+                                       }\r
+                       }\r
+                       else {\r
+                               if (fDUP) {\r
+                                       if (fListA)\r
+                                         Column += fprintf(lst_fh, "%08lX * (%02lX) ",nDUP,TNumber);\r
+                                       while (nDUP--)\r
+                                               OutByte(TNumber);\r
+                                       }\r
+                               else {\r
+                                       if (fListA)\r
+                                         Column += fprintf(lst_fh, "%02lX ", TNumber);\r
+                                       OutByte(TNumber);\r
+                                       }\r
+                       }\r
+                       break;\r
+               case COMMA:     /* Just eat the comma */\r
+                       if (fComma) {\r
+                               line_error(48);\r
+                               return;\r
+                       }\r
+                       fComma = 1;\r
+                       break;\r
+               case COLON:\r
+                       fComma=0;\r
+                       if ((StoreSize == 6) && (fExpectColon)) {\r
+                               fColon = 1;\r
+                               fExpectColon = 0;\r
+                       }\r
+                       else {\r
+                               line_error(49);\r
+                               return;\r
+                       }\r
+                       break;\r
+               case ZERO:\r
+                       if (fComma)     fMoreStorage = 1;\r
+                       return;\r
+               default: {\r
+                       line_error(51);\r
+                       fMoreStorage = 0;\r
+                       return;\r
+                       }\r
+       }\r
+}\r
+}\r
+\r
+/********************************************\r
+  Add new GLOBAL symbol to table (TString).\r
+  Then parse again to hand off to\r
+  proper function. This stores all\r
+  Symbols UPPER case.\r
+*********************************************/\r
+void NewSymbol()\r
+{\r
+S16 i;\r
+S8   fColon, fStorage;\r
+\r
+       if ((pSymNext + CBString) >= (pSymBuf + SYMBUFMAX))\r
+               fatal_error("Symbol buffer overflow...");\r
+       if (iSymNext >= SYMSMAX)\r
+               fatal_error("Symbol table overflow...");\r
+\r
+       strncpy(pSymNext, TString, CBString);\r
+       gst[iSymNext].Size = CBString;\r
+       gst[iSymNext].Type = 0;                         /* initialize type */\r
+       gst[iSymNext].Ptr = pSymNext;\r
+       gst[iSymNext].Line = lineno[level];\r
+       gst[iSymNext].Offs = 0;\r
+\r
+       /* All declarations that reach NewSymbol are either at\r
+       level 0 or defined as PUBLIC or EXTERN. */\r
+\r
+       if (fExtern)\r
+               gst[iSymNext].Type |= tEXTRN;\r
+       else\r
+               gst[iSymNext].Type |= tPUBLIC;\r
+\r
+       if (fFarLabel) gst[iSymNext].Type |= tFAR;\r
+\r
+       if (fDataSeg) {\r
+               if (!fExtern)\r
+                       gst[iSymNext].Offs = oNextData;\r
+           gst[iSymNext].Type |= DLABEL;\r
+       }\r
+       else {\r
+               if (!fExtern)\r
+                       gst[iSymNext].Offs = oNextCode;\r
+               gst[iSymNext].Type |= CLABEL;\r
+       }\r
+\r
+       /* update for next symbol */\r
+       pSymNext += CBString;\r
+       iSymNext++;\r
+\r
+\r
+       /* Now, parse again and hand off. We have just added a symbol\r
+       so expect to see an EQU, COLON or Storage statement.\r
+       If we don't see one of these it's an error unless it's an extern.\r
+       If we see a COLON we parse again and expect an instruction or EOL!\r
+       */\r
+\r
+       fStorage = 0;\r
+       fColon=0;\r
+       i = Parse();\r
+\r
+       if (i == COLON) {\r
+               fColon = 1;\r
+               if (fDataSeg) {\r
+               line_error(49);\r
+                   return;\r
+               }\r
+               i = Parse();\r
+       }\r
+\r
+       switch(i) {             /* parse returns Token */\r
+               case INSTRU:\r
+                   if (fDataSeg) {\r
+                       line_error(41);\r
+                           return;\r
+                       }\r
+                       if (!fColon) {\r
+                       line_error(54);\r
+                           return;\r
+                       }\r
+                   Instruction();\r
+                   break;\r
+           case rDB:\r
+                       gst[iSymNext-1].Type |= sBYTE;          /*  type */\r
+                       fStorage = 1;\r
+                       break;\r
+           case rDW:\r
+                       gst[iSymNext-1].Type |= sWORD;  /*  type */\r
+                       fStorage = 1;\r
+                       break;\r
+           case rDD:\r
+                       gst[iSymNext-1].Type |= sDWORD; /*  type */\r
+                       fStorage = 1;\r
+                       break;\r
+               case rDF:\r
+                       if ((!fDataSeg) && (!fColon)) {\r
+                               line_error(54);\r
+                                   return;\r
+                               }\r
+                       gst[iSymNext-1].Type |= sFWORD; /*  type */\r
+                       fStorage = 1;\r
+                       break;\r
+               case rEQU:\r
+               line_error(55);\r
+       /*              AddMacro(); */\r
+                       break;\r
+               case COLON:\r
+                       if (fExtern)\r
+                       return;\r
+               case ZERO:\r
+                       if ((fDataSeg) && (!fExtern))\r
+                               line_error(56);\r
+                       break;\r
+               default:\r
+                       if (fDataSeg)\r
+                               line_error(56);\r
+         }\r
+\r
+       if (gst[iSymNext-1].Type & tEXTRN)\r
+               fStorage = 0;\r
+\r
+       if (fStorage)\r
+               Storage();\r
+}\r
+\r
+/********************************************\r
+  This changes an EXTRN entry in the gst to\r
+  a PUBLIC once we find it.  This checks to\r
+  make sure the extern declaration was the\r
+  same type as this public.\r
+*********************************************/\r
+\r
+void MakePublic(void)\r
+{\r
+S16 i;\r
+S8   fColon, fStorage;\r
+\r
+       if (gst[TSymnum].Type & tPUBLIC) {\r
+               line_error(64);\r
+               return;\r
+       }\r
+\r
+       if ((fDataSeg) && (!(gst[TSymnum].Type & DLABEL))) {\r
+               line_error(69);\r
+               return;\r
+       }\r
+\r
+       if ((!fDataSeg) && (!(gst[TSymnum].Type & CLABEL))) {\r
+               line_error(69);\r
+               return;\r
+       }\r
+\r
+       gst[TSymnum].Type |= tPUBLIC;   /* Turn ON Public */\r
+       gst[TSymnum].Type &= ~tEXTRN;   /* Turn off EXTERN */\r
+\r
+       if (fDataSeg)\r
+               gst[TSymnum].Offs = oNextData;\r
+       else\r
+               gst[TSymnum].Offs = oNextCode;\r
+\r
+       /* Now, parse again and hand off. We have just added a symbol\r
+       so expect to see an EQU, COLON or Storage statement.\r
+       If we don't see one of these it's an error unless it's an extern.\r
+       If we see a COLON we parse again and expect an instruction or EOL!\r
+       */\r
+\r
+fStorage = 0;\r
+fColon=0;\r
+i = Parse();\r
+\r
+if (i == COLON) {\r
+       fColon = 1;\r
+       if (fDataSeg) {\r
+       line_error(49);\r
+           return;\r
+       }\r
+       i = Parse();\r
+}\r
+\r
+switch(i) {            /* parse returns Token */\r
+       case INSTRU:\r
+           if (fDataSeg) {\r
+               line_error(41);\r
+                   return;\r
+               }\r
+               if (!fColon) {\r
+               line_error(54);\r
+                   return;\r
+               }\r
+           Instruction();\r
+           break;\r
+    case rDB:\r
+               gst[TSymnum].Type |= sBYTE;             /*  type */\r
+               fStorage = 1;\r
+               break;\r
+    case rDW:\r
+               gst[TSymnum].Type |= sWORD;     /*  type */\r
+               fStorage = 1;\r
+               break;\r
+    case rDD:\r
+               gst[TSymnum].Type |= sDWORD;    /*  type */\r
+               fStorage = 1;\r
+               break;\r
+       case rDF:\r
+               if ((!fDataSeg) && (!fColon)) {\r
+                       line_error(54);\r
+                           return;\r
+                       }\r
+               gst[TSymnum].Type |= sFWORD;    /*  type */\r
+               fStorage = 1;\r
+               break;\r
+       case rEQU:\r
+       line_error(55);\r
+               break;\r
+       case COLON:\r
+               return;\r
+       default:\r
+               if (fDataSeg)\r
+                       line_error(56);\r
+  }\r
+\r
+if (fStorage)\r
+       Storage();\r
+\r
+}\r
+\r
+\r
+/********************************************\r
+  This checks to ensure multiple externs are\r
+  the same type when we run across them, and\r
+  also that an extern is the same type if\r
+  the public is already declared.\r
+*********************************************/\r
+void CheckExtern(void)\r
+{\r
+       /* Check to make sure new extern and symbol are same type */\r
+\r
+       if ((fDataSeg) && (!(gst[TSymnum].Type & DLABEL))) {\r
+               line_error(69);\r
+               return;\r
+       }\r
+\r
+       if ((!fDataSeg) && (!(gst[TSymnum].Type & CLABEL))) {\r
+               line_error(69);\r
+               return;\r
+       }\r
+}\r
+\r
+\r
+/********************************************\r
+  Add new LOCAL symbol to table (TString).\r
+  Then parse again to hand off to\r
+  proper function. This stores all\r
+  Symbols UPPER case.\r
+*********************************************/\r
+void NewLSymbol(void)\r
+{\r
+S16 i;\r
+S8   fColon, fStorage;\r
+\r
+if ((pLSymNext + CBString) >= (pLSymBuf + LSYMBUFMAX))\r
+       fatal_error("Local symbol buffer overflow...");\r
+if (iLSymNext >= LSYMSMAX)\r
+       fatal_error("Local symbol table overflow...");\r
+\r
+strncpy(pLSymNext, TString, CBString);\r
+lst[iLSymNext].Size = CBString;\r
+lst[iLSymNext].Type = 0;                               /* initialize type */\r
+lst[iLSymNext].Ptr = pLSymNext;\r
+lst[iLSymNext].Line = lineno[level];\r
+\r
+if (fDataSeg) {\r
+       lst[iLSymNext].Offs = oNextData;\r
+       lst[iLSymNext].Type |= DLABEL;\r
+       }\r
+else {\r
+       lst[iLSymNext].Offs = oNextCode;\r
+       lst[iLSymNext].Type |= CLABEL;\r
+       }\r
+\r
+/* update for next symbol */\r
+pLSymNext += CBString;\r
+iLSymNext++;\r
+\r
+/* Now, parse again and hand off. We have just added a symbol\r
+so expect to see an EQU, COLON or Storage statement.\r
+If we don't see one of these it's an error!\r
+If we see a COLON we parse again and expect an instruction or EOL!\r
+ */\r
+\r
+fStorage = 0;\r
+fColon=0;\r
+i = Parse();\r
+\r
+if (i == COLON) {\r
+       fColon = 1;\r
+       if (fDataSeg) {\r
+       line_error(49);\r
+           return;\r
+       }\r
+       i = Parse();\r
+}\r
+\r
+switch(i) {            /* parse returns Token */\r
+       case INSTRU:\r
+           if (fDataSeg) {\r
+               line_error(41);\r
+                   return;\r
+               }\r
+               if (!fColon) {\r
+               line_error(54);\r
+                   return;\r
+               }\r
+           Instruction();\r
+           break;\r
+    case rDB:\r
+               lst[iLSymNext-1].Type |= sBYTE;         /*  type */\r
+               fStorage = 1;\r
+               break;\r
+    case rDW:\r
+               lst[iLSymNext-1].Type |= sWORD; /*  type */\r
+               fStorage = 1;\r
+               break;\r
+    case rDD:\r
+               lst[iLSymNext-1].Type |= sDWORD;        /*  type */\r
+               fStorage = 1;\r
+               break;\r
+       case rDF:\r
+               if ((!fDataSeg) && (!fColon)) {\r
+                       line_error(54);\r
+                           return;\r
+                       }\r
+               lst[iLSymNext-1].Type |= sFWORD;        /*  type */\r
+               fStorage = 1;\r
+               break;\r
+       case rEQU:\r
+               AddMacro();\r
+               break;\r
+       case COLON:\r
+               return;\r
+       default:\r
+               if (fDataSeg)\r
+                       line_error(56);\r
+  }\r
+\r
+if (lst[iLSymNext-1].Type & tEXTRN)\r
+       fStorage = 0;\r
+\r
+if (fStorage)\r
+       Storage();\r
+\r
+}\r
+\r
+/*****************************************\r
+ After we transition from level 1 back to\r
+ level 0 we go back to the point in the\r
+ code or data file where we began writing this\r
+ section and resolve all forward code\r
+ and local data references. These will be\r
+ referenced in the module we just finished.\r
+ ******************************************/\r
+\r
+void Resolve(void)\r
+{\r
+int i, isym;\r
+S32 Relative;\r
+S32 Partial;\r
+S32 AddFix;\r
+\r
+       i = 0;\r
+\r
+       while (i < iRefNext)  /* While there are forward references */\r
+       {\r
+               if (pfrt[i].Type == DSEGREF)            /* Ref is in DSEG */\r
+               {\r
+                       fseek(ds_fh, (pfrt[i].Offs - DataOffset) , SEEK_SET);\r
+                       fread(&Partial, 4, 1, ds_fh);\r
+                       fseek(ds_fh, (pfrt[i].Offs - DataOffset) , SEEK_SET);\r
+                       AddFix = pfrt[i].Offs - DataOffset;\r
+               }\r
+               else    /* Ref is in CSEG */\r
+               {\r
+                       fseek(cs_fh, (pfrt[i].Offs - CodeOffset) , SEEK_SET);\r
+\r
+                       if (pfrt[i].Type == CSEGREF)     /* IT'S ABSOLUTE! */\r
+                       {\r
+                               fread(&Partial, 4, 1, cs_fh);\r
+                               fseek(cs_fh, (pfrt[i].Offs - CodeOffset) , SEEK_SET);\r
+                               AddFix = pfrt[i].Offs - CodeOffset;\r
+                       }\r
+               }\r
+               /* We are where we should write the reference\r
+                  now we need to find it in the local symbol table\r
+                  and calculate the proper offset.  The calculation\r
+                  is different for Relative and absolute references.\r
+                  For Relative, we subtract the address where the correction\r
+                  is going to be stored from the offset of reference.\r
+                  For Absolute, we read what was already at the address\r
+                  and add it to the offset of the referenced item.\r
+                  Both of these are also adjusted for the Virtual segment offset.\r
+               */\r
+\r
+               /* Look in the Local Symbol table first! */\r
+\r
+               isym = findLsymbol(pfrt[i].Ptr, pfrt[i].NameSz);\r
+\r
+               if (isym)               /* we found it! */\r
+               {\r
+                       if (pfrt[i].Type == CCR8REF)            /* 8 bit relative */\r
+                       {\r
+                               Relative = lst[isym].Offs - (pfrt[i].Offs - CodeOffset + 1);\r
+                               OutByteCS(Relative);\r
+                       }\r
+                       else if (pfrt[i].Type == CCR32REF) /* 32 bit relative */\r
+                       {\r
+                               /* Fixed to make relatives ok in Virtual Segs */\r
+\r
+                               Relative = (lst[isym].Offs - CodeOffset) -\r
+                                          (pfrt[i].Offs - CodeOffset + 4);\r
+                               OutDWordCS(Relative);\r
+                       }\r
+                       else if (pfrt[i].Type == CSEGREF)  /* 32 bit absolute */\r
+                       {\r
+                               Partial += lst[isym].Offs;\r
+\r
+                               if (lst[isym].Type & CLABEL)\r
+                                       FixUp(CCFIXTAG, AddFix, 0);\r
+                               else if (lst[isym].Type & DLABEL)\r
+                                       FixUp(CDFIXTAG, AddFix, 0);\r
+\r
+                               OutDWordCS(Partial);\r
+                       }\r
+                       else if (pfrt[i].Type == DSEGREF)\r
+                       {\r
+                               Partial += lst[isym].Offs;                      /* RAB was + DataOffset */\r
+\r
+                               if (lst[isym].Type & CLABEL)\r
+                                       FixUp(DCFIXTAG, AddFix, 0);\r
+                               else if (lst[isym].Type & DLABEL)\r
+                                       FixUp(DDFIXTAG, AddFix, 0);\r
+\r
+                               OutDWordDS(Partial);\r
+                       }\r
+               }\r
+               else    /* Look in Global table */\r
+               {\r
+\r
+                       isym = findGsymbol(pfrt[i].Ptr, pfrt[i].NameSz);\r
+\r
+                       if (isym)\r
+\r
+                       {               /* we found it! */\r
+\r
+\r
+                               if (pfrt[i].Type == CCR8REF) {          /* 8 bit relative */\r
+                                       Relative = gst[isym].Offs - (pfrt[i].Offs - CodeOffset + 1);\r
+                                       OutByteCS(Relative);\r
+                               }\r
+                               else if (pfrt[i].Type == CCR32REF) {  /*  32 bit relative */\r
+                                       Relative = gst[isym].Offs - (pfrt[i].Offs - CodeOffset + 4);\r
+                                       OutDWordCS(Relative);\r
+                               }\r
+                               else if (pfrt[i].Type == CSEGREF) {\r
+                                       Partial += gst[isym].Offs;\r
+\r
+                                       if (gst[isym].Type & CLABEL)\r
+                                               FixUp(CCFIXTAG, AddFix, 0);\r
+                                       else if (gst[isym].Type & DLABEL)\r
+                                               FixUp(CDFIXTAG, AddFix, 0);\r
+\r
+                                       OutDWordCS(Partial);\r
+                               }\r
+                               else if (pfrt[i].Type == DSEGREF)\r
+                               {\r
+                                       Partial += gst[isym].Offs;\r
+\r
+                                       if (gst[isym].Type & CLABEL)\r
+                                               FixUp(DCFIXTAG, AddFix, 0);\r
+                                       else if (gst[isym].Type & DLABEL)\r
+                                               FixUp(DDFIXTAG, AddFix, 0);\r
+\r
+                                       OutDWordDS(Partial);\r
+                               }\r
+                       }\r
+                       else\r
+                               prev_error("Unresolved symbol in current module", pfrt[i].Line);\r
+               }\r
+               i++;\r
+       }\r
+\r
+       fseek(cs_fh, 0L, SEEK_END);     /* Get back to the end! */\r
+       fseek(ds_fh, 0L, SEEK_END);\r
+\r
+}\r
+\r
+/*****************************************\r
+ When we have processed all the source\r
+ we call this to resolve ALL externals.\r
+ ******************************************/\r
+\r
+void ResolveExt(void)\r
+{\r
+int i, isym;\r
+S32 Relative;\r
+S32 Partial;\r
+S32 AddFix;\r
+char name[31];\r
+\r
+i = 0;\r
+Partial = 0;\r
+Relative = 0;\r
+AddFix = 0;\r
+\r
+while (i < iERefNext) {        /* While there are unresolved externals */\r
+\r
+       /* See if ref is in GST as PUBLIC */\r
+\r
+       isym = ert[i].iSym;\r
+\r
+       if (gst[isym].Type & tPUBLIC) {\r
+\r
+               if (ert[i].Type == DSEGREF) {                                   /* Ref is in DSEG */\r
+\r
+                       fseek(ds_fh, (ert[i].Offs - DataOffset) , SEEK_SET);\r
+                       fread(&Partial, 4, 1, ds_fh);\r
+                       fseek(ds_fh, (ert[i].Offs - DataOffset) , SEEK_SET);\r
+                       AddFix = ert[i].Offs - DataOffset;\r
+               }\r
+               else  {                                                                                 /* Ref is in CSEG */\r
+\r
+                       fseek(cs_fh, (ert[i].Offs - CodeOffset) , SEEK_SET);\r
+\r
+                       if (ert[i].Type == CSEGREF) {                    /* and IT'S ABSOLUTE! */\r
+                               fread(&Partial, 4, 1, cs_fh);\r
+                               fseek(cs_fh, (ert[i].Offs - CodeOffset) , SEEK_SET);\r
+                               AddFix = ert[i].Offs - CodeOffset;\r
+                       }\r
+               }\r
+                       /* We are where we should write the reference\r
+                          now we need to use the index in the external ref\r
+                          table to see if it has been defined PUBLIC.\r
+                          If so, we resolve it, else we error out.\r
+                          To resolve it, the calculation is different for Relative\r
+                          and absolute references.\r
+                          For Relative, we subtract the address where the correction\r
+                          is going to be stored from the offset of reference.\r
+                          For Absolute, we read what was already at the address\r
+                          and add it to the offset of the referenced item.\r
+                          Both of these are also adjusted for the Virtual segment offset.\r
+                       */\r
+\r
+               if (ert[i].Type == CCR32REF) {  /*  32 bit relative */\r
+\r
+                       /* Fixed to make relatives ok in Virtual Segs */\r
+\r
+                       Relative = (gst[isym].Offs - CodeOffset) -\r
+                                  (ert[i].Offs - CodeOffset + 4);\r
+                       OutDWordCS(Relative);\r
+               }\r
+               else if (ert[i].Type == CSEGREF) {\r
+                       Partial += gst[isym].Offs;\r
+\r
+                       if (gst[isym].Type & DLABEL)\r
+                               FixUp(CDFIXTAG, AddFix, 0);\r
+                       else if (gst[isym].Type & CLABEL)\r
+                               FixUp(CCFIXTAG, AddFix, 0);\r
+\r
+                       OutDWordCS(Partial);\r
+               }\r
+               else if (ert[i].Type == DSEGREF) {\r
+                       Partial += gst[isym].Offs;\r
+\r
+                       if (gst[isym].Type & CLABEL)\r
+                               FixUp(DCFIXTAG, AddFix, 0);\r
+                       else if (gst[isym].Type & DLABEL)\r
+                                       FixUp(DDFIXTAG, AddFix, 0);\r
+\r
+                       OutDWordDS(Partial);\r
+               }\r
+       }\r
+       else {\r
+               strncpy(name, gst[isym].Ptr, gst[isym].Size);\r
+               name[gst[isym].Size] = '\0';\r
+               fprintf(lst_fh, "Unresolved external: %s\n", name);\r
+               Column = 0;\r
+               ++error_count;\r
+       }\r
+i++;\r
+}      /* while more Erefs */\r
+\r
+fseek(cs_fh, 0L, SEEK_END);    /* Get back to the end! */\r
+fseek(ds_fh, 0L, SEEK_END);\r
+\r
+}\r
+\r
+/*****************************************\r
+  If there were no errors, and all looks\r
+  well, we build the run file. This consists\r
+  of building the required tags in order\r
+  and writing them to the file with the\r
+  data.\r
+******************************************/\r
+\r
+void BuildRunFile(void)\r
+{\r
+unsigned char b;\r
+int i;\r
+long sdata;\r
+\r
+       tag.id = IDTAG;                                         /* File type */\r
+       tag.len = 1;\r
+       fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
+       fwrite(&filetype, 1, 1, run_fh);        /* Write the filetype */\r
+\r
+       /* Version tag goes here */\r
+       /* DatTime tag goes here */\r
+       /* Comment tag(s) goes here */\r
+\r
+       tag.id = SEGTAG;                                        /* Initial Segment Sizes */\r
+       tag.len = 12;\r
+       fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
+       fwrite(&StackTotal, 4, 1, run_fh);      /* Write the Stacktotal */\r
+       sdata = oNextCode - CodeOffset;         /* Size of CS.TMP */\r
+       fwrite(&sdata, 4, 1, run_fh);           /* Write the Code Size */\r
+       sdata = oNextData - DataOffset;         /* Size of DS.TMP */\r
+       fwrite(&sdata, 4, 1, run_fh);           /* Write the Data Size */\r
+\r
+       printf("Stack Size: %ld\r\n", StackTotal);\r
+       printf("Code  Size: %ld\r\n", oNextCode - CodeOffset);\r
+       printf("Data  Size: %ld\r\n", oNextData - DataOffset);\r
+\r
+       tag.id = DOFFTAG;                                       /* Assumed Data Offset */\r
+       tag.len = 4;\r
+       fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
+       fwrite(&DataOffset, 4, 1, run_fh);      /* Write the data */\r
+\r
+       tag.id = COFFTAG;                                       /* Assumed Code Offset */\r
+       tag.len = 4;\r
+       fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
+       fwrite(&CodeOffset, 4, 1, run_fh);      /* Write the data */\r
+\r
+       tag.id = STRTTAG;                                       /* Starting Address */\r
+       tag.len = 4;\r
+       fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
+       fwrite(&StartAddr, 4, 1, run_fh);       /* Write the data */\r
+\r
+       tag.id = CODETAG;                                       /* Code Segment */\r
+       tag.len = oNextCode - CodeOffset;       /* Size of CS.TMP */\r
+       fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
+\r
+       fseek(cs_fh, 0L , SEEK_SET);\r
+       sdata = tag.len;\r
+       while (sdata > 0) {\r
+               i = fread(line_buf0, 1, 200, cs_fh);\r
+               sdata -= i;\r
+               if (!i) break;\r
+               fwrite(line_buf0, 1, i, run_fh);\r
+       }\r
+\r
+       tag.id = DATATAG;                                       /* Data Segment */\r
+       tag.len = oNextData - DataOffset;       /* Size of DS.TMP */\r
+       fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
+\r
+       fseek(ds_fh, 0L , SEEK_SET);\r
+       sdata = tag.len;\r
+       while (sdata > 0) {\r
+               i = fread(line_buf0, 1, 200, ds_fh);\r
+               sdata -= i;\r
+               if (!i) break;\r
+               fwrite(line_buf0, 1, i, run_fh);\r
+       }\r
+\r
+       if (nCDFix) {\r
+               tag.id = CDFIXTAG;                                      /* CSEG Data Fixups */\r
+               tag.len = nCDFix * 4;                           /* Count * 4 of Fixups */\r
+               fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
+               i = iFUNext;\r
+               while (i--) {                                           /* Write CD fixups */\r
+                       if (pfut[i].type == CDFIXTAG)\r
+                               fwrite(&pfut[i].Offs, 1, 4, run_fh);\r
+               }\r
+       }\r
+\r
+       if (nCCFix) {\r
+               tag.id = CCFIXTAG;                                      /* CSEG Code Fixups */\r
+               tag.len = nCCFix * 4;                           /* Count * 4 of Fixups */\r
+               fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
+               i = iFUNext;\r
+               while (i--)     {                                               /* Write CC fixups */\r
+                       if (pfut[i].type == CCFIXTAG)\r
+                               fwrite(&pfut[i].Offs, 1, 4, run_fh);\r
+               }\r
+       }\r
+\r
+       if (nDDFix) {\r
+               tag.id = DDFIXTAG;                                      /* DESG Data Fixups */\r
+               tag.len = nDDFix * 4;                           /* Count * 4 of Fixups */\r
+               fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
+               i = iFUNext;\r
+               while (i--)     {                                               /* Write DD fixups */\r
+                       if (pfut[i].type == DDFIXTAG)\r
+                               fwrite(&pfut[i].Offs, 1, 4, run_fh);\r
+               }\r
+       }\r
+\r
+       if (nDCFix) {\r
+               tag.id = DCFIXTAG;                                      /* DESG Code Fixups */\r
+               tag.len = nDCFix * 4;                           /* Count * 4 of Fixups */\r
+               fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
+               i = iFUNext;\r
+               while (i--)     {                                               /* Write DC fixups */\r
+                       if (pfut[i].type == DCFIXTAG)\r
+                               fwrite(&pfut[i].Offs, 1, 4, run_fh);\r
+               }\r
+       }\r
+\r
+       /* DLL Address fixup tag goes here */\r
+       /* DLL Public tag goes here */\r
+\r
+       tag.id = ENDTAG;                                                /* End Tag */\r
+       tag.len = 4;    /* Size of CS.TMP */\r
+       fwrite(&tag, 5, 1, run_fh);                             /* Write the tag record */\r
+       sdata = 0;\r
+       fwrite(&sdata, 4, 1, run_fh);                   /* Write the tag record */\r
+\r
+}\r
+\r
+\r
+/*****************************************\r
+    Reads a whole line into line buffer.\r
+******************************************/\r
+\r
+S16 readline(void)\r
+{\r
+U32 i;\r
+U8 *pLine;\r
+\r
+ if (!(fgets(line_ptr = line_buf0, 100, src_fh[level]))) {\r
+\r
+       if (level) {    /* we are in a nested include */\r
+               fclose(src_fh[level]);\r
+               --level;\r
+               if (level==0) {         /* back up one level */\r
+\r
+                       /* Processes forward references from this module */\r
+                       Resolve();\r
+\r
+                       if (fSymDump) {\r
+                               DumpLSymbols();\r
+                               DumpFRT();\r
+                       }\r
+\r
+                       /* Clear local symbol, forward refs, & macro tables */\r
+\r
+                       iLSymNext = 1;  /* 1st entry.  */\r
+                       pLSymNext = pLSymBuf; /* beginning of buffer */\r
+\r
+                       iRefNext = 0;   /* 1st entry.  */\r
+                       pRefNext = pRefBuf;             /* Allocate memory - Was RefBuf */\r
+\r
+                       iMacNext = 0;                   /* 1st entry */\r
+                       pMacNext = pMacBuf;             /* Begining of buffer */\r
+\r
+\r
+               }\r
+               if (fListA)\r
+                       fprintf(lst_fh, "\r\n                ");\r
+               fprintf(lst_fh, "CONTINUING-> %s, Level:%d\r\n", srcname[level],level);\r
+           fprintf(lst_fh, "\r\n");\r
+\r
+               if (lineno[level]) --lineno[level];\r
+               fContinue = 1;\r
+               }\r
+       else {          /* We are at the end of the ATF file */\r
+\r
+               /* Processes forward references from Level 0 */\r
+               Resolve();\r
+\r
+               if (fSymDump) {\r
+                       DumpGSymbols();\r
+                       DumpFRT();\r
+               }\r
+\r
+               if (!fStart)\r
+                       line_error(12); /* Starting address not found */\r
+\r
+               if (!error_count)\r
+                       ResolveExt();\r
+\r
+               printf("%d Errors\r\n%d Warnings\r\n", error_count, warn_count);\r
+\r
+               if (fListA | fListE)\r
+                       fprintf(lst_fh,"%d Errors\r\n%d Warnings\r\n",\r
+                                       error_count,warn_count);\r
+\r
+               if (!error_count) {\r
+                       printf("Building Run file...\n");\r
+                       BuildRunFile();\r
+                       printf("Done.\n");\r
+               }\r
+\r
+               fclose(lst_fh);\r
+               fclose(cs_fh);\r
+               fclose(ds_fh);\r
+               fclose(lst_fh);\r
+               fclose(src_fh[level]);\r
+               remove("CS.TMP");\r
+               remove("DS.TMP");\r
+           exit(1);\r
+           }\r
+    }\r
+\r
+ list_buf[0] = 0;\r
+ if (fListA) {\r
+        pLine = line_ptr;\r
+        i=0;\r
+        while (isspace(*pLine)) pLine++;\r
+        while ((*pLine) && (*pLine != ';') && (*pLine != 0x0A))\r
+               list_buf[i++] = *pLine++;\r
+        while ((i) && (list_buf[i-1] == ' ')) --i; /* eat trailing spaces */\r
+        list_buf[i] = 0;                                                       /* null terminate */\r
+        if (i) fLineIn = 1;\r
+        else fLineIn = 0;\r
+        }\r
+ ++lineno[level];\r
+ return(1);\r
+}\r
+\r
+\r
+/********************************************\r
+   Dispatch calls Parse from the beginning\r
+   of a line and calls the proper routine\r
+   based on what it finds (from Parse()).\r
+   Dispatch  calls readline to get a new line\r
+   after each of the line-specific modules\r
+   gets done with it's line or lines(s).\r
+*********************************************/\r
+\r
+void Dispatch(void)\r
+{\r
+S16 i, j;\r
+S8   st[80];\r
+\r
+while (1) {\r
+  readline();\r
+\r
+  if (fContinue) {             /* We have just returned from an include */\r
+       fContinue = 0;          /* and must reread the line without processing */\r
+       continue;\r
+       }\r
+\r
+  if (lineno[level] == 1) {\r
+       if (fListA)\r
+               fprintf(lst_fh, "\r\n                ");\r
+       fprintf(lst_fh, "PROCESSING-> %s, Level:%d\r\n", srcname[level], level);\r
+       }\r
+\r
+  if (fListA) {\r
+      Column = fprintf(lst_fh, "%06d ", lineno[level]);\r
+      }\r
+\r
+  fPublic = 0;\r
+  fExtern = 0;\r
+  fFarLabel = 0;\r
+\r
+  i = Parse();\r
+  if (fMoreStorage)\r
+       Storage();\r
+  else switch (i) {\r
+    case INSTRU:\r
+                       if (fListA)\r
+                               Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
+                       Instruction();\r
+                       break;\r
+       case REGIST:\r
+                       line_error(63);\r
+                       break;\r
+       case SYMBOL:\r
+                       line_error(64);\r
+                       break;\r
+       case LSYMBOL:\r
+                       line_error(65);\r
+                       break;\r
+       case STRING:\r
+       case NUMBER:\r
+                       line_error(66);\r
+                       break;\r
+       case rPUBLIC:\r
+                       fPublic = 1;\r
+                       if (fListA)\r
+                               Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
+                       j = Parse();\r
+                       if (j==SYMBOL)\r
+                                       MakePublic();\r
+                       else if (j==UNKSYM)\r
+                               NewSymbol();\r
+                       else\r
+                               line_error(67);\r
+                       break;\r
+       case rEXTRN:\r
+                       fExtern = 1;\r
+                       if (fListA)\r
+                               Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
+                       j = Parse();\r
+                       if (j==SYMBOL)\r
+                                       CheckExtern();\r
+                       else if (j==UNKSYM)\r
+                               NewSymbol();\r
+                       else\r
+                               line_error(67);\r
+                       break;\r
+       case UNKSYM:\r
+                       if (fListA)\r
+                               Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
+                       if (level)\r
+                               NewLSymbol();\r
+                       else\r
+                               NewSymbol();\r
+                       break;\r
+       case DOT:\r
+                       Command();\r
+                       break;\r
+       case rDB:\r
+       case rDD:\r
+       case rDW:\r
+       case rDF:\r
+               if (fListA)\r
+                       Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
+               Storage();\r
+               break;\r
+       case ZERO:\r
+               break;\r
+       default:\r
+               line_error(68);\r
+               break;\r
+       }\r
+\r
+  if ((fLineIn) && (fListA)) {\r
+         while (Column < 53) Column += fprintf(lst_fh, " ");\r
+         fprintf(lst_fh, "%s", list_buf);\r
+      }\r
+  if (Column)\r
+         fprintf(lst_fh, "\r\n");\r
+\r
+ } /* while */\r
+}\r
+\r
+/*********************\r
+* Main program\r
+**********************/\r
+\r
+void main(S16 argc, S8  *argv[])\r
+{\r
+S8   *ptr, *pname;\r
+S16 i, j, fdone;\r
+\r
+       lst_fh = stdout;        /* default the list file */\r
+\r
+       for(i=1; i < argc; ++i) {\r
+               ptr = argv[i];\r
+               if (*ptr == '/') {\r
+                 ptr++;\r
+                 switch(*ptr) {\r
+                       case 'L' :                      /* List file ON */\r
+                       case 'l' :\r
+                               fListA = 1;\r
+                               break;\r
+                       case 'S' :                      /* Dump Symbols */\r
+                       case 's' :\r
+                               fSymDump = 1;\r
+                               break;\r
+                       case 'E' :                      /* List file ON for errors/warns only */\r
+                       case 'e' :\r
+                               fListE = 1;\r
+                               break;\r
+                       case 'D' :                      /* Process as DLL */\r
+                       case 'd' :\r
+                               filetype = 2;\r
+                               break;\r
+                       case 'V' :                      /* Process as Devive Driver */\r
+                       case 'v' :\r
+                               filetype = 3;\r
+                               break;\r
+                       default:\r
+                               fatal_error("Invalid option\n");\r
+                               break;\r
+                 }\r
+               }\r
+               else {\r
+                       if(!src_fh[0]) {\r
+                               strncpy(srcname, argv[i], 39);\r
+                               src_fh[0] = fopen(argv[i], "r");\r
+                               }\r
+                       else if(!run_fh) {\r
+                               strncpy(runname, argv[i], 39);\r
+                               if(!(run_fh = fopen(argv[i], "wb"))) {\r
+                                 fatal_error("Can't open RUN file\n");\r
+                                 }\r
+                               }\r
+                       else\r
+                               fatal_error("Too many options\n"); /* Too many parameters */\r
+          }\r
+       }\r
+\r
+/* Input file not explicitly named errors out */\r
+       if(!src_fh[0]) {\r
+               printf("Usage: ATFfile [RunFile] /L /E /D /V\r\n");\r
+               printf("/L = Complete List file generated\r\n");\r
+               printf("/S = Include SYMBOLS (only in complete list file)\r\n");\r
+               printf("/E = List file for Errors/warnings only\r\n");\r
+               printf("/D = Process as Dynamic link library\r\n");\r
+               printf("/V = Process as deVice driver\r\n");\r
+               fatal_error("Can't open Template file\n"); /* Can't open ATF file */\r
+               }\r
+\r
+/* Output file not explicitly named defaults to Source.RUN */\r
+\r
+       if(!run_fh)     {                       /* default asm name to SourceName.run */\r
+               strncpy(runname, srcname, 40);\r
+               pname=runname;\r
+               while ((*pname != '.') && (*pname!= '\0')) pname++;\r
+               *pname++ = '.';\r
+        if (filetype == 2) {\r
+                *pname++ = 'D';\r
+                *pname++ = 'L';\r
+                *pname++ = 'L';\r
+        }\r
+        else if (filetype == 3) {\r
+                *pname++ = 'D';\r
+                *pname++ = 'D';\r
+                *pname++ = 'R';\r
+        }\r
+        else {\r
+         filetype = 1;\r
+                *pname++ = 'R';\r
+                *pname++ = 'U';\r
+                *pname++ = 'N';\r
+               }\r
+               *pname   = '\0';\r
+               if(!(run_fh = fopen(runname, "wb"))) {\r
+                       fatal_error("Can't open OUTPUT file\n");  /* Can't open RUN file */\r
+                       }\r
+               }\r
+\r
+/* List file named Source.LIS for fListA and fListE only. */\r
+\r
+       if (fListA | fListE) {\r
+               strncpy(lstname, srcname, 40);\r
+               pname=lstname;\r
+               while ((*pname != '.') && (*pname!= '\0')) pname++;\r
+               *pname++ = '.';\r
+               *pname++ = 'L';\r
+               *pname++ = 'I';\r
+               *pname++ = 'S';\r
+               *pname   = '\0';\r
+               if(!(lst_fh = fopen(lstname, "w")))\r
+                       fatal_error("Can't open list file (source.LIS)\n"); /* Can't open List file */\r
+               }\r
+               else\r
+            lst_fh = stdout;\r
+\r
+printf("DASM-DOS Ver 1.6 (c) R.A. Burgess 1992,1993,1994\r\n\r\n");\r
+\r
+if (fListA | fListE)\r
+       fprintf(lst_fh, "DASM-DOS Ver 1.6 (c) R.A. Burgess 1992, 1993, 1994\r\n\r\n");\r
+\r
+if (fListA)\r
+       fprintf(lst_fh,\r
+    "LINE   OFFSET   ACTION/DATA/CODE                     SOURCE\r\n\r\n");\r
+\r
+       pLSymBuf = malloc(LSYMBUFMAX);\r
+       if(!pLSymBuf)\r
+               fatal_error("Can't Allocate buffer 1\n");\r
+\r
+       pSymBuf = malloc(SYMBUFMAX);\r
+       if(!pSymBuf)\r
+               fatal_error("Can't Allocate buffer 2\n");\r
+\r
+       pMacBuf = malloc(MACBUFMAX);\r
+       if(!pMacBuf)\r
+               fatal_error("Can't Allocate buffer 3\n");\r
+\r
+       pRefBuf = malloc(FREFBUFMAX);\r
+       if(!pRefBuf)\r
+               fatal_error("Can't Allocate buffer 4\n");\r
+\r
+       pfrt = malloc(FREFTABMAX);\r
+       if(!pfrt)\r
+               fatal_error("Can't Allocate buffer 5\n");\r
+\r
+       pfut = malloc(FIXUPBUFMAX);\r
+       if(!pfut)\r
+               fatal_error("Can't Allocate buffer 6\n");\r
+\r
+pSymNext = pSymBuf;            /* Allocate memory - Was SymBuf */\r
+pLSymNext = pLSymBuf;  /* Allocate memory - Was LSymBuf */\r
+pMacNext = pMacBuf;            /* Allocate memory - Was MacBuf */\r
+pRefNext = pRefBuf;            /* Allocate memory - Was RefBuf */\r
+\r
+\r
+pNextAddr = &oNextData;        /* default to DataSeg */\r
+\r
+if(!(cs_fh = fopen(csname, "wb+")))\r
+       fatal_error("Can't open CS temp file\n");\r
+\r
+if(!(ds_fh = fopen(dsname, "wb+")))\r
+       fatal_error("Can't open DS temp file\n");\r
+\r
+/* We now build a dynamic instruction lookup table which indexes\r
+the first entry of an instruction in the opcode array rgINS.\r
+This is done dynamically because we are still optimizing.\r
+*/\r
+\r
+/* i is the instruction we are indexing */\r
+/* j is the position in rgINS */\r
+\r
+for (i=1; i<ninst+1; i++) {\r
+       for (j=1; j<nrgINS; j++) {\r
+               if (rgINS[j][0] == i) {\r
+               rgInsLookUp[i] = j;\r
+               break;\r
+               }\r
+       }\r
+}\r
+\r
+Dispatch();\r
+\r
+}\r