]> pd.if.org Git - mmurtl/blob - dasm/source/dasm.c
autocommit for file dated 1995-01-31 08:28:28
[mmurtl] / dasm / source / dasm.c
1 /*\r
2  * D-Group Assembler for MMURTL (DOS Version).\r
3  *\r
4  * Copyright 1991,1992,1993,1994 R.A. Burgess\r
5 \r
6   Version 1.2 11/20/93 - major rewrite on instruction table\r
7   Version 1.3 8/28/94 - Clear macro buf on level 1 to 0 transition\r
8   Version 1.4 9/29/94 - Smashed bug in 66| prefix for string commands\r
9   Version 1.5 10/5/94 - Optimized a couple of commands and fixed\r
10                                 bug in ENTER X,X instruction.  This version seems\r
11                                 really stable ("yeaaaaa Right," he says...)\r
12                                 Actually it is....\r
13                10/29/94 Fix problem with sign extending bytes on ADD\r
14   Version 1.6  12/31/94 - Removed temp files on succesful assemble\r
15  */\r
16 \r
17 #define U32 unsigned long\r
18 #define S32 long\r
19 #define U16 unsigned int\r
20 #define S16 int\r
21 #define U8 unsigned char\r
22 #define S8 char\r
23 \r
24 \r
25 #include <ctype.h>\r
26 #include <stdio.h>\r
27 #include <string.h>\r
28 #include <stdlib.h>\r
29 #include "dasm.h"\r
30 #include "runfile.h"\r
31 \r
32 /* variables */\r
33 \r
34 #define LEVELS 5\r
35 U8 level = 0;                           /* current include level */\r
36 U32 lineno[LEVELS];                     /* line number being parsed */\r
37 U8 fContinue = 0;                       /* True if just returned from include */\r
38 \r
39 char srcname[LEVELS][40];       /* also active include filenames */\r
40 char runname[40];\r
41 char lstname[40];\r
42 \r
43 /* File handles for all files */\r
44 \r
45 FILE *src_fh[5] = {0,0,0,0,0};  /* Current source file */\r
46 FILE *run_fh   = 0;             /* Current .RUN, .DLL, or .DDR (output) */\r
47 FILE *ds_fh    = 0;             /* temp file for ALL DS strorage */\r
48 FILE *cs_fh    = 0;             /* temp file for ALL CS code */\r
49 FILE *lst_fh   = 0;             /* List file */\r
50 FILE *sym_fh   = 0;             /* Symbol file for debugger */\r
51 \r
52 char *csname = "CS.TMP";\r
53 char *dsname = "DS.TMP";\r
54 \r
55 U8 filetype = 1;                /* 1 = RUN, 2 = DLL, 3 = DDR */\r
56 \r
57 U8 fListA = 0;                  /* True if detailed list file */\r
58 U8 fListE = 0;                  /* True if Error only list file */\r
59 U8 fSymDump = 0;                /* True if we add symbols to the list file */\r
60 U8 Column = 0;                  /* where are we on the LIST line */\r
61 U16 error_count = 0;\r
62 U16 warn_count = 0;\r
63 \r
64 \r
65  /* Max input line is 132, but 200 allows plenty for macro subs */\r
66 S8 line_buf0[200];      /* Two buffers are swapped during macro substitution */\r
67 S8 line_buf1[200];\r
68 S8 *line_ptr;           /* pointer to next char on line */\r
69 \r
70 S8 list_buf[200];       /* Used to hold line string for list file */\r
71 S8 fLineIn =0;          /* TRUE is list_buf has something to list */\r
72 \r
73 S8 TString[133];        /* all parsed tokens are placed here in text form */\r
74 S16 CBString;           /* size of parsed token */\r
75 S16  TSymnum;           /* Symbol table entry number, else 0 */\r
76 U32  TNumber;           /* value of numeric token */\r
77 S16  TInst;                     /* Instruction number, else 0 */\r
78 S16  TReg;                      /* Register number, else 0 */\r
79 S16  Token;                     /* Token type (also returned from parse) */\r
80 S8   fPutBack = 0;  /* TRUE (non=zero) if last token was not used */\r
81 \r
82 S8   LTString[133];     /* Duplicates of Token storage for ReturnToken(); */\r
83 S16  LCBString;\r
84 S16  LTSymnum;\r
85 U32  LTNumber;\r
86 S16  LTInst;\r
87 S16  LTReg;\r
88 S16  LToken;\r
89 \r
90 S8 UString[31]; /* Place to save unknown labels for Forward Reference */\r
91 S16 UCBString;          /* Size of Unknown label */\r
92 \r
93 /* The two Symbol tables have 5 entries;  Type, Size, Pointer to Name,\r
94    Segment Offset, and Line.\r
95    As each symbol is found, it's identifed by type, and the name\r
96    is moved to the packed symbol buffer. A pointer is added to the\r
97    table to point to the name in the buffer, while it's size, type,\r
98    segment offset, and line number are added to the table.\r
99    Macro names are also stored in the symbol table, but offset entry\r
100    for a macro indicates it's offset in the Macro buffer.\r
101 */\r
102 \r
103 /* Variables for symbol tables */\r
104 \r
105 /* Global Symbol Table */\r
106 \r
107 #define SYMSMAX 500\r
108 #define SYMBUFMAX 10140         /* Avg of 10 byte per name, 700 Max */\r
109 \r
110 struct symtab {\r
111         U16  Type;              /* Token (e.g, CLabel) */\r
112         U16  Line;              /* Line symbol was declared on */\r
113         U8   Size;              /* Size of symbol name */\r
114         S8   *Ptr;              /* Pointer to name in packed buffer */\r
115         U32  Offs;              /* Offset in segment */\r
116         };\r
117 \r
118 struct symtab gst[SYMSMAX];     /* storage for the GST */\r
119 \r
120 /* S8  SymBuf[SYMBUFMAX];       */      /* Where names are stored. Will be Alloced */\r
121 S8 *pSymBuf;                            /* ptr to allocated buffer */\r
122 \r
123 S8   *pSymNext;         /* ptr to next new entry in symbol buffer */\r
124 S16 iSymNext = 1;       /* index to next new symbol table entry.  */\r
125                                         /* Starts at 1 - zero it reserved because */\r
126                                         /* Parse returns 0 for EOL */\r
127 \r
128 S8 fPublic = 0;\r
129 S8 fExtern = 0;\r
130 S8 fFarLabel = 0;\r
131 \r
132 /*********** Local Symbol Table *************/\r
133 \r
134 /* This is cleared after each include file from level 1 is closed */\r
135 /* Clearing means we reset *pLSymNext to begining of buffer */\r
136 /* and reset iLSymNext to 1. This "hides" local symbols. */\r
137 \r
138 #define LSYMSMAX 1800\r
139 #define LSYMBUFMAX 16384                        /* Avg of 7 bytes per name */\r
140 \r
141 struct symtab lst[LSYMSMAX];    /* storage for the LST */\r
142 \r
143 /* S8  LSymBuf[LSYMBUFMAX]; */          /* Where names are stored.*/\r
144 S8  *pLSymBuf;                                  /* for allocated buffer */\r
145 \r
146 S8   *pLSymNext;        /* ptr to next new entry in symbol buffer */\r
147 S16 iLSymNext = 1;      /* index to next new symbol table entry.  */\r
148                                         /* Starts at 1 - zero it reserved because */\r
149                                         /* Parse returns 0 for EOL */\r
150 \r
151 /************* Forward Ref Table *********************************/\r
152 /*\r
153    Labels that are encountered as forward references are\r
154    stored in this table.  When we run across a forward, we do\r
155    not know what segment they are refering to unless it is from\r
156    a jump, call, or loop instruction.  We will NOT know for many\r
157    items until they are actually declared.  After all the code\r
158    and data has been processed, we go through this table\r
159    and fix all the unknown references using the relative\r
160         The type of forward references are:\r
161 \r
162                 1) DSEG DWORD item refers to UNK item (?Seg MemRef)\r
163                 2) CSEG DWORD item refers to UNK item (?Seg MemRef)\r
164                 3) CSEG to CSEG relative 8  (Jump, Jc, or Loop)\r
165                 4) CSEG to CSEG relative 32 (Jump or Call)\r
166 \r
167         MOTE: If a calculation is made with the unknown reference, 0\r
168         is used in the calculation. We ALWAYS ADD the value we stored\r
169         with what is found when the reference is resolved.\r
170 \r
171 */\r
172 \r
173 #define FREFSMAX   32768/12\r
174 #define FREFTABMAX 32768\r
175 #define FREFBUFMAX 16384\r
176 \r
177 /* Types of forward references. */\r
178 \r
179 #define DSEGREF   1             /* 32 bit Abs Ref in DSeg, to what is unknown! */\r
180 #define CSEGREF   2             /* 32 bit Abs Ref in CSeg, to what is unknown! */\r
181 #define CCR32REF  3             /* 32 bit Relative in CSeg */\r
182 #define CCR8REF   4             /* 8 bit Relative in CSeg */\r
183 \r
184 struct forreftab {\r
185         U8   Type;      /* 1, 2, 3, or 4 */\r
186         U8   NameSz;    /* Size of ref name */\r
187         U16  Line;              /* Line reference was made on  (for error if not found) */\r
188         S8   *Ptr;              /* Pointer to name in packed buffer */\r
189         S32  Offs;              /* Offset in segment were it should go */\r
190         };\r
191 \r
192 struct forreftab *pfrt; /* pointer to allocated table */\r
193 \r
194 S8   *pRefBuf;\r
195 S8   *pRefNext;         /* ptr to next new entry in symbol buffer */\r
196 S16  iRefNext = 0;      /* index to next new forward ref table entry.  */\r
197 \r
198 /************ External Reference table ************/\r
199 \r
200 /* External definitions that are encountered in a module are\r
201    first entered in the Global Symbol Table (GST) as externals\r
202    if they haven't already been defined (public) by the module\r
203    that owns them.\r
204    When a reference is made to an external, we see if the public has\r
205    already been defined. If so, we resolve it immediately. If not,\r
206    we make an entry in the External Reference Table (ERT).  The\r
207    entry has the following 4 pieces of information:\r
208      - Line where reference was made.\r
209      - Index to place holder entry in GST.\r
210          - Segment where reference was made (boolean - TRUE for code seg).\r
211          - Offset in that segment where the resolution will be made.\r
212    With this information we can reslove all the external references\r
213    before we write the code segment to the run file.\r
214 */\r
215 \r
216 #define EREFSMAX 400\r
217 \r
218 struct extreftab {\r
219         U8   Type;   /* Type of reference so we know how to apply it */\r
220         U16  iSym;       /* Index of gst entry. Hi bit seg if CSeg ref */\r
221         U32  Offs;       /* Offset in segment were ref needs 32 bit fixing */\r
222         };\r
223 \r
224 struct extreftab ert[FREFSMAX];\r
225 \r
226 S16  iERefNext = 0;     /* index to next external ref table entry.  */\r
227 \r
228 U16 nExtRef;\r
229 \r
230 /*********** Fix Up Table *********************/\r
231 \r
232 /* This table holds 6 types of fixups along with the offset\r
233    in the segment to be fixed up, and if applicable, an index\r
234    to the DLL public name in the GST (which should be defined\r
235    as EXTRNDLL):\r
236      - Fixup type\r
237          - Ref in CSEG to address in DSEG\r
238          - Ref in CSEG to address in CSEG\r
239          - Ref in DSEG to address in DSEG\r
240          - Ref in DSEG to address in CSEG\r
241          - CSEG DLL near 32 bit call used\r
242          - CSEG DLL near 32 bit call defined\r
243      - Offset of 32 bit reference to be resolved\r
244      - Index to DLL public name in GST (if applicable)\r
245 \r
246    With this information we can supply the loader with the TAG entries\r
247    in the RUN file needed to resolve them.  Most of these entries will\r
248    be made as we parse the code, but many will also be added after\r
249    we fix the forward references because we won't know what segment\r
250    the reference is made to until then.\r
251 */\r
252 \r
253 #define FIXUPSMAX    32768/7\r
254 #define FIXUPBUFMAX  32768\r
255 \r
256 struct futab {\r
257         U8   type;   /* Type of fixup C0, C1, C2, C3, C5, or C8 */\r
258         U32  Offs;       /* Offset in segment for 32 bit fixup */\r
259         U16  iSym;       /* index of DLL entry in gst, else 0 */\r
260         };\r
261 \r
262 struct futab *pfut;     /* pointer to allocated Fix Up Table */\r
263 \r
264 S16  iFUNext = 0;       /* index to next fix up table entry.  */\r
265                                         /* Starts at 0 */\r
266 \r
267 U16     nCDFix = 0;\r
268 U16 nDDFix = 0;\r
269 U16 nDCFix = 0;\r
270 U16 nCCFix = 0;\r
271 \r
272 /********* Macro variables *******************/\r
273 \r
274 #define MACSMAX 200\r
275 #define MACBUFMAX  3000\r
276 \r
277 S8   *rgMacPtr[MACSMAX];        /* pointer to simple macros */\r
278 S8   *pMacBuf;\r
279 S8   *pMacNext;                         /* ptr to next new entry in macro buffer */\r
280 S16  iMacNext = 0;                      /* index to next new symbol entry */\r
281 \r
282 /* Variables for current segment address offset tracking */\r
283 \r
284 S8  fStart = 0;                 /* True if they gave a start address */\r
285 S32 StartAddr = 0;              /* Filled in when .START is encountered */\r
286 S32 oNextData = 0;              /* Tracks current DSEG offset */\r
287 S32 oNextCode = 0;      /* Tracks current CSEG offset */\r
288 S32 CodeOffset = 0;             /* From Virtual Command */\r
289 S32 DataOffset = 0;             /* From Virtual Command */\r
290 S32 *pNextAddr = 0;             /* Points to current segment offset counter */\r
291 S8  fDataSeg = 0;               /* True if parsing DSEG, else parsing CSEG */\r
292 S32 StackTotal = 0;             /* Total Stack Specified in Code segs */\r
293 \r
294 /******************************************************************\r
295    Variables for RAW operands in an instruction.\r
296    These are used when we read in and separate each part of the\r
297    operands so it can be evaluated.\r
298 */\r
299 \r
300 S16  rgToken[3][20]; /* Raw tokens in the operand (as many as 20) */\r
301 S32  rgVal[3][20];   /* value if token is number/displacement */\r
302 S16  rgTID[3][20];       /* Register ID if token is a register */\r
303 S16  rgTCnt[3];          /* total count of tokens in raw operand */\r
304 \r
305 /******************************************************************\r
306    These variables are filled in while parsing and evaluating\r
307    instructions that have been read in.\r
308    They have all the info needed to\r
309    encode the instruction into the object module and\r
310    produce FixUp Records if needed.\r
311 */\r
312 \r
313 /* These are used in the description of all OPERANDS for the current\r
314    instruction we are working on.\r
315 */\r
316 S16  rgOpType[3];       /* Operand type for compare to instruction */\r
317 S16  rgOpReg[3];    /* If reg only, this which one */\r
318 S8   OpSize[3];     /* Operand size for first two (fByte, fWord, fFar etc.) */\r
319 S8   OpSizeA;       /* Overall operand size for instruction */\r
320 S8   OpPrefix;      /* Bit set for a segment prefix (fESp etc.) */\r
321 S16  iInstEntry;        /* Which entry is it in rgINS */\r
322 S16  CrntInst;          /* instruction we are working on        */\r
323 S16  InstPfx;           /* Special Insturction prefix for crnt inst */\r
324 S16  nOperands;         /* number of operands we found */\r
325 S8   fForRef;       /* Crnt inst makes a Forward Reference */\r
326 \r
327 /* The following vars are used if we have a memory reference that is\r
328    encoded as part of the instruction.\r
329 */\r
330 S8   OpMType;           /* Mem type (compared to rgM32). 0 if not mem type */\r
331 S16  OpBase;        /* Base register if fBase is true */\r
332 S16  OpIndx;        /* Index register if fIndx is true */\r
333 S32  OpDisp;        /* Displacement if fDisp8 or fDisp32 is TRUE */\r
334 S16  iMemEntry;         /* If mem operand, which entry in rgM32 */\r
335 \r
336 /* The following are used if we have immediate values to be encoded as\r
337 part of the instruction.  Immediates can also be addresses such as\r
338 those in Direct and Relative Jumps and Calls!\r
339 */\r
340 S32  OpImm;         /* Immediate value if fOpImm is true */\r
341 S8   fOpImm;            /* If OpImm has a value */\r
342 S32  OpImm2;        /* Second Imm value for iSAD and other multi-Imm types */\r
343 S8   fOpImm2;           /* If OpImm2 has a value */\r
344 \r
345 /* This is set for each type of fixup required after an instruction\r
346 line.  Data fixups are done directly in the code that generates\r
347 storage in DSeg. */\r
348 \r
349 U8   nFixUp;            /* Fixup number (Cx) */\r
350 \r
351 /*************************************************************************/\r
352 \r
353 /* In the final stages of building an instruction, these contain the\r
354    fragment bytes of encoded instructions (along with flags for\r
355    optional parts used).\r
356 */\r
357 \r
358 U8  bOpc1;              /* Zero if not used */\r
359 U8  bOpc2;              /* Always used */\r
360 U8  bModRM;             /* ModRM byte value if used */\r
361 U8  bSIB;               /* SIB value if used */\r
362 S8  fModRM;     /* True if bModRM is used */\r
363 S8  fSIB;       /* True if bSIB is used */\r
364 \r
365 /*** These are used in the expression parser ******/\r
366 \r
367 U8  ExpType;            /* 0 = Forward, 1 = Local, 2 = Global, 3 = Current Addr */\r
368 U8  ExpType0;\r
369 S16 nExpSyms;           /* Used by the numeric expression evaluator */\r
370 S16 iExpSym, iExpSym0;  /* if a symbol value translates to a SYMOFF,\r
371                                            this holds the symbol table index. */\r
372 S8  fOffset;            /* True if derived from an Offset */\r
373 \r
374 /* Variables for Storage allocation */\r
375 \r
376 \r
377 S8  fMoreStorage = 0;   /* True when storage continues to next line */\r
378 S16 StoreSize = 0;\r
379 \r
380 /****  Variables for building the RUN File (DLL or Device Driver) ********/\r
381 \r
382 /* Once we have the CS and DS tmp files run through to correct any external\r
383    variables or forward labels, we build the run file.  This is done\r
384    by building the tag records, sending them followed by the proper data\r
385    for each one.\r
386 */\r
387 \r
388 struct tagtype tag;\r
389 \r
390 \r
391 /******************* END VARIABLES - BEGIN CODE ********************/\r
392 \r
393 /* ANSI prototypes for all functions are in DProtos.h */\r
394 \r
395 #include "DProtos.h"\r
396 \r
397 \r
398 /***************************************************************/\r
399 /* Write a DWord to the current segment and update the counter */\r
400 /***************************************************************/\r
401 \r
402 void OutDWord(unsigned long Data)\r
403 {\r
404 unsigned char *pOut, b;\r
405 int i;\r
406         pOut = &Data;\r
407         if (fDataSeg) {\r
408                 for (i=0; i<4; i++) {\r
409                         b = *pOut++;\r
410                         fputc(b , ds_fh);\r
411                 }\r
412             oNextData+=4;\r
413         }\r
414         else {\r
415                 for (i=0; i<4; i++) {\r
416                         b = *pOut++;\r
417                         fputc(b , cs_fh);\r
418                 }\r
419             oNextCode+=4;\r
420     }\r
421 }\r
422 \r
423 /******************************************************************/\r
424 /* Write a DWord to the current segment and DO NOT update counter */\r
425 /******************************************************************/\r
426 \r
427 void OutDWordCS(unsigned long Data)\r
428 {\r
429 unsigned char *pOut, b;\r
430 int i;\r
431         pOut = &Data;\r
432         for (i=0; i<4; i++) {\r
433                 b = *pOut++;\r
434                 fputc(b , cs_fh);\r
435         }\r
436 }\r
437 \r
438 /******************************************************************/\r
439 /* Write a DWord to the current segment and DO NOT update counter */\r
440 /******************************************************************/\r
441 \r
442 void OutDWordDS(unsigned long Data)\r
443 {\r
444 unsigned char *pOut, b;\r
445 int i;\r
446         pOut = &Data;\r
447         for (i=0; i<4; i++) {\r
448                 b = *pOut++;\r
449                 fputc(b , ds_fh);\r
450         }\r
451 }\r
452 \r
453 /**************************************************************/\r
454 /* Write a Word to the current segment and update the counter */\r
455 /**************************************************************/\r
456 \r
457 void OutWord(unsigned int Data)\r
458 {\r
459 unsigned char *pOut, b;\r
460 int i;\r
461         pOut = &Data;\r
462         b = *pOut++;\r
463         if (fDataSeg) {\r
464                 fputc(b , ds_fh);\r
465                 b = *pOut;\r
466                 fputc(b , ds_fh);\r
467             oNextData+=2;\r
468         }\r
469         else {\r
470                 fputc(b , cs_fh);\r
471                 b = *pOut;\r
472                 fputc(b , cs_fh);\r
473             oNextCode+=2;\r
474         }\r
475 }\r
476 \r
477 /**************************************************************/\r
478 /* Write a BYTE to the current segment and update the counter */\r
479 /**************************************************************/\r
480 \r
481 void OutByte(unsigned char Data)\r
482 {\r
483         if (fDataSeg) {\r
484                 fputc(Data , ds_fh);\r
485             oNextData++;\r
486         }\r
487         else {\r
488                 fputc(Data , cs_fh);\r
489             oNextCode++;\r
490         }\r
491 }\r
492 \r
493 /*****************************************************************/\r
494 /* Write a BYTE to the current segment and DO NOT update counter */\r
495 /*****************************************************************/\r
496 \r
497 void OutByteCS(unsigned long Data)\r
498 {\r
499 char b;\r
500         b = Data;\r
501         fputc(b , cs_fh);\r
502 }\r
503 \r
504 /* All the "grunt work" functions are in dasmq.c */\r
505 \r
506 #include "DASMq.c"\r
507 \r
508 /*********************************************\r
509 This searches the Reference table for the name\r
510 described by pb, cb. It only compares items that\r
511 are the same length (cb == TRefSize[x]).\r
512 It returns the number or 0 if not found.\r
513 **********************************************/\r
514 \r
515 S16 findref(S8 *pb, S16 cb)  /* pointer to, and size of string */\r
516 {\r
517 S16 i;\r
518 S8   name[132];\r
519 \r
520 strncpy(name, pb, cb);          /* move name local */\r
521 name[cb] = 0;                           /* null terminate */\r
522 \r
523 i = iRefNext;\r
524 while (i>0) {                           /* backwards through forward ref table */\r
525         i--;\r
526                                 /* Only compare if same size  */\r
527         if (pfrt[i].NameSz == cb) {\r
528                 if (strncmp(name, pfrt[i].Ptr, cb) == 0) return(i);\r
529         }\r
530 }\r
531 return(0);\r
532 }\r
533 \r
534 \r
535 /*****************************************************\r
536    Evaluates only single token operands and sets up\r
537    globals so EvalOper can finish the job.\r
538    The actual value or register is left in\r
539    rgToken[op][0], and the type is placed\r
540    in rgTempl[op][0] for a memory operand.\r
541 *****************************************************/\r
542 S16 EvalOper1(S16 op)\r
543 {\r
544 S16 i;\r
545 U16 symtype;\r
546 \r
547         /* Set up symtype up front in case it's needed */\r
548 \r
549         if (ExpType == 1)                               /* Local */\r
550                 symtype = lst[iExpSym].Type;\r
551         else if (ExpType == 2) {                /* global */\r
552                 if (gst[iExpSym].Type & tEXTRN)\r
553                         nExtRef = iExpSym;\r
554                 symtype = gst[iExpSym].Type;\r
555         }\r
556         else symtype = 0;\r
557 \r
558         switch (rgToken[op][0]) {\r
559                 case REGIST:\r
560                         if (is_r32(rgTID[op][0]))  rgOpType[op] = r32;\r
561                         else if (is_r16(rgTID[op][0])) rgOpType[op] = r16;\r
562                         else if (is_r8(rgTID[op][0]))   rgOpType[op] = r8;\r
563                         else if (is_rCRG(rgTID[op][0])) rgOpType[op] = rCRG;\r
564                         else if (is_rDRG(rgTID[op][0])) rgOpType[op] = rDRG;\r
565                         else if (is_rTRG(rgTID[op][0])) rgOpType[op] = rTRG;\r
566                         else if (is_rSEG(rgTID[op][0])) rgOpType[op] = rSEG;\r
567                         rgOpReg[op] = rgTID[op][0];\r
568                         break;\r
569                 case NUMBER:\r
570                         if ((rgVal[op][0] >= -128) && (rgVal[op][0] <= 127))\r
571                  rgOpType[op] = val8;\r
572                         else if ((rgVal[op][0] >= -32768) && (rgVal[op][0] <= 32767))\r
573                  rgOpType[op] = val16;\r
574                         else rgOpType[op] = val32;\r
575                         if (!fOpImm) {\r
576                     OpImm = rgVal[op][0];\r
577                     fOpImm = 1;\r
578                     }\r
579                         else {\r
580                     OpImm2 = rgVal[op][0];\r
581                     fOpImm2 = 1;\r
582                     }\r
583                         break;\r
584                 case NUMOFF:            /* OFFSET var name. IMMEDIATE VALUE. */\r
585                         OpSize[op] = fDWord;\r
586                         rgOpType[op] = val32;\r
587             OpImm = rgVal[op][0];\r
588             fOpImm = 1;\r
589                         if (symtype & CLABEL)\r
590                                 nFixUp = CCFIXTAG;\r
591                         else if (symtype & DLABEL)\r
592                                 nFixUp = CDFIXTAG;\r
593                         if (!symtype)\r
594                                 fForRef = 1;\r
595                         break;\r
596                 case SYMOFF:   /* Check for ALL jump, call & Loop instructions */\r
597 \r
598                         if (ExpType == 1)                               /* Local */\r
599                                 symtype = lst[iExpSym].Type;\r
600                         else if (ExpType == 2) {                /* global */\r
601                                 if (gst[iExpSym].Type & tEXTRN)\r
602                                         nExtRef = iExpSym;\r
603                                 symtype = gst[iExpSym].Type;\r
604                         }\r
605                         else                                                    /* Unknown - Forward */\r
606                                 symtype = 0;\r
607 \r
608                         if (((CrntInst >= xJA) &&\r
609                              (CrntInst <= xJZ)) ||\r
610                  (CrntInst == xCALL)) {\r
611 \r
612                                 if (OpSize[op] & fShort)\r
613                                         rgOpType[op]  = rel8;\r
614                                 else\r
615                                         rgOpType[op] = relW;\r
616                         OpImm = rgVal[op][0];\r
617                         fOpImm = 1;\r
618                         }\r
619 \r
620                         else if ((CrntInst >= xLOOP) && (CrntInst <= xLOOPZ)) {\r
621                                         rgOpType[op] = rel8;\r
622                                 OpImm = rgVal[op][0];\r
623                                 fOpImm = 1;\r
624                         }\r
625                         else {\r
626                                 rgOpType[op]  = mem;\r
627                     OpMType |= fDisp32;\r
628                     OpDisp = rgVal[op][0];\r
629                                 if (symtype & CLABEL)\r
630                                         nFixUp = CCFIXTAG;\r
631                                 else if (symtype & DLABEL)\r
632                                         nFixUp = CDFIXTAG;\r
633                         }\r
634                         if (!symtype)\r
635                                 fForRef = 1;\r
636                         break;\r
637                 default:\r
638                    line_error(15);\r
639                    return(0);\r
640         } /* switch */\r
641 \r
642 /*  print_Oper(op); Testing only... */\r
643 \r
644 return(1);\r
645 }\r
646 \r
647 /***********  EvalOper *******************************\r
648    Evaluates the array of reserved words, registers,\r
649    numbers, etc. that should make up an operand.\r
650    For single token operands it's easy! BUT for memory\r
651    operands it gets a little more complicated.\r
652    For memory operands we look for key sequences of\r
653    tokens that make up the "effective address" as\r
654    described in the Intel documentation, then see if\r
655    we have all the pieces to make one (EA).\r
656    This returns 1 if we can classify the operand and\r
657    there were no errors.  The type of operand we find\r
658    (e.g., r8, r16, r32, val8, val16, val32, mem,\r
659    relW, etc.) is placed in rgOpType[op].\r
660    This calls EvalOper1() to handle single token\r
661    oprerands and evaluates multiple token operands\r
662    internally. The reason we break single token operands\r
663    out in a separate call is for speed and clarity\r
664    of the code.\r
665    Special handling is required for for JMP, Jcond,\r
666    and CALL instructions because they may be using\r
667    a forward reference not yet defined.  This is the\r
668    only case where such a reference is allowed.\r
669 *****************************************************/\r
670 \r
671 S16 EvalOper(S16 op)\r
672 {\r
673 S16 i;\r
674 S8   fDone, fOpenSQ, fError;\r
675 U16 symtype;\r
676 /*\r
677 These are the Raw operands:\r
678 S16  rgToken[3][20];  Raw tokens in the operand\r
679 S32  rgVal[3][20];    value if token is number/displacement\r
680 S16  rgTID[3][20];        Register ID if token is a register\r
681 S16  rgTCnt[3];           total count of tokens in raw operand\r
682 \r
683  This is what is produced:\r
684 */\r
685 \r
686 rgOpType[op] = 0;       /* int - Operand type for compare to instruction */\r
687 rgOpReg[op] = 0;    /* If reg only, this which one */\r
688 \r
689 i = 0;           /* index into raw tokens */\r
690 fError = 0;  /* set true for invalid operand error */\r
691 fDone = 0;   /* Set when no more tokens are expected in operand */\r
692 fOpenSQ = 0; /* keep track of [] */\r
693 \r
694 /* flags for segment instruction prefix - NONE unless otherwise set */\r
695 /* If it's a single token operand, take the fast, easy way out! */\r
696 \r
697 if (rgTCnt[op] == 1) {\r
698         return (EvalOper1(op));\r
699 }\r
700 \r
701 else {          /* multiple tokens in operand */\r
702 \r
703         /* with more than 1 token it is usually a memory reference\r
704            but not always.  We will default to mem and change those we\r
705            find that aren't.  */\r
706 \r
707         rgOpType[op] = mem;\r
708 \r
709         /* Segment prefix?  If so, set flag and eat 2 tokens */\r
710 \r
711         if ((rgToken[op][0]==REGIST) && (is_rSEG(rgTID[op][0]))) {\r
712                 if (rgToken[op][1] == COLON) {\r
713                         switch (rgToken[op][0]) {\r
714                                 case rDS: OpPrefix |= fDSp; break;\r
715                                 case rES: OpPrefix |= fESp; break;\r
716                                 case rSS: OpPrefix |= fSSp; break;\r
717                                 case rFS: OpPrefix |= fFSp; break;\r
718                                 case rGS: OpPrefix |= fGSp; break;\r
719                                 case rCS: OpPrefix |= fCSp; break;\r
720                                 default:;\r
721                         }\r
722                         i += 2;         /* skip rSEG and colon */\r
723                 }\r
724                 else {\r
725                    line_error(16);\r
726                    return(0);\r
727            }\r
728         }\r
729 \r
730 /* Loop through the raw tokens looking for Base Reg, Index Reg,\r
731    Scale value, or displacement and setting varaibles as needed.\r
732 */\r
733 \r
734         while ((i < rgTCnt[op]) &&\r
735                   (!fError) &&\r
736                   (!fDone)) {\r
737                 switch (rgToken[op][i]) {\r
738 \r
739                 case REGIST:\r
740                         if (is_r32(rgTID[op][i])) {  /* check for Indx & Base Reg */\r
741                 if (rgToken[op][i+1] == STAR) {                 /* Index w/Scale */\r
742                                         if (!(OpMType & fIndx))  {      /* still OK */\r
743                         OpMType |= fIndx;\r
744                         OpIndx = rgTID[op][i];\r
745                                                 if (rgToken[op][i+2] == NUMBER) {\r
746                                                         switch (rgVal[op][i+2]) {\r
747                                                         case 2: OpMType |= fScale2; break;\r
748                                                         case 4: OpMType |= fScale4; break;\r
749                                                         case 8: OpMType |= fScale8; break;\r
750                                                         default:\r
751                                                                 line_error(17);\r
752                                                                 fError = 1;\r
753                                                         }\r
754                                                 }\r
755                                                 else {\r
756                                                         line_error(18);\r
757                                                         fError = 1;\r
758                                                 }\r
759                                         }\r
760                                         else {\r
761                                                 line_error(19);\r
762                                                 fError = 1;\r
763                                         }\r
764                                         i+=3;   /* get past *NUMBER */\r
765                 }\r
766                 /* Must be base, unless fBase true, then try Index */\r
767                 else {\r
768                                         if (!(OpMType & fBase)) { /* Base for sure */\r
769                         OpMType |= fBase;\r
770                         OpBase = rgTID[op][i];\r
771                         i++;\r
772                                         }\r
773                                         else {  /* try Index */\r
774                                                 if (!(OpMType & fIndx)) { /* It's free, use it */\r
775                                 OpMType |= fIndx;\r
776                             OpIndx = rgTID[op][i];\r
777                                 i++;\r
778                                                 }\r
779                                         }\r
780                                 }\r
781                         }\r
782                         else { /* must be 32 bit general purpose register */\r
783                                 line_error(20);\r
784                                 fError = 1;\r
785                         }\r
786                         break;\r
787 \r
788 \r
789                 case SYMOFF:  /* One symbol was used by itself or in an expression */\r
790                         if (ExpType == 1)                               /* Local */\r
791                                 symtype = lst[iExpSym].Type;\r
792                         else if (ExpType == 2) {                /* global */\r
793                                 if (gst[iExpSym].Type & tEXTRN)\r
794                                         nExtRef = iExpSym;\r
795                                 symtype = gst[iExpSym].Type;\r
796                         }\r
797                         else                                                    /* Unknown - Forward */\r
798                                 symtype = 0;\r
799 \r
800                         if (OpMType & (fDisp32|fDisp8)) {   /* Already a disp! */\r
801                                 line_error(21);\r
802                                 fError = 1;\r
803                                 }\r
804 \r
805                         /* Check for conditional jumps. */\r
806 \r
807                         else if ((CrntInst >= xJA) &&\r
808                                      (CrntInst <= xJZ) &&\r
809                                      (CrntInst != xJMP) &&\r
810                                      (!(fOpenSQ)))\r
811                         {\r
812                                         if (OpSize[op] & fShort)\r
813                                                 rgOpType[op] = rel8;\r
814                                         else rgOpType[op] = relW;\r
815                                         if (fOpImm) {\r
816                                         OpImm2 = rgVal[op][i];\r
817                                         fOpImm2 = 1;\r
818                                 }\r
819                                         else {\r
820                                         OpImm = rgVal[op][i];\r
821                                         fOpImm = 1;\r
822                                         }\r
823                                         if (!symtype)\r
824                                                 fForRef = 1;\r
825                         }\r
826 \r
827                                 /* Check for JMP */\r
828 \r
829                         else if (CrntInst == xJMP)  /* &&  (!(fOpenSQ))) */\r
830                         {\r
831                                 if ((OpSize[op] & fFar) || (symtype & tFAR)) {\r
832                                         rgOpType[op] = iSAD;\r
833                                         if (fOpImm) {\r
834                                         OpImm2 = rgVal[op][i];\r
835                                         fOpImm2 = 1;\r
836                                 }\r
837                                         else {\r
838                                         OpImm = rgVal[op][i];\r
839                                         fOpImm = 1;\r
840                                         }\r
841                                 }\r
842                                 else if (OpSize[op] & fShort) {\r
843                                         rgOpType[op] = rel8;\r
844                                 OpImm = rgVal[op][i];\r
845                                 fOpImm = 1;\r
846                                         if (!symtype)\r
847                                                 fForRef = 1;\r
848                                 }\r
849                                 else if (OpSize[op] & fFWord) {\r
850                                         rgOpType[op]  = memF;  /* memF = 32 disp which has 16:32 */\r
851                             OpMType |= fDisp32;\r
852                             OpDisp = rgVal[op][i];\r
853                                         if (symtype & CLABEL)\r
854                                                 nFixUp = CCFIXTAG;\r
855                                         else if (symtype & DLABEL)\r
856                                                 nFixUp = CDFIXTAG;\r
857                                         if (!symtype)\r
858                                                 fForRef = 1;\r
859                                 }\r
860                                 else {\r
861                                         rgOpType[op] = relW;\r
862                                     OpImm = rgVal[op][i];\r
863                                     fOpImm = 1;\r
864                                         if (!symtype)\r
865                                                 fForRef = 1;\r
866                                 }\r
867                         }\r
868 \r
869                                 /* Check for CALL */\r
870 \r
871                         else if ((CrntInst == xCALL) && (!(fOpenSQ)))\r
872                         {\r
873                                 if ((OpSize[op] & fFar) || (symtype & tFAR)) {\r
874                                         rgOpType[op] = iSAD;\r
875                                         if (fOpImm) {\r
876                                         OpImm2 = rgVal[op][i];\r
877                                         fOpImm2 = 1;\r
878                                     }\r
879                                         else {\r
880                                         OpImm = rgVal[op][i];\r
881                                         fOpImm = 1;\r
882                                         }\r
883                                 }\r
884                                 else if (OpSize[op] & fFWord) {\r
885                                         rgOpType[op]  = memF;  /* memF = 32 disp which has 16:32 */\r
886                             OpMType |= fDisp32;\r
887                             OpDisp = rgVal[op][i];\r
888                                         if (symtype & CLABEL)\r
889                                                 nFixUp = CCFIXTAG;\r
890                                         else if (symtype & DLABEL)\r
891                                                 nFixUp = CDFIXTAG;\r
892                                         if (!symtype)\r
893                                                 fForRef = 1;\r
894                                 }\r
895                                 else {          /* Relative call */\r
896                                         rgOpType[op] = relW;\r
897                                         if (!symtype)\r
898                                                 fForRef = 1;\r
899                                 }\r
900                         }\r
901 \r
902                                 /* Check for SGDT SIDT */\r
903 \r
904                         else if ((CrntInst == xSGDT) || (CrntInst == xSIDT))\r
905                         {\r
906                                 if (OpSize[op] & fFWord) {\r
907                                         rgOpType[op]  = memF;  /* memF = 32 disp which has 16:32 */\r
908                             OpMType |= fDisp32;\r
909                             OpDisp = rgVal[op][i];\r
910                                         if (symtype & CLABEL)\r
911                                                 nFixUp = CCFIXTAG;\r
912                                         else if (symtype & DLABEL)\r
913                                                 nFixUp = CDFIXTAG;\r
914                                         if (!symtype)\r
915                                                 fForRef = 1;\r
916                                 }\r
917                         }\r
918 \r
919                           /* Check for Loop */\r
920 \r
921                         else if ((CrntInst >= xLOOP) && (CrntInst <= xLOOPZ))\r
922                         {\r
923                                         rgOpType[op] = rel8;\r
924                                     OpImm = rgVal[op][0];\r
925                                     fOpImm = 1;\r
926                                         if (!symtype)\r
927                                                 fForRef = 1;\r
928                         }\r
929                         else {\r
930                                     OpDisp = rgVal[op][i];\r
931                                         OpMType |= fDisp32;\r
932                                         if (symtype & CLABEL)\r
933                                                 nFixUp = CCFIXTAG;\r
934                                         else if (symtype & DLABEL)\r
935                                                 nFixUp = CDFIXTAG;\r
936                                         if (!symtype)\r
937                                                 fForRef = 1;\r
938                         }\r
939                         i++;\r
940                         break;\r
941 \r
942                 case NUMBER:  /* can be 8 or 32 bit disp, or hard address */\r
943                 OpDisp = rgVal[op][i];\r
944                         if ((rgVal[op][i] >= -128) && (rgVal[op][i] <= 127))\r
945                                 OpMType |= fDisp8;\r
946                         else\r
947                                 OpMType |= fDisp32;\r
948                         i++;\r
949                         break;\r
950 \r
951                 case OPENSQR:\r
952                         if (fOpenSQ) {\r
953                                 line_error(23);\r
954                                 fError = 1;\r
955                                 }\r
956                         else fOpenSQ = 1;\r
957                         i++;\r
958                         break;\r
959                 case CLOSSQR:\r
960                         if (!fOpenSQ) {\r
961                                 line_error(24);\r
962                                 fError = 1;\r
963                                 }\r
964                         else fOpenSQ = 0;\r
965                         i++;\r
966                         break;\r
967                 case COLON:             /*  for far addresses */\r
968                         i++;\r
969                         break;\r
970                 case PLUS:\r
971                         i++;\r
972                         break;\r
973             case rBYTE:\r
974                 if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {\r
975                                 OpSize[op] |= fByte;\r
976                                 i+=2;\r
977                                 }\r
978                         else {\r
979                                 line_error(25);\r
980                                 fError = 1;\r
981                                 }\r
982                         break;\r
983             case rWORD:\r
984                 if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {\r
985                                 OpSize[op] |= fWord;\r
986                                 i+=2;\r
987                                 }\r
988                         else {\r
989                                 line_error(25);\r
990                                 fError = 1;\r
991                                 }\r
992                         break;\r
993             case rDWORD:\r
994                 if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {\r
995                                 OpSize[op] |= fDWord;\r
996                                 i+=2;\r
997                                 }\r
998                         else {\r
999                                 line_error(25);\r
1000                                 fError = 1;\r
1001                                 }\r
1002                         break;\r
1003             case rFWORD:\r
1004                 if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {\r
1005                                 OpSize[op] |= fFWord;\r
1006                                 i+=2;\r
1007                                 }\r
1008                         else {\r
1009                                 line_error(25);\r
1010                                 fError = 1;\r
1011                                 }\r
1012                         break;\r
1013                 case rNEAR:\r
1014                 if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {\r
1015                                 OpSize[op] |= fNear;\r
1016                                 i+=2;\r
1017                                 }\r
1018                         else {\r
1019                                 line_error(25);\r
1020                                 fError = 1;\r
1021                                 }\r
1022                         break;\r
1023                 case rFAR:\r
1024                 if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {\r
1025                                 OpSize[op] |= fFar;\r
1026                                 i+=2;\r
1027                                 }\r
1028                         else {\r
1029                                 line_error(25);\r
1030                                 fError = 1;\r
1031                                 }\r
1032                         break;\r
1033                 case rSHORT:\r
1034                 if (!OpSize[op]) {\r
1035                                 OpSize[op] |= fShort;\r
1036                                 i++;\r
1037                                 }\r
1038                         else {\r
1039                                 line_error(25);\r
1040                                 fError = 1;\r
1041                                 }\r
1042                         break;\r
1043                 default: {\r
1044                         line_error(32);\r
1045                         fprintf(lst_fh, "  %d  ", rgToken[op][i]);  /* TESTING */\r
1046                         i++;\r
1047                         }\r
1048 \r
1049                 } /* switch */\r
1050         } /* while */\r
1051 }\r
1052 if (fError) return(0);\r
1053 if ((fDone) && (i< rgTCnt[op])) {\r
1054         line_error(33);\r
1055         return(0);\r
1056         }\r
1057 \r
1058 return(1);\r
1059 \r
1060 }\r
1061 \r
1062 /********************************************\r
1063   Adds ALL forward reference to the Ref table.\r
1064   This holds references to all foward addresses\r
1065   (unknown) in the current module.\r
1066   This stores all Refs UPPER case.\r
1067 *********************************************/\r
1068 void ForRef(U8 type, S32 Offset)\r
1069 {\r
1070 S16 i;\r
1071 \r
1072 if (pRefNext >= (pRefBuf + FREFBUFMAX))\r
1073         fatal_error("Forward Reference buffer overflow...");\r
1074 if (iRefNext >= FREFSMAX)\r
1075         fatal_error("Forward Reference table overflow...");\r
1076 \r
1077 /* Make a forward reference table entry */\r
1078 \r
1079 strncpy(pRefNext, UString, UCBString);\r
1080 pfrt[iRefNext].NameSz = UCBString;      /* size of name */\r
1081 pfrt[iRefNext].Ptr = pRefNext;\r
1082 pfrt[iRefNext].Line = lineno[level];    /* for error reporting */\r
1083 pfrt[iRefNext].Type = type;                     /* type of ref */\r
1084 \r
1085 \r
1086 pfrt[iRefNext].Offs = Offset;           /* Offset to correction in CS or DS */\r
1087 \r
1088 /* update for next symbol */\r
1089 \r
1090 pRefNext += UCBString;\r
1091 iRefNext++;\r
1092 \r
1093 }\r
1094 \r
1095 /********************************************\r
1096   Adds fixup table entries to be placed in\r
1097   the run file.  This includes DLL entries.\r
1098 *********************************************/\r
1099 \r
1100 void FixUp(U8 typef, S32 Offset, U16 iSymbol)\r
1101 {\r
1102 \r
1103 if (typef == CDFIXTAG)\r
1104         nCDFix++;\r
1105 else if (typef == DDFIXTAG)\r
1106         nDDFix++;\r
1107 else if (typef == DCFIXTAG)\r
1108         nDCFix++;\r
1109 else if (typef == CCFIXTAG)\r
1110         nCCFix++;\r
1111 \r
1112 \r
1113 if (iFUNext >= FIXUPSMAX)\r
1114         fatal_error("Fixup Table overflow...");\r
1115 pfut[iFUNext].type = typef;\r
1116 pfut[iFUNext].Offs = Offset;\r
1117 pfut[iFUNext].iSym = iSymbol;  /* global symbol entry for DLL */\r
1118 \r
1119 iFUNext++;\r
1120 \r
1121 }\r
1122 \r
1123 /********************************************\r
1124   Adds External Reference to table.\r
1125   This DOES NOT includes DLL Refs.\r
1126   ETypes are the same as ForRef types\r
1127   except there and no 8 bit externals.\r
1128 *********************************************/\r
1129 \r
1130 void ExtRef(U8 EType, U16 iSymbol)\r
1131 {\r
1132 \r
1133 if (iERefNext >= EREFSMAX)\r
1134         fatal_error("External Reference Table overflow...");\r
1135 \r
1136 if (fDataSeg)\r
1137         ert[iERefNext].Offs = oNextData;\r
1138 else {\r
1139         ert[iERefNext].Offs = oNextCode;\r
1140         }\r
1141 ert[iERefNext].iSym = iSymbol;  /* global symbol entry for external */\r
1142 ert[iERefNext].Type = EType;  /* global symbol entry for external */\r
1143 \r
1144 iERefNext++;\r
1145 }\r
1146 \r
1147 /*****************************************************\r
1148    Reads in all of the reserved words, numbers, math\r
1149    operators, etc. that make up one operand.  They are\r
1150    read into one of 3 2D arrays as indicated by "op".\r
1151    Integer rgTCnt[op] is number if items.  A special\r
1152    case for jump and call instructions is tested if\r
1153    we end up with an Unknown Symbol as and operand.\r
1154    We Error out if we have an UNKSYM without a\r
1155    jump or call.\r
1156 *****************************************************/\r
1157 \r
1158 S16 GetOper(S16 op)\r
1159 {\r
1160 S16 i, T;\r
1161 \r
1162 i = 0;\r
1163 while (1) {\r
1164         T = Parse();\r
1165         switch (T) {\r
1166           case ZERO:\r
1167                     rgTCnt[op] = i;\r
1168                         if (i) return(1);\r
1169                         else return(0);\r
1170           case REGIST:\r
1171                 rgTID[op][i] = TReg;\r
1172                 rgToken[op][i] = T;\r
1173                 break;\r
1174           case NUMBER:  /* check for special case of REG*2,*4,*8  */\r
1175                 if ((i > 1) &&\r
1176                         (rgToken[op][i-1] == STAR) &&\r
1177                         (rgToken[op][i-2] == REGIST)) {\r
1178                                 rgVal[op][i] = TNumber;\r
1179                                 rgToken[op][i] = T;\r
1180                                 break;  /* only break here if we find special case */\r
1181                         }                       /* Else fall thru to Expression */\r
1182           case LSYMBOL:\r
1183           case SYMBOL:\r
1184           case DOLLAR:          /* These should all evaluate to a number!! */\r
1185           case OPENRND:\r
1186           case MINUS:\r
1187           case UNKSYM:\r
1188           case rOFFSET:\r
1189                 if (Expression()) {\r
1190                         rgVal[op][i] = TNumber;\r
1191                         rgToken[op][i] = Token;         /* Token instead of T (From Expr)*/\r
1192                         }\r
1193                 else {\r
1194                         line_error(35);\r
1195                         return(0);\r
1196                         }\r
1197 \r
1198                 break;\r
1199           case COMMA:\r
1200                         if (!i) {\r
1201                                 line_error(36);\r
1202                                 return(0);\r
1203                         }\r
1204                     rgTCnt[op] = i;\r
1205                         ReturnToken();\r
1206                         return(1);\r
1207           case OPENSQR:\r
1208           case CLOSSQR:\r
1209           case STAR:\r
1210           case PLUS:\r
1211           case SLASH:\r
1212           case SEMI:\r
1213           case COLON:\r
1214           case rFAR:\r
1215           case rBYTE:\r
1216           case rWORD:\r
1217           case rDWORD:\r
1218           case rFWORD:\r
1219           case rPTR:\r
1220           case rSHORT:\r
1221                         rgToken[op][i] = T;\r
1222                         break;\r
1223           default:\r
1224                         line_error(38);\r
1225                         return(0);\r
1226         }\r
1227  i++;\r
1228 } /* while */\r
1229 }\r
1230 \r
1231 /********************************************\r
1232  This finds the first matching entry in rgINS\r
1233  by first matching the instruction number,\r
1234  then matching operands.  The table is indexed\r
1235  with an array providing the first entry for\r
1236  the instruction. This speed things up a bit.\r
1237 *********************************************/\r
1238 \r
1239 S16 INSEntry(S16 InsNum, S16 nOpers)\r
1240 {\r
1241 S16 i;\r
1242 \r
1243         i = rgInsLookUp[InsNum];\r
1244         while (i <= nrgINS) {\r
1245 \r
1246                 /* instruction entries of the same type\r
1247                 are all kept together. This is an early out.\r
1248                 */\r
1249 \r
1250                 if (rgINS[i][0] != InsNum)\r
1251                   return(0);    /* couldn't find a match at all... */\r
1252 \r
1253                 /* See if all the operators match by calling is_Comp for each.\r
1254                 */\r
1255 \r
1256                 if ((is_Comp(i,0)) &&\r
1257                     (is_Comp(i,1)) &&\r
1258                     (is_Comp(i,2)))\r
1259 \r
1260                         return(i);              /* yes, they all match! */\r
1261 \r
1262                 i++;    /* No, goto next entry */\r
1263         }\r
1264 }\r
1265 \r
1266 \r
1267 /********************************************\r
1268   EmitInst spits out the instruction bytes that\r
1269   were encoded into variables by EncodeInst.\r
1270   This handles output to the code segment\r
1271   file as well as the text to the list file.\r
1272   It updates the code segment address and\r
1273   also adds fixup records as they are needed.\r
1274 \r
1275 The instruction  (up to 16 bytes) is ordered\r
1276 as follows:\r
1277   Instruction Prefix   0 or 1 byte\r
1278   Address Size Prefix  0 or 1 byte\r
1279   Operand Prefix       0 or 1 byte\r
1280   Segment Override     0 or 1 bytes\r
1281   Opcode               1 or 2 bytes\r
1282   MODR/M               0 or 1 bytes\r
1283   SIB                  0 or 1 bytes\r
1284   Displacement         0,1,2 or 4 bytes\r
1285   Immediate            0,1,2, or 4 bytes\r
1286 **********************************************/\r
1287 \r
1288 void EmitInst(void)\r
1289 {\r
1290 U8   oppfx;\r
1291 S8   sbyte;\r
1292 S16  sword;\r
1293 U16  i;         /* used local to each section if needed */\r
1294 \r
1295 \r
1296 \r
1297         /*\r
1298     Instruction prefix: 0 or 1 byte (Lock, Rep, etc.)\r
1299         */\r
1300 \r
1301         if (InstPfx) {\r
1302                 if (InstPfx==xLOCK) {\r
1303                         if (fListA) {\r
1304                                 Column += 2;\r
1305                                 put_hexb(0x0F, lst_fh);\r
1306                                 }\r
1307                         OutByte(0xF0);\r
1308                         }\r
1309                 else if ((InstPfx==xREPNE) || (InstPfx==xREPNZ)) {\r
1310                         if (fListA) {\r
1311                                 Column += 2;\r
1312                                 put_hexb(0xF2, lst_fh);\r
1313                                 }\r
1314                         OutByte(0xf2);\r
1315                         }\r
1316                 else {  /* Must be REP... */\r
1317                         if (fListA) {\r
1318                                 Column += 2;\r
1319                                 put_hexb(0xF3, lst_fh);\r
1320                                 }\r
1321                         OutByte(0xf3);\r
1322                         }\r
1323                 if (fListA)\r
1324                         Column += fprintf(lst_fh, "| ");\r
1325         }\r
1326 \r
1327 /*\r
1328    Skip Address Size prefix: (67h)  cause we aren't\r
1329    doing USE16, nor do we support 16 bit addressing modes!\r
1330 */\r
1331 \r
1332 /* Operand Size prefix: 0 or 1 (66h)  */\r
1333 \r
1334         if (OpSizeA & fWord) {\r
1335                 if (fListA) {\r
1336                         Column += 2;\r
1337                         put_hexb(0x66, lst_fh);\r
1338                         Column += fprintf(lst_fh, "| ");\r
1339                         }\r
1340                 OutByte(0x66);\r
1341                 }\r
1342 \r
1343 /* Segment Override prefix */\r
1344 \r
1345         switch (OpPrefix) {\r
1346                 case fDSp: oppfx = 0x3e; break;\r
1347                 case fESp: oppfx = 0x26; break;\r
1348                 case fSSp: oppfx = 0x36; break;\r
1349                 case fFSp: oppfx = 0x64; break;\r
1350                 case fGSp: oppfx = 0x65; break;\r
1351                 case fCSp: oppfx = 0x2e; break;\r
1352                 default: oppfx = 0;\r
1353         }\r
1354         if (oppfx) {\r
1355                 if (fListA) {\r
1356                         Column += 2;\r
1357                         put_hexb(oppfx, lst_fh);\r
1358                         Column += fprintf(lst_fh, "| ");\r
1359                         }\r
1360                         OutByte(oppfx);\r
1361                 }\r
1362 \r
1363 /*   OpCode byte 1 (optional)\r
1364      bOpc1 was setup in EncodeInst (either 0 or 0Fh)\r
1365 */\r
1366 \r
1367         if (bOpc1) {\r
1368                 if (fListA) {\r
1369                         Column += 2;\r
1370                         put_hexb(bOpc1, lst_fh);\r
1371                         Column += fprintf(lst_fh, " ");\r
1372                         }\r
1373                         OutByte(bOpc1);\r
1374                 }\r
1375 \r
1376 /*   OpCode byte 2 (always sent) */\r
1377 \r
1378         if (fListA) {\r
1379                         Column += 2;\r
1380                         put_hexb(bOpc2, lst_fh);\r
1381                         Column += fprintf(lst_fh, " ");\r
1382                 }\r
1383 \r
1384         OutByte(bOpc2);\r
1385 \r
1386 /*  ModR/M  (optional)  */\r
1387 \r
1388         if (fModRM) {\r
1389                 if (fListA) {\r
1390                         Column += 2;\r
1391                         put_hexb(bModRM, lst_fh);\r
1392                         Column += fprintf(lst_fh, " ");\r
1393                 }\r
1394                 OutByte(bModRM);\r
1395         }\r
1396 \r
1397 /*  SIB  (optional) */\r
1398 \r
1399         if (fSIB) {\r
1400                 if (fListA) {\r
1401                         Column += 2;\r
1402                         put_hexb(bSIB, lst_fh);\r
1403                         Column += fprintf(lst_fh, " ");\r
1404                 }\r
1405                 OutByte(bSIB);\r
1406         }\r
1407 \r
1408 /*\r
1409    Disp: 0, 1, 2 or 4\r
1410    A Displacement is a memory reference (an offset in a segment)\r
1411    that is encoded as part of the instruction. The value to encode\r
1412    is placed in OpDisp when the instruction is parsed and\r
1413    evaluated.\r
1414 */\r
1415 \r
1416         if (OpMType & fDisp32) {\r
1417 \r
1418                 if (fListA) {\r
1419                         Column += 8;\r
1420                         put_hexd(OpDisp, lst_fh);\r
1421                         if ((nExtRef) || (fForRef))\r
1422                                 Column += fprintf(lst_fh, "r ");\r
1423                         else\r
1424                                 Column += fprintf(lst_fh, "  ");\r
1425                 }\r
1426                 if (nExtRef)\r
1427                         ExtRef(CSEGREF, nExtRef);\r
1428                 else if (fForRef)\r
1429                         ForRef(CSEGREF, oNextCode);\r
1430                 else if (nFixUp)\r
1431                         FixUp(nFixUp, oNextCode, 0); /* Code ref to data */\r
1432                 OutDWord(OpDisp);\r
1433         }\r
1434 \r
1435         if (OpMType & fDisp8) {\r
1436 \r
1437                 if (fListA) {\r
1438                         sbyte = OpDisp;\r
1439                         Column += 2;\r
1440                         put_hexb(sbyte, lst_fh);\r
1441                         Column += fprintf(lst_fh, "  ");\r
1442                 }\r
1443                 OutByte(OpDisp);\r
1444         }\r
1445 \r
1446 /*\r
1447    Immediate: 0, 1, 2 or 4\r
1448    The type of instruction operands tell us if we must encode\r
1449    immediate values as part of the instruction.  All instructions\r
1450    have only one immediate value except ENTER. We make a check here\r
1451    to determine if it is this instruction.\r
1452 \r
1453      imm8  = Immediate Byte in OpImm\r
1454      imm16 = immediate 16 bit value in OpImm\r
1455      immX  = immediate value matching OpSize in OpImm\r
1456      rel8  = immediate Byte calculated from a label\r
1457      relW  = immediate Word (16 or 32) calculated from a label\r
1458      iSAD  = immediate DWORD:WORD from Far Pointer (OpImm & OpImm2)\r
1459 \r
1460      immv1 is not encoded (implied by instruction)\r
1461      immv3 is not encoded (also implied - INT 03 - Debug)\r
1462    */\r
1463         if (fOpImm) \r
1464         {\r
1465                 if ((rgINS[iInstEntry][1] == immX) ||\r
1466                     (rgINS[iInstEntry][2] == immX) ||\r
1467             (rgINS[iInstEntry][3] == immX))\r
1468         {\r
1469                         if (OpSizeA & fByte)\r
1470                         {\r
1471                                 if (fListA)\r
1472                                 {\r
1473                                         sbyte = OpImm;\r
1474                                         Column += 2;\r
1475                                         put_hexb(sbyte, lst_fh);\r
1476                                         Column += fprintf(lst_fh, "  ");\r
1477                                 }\r
1478                                 OutByte(OpImm);\r
1479                         }\r
1480                         else if (OpSizeA & fWord)\r
1481                         {\r
1482                                 if (fListA) \r
1483                                 {\r
1484                                         sword = OpImm;\r
1485                                         Column += 4;\r
1486                                         put_hexw(sword, lst_fh);\r
1487                                         Column += fprintf(lst_fh, "  ");\r
1488                                 }\r
1489                                 OutWord(OpImm);\r
1490                         }\r
1491                         else {                                  /* MUST be a DWord */\r
1492                                 if (fListA) {\r
1493                                         Column += 8;\r
1494                                         put_hexd(OpImm, lst_fh);\r
1495                                         if (nFixUp)\r
1496                                                 Column += fprintf(lst_fh, "r ");\r
1497                                         else\r
1498                                                 Column += fprintf(lst_fh, "  ");\r
1499                                 }\r
1500                                 if (nExtRef)\r
1501                                         ExtRef(CSEGREF, nExtRef);\r
1502                                 else if (fForRef)\r
1503                                         ForRef(CSEGREF, oNextCode);\r
1504                                 else if (nFixUp)\r
1505                                         FixUp(nFixUp, oNextCode, 0); /* Code ref to data */\r
1506                                 OutDWord(OpImm);\r
1507                         }\r
1508                 }\r
1509 \r
1510                 if ((rgINS[iInstEntry][1] == imm16) ||\r
1511                     (rgINS[iInstEntry][2] == imm16) ||\r
1512             (rgINS[iInstEntry][3] == imm16))   {\r
1513                         if (fListA) {\r
1514                                 Column += 4;\r
1515                                 sword = OpImm;\r
1516                                 put_hexw(sword, lst_fh);\r
1517                                 Column += fprintf(lst_fh, "  ");\r
1518                                 }\r
1519                         OutWord(OpImm);\r
1520                 }\r
1521                 else if ((rgINS[iInstEntry][1] == imm8) ||\r
1522                          (rgINS[iInstEntry][2] == imm8) ||\r
1523                          (rgINS[iInstEntry][3] == imm8) ||\r
1524                          (rgINS[iInstEntry][1] == ims8) ||\r
1525                          (rgINS[iInstEntry][2] == ims8) ||\r
1526                  (rgINS[iInstEntry][3] == ims8))\r
1527         {\r
1528                         if (fListA) {\r
1529                                 Column += 2;\r
1530                                 sbyte = OpImm;\r
1531                                 put_hexb(sbyte, lst_fh);\r
1532                                 Column += fprintf(lst_fh, "  ");\r
1533                                 }\r
1534                         OutByte(OpImm);\r
1535                 }\r
1536 \r
1537                 /* Special check for Enter. It is only instructon with 2 Imms!*/\r
1538 \r
1539                 if (rgINS[iInstEntry][0] == xENTER)\r
1540         {\r
1541                         if (fListA) {\r
1542                                 Column += 2;\r
1543                                 sbyte = OpImm2;\r
1544                                 put_hexb(sbyte, lst_fh);\r
1545                                 Column += fprintf(lst_fh, "  ");\r
1546                                 }\r
1547                         OutByte(OpImm2);\r
1548                 }\r
1549 \r
1550 \r
1551                 /* With relative values for immediates, OpImm comes in as\r
1552                   the address of the target jump or call. We must take\r
1553                    the current code offset (of the next instruction) and\r
1554                    subtract it from the target (OpImm) to get the relative\r
1555                    jump value. If it is an UNKSYM we will put the value\r
1556                    of the target into the FRT to hold it and\r
1557                    do the math on the second pass of the machine code.\r
1558                    Math Example:\r
1559 \r
1560                         oCode  = 100  (next instruction)\r
1561                         Target =  50\r
1562                         Jump = -50  (Target-Current)\r
1563 \r
1564                         oCode  = 100  (next instruction)\r
1565                         Target = 150\r
1566                         Jump = 50  (Target-Current)\r
1567 \r
1568                         Relative immediate values found in the GST as EXTERN\r
1569                         require an ERT entry so they can be fixed up when\r
1570                         the final code module is written to the run file.\r
1571 \r
1572                         Relative immediate values found in the GST as PUBLICS\r
1573                         can be fixed up NOW.\r
1574 \r
1575                         Relative immediate values NOT found are assumed local\r
1576                         and an entry is made in the FRT so they can be fixed\r
1577                         up when this code module is written to the main\r
1578                         temp code module.\r
1579                    */\r
1580 \r
1581                 if (rgINS[iInstEntry][1] == relW) {\r
1582                         if (nExtRef) {                                          /* list external */\r
1583                                 OpImm = 0;\r
1584                                 ExtRef(CCR32REF, nExtRef);\r
1585                         }\r
1586                         else if (fForRef) {                                     /* list Forward Relative */\r
1587                                 OpImm = 0;\r
1588                                 ForRef(CCR32REF, oNextCode);\r
1589                         }\r
1590                         else {                                                          /* Fix known ref */\r
1591                                 OpImm = OpImm - (oNextCode + 4);\r
1592                         }\r
1593 \r
1594                         if (fListA) {\r
1595                                 Column += 8;\r
1596                                 put_hexd(OpImm, lst_fh);\r
1597                                 if ((!fForRef) && (!nExtRef))\r
1598                                         Column += fprintf(lst_fh, "  ");\r
1599                                 else\r
1600                                         Column += fprintf(lst_fh, "R ");\r
1601                         }\r
1602                         OutDWord(OpImm);\r
1603                 }\r
1604 \r
1605                 if (rgINS[iInstEntry][1] == rel8) {\r
1606                         if (!fForRef) {                                 /* Fix KNOWN Relative */\r
1607                                 OpImm = OpImm - (oNextCode + 1);\r
1608                                 if ((OpImm > 127) || (OpImm < -127))\r
1609                                         line_error(39);\r
1610                         }\r
1611                         else {                                                  /* Else List Unknown */\r
1612                                 ForRef(CCR8REF, oNextCode);\r
1613                                 OpImm = 0;\r
1614                                 }\r
1615 \r
1616                         if (fListA) {\r
1617                                 Column += 2;\r
1618                                 sbyte = OpImm;\r
1619                                 put_hexb(sbyte, lst_fh);\r
1620                                 if ((!fForRef) && (!nExtRef))\r
1621                                         Column += fprintf(lst_fh, "  ");\r
1622                                 else\r
1623                                         Column += fprintf(lst_fh, "R ");\r
1624                         }\r
1625                         OutByte(OpImm);\r
1626                 }\r
1627 \r
1628                 if (rgINS[iInstEntry][1] == iSAD) {\r
1629                         if (fListA) {\r
1630                                 Column += 4;\r
1631                                 sword = OpImm;\r
1632                                 put_hexw(sword, lst_fh);\r
1633                                 Column += fprintf(lst_fh, ":");\r
1634                                 Column += 4;\r
1635                                 put_hexd(OpImm2, lst_fh);\r
1636                                 Column += fprintf(lst_fh, "  ");\r
1637                         }\r
1638                         OutWord(OpImm);\r
1639                         OutDWord(OpImm2);\r
1640                 }\r
1641         }\r
1642 }\r
1643 \r
1644 \r
1645 /********************************************\r
1646   This encodes the instructions into bytes\r
1647   and calls EmitInst() to put them into the\r
1648   current code segment. The instruction can\r
1649   be as long as 16 bytes if all options are used.\r
1650   The order of the bytes and their possible\r
1651   sizes are as follows:\r
1652    Inst Prefix: 0 or 1 (Lock, Rep, etc.)\r
1653    Address Size prefix: 0 or 1 (67h) - We don't use this\r
1654    Operand Size prefix: 0 or 1 (66h)\r
1655    Segment Override: 0 or 1\r
1656    OpCode: 1 or 2\r
1657    ModR/M: 0 or 1\r
1658    SIB: 0 or 1\r
1659    Disp: 0, 1, 2 or 4\r
1660    Immediate: 0, 1, 2 or 4\r
1661    This routine follows the guidance to build\r
1662    instructions given in the rgINS table\r
1663    (as bit flags). It calls     EmitInst() to\r
1664    emit the code, list-file information and\r
1665    fixups to the FUT.\r
1666    **********************************************/\r
1667 void EncodeInst(void)\r
1668 {\r
1669 S8   fError;\r
1670 S16 i;\r
1671 U8 bTmp;\r
1672 \r
1673 /*\r
1674 U8 bOpc1;               Zero if not used   THESE ARE GLOBAL...\r
1675 U8 bOpc2;               Always used\r
1676 U8 bModRM;\r
1677 U8 bSIB;\r
1678 S8 fModRM;          Is bModRM set/used?\r
1679 S8 fSIB;                Is bSIB set/used?\r
1680 */\r
1681 \r
1682 fModRM = 0;             /* not used by default */\r
1683 fSIB   = 0;\r
1684 \r
1685 \r
1686 /* SKIP the Address Size Prefix for now because we don't do 16 Bit\r
1687    Effective addresses\r
1688 */\r
1689 \r
1690 \r
1691 /*\r
1692    Now we will build the instruction in (up to) 4 temporary bytes.\r
1693    We do it in temporary byte vars so we can see if an Operand Prefix\r
1694    and a possible address fixup record is required before we\r
1695    actually put it into the code segment.\r
1696 */\r
1697 \r
1698 /*\r
1699   The WORD forms of string instructions require us\r
1700   to force a WORD size. We set this in the instruction table\r
1701   as qUW in byte [4],\r
1702 */\r
1703 \r
1704 if (rgINS[iInstEntry][4] & qUW)\r
1705   OpSizeA |= fWord;\r
1706 \r
1707 /* Put in the first byte of Opcode from table (if required). qP0F is\r
1708    set in rgINS[iInstEntry][4] if a 0Fh prefix is required for this inst.\r
1709    A 0 in bObc1 indicates that this byte is NOT to be used.\r
1710 */\r
1711 \r
1712 if (rgINS[iInstEntry][4] & qP0F)\r
1713     bOpc1 = 0x0F;\r
1714 else bOpc1 = 0;\r
1715 \r
1716 /* Get the Opcode from table into bOpc2 */\r
1717 \r
1718 bOpc2 = rgINS[iInstEntry][5];\r
1719 \r
1720 /* The flags zMR1, zMR2, zMOP, zAR1, and zAR2 all indicate that the\r
1721    ModRM is needed. The following set of if-else statements checks these\r
1722    flags and sets REG/OP field of MOD/RM byte if required.\r
1723    OpSize should already be set. We also complete\r
1724    the instruction encoding (with the exception of any immediate values)\r
1725    if the other operand is a register.\r
1726 */\r
1727 \r
1728 if (rgINS[iInstEntry][7] & zMR1) {\r
1729         bModRM = rgINS[iInstEntry][6];\r
1730         fModRM = 1;\r
1731         if (is_Reg(rgOpType[0]))\r
1732             EncodeRegBits(rgOpReg[0], &bModRM, 3);\r
1733         if (is_Reg(rgOpType[1])) {\r
1734             EncodeRegBits(rgOpReg[1], &bModRM, 0);\r
1735             bModRM |= 0xC0;     /* indictes REG in RM field */\r
1736                 }\r
1737         }\r
1738 else if (rgINS[iInstEntry][7] & zMR2) {\r
1739         bModRM = rgINS[iInstEntry][6];\r
1740         fModRM = 1;\r
1741         if (is_Reg(rgOpType[1]))\r
1742             EncodeRegBits(rgOpReg[1], &bModRM, 3);\r
1743         if (is_Reg(rgOpType[0])) {\r
1744             EncodeRegBits(rgOpReg[0], &bModRM, 0);\r
1745             bModRM |= 0xC0;     /* indictes REG in RM field */\r
1746                 }\r
1747         }\r
1748 else if (rgINS[iInstEntry][7] & zMOP) {\r
1749         bModRM = rgINS[iInstEntry][6];\r
1750         fModRM = 1;\r
1751         if (is_Reg(rgOpType[0])) {\r
1752             EncodeRegBits(rgOpReg[0], &bModRM, 0);\r
1753             bModRM |= 0xC0;     /* indictes REG in RM field */\r
1754                 }\r
1755         }\r
1756 else if (rgINS[iInstEntry][7] & zAR1) {\r
1757         bTmp = 0;\r
1758     EncodeRegBits(rgOpReg[0], &bTmp, 0);\r
1759         bOpc2 += bTmp;\r
1760         }\r
1761 else if (rgINS[iInstEntry][7] & zAR2) {\r
1762         bTmp = 0;\r
1763     EncodeRegBits(rgOpReg[1], &bTmp, 0);\r
1764         bOpc2 += bTmp;\r
1765         }\r
1766 else if ((rgINS[iInstEntry][7] & zRG1) && (rgOpType[0] != mem)) {\r
1767         bModRM = rgINS[iInstEntry][6];\r
1768         fModRM = 1;\r
1769     EncodeRegBits(rgOpReg[0], &bModRM, 3);\r
1770     bModRM |= 0xC0;     /* indictes REG in RM field */\r
1771         }\r
1772 \r
1773 \r
1774         /* OpSize may not be required for many instructions, but we know\r
1775            for a fact it MUST be known for memory operands!\r
1776         */\r
1777 \r
1778         if ((rgOpType[0] == mem) ||\r
1779                 (rgOpType[1] == mem) ||\r
1780                 (rgOpType[0] == memF)) {\r
1781                         if  (!(OpSizeA & (fByte|fWord|fDWord|fFWord))) {\r
1782                                 line_error(40);\r
1783                                 return;\r
1784                                 }\r
1785         }\r
1786 \r
1787         /*\r
1788            If zORD, see if we have word or dword register and OR the Opcode\r
1789            (Opc2) with 01 if so.\r
1790         */\r
1791 \r
1792         if (rgINS[iInstEntry][7] & zORD) {\r
1793                 if (OpSizeA & (fWord | fDWord))\r
1794                 bOpc2 |= 0x01;\r
1795                 }\r
1796 \r
1797         /* Perform the following additonal steps if we have a memory reference\r
1798            as determined by iMemEntry.\r
1799         */\r
1800 \r
1801         fSIB = 0;\r
1802         if (iMemEntry) {\r
1803 \r
1804         /* If SIB is needed (as determined from OpMType), get it and also\r
1805          OR ModRM by required value from rgM32 table\r
1806         */\r
1807 \r
1808                 bModRM |= rgM32[iMemEntry][2];  /* Use ModRM 'OR' value from table */\r
1809                 if (rgM32[iMemEntry][1]) {              /* is there an SIB byte? */\r
1810                         bModRM &= 0x38;                                 /* 00111000 leaves Reg bit on */\r
1811                         bModRM |= rgM32[iMemEntry][2];  /* 'OR' ModRM with table value */\r
1812                         bSIB = rgM32[iMemEntry][3];\r
1813                         fSIB = 1;\r
1814                 }\r
1815 \r
1816 \r
1817                 /* At this point we have our Opcode, ModRM, and SIB (if required).\r
1818                    The MOD and SS bit are already filled in from the table.\r
1819                    This means we just stick the register values or bits for Disp etc\r
1820                    in the correct positions to complete it.\r
1821                    If we didn't have an SIB, we either have a single displacement,\r
1822                    a base or both.\r
1823                 */\r
1824 \r
1825                 if (!fSIB) {            /* only a base, disp, or both */\r
1826                         if (OpMType & fBase)\r
1827                             EncodeRegBits(OpBase, &bModRM, 0);\r
1828                         else\r
1829                             bModRM |= 0x05;             /* only a disp32 */\r
1830                         }\r
1831                 else {\r
1832                         if (OpMType & fBase)\r
1833                             EncodeRegBits(OpBase, &bSIB, 0);\r
1834                         else bModRM |= 0x20;                            /* else set [--][--] bits */\r
1835                         if (OpMType & fIndx)\r
1836                             EncodeRegBits(OpIndx, &bSIB, 3);\r
1837                         }\r
1838         }\r
1839 \r
1840         EmitInst();\r
1841 \r
1842 }\r
1843 \r
1844 \r
1845 /********************************************\r
1846   When the dispatcher detects an Instruction\r
1847   it calls this code to read in (via parse)\r
1848   the parametrs for the instruction and to\r
1849   put together the opcodes.  First we loop thru\r
1850   and get up to 3 operands, then we evaluate\r
1851   them (classify by type). Next we look up\r
1852   the instruction and find a match for the\r
1853   operand types they have specified, and\r
1854   finally, we encode the instruction into the\r
1855   code segment updating the code segment offset\r
1856   pointer.\r
1857 *********************************************/\r
1858 void Instruction(void)\r
1859 {\r
1860 S16 i;\r
1861 S8   fError;\r
1862 S8   OpSizeTmp;\r
1863 \r
1864 fError = 0;\r
1865 if (fDataSeg) {\r
1866         line_error(41);\r
1867         return;\r
1868         }\r
1869 \r
1870 /* If the instruction is a prefix instruction, save it\r
1871    and Parse again to get the real instruction */\r
1872 \r
1873 if ((TInst==xREP) || (TInst==xREPE) || (TInst==xREPZ) ||\r
1874     (TInst==xREPNE) || (TInst==xREPNZ) || (TInst==xLOCK)) {\r
1875     InstPfx = TInst;\r
1876         i = Parse();\r
1877         if (i != INSTRU) {\r
1878                 line_error(42);\r
1879                 return;\r
1880         }\r
1881 } else InstPfx = 0;\r
1882 \r
1883 /* RESET all global instruction variables */\r
1884 \r
1885 CrntInst = TInst;       /* Save the instruction */\r
1886 nOperands = 0;          /* none yet... */\r
1887 rgOpType[0] = 0;\r
1888 rgOpType[1] = 0;\r
1889 rgOpType[2] = 0;\r
1890 OpMType = 0;        /* char - memory type (a byte to compare to rgM32) */\r
1891 OpSize[0] = 0;          /* char - Mem op size (fByte, fWord, fDword, fFword) */\r
1892 OpSize[1] = 0;          /* char - Mem op size (fByte, fWord, fDword, fFword) */\r
1893 OpSizeA = 0;            /* char - Mem op size (fByte, fWord, fDword, fFword) */\r
1894 OpSizeTmp = 0;          /* char - Mem op size (fByte, fWord, fDword, fFword) */\r
1895 OpPrefix = 0;           /* For Segment register prefix flags */\r
1896 OpDisp = 0;         /* long - Displacement if fDisp8 or fDisp32 is TRUE */\r
1897 OpBase = 0;         /* int - Base register if fBase is true */\r
1898 OpIndx = 0;         /* int - Index register if fIndx is true */\r
1899 fOpImm = 0;                     /* No Immediate value yet */\r
1900 OpImm = 0;                      /* Default to 0 */\r
1901 fOpImm2 = 0;            /* No second Immediate value yet */\r
1902 OpImm2 = 0;                     /* Default to 0 */\r
1903 nFixUp = 0;                     /* Fixup type if needed, else 0 */\r
1904 nExtRef = 0;            /* GST entry if external ref was made */\r
1905 fForRef = 0;            /* No Forward Ref in crnt inst yet */\r
1906 ExpType = 0;            /* Type of symbol used in instruction */\r
1907 ExpType0 = 0;           /* Type of symbol used in instruction */\r
1908 iExpSym = 0;            /* Index into symtab for symbol if used */\r
1909 iExpSym0 = 0;           /* Index into symtab for symbol if used */\r
1910 \r
1911 if (GetOper(0)) {\r
1912         nOperands++;\r
1913         ExpType0 = ExpType;\r
1914         iExpSym0 = iExpSym;\r
1915         if ((Parse()== COMMA)) {\r
1916                 if (GetOper(1)) {\r
1917                         nOperands++;\r
1918                         if ((Parse()== COMMA)) {\r
1919                                 if (GetOper(2)) {\r
1920                                         nOperands++;\r
1921                                         if (Parse()) {\r
1922                                                 line_error(33);\r
1923                                                 return;\r
1924                                         }\r
1925                                 }\r
1926                     }\r
1927                 }\r
1928         }\r
1929 }\r
1930 \r
1931 /*\r
1932 At this point we have the instruction operands stored in\r
1933 tokenized form in arrays.  We now call EvalOper() which evaluates\r
1934 the operands and fills in several variables that will assist in\r
1935 building the instruction. EvalOper() returns 1 if it was a valid\r
1936 operand, else 0.\r
1937 */\r
1938 \r
1939 if (nOperands) {                                                                /* at least one */\r
1940         if (EvalOper(0)) {\r
1941                 if (nOperands > 1) {                                    /* a second operand */\r
1942                         if (EvalOper(1)) {\r
1943                                 if (nOperands > 2) {                    /* a third??? - could be... */\r
1944                                         if (!(EvalOper(2)))\r
1945                                                 fError = 1;\r
1946                                 }\r
1947                         }\r
1948                         else fError = 1;\r
1949             }\r
1950         }\r
1951         else fError = 1;\r
1952 }\r
1953 \r
1954 if (fError) return;\r
1955 \r
1956 /*\r
1957    We must check to see what the word size of the instruction is\r
1958    by looking at register sizes if any are included in the instruction.\r
1959    If there are memory references or immediates involved, OpSizeA\r
1960    MUST be set properly else it's an error!      When there is a symbol involved\r
1961    such as a move to a memory variable, we check the variable size and set\r
1962    the OpSize to the variable size. If it's still not set, the line will\r
1963    error out when we try to build the instruction because the caller\r
1964    should have explicitly set the size (e.g., DWORD PTR ...).\r
1965 \r
1966    If a register is one of the operands in a memory transfer\r
1967    (e.g., MOV [mem], EAX) then the move obviously defaults to the size\r
1968    of the register (no ifs, ands, or buts).\r
1969 \r
1970    If there is no reg involved, we then look at 'OpSize[i]'\r
1971    which may have been set by the size operators (e.g., DWORD PTR).\r
1972    If it's zero we look at iExpSym which was set if there was a single\r
1973    symbol involved in the memory reference. If there was, then we use it.\r
1974    If it is blank, we error out cause we don't know what size memory\r
1975    access we are doing!\r
1976    This is done for each operand then the two are compared. If one is\r
1977    zero we use the other, if both have something but are different\r
1978    we error out!\r
1979 \r
1980 */\r
1981         /* Find the first operand size */\r
1982 \r
1983         /* First, let's look to see if they forced it! */\r
1984 \r
1985         if  (OpSize[0] & (fByte|fWord|fDWord|fFWord))\r
1986 \r
1987         { /* do nothing */ }\r
1988 \r
1989         /* If they didn't force it, we'll look for the register size! */\r
1990 \r
1991     else if (rgOpType[0] == r32) OpSize[0] |= fDWord;\r
1992     else if (rgOpType[0] == r16) OpSize[0] |= fWord;\r
1993     else if (rgOpType[0] == rSEG) OpSize[0] |= fWord;\r
1994     else if (rgOpType[0] == r8) OpSize[0] |= fByte;\r
1995 \r
1996                 /* Still nothing, so let's at symbols.  */\r
1997 \r
1998         else if (ExpType0 == 1)\r
1999         {       /* Local symbol */\r
2000                 if (lst[iExpSym0].Type & sBYTE) OpSize[0] |= fByte;\r
2001                 else if (lst[iExpSym0].Type & sWORD) OpSize[0]  |= fWord;\r
2002                 else if (lst[iExpSym0].Type & sDWORD) OpSize[0] |= fDWord;\r
2003                 else if (lst[iExpSym0].Type & sFWORD) OpSize[0] |= fFWord;\r
2004         }\r
2005     else if (ExpType0 == 2)\r
2006         {   /* Global Symbol */\r
2007                 if (gst[iExpSym0].Type & sBYTE) OpSize[0] |= fByte;\r
2008                 else if (gst[iExpSym0].Type & sWORD) OpSize[0] |= fWord;\r
2009                 else if (gst[iExpSym0].Type & sDWORD) OpSize[0] |= fDWord;\r
2010                 else if (gst[iExpSym0].Type & sFWORD) OpSize[0] |= fFWord;\r
2011         }\r
2012         else if (ExpType0 == 3)\r
2013                 OpSize[0] |= fDWord;            /* $ defaults to DWord */\r
2014 \r
2015 \r
2016         /* Find the second operand size. Check "forced fit" first */\r
2017 \r
2018         if  (OpSize[1] & (fByte|fWord|fDWord|fFWord))\r
2019         { /* do nothing */ }\r
2020 \r
2021     else if (rgOpType[1] == r32) OpSize[1] |= fDWord;\r
2022     else if (rgOpType[1] == r16) OpSize[1] |= fWord;\r
2023     else if (rgOpType[1] == rSEG) OpSize[1] |= fWord;\r
2024     else if (rgOpType[1] == r8) OpSize[1] |= fByte;\r
2025 \r
2026                 /* No registers, so let's look to see if they forced it! */\r
2027 \r
2028                 /* Still nothing, so let's at symbols.  */\r
2029 \r
2030         else if (ExpType == 1)\r
2031         {       /* Local symbol */\r
2032                 if (lst[iExpSym].Type & sBYTE) OpSize[1] |= fByte;\r
2033                 else if (lst[iExpSym].Type & sWORD) OpSize[1]  |= fWord;\r
2034                 else if (lst[iExpSym].Type & sDWORD) OpSize[1] |= fDWord;\r
2035                 else if (lst[iExpSym].Type & sFWORD) OpSize[1] |= fFWord;\r
2036         }\r
2037     else if (ExpType == 2)\r
2038         {   /* Global Symbol */\r
2039                 if (gst[iExpSym].Type & sBYTE) OpSize[1] |= fByte;\r
2040                 else if (gst[iExpSym].Type & sWORD) OpSize[1] |= fWord;\r
2041                 else if (gst[iExpSym].Type & sDWORD) OpSize[1] |= fDWord;\r
2042                 else if (gst[iExpSym].Type & sFWORD) OpSize[1] |= fFWord;\r
2043         }\r
2044         else if (ExpType == 3)\r
2045                 OpSize[1] |= fDWord;            /* $ defaults to DWord */\r
2046 \r
2047     /* Special cases for operand size matching. */\r
2048 \r
2049         if (CrntInst == xOUT)\r
2050                 OpSize[0] = OpSize[1];\r
2051 \r
2052 \r
2053 /*\r
2054    Now that have the operands, and we know the TYPE of data (fByte etc.)\r
2055    we call INSEntry to find the matching\r
2056    entry in the array that describes each instruction. If we don't\r
2057    find one that matches we error out telling them they have bad\r
2058    operands.\r
2059 */\r
2060 \r
2061 /* find first matching entry in rgINS */\r
2062 \r
2063     iInstEntry = INSEntry(CrntInst, nOperands);\r
2064 \r
2065     if (!iInstEntry) {\r
2066         line_error(44);\r
2067         return;\r
2068     }\r
2069 \r
2070     /* Now we make sure that we have set all operand sizes\r
2071        and check for special cases as defined in rgINS.\r
2072         */\r
2073 \r
2074         if (rgINS[iInstEntry][7] & zSIZ)\r
2075         OpSize[1] = OpSize[0];\r
2076 \r
2077     if (!OpSize[1])\r
2078         OpSize[1] = OpSize[0];\r
2079 \r
2080     if (!OpSize[0])\r
2081         OpSize[0] = OpSize[1];\r
2082 \r
2083     /* Give them an error if operand sizes don't match */\r
2084 \r
2085     if (nOperands > 1)\r
2086         if (OpSize[0] != OpSize[1]) {\r
2087            line_error(43);\r
2088                return;\r
2089            }\r
2090 \r
2091         OpSizeA = OpSize[0];   /* Set primary operand size */\r
2092 \r
2093 /* If either the first or second operand was memory, we have to find\r
2094    which entry in rgM32 it matches before we can encode it. If none\r
2095    matches it is an invalid memory operand.  If neither is a mem operand\r
2096    we set iMemEntry to zero.  There is the special case of moffs type\r
2097    which is a short form of displacmement when moving data to and from thew\r
2098    accumulator (e.g., MOV EAX, VAR1).  We check for this and skip the\r
2099    mem check if this is the instruction type we are on.\r
2100 */\r
2101 \r
2102         if ((rgINS[iInstEntry][1] == moff) || (rgINS[iInstEntry][2] == moff))\r
2103                 iMemEntry = 0;\r
2104         else if ((rgOpType[0]==mem) ||\r
2105                          (rgOpType[1]==mem) ||\r
2106                          (rgOpType[0]==memF))\r
2107         {\r
2108 \r
2109                 for (i=1; i<nrgM32; i++) {\r
2110                         if (OpMType == rgM32[i][0]) break;\r
2111                 }\r
2112 \r
2113                 /* if i is off the end of the array we\r
2114                    didn't find an entry that matched\r
2115                 */\r
2116 \r
2117                 if (i==nrgM32) {\r
2118                         line_error(45);\r
2119                         return;\r
2120                 }\r
2121                         else iMemEntry = i;\r
2122         }\r
2123         else iMemEntry = 0;\r
2124 \r
2125 /*\r
2126  At this point we should have all information we need to actually\r
2127  encode the instruction (unless it's a forward ref). So we call EncodeInst.\r
2128 */\r
2129 \r
2130 EncodeInst();\r
2131 \r
2132 \r
2133 }\r
2134 \r
2135 \r
2136 /********************************************\r
2137    Create Storage in current segment. At this\r
2138    point we should see a storage statement as\r
2139    the current token followed by a number (or\r
2140    string if DB). If string (DB) we insert\r
2141    single byte values (one per char) into the\r
2142    segment.\r
2143 *********************************************/\r
2144 void Storage(void)\r
2145 {\r
2146 S32 TSave, NSave, nDUP;\r
2147 S16 i, j, sword;\r
2148 S8   fColon, fExpectColon, fComma, fDUP;\r
2149 U16 symtype;\r
2150 \r
2151 fDUP = 0;\r
2152 nDUP = 1;               /* default duplicate value */\r
2153 fComma = 0;\r
2154 fColon = 0;\r
2155 fExpectColon = 0;\r
2156 \r
2157 if (!fMoreStorage) {            /* is it a continuation of previous line? */\r
2158         switch(Token) {                 /* parse returns Token */\r
2159                 case rDB:\r
2160                         StoreSize = 1;\r
2161                 break;\r
2162             case rDW:\r
2163                 StoreSize = 2;\r
2164                 break;\r
2165             case rDD:\r
2166                 StoreSize = 4;\r
2167                 break;\r
2168                 case rDF:\r
2169                 StoreSize = 6;\r
2170                 break;\r
2171                 default:;\r
2172         }\r
2173 }\r
2174 \r
2175 /* Now we loop thru looking for strings and numbers taking into account\r
2176    the special case of DF which should be DWORD:WORD, and OFFSET\r
2177    which will be a DWORD.\r
2178 */\r
2179 \r
2180 while (1) {\r
2181         if (fMoreStorage) {\r
2182                 i = Token;\r
2183                 fMoreStorage = 0;\r
2184         }\r
2185         else i = Parse();\r
2186 \r
2187         switch(i) {\r
2188                 case STRING:\r
2189                         fComma=0;\r
2190                         if (StoreSize==1) {\r
2191                                 for(j=0; j<CBString; j++) {\r
2192                                         if (fListA) {\r
2193                                                 put_hexb(TString[j], lst_fh);\r
2194                                                 Column += 2;\r
2195                                                 Column += fprintf(lst_fh, "  ");\r
2196                                                 if (Column > 51) {\r
2197                                                         fprintf(lst_fh, "\r\n                ");\r
2198                                                         Column=16;\r
2199                                                 }\r
2200                                         }\r
2201                                         OutByte(TString[j]);\r
2202                                 }\r
2203                         }\r
2204                         else {\r
2205                                 line_error(46);\r
2206                                 return;\r
2207                         }\r
2208                         break;\r
2209                 case rOFFSET:\r
2210                         if (StoreSize != 4) {\r
2211                                 line_error(50);\r
2212                                 return;\r
2213                         }\r
2214                         /* fall thru to evaluate & store value */\r
2215                 case NUMBER:\r
2216                 case DOLLAR:    /* These should all evaluate to a number. */\r
2217                 case OPENRND:   /* If it's SYMOFF, we do a fixup or Forward Ref */\r
2218                 case MINUS:\r
2219                 case SYMBOL:\r
2220                 case LSYMBOL:\r
2221                 case UNKSYM:\r
2222                         fComma=0;\r
2223                         if (!(Expression()))    /* 0 means error was emmited. */\r
2224                                 return;\r
2225 \r
2226                         symtype = 0;            /* default to no symbol type */\r
2227                         nExtRef = 0;            /* default to no external ref */\r
2228 \r
2229                         if ((Token==SYMOFF) || (Token==NUMOFF))\r
2230                         {\r
2231                                 if (ExpType == 1)                               /* Local */\r
2232                                         symtype = lst[iExpSym].Type;\r
2233                                 else if (ExpType == 2) {                /* global */\r
2234                                         symtype = gst[iExpSym].Type;\r
2235                                         if (gst[iExpSym].Type & tEXTRN)\r
2236                                                 nExtRef = iExpSym;\r
2237                                 }\r
2238                         }\r
2239 \r
2240                         if (!fDUP) {\r
2241                                 NSave = TNumber;\r
2242                                 TSave = Token;\r
2243                                 if (Parse() == rDUP)\r
2244                                 {\r
2245                                         nDUP = NSave;\r
2246                                         fDUP = 1;\r
2247                     Parse();\r
2248                     if (Token == OPENRND) {\r
2249                                                 if (!(Expression()))    /* 0 means error was emitted.*/\r
2250                                                         return;\r
2251                                         }\r
2252                                         else\r
2253                                                 line_error(47);\r
2254                                         /* TNumber now has (VALUE) from DUP */\r
2255                                 }\r
2256                                 else {\r
2257                                         ReturnToken();\r
2258                                         TNumber = NSave;\r
2259                                         Token = TSave;\r
2260                                 }\r
2261                         }\r
2262 \r
2263                         if (StoreSize==6)\r
2264                         {\r
2265                                 if (fColon) {\r
2266                                         fColon=0;               /* reset it */\r
2267                                         if (fListA) {\r
2268                                                 sword = TNumber;\r
2269                                                 Column += 4;\r
2270                                                 put_hexw(sword, lst_fh);\r
2271                                                 Column += fprintf(lst_fh, " ");\r
2272                                                 }\r
2273                                         OutWord(TNumber);\r
2274                                 }\r
2275                                 else {\r
2276                                         fExpectColon = 1;\r
2277                                         if (fListA) {\r
2278                                                 Column += 8;\r
2279                                                 put_hexd(TNumber, lst_fh);\r
2280                                                 Column += fprintf(lst_fh, " ");\r
2281                                                 }\r
2282                                         OutDWord(TNumber);\r
2283                                 }\r
2284                         }\r
2285                         else if (StoreSize==4) {\r
2286                                 if (fDUP)\r
2287                                 {\r
2288                                         if (fListA) {\r
2289                                           if ((Token == SYMOFF) || (Token == NUMOFF))\r
2290                                             Column += fprintf(lst_fh, "%08lX * (%08lXr)",nDUP,TNumber);\r
2291                                           else\r
2292                                             Column += fprintf(lst_fh, "%08lX * (%08lX)",nDUP,TNumber);\r
2293                                         }\r
2294                                         while (nDUP--)\r
2295                                         {\r
2296                                                 if ((Token==SYMOFF) || (Token==NUMOFF))\r
2297                                                 {\r
2298                                                         if (fDataSeg) {         /* Data Seg */\r
2299                                                                 if (nExtRef)\r
2300                                                                         ExtRef(DSEGREF, iExpSym);\r
2301                                                                 else if (!symtype)\r
2302                                                                         ForRef(DSEGREF, oNextData);\r
2303                                                                 else if (symtype & CLABEL)\r
2304                                                                         FixUp(DCFIXTAG, oNextData, 0);\r
2305                                                                 else if (symtype & DLABEL)\r
2306                                                                         FixUp(DDFIXTAG, oNextData, 0);\r
2307                                                         }\r
2308                                                         else {                          /* Code Seg */\r
2309                                                                 if (nExtRef)\r
2310                                                                         ExtRef(CSEGREF, iExpSym);\r
2311                                                                 if (!symtype)\r
2312                                                                         ForRef(CSEGREF, oNextCode);\r
2313                                                                 else if (symtype & CLABEL)\r
2314                                                                         FixUp(CCFIXTAG, oNextCode, 0);\r
2315                                                                 else if (symtype & DLABEL)\r
2316                                                                         FixUp(CDFIXTAG, oNextCode, 0);\r
2317                                                         }\r
2318                                                 }\r
2319                                                 OutDWord(TNumber);\r
2320                                     }\r
2321                                 }\r
2322                                 else {\r
2323                                         if (fListA)\r
2324                                         {\r
2325                                           if ((Token == SYMOFF) || (Token == NUMOFF))\r
2326                                             Column += fprintf(lst_fh, " %08lXr", TNumber);\r
2327                                           else\r
2328                                             Column += fprintf(lst_fh, " %08lX", TNumber);\r
2329                                         }\r
2330 \r
2331                                         /* Fixup & Forref here! */\r
2332                                         if ((Token==SYMOFF) || (Token==NUMOFF))\r
2333                                         {\r
2334                                           if (fDataSeg)\r
2335                                           {                                     /* Data Seg */\r
2336                                                 if (nExtRef)\r
2337                                                         ExtRef(DSEGREF, iExpSym);\r
2338                                                 else if (!symtype)\r
2339                                                         ForRef(DSEGREF, oNextData);\r
2340                                                 else if (symtype & CLABEL)\r
2341                                                         FixUp(DCFIXTAG, oNextData, 0);\r
2342                                                 else if (symtype & DLABEL)\r
2343                                                         FixUp(DDFIXTAG, oNextData, 0);\r
2344                                           }\r
2345                                           else\r
2346                                           {                                     /* Code Seg */\r
2347                                                 if (nExtRef)\r
2348                                                         ExtRef(CSEGREF, iExpSym);\r
2349                                                 else if (!symtype)\r
2350                                                         ForRef(CSEGREF, oNextCode);\r
2351                                                 else if (symtype & CLABEL)\r
2352                                                         FixUp(CCFIXTAG, oNextCode, 0);\r
2353                                                 else if (symtype & DLABEL)\r
2354                                                         FixUp(CDFIXTAG, oNextCode, 0);\r
2355                                           }\r
2356                                         }\r
2357                                         OutDWord(TNumber);\r
2358                                 }\r
2359                         }\r
2360                         else if (StoreSize==2) {\r
2361                                 if (fDUP) {\r
2362                                         if (fListA)\r
2363                                           Column += fprintf(lst_fh, "%08lX * (%04lX) ",nDUP,TNumber);\r
2364                                         while (nDUP--)\r
2365                                                 OutWord(TNumber);\r
2366                                         }\r
2367                                 else {\r
2368                                         if (fListA)\r
2369                                                 Column += fprintf(lst_fh, "%04lX ", TNumber);\r
2370                                         OutWord(TNumber);\r
2371                                         }\r
2372                         }\r
2373                         else {\r
2374                                 if (fDUP) {\r
2375                                         if (fListA)\r
2376                                           Column += fprintf(lst_fh, "%08lX * (%02lX) ",nDUP,TNumber);\r
2377                                         while (nDUP--)\r
2378                                                 OutByte(TNumber);\r
2379                                         }\r
2380                                 else {\r
2381                                         if (fListA)\r
2382                                           Column += fprintf(lst_fh, "%02lX ", TNumber);\r
2383                                         OutByte(TNumber);\r
2384                                         }\r
2385                         }\r
2386                         break;\r
2387                 case COMMA:     /* Just eat the comma */\r
2388                         if (fComma) {\r
2389                                 line_error(48);\r
2390                                 return;\r
2391                         }\r
2392                         fComma = 1;\r
2393                         break;\r
2394                 case COLON:\r
2395                         fComma=0;\r
2396                         if ((StoreSize == 6) && (fExpectColon)) {\r
2397                                 fColon = 1;\r
2398                                 fExpectColon = 0;\r
2399                         }\r
2400                         else {\r
2401                                 line_error(49);\r
2402                                 return;\r
2403                         }\r
2404                         break;\r
2405                 case ZERO:\r
2406                         if (fComma)     fMoreStorage = 1;\r
2407                         return;\r
2408                 default: {\r
2409                         line_error(51);\r
2410                         fMoreStorage = 0;\r
2411                         return;\r
2412                         }\r
2413         }\r
2414 }\r
2415 }\r
2416 \r
2417 /********************************************\r
2418   Add new GLOBAL symbol to table (TString).\r
2419   Then parse again to hand off to\r
2420   proper function. This stores all\r
2421   Symbols UPPER case.\r
2422 *********************************************/\r
2423 void NewSymbol()\r
2424 {\r
2425 S16 i;\r
2426 S8   fColon, fStorage;\r
2427 \r
2428         if ((pSymNext + CBString) >= (pSymBuf + SYMBUFMAX))\r
2429                 fatal_error("Symbol buffer overflow...");\r
2430         if (iSymNext >= SYMSMAX)\r
2431                 fatal_error("Symbol table overflow...");\r
2432 \r
2433         strncpy(pSymNext, TString, CBString);\r
2434         gst[iSymNext].Size = CBString;\r
2435         gst[iSymNext].Type = 0;                         /* initialize type */\r
2436         gst[iSymNext].Ptr = pSymNext;\r
2437         gst[iSymNext].Line = lineno[level];\r
2438         gst[iSymNext].Offs = 0;\r
2439 \r
2440         /* All declarations that reach NewSymbol are either at\r
2441         level 0 or defined as PUBLIC or EXTERN. */\r
2442 \r
2443         if (fExtern)\r
2444                 gst[iSymNext].Type |= tEXTRN;\r
2445         else\r
2446                 gst[iSymNext].Type |= tPUBLIC;\r
2447 \r
2448         if (fFarLabel) gst[iSymNext].Type |= tFAR;\r
2449 \r
2450         if (fDataSeg) {\r
2451                 if (!fExtern)\r
2452                         gst[iSymNext].Offs = oNextData;\r
2453             gst[iSymNext].Type |= DLABEL;\r
2454         }\r
2455         else {\r
2456                 if (!fExtern)\r
2457                         gst[iSymNext].Offs = oNextCode;\r
2458                 gst[iSymNext].Type |= CLABEL;\r
2459         }\r
2460 \r
2461         /* update for next symbol */\r
2462         pSymNext += CBString;\r
2463         iSymNext++;\r
2464 \r
2465 \r
2466         /* Now, parse again and hand off. We have just added a symbol\r
2467         so expect to see an EQU, COLON or Storage statement.\r
2468         If we don't see one of these it's an error unless it's an extern.\r
2469         If we see a COLON we parse again and expect an instruction or EOL!\r
2470         */\r
2471 \r
2472         fStorage = 0;\r
2473         fColon=0;\r
2474         i = Parse();\r
2475 \r
2476         if (i == COLON) {\r
2477                 fColon = 1;\r
2478                 if (fDataSeg) {\r
2479                 line_error(49);\r
2480                     return;\r
2481                 }\r
2482                 i = Parse();\r
2483         }\r
2484 \r
2485         switch(i) {             /* parse returns Token */\r
2486                 case INSTRU:\r
2487                     if (fDataSeg) {\r
2488                         line_error(41);\r
2489                             return;\r
2490                         }\r
2491                         if (!fColon) {\r
2492                         line_error(54);\r
2493                             return;\r
2494                         }\r
2495                     Instruction();\r
2496                     break;\r
2497             case rDB:\r
2498                         gst[iSymNext-1].Type |= sBYTE;          /*  type */\r
2499                         fStorage = 1;\r
2500                         break;\r
2501             case rDW:\r
2502                         gst[iSymNext-1].Type |= sWORD;  /*  type */\r
2503                         fStorage = 1;\r
2504                         break;\r
2505             case rDD:\r
2506                         gst[iSymNext-1].Type |= sDWORD; /*  type */\r
2507                         fStorage = 1;\r
2508                         break;\r
2509                 case rDF:\r
2510                         if ((!fDataSeg) && (!fColon)) {\r
2511                                 line_error(54);\r
2512                                     return;\r
2513                                 }\r
2514                         gst[iSymNext-1].Type |= sFWORD; /*  type */\r
2515                         fStorage = 1;\r
2516                         break;\r
2517                 case rEQU:\r
2518                 line_error(55);\r
2519         /*              AddMacro(); */\r
2520                         break;\r
2521                 case COLON:\r
2522                         if (fExtern)\r
2523                         return;\r
2524                 case ZERO:\r
2525                         if ((fDataSeg) && (!fExtern))\r
2526                                 line_error(56);\r
2527                         break;\r
2528                 default:\r
2529                         if (fDataSeg)\r
2530                                 line_error(56);\r
2531           }\r
2532 \r
2533         if (gst[iSymNext-1].Type & tEXTRN)\r
2534                 fStorage = 0;\r
2535 \r
2536         if (fStorage)\r
2537                 Storage();\r
2538 }\r
2539 \r
2540 /********************************************\r
2541   This changes an EXTRN entry in the gst to\r
2542   a PUBLIC once we find it.  This checks to\r
2543   make sure the extern declaration was the\r
2544   same type as this public.\r
2545 *********************************************/\r
2546 \r
2547 void MakePublic(void)\r
2548 {\r
2549 S16 i;\r
2550 S8   fColon, fStorage;\r
2551 \r
2552         if (gst[TSymnum].Type & tPUBLIC) {\r
2553                 line_error(64);\r
2554                 return;\r
2555         }\r
2556 \r
2557         if ((fDataSeg) && (!(gst[TSymnum].Type & DLABEL))) {\r
2558                 line_error(69);\r
2559                 return;\r
2560         }\r
2561 \r
2562         if ((!fDataSeg) && (!(gst[TSymnum].Type & CLABEL))) {\r
2563                 line_error(69);\r
2564                 return;\r
2565         }\r
2566 \r
2567         gst[TSymnum].Type |= tPUBLIC;   /* Turn ON Public */\r
2568         gst[TSymnum].Type &= ~tEXTRN;   /* Turn off EXTERN */\r
2569 \r
2570         if (fDataSeg)\r
2571                 gst[TSymnum].Offs = oNextData;\r
2572         else\r
2573                 gst[TSymnum].Offs = oNextCode;\r
2574 \r
2575         /* Now, parse again and hand off. We have just added a symbol\r
2576         so expect to see an EQU, COLON or Storage statement.\r
2577         If we don't see one of these it's an error unless it's an extern.\r
2578         If we see a COLON we parse again and expect an instruction or EOL!\r
2579         */\r
2580 \r
2581 fStorage = 0;\r
2582 fColon=0;\r
2583 i = Parse();\r
2584 \r
2585 if (i == COLON) {\r
2586         fColon = 1;\r
2587         if (fDataSeg) {\r
2588         line_error(49);\r
2589             return;\r
2590         }\r
2591         i = Parse();\r
2592 }\r
2593 \r
2594 switch(i) {             /* parse returns Token */\r
2595         case INSTRU:\r
2596             if (fDataSeg) {\r
2597                 line_error(41);\r
2598                     return;\r
2599                 }\r
2600                 if (!fColon) {\r
2601                 line_error(54);\r
2602                     return;\r
2603                 }\r
2604             Instruction();\r
2605             break;\r
2606     case rDB:\r
2607                 gst[TSymnum].Type |= sBYTE;             /*  type */\r
2608                 fStorage = 1;\r
2609                 break;\r
2610     case rDW:\r
2611                 gst[TSymnum].Type |= sWORD;     /*  type */\r
2612                 fStorage = 1;\r
2613                 break;\r
2614     case rDD:\r
2615                 gst[TSymnum].Type |= sDWORD;    /*  type */\r
2616                 fStorage = 1;\r
2617                 break;\r
2618         case rDF:\r
2619                 if ((!fDataSeg) && (!fColon)) {\r
2620                         line_error(54);\r
2621                             return;\r
2622                         }\r
2623                 gst[TSymnum].Type |= sFWORD;    /*  type */\r
2624                 fStorage = 1;\r
2625                 break;\r
2626         case rEQU:\r
2627         line_error(55);\r
2628                 break;\r
2629         case COLON:\r
2630                 return;\r
2631         default:\r
2632                 if (fDataSeg)\r
2633                         line_error(56);\r
2634   }\r
2635 \r
2636 if (fStorage)\r
2637         Storage();\r
2638 \r
2639 }\r
2640 \r
2641 \r
2642 /********************************************\r
2643   This checks to ensure multiple externs are\r
2644   the same type when we run across them, and\r
2645   also that an extern is the same type if\r
2646   the public is already declared.\r
2647 *********************************************/\r
2648 void CheckExtern(void)\r
2649 {\r
2650         /* Check to make sure new extern and symbol are same type */\r
2651 \r
2652         if ((fDataSeg) && (!(gst[TSymnum].Type & DLABEL))) {\r
2653                 line_error(69);\r
2654                 return;\r
2655         }\r
2656 \r
2657         if ((!fDataSeg) && (!(gst[TSymnum].Type & CLABEL))) {\r
2658                 line_error(69);\r
2659                 return;\r
2660         }\r
2661 }\r
2662 \r
2663 \r
2664 /********************************************\r
2665   Add new LOCAL symbol to table (TString).\r
2666   Then parse again to hand off to\r
2667   proper function. This stores all\r
2668   Symbols UPPER case.\r
2669 *********************************************/\r
2670 void NewLSymbol(void)\r
2671 {\r
2672 S16 i;\r
2673 S8   fColon, fStorage;\r
2674 \r
2675 if ((pLSymNext + CBString) >= (pLSymBuf + LSYMBUFMAX))\r
2676         fatal_error("Local symbol buffer overflow...");\r
2677 if (iLSymNext >= LSYMSMAX)\r
2678         fatal_error("Local symbol table overflow...");\r
2679 \r
2680 strncpy(pLSymNext, TString, CBString);\r
2681 lst[iLSymNext].Size = CBString;\r
2682 lst[iLSymNext].Type = 0;                                /* initialize type */\r
2683 lst[iLSymNext].Ptr = pLSymNext;\r
2684 lst[iLSymNext].Line = lineno[level];\r
2685 \r
2686 if (fDataSeg) {\r
2687         lst[iLSymNext].Offs = oNextData;\r
2688         lst[iLSymNext].Type |= DLABEL;\r
2689         }\r
2690 else {\r
2691         lst[iLSymNext].Offs = oNextCode;\r
2692         lst[iLSymNext].Type |= CLABEL;\r
2693         }\r
2694 \r
2695 /* update for next symbol */\r
2696 pLSymNext += CBString;\r
2697 iLSymNext++;\r
2698 \r
2699 /* Now, parse again and hand off. We have just added a symbol\r
2700 so expect to see an EQU, COLON or Storage statement.\r
2701 If we don't see one of these it's an error!\r
2702 If we see a COLON we parse again and expect an instruction or EOL!\r
2703  */\r
2704 \r
2705 fStorage = 0;\r
2706 fColon=0;\r
2707 i = Parse();\r
2708 \r
2709 if (i == COLON) {\r
2710         fColon = 1;\r
2711         if (fDataSeg) {\r
2712         line_error(49);\r
2713             return;\r
2714         }\r
2715         i = Parse();\r
2716 }\r
2717 \r
2718 switch(i) {             /* parse returns Token */\r
2719         case INSTRU:\r
2720             if (fDataSeg) {\r
2721                 line_error(41);\r
2722                     return;\r
2723                 }\r
2724                 if (!fColon) {\r
2725                 line_error(54);\r
2726                     return;\r
2727                 }\r
2728             Instruction();\r
2729             break;\r
2730     case rDB:\r
2731                 lst[iLSymNext-1].Type |= sBYTE;         /*  type */\r
2732                 fStorage = 1;\r
2733                 break;\r
2734     case rDW:\r
2735                 lst[iLSymNext-1].Type |= sWORD; /*  type */\r
2736                 fStorage = 1;\r
2737                 break;\r
2738     case rDD:\r
2739                 lst[iLSymNext-1].Type |= sDWORD;        /*  type */\r
2740                 fStorage = 1;\r
2741                 break;\r
2742         case rDF:\r
2743                 if ((!fDataSeg) && (!fColon)) {\r
2744                         line_error(54);\r
2745                             return;\r
2746                         }\r
2747                 lst[iLSymNext-1].Type |= sFWORD;        /*  type */\r
2748                 fStorage = 1;\r
2749                 break;\r
2750         case rEQU:\r
2751                 AddMacro();\r
2752                 break;\r
2753         case COLON:\r
2754                 return;\r
2755         default:\r
2756                 if (fDataSeg)\r
2757                         line_error(56);\r
2758   }\r
2759 \r
2760 if (lst[iLSymNext-1].Type & tEXTRN)\r
2761         fStorage = 0;\r
2762 \r
2763 if (fStorage)\r
2764         Storage();\r
2765 \r
2766 }\r
2767 \r
2768 /*****************************************\r
2769  After we transition from level 1 back to\r
2770  level 0 we go back to the point in the\r
2771  code or data file where we began writing this\r
2772  section and resolve all forward code\r
2773  and local data references. These will be\r
2774  referenced in the module we just finished.\r
2775  ******************************************/\r
2776 \r
2777 void Resolve(void)\r
2778 {\r
2779 int i, isym;\r
2780 S32 Relative;\r
2781 S32 Partial;\r
2782 S32 AddFix;\r
2783 \r
2784         i = 0;\r
2785 \r
2786         while (i < iRefNext)  /* While there are forward references */\r
2787         {\r
2788                 if (pfrt[i].Type == DSEGREF)            /* Ref is in DSEG */\r
2789                 {\r
2790                         fseek(ds_fh, (pfrt[i].Offs - DataOffset) , SEEK_SET);\r
2791                         fread(&Partial, 4, 1, ds_fh);\r
2792                         fseek(ds_fh, (pfrt[i].Offs - DataOffset) , SEEK_SET);\r
2793                         AddFix = pfrt[i].Offs - DataOffset;\r
2794                 }\r
2795                 else    /* Ref is in CSEG */\r
2796                 {\r
2797                         fseek(cs_fh, (pfrt[i].Offs - CodeOffset) , SEEK_SET);\r
2798 \r
2799                         if (pfrt[i].Type == CSEGREF)     /* IT'S ABSOLUTE! */\r
2800                         {\r
2801                                 fread(&Partial, 4, 1, cs_fh);\r
2802                                 fseek(cs_fh, (pfrt[i].Offs - CodeOffset) , SEEK_SET);\r
2803                                 AddFix = pfrt[i].Offs - CodeOffset;\r
2804                         }\r
2805                 }\r
2806                 /* We are where we should write the reference\r
2807                    now we need to find it in the local symbol table\r
2808                    and calculate the proper offset.  The calculation\r
2809                    is different for Relative and absolute references.\r
2810                    For Relative, we subtract the address where the correction\r
2811                    is going to be stored from the offset of reference.\r
2812                    For Absolute, we read what was already at the address\r
2813                    and add it to the offset of the referenced item.\r
2814                    Both of these are also adjusted for the Virtual segment offset.\r
2815                 */\r
2816 \r
2817                 /* Look in the Local Symbol table first! */\r
2818 \r
2819                 isym = findLsymbol(pfrt[i].Ptr, pfrt[i].NameSz);\r
2820 \r
2821                 if (isym)               /* we found it! */\r
2822                 {\r
2823                         if (pfrt[i].Type == CCR8REF)            /* 8 bit relative */\r
2824                         {\r
2825                                 Relative = lst[isym].Offs - (pfrt[i].Offs - CodeOffset + 1);\r
2826                                 OutByteCS(Relative);\r
2827                         }\r
2828                         else if (pfrt[i].Type == CCR32REF) /* 32 bit relative */\r
2829                         {\r
2830                                 /* Fixed to make relatives ok in Virtual Segs */\r
2831 \r
2832                                 Relative = (lst[isym].Offs - CodeOffset) -\r
2833                                            (pfrt[i].Offs - CodeOffset + 4);\r
2834                                 OutDWordCS(Relative);\r
2835                         }\r
2836                         else if (pfrt[i].Type == CSEGREF)  /* 32 bit absolute */\r
2837                         {\r
2838                                 Partial += lst[isym].Offs;\r
2839 \r
2840                                 if (lst[isym].Type & CLABEL)\r
2841                                         FixUp(CCFIXTAG, AddFix, 0);\r
2842                                 else if (lst[isym].Type & DLABEL)\r
2843                                         FixUp(CDFIXTAG, AddFix, 0);\r
2844 \r
2845                                 OutDWordCS(Partial);\r
2846                         }\r
2847                         else if (pfrt[i].Type == DSEGREF)\r
2848                         {\r
2849                                 Partial += lst[isym].Offs;                      /* RAB was + DataOffset */\r
2850 \r
2851                                 if (lst[isym].Type & CLABEL)\r
2852                                         FixUp(DCFIXTAG, AddFix, 0);\r
2853                                 else if (lst[isym].Type & DLABEL)\r
2854                                         FixUp(DDFIXTAG, AddFix, 0);\r
2855 \r
2856                                 OutDWordDS(Partial);\r
2857                         }\r
2858                 }\r
2859                 else    /* Look in Global table */\r
2860                 {\r
2861 \r
2862                         isym = findGsymbol(pfrt[i].Ptr, pfrt[i].NameSz);\r
2863 \r
2864                         if (isym)\r
2865 \r
2866                         {               /* we found it! */\r
2867 \r
2868 \r
2869                                 if (pfrt[i].Type == CCR8REF) {          /* 8 bit relative */\r
2870                                         Relative = gst[isym].Offs - (pfrt[i].Offs - CodeOffset + 1);\r
2871                                         OutByteCS(Relative);\r
2872                                 }\r
2873                                 else if (pfrt[i].Type == CCR32REF) {  /*  32 bit relative */\r
2874                                         Relative = gst[isym].Offs - (pfrt[i].Offs - CodeOffset + 4);\r
2875                                         OutDWordCS(Relative);\r
2876                                 }\r
2877                                 else if (pfrt[i].Type == CSEGREF) {\r
2878                                         Partial += gst[isym].Offs;\r
2879 \r
2880                                         if (gst[isym].Type & CLABEL)\r
2881                                                 FixUp(CCFIXTAG, AddFix, 0);\r
2882                                         else if (gst[isym].Type & DLABEL)\r
2883                                                 FixUp(CDFIXTAG, AddFix, 0);\r
2884 \r
2885                                         OutDWordCS(Partial);\r
2886                                 }\r
2887                                 else if (pfrt[i].Type == DSEGREF)\r
2888                                 {\r
2889                                         Partial += gst[isym].Offs;\r
2890 \r
2891                                         if (gst[isym].Type & CLABEL)\r
2892                                                 FixUp(DCFIXTAG, AddFix, 0);\r
2893                                         else if (gst[isym].Type & DLABEL)\r
2894                                                 FixUp(DDFIXTAG, AddFix, 0);\r
2895 \r
2896                                         OutDWordDS(Partial);\r
2897                                 }\r
2898                         }\r
2899                         else\r
2900                                 prev_error("Unresolved symbol in current module", pfrt[i].Line);\r
2901                 }\r
2902                 i++;\r
2903         }\r
2904 \r
2905         fseek(cs_fh, 0L, SEEK_END);     /* Get back to the end! */\r
2906         fseek(ds_fh, 0L, SEEK_END);\r
2907 \r
2908 }\r
2909 \r
2910 /*****************************************\r
2911  When we have processed all the source\r
2912  we call this to resolve ALL externals.\r
2913  ******************************************/\r
2914 \r
2915 void ResolveExt(void)\r
2916 {\r
2917 int i, isym;\r
2918 S32 Relative;\r
2919 S32 Partial;\r
2920 S32 AddFix;\r
2921 char name[31];\r
2922 \r
2923 i = 0;\r
2924 Partial = 0;\r
2925 Relative = 0;\r
2926 AddFix = 0;\r
2927 \r
2928 while (i < iERefNext) { /* While there are unresolved externals */\r
2929 \r
2930         /* See if ref is in GST as PUBLIC */\r
2931 \r
2932         isym = ert[i].iSym;\r
2933 \r
2934         if (gst[isym].Type & tPUBLIC) {\r
2935 \r
2936                 if (ert[i].Type == DSEGREF) {                                   /* Ref is in DSEG */\r
2937 \r
2938                         fseek(ds_fh, (ert[i].Offs - DataOffset) , SEEK_SET);\r
2939                         fread(&Partial, 4, 1, ds_fh);\r
2940                         fseek(ds_fh, (ert[i].Offs - DataOffset) , SEEK_SET);\r
2941                         AddFix = ert[i].Offs - DataOffset;\r
2942                 }\r
2943                 else  {                                                                                 /* Ref is in CSEG */\r
2944 \r
2945                         fseek(cs_fh, (ert[i].Offs - CodeOffset) , SEEK_SET);\r
2946 \r
2947                         if (ert[i].Type == CSEGREF) {                    /* and IT'S ABSOLUTE! */\r
2948                                 fread(&Partial, 4, 1, cs_fh);\r
2949                                 fseek(cs_fh, (ert[i].Offs - CodeOffset) , SEEK_SET);\r
2950                                 AddFix = ert[i].Offs - CodeOffset;\r
2951                         }\r
2952                 }\r
2953                         /* We are where we should write the reference\r
2954                            now we need to use the index in the external ref\r
2955                            table to see if it has been defined PUBLIC.\r
2956                            If so, we resolve it, else we error out.\r
2957                            To resolve it, the calculation is different for Relative\r
2958                            and absolute references.\r
2959                            For Relative, we subtract the address where the correction\r
2960                            is going to be stored from the offset of reference.\r
2961                            For Absolute, we read what was already at the address\r
2962                            and add it to the offset of the referenced item.\r
2963                            Both of these are also adjusted for the Virtual segment offset.\r
2964                         */\r
2965 \r
2966                 if (ert[i].Type == CCR32REF) {  /*  32 bit relative */\r
2967 \r
2968                         /* Fixed to make relatives ok in Virtual Segs */\r
2969 \r
2970                         Relative = (gst[isym].Offs - CodeOffset) -\r
2971                                    (ert[i].Offs - CodeOffset + 4);\r
2972                         OutDWordCS(Relative);\r
2973                 }\r
2974                 else if (ert[i].Type == CSEGREF) {\r
2975                         Partial += gst[isym].Offs;\r
2976 \r
2977                         if (gst[isym].Type & DLABEL)\r
2978                                 FixUp(CDFIXTAG, AddFix, 0);\r
2979                         else if (gst[isym].Type & CLABEL)\r
2980                                 FixUp(CCFIXTAG, AddFix, 0);\r
2981 \r
2982                         OutDWordCS(Partial);\r
2983                 }\r
2984                 else if (ert[i].Type == DSEGREF) {\r
2985                         Partial += gst[isym].Offs;\r
2986 \r
2987                         if (gst[isym].Type & CLABEL)\r
2988                                 FixUp(DCFIXTAG, AddFix, 0);\r
2989                         else if (gst[isym].Type & DLABEL)\r
2990                                         FixUp(DDFIXTAG, AddFix, 0);\r
2991 \r
2992                         OutDWordDS(Partial);\r
2993                 }\r
2994         }\r
2995         else {\r
2996                 strncpy(name, gst[isym].Ptr, gst[isym].Size);\r
2997                 name[gst[isym].Size] = '\0';\r
2998                 fprintf(lst_fh, "Unresolved external: %s\n", name);\r
2999                 Column = 0;\r
3000                 ++error_count;\r
3001         }\r
3002 i++;\r
3003 }       /* while more Erefs */\r
3004 \r
3005 fseek(cs_fh, 0L, SEEK_END);     /* Get back to the end! */\r
3006 fseek(ds_fh, 0L, SEEK_END);\r
3007 \r
3008 }\r
3009 \r
3010 /*****************************************\r
3011   If there were no errors, and all looks\r
3012   well, we build the run file. This consists\r
3013   of building the required tags in order\r
3014   and writing them to the file with the\r
3015   data.\r
3016 ******************************************/\r
3017 \r
3018 void BuildRunFile(void)\r
3019 {\r
3020 unsigned char b;\r
3021 int i;\r
3022 long sdata;\r
3023 \r
3024         tag.id = IDTAG;                                         /* File type */\r
3025         tag.len = 1;\r
3026         fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
3027         fwrite(&filetype, 1, 1, run_fh);        /* Write the filetype */\r
3028 \r
3029         /* Version tag goes here */\r
3030         /* DatTime tag goes here */\r
3031         /* Comment tag(s) goes here */\r
3032 \r
3033         tag.id = SEGTAG;                                        /* Initial Segment Sizes */\r
3034         tag.len = 12;\r
3035         fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
3036         fwrite(&StackTotal, 4, 1, run_fh);      /* Write the Stacktotal */\r
3037         sdata = oNextCode - CodeOffset;         /* Size of CS.TMP */\r
3038         fwrite(&sdata, 4, 1, run_fh);           /* Write the Code Size */\r
3039         sdata = oNextData - DataOffset;         /* Size of DS.TMP */\r
3040         fwrite(&sdata, 4, 1, run_fh);           /* Write the Data Size */\r
3041 \r
3042         printf("Stack Size: %ld\r\n", StackTotal);\r
3043         printf("Code  Size: %ld\r\n", oNextCode - CodeOffset);\r
3044         printf("Data  Size: %ld\r\n", oNextData - DataOffset);\r
3045 \r
3046         tag.id = DOFFTAG;                                       /* Assumed Data Offset */\r
3047         tag.len = 4;\r
3048         fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
3049         fwrite(&DataOffset, 4, 1, run_fh);      /* Write the data */\r
3050 \r
3051         tag.id = COFFTAG;                                       /* Assumed Code Offset */\r
3052         tag.len = 4;\r
3053         fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
3054         fwrite(&CodeOffset, 4, 1, run_fh);      /* Write the data */\r
3055 \r
3056         tag.id = STRTTAG;                                       /* Starting Address */\r
3057         tag.len = 4;\r
3058         fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
3059         fwrite(&StartAddr, 4, 1, run_fh);       /* Write the data */\r
3060 \r
3061         tag.id = CODETAG;                                       /* Code Segment */\r
3062         tag.len = oNextCode - CodeOffset;       /* Size of CS.TMP */\r
3063         fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
3064 \r
3065         fseek(cs_fh, 0L , SEEK_SET);\r
3066         sdata = tag.len;\r
3067         while (sdata > 0) {\r
3068                 i = fread(line_buf0, 1, 200, cs_fh);\r
3069                 sdata -= i;\r
3070                 if (!i) break;\r
3071                 fwrite(line_buf0, 1, i, run_fh);\r
3072         }\r
3073 \r
3074         tag.id = DATATAG;                                       /* Data Segment */\r
3075         tag.len = oNextData - DataOffset;       /* Size of DS.TMP */\r
3076         fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
3077 \r
3078         fseek(ds_fh, 0L , SEEK_SET);\r
3079         sdata = tag.len;\r
3080         while (sdata > 0) {\r
3081                 i = fread(line_buf0, 1, 200, ds_fh);\r
3082                 sdata -= i;\r
3083                 if (!i) break;\r
3084                 fwrite(line_buf0, 1, i, run_fh);\r
3085         }\r
3086 \r
3087         if (nCDFix) {\r
3088                 tag.id = CDFIXTAG;                                      /* CSEG Data Fixups */\r
3089                 tag.len = nCDFix * 4;                           /* Count * 4 of Fixups */\r
3090                 fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
3091                 i = iFUNext;\r
3092                 while (i--) {                                           /* Write CD fixups */\r
3093                         if (pfut[i].type == CDFIXTAG)\r
3094                                 fwrite(&pfut[i].Offs, 1, 4, run_fh);\r
3095                 }\r
3096         }\r
3097 \r
3098         if (nCCFix) {\r
3099                 tag.id = CCFIXTAG;                                      /* CSEG Code Fixups */\r
3100                 tag.len = nCCFix * 4;                           /* Count * 4 of Fixups */\r
3101                 fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
3102                 i = iFUNext;\r
3103                 while (i--)     {                                               /* Write CC fixups */\r
3104                         if (pfut[i].type == CCFIXTAG)\r
3105                                 fwrite(&pfut[i].Offs, 1, 4, run_fh);\r
3106                 }\r
3107         }\r
3108 \r
3109         if (nDDFix) {\r
3110                 tag.id = DDFIXTAG;                                      /* DESG Data Fixups */\r
3111                 tag.len = nDDFix * 4;                           /* Count * 4 of Fixups */\r
3112                 fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
3113                 i = iFUNext;\r
3114                 while (i--)     {                                               /* Write DD fixups */\r
3115                         if (pfut[i].type == DDFIXTAG)\r
3116                                 fwrite(&pfut[i].Offs, 1, 4, run_fh);\r
3117                 }\r
3118         }\r
3119 \r
3120         if (nDCFix) {\r
3121                 tag.id = DCFIXTAG;                                      /* DESG Code Fixups */\r
3122                 tag.len = nDCFix * 4;                           /* Count * 4 of Fixups */\r
3123                 fwrite(&tag, 5, 1, run_fh);                     /* Write the tag record */\r
3124                 i = iFUNext;\r
3125                 while (i--)     {                                               /* Write DC fixups */\r
3126                         if (pfut[i].type == DCFIXTAG)\r
3127                                 fwrite(&pfut[i].Offs, 1, 4, run_fh);\r
3128                 }\r
3129         }\r
3130 \r
3131         /* DLL Address fixup tag goes here */\r
3132         /* DLL Public tag goes here */\r
3133 \r
3134         tag.id = ENDTAG;                                                /* End Tag */\r
3135         tag.len = 4;    /* Size of CS.TMP */\r
3136         fwrite(&tag, 5, 1, run_fh);                             /* Write the tag record */\r
3137         sdata = 0;\r
3138         fwrite(&sdata, 4, 1, run_fh);                   /* Write the tag record */\r
3139 \r
3140 }\r
3141 \r
3142 \r
3143 /*****************************************\r
3144     Reads a whole line into line buffer.\r
3145 ******************************************/\r
3146 \r
3147 S16 readline(void)\r
3148 {\r
3149 U32 i;\r
3150 U8 *pLine;\r
3151 \r
3152  if (!(fgets(line_ptr = line_buf0, 100, src_fh[level]))) {\r
3153 \r
3154         if (level) {    /* we are in a nested include */\r
3155                 fclose(src_fh[level]);\r
3156                 --level;\r
3157                 if (level==0) {         /* back up one level */\r
3158 \r
3159                         /* Processes forward references from this module */\r
3160                         Resolve();\r
3161 \r
3162                         if (fSymDump) {\r
3163                                 DumpLSymbols();\r
3164                                 DumpFRT();\r
3165                         }\r
3166 \r
3167                         /* Clear local symbol, forward refs, & macro tables */\r
3168 \r
3169                         iLSymNext = 1;  /* 1st entry.  */\r
3170                         pLSymNext = pLSymBuf; /* beginning of buffer */\r
3171 \r
3172                         iRefNext = 0;   /* 1st entry.  */\r
3173                         pRefNext = pRefBuf;             /* Allocate memory - Was RefBuf */\r
3174 \r
3175                         iMacNext = 0;                   /* 1st entry */\r
3176                         pMacNext = pMacBuf;             /* Begining of buffer */\r
3177 \r
3178 \r
3179                 }\r
3180                 if (fListA)\r
3181                         fprintf(lst_fh, "\r\n                ");\r
3182                 fprintf(lst_fh, "CONTINUING-> %s, Level:%d\r\n", srcname[level],level);\r
3183             fprintf(lst_fh, "\r\n");\r
3184 \r
3185                 if (lineno[level]) --lineno[level];\r
3186                 fContinue = 1;\r
3187                 }\r
3188         else {          /* We are at the end of the ATF file */\r
3189 \r
3190                 /* Processes forward references from Level 0 */\r
3191                 Resolve();\r
3192 \r
3193                 if (fSymDump) {\r
3194                         DumpGSymbols();\r
3195                         DumpFRT();\r
3196                 }\r
3197 \r
3198                 if (!fStart)\r
3199                         line_error(12); /* Starting address not found */\r
3200 \r
3201                 if (!error_count)\r
3202                         ResolveExt();\r
3203 \r
3204                 printf("%d Errors\r\n%d Warnings\r\n", error_count, warn_count);\r
3205 \r
3206                 if (fListA | fListE)\r
3207                         fprintf(lst_fh,"%d Errors\r\n%d Warnings\r\n",\r
3208                                         error_count,warn_count);\r
3209 \r
3210                 if (!error_count) {\r
3211                         printf("Building Run file...\n");\r
3212                         BuildRunFile();\r
3213                         printf("Done.\n");\r
3214                 }\r
3215 \r
3216                 fclose(lst_fh);\r
3217                 fclose(cs_fh);\r
3218                 fclose(ds_fh);\r
3219                 fclose(lst_fh);\r
3220                 fclose(src_fh[level]);\r
3221                 remove("CS.TMP");\r
3222                 remove("DS.TMP");\r
3223             exit(1);\r
3224             }\r
3225     }\r
3226 \r
3227  list_buf[0] = 0;\r
3228  if (fListA) {\r
3229          pLine = line_ptr;\r
3230          i=0;\r
3231          while (isspace(*pLine)) pLine++;\r
3232          while ((*pLine) && (*pLine != ';') && (*pLine != 0x0A))\r
3233                 list_buf[i++] = *pLine++;\r
3234          while ((i) && (list_buf[i-1] == ' ')) --i; /* eat trailing spaces */\r
3235          list_buf[i] = 0;                                                       /* null terminate */\r
3236          if (i) fLineIn = 1;\r
3237          else fLineIn = 0;\r
3238          }\r
3239  ++lineno[level];\r
3240  return(1);\r
3241 }\r
3242 \r
3243 \r
3244 /********************************************\r
3245    Dispatch calls Parse from the beginning\r
3246    of a line and calls the proper routine\r
3247    based on what it finds (from Parse()).\r
3248    Dispatch  calls readline to get a new line\r
3249    after each of the line-specific modules\r
3250    gets done with it's line or lines(s).\r
3251 *********************************************/\r
3252 \r
3253 void Dispatch(void)\r
3254 {\r
3255 S16 i, j;\r
3256 S8   st[80];\r
3257 \r
3258 while (1) {\r
3259   readline();\r
3260 \r
3261   if (fContinue) {              /* We have just returned from an include */\r
3262         fContinue = 0;          /* and must reread the line without processing */\r
3263         continue;\r
3264         }\r
3265 \r
3266   if (lineno[level] == 1) {\r
3267         if (fListA)\r
3268                 fprintf(lst_fh, "\r\n                ");\r
3269         fprintf(lst_fh, "PROCESSING-> %s, Level:%d\r\n", srcname[level], level);\r
3270         }\r
3271 \r
3272   if (fListA) {\r
3273       Column = fprintf(lst_fh, "%06d ", lineno[level]);\r
3274       }\r
3275 \r
3276   fPublic = 0;\r
3277   fExtern = 0;\r
3278   fFarLabel = 0;\r
3279 \r
3280   i = Parse();\r
3281   if (fMoreStorage)\r
3282         Storage();\r
3283   else switch (i) {\r
3284     case INSTRU:\r
3285                         if (fListA)\r
3286                                 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
3287                         Instruction();\r
3288                         break;\r
3289         case REGIST:\r
3290                         line_error(63);\r
3291                         break;\r
3292         case SYMBOL:\r
3293                         line_error(64);\r
3294                         break;\r
3295         case LSYMBOL:\r
3296                         line_error(65);\r
3297                         break;\r
3298         case STRING:\r
3299         case NUMBER:\r
3300                         line_error(66);\r
3301                         break;\r
3302         case rPUBLIC:\r
3303                         fPublic = 1;\r
3304                         if (fListA)\r
3305                                 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
3306                         j = Parse();\r
3307                         if (j==SYMBOL)\r
3308                                         MakePublic();\r
3309                         else if (j==UNKSYM)\r
3310                                 NewSymbol();\r
3311                         else\r
3312                                 line_error(67);\r
3313                         break;\r
3314         case rEXTRN:\r
3315                         fExtern = 1;\r
3316                         if (fListA)\r
3317                                 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
3318                         j = Parse();\r
3319                         if (j==SYMBOL)\r
3320                                         CheckExtern();\r
3321                         else if (j==UNKSYM)\r
3322                                 NewSymbol();\r
3323                         else\r
3324                                 line_error(67);\r
3325                         break;\r
3326         case UNKSYM:\r
3327                         if (fListA)\r
3328                                 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
3329                         if (level)\r
3330                                 NewLSymbol();\r
3331                         else\r
3332                                 NewSymbol();\r
3333                         break;\r
3334         case DOT:\r
3335                         Command();\r
3336                         break;\r
3337         case rDB:\r
3338         case rDD:\r
3339         case rDW:\r
3340         case rDF:\r
3341                 if (fListA)\r
3342                         Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
3343                 Storage();\r
3344                 break;\r
3345         case ZERO:\r
3346                 break;\r
3347         default:\r
3348                 line_error(68);\r
3349                 break;\r
3350         }\r
3351 \r
3352   if ((fLineIn) && (fListA)) {\r
3353           while (Column < 53) Column += fprintf(lst_fh, " ");\r
3354           fprintf(lst_fh, "%s", list_buf);\r
3355       }\r
3356   if (Column)\r
3357           fprintf(lst_fh, "\r\n");\r
3358 \r
3359  } /* while */\r
3360 }\r
3361 \r
3362 /*********************\r
3363 * Main program\r
3364 **********************/\r
3365 \r
3366 void main(S16 argc, S8  *argv[])\r
3367 {\r
3368 S8   *ptr, *pname;\r
3369 S16 i, j, fdone;\r
3370 \r
3371         lst_fh = stdout;        /* default the list file */\r
3372 \r
3373         for(i=1; i < argc; ++i) {\r
3374                 ptr = argv[i];\r
3375                 if (*ptr == '/') {\r
3376                   ptr++;\r
3377                   switch(*ptr) {\r
3378                         case 'L' :                      /* List file ON */\r
3379                         case 'l' :\r
3380                                 fListA = 1;\r
3381                                 break;\r
3382                         case 'S' :                      /* Dump Symbols */\r
3383                         case 's' :\r
3384                                 fSymDump = 1;\r
3385                                 break;\r
3386                         case 'E' :                      /* List file ON for errors/warns only */\r
3387                         case 'e' :\r
3388                                 fListE = 1;\r
3389                                 break;\r
3390                         case 'D' :                      /* Process as DLL */\r
3391                         case 'd' :\r
3392                                 filetype = 2;\r
3393                                 break;\r
3394                         case 'V' :                      /* Process as Devive Driver */\r
3395                         case 'v' :\r
3396                                 filetype = 3;\r
3397                                 break;\r
3398                         default:\r
3399                                 fatal_error("Invalid option\n");\r
3400                                 break;\r
3401                   }\r
3402                 }\r
3403                 else {\r
3404                         if(!src_fh[0]) {\r
3405                                 strncpy(srcname, argv[i], 39);\r
3406                                 src_fh[0] = fopen(argv[i], "r");\r
3407                                 }\r
3408                         else if(!run_fh) {\r
3409                                 strncpy(runname, argv[i], 39);\r
3410                                 if(!(run_fh = fopen(argv[i], "wb"))) {\r
3411                                   fatal_error("Can't open RUN file\n");\r
3412                                   }\r
3413                                 }\r
3414                         else\r
3415                                 fatal_error("Too many options\n"); /* Too many parameters */\r
3416            }\r
3417         }\r
3418 \r
3419 /* Input file not explicitly named errors out */\r
3420         if(!src_fh[0]) {\r
3421                 printf("Usage: ATFfile [RunFile] /L /E /D /V\r\n");\r
3422                 printf("/L = Complete List file generated\r\n");\r
3423                 printf("/S = Include SYMBOLS (only in complete list file)\r\n");\r
3424                 printf("/E = List file for Errors/warnings only\r\n");\r
3425                 printf("/D = Process as Dynamic link library\r\n");\r
3426                 printf("/V = Process as deVice driver\r\n");\r
3427                 fatal_error("Can't open Template file\n"); /* Can't open ATF file */\r
3428                 }\r
3429 \r
3430 /* Output file not explicitly named defaults to Source.RUN */\r
3431 \r
3432         if(!run_fh)     {                       /* default asm name to SourceName.run */\r
3433                 strncpy(runname, srcname, 40);\r
3434                 pname=runname;\r
3435                 while ((*pname != '.') && (*pname!= '\0')) pname++;\r
3436                 *pname++ = '.';\r
3437         if (filetype == 2) {\r
3438                  *pname++ = 'D';\r
3439                  *pname++ = 'L';\r
3440                  *pname++ = 'L';\r
3441         }\r
3442         else if (filetype == 3) {\r
3443                  *pname++ = 'D';\r
3444                  *pname++ = 'D';\r
3445                  *pname++ = 'R';\r
3446         }\r
3447         else {\r
3448          filetype = 1;\r
3449                  *pname++ = 'R';\r
3450                  *pname++ = 'U';\r
3451                  *pname++ = 'N';\r
3452                 }\r
3453                 *pname   = '\0';\r
3454                 if(!(run_fh = fopen(runname, "wb"))) {\r
3455                         fatal_error("Can't open OUTPUT file\n");  /* Can't open RUN file */\r
3456                         }\r
3457                 }\r
3458 \r
3459 /* List file named Source.LIS for fListA and fListE only. */\r
3460 \r
3461         if (fListA | fListE) {\r
3462                 strncpy(lstname, srcname, 40);\r
3463                 pname=lstname;\r
3464                 while ((*pname != '.') && (*pname!= '\0')) pname++;\r
3465                 *pname++ = '.';\r
3466                 *pname++ = 'L';\r
3467                 *pname++ = 'I';\r
3468                 *pname++ = 'S';\r
3469                 *pname   = '\0';\r
3470                 if(!(lst_fh = fopen(lstname, "w")))\r
3471                         fatal_error("Can't open list file (source.LIS)\n"); /* Can't open List file */\r
3472                 }\r
3473                 else\r
3474             lst_fh = stdout;\r
3475 \r
3476 printf("DASM-DOS Ver 1.6 (c) R.A. Burgess 1992,1993,1994\r\n\r\n");\r
3477 \r
3478 if (fListA | fListE)\r
3479         fprintf(lst_fh, "DASM-DOS Ver 1.6 (c) R.A. Burgess 1992, 1993, 1994\r\n\r\n");\r
3480 \r
3481 if (fListA)\r
3482         fprintf(lst_fh,\r
3483     "LINE   OFFSET   ACTION/DATA/CODE                     SOURCE\r\n\r\n");\r
3484 \r
3485         pLSymBuf = malloc(LSYMBUFMAX);\r
3486         if(!pLSymBuf)\r
3487                 fatal_error("Can't Allocate buffer 1\n");\r
3488 \r
3489         pSymBuf = malloc(SYMBUFMAX);\r
3490         if(!pSymBuf)\r
3491                 fatal_error("Can't Allocate buffer 2\n");\r
3492 \r
3493         pMacBuf = malloc(MACBUFMAX);\r
3494         if(!pMacBuf)\r
3495                 fatal_error("Can't Allocate buffer 3\n");\r
3496 \r
3497         pRefBuf = malloc(FREFBUFMAX);\r
3498         if(!pRefBuf)\r
3499                 fatal_error("Can't Allocate buffer 4\n");\r
3500 \r
3501         pfrt = malloc(FREFTABMAX);\r
3502         if(!pfrt)\r
3503                 fatal_error("Can't Allocate buffer 5\n");\r
3504 \r
3505         pfut = malloc(FIXUPBUFMAX);\r
3506         if(!pfut)\r
3507                 fatal_error("Can't Allocate buffer 6\n");\r
3508 \r
3509 pSymNext = pSymBuf;             /* Allocate memory - Was SymBuf */\r
3510 pLSymNext = pLSymBuf;   /* Allocate memory - Was LSymBuf */\r
3511 pMacNext = pMacBuf;             /* Allocate memory - Was MacBuf */\r
3512 pRefNext = pRefBuf;             /* Allocate memory - Was RefBuf */\r
3513 \r
3514 \r
3515 pNextAddr = &oNextData; /* default to DataSeg */\r
3516 \r
3517 if(!(cs_fh = fopen(csname, "wb+")))\r
3518         fatal_error("Can't open CS temp file\n");\r
3519 \r
3520 if(!(ds_fh = fopen(dsname, "wb+")))\r
3521         fatal_error("Can't open DS temp file\n");\r
3522 \r
3523 /* We now build a dynamic instruction lookup table which indexes\r
3524 the first entry of an instruction in the opcode array rgINS.\r
3525 This is done dynamically because we are still optimizing.\r
3526 */\r
3527 \r
3528 /* i is the instruction we are indexing */\r
3529 /* j is the position in rgINS */\r
3530 \r
3531 for (i=1; i<ninst+1; i++) {\r
3532         for (j=1; j<nrgINS; j++) {\r
3533                 if (rgINS[j][0] == i) {\r
3534                 rgInsLookUp[i] = j;\r
3535                 break;\r
3536                 }\r
3537         }\r
3538 }\r
3539 \r
3540 Dispatch();\r
3541 \r
3542 }\r