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
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
13 char is_ident(char chr)
\r
15 return (isalpha(chr)) || (chr == '_');
\r
19 /********************************************
\r
20 Determine if character is "skip" character.
\r
21 All values from 0x20 down to CTRL-A are
\r
23 *********************************************/
\r
25 char isskip(char chr)
\r
27 if ((chr > 0) && (chr <= ' ')) return(1);
\r
30 /**************************************
\r
31 Write a Hex byte to a file fout.
\r
32 ***************************************/
\r
34 void put_hexb(U8 value, FILE *fout)
\r
41 stack[i] = (value % 16) + '0';
\r
42 if (stack[i] > 0x39)
\r
47 while (i < j--) { /* zero pad front end to width */
\r
51 fputc(stack[--i], fout);
\r
55 /**************************************
\r
56 Write a Hex number to a file fout.
\r
57 ***************************************/
\r
59 void put_hexw(U32 value, FILE *fout)
\r
67 stack[i] = (value % 16) + '0';
\r
68 if (stack[i] > 0x39)
\r
73 while (i < j--) { /* zero pad front end to width */
\r
77 fputc(stack[--i], fout);
\r
81 /**************************************
\r
82 Write a hex dword to a file fout.
\r
83 ***************************************/
\r
85 void put_hexd(U32 value, FILE *fout)
\r
93 stack[i] = (value % 16) + '0';
\r
94 if (stack[i] > 0x39)
\r
99 while (i < j--) { /* zero pad front end to width */
\r
103 fputc(stack[--i], fout);
\r
108 /*************************************
\r
109 Acquires VALUE for Expression()
\r
110 *************************************/
\r
111 long expr4(long *val)
\r
115 if (Token == rOFFSET) {
\r
120 if (Token == OPENRND) { /* Open paren */
\r
123 if (Token == CLOSRND) {
\r
131 else if (Token == NUMBER) {
\r
133 Parse(); /* set up for next token check */
\r
135 else if (Token == LSYMBOL) {
\r
137 *val = lst[TSymnum].Offs;
\r
138 iExpSym = TSymnum; /* so we can trace symbol number came from */
\r
140 Parse(); /* set up for next token check */
\r
142 else if (Token == SYMBOL) {
\r
144 *val = gst[TSymnum].Offs;
\r
145 iExpSym = TSymnum; /* so we can trace symbol number came from */
\r
147 Parse(); /* set up for next token check */
\r
149 else if (Token == UNKSYM) {
\r
151 *val = 0; /* No offset for UNKSYM */
\r
153 ExpType = 0; /* 0 means forward ref. No Assumption. */
\r
155 /* Save name for forward reference */
\r
156 strncpy(UString, TString, 30);
\r
160 UCBString = CBString; /* Size of Unknown label */
\r
161 UString[UCBString] = '\0'; /* Null terminate */
\r
163 Parse(); /* set up for next token check */
\r
165 else if (Token == DOLLAR) {
\r
171 Parse(); /* set up for next token check */
\r
180 /*****************************************
\r
181 Evaluates a UNARY MINUS for Expression()
\r
182 *****************************************/
\r
183 long expr3(long *val)
\r
187 if (Token == MINUS) { /* Unary MINUS */
\r
188 Parse(); /* set up for next token check */
\r
206 /*************************************
\r
207 Evaluates a * and / Expression()
\r
208 *************************************/
\r
209 long expr2(long *val)
\r
215 if ((Token != STAR) && (Token != SLASH))
\r
218 if (Token == STAR) { /* MULTIPLY */
\r
219 Parse(); /* set up for next token check */
\r
223 else if (Token == SLASH) { /* DIVIDE */
\r
224 Parse(); /* set up for next token check */
\r
228 else return(1); /* Expr doesn't continue but it's OK to here */
\r
232 /*************************************
\r
233 Evaluates a + and - for Expression()
\r
234 *************************************/
\r
235 long expr1(long *val)
\r
241 if ((Token != PLUS) && (Token != MINUS)) return(k);
\r
243 if (Token == PLUS) {
\r
245 if (Token==REGIST) return(1); /* allow for N+REG */
\r
250 else if (Token == MINUS) {
\r
252 if (Token==REGIST) return(1); /* allow for N+REG */
\r
257 else return(1); /* Expr doesn't continue but it's OK to here */
\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
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
290 long Expression(void)
\r
300 if (Token) /* if not EOL (EOL returns 0) */
\r
301 ReturnToken(); /* give back non-expression token */
\r
302 if (nExpSyms == 1) {
\r
304 Token = NUMOFF; /* Derived from OFFSET cmd */
\r
306 Token = SYMOFF; /* single address operator used (Mem Type) */
\r
309 Token = NUMBER; /* Make current token a NUMBER */
\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
315 else return(0); /* Tell em they got an error */
\r
318 /*****************************************************
\r
319 Determines if token is 32 bit general register.
\r
320 *****************************************************/
\r
321 long is_r32(long id)
\r
331 case rESP: return(1);
\r
332 default: return(0);
\r
336 /*****************************************************
\r
337 Determines if token is 16 bit general.
\r
338 *****************************************************/
\r
339 long is_r16(long id)
\r
349 case rSP: return(1);
\r
350 default: return(0);
\r
354 /*****************************************************
\r
355 Determines if token is 8 bit general register.
\r
356 *****************************************************/
\r
357 long is_r8(long id)
\r
367 case rDH: return(1);
\r
368 default: return(0);
\r
372 /*****************************************************
\r
373 Determines if token is Segment Register.
\r
374 *****************************************************/
\r
375 long is_rSEG(long id)
\r
383 case rSS: return(1);
\r
384 default: return(0);
\r
388 /*****************************************************
\r
389 Determines if token is Debug register.
\r
390 *****************************************************/
\r
391 long is_rDRG(long id)
\r
399 case rDR7: return(1);
\r
400 default: return(0);
\r
404 /*****************************************************
\r
405 Determines if token is Control register.
\r
406 *****************************************************/
\r
407 long is_rCRG(long id)
\r
409 return ((id == rCR0) || (id == rCR2) || (id == rCR3));
\r
412 /*****************************************************
\r
413 Determines if token is Test register.
\r
414 *****************************************************/
\r
415 long is_rTRG(long id)
\r
417 return ((id == rTR6) || (id == rTR7));
\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
425 *****************************************************/
\r
428 long is_Comp(long ins, long op)
\r
430 switch (rgINS[ins][op+1]) { /* check against op type in instruction */
\r
432 if (!rgOpType[op]) return(1); /* no operand in either matches */
\r
435 if (rgOpType[op] == rel8) return(1);
\r
438 if (rgOpType[op] == relW) return(1);
\r
441 if (rgOpType[op] == r8) return(1);
\r
444 if (rgOpType[op] == r8) return(1);
\r
447 if (rgOpType[op] == r16) return(1);
\r
450 if (rgOpType[op] == r32) return(1);
\r
453 if ((rgOpType[op] == r8) ||
\r
454 (rgOpType[op] == r16) ||
\r
455 (rgOpType[op] == r32)) return(1);
\r
458 if ((rgOpType[op] == r16) ||
\r
459 (rgOpType[op] == r32)) return(1);
\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
468 if (rgOpType[op] == rSEG) return(1);
\r
471 if (rgOpType[op] == rCRG) return(1);
\r
474 if (rgOpType[op] == rDRG) return(1);
\r
477 if (rgOpType[op] == rTRG) return(1);
\r
480 if (rgOpType[op] == val8)
\r
483 if ((rgOpType[op] == val16) &&
\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
495 if (rgOpType[op] == val8)
\r
498 if ((rgOpType[op] == val16) &&
\r
505 if ((rgOpType[op] == val8) ||
\r
506 (rgOpType[op] == val16)) return(1);
\r
509 if ((rgOpType[op] == val8) ||
\r
510 (rgOpType[op] == val16) ||
\r
511 (rgOpType[op] == val32)) return(1);
\r
514 if ((rgOpType[op] == r8) ||
\r
515 ((rgOpType[op] == mem) && (OpSize[op] & fByte))) return(1);
\r
518 if ((rgOpType[op] == r16) ||
\r
519 ((rgOpType[op] == mem) && (OpSize[op] & fWord)) ) return(1);
\r
522 if ((rgOpType[op] == r8) ||
\r
523 (rgOpType[op] == r16) ||
\r
524 (rgOpType[op] == r32) ||
\r
525 (rgOpType[op] == mem)) return(1);
\r
528 if (rgOpType[op] == mem)
\r
530 if (OpSize[op] & fFWord)
\r
532 if (OpSize[op] & fByte)
\r
536 if ((rgOpType[op] == r16) ||
\r
537 (rgOpType[op] == r32))
\r
541 if ((rgOpType[op] == mem) && (!(OpSize[op] & fFWord))) return(1);
\r
544 if ((rgOpType[op] == memF) && (OpSize[op] & fFWord)) return(1);
\r
547 if ((rgOpType[op] == mem) &&
\r
548 (OpMType & fDisp32) &&
\r
549 ((OpMType & fIndx)==0) &&
\r
550 ((OpMType & fBase)==0))
\r
554 if ((rgOpType[op] == val8) &&
\r
555 (OpImm == 3)) return(1);
\r
558 if ((rgOpType[op] == val8) &&
\r
559 (OpImm == 1)) return(1);
\r
562 if ((rgOpType[op] == r16) &&
\r
563 (rgOpReg[op] == rDX)) return(1);
\r
566 if ((rgOpType[op] == r8) &&
\r
567 (rgOpReg[op] == rCL)) return(1);
\r
570 if ((rgOpType[op] == r8) &&
\r
571 (rgOpReg[op] == rAL)) return(1);
\r
574 if ((rgOpType[op] == r16) &&
\r
575 (rgOpReg[op] == rAX)) return(1);
\r
578 if ((rgOpType[op] == r32) &&
\r
579 (rgOpReg[op] == rEAX)) return(1);
\r
587 if ((rgOpType[op] == rSEG) &&
\r
588 (rgOpReg[op] == rgINS[ins][op+1])) return(1);
\r
595 /*****************************************************
\r
596 Determines if entry in rgOpType is a register.
\r
597 *****************************************************/
\r
599 long is_Reg(long op)
\r
601 switch (op) { /* This should be the value from rgOpType[x] */
\r
615 /*********************************************
\r
616 This displays the string and exits for a FATAL
\r
618 **********************************************/
\r
620 void fatal_error(S8 *pst)
\r
625 if (fListA | fListE) {
\r
626 fprintf(lst_fh, "\r\nFATAL ERROR, line %ld - %s\r\n", lineno[level], pst);
\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
641 /*********************************************
\r
642 This displays the string and line number for
\r
644 **********************************************/
\r
646 void line_error(long 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
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
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
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
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
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
737 void prev_error(S8 *pst, S32 line)
\r
739 fprintf(lst_fh, "\r\nERROR, line %d - %s\r\n", line, pst);
\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
751 U32 get_number(void)
\r
759 base = 10; /* default base is 10 */
\r
761 while(isxdigit(c = *line_ptr)) { /* get all the digits */
\r
766 if ((*line_ptr== 'h') || (*line_ptr== 'H')) { /* looks like hex */
\r
770 else if ((st[len-1] == 'b') || (st[len-1] == 'B')) {
\r
774 if (((base == 2) && (len > 33)) ||
\r
775 ((base == 10) && (len > 10)) ||
\r
776 ((base == 16) && (len > 9))) {
\r
783 if(isdigit(c)) /* convert numeric digits */
\r
785 else if(c >= 'a') /* convert lower case alphas */
\r
787 else if(c >= 'A') /* convert upper case alphas */
\r
791 if(c >= base) { /* outside of base */
\r
795 value = (value * base) + c; /* include in total */
\r
797 while(i < len); /* to length of string */
\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
806 S32 findrsvd(S8 *pb, S32 cb) /* pointer to and size of string */
\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
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
823 else /* it was more */
\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
834 S32 findinst(S8 *pb, S32 cb) /* pointer to and size of parsed string */
\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
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
851 else /* idwas more */
\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
862 S32 findreg(S8 *pb, S32 cb) /* pointer to, and size of parsed string */
\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
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
879 else /* it was more */
\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
892 S32 findLsymbol(S8 *pb, S32 cb) /* pointer to, and size of string */
\r
897 strncpy(name, pb, cb); /* move name local */
\r
898 name[cb] = 0; /* null terminate */
\r
901 while (i>1) { /* backwards through symbol table */
\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
908 return(0); /* not found... */
\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
922 S32 findGsymbol(S8 *pb, S32 cb) /* pointer to, and size of string */
\r
927 strncpy(name, pb, cb); /* move name local */
\r
928 name[cb] = 0; /* null terminate */
\r
931 while (i>1) { /* backwards through symbol table */
\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
938 return(0); /* not found... */
\r
941 /*********************************************
\r
942 DUMP SYMBOL TABLE FOR TESTING
\r
943 **********************************************/
\r
945 void DumpGSymbols(void)
\r
950 fprintf(lst_fh, "PUBLIC SYMBOLS: \r\n");
\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
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
984 /*********************************************
\r
985 DUMP SYMBOL TABLE FOR TESTING
\r
986 **********************************************/
\r
988 void DumpLSymbols(void)
\r
993 fprintf(lst_fh, "LOCAL SYMBOLS: \r\n");
\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
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
1026 /*********************************************
\r
1027 DUMP Forward Reference Table for testing
\r
1028 **********************************************/
\r
1030 void DumpFRT(void)
\r
1035 fprintf(lst_fh, "FORWARD REFERENCES:\n");
\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
1042 fprintf(lst_fh, "Name: %s Offset: %lX Line: %d\n",
\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
1056 **********************************************/
\r
1057 void ReturnToken(void)
\r
1059 strncpy(LTString, TString, 132);
\r
1060 LCBString = CBString;
\r
1061 LTSymnum = TSymnum;
\r
1062 LTNumber = TNumber;
\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
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
1089 *********************************************/
\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
1107 begin: /* return here after MACRO substitution */
\r
1116 while(isskip(*line_ptr)) line_ptr++; /* skip while space */
\r
1117 if (!(*line_ptr)) return(0); /* end of line */
\r
1119 if (*line_ptr == SEMI) /* if comment */
\r
1121 *line_ptr = 0; /* kill rest of line */
\r
1122 return(0); /* return 0 for EOL */
\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
1129 if (is_ident(*line_ptr))
\r
1131 while( (isalnum(*line_ptr)) || (*line_ptr == '_') )
\r
1133 TString[i++] = toupper(*line_ptr++);
\r
1138 if (TReg = findreg(TString, i)) /* Register? */
\r
1139 return (Token = REGIST);
\r
1141 if (TInst = findinst(TString, i)) /* Instruction? */
\r
1142 return (Token = INSTRU);
\r
1144 if (Token = findrsvd(TString, i)) /* Reserved Word? */
\r
1148 if (TSymnum = findLsymbol(TString, i)) {
\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
1157 else return (Token = LSYMBOL);
\r
1161 if (TSymnum = findGsymbol(TString, i))
\r
1163 return (Token = SYMBOL);
\r
1165 else return (Token = UNKSYM);
\r
1168 /* If char was not legal for an identifier the only things left
\r
1169 are digits, special characters, and 'strings' */
\r
1171 if (isdigit(*line_ptr))
\r
1173 TNumber = get_number();
\r
1174 return (Token = NUMBER);
\r
1176 switch (*line_ptr) {
\r
1190 Token = *line_ptr;
\r
1191 TString[0] = *line_ptr++;
\r
1199 while ((*line_ptr) && (*line_ptr != SQUOTE) && (i < 132))
\r
1200 TString[i++] = *line_ptr++;
\r
1202 if (*line_ptr != SQUOTE)
\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
1212 return(Token = ERROR);
\r
1214 } /* end switch */
\r
1217 /**************************************
\r
1218 Handles include files for INCLUDE and
\r
1220 ***************************************/
\r
1221 void DoInclude(char *pName)
\r
1223 if (level < LEVELS-1) {
\r
1226 strcpy(srcname[level], pName);
\r
1228 if(!(src_fh[level] = fopen(srcname[level], "r"))) {
\r
1230 fatal_error("Can't open INCLUDE file\n");
\r
1233 lineno[level] = 0;
\r
1236 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
1237 Column += fprintf(lst_fh, "INCLUDE: %s", srcname[level]);
\r
1241 fatal_error("EXCEEDED MAX INCLUDE DEPTH (5)");
\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
1251 *******************************************/
\r
1252 void DoSearch(char *pName)
\r
1258 /********************************************
\r
1259 Handles DOT Commands
\r
1260 *********************************************/
\r
1261 void Command(void)
\r
1274 pNextAddr = &oNextData;
\r
1275 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
1276 Column += fprintf(lst_fh, "<- DSEG Begin", lst_fh);
\r
1282 pNextAddr = &oNextCode;
\r
1283 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
1284 Column += fprintf(lst_fh, "<- CSEG Begin", lst_fh);
\r
1290 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
1294 Column += fprintf(lst_fh, "<- WORD ALIGN, PAD: ", lst_fh);
\r
1297 if (oNextData & 1)
\r
1299 OutByteX(0); /* EMIT byte to Data seg, value 0 */
\r
1301 Column += fprintf(lst_fh, "00 ", lst_fh);
\r
1306 if (oNextCode & 1)
\r
1308 OutByteX(0x90); /* EMIT byte to Code seg, 0x90 (NOP) */
\r
1310 Column += fprintf(lst_fh, "90 ", lst_fh);
\r
1314 else if (ii == rDWORD)
\r
1317 Column += fprintf(lst_fh, "<- DWORD ALIGN, PAD: ", lst_fh);
\r
1320 while (oNextData & 3) {
\r
1321 OutByteX(0); /* EMIT byte to Data seg, value 0 */
\r
1323 Column += fprintf(lst_fh, "00 ", lst_fh);
\r
1328 while (oNextCode & 3)
\r
1330 OutByteX(0x90); /* EMIT byte to Code seg, 0x90 (NOP) */
\r
1332 Column += fprintf(lst_fh, "90 ", lst_fh);
\r
1336 else if (ii == rPARA)
\r
1339 Column += fprintf(lst_fh, "<- PARA(16) ALIGN, PAD: ", lst_fh);
\r
1342 while (oNextData & 0x0f) {
\r
1343 OutByteX(0); /* EMIT byte to Data seg, value 0 */
\r
1345 Column += fprintf(lst_fh, "00 ", lst_fh);
\r
1350 while (oNextCode & 0x0f)
\r
1352 OutByteX(0x90); /* EMIT byte to Code seg, 0x90 (NOP) */
\r
1354 Column += fprintf(lst_fh, "90 ", lst_fh);
\r
1363 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
1364 Column += fprintf(lst_fh, "<- END of Source ");
\r
1370 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
1371 Column += fprintf(lst_fh, "<- START Address ");
\r
1374 StartAddr = oNextCode;
\r
1382 Column += fprintf(lst_fh, "VIRTUAL Segment address: ");
\r
1383 if (Parse() == NUMBER) {
\r
1384 if (oNextData > 0)
\r
1388 Column += fprintf(lst_fh, "%08lX", TNumber);
\r
1389 oNextData = TNumber;
\r
1390 DataOffset = TNumber;
\r
1398 Column += fprintf(lst_fh, "VIRTUAL Segment address: ");
\r
1399 if (Parse() == NUMBER) {
\r
1400 if (oNextCode > 0)
\r
1404 Column += fprintf(lst_fh, "%08lX", TNumber);
\r
1405 oNextCode = TNumber;
\r
1406 CodeOffset = TNumber;
\r
1414 tmpname[0] = 0; /* default to null name */
\r
1415 while (isskip(*line_ptr)) line_ptr++;
\r
1417 while ((*line_ptr) && (*line_ptr != ';') && (!isskip(*line_ptr)))
\r
1418 tmpname[i++] = *line_ptr++;
\r
1419 tmpname[i] = 0; /* null terminate */
\r
1421 DoInclude(tmpname);
\r
1424 tmpname[0] = 0; /* default to null name */
\r
1425 while (isskip(*line_ptr)) line_ptr++;
\r
1427 while ((*line_ptr) && (*line_ptr != ';') && (!isskip(*line_ptr)))
\r
1428 tmpname[i++] = *line_ptr++;
\r
1429 tmpname[i] = 0; /* null terminate */
\r
1431 DoSearch(tmpname);
\r
1436 Column += fprintf(lst_fh, "Stack Total: ");
\r
1437 if (Parse() == NUMBER) {
\r
1438 StackTotal += TNumber;
\r
1440 Column += fprintf(lst_fh, "%08lX", StackTotal);
\r
1443 line_error(35); /* Invalid number or expression */
\r
1448 default: line_error(14);
\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
1461 void EncodeRegBits(S32 regnum, S8 *modbyte, S32 nshift)
\r
1466 case rAX: /* value is 1 don't do anything */
\r
1478 *modbyte |= (1 << nshift);
\r
1486 *modbyte |= (2 << nshift);
\r
1494 *modbyte |= (3 << nshift);
\r
1499 *modbyte |= (4 << nshift);
\r
1505 *modbyte |= (5 << nshift);
\r
1513 *modbyte |= (6 << nshift);
\r
1520 *modbyte |= (7 << nshift);
\r
1522 default:; /* if it's not one of these we do nothing */
\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
1531 *********************************************/
\r
1532 void AddMacro(void)
\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
1545 while(isskip(*line_ptr)) line_ptr++; /* skip while space */
\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
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
1557 strncpy(pMacNext, mac, j);
\r
1559 /* These are all "iLSymNext-1" because the Macro label has
\r
1560 already been added to the symbol table when AddMacro
\r
1564 lst[iLSymNext-1].Type = 0; /* cancel previous type */
\r
1565 lst[iLSymNext-1].Type |= MACRO; /* initialize type */
\r
1567 rgMacPtr[iMacNext] = pMacNext; /* store mac ptr in pmac array */
\r
1568 lst[iLSymNext-1].Offs = iMacNext; /* store mac # in offset */
\r
1571 *pMacNext = 0; /* null terminate the macro */
\r