]> pd.if.org Git - mmurtl/blob - dasm/source/dasmq.c
autocommit for file dated 1995-02-09 16:00:32
[mmurtl] / dasm / source / dasmq.c
1 /* DASMQ.c contains procedures that are stable and are not\r
2   subject to change during debugging and development. They\r
3   have been moved out of the main module to reduce SCROLL Mania...\r
4 \r
5 */\r
6 \r
7 /******************************************\r
8 * Determine if a character is alphabetic\r
9 * or underscore. These can be used for first\r
10 * or subsequent chars in an identifier.\r
11 *******************************************/\r
12 \r
13 char is_ident(char chr)\r
14 {\r
15         return (isalpha(chr)) || (chr == '_');\r
16 }\r
17 \r
18 \r
19 /********************************************\r
20   Determine if character is "skip" character.\r
21   All values from 0x20 down to CTRL-A are\r
22   skipped.\r
23 *********************************************/\r
24 \r
25 char isskip(char chr)\r
26 {\r
27         if ((chr > 0) && (chr <= ' ')) return(1);\r
28         else return(0);\r
29 }\r
30 /**************************************\r
31   Write a Hex byte to a file fout.\r
32 ***************************************/\r
33 \r
34 void put_hexb(U8 value, FILE *fout)\r
35 {\r
36 S8  stack[10];\r
37 U16 i, j;\r
38 \r
39         i = 0; j = 2;\r
40         do {\r
41                 stack[i] = (value % 16) + '0';\r
42                 if (stack[i] > 0x39)\r
43             stack[i] += 7;\r
44                 i++;\r
45                 }\r
46         while(value /= 16);\r
47         while (i < j--) {                       /* zero pad front end to width */\r
48                 fputc('0', fout);\r
49                 }\r
50         while(i) {\r
51                 fputc(stack[--i], fout);\r
52                 }\r
53 }\r
54 \r
55 /**************************************\r
56   Write a Hex number to a file fout.\r
57 ***************************************/\r
58 \r
59 void put_hexw(U16 value, FILE *fout)\r
60 {\r
61 S8  stack[10];\r
62 U16 i, j;\r
63 \r
64         i = 0;\r
65         j = 4;\r
66         do {\r
67                 stack[i] = (value % 16) + '0';\r
68                 if (stack[i] > 0x39)\r
69             stack[i] += 7;\r
70                 i++;\r
71                 }\r
72         while(value /= 16);\r
73         while (i < j--) {                       /* zero pad front end to width */\r
74                 fputc('0', fout);\r
75                 }\r
76         while(i) {\r
77                 fputc(stack[--i], fout);\r
78                 }\r
79 }\r
80 \r
81 /**************************************\r
82   Write a hex dword to a file fout.\r
83 ***************************************/\r
84 \r
85 void put_hexd(U32 value, FILE *fout)\r
86 {\r
87 S8  stack[10];\r
88 U16 i, j;\r
89 \r
90         i = 0;\r
91         j = 8;\r
92         do {\r
93                 stack[i] = (value % 16) + '0';\r
94                 if (stack[i] > 0x39)\r
95             stack[i] += 7;\r
96                 i++;\r
97                 }\r
98         while(value /= 16);\r
99         while (i < j--) {                       /* zero pad front end to width */\r
100                 fputc('0', fout);\r
101                 }\r
102         while(i) {\r
103                 fputc(stack[--i], fout);\r
104                 }\r
105 }\r
106 \r
107 \r
108 /*************************************\r
109   Acquires VALUE for Expression()\r
110 *************************************/\r
111 int expr4(long *val)\r
112 {\r
113 int k;\r
114 \r
115 if (Token == rOFFSET) {\r
116         fOffset = 1;\r
117         Parse();\r
118         }\r
119 \r
120 if (Token == OPENRND) {                 /* Open paren */\r
121         Parse();\r
122         k=expr1(val);\r
123         if (Token == CLOSRND) {\r
124                 Parse();\r
125                 }\r
126         else{\r
127                 line_error(1);\r
128                 return(0);\r
129                 }\r
130         }\r
131 else if (Token == NUMBER) {\r
132         *val = TNumber;\r
133         Parse();                                /* set up for next token check */\r
134         }\r
135 else if (Token == LSYMBOL) {\r
136         nExpSyms++;\r
137         *val = lst[TSymnum].Offs;\r
138         iExpSym = TSymnum;              /* so we can trace symbol number came from */\r
139         ExpType = 1;\r
140         Parse();                                /* set up for next token check */\r
141         }\r
142 else if (Token == SYMBOL) {\r
143         nExpSyms++;\r
144         *val = gst[TSymnum].Offs;\r
145         iExpSym = TSymnum;              /* so we can trace symbol number came from */\r
146         ExpType = 2;\r
147         Parse();                                /* set up for next token check */\r
148         }\r
149 else if (Token == UNKSYM) {\r
150         nExpSyms++;\r
151         *val = 0;                               /* No offset for UNKSYM */\r
152         iExpSym =0;\r
153         ExpType = 0;                    /* 0 means forward ref. No Assumption. */\r
154 \r
155         /* Save name for forward reference */\r
156         strncpy(UString, TString, 30);\r
157         if (CBString > 30)\r
158                 UCBString = 30;\r
159         else\r
160                 UCBString = CBString;                   /* Size of Unknown label */\r
161         UString[UCBString] = '\0';                      /* Null terminate */\r
162 \r
163         Parse();                                /* set up for next token check */\r
164         }\r
165 else if (Token == DOLLAR) {\r
166         if (fDataSeg)\r
167                 *val = oNextData;\r
168         else\r
169                 *val = oNextCode;\r
170         ExpType = 3;\r
171         Parse();                                /* set up for next token check */\r
172         }\r
173 else{\r
174         line_error(2);\r
175         return(0);\r
176         }\r
177 return(1);\r
178 }\r
179 \r
180 /*****************************************\r
181  Evaluates a UNARY MINUS for Expression()\r
182 *****************************************/\r
183 int expr3(long *val)\r
184 {\r
185 int k;\r
186 \r
187 if (Token == MINUS) {           /* Unary MINUS */\r
188         Parse();                                /* set up for next token check */\r
189         k=expr4(val);\r
190         if (k) {\r
191                 *val = -(*val);\r
192                 return(1);\r
193                 }\r
194         else {\r
195                 line_error(3);\r
196                 return(0);\r
197                 }\r
198         }\r
199 else {\r
200         k = expr4(val);\r
201         return(k);\r
202         }\r
203 }\r
204 \r
205 \r
206 /*************************************\r
207  Evaluates a * and / Expression()\r
208 *************************************/\r
209 int expr2(long *val)\r
210 {\r
211 int k;\r
212 long val2;\r
213 \r
214 k=expr3(val);\r
215 if ((Token != STAR) && (Token != SLASH))\r
216         return(k);\r
217 while(1) {\r
218         if (Token == STAR) {            /* MULTIPLY */\r
219                 Parse();                                /* set up for next token check */\r
220                 if(expr2(&val2))\r
221                         *val *= val2;\r
222                 }\r
223         else if (Token == SLASH) {      /* DIVIDE */\r
224                 Parse();                                /* set up for next token check */\r
225                 if(expr2(&val2))\r
226                         *val /= val2;\r
227                 }\r
228         else return(1);  /* Expr doesn't continue but it's OK to here */\r
229 }\r
230 }\r
231 \r
232 /*************************************\r
233   Evaluates a + and - for Expression()\r
234 *************************************/\r
235 int expr1(long *val)\r
236 {\r
237 int k;\r
238 long val2;\r
239 \r
240 k=expr2(val);\r
241 if ((Token != PLUS) && (Token != MINUS)) return(k);\r
242 while(1) {\r
243         if (Token == PLUS) {\r
244                 Parse();\r
245                 if (Token==REGIST) return(1);   /* allow for N+REG */\r
246                 if(expr2(&val2))\r
247                         *val += val2;\r
248                 else return(0);\r
249                 }\r
250         else if (Token == MINUS) {\r
251                 Parse();\r
252                 if (Token==REGIST) return(1);   /* allow for N+REG */\r
253                 if(expr2(&val2))\r
254                         *val -= val2;\r
255                 else return(0);\r
256                 }\r
257         else return(1);  /* Expr doesn't continue but it's OK to here */\r
258 }\r
259 }\r
260 \r
261 /*******************************************\r
262   Expression is called to evaluate a math\r
263   expression made of constants, and/or\r
264   address labels (offsets).\r
265   Uses functions expr1 - expr4 recursively\r
266   to handle parenthetical expressions\r
267   while keeping standard math operator\r
268   precedence correct. Exits with (0) if error\r
269   in expression is encountered. Exits with\r
270   1 if value is left in TNumber.  If a NON\r
271   math Token is encountered but expression\r
272   was OK to that point, it calls ReturnToken\r
273   and leaves the currenly evaluated number\r
274   as the current token.\r
275 \r
276   If a single symbol or a single "current address"\r
277   opeator ($) is used in the expression, it will\r
278   return with SYMOFF as the Token type with the\r
279   offset value in TNumber, and the symbol\r
280   in TSymnum. If the OFFSET operator is used,\r
281   it will return with the offset in TNumber\r
282   and it will be a NUMOFF.\r
283   If more than 1 symbol or the\r
284   current address operator ($) and a symbol\r
285   is used it will assume a simple numeric\r
286   value from the computation and return\r
287   NUMBER as it's token.\r
288 ********************************************/\r
289 \r
290 int Expression(void)\r
291 {\r
292 long val;\r
293 \r
294 /* iExpSym = 0; */\r
295 nExpSyms = 0;\r
296 fOffset = 0;\r
297 \r
298 if (expr1(&val)) {\r
299 \r
300     if (Token)                  /* if not EOL (EOL returns 0) */\r
301                 ReturnToken();  /*   give back non-expression token */\r
302         if (nExpSyms == 1) {\r
303                 if (fOffset)\r
304                         Token = NUMOFF; /* Derived from OFFSET cmd */\r
305                 else\r
306                         Token = SYMOFF; /* single address operator used (Mem Type) */\r
307         }\r
308         else\r
309                 Token = NUMBER; /* Make current token a NUMBER */\r
310 \r
311         TSymnum = iExpSym;      /* We can tell where number came from */\r
312         TNumber = val;          /* Tell em what it is */\r
313         return(1);                      /* Tell em they got one */\r
314 }\r
315 else return(0);                 /* Tell em they got an error */\r
316 }\r
317 \r
318 /*****************************************************\r
319    Determines if token is 32 bit general register.\r
320 *****************************************************/\r
321 int is_r32(int id)\r
322 {\r
323 switch (id) {\r
324         case rEAX:\r
325         case rEBX:\r
326         case rECX:\r
327         case rEDX:\r
328         case rESI:\r
329         case rEDI:\r
330         case rEBP:\r
331         case rESP: return(1);\r
332         default:   return(0);\r
333   }\r
334 }\r
335 \r
336 /*****************************************************\r
337    Determines if token is 16 bit general.\r
338 *****************************************************/\r
339 int is_r16(int id)\r
340 {\r
341 switch (id) {\r
342         case rAX:\r
343         case rBX:\r
344         case rCX:\r
345         case rDX:\r
346         case rSI:\r
347         case rDI:\r
348         case rBP:\r
349         case rSP: return(1);\r
350         default:  return(0);\r
351   }\r
352 }\r
353 \r
354 /*****************************************************\r
355    Determines if token is 8 bit general register.\r
356 *****************************************************/\r
357 int is_r8(int id)\r
358 {\r
359 switch (id) {\r
360         case rAL:\r
361         case rBL:\r
362         case rCL:\r
363         case rDL:\r
364         case rAH:\r
365         case rBH:\r
366         case rCH:\r
367         case rDH: return(1);\r
368         default:  return(0);\r
369   }\r
370 }\r
371 \r
372 /*****************************************************\r
373    Determines if token is Segment Register.\r
374 *****************************************************/\r
375 int is_rSEG(int id)\r
376 {\r
377 switch (id) {\r
378         case rDS:\r
379         case rES:\r
380         case rCS:\r
381         case rFS:\r
382         case rGS:\r
383         case rSS: return(1);\r
384         default:   return(0);\r
385   }\r
386 }\r
387 \r
388 /*****************************************************\r
389    Determines if token is Debug register.\r
390 *****************************************************/\r
391 int is_rDRG(int id)\r
392 {\r
393 switch (id) {\r
394         case rDR0:\r
395         case rDR1:\r
396         case rDR2:\r
397         case rDR3:\r
398         case rDR6:\r
399         case rDR7: return(1);\r
400         default:   return(0);\r
401   }\r
402 }\r
403 \r
404 /*****************************************************\r
405    Determines if token is Control register.\r
406 *****************************************************/\r
407 int is_rCRG(int id)\r
408 {\r
409 return ((id == rCR0) || (id == rCR2) || (id == rCR3));\r
410 }\r
411 \r
412 /*****************************************************\r
413    Determines if token is Test register.\r
414 *****************************************************/\r
415 int is_rTRG(int id)\r
416 {\r
417 return ((id == rTR6) || (id == rTR7));\r
418 }\r
419 \r
420 /*****************************************************\r
421    Determines if operand entry in instruction (ins) is\r
422    compatible with the operand type the user gave (op).\r
423    An entry of 0 may match which means there is no\r
424    operand.\r
425 *****************************************************/\r
426 \r
427 \r
428 int is_Comp(int ins, int op)\r
429 {\r
430 switch (rgINS[ins][op+1]) {     /* check against op type in instruction */\r
431     case 0:\r
432         if (!rgOpType[op]) return(1);   /* no operand in either matches */\r
433                 break;\r
434     case rel8:\r
435         if (rgOpType[op] == rel8) return(1);\r
436         break;\r
437     case relW:\r
438         if (rgOpType[op] == relW) return(1);\r
439         break;\r
440     case iSAD:\r
441         if (rgOpType[op] == r8) return(1);\r
442         break;\r
443     case r8:\r
444         if (rgOpType[op] == r8) return(1);\r
445         break;\r
446     case r16:\r
447         if (rgOpType[op] == r16) return(1);\r
448         break;\r
449     case r32:\r
450         if (rgOpType[op] == r32) return(1);\r
451         break;\r
452     case rREG:\r
453         if ((rgOpType[op] == r8) ||\r
454             (rgOpType[op] == r16) ||\r
455             (rgOpType[op] == r32)) return(1);\r
456         break;\r
457     case rRGW:\r
458         if ((rgOpType[op] == r16) ||\r
459             (rgOpType[op] == r32)) return(1);\r
460         break;\r
461     case rACC:\r
462         if (((rgOpType[op] == r8) && (rgOpReg[op] == rAL)) ||\r
463             ((rgOpType[op] == r16) && (rgOpReg[op] == rAX)) ||\r
464             ((rgOpType[op] == r32) && (rgOpReg[op] == rEAX)))\r
465         return(1);\r
466         break;\r
467     case rSEG:\r
468         if (rgOpType[op] == rSEG) return(1);\r
469         break;\r
470     case rCRG:\r
471         if (rgOpType[op] == rCRG) return(1);\r
472         break;\r
473     case rDRG:\r
474         if (rgOpType[op] == rDRG) return(1);\r
475         break;\r
476     case rTRG:\r
477         if (rgOpType[op] == rTRG) return(1);\r
478         break;\r
479     case imm8:\r
480         if (rgOpType[op] == val8)\r
481             return(1);\r
482 \r
483         if ((rgOpType[op] == val16) &&\r
484             (OpImm < 256) &&\r
485             (OpImm >= 0))\r
486             return(1);\r
487 \r
488         break;\r
489     case ims8:  /* This is where a byte in an instruction\r
490                 will be sign extended. We will only allow byte values\r
491                             between -128 and 127 to be compatible here. This is because\r
492                             they can put AND EAX, A0h and we have to assume they DON'T\r
493                             want it extended into a negative 32 bit integer such as 0FFFFFFA0h.\r
494                         */\r
495         if (rgOpType[op] == val8)\r
496             return(1);\r
497 \r
498         if ((rgOpType[op] == val16) &&\r
499             (OpImm < 128) &&\r
500             (OpImm >= 0))\r
501             return(1);\r
502 \r
503         break;\r
504     case imm16:\r
505         if ((rgOpType[op] == val8) ||\r
506             (rgOpType[op] == val16)) return(1);\r
507         break;\r
508     case immX:\r
509         if ((rgOpType[op] == val8) ||\r
510             (rgOpType[op] == val16) ||\r
511             (rgOpType[op] == val32)) return(1);\r
512         break;\r
513     case rm8:\r
514         if ((rgOpType[op] == r8) ||\r
515             ((rgOpType[op] == mem) && (OpSize[op] & fByte))) return(1);\r
516         break;\r
517     case rm16:\r
518         if ((rgOpType[op] == r16) ||\r
519             ((rgOpType[op] == mem) && (OpSize[op] & fWord)) ) return(1);\r
520         break;\r
521     case rRM:\r
522         if ((rgOpType[op] == r8) ||\r
523             (rgOpType[op] == r16) ||\r
524             (rgOpType[op] == r32) ||\r
525             (rgOpType[op] == mem)) return(1);\r
526         break;\r
527     case rRMW:\r
528                 if (rgOpType[op] == mem)\r
529                 {\r
530                         if (OpSize[op] & fFWord)\r
531                                 return(0);\r
532                         if (OpSize[op] & fByte)\r
533                                 return(0);\r
534                         return(1);\r
535                 }\r
536         if ((rgOpType[op] == r16) ||\r
537              (rgOpType[op] == r32))\r
538              return(1);\r
539                 break;\r
540         case mem:\r
541                 if ((rgOpType[op] == mem) && (!(OpSize[op] & fFWord))) return(1);\r
542                 break;\r
543         case memF:\r
544                 if ((rgOpType[op] == memF) && (OpSize[op] & fFWord)) return(1);\r
545                 break;\r
546     case moff:\r
547         if ((rgOpType[op] == mem) &&\r
548                 (OpMType & fDisp32)  &&\r
549                 ((OpMType & fIndx)==0) &&\r
550                 ((OpMType & fBase)==0))\r
551         return(1);\r
552         break;\r
553     case immv3:\r
554         if ((rgOpType[op] == val8) &&\r
555             (OpImm == 3)) return(1);\r
556         break;\r
557     case immv1:\r
558         if ((rgOpType[op] == val8) &&\r
559             (OpImm == 1)) return(1);\r
560         break;\r
561     case rDX:\r
562         if ((rgOpType[op] == r16) &&\r
563             (rgOpReg[op] == rDX)) return(1);\r
564         break;\r
565     case rCL:\r
566         if ((rgOpType[op] == r8) &&\r
567             (rgOpReg[op] == rCL)) return(1);\r
568         break;\r
569     case rAL:\r
570         if ((rgOpType[op] == r8) &&\r
571             (rgOpReg[op] == rAL)) return(1);\r
572         break;\r
573     case rAX:\r
574         if ((rgOpType[op] == r16) &&\r
575             (rgOpReg[op] == rAX)) return(1);\r
576         break;\r
577     case rEAX:\r
578         if ((rgOpType[op] == r32) &&\r
579             (rgOpReg[op] == rEAX)) return(1);\r
580         break;\r
581     case rCS:\r
582     case rSS:\r
583     case rDS:\r
584     case rES:\r
585     case rFS:\r
586     case rGS:\r
587         if ((rgOpType[op] == rSEG) &&\r
588             (rgOpReg[op] == rgINS[ins][op+1])) return(1);\r
589         break;\r
590         default:;\r
591         }\r
592 return(0);\r
593 }\r
594 \r
595 /*****************************************************\r
596    Determines if entry in rgOpType is a register.\r
597 *****************************************************/\r
598 \r
599 int is_Reg(int op)\r
600 {\r
601         switch (op) {   /* This should be the value from rgOpType[x] */\r
602                 case r8:\r
603             case r16:\r
604             case r32:\r
605             case rCRG:\r
606             case rDRG:\r
607             case rTRG:\r
608                 return(1);\r
609                 default:;\r
610         }\r
611         return(0);\r
612 }\r
613 \r
614 \r
615 /*********************************************\r
616 This displays the string and exits for a FATAL\r
617 assembler error.\r
618 **********************************************/\r
619 \r
620 void fatal_error(S8   *pst)\r
621 {\r
622 \r
623 ++error_count;\r
624 \r
625 if (fListA | fListE) {\r
626         fprintf(lst_fh, "\r\nFATAL ERROR, line %ld - %s\r\n", lineno[level], pst);\r
627 \r
628 /*\r
629         DumpGSymbols();\r
630         DumpLSymbols();\r
631 */\r
632         fclose(lst_fh);\r
633         }\r
634 \r
635 printf("\r\nFATAL ERROR, line %ld - %s\r\n", lineno[level], pst);\r
636 printf("%d Errors\r\n%d Warnings\r\n", error_count, warn_count);\r
637 \r
638 /* close all files here and delete temps */\r
639         fclose(cs_fh);\r
640         fclose(ds_fh);\r
641 \r
642 exit(1);\r
643 }\r
644 \r
645 /*********************************************\r
646 This displays the string and line number for\r
647 non-fatal errors.\r
648 **********************************************/\r
649 \r
650 void line_error(int num)\r
651 {\r
652 S8 *p;\r
653 \r
654         switch (num) {\r
655         case  1: p="Invalid expression, ')' expected";          break;\r
656         case  2: p="Invalid expression, value expected";        break;\r
657         case  3: p="Value expected after unary '-'";            break;\r
658         case  4: p="Too many digits for numeric radix";         break;\r
659         case  5: p="Invalid character in a number";                     break;\r
660         case  6: p="Unterminated string";                                       break;\r
661         case  7: p="Unrecognized character";                            break;\r
662         case  8: p="Invalid Alignment specified";                       break;\r
663         case  9: p="Start command only allowed in CSEG";                break;\r
664         case 10: p="Virtual command must be first in segment";  break;\r
665         case 11: p="Invalid Virtual value";                                     break;\r
666         case 12: p="Starting address not found";                        break;\r
667         case 13: p="Stack command not allowed in DSEG";         break;\r
668         case 14: p="Invalid command";                                           break;\r
669         case 15: p="Invalid Operand";                                           break;\r
670         case 16: p="Invalid segment register use";                      break;\r
671         case 17: p="Invalid scale value 'Reg*?'";                       break;\r
672         case 18: p="Scale value expected (*2,*4,*8)";           break;\r
673         case 19: p="Too many address scale values";                     break;\r
674         case 20: p="Invalid register for memory operand";       break;\r
675         case 21: p="Invalid memory operand";                            break;\r
676         case 22: p="Offset must be from data segment";          break;\r
677         case 23: p="Nested brackets";                                           break;\r
678         case 24: p="Unbalanced brackets";                                       break;\r
679         case 25: p="Invalid operand size attribute";            break;\r
680         case 26:\r
681         case 27:\r
682         case 28:\r
683         case 29:\r
684         case 30:\r
685         case 31: p="";                                                                                  break;\r
686         case 32: p="Unknown token in operand array";                    break;\r
687         case 33: p="Too many operands or extra character";              break;\r
688         case 34: p="";                                                                                  break;\r
689         case 35: p="Invalid expression or numeric value";       break;\r
690         case 36: p="Operand expected before comma";                             break;\r
691         case 37: p="";                                                                                  break;\r
692         case 38: p="Invalid character or reserved word in operand";     break;\r
693         case 39: p="Relative jump out of range";                                        break;\r
694         case 40: p="Operand size NOT specified or implied";                     break;\r
695         case 41: p="Instructions not allowed in data segment";          break;\r
696         case 42: p="Instruction expected after prefix";                         break;\r
697         case 43: p="Operand sizes don't match";                                         break;\r
698         case 44: p="Wrong operand type for instruction";                        break;\r
699         case 45: p="Incorrect format for memory operand";                       break;\r
700         case 46: p="Strings only valid for DB storage";                         break;\r
701         case 47: p="Expected '(' after 'DUP'";                                          break;\r
702         case 48: p="Storage expected between commas";                           break;\r
703         case 49: p="':' not expected";                                                          break;\r
704         case 50: p="DWord storage required for OFFSET";                         break;\r
705         case 51: p="Invalid storage value";                                                     break;\r
706         case 52:\r
707         case 53: p="";                                                                                          break;\r
708         case 54: p="':' expected after last label";                                     break;\r
709         case 55: p="Macro not allowed in lexical level 0";                      break;\r
710         case 56: p="EQU or Storage expected";                                           break;\r
711         case 57:\r
712         case 58:\r
713         case 59:\r
714         case 60:\r
715         case 61:\r
716         case 62: p="";                                                                                          break;\r
717         case 63: p="Instruction expected before register name";         break;\r
718         case 64: p="Public Symbol already defined";                                     break;\r
719         case 65: p="Local symbol already defined";                                      break;\r
720         case 66: p="Number not expected";                                                       break;\r
721         case 67: p="New symbol must follow PUBLIC keyword";                     break;\r
722         case 68: p="Label, Command, Instruction, or Storage expected";  break;\r
723         case 69: p="Inconsistant redeclaration";                                                break;\r
724         case 70: p="";                                                                                                  break;\r
725         default:\r
726                 break;\r
727     }\r
728 \r
729   fprintf(lst_fh, "\r\nERROR: %d, line: %ld, %s\r\n", num, lineno[level], p);\r
730   *line_ptr = 0;                                /* this KILLS the rest of the line */\r
731   Column = 0;\r
732   ++error_count;\r
733 }\r
734 \r
735 /*********************************************\r
736 This displays the string and line number for\r
737 errors dicovered AFTER we past the line.\r
738 This is for non-fatal errors.\r
739 **********************************************/\r
740 \r
741 void prev_error(S8  *pst, S16 line)\r
742 {\r
743    fprintf(lst_fh, "\r\nERROR, line %d - %s\r\n", line, pst);\r
744   Column = 0;\r
745   ++error_count;\r
746 }\r
747 \r
748 /**********************************************************\r
749   The parser calls this when it detects a digit leaving\r
750   the line_ptr* pointing to digit. It accepts base 2, 10\r
751   & 16. Base 2 numbers are suffixed with a B or b, base 16\r
752   with an h or H and base 10 with no suffix.\r
753 ***********************************************************/\r
754 \r
755 U32 get_number(void)\r
756 {\r
757 U32  value, base;\r
758 S8   c, i;\r
759 S16  len;\r
760 S8   st[33];\r
761   value = 0;\r
762   len = 0;\r
763   base = 10;                                            /* default base is 10 */\r
764 \r
765   while(isxdigit(c = *line_ptr)) {      /* get all the digits */\r
766         st[len++] = c;\r
767         line_ptr++;\r
768   }\r
769 \r
770   if ((*line_ptr== 'h') || (*line_ptr== 'H')) {   /* looks like hex */\r
771         line_ptr++;\r
772         base = 16;\r
773   }\r
774   else if ((st[len-1] == 'b') || (st[len-1] == 'B')) {\r
775         base = 2;\r
776         len--;\r
777   }\r
778   if (((base == 2) && (len > 33)) ||\r
779           ((base == 10) && (len > 10)) ||\r
780           ((base == 16) && (len > 9))) {\r
781         line_error(4);\r
782         return(0);\r
783   }\r
784   i = 0;\r
785   do {\r
786         c = st[i];\r
787         if(isdigit(c))                                  /* convert numeric digits */\r
788                 c -= '0';\r
789         else if(c >= 'a')                               /* convert lower case alphas */\r
790                 c -= ('a' - 10);\r
791         else if(c >= 'A')                               /* convert upper case alphas */\r
792                 c -= ('A' - 10);\r
793         else\r
794                 break;\r
795         if(c >= base) {                                 /* outside of base */\r
796                 line_error(5);\r
797                 return(0);\r
798         }\r
799         value = (value * base) + c;             /* include in total */\r
800         i++; }\r
801   while(i < len);                                               /* to length of string */\r
802   return value;\r
803 }\r
804 \r
805 /*********************************************\r
806 This is a fast binary search for a reserved\r
807 word that is not an instructions or a register.\r
808 **********************************************/\r
809 \r
810 S16 findrsvd(S8 *pb, S16 cb)  /* pointer to and size of string */\r
811 {\r
812 S16 f, m, n, k;\r
813 S8   id[8];\r
814 \r
815  if (cb>srsvd) return(0);               /* can't be a reserved word */\r
816  strncpy(id, pb, cb);                   /* move string local */\r
817  id[cb] = 0;                                    /* null terminate */\r
818 \r
819  m = 0;\r
820  n = nreserved-1;\r
821  while (m<=n) {\r
822     k = m + (n-m) / 2;\r
823         f = strncmp(id, rgReserved[k], srsvd-1);\r
824     if (!f) return(k + nrsvd1);                 /* found it!   */\r
825     else if (f > 0)                                             /* it was less */\r
826            m = k+1;\r
827         else                                                            /* it was more  */\r
828            n = k-1;\r
829  }\r
830  return(0);\r
831 }\r
832 \r
833 /*********************************************\r
834 This is a fast binary search for an instuction.\r
835 It returns the number or 0 if not found.\r
836 **********************************************/\r
837 \r
838 S16 findinst(S8 *pb, S16 cb)  /* pointer to and size of parsed string */\r
839 {\r
840 S16 f, m, n, k;\r
841 S8   id[6];\r
842 \r
843  if (cb>sinst) return(0);               /* can't be an instruction */\r
844  strncpy(id, pb, cb);           /* move string local */\r
845  id[cb] = 0;                            /* null terminate */\r
846 \r
847  m = 0;\r
848  n = ninst-1;\r
849  while (m<=n) {\r
850     k = m + (n-m) / 2;\r
851         f = strncmp(id, rginst[k], sinst-1);\r
852     if (!f) return(k+1);                                /* found it!   */\r
853     else if (f > 0)                                             /* id was less */\r
854            m = k+1;\r
855         else                                                            /* idwas more  */\r
856            n = k-1;\r
857  }\r
858  return(0);\r
859 }\r
860 \r
861 /*********************************************\r
862 This is a fast binary search for a register.\r
863 It returns the number or 0 if not found.\r
864 **********************************************/\r
865 \r
866 S16 findreg(S8 *pb, S16 cb)  /* pointer to, and size of parsed string */\r
867 {\r
868 S16 f, m, n, k;\r
869 S8   id[3];\r
870 \r
871  if ((cb>sregs-1) || (cb<2)) return(0); /* can't be a register */\r
872  strncpy(id, pb, cb);                           /* move string local */\r
873  id[cb] = 0;                                            /* null pad */\r
874 \r
875  m = 0;\r
876  n = nregs-1;\r
877  while (m<=n) {\r
878     k = m + (n-m) / 2;\r
879         f = strncmp(id, rgreg[k], sregs-1);\r
880     if (!f) return(k+nreg1);                    /* found it!   */\r
881     else if (f > 0)                                             /* it was less */\r
882            m = k+1;\r
883         else                                                            /* it was more  */\r
884            n = k-1;\r
885  }\r
886  return(0);\r
887 }\r
888 \r
889 /*********************************************\r
890 This searches the LOCAL symbol table for the name\r
891 described by pb, cb. It only compares items that\r
892 are the same length (cb == TSymsize[x]).\r
893 It returns the number or 0 if not found.\r
894 **********************************************/\r
895 \r
896 S16 findLsymbol(S8 *pb, S16 cb)  /* pointer to, and size of string */\r
897 {\r
898 S16 i;\r
899 S8   name[132];\r
900 \r
901 strncpy(name, pb, cb);          /* move name local */\r
902 name[cb] = 0;                           /* null terminate */\r
903 \r
904 i = iLSymNext;\r
905 while (i>1) {                           /* backwards through symbol table */\r
906         i--;\r
907                                 /* Only compare if same size  */\r
908         if (lst[i].Size == cb) {\r
909                 if (strncmp(name, lst[i].Ptr, cb) == 0) return(i);\r
910                 }\r
911         }\r
912 return(0);              /* not found... */\r
913 }\r
914 \r
915 \r
916 /*********************************************\r
917 This searches the symbol table for the name\r
918 described by pb, cb. It only compares items that\r
919 are the same length (cb == TSymsize[x]).\r
920 If the include level is greater than 0 it\r
921 searches the local first, then the global.\r
922 If at level 0, it only searches the global.\r
923 It returns the number or 0 if not found.\r
924 **********************************************/\r
925 \r
926 S16 findGsymbol(S8 *pb, S16 cb)  /* pointer to, and size of string */\r
927 {\r
928 S16 i;\r
929 S8   name[132];\r
930 \r
931 strncpy(name, pb, cb);          /* move name local */\r
932 name[cb] = 0;                           /* null terminate */\r
933 \r
934 i = iSymNext;\r
935 while (i>1) {                           /* backwards through symbol table */\r
936         i--;\r
937                                 /* Only compare if same size  */\r
938         if (gst[i].Size == cb) {\r
939                 if (strncmp(name, gst[i].Ptr, cb) == 0) return(i);\r
940                 }\r
941         }\r
942 return(0);              /* not found... */\r
943 }\r
944 \r
945 /*********************************************\r
946         DUMP SYMBOL TABLE FOR TESTING\r
947 **********************************************/\r
948 \r
949 void DumpGSymbols(void)\r
950 {\r
951 S16 i;\r
952 S8   name[132];\r
953 \r
954 fprintf(lst_fh, "PUBLIC SYMBOLS: \r\n");\r
955 \r
956 i = 1;\r
957 while (i<iSymNext) {                                            /* forward through symbol table */\r
958         strncpy(name, gst[i].Ptr, gst[i].Size); /* move to name */\r
959         name[gst[i].Size] = 0;                                  /* null terminate */\r
960 \r
961         fprintf(lst_fh, "Name: %s      Offset %08lX  ", name, gst[i].Offs);\r
962         if (gst[i].Type & CLABEL)\r
963                 fprintf(lst_fh, "CSEG  ");\r
964         if (gst[i].Type & DLABEL)\r
965                 fprintf(lst_fh, "DSEG  ");\r
966         if (gst[i].Type & sBYTE)\r
967                 fprintf(lst_fh, "BYTE  ");\r
968         if (gst[i].Type & sWORD)\r
969                 fprintf(lst_fh, "WORD  ");\r
970         if (gst[i].Type & sDWORD)\r
971                 fprintf(lst_fh, "DWORD  ");\r
972         if (gst[i].Type & sFWORD)\r
973                 fprintf(lst_fh, "FWORD  ");\r
974         if (gst[i].Type & tEXTRN)\r
975                 fprintf(lst_fh, "EXTRN  ");\r
976         if (gst[i].Type & tFAR)\r
977                 fprintf(lst_fh, "FAR    ");\r
978         if (gst[i].Type & tPUBLIC)\r
979                 fprintf(lst_fh, "PUBLIC ");\r
980         if (gst[i].Type & MACRO)\r
981                 fprintf(lst_fh, "MACRO  ");\r
982         fprintf(lst_fh, "\r\n");\r
983         i++;\r
984         }\r
985 \r
986 }\r
987 \r
988 /*********************************************\r
989         DUMP SYMBOL TABLE FOR TESTING\r
990 **********************************************/\r
991 \r
992 void DumpLSymbols(void)\r
993 {\r
994 S16 i;\r
995 S8   name[132];\r
996 \r
997 fprintf(lst_fh, "LOCAL SYMBOLS: \r\n");\r
998 \r
999 i = 1;\r
1000 while (i<iLSymNext) {                                           /* forward through symbol table */\r
1001         strncpy(name, lst[i].Ptr, lst[i].Size); /* move to name */\r
1002         name[lst[i].Size] = 0;                                  /* null terminate */\r
1003 \r
1004         fprintf(lst_fh, "Name: %s      Offset %lX   ", name, lst[i].Offs);\r
1005         if (lst[i].Type & CLABEL)\r
1006                 fprintf(lst_fh, "CSEG  ");\r
1007         if (lst[i].Type & DLABEL)\r
1008                 fprintf(lst_fh, "DSEG  ");\r
1009         if (lst[i].Type & sBYTE)\r
1010                 fprintf(lst_fh, "BYTE  ");\r
1011         if (lst[i].Type & sWORD)\r
1012                 fprintf(lst_fh, "WORD  ");\r
1013         if (lst[i].Type & sDWORD)\r
1014                 fprintf(lst_fh, "DWORD  ");\r
1015         if (lst[i].Type & sFWORD)\r
1016                 fprintf(lst_fh, "FWORD  ");\r
1017         if (lst[i].Type & tEXTRN)\r
1018                 fprintf(lst_fh, "EXTRN  ");\r
1019         if (lst[i].Type & tFAR)\r
1020                 fprintf(lst_fh, "FAR    ");\r
1021         if (lst[i].Type & tPUBLIC)\r
1022                 fprintf(lst_fh, "PUBLIC ");\r
1023         if (lst[i].Type & MACRO)\r
1024                 fprintf(lst_fh, "MACRO");\r
1025         fprintf(lst_fh, "\r\n");\r
1026         i++;\r
1027         }\r
1028 }\r
1029 \r
1030 /*********************************************\r
1031         DUMP Forward Reference Table for testing\r
1032 **********************************************/\r
1033 \r
1034 void DumpFRT(void)\r
1035 {\r
1036 S16 i;\r
1037 S8   name[132];\r
1038 \r
1039 fprintf(lst_fh, "FORWARD REFERENCES:\n");\r
1040 \r
1041 i = 0;\r
1042 while (i<iRefNext) {                                            /* forward through symbol table */\r
1043         strncpy(name, pfrt[i].Ptr, pfrt[i].NameSz);     /* move to name */\r
1044         name[pfrt[i].NameSz] = 0;                                       /* null terminate */\r
1045 \r
1046         fprintf(lst_fh, "Name: %s      Offset: %lX   Line: %d\n",\r
1047                         name,\r
1048                         pfrt[i].Offs,\r
1049                         pfrt[i].Line);\r
1050         i++;\r
1051         }\r
1052 \r
1053 }\r
1054 \r
1055 /*********************************************\r
1056 This sets the global variable fPutBack to TRUE\r
1057 and copies the current token info so save it\r
1058 so it can be used again. (returning a token\r
1059 to the stream...)\r
1060 **********************************************/\r
1061 void ReturnToken(void)\r
1062 {\r
1063 strncpy(LTString, TString, 132);\r
1064 LCBString = CBString;\r
1065 LTSymnum = TSymnum;\r
1066 LTNumber = TNumber;\r
1067 LTInst = TInst;\r
1068 LTReg = TReg;\r
1069 LToken = Token;\r
1070 fPutBack = 1;\r
1071 }\r
1072 \r
1073 \r
1074 /********************************************\r
1075  Parse reads and identifies the next token\r
1076  for the caller. See SASM.h for info on each\r
1077  of the tokens it identifies.\r
1078  Token type is placed in Token.\r
1079  All parsed chars are placed in TString.\r
1080  Size of TString is placed in CBString.\r
1081  Converted numeric values are put in TNumber.\r
1082  Instruction numbers are placed in TInst.\r
1083  Declared symbol ID numbers are placed in TSymnum.\r
1084 \r
1085  Unidentified strings are first checked for\r
1086  macro substitution and replaced with the\r
1087  stored string if found. If no macro is\r
1088  found, the symbol table is searched to see if\r
1089  it's a symbol. If so, it's returned. If not\r
1090  a symbol, Parse assumes it may be a new one\r
1091  and leaves it in TString with the TokenType\r
1092  of UNKSYM.\r
1093 *********************************************/\r
1094 \r
1095 S16 Parse(void)\r
1096 {\r
1097 S16  i;\r
1098 \r
1099 \r
1100 if (fPutBack) {         /* if a symbol was put back this makes it current */\r
1101         strncpy(TString, LTString, 132);\r
1102         CBString = LCBString;\r
1103         TSymnum = LTSymnum;\r
1104         TNumber = LTNumber;\r
1105         TInst = LTInst;\r
1106         TReg = LTReg;\r
1107         Token = LToken;\r
1108         fPutBack = 0;\r
1109         return(Token);\r
1110 }\r
1111 \r
1112 begin:                          /* return here after MACRO substitution */\r
1113  TSymnum = 0;\r
1114  TInst = 0;\r
1115  TReg = 0;\r
1116  Token = 0;\r
1117  TString[0] = 0;\r
1118  CBString = 0;\r
1119  TNumber = 0;\r
1120 \r
1121  while(isskip(*line_ptr)) line_ptr++;           /* skip while space */\r
1122  if (!(*line_ptr)) return(0);                           /* end of line */\r
1123 \r
1124  if     (*line_ptr == SEMI)                                     /* if comment */\r
1125  {\r
1126         *line_ptr = 0;                                  /* kill rest of line */\r
1127         return(0);                                              /* return 0 for EOL */\r
1128  }\r
1129 \r
1130   /* See if it's a legal 1st char for identifier or reserved word. */\r
1131   /* If so, pick it up and put it in TString ALL UPPER CASE */\r
1132 \r
1133  i=0;\r
1134  if (is_ident(*line_ptr)) {\r
1135          while( (isalnum(*line_ptr)) || (*line_ptr == '_') ) {\r
1136                  TString[i++] = toupper(*line_ptr++);\r
1137          }\r
1138         CBString = i;\r
1139 \r
1140     if (TReg = findreg(TString, i))    /* Register? */\r
1141                 return (Token = REGIST);\r
1142 \r
1143     if (TInst = findinst(TString, i))  /* Instruction? */\r
1144                 return (Token = INSTRU);\r
1145 \r
1146     if (Token = findrsvd(TString, i))  /* Reserved Word? */\r
1147                 return (Token);\r
1148 \r
1149         if (level) {\r
1150                 if (TSymnum = findLsymbol(TString, i)) {\r
1151 \r
1152                         if (lst[TSymnum].Type & MACRO) {                /* MACRO !! */\r
1153                           i = lst[TSymnum].Offs;                                /* get number */\r
1154                           strcpy(line_buf1, rgMacPtr[i]);               /* move it in */\r
1155                           strncat(line_buf1, line_ptr, 132);    /* cat rest of line */\r
1156                           line_ptr = line_buf1;\r
1157                           goto begin;\r
1158                         }\r
1159                         else return (Token = LSYMBOL);\r
1160                 }\r
1161         }\r
1162 \r
1163         if (TSymnum = findGsymbol(TString, i)) {\r
1164                  return (Token = SYMBOL);\r
1165         }\r
1166         else return (Token = UNKSYM);\r
1167  }\r
1168 \r
1169  /* If char was not legal for an identifier the only things left\r
1170     are digits, special characters, and 'strings' */\r
1171 \r
1172  if (isdigit(*line_ptr)) {\r
1173         TNumber = get_number();\r
1174         return (Token = NUMBER);\r
1175  }\r
1176  switch (*line_ptr) {\r
1177         case DOLLAR:\r
1178         case OPENRND:\r
1179         case CLOSRND:\r
1180         case STAR:\r
1181         case PLUS:\r
1182         case COMMA:\r
1183         case MINUS:\r
1184         case DOT:\r
1185         case SLASH:\r
1186         case COLON:\r
1187         case OPENSQR:\r
1188         case CLOSSQR:\r
1189                 {\r
1190                 Token = *line_ptr;\r
1191                 TString[0] = *line_ptr++;\r
1192                 TString[1] = 0;\r
1193                 CBString = 1;\r
1194                 return (Token);\r
1195                 }\r
1196     case SQUOTE: {\r
1197                 line_ptr++;\r
1198                 while ((*line_ptr) && (*line_ptr != SQUOTE) && (i < 132))\r
1199                         TString[i++] = *line_ptr++;\r
1200                 CBString = i;\r
1201                 if (*line_ptr != SQUOTE)\r
1202                         line_error(6);\r
1203                 else\r
1204                         line_ptr++;             /* next char if this is SQUOTE */\r
1205                 TString[i] = 0;         /* null terminate string */\r
1206                 CBString = i;           /* Set size */\r
1207                 return(Token = STRING);\r
1208         }\r
1209     default: {\r
1210                 line_error(7);\r
1211                 return(Token = ERROR);\r
1212         }\r
1213  } /* end switch */\r
1214 }\r
1215 \r
1216 /**************************************\r
1217   Handles include files for INCLUDE and\r
1218   SEARCH commands.\r
1219 ***************************************/\r
1220 void DoInclude(char *pName)\r
1221 {\r
1222                 if (level < LEVELS-1) {\r
1223                          ++level;\r
1224 \r
1225                         strcpy(srcname[level], pName);\r
1226 \r
1227                         if(!(src_fh[level] = fopen(srcname[level], "r"))) {\r
1228                                 --level;\r
1229                                 fatal_error("Can't open INCLUDE file\n");\r
1230                                 }\r
1231                         else\r
1232                                 lineno[level] = 0;\r
1233 \r
1234                         if (fListA) {\r
1235                                 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
1236                                 Column += fprintf(lst_fh, "INCLUDE: %s", srcname[level]);\r
1237                                 }\r
1238                         }\r
1239                 else\r
1240                         fatal_error("EXCEEDED MAX INCLUDE DEPTH (5)");\r
1241 \r
1242 }\r
1243 \r
1244 /*******************************************\r
1245   Handles SEARCH command for library search.\r
1246   We open the PUB file given and find the\r
1247   first filename. We save this name, then\r
1248   run through the publics seeing if we\r
1249   need any of them.\r
1250 *******************************************/\r
1251 void DoSearch(char *pName)\r
1252 {\r
1253 \r
1254 }\r
1255 \r
1256 /********************************************\r
1257    Handles DOT Commands\r
1258 *********************************************/\r
1259 void Command(void)\r
1260 {\r
1261 U32 num;\r
1262 S16 i, ii;\r
1263 char tmpname[50];\r
1264 \r
1265 switch(i = Parse()) {\r
1266         case rDATA:\r
1267                 fDataSeg = 1;\r
1268                 if (fListA) {\r
1269                         pNextAddr = &oNextData;\r
1270                         Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
1271                         Column += fprintf(lst_fh, "<- DSEG Begin", lst_fh);\r
1272                         }\r
1273                 break;\r
1274         case rCODE:\r
1275                 fDataSeg = 0;\r
1276                 if (fListA) {\r
1277                         pNextAddr = &oNextCode;\r
1278                         Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
1279                         Column += fprintf(lst_fh, "<- CSEG Begin", lst_fh);\r
1280                         }\r
1281                 break;\r
1282         case rALIGN:\r
1283                 ii = Parse();\r
1284                 if (fListA)\r
1285                         Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
1286                 if (ii == rWORD)\r
1287                 {\r
1288                         if (fListA)\r
1289                                 Column += fprintf(lst_fh, "<- WORD ALIGN, PAD: ", lst_fh);\r
1290                         if (fDataSeg)\r
1291                         {\r
1292                                 if (oNextData & 1)\r
1293                                 {\r
1294                                         OutByte(0);     /* EMIT byte to Data seg, value 0 */\r
1295                                         if (fListA)\r
1296                                                 Column += fprintf(lst_fh, "00 ", lst_fh);\r
1297                                 }\r
1298                         }\r
1299                         else\r
1300                         {\r
1301                                 if (oNextCode & 1)\r
1302                                 {\r
1303                                         OutByte(0x90); /* EMIT byte to Code seg, 0x90 (NOP) */\r
1304                                         if (fListA)\r
1305                                                 Column += fprintf(lst_fh, "90 ", lst_fh);\r
1306                                 }\r
1307                         }\r
1308                 }\r
1309                 else if (ii == rDWORD)\r
1310                 {\r
1311                         if (fListA)\r
1312                                 Column += fprintf(lst_fh, "<- DWORD ALIGN, PAD: ", lst_fh);\r
1313                         if (fDataSeg)\r
1314                         {\r
1315                                 while (oNextData & 3) {\r
1316                                         OutByte(0);     /* EMIT byte to Data seg, value 0 */\r
1317                                         if (fListA)\r
1318                                                 Column += fprintf(lst_fh, "00 ", lst_fh);\r
1319                                 }\r
1320                         }\r
1321                         else\r
1322                         {\r
1323                                 while (oNextCode & 3)\r
1324                                 {\r
1325                                         OutByte(0x90); /* EMIT byte to Code seg, 0x90 (NOP) */\r
1326                                         if (fListA)\r
1327                                                 Column += fprintf(lst_fh, "90 ", lst_fh);\r
1328                                 }\r
1329                         }\r
1330                 }\r
1331                 else if (ii == rPARA)\r
1332                 {\r
1333                         if (fListA)\r
1334                                 Column += fprintf(lst_fh, "<- PARA(16) ALIGN, PAD: ", lst_fh);\r
1335                         if (fDataSeg)\r
1336                         {\r
1337                                 while (oNextData & 0x0f) {\r
1338                                         OutByte(0);     /* EMIT byte to Data seg, value 0 */\r
1339                                         if (fListA)\r
1340                                                 Column += fprintf(lst_fh, "00 ", lst_fh);\r
1341                                 }\r
1342                         }\r
1343                         else\r
1344                         {\r
1345                                 while (oNextCode & 0x0f)\r
1346                                 {\r
1347                                         OutByte(0x90); /* EMIT byte to Code seg, 0x90 (NOP) */\r
1348                                         if (fListA)\r
1349                                                 Column += fprintf(lst_fh, "90 ", lst_fh);\r
1350                                 }\r
1351                         }\r
1352                 }\r
1353                 else\r
1354                         line_error(8);\r
1355                 break;\r
1356         case rEND:\r
1357                 if (fListA) {\r
1358                         Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
1359                         Column += fprintf(lst_fh, "<- END of Source ");\r
1360                         }\r
1361                 break;\r
1362         case rSTART:\r
1363                 if (!fDataSeg) {\r
1364                         if (fListA) {\r
1365                                 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
1366                                 Column += fprintf(lst_fh, "<- START Address ");\r
1367                                 }\r
1368             fStart = 1;\r
1369             StartAddr = oNextCode;\r
1370                         }\r
1371                 else\r
1372                         line_error(9);\r
1373                 break;\r
1374         case rVIRTUAL:\r
1375                 if (fDataSeg) {\r
1376                         if (fListA)\r
1377                                 Column += fprintf(lst_fh, "VIRTUAL Segment address: ");\r
1378                         if (Parse() == NUMBER) {\r
1379                                 if (oNextData > 0)\r
1380                                         line_error(10);\r
1381                                 else {\r
1382                                         if (fListA)\r
1383                                                 Column += fprintf(lst_fh, "%08lX", TNumber);\r
1384                                         oNextData = TNumber;\r
1385                                         DataOffset = TNumber;\r
1386                                 }\r
1387                         }\r
1388                         else\r
1389                           line_error(11);\r
1390                 }\r
1391                 else {\r
1392                         if (fListA)\r
1393                                 Column += fprintf(lst_fh, "VIRTUAL Segment address: ");\r
1394                         if (Parse() == NUMBER) {\r
1395                                 if (oNextCode > 0)\r
1396                                         line_error(10);\r
1397                                 else {\r
1398                                         if (fListA)\r
1399                                                 Column += fprintf(lst_fh, "%08lX", TNumber);\r
1400                                         oNextCode = TNumber;\r
1401                                         CodeOffset = TNumber;\r
1402                                 }\r
1403                     }\r
1404                         else\r
1405                           line_error(11);\r
1406                 }\r
1407                 break;\r
1408         case rINCLUDE:\r
1409                 tmpname[0] = 0;         /* default to null name */\r
1410                 while (isskip(*line_ptr)) line_ptr++;\r
1411                 i=0;\r
1412                 while ((*line_ptr) && (*line_ptr != ';') && (!isskip(*line_ptr)))\r
1413                         tmpname[i++] = *line_ptr++;\r
1414                 tmpname[i] = 0;                                 /* null terminate */\r
1415 \r
1416                 DoInclude(tmpname);\r
1417                 break;\r
1418         case rSEARCH:\r
1419                 tmpname[0] = 0;         /* default to null name */\r
1420                 while (isskip(*line_ptr)) line_ptr++;\r
1421                 i=0;\r
1422                 while ((*line_ptr) && (*line_ptr != ';') && (!isskip(*line_ptr)))\r
1423                         tmpname[i++] = *line_ptr++;\r
1424                 tmpname[i] = 0;                                 /* null terminate */\r
1425 \r
1426                 DoSearch(tmpname);\r
1427                 break;\r
1428         case rSTACK:\r
1429                 if (!fDataSeg) {\r
1430                         if (fListA)\r
1431                                 Column += fprintf(lst_fh, "Stack Total: ");\r
1432                         if (Parse() == NUMBER) {\r
1433                                 StackTotal += TNumber;\r
1434                                 if (fListA)\r
1435                                         Column += fprintf(lst_fh, "%08lX", StackTotal);\r
1436                         }\r
1437                         else\r
1438                                 line_error(35); /* Invalid number or expression */\r
1439                 }\r
1440                 else\r
1441                   line_error(13);\r
1442                 break;\r
1443         default: line_error(14);\r
1444                 return;\r
1445    }\r
1446  }\r
1447 \r
1448 /********************************************\r
1449  This adds the 3 bit code for the specified\r
1450  register to the ModRM or SIB bytes which\r
1451  is pointed to by *modbyte. nshift is the\r
1452  number of bits to shift the register code\r
1453  before ORing it with *modbyte (ModRM or SIB).\r
1454 *********************************************/\r
1455 \r
1456 void EncodeRegBits(S16 regnum, S8   *modbyte, S16 nshift)\r
1457 {\r
1458 \r
1459 switch (regnum) {\r
1460         case rAL:\r
1461         case rAX:               /* value is 1 don't do anything */\r
1462         case rEAX:\r
1463         case rES:\r
1464         case rCR0:\r
1465         case rDR0:\r
1466                 break;\r
1467         case rCL:\r
1468         case rCX:\r
1469         case rECX:\r
1470         case rCS:\r
1471         case rCR1:\r
1472         case rDR1:\r
1473                 *modbyte |= (1 << nshift);\r
1474                 break;\r
1475         case rDL:\r
1476         case rDX:\r
1477         case rEDX:\r
1478         case rSS:\r
1479         case rCR2:\r
1480         case rDR2:\r
1481                 *modbyte |= (2 << nshift);\r
1482                 break;\r
1483         case rBL:\r
1484         case rBX:\r
1485         case rEBX:\r
1486         case rDS:\r
1487         case rCR3:\r
1488         case rDR3:\r
1489                 *modbyte |= (3 << nshift);\r
1490                 break;\r
1491         case rAH:\r
1492         case rSP:\r
1493         case rESP:\r
1494                 *modbyte |= (4 << nshift);\r
1495                 break;\r
1496         case rCH:\r
1497         case rBP:\r
1498         case rEBP:\r
1499         case rFS:\r
1500                 *modbyte |= (5 << nshift);\r
1501                 break;\r
1502         case rDH:\r
1503         case rSI:\r
1504         case rESI:\r
1505         case rGS:\r
1506         case rTR6:\r
1507         case rDR6:\r
1508                 *modbyte |= (6 << nshift);\r
1509                 break;\r
1510         case rBH:\r
1511         case rDI:\r
1512         case rEDI:\r
1513         case rTR7:\r
1514         case rDR7:\r
1515                 *modbyte |= (7 << nshift);\r
1516                 break;\r
1517         default:;               /* if it's not one of these we do nothing */\r
1518 }\r
1519 }\r
1520 \r
1521 /********************************************\r
1522   Add Macro to LOCAL symbol table.\r
1523   The last symbol added to the symbol\r
1524   table is the label for this macro.\r
1525 \r
1526 *********************************************/\r
1527 void AddMacro(void)\r
1528 {\r
1529 S16 i, j;\r
1530 S8   mac[100];\r
1531 \r
1532 mac[0] = 0;\r
1533 \r
1534 if (iMacNext >= MACBUFMAX-50)\r
1535         fatal_error("Macro buffer overflow...");\r
1536 if (iMacNext >= MACSMAX)\r
1537         fatal_error("Macro table overflow...");\r
1538 \r
1539 i = 0; j = 0;\r
1540 while(isskip(*line_ptr)) line_ptr++;            /* skip while space */\r
1541 \r
1542 /* Read the macro including white space upto EOL or comment.\r
1543    j keeps track of the last NON-space character so we don't\r
1544    store unneeded spaces at the end of the macro.\r
1545 */\r
1546 \r
1547 while ((*line_ptr) && (*line_ptr != SEMI)) {\r
1548         mac[i++] = *line_ptr++;\r
1549         if (mac[i-1] > 0x20) j = i;                     /* j will be length */\r
1550 }\r
1551 \r
1552 strncpy(pMacNext, mac, j);\r
1553 \r
1554 /* These are all "iLSymNext-1" because the Macro label has\r
1555    already been added to the symbol table when AddMacro\r
1556    is called.\r
1557 */\r
1558 \r
1559 lst[iLSymNext-1].Type = 0;                      /* cancel previous type */\r
1560 lst[iLSymNext-1].Type |= MACRO;         /* initialize type */\r
1561 \r
1562 rgMacPtr[iMacNext] = pMacNext;          /* store mac ptr in pmac array */\r
1563 lst[iLSymNext-1].Offs = iMacNext;       /* store mac # in offset */\r
1564 iMacNext++;\r
1565 pMacNext += j;\r
1566 *pMacNext = 0;                                          /* null terminate the macro */\r
1567 pMacNext++;\r
1568 \r
1569 }\r