]> pd.if.org Git - mmurtl/blob - msamples/dasmm/dasmq.c
autocommit for files dated 1995-02-09 16:53:44
[mmurtl] / msamples / dasmm / 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 U32 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(U32 value, FILE *fout)\r
60 {\r
61 S8  stack[10];\r
62 U32 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 U32 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 long expr4(long *val)\r
112 {\r
113 long 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 long expr3(long *val)\r
184 {\r
185 long 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 long expr2(long *val)\r
210 {\r
211 long 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 long expr1(long *val)\r
236 {\r
237 long 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 long 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 long is_r32(long 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 long is_r16(long 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 long is_r8(long 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 long is_rSEG(long 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 long is_rDRG(long 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 long is_rCRG(long 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 long is_rTRG(long 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 long is_Comp(long ins, long 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 long is_Reg(long 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 exit(1);\r
639 }\r
640 \r
641 /*********************************************\r
642 This displays the string and line number for\r
643 non-fatal errors.\r
644 **********************************************/\r
645 \r
646 void line_error(long num)\r
647 {\r
648 S8 *p;\r
649 \r
650         switch (num) {\r
651         case  1: p="Invalid expression, ')' expected";          break;\r
652         case  2: p="Invalid expression, value expected";        break;\r
653         case  3: p="Value expected after unary '-'";            break;\r
654         case  4: p="Too many digits for numeric radix";         break;\r
655         case  5: p="Invalid character in a number";                     break;\r
656         case  6: p="Unterminated string";                                       break;\r
657         case  7: p="Unrecognized character";                            break;\r
658         case  8: p="Invalid Alignment specified";                       break;\r
659         case  9: p="Start command only allowed in CSEG";                break;\r
660         case 10: p="Virtual command must be first in segment";  break;\r
661         case 11: p="Invalid Virtual value";                                     break;\r
662         case 12: p="Starting address not found";                        break;\r
663         case 13: p="Stack command not allowed in DSEG";         break;\r
664         case 14: p="Invalid DOT command";                                       break;\r
665         case 15: p="Invalid Operand";                                           break;\r
666         case 16: p="Invalid segment register use";                      break;\r
667         case 17: p="Invalid scale value 'Reg*?'";                       break;\r
668         case 18: p="Scale value expected (*2,*4,*8)";           break;\r
669         case 19: p="Too many address scale values";                     break;\r
670         case 20: p="Invalid register for memory operand";       break;\r
671         case 21: p="Invalid memory operand";                            break;\r
672         case 22: p="Offset must be from data segment";          break;\r
673         case 23: p="Nested brackets";                                           break;\r
674         case 24: p="Unbalanced brackets";                                       break;\r
675         case 25: p="Invalid operand size attribute";            break;\r
676         case 26:\r
677         case 27:\r
678         case 28:\r
679         case 29:\r
680         case 30:\r
681         case 31: p="";                                                                                  break;\r
682         case 32: p="Unknown token in operand array";                    break;\r
683         case 33: p="Too many operands or extra character";              break;\r
684         case 34: p="";                                                                                  break;\r
685         case 35: p="Invalid expression or numeric value";       break;\r
686         case 36: p="Operand expected before comma";                             break;\r
687         case 37: p="";                                                                                  break;\r
688         case 38: p="Invalid character or reserved word in operand";     break;\r
689         case 39: p="Relative jump out of range";                                        break;\r
690         case 40: p="Operand size NOT specified or implied";                     break;\r
691         case 41: p="Instructions not allowed in data segment";          break;\r
692         case 42: p="Instruction expected after prefix";                         break;\r
693         case 43: p="Operand sizes don't match";                                         break;\r
694         case 44: p="Wrong operand type for instruction";                        break;\r
695         case 45: p="Incorrect format for memory operand";                       break;\r
696         case 46: p="Strings only valid for DB storage";                         break;\r
697         case 47: p="Expected '(' after 'DUP'";                                          break;\r
698         case 48: p="Storage expected between commas";                           break;\r
699         case 49: p="':' not expected";                                                          break;\r
700         case 50: p="DWord storage required for OFFSET";                         break;\r
701         case 51: p="Invalid storage value";                                                     break;\r
702         case 52:\r
703         case 53: p="";                                                                                          break;\r
704         case 54: p="':' expected after last label";                                     break;\r
705         case 55: p="Macro not allowed in lexical level 0";                      break;\r
706         case 56: p="EQU or Storage expected";                                           break;\r
707         case 57:\r
708         case 58:\r
709         case 59:\r
710         case 60:\r
711         case 61:\r
712         case 62: p="";                                                                                          break;\r
713         case 63: p="Instruction expected before register name";         break;\r
714         case 64: p="Public Symbol already defined";                                     break;\r
715         case 65: p="Local symbol already defined";                                      break;\r
716         case 66: p="Number not expected";                                                       break;\r
717         case 67: p="New symbol must follow PUBLIC keyword";                     break;\r
718         case 68: p="Label, Command, Instruction, or Storage expected";  break;\r
719         case 69: p="Inconsistant redeclaration";                                                break;\r
720         case 70: p="";                                                                                                  break;\r
721         default:\r
722                 break;\r
723     }\r
724 \r
725   fprintf(lst_fh, "\r\nERROR: %d, line: %ld, %s\r\n", num, lineno[level], p);\r
726   *line_ptr = 0;                                /* this KILLS the rest of the line */\r
727   Column = 0;\r
728   ++error_count;\r
729 }\r
730 \r
731 /*********************************************\r
732 This displays the string and line number for\r
733 errors dicovered AFTER we past the line.\r
734 This is for non-fatal errors.\r
735 **********************************************/\r
736 \r
737 void prev_error(S8  *pst, S32 line)\r
738 {\r
739    fprintf(lst_fh, "\r\nERROR, line %d - %s\r\n", line, pst);\r
740   Column = 0;\r
741   ++error_count;\r
742 }\r
743 \r
744 /**********************************************************\r
745   The parser calls this when it detects a digit leaving\r
746   the line_ptr* pointing to digit. It accepts base 2, 10\r
747   & 16. Base 2 numbers are suffixed with a B or b, base 16\r
748   with an h or H and base 10 with no suffix.\r
749 ***********************************************************/\r
750 \r
751 U32 get_number(void)\r
752 {\r
753 U32  value, base;\r
754 S8   c, i;\r
755 S32  len;\r
756 S8   st[33];\r
757   value = 0;\r
758   len = 0;\r
759   base = 10;                                            /* default base is 10 */\r
760 \r
761   while(isxdigit(c = *line_ptr)) {      /* get all the digits */\r
762         st[len++] = c;\r
763         line_ptr++;\r
764   }\r
765 \r
766   if ((*line_ptr== 'h') || (*line_ptr== 'H')) {   /* looks like hex */\r
767         line_ptr++;\r
768         base = 16;\r
769   }\r
770   else if ((st[len-1] == 'b') || (st[len-1] == 'B')) {\r
771         base = 2;\r
772         len--;\r
773   }\r
774   if (((base == 2) && (len > 33)) ||\r
775           ((base == 10) && (len > 10)) ||\r
776           ((base == 16) && (len > 9))) {\r
777         line_error(4);\r
778         return(0);\r
779   }\r
780   i = 0;\r
781   do {\r
782         c = st[i];\r
783         if(isdigit(c))                                  /* convert numeric digits */\r
784                 c -= '0';\r
785         else if(c >= 'a')                               /* convert lower case alphas */\r
786                 c -= ('a' - 10);\r
787         else if(c >= 'A')                               /* convert upper case alphas */\r
788                 c -= ('A' - 10);\r
789         else\r
790                 break;\r
791         if(c >= base) {                                 /* outside of base */\r
792                 line_error(5);\r
793                 return(0);\r
794         }\r
795         value = (value * base) + c;             /* include in total */\r
796         i++; }\r
797   while(i < len);                                               /* to length of string */\r
798   return value;\r
799 }\r
800 \r
801 /*********************************************\r
802 This is a fast binary search for a reserved\r
803 word that is not an instructions or a register.\r
804 **********************************************/\r
805 \r
806 S32 findrsvd(S8 *pb, S32 cb)  /* pointer to and size of string */\r
807 {\r
808 S32 f, m, n, k;\r
809 S8   id[8];\r
810 \r
811  if (cb>srsvd) return(0);               /* can't be a reserved word */\r
812  strncpy(id, pb, cb);                   /* move string local */\r
813  id[cb] = 0;                                    /* null terminate */\r
814 \r
815  m = 0;\r
816  n = nreserved-1;\r
817  while (m<=n) {\r
818     k = m + (n-m) / 2;\r
819         f = strncmp(id, rgReserved[k], srsvd-1);\r
820     if (!f) return(k + nrsvd1);                 /* found it!   */\r
821     else if (f > 0)                                             /* it was less */\r
822            m = k+1;\r
823         else                                                            /* it was more  */\r
824            n = k-1;\r
825  }\r
826  return(0);\r
827 }\r
828 \r
829 /*********************************************\r
830 This is a fast binary search for an instuction.\r
831 It returns the number or 0 if not found.\r
832 **********************************************/\r
833 \r
834 S32 findinst(S8 *pb, S32 cb)  /* pointer to and size of parsed string */\r
835 {\r
836 S32 f, m, n, k;\r
837 S8   id[6];\r
838 \r
839  if (cb>sinst) return(0);               /* can't be an instruction */\r
840  strncpy(id, pb, cb);           /* move string local */\r
841  id[cb] = 0;                            /* null terminate */\r
842 \r
843  m = 0;\r
844  n = ninst-1;\r
845  while (m<=n) {\r
846     k = m + (n-m) / 2;\r
847         f = strncmp(id, rginst[k], sinst-1);\r
848     if (!f) return(k+1);                                /* found it!   */\r
849     else if (f > 0)                                             /* id was less */\r
850            m = k+1;\r
851         else                                                            /* idwas more  */\r
852            n = k-1;\r
853  }\r
854  return(0);\r
855 }\r
856 \r
857 /*********************************************\r
858 This is a fast binary search for a register.\r
859 It returns the number or 0 if not found.\r
860 **********************************************/\r
861 \r
862 S32 findreg(S8 *pb, S32 cb)  /* pointer to, and size of parsed string */\r
863 {\r
864 S32 f, m, n, k;\r
865 S8   id[3];\r
866 \r
867  if ((cb>sregs-1) || (cb<2)) return(0); /* can't be a register */\r
868  strncpy(id, pb, cb);                           /* move string local */\r
869  id[cb] = 0;                                            /* null pad */\r
870 \r
871  m = 0;\r
872  n = nregs-1;\r
873  while (m<=n) {\r
874     k = m + (n-m) / 2;\r
875         f = strncmp(id, rgreg[k], sregs-1);\r
876     if (!f) return(k+nreg1);                    /* found it!   */\r
877     else if (f > 0)                                             /* it was less */\r
878            m = k+1;\r
879         else                                                            /* it was more  */\r
880            n = k-1;\r
881  }\r
882  return(0);\r
883 }\r
884 \r
885 /*********************************************\r
886 This searches the LOCAL symbol table for the name\r
887 described by pb, cb. It only compares items that\r
888 are the same length (cb == TSymsize[x]).\r
889 It returns the number or 0 if not found.\r
890 **********************************************/\r
891 \r
892 S32 findLsymbol(S8 *pb, S32 cb)  /* pointer to, and size of string */\r
893 {\r
894 S32 i;\r
895 S8   name[132];\r
896 \r
897 strncpy(name, pb, cb);          /* move name local */\r
898 name[cb] = 0;                           /* null terminate */\r
899 \r
900 i = iLSymNext;\r
901 while (i>1) {                           /* backwards through symbol table */\r
902         i--;\r
903                                 /* Only compare if same size  */\r
904         if (lst[i].Size == cb) {\r
905                 if (strncmp(name, lst[i].Ptr, cb) == 0) return(i);\r
906                 }\r
907         }\r
908 return(0);              /* not found... */\r
909 }\r
910 \r
911 \r
912 /*********************************************\r
913 This searches the symbol table for the name\r
914 described by pb, cb. It only compares items that\r
915 are the same length (cb == TSymsize[x]).\r
916 If the include level is greater than 0 it\r
917 searches the local first, then the global.\r
918 If at level 0, it only searches the global.\r
919 It returns the number or 0 if not found.\r
920 **********************************************/\r
921 \r
922 S32 findGsymbol(S8 *pb, S32 cb)  /* pointer to, and size of string */\r
923 {\r
924 S32 i;\r
925 S8   name[132];\r
926 \r
927 strncpy(name, pb, cb);          /* move name local */\r
928 name[cb] = 0;                           /* null terminate */\r
929 \r
930 i = iSymNext;\r
931 while (i>1) {                           /* backwards through symbol table */\r
932         i--;\r
933                                 /* Only compare if same size  */\r
934         if (gst[i].Size == cb) {\r
935                 if (strncmp(name, gst[i].Ptr, cb) == 0) return(i);\r
936                 }\r
937         }\r
938 return(0);              /* not found... */\r
939 }\r
940 \r
941 /*********************************************\r
942         DUMP SYMBOL TABLE FOR TESTING\r
943 **********************************************/\r
944 \r
945 void DumpGSymbols(void)\r
946 {\r
947 S32 i;\r
948 S8   name[132];\r
949 \r
950 fprintf(lst_fh, "PUBLIC SYMBOLS: \r\n");\r
951 \r
952 i = 1;\r
953 while (i<iSymNext) {                                            /* forward through symbol table */\r
954         strncpy(name, gst[i].Ptr, gst[i].Size); /* move to name */\r
955         name[gst[i].Size] = 0;                                  /* null terminate */\r
956 \r
957         fprintf(lst_fh, "Name: %s      Offset %08lX  ", name, gst[i].Offs);\r
958         if (gst[i].Type & CLABEL)\r
959                 fprintf(lst_fh, "CSEG  ");\r
960         if (gst[i].Type & DLABEL)\r
961                 fprintf(lst_fh, "DSEG  ");\r
962         if (gst[i].Type & sBYTE)\r
963                 fprintf(lst_fh, "BYTE  ");\r
964         if (gst[i].Type & sWORD)\r
965                 fprintf(lst_fh, "WORD  ");\r
966         if (gst[i].Type & sDWORD)\r
967                 fprintf(lst_fh, "DWORD  ");\r
968         if (gst[i].Type & sFWORD)\r
969                 fprintf(lst_fh, "FWORD  ");\r
970         if (gst[i].Type & tEXTRN)\r
971                 fprintf(lst_fh, "EXTRN  ");\r
972         if (gst[i].Type & tFAR)\r
973                 fprintf(lst_fh, "FAR    ");\r
974         if (gst[i].Type & tPUBLIC)\r
975                 fprintf(lst_fh, "PUBLIC ");\r
976         if (gst[i].Type & MACRO)\r
977                 fprintf(lst_fh, "MACRO  ");\r
978         fprintf(lst_fh, "\r\n");\r
979         i++;\r
980         }\r
981 \r
982 }\r
983 \r
984 /*********************************************\r
985         DUMP SYMBOL TABLE FOR TESTING\r
986 **********************************************/\r
987 \r
988 void DumpLSymbols(void)\r
989 {\r
990 S32 i;\r
991 S8   name[132];\r
992 \r
993 fprintf(lst_fh, "LOCAL SYMBOLS: \r\n");\r
994 \r
995 i = 1;\r
996 while (i<iLSymNext) {                                           /* forward through symbol table */\r
997         strncpy(name, lst[i].Ptr, lst[i].Size); /* move to name */\r
998         name[lst[i].Size] = 0;                                  /* null terminate */\r
999 \r
1000         fprintf(lst_fh, "Name: %s      Offset %lX   ", name, lst[i].Offs);\r
1001         if (lst[i].Type & CLABEL)\r
1002                 fprintf(lst_fh, "CSEG  ");\r
1003         if (lst[i].Type & DLABEL)\r
1004                 fprintf(lst_fh, "DSEG  ");\r
1005         if (lst[i].Type & sBYTE)\r
1006                 fprintf(lst_fh, "BYTE  ");\r
1007         if (lst[i].Type & sWORD)\r
1008                 fprintf(lst_fh, "WORD  ");\r
1009         if (lst[i].Type & sDWORD)\r
1010                 fprintf(lst_fh, "DWORD  ");\r
1011         if (lst[i].Type & sFWORD)\r
1012                 fprintf(lst_fh, "FWORD  ");\r
1013         if (lst[i].Type & tEXTRN)\r
1014                 fprintf(lst_fh, "EXTRN  ");\r
1015         if (lst[i].Type & tFAR)\r
1016                 fprintf(lst_fh, "FAR    ");\r
1017         if (lst[i].Type & tPUBLIC)\r
1018                 fprintf(lst_fh, "PUBLIC ");\r
1019         if (lst[i].Type & MACRO)\r
1020                 fprintf(lst_fh, "MACRO");\r
1021         fprintf(lst_fh, "\r\n");\r
1022         i++;\r
1023         }\r
1024 }\r
1025 \r
1026 /*********************************************\r
1027         DUMP Forward Reference Table for testing\r
1028 **********************************************/\r
1029 \r
1030 void DumpFRT(void)\r
1031 {\r
1032 S32 i;\r
1033 S8   name[132];\r
1034 \r
1035 fprintf(lst_fh, "FORWARD REFERENCES:\n");\r
1036 \r
1037 i = 0;\r
1038 while (i<iRefNext) {                                            /* forward through symbol table */\r
1039         strncpy(name, pfrt[i].Ptr, pfrt[i].NameSz);     /* move to name */\r
1040         name[pfrt[i].NameSz] = 0;                                       /* null terminate */\r
1041 \r
1042         fprintf(lst_fh, "Name: %s      Offset: %lX   Line: %d\n",\r
1043                         name,\r
1044                         pfrt[i].Offs,\r
1045                         pfrt[i].Line);\r
1046         i++;\r
1047         }\r
1048 \r
1049 }\r
1050 \r
1051 /*********************************************\r
1052 This sets the global variable fPutBack to TRUE\r
1053 and copies the current token info so save it\r
1054 so it can be used again. (returning a token\r
1055 to the stream...)\r
1056 **********************************************/\r
1057 void ReturnToken(void)\r
1058 {\r
1059 strncpy(LTString, TString, 132);\r
1060 LCBString = CBString;\r
1061 LTSymnum = TSymnum;\r
1062 LTNumber = TNumber;\r
1063 LTInst = TInst;\r
1064 LTReg = TReg;\r
1065 LToken = Token;\r
1066 fPutBack = 1;\r
1067 }\r
1068 \r
1069 \r
1070 /********************************************\r
1071  Parse reads and identifies the next token\r
1072  for the caller. See SASM.h for info on each\r
1073  of the tokens it identifies.\r
1074  Token type is placed in Token.\r
1075  All parsed chars are placed in TString.\r
1076  Size of TString is placed in CBString.\r
1077  Converted numeric values are put in TNumber.\r
1078  Instruction numbers are placed in TInst.\r
1079  Declared symbol ID numbers are placed in TSymnum.\r
1080 \r
1081  Unidentified strings are first checked for\r
1082  macro substitution and replaced with the\r
1083  stored string if found. If no macro is\r
1084  found, the symbol table is searched to see if\r
1085  it's a symbol. If so, it's returned. If not\r
1086  a symbol, Parse assumes it may be a new one\r
1087  and leaves it in TString with the TokenType\r
1088  of UNKSYM.\r
1089 *********************************************/\r
1090 \r
1091 S32 Parse(void)\r
1092 {\r
1093 S32  i;\r
1094 \r
1095 if (fPutBack) {         /* if a symbol was put back this makes it current */\r
1096         strncpy(TString, LTString, 132);\r
1097         CBString = LCBString;\r
1098         TSymnum = LTSymnum;\r
1099         TNumber = LTNumber;\r
1100         TInst = LTInst;\r
1101         TReg = LTReg;\r
1102         Token = LToken;\r
1103         fPutBack = 0;\r
1104         return(Token);\r
1105 }\r
1106 \r
1107 begin:                          /* return here after MACRO substitution */\r
1108  TSymnum = 0;\r
1109  TInst = 0;\r
1110  TReg = 0;\r
1111  Token = 0;\r
1112  TString[0] = 0;\r
1113  CBString = 0;\r
1114  TNumber = 0;\r
1115 \r
1116  while(isskip(*line_ptr)) line_ptr++;           /* skip while space */\r
1117  if (!(*line_ptr)) return(0);                           /* end of line */\r
1118 \r
1119  if     (*line_ptr == SEMI)                                     /* if comment */\r
1120  {\r
1121         *line_ptr = 0;                                  /* kill rest of line */\r
1122         return(0);                                              /* return 0 for EOL */\r
1123  }\r
1124 \r
1125   /* See if it's a legal 1st char for identifier or reserved word. */\r
1126   /* If so, pick it up and put it in TString ALL UPPER CASE */\r
1127 \r
1128  i=0;\r
1129  if (is_ident(*line_ptr))\r
1130  {\r
1131          while( (isalnum(*line_ptr)) || (*line_ptr == '_') )\r
1132          {\r
1133                  TString[i++] = toupper(*line_ptr++);\r
1134          }\r
1135         CBString = i;\r
1136         TString[i] = 0;\r
1137 \r
1138     if (TReg = findreg(TString, i))    /* Register? */\r
1139                 return (Token = REGIST);\r
1140 \r
1141     if (TInst = findinst(TString, i))  /* Instruction? */\r
1142                 return (Token = INSTRU);\r
1143 \r
1144     if (Token = findrsvd(TString, i))  /* Reserved Word? */\r
1145                 return (Token);\r
1146 \r
1147         if (level) {\r
1148                 if (TSymnum = findLsymbol(TString, i)) {\r
1149 \r
1150                         if (lst[TSymnum].Type & MACRO) {                /* MACRO !! */\r
1151                           i = lst[TSymnum].Offs;                                /* get number */\r
1152                           strcpy(line_buf1, rgMacPtr[i]);               /* move it in */\r
1153                           strncat(line_buf1, line_ptr, 132);    /* cat rest of line */\r
1154                           line_ptr = line_buf1;\r
1155                           goto begin;\r
1156                         }\r
1157                         else return (Token = LSYMBOL);\r
1158                 }\r
1159         }\r
1160 \r
1161         if (TSymnum = findGsymbol(TString, i))\r
1162         {\r
1163                  return (Token = SYMBOL);\r
1164         }\r
1165         else return (Token = UNKSYM);\r
1166  }\r
1167 \r
1168  /* If char was not legal for an identifier the only things left\r
1169     are digits, special characters, and 'strings' */\r
1170 \r
1171  if (isdigit(*line_ptr))\r
1172  {\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         {\r
1198                 line_ptr++;\r
1199                 while ((*line_ptr) && (*line_ptr != SQUOTE) && (i < 132))\r
1200                         TString[i++] = *line_ptr++;\r
1201                 CBString = i;\r
1202                 if (*line_ptr != SQUOTE)\r
1203                         line_error(6);\r
1204                 else\r
1205                         line_ptr++;             /* next char if this is SQUOTE */\r
1206                 TString[i] = 0;         /* null terminate string */\r
1207                 CBString = i;           /* Set size */\r
1208                 return(Token = STRING);\r
1209                 }\r
1210     default: {\r
1211                 line_error(7);\r
1212                 return(Token = ERROR);\r
1213         }\r
1214  } /* end switch */\r
1215 }\r
1216 \r
1217 /**************************************\r
1218   Handles include files for INCLUDE and\r
1219   SEARCH commands.\r
1220 ***************************************/\r
1221 void DoInclude(char *pName)\r
1222 {\r
1223                 if (level < LEVELS-1) {\r
1224                          ++level;\r
1225 \r
1226                         strcpy(srcname[level], pName);\r
1227 \r
1228                         if(!(src_fh[level] = fopen(srcname[level], "r"))) {\r
1229                                 --level;\r
1230                                 fatal_error("Can't open INCLUDE file\n");\r
1231                                 }\r
1232                         else\r
1233                                 lineno[level] = 0;\r
1234 \r
1235                         if (fListA) {\r
1236                                 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
1237                                 Column += fprintf(lst_fh, "INCLUDE: %s", srcname[level]);\r
1238                                 }\r
1239                         }\r
1240                 else\r
1241                         fatal_error("EXCEEDED MAX INCLUDE DEPTH (5)");\r
1242 \r
1243 }\r
1244 \r
1245 /*******************************************\r
1246   Handles SEARCH command for library search.\r
1247   We open the PUB file given and find the\r
1248   first filename. We save this name, then\r
1249   run through the publics seeing if we\r
1250   need any of them.\r
1251 *******************************************/\r
1252 void DoSearch(char *pName)\r
1253 {\r
1254 \r
1255 }\r
1256 \r
1257 \r
1258 /********************************************\r
1259    Handles DOT Commands\r
1260 *********************************************/\r
1261 void Command(void)\r
1262 {\r
1263 U32 num;\r
1264 S32 i, ii;\r
1265 char tmpname[50];\r
1266 \r
1267 i = Parse();\r
1268 \r
1269 switch(i)\r
1270 {\r
1271         case rDATA:\r
1272                 fDataSeg = 1;\r
1273                 if (fListA) {\r
1274                         pNextAddr = &oNextData;\r
1275                         Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
1276                         Column += fprintf(lst_fh, "<- DSEG Begin", lst_fh);\r
1277                         }\r
1278                 break;\r
1279         case rCODE:\r
1280                 fDataSeg = 0;\r
1281                 if (fListA) {\r
1282                         pNextAddr = &oNextCode;\r
1283                         Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
1284                         Column += fprintf(lst_fh, "<- CSEG Begin", lst_fh);\r
1285                         }\r
1286                 break;\r
1287         case rALIGN:\r
1288                 ii = Parse();\r
1289                 if (fListA)\r
1290                         Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
1291                 if (ii == rWORD)\r
1292                 {\r
1293                         if (fListA)\r
1294                                 Column += fprintf(lst_fh, "<- WORD ALIGN, PAD: ", lst_fh);\r
1295                         if (fDataSeg)\r
1296                         {\r
1297                                 if (oNextData & 1)\r
1298                                 {\r
1299                                         OutByteX(0);    /* EMIT byte to Data seg, value 0 */\r
1300                                         if (fListA)\r
1301                                                 Column += fprintf(lst_fh, "00 ", lst_fh);\r
1302                                 }\r
1303                         }\r
1304                         else\r
1305                         {\r
1306                                 if (oNextCode & 1)\r
1307                                 {\r
1308                                         OutByteX(0x90); /* EMIT byte to Code seg, 0x90 (NOP) */\r
1309                                         if (fListA)\r
1310                                                 Column += fprintf(lst_fh, "90 ", lst_fh);\r
1311                                 }\r
1312                         }\r
1313                 }\r
1314                 else if (ii == rDWORD)\r
1315                 {\r
1316                         if (fListA)\r
1317                                 Column += fprintf(lst_fh, "<- DWORD ALIGN, PAD: ", lst_fh);\r
1318                         if (fDataSeg)\r
1319                         {\r
1320                                 while (oNextData & 3) {\r
1321                                         OutByteX(0);    /* EMIT byte to Data seg, value 0 */\r
1322                                         if (fListA)\r
1323                                                 Column += fprintf(lst_fh, "00 ", lst_fh);\r
1324                                 }\r
1325                         }\r
1326                         else\r
1327                         {\r
1328                                 while (oNextCode & 3)\r
1329                                 {\r
1330                                         OutByteX(0x90); /* EMIT byte to Code seg, 0x90 (NOP) */\r
1331                                         if (fListA)\r
1332                                                 Column += fprintf(lst_fh, "90 ", lst_fh);\r
1333                                 }\r
1334                         }\r
1335                 }\r
1336                 else if (ii == rPARA)\r
1337                 {\r
1338                         if (fListA)\r
1339                                 Column += fprintf(lst_fh, "<- PARA(16) ALIGN, PAD: ", lst_fh);\r
1340                         if (fDataSeg)\r
1341                         {\r
1342                                 while (oNextData & 0x0f) {\r
1343                                         OutByteX(0);    /* EMIT byte to Data seg, value 0 */\r
1344                                         if (fListA)\r
1345                                                 Column += fprintf(lst_fh, "00 ", lst_fh);\r
1346                                 }\r
1347                         }\r
1348                         else\r
1349                         {\r
1350                                 while (oNextCode & 0x0f)\r
1351                                 {\r
1352                                         OutByteX(0x90); /* EMIT byte to Code seg, 0x90 (NOP) */\r
1353                                         if (fListA)\r
1354                                                 Column += fprintf(lst_fh, "90 ", lst_fh);\r
1355                                 }\r
1356                         }\r
1357                 }\r
1358                 else\r
1359                         line_error(8);\r
1360                 break;\r
1361         case rEND:\r
1362                 if (fListA) {\r
1363                         Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
1364                         Column += fprintf(lst_fh, "<- END of Source ");\r
1365                         }\r
1366                 break;\r
1367         case rSTART:\r
1368                 if (!fDataSeg) {\r
1369                         if (fListA) {\r
1370                                 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
1371                                 Column += fprintf(lst_fh, "<- START Address ");\r
1372                                 }\r
1373             fStart = 1;\r
1374             StartAddr = oNextCode;\r
1375                         }\r
1376                 else\r
1377                         line_error(9);\r
1378                 break;\r
1379         case rVIRTUAL:\r
1380                 if (fDataSeg) {\r
1381                         if (fListA)\r
1382                                 Column += fprintf(lst_fh, "VIRTUAL Segment address: ");\r
1383                         if (Parse() == NUMBER) {\r
1384                                 if (oNextData > 0)\r
1385                                         line_error(10);\r
1386                                 else {\r
1387                                         if (fListA)\r
1388                                                 Column += fprintf(lst_fh, "%08lX", TNumber);\r
1389                                         oNextData = TNumber;\r
1390                                         DataOffset = TNumber;\r
1391                                 }\r
1392                         }\r
1393                         else\r
1394                           line_error(11);\r
1395                 }\r
1396                 else {\r
1397                         if (fListA)\r
1398                                 Column += fprintf(lst_fh, "VIRTUAL Segment address: ");\r
1399                         if (Parse() == NUMBER) {\r
1400                                 if (oNextCode > 0)\r
1401                                         line_error(10);\r
1402                                 else {\r
1403                                         if (fListA)\r
1404                                                 Column += fprintf(lst_fh, "%08lX", TNumber);\r
1405                                         oNextCode = TNumber;\r
1406                                         CodeOffset = TNumber;\r
1407                                 }\r
1408                     }\r
1409                         else\r
1410                           line_error(11);\r
1411                 }\r
1412                 break;\r
1413         case rINCLUDE:\r
1414                 tmpname[0] = 0;         /* default to null name */\r
1415                 while (isskip(*line_ptr)) line_ptr++;\r
1416                 i=0;\r
1417                 while ((*line_ptr) && (*line_ptr != ';') && (!isskip(*line_ptr)))\r
1418                         tmpname[i++] = *line_ptr++;\r
1419                 tmpname[i] = 0;                                 /* null terminate */\r
1420 \r
1421                 DoInclude(tmpname);\r
1422                 break;\r
1423         case rSEARCH:\r
1424                 tmpname[0] = 0;         /* default to null name */\r
1425                 while (isskip(*line_ptr)) line_ptr++;\r
1426                 i=0;\r
1427                 while ((*line_ptr) && (*line_ptr != ';') && (!isskip(*line_ptr)))\r
1428                         tmpname[i++] = *line_ptr++;\r
1429                 tmpname[i] = 0;                                 /* null terminate */\r
1430 \r
1431                 DoSearch(tmpname);\r
1432                 break;\r
1433         case rSTACK:\r
1434                 if (!fDataSeg) {\r
1435                         if (fListA)\r
1436                                 Column += fprintf(lst_fh, "Stack Total: ");\r
1437                         if (Parse() == NUMBER) {\r
1438                                 StackTotal += TNumber;\r
1439                                 if (fListA)\r
1440                                         Column += fprintf(lst_fh, "%08lX", StackTotal);\r
1441                         }\r
1442                         else\r
1443                                 line_error(35); /* Invalid number or expression */\r
1444                 }\r
1445                 else\r
1446                   line_error(13);\r
1447                 break;\r
1448         default: line_error(14);\r
1449                 return;\r
1450 }\r
1451 }\r
1452 \r
1453 /********************************************\r
1454  This adds the 3 bit code for the specified\r
1455  register to the ModRM or SIB bytes which\r
1456  is pointed to by *modbyte. nshift is the\r
1457  number of bits to shift the register code\r
1458  before ORing it with *modbyte (ModRM or SIB).\r
1459 *********************************************/\r
1460 \r
1461 void EncodeRegBits(S32 regnum, S8   *modbyte, S32 nshift)\r
1462 {\r
1463 \r
1464 switch (regnum) {\r
1465         case rAL:\r
1466         case rAX:               /* value is 1 don't do anything */\r
1467         case rEAX:\r
1468         case rES:\r
1469         case rCR0:\r
1470         case rDR0:\r
1471                 break;\r
1472         case rCL:\r
1473         case rCX:\r
1474         case rECX:\r
1475         case rCS:\r
1476         case rCR1:\r
1477         case rDR1:\r
1478                 *modbyte |= (1 << nshift);\r
1479                 break;\r
1480         case rDL:\r
1481         case rDX:\r
1482         case rEDX:\r
1483         case rSS:\r
1484         case rCR2:\r
1485         case rDR2:\r
1486                 *modbyte |= (2 << nshift);\r
1487                 break;\r
1488         case rBL:\r
1489         case rBX:\r
1490         case rEBX:\r
1491         case rDS:\r
1492         case rCR3:\r
1493         case rDR3:\r
1494                 *modbyte |= (3 << nshift);\r
1495                 break;\r
1496         case rAH:\r
1497         case rSP:\r
1498         case rESP:\r
1499                 *modbyte |= (4 << nshift);\r
1500                 break;\r
1501         case rCH:\r
1502         case rBP:\r
1503         case rEBP:\r
1504         case rFS:\r
1505                 *modbyte |= (5 << nshift);\r
1506                 break;\r
1507         case rDH:\r
1508         case rSI:\r
1509         case rESI:\r
1510         case rGS:\r
1511         case rTR6:\r
1512         case rDR6:\r
1513                 *modbyte |= (6 << nshift);\r
1514                 break;\r
1515         case rBH:\r
1516         case rDI:\r
1517         case rEDI:\r
1518         case rTR7:\r
1519         case rDR7:\r
1520                 *modbyte |= (7 << nshift);\r
1521                 break;\r
1522         default:;               /* if it's not one of these we do nothing */\r
1523 }\r
1524 }\r
1525 \r
1526 /********************************************\r
1527   Add Macro to LOCAL symbol table.\r
1528   The last symbol added to the symbol\r
1529   table is the label for this macro.\r
1530 \r
1531 *********************************************/\r
1532 void AddMacro(void)\r
1533 {\r
1534 S32 i, j;\r
1535 S8   mac[100];\r
1536 \r
1537 mac[0] = 0;\r
1538 \r
1539 if (iMacNext >= MACBUFMAX-50)\r
1540         fatal_error("Macro buffer overflow...");\r
1541 if (iMacNext >= MACSMAX)\r
1542         fatal_error("Macro table overflow...");\r
1543 \r
1544 i = 0; j = 0;\r
1545 while(isskip(*line_ptr)) line_ptr++;            /* skip while space */\r
1546 \r
1547 /* Read the macro including white space upto EOL or comment.\r
1548    j keeps track of the last NON-space character so we don't\r
1549    store unneeded spaces at the end of the macro.\r
1550 */\r
1551 \r
1552 while ((*line_ptr) && (*line_ptr != SEMI)) {\r
1553         mac[i++] = *line_ptr++;\r
1554         if (mac[i-1] > 0x20) j = i;                     /* j will be length */\r
1555 }\r
1556 \r
1557 strncpy(pMacNext, mac, j);\r
1558 \r
1559 /* These are all "iLSymNext-1" because the Macro label has\r
1560    already been added to the symbol table when AddMacro\r
1561    is called.\r
1562 */\r
1563 \r
1564 lst[iLSymNext-1].Type = 0;                      /* cancel previous type */\r
1565 lst[iLSymNext-1].Type |= MACRO;         /* initialize type */\r
1566 \r
1567 rgMacPtr[iMacNext] = pMacNext;          /* store mac ptr in pmac array */\r
1568 lst[iLSymNext-1].Offs = iMacNext;       /* store mac # in offset */\r
1569 iMacNext++;\r
1570 pMacNext += j;\r
1571 *pMacNext = 0;                                          /* null terminate the macro */\r
1572 pMacNext++;\r
1573 \r
1574 }\r