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(U16 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 int 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 int 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 int 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 int 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 int 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
331 case rESP: return(1);
\r
332 default: return(0);
\r
336 /*****************************************************
\r
337 Determines if token is 16 bit general.
\r
338 *****************************************************/
\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
367 case rDH: return(1);
\r
368 default: return(0);
\r
372 /*****************************************************
\r
373 Determines if token is Segment Register.
\r
374 *****************************************************/
\r
375 int is_rSEG(int 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 int is_rDRG(int 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 int is_rCRG(int id)
\r
409 return ((id == rCR0) || (id == rCR2) || (id == rCR3));
\r
412 /*****************************************************
\r
413 Determines if token is Test register.
\r
414 *****************************************************/
\r
415 int is_rTRG(int 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 int is_Comp(int ins, int 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
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
638 /* close all files here and delete temps */
\r
645 /*********************************************
\r
646 This displays the string and line number for
\r
648 **********************************************/
\r
650 void line_error(int num)
\r
655 case 1: p="Invalid expression, ')' expected"; break;
\r
656 case 2: p="Invalid expression, value expected"; break;
\r
657 case 3: p="Value expected after unary '-'"; break;
\r
658 case 4: p="Too many digits for numeric radix"; break;
\r
659 case 5: p="Invalid character in a number"; break;
\r
660 case 6: p="Unterminated string"; break;
\r
661 case 7: p="Unrecognized character"; break;
\r
662 case 8: p="Invalid Alignment specified"; break;
\r
663 case 9: p="Start command only allowed in CSEG"; break;
\r
664 case 10: p="Virtual command must be first in segment"; break;
\r
665 case 11: p="Invalid Virtual value"; break;
\r
666 case 12: p="Starting address not found"; break;
\r
667 case 13: p="Stack command not allowed in DSEG"; break;
\r
668 case 14: p="Invalid command"; break;
\r
669 case 15: p="Invalid Operand"; break;
\r
670 case 16: p="Invalid segment register use"; break;
\r
671 case 17: p="Invalid scale value 'Reg*?'"; break;
\r
672 case 18: p="Scale value expected (*2,*4,*8)"; break;
\r
673 case 19: p="Too many address scale values"; break;
\r
674 case 20: p="Invalid register for memory operand"; break;
\r
675 case 21: p="Invalid memory operand"; break;
\r
676 case 22: p="Offset must be from data segment"; break;
\r
677 case 23: p="Nested brackets"; break;
\r
678 case 24: p="Unbalanced brackets"; break;
\r
679 case 25: p="Invalid operand size attribute"; break;
\r
685 case 31: p=""; break;
\r
686 case 32: p="Unknown token in operand array"; break;
\r
687 case 33: p="Too many operands or extra character"; break;
\r
688 case 34: p=""; break;
\r
689 case 35: p="Invalid expression or numeric value"; break;
\r
690 case 36: p="Operand expected before comma"; break;
\r
691 case 37: p=""; break;
\r
692 case 38: p="Invalid character or reserved word in operand"; break;
\r
693 case 39: p="Relative jump out of range"; break;
\r
694 case 40: p="Operand size NOT specified or implied"; break;
\r
695 case 41: p="Instructions not allowed in data segment"; break;
\r
696 case 42: p="Instruction expected after prefix"; break;
\r
697 case 43: p="Operand sizes don't match"; break;
\r
698 case 44: p="Wrong operand type for instruction"; break;
\r
699 case 45: p="Incorrect format for memory operand"; break;
\r
700 case 46: p="Strings only valid for DB storage"; break;
\r
701 case 47: p="Expected '(' after 'DUP'"; break;
\r
702 case 48: p="Storage expected between commas"; break;
\r
703 case 49: p="':' not expected"; break;
\r
704 case 50: p="DWord storage required for OFFSET"; break;
\r
705 case 51: p="Invalid storage value"; break;
\r
707 case 53: p=""; break;
\r
708 case 54: p="':' expected after last label"; break;
\r
709 case 55: p="Macro not allowed in lexical level 0"; break;
\r
710 case 56: p="EQU or Storage expected"; break;
\r
716 case 62: p=""; break;
\r
717 case 63: p="Instruction expected before register name"; break;
\r
718 case 64: p="Public Symbol already defined"; break;
\r
719 case 65: p="Local symbol already defined"; break;
\r
720 case 66: p="Number not expected"; break;
\r
721 case 67: p="New symbol must follow PUBLIC keyword"; break;
\r
722 case 68: p="Label, Command, Instruction, or Storage expected"; break;
\r
723 case 69: p="Inconsistant redeclaration"; break;
\r
724 case 70: p=""; break;
\r
729 fprintf(lst_fh, "\r\nERROR: %d, line: %ld, %s\r\n", num, lineno[level], p);
\r
730 *line_ptr = 0; /* this KILLS the rest of the line */
\r
735 /*********************************************
\r
736 This displays the string and line number for
\r
737 errors dicovered AFTER we past the line.
\r
738 This is for non-fatal errors.
\r
739 **********************************************/
\r
741 void prev_error(S8 *pst, S16 line)
\r
743 fprintf(lst_fh, "\r\nERROR, line %d - %s\r\n", line, pst);
\r
748 /**********************************************************
\r
749 The parser calls this when it detects a digit leaving
\r
750 the line_ptr* pointing to digit. It accepts base 2, 10
\r
751 & 16. Base 2 numbers are suffixed with a B or b, base 16
\r
752 with an h or H and base 10 with no suffix.
\r
753 ***********************************************************/
\r
755 U32 get_number(void)
\r
763 base = 10; /* default base is 10 */
\r
765 while(isxdigit(c = *line_ptr)) { /* get all the digits */
\r
770 if ((*line_ptr== 'h') || (*line_ptr== 'H')) { /* looks like hex */
\r
774 else if ((st[len-1] == 'b') || (st[len-1] == 'B')) {
\r
778 if (((base == 2) && (len > 33)) ||
\r
779 ((base == 10) && (len > 10)) ||
\r
780 ((base == 16) && (len > 9))) {
\r
787 if(isdigit(c)) /* convert numeric digits */
\r
789 else if(c >= 'a') /* convert lower case alphas */
\r
791 else if(c >= 'A') /* convert upper case alphas */
\r
795 if(c >= base) { /* outside of base */
\r
799 value = (value * base) + c; /* include in total */
\r
801 while(i < len); /* to length of string */
\r
805 /*********************************************
\r
806 This is a fast binary search for a reserved
\r
807 word that is not an instructions or a register.
\r
808 **********************************************/
\r
810 S16 findrsvd(S8 *pb, S16 cb) /* pointer to and size of string */
\r
815 if (cb>srsvd) return(0); /* can't be a reserved word */
\r
816 strncpy(id, pb, cb); /* move string local */
\r
817 id[cb] = 0; /* null terminate */
\r
823 f = strncmp(id, rgReserved[k], srsvd-1);
\r
824 if (!f) return(k + nrsvd1); /* found it! */
\r
825 else if (f > 0) /* it was less */
\r
827 else /* it was more */
\r
833 /*********************************************
\r
834 This is a fast binary search for an instuction.
\r
835 It returns the number or 0 if not found.
\r
836 **********************************************/
\r
838 S16 findinst(S8 *pb, S16 cb) /* pointer to and size of parsed string */
\r
843 if (cb>sinst) return(0); /* can't be an instruction */
\r
844 strncpy(id, pb, cb); /* move string local */
\r
845 id[cb] = 0; /* null terminate */
\r
851 f = strncmp(id, rginst[k], sinst-1);
\r
852 if (!f) return(k+1); /* found it! */
\r
853 else if (f > 0) /* id was less */
\r
855 else /* idwas more */
\r
861 /*********************************************
\r
862 This is a fast binary search for a register.
\r
863 It returns the number or 0 if not found.
\r
864 **********************************************/
\r
866 S16 findreg(S8 *pb, S16 cb) /* pointer to, and size of parsed string */
\r
871 if ((cb>sregs-1) || (cb<2)) return(0); /* can't be a register */
\r
872 strncpy(id, pb, cb); /* move string local */
\r
873 id[cb] = 0; /* null pad */
\r
879 f = strncmp(id, rgreg[k], sregs-1);
\r
880 if (!f) return(k+nreg1); /* found it! */
\r
881 else if (f > 0) /* it was less */
\r
883 else /* it was more */
\r
889 /*********************************************
\r
890 This searches the LOCAL symbol table for the name
\r
891 described by pb, cb. It only compares items that
\r
892 are the same length (cb == TSymsize[x]).
\r
893 It returns the number or 0 if not found.
\r
894 **********************************************/
\r
896 S16 findLsymbol(S8 *pb, S16 cb) /* pointer to, and size of string */
\r
901 strncpy(name, pb, cb); /* move name local */
\r
902 name[cb] = 0; /* null terminate */
\r
905 while (i>1) { /* backwards through symbol table */
\r
907 /* Only compare if same size */
\r
908 if (lst[i].Size == cb) {
\r
909 if (strncmp(name, lst[i].Ptr, cb) == 0) return(i);
\r
912 return(0); /* not found... */
\r
916 /*********************************************
\r
917 This searches the symbol table for the name
\r
918 described by pb, cb. It only compares items that
\r
919 are the same length (cb == TSymsize[x]).
\r
920 If the include level is greater than 0 it
\r
921 searches the local first, then the global.
\r
922 If at level 0, it only searches the global.
\r
923 It returns the number or 0 if not found.
\r
924 **********************************************/
\r
926 S16 findGsymbol(S8 *pb, S16 cb) /* pointer to, and size of string */
\r
931 strncpy(name, pb, cb); /* move name local */
\r
932 name[cb] = 0; /* null terminate */
\r
935 while (i>1) { /* backwards through symbol table */
\r
937 /* Only compare if same size */
\r
938 if (gst[i].Size == cb) {
\r
939 if (strncmp(name, gst[i].Ptr, cb) == 0) return(i);
\r
942 return(0); /* not found... */
\r
945 /*********************************************
\r
946 DUMP SYMBOL TABLE FOR TESTING
\r
947 **********************************************/
\r
949 void DumpGSymbols(void)
\r
954 fprintf(lst_fh, "PUBLIC SYMBOLS: \r\n");
\r
957 while (i<iSymNext) { /* forward through symbol table */
\r
958 strncpy(name, gst[i].Ptr, gst[i].Size); /* move to name */
\r
959 name[gst[i].Size] = 0; /* null terminate */
\r
961 fprintf(lst_fh, "Name: %s Offset %08lX ", name, gst[i].Offs);
\r
962 if (gst[i].Type & CLABEL)
\r
963 fprintf(lst_fh, "CSEG ");
\r
964 if (gst[i].Type & DLABEL)
\r
965 fprintf(lst_fh, "DSEG ");
\r
966 if (gst[i].Type & sBYTE)
\r
967 fprintf(lst_fh, "BYTE ");
\r
968 if (gst[i].Type & sWORD)
\r
969 fprintf(lst_fh, "WORD ");
\r
970 if (gst[i].Type & sDWORD)
\r
971 fprintf(lst_fh, "DWORD ");
\r
972 if (gst[i].Type & sFWORD)
\r
973 fprintf(lst_fh, "FWORD ");
\r
974 if (gst[i].Type & tEXTRN)
\r
975 fprintf(lst_fh, "EXTRN ");
\r
976 if (gst[i].Type & tFAR)
\r
977 fprintf(lst_fh, "FAR ");
\r
978 if (gst[i].Type & tPUBLIC)
\r
979 fprintf(lst_fh, "PUBLIC ");
\r
980 if (gst[i].Type & MACRO)
\r
981 fprintf(lst_fh, "MACRO ");
\r
982 fprintf(lst_fh, "\r\n");
\r
988 /*********************************************
\r
989 DUMP SYMBOL TABLE FOR TESTING
\r
990 **********************************************/
\r
992 void DumpLSymbols(void)
\r
997 fprintf(lst_fh, "LOCAL SYMBOLS: \r\n");
\r
1000 while (i<iLSymNext) { /* forward through symbol table */
\r
1001 strncpy(name, lst[i].Ptr, lst[i].Size); /* move to name */
\r
1002 name[lst[i].Size] = 0; /* null terminate */
\r
1004 fprintf(lst_fh, "Name: %s Offset %lX ", name, lst[i].Offs);
\r
1005 if (lst[i].Type & CLABEL)
\r
1006 fprintf(lst_fh, "CSEG ");
\r
1007 if (lst[i].Type & DLABEL)
\r
1008 fprintf(lst_fh, "DSEG ");
\r
1009 if (lst[i].Type & sBYTE)
\r
1010 fprintf(lst_fh, "BYTE ");
\r
1011 if (lst[i].Type & sWORD)
\r
1012 fprintf(lst_fh, "WORD ");
\r
1013 if (lst[i].Type & sDWORD)
\r
1014 fprintf(lst_fh, "DWORD ");
\r
1015 if (lst[i].Type & sFWORD)
\r
1016 fprintf(lst_fh, "FWORD ");
\r
1017 if (lst[i].Type & tEXTRN)
\r
1018 fprintf(lst_fh, "EXTRN ");
\r
1019 if (lst[i].Type & tFAR)
\r
1020 fprintf(lst_fh, "FAR ");
\r
1021 if (lst[i].Type & tPUBLIC)
\r
1022 fprintf(lst_fh, "PUBLIC ");
\r
1023 if (lst[i].Type & MACRO)
\r
1024 fprintf(lst_fh, "MACRO");
\r
1025 fprintf(lst_fh, "\r\n");
\r
1030 /*********************************************
\r
1031 DUMP Forward Reference Table for testing
\r
1032 **********************************************/
\r
1034 void DumpFRT(void)
\r
1039 fprintf(lst_fh, "FORWARD REFERENCES:\n");
\r
1042 while (i<iRefNext) { /* forward through symbol table */
\r
1043 strncpy(name, pfrt[i].Ptr, pfrt[i].NameSz); /* move to name */
\r
1044 name[pfrt[i].NameSz] = 0; /* null terminate */
\r
1046 fprintf(lst_fh, "Name: %s Offset: %lX Line: %d\n",
\r
1055 /*********************************************
\r
1056 This sets the global variable fPutBack to TRUE
\r
1057 and copies the current token info so save it
\r
1058 so it can be used again. (returning a token
\r
1060 **********************************************/
\r
1061 void ReturnToken(void)
\r
1063 strncpy(LTString, TString, 132);
\r
1064 LCBString = CBString;
\r
1065 LTSymnum = TSymnum;
\r
1066 LTNumber = TNumber;
\r
1074 /********************************************
\r
1075 Parse reads and identifies the next token
\r
1076 for the caller. See SASM.h for info on each
\r
1077 of the tokens it identifies.
\r
1078 Token type is placed in Token.
\r
1079 All parsed chars are placed in TString.
\r
1080 Size of TString is placed in CBString.
\r
1081 Converted numeric values are put in TNumber.
\r
1082 Instruction numbers are placed in TInst.
\r
1083 Declared symbol ID numbers are placed in TSymnum.
\r
1085 Unidentified strings are first checked for
\r
1086 macro substitution and replaced with the
\r
1087 stored string if found. If no macro is
\r
1088 found, the symbol table is searched to see if
\r
1089 it's a symbol. If so, it's returned. If not
\r
1090 a symbol, Parse assumes it may be a new one
\r
1091 and leaves it in TString with the TokenType
\r
1093 *********************************************/
\r
1100 if (fPutBack) { /* if a symbol was put back this makes it current */
\r
1101 strncpy(TString, LTString, 132);
\r
1102 CBString = LCBString;
\r
1103 TSymnum = LTSymnum;
\r
1104 TNumber = LTNumber;
\r
1112 begin: /* return here after MACRO substitution */
\r
1121 while(isskip(*line_ptr)) line_ptr++; /* skip while space */
\r
1122 if (!(*line_ptr)) return(0); /* end of line */
\r
1124 if (*line_ptr == SEMI) /* if comment */
\r
1126 *line_ptr = 0; /* kill rest of line */
\r
1127 return(0); /* return 0 for EOL */
\r
1130 /* See if it's a legal 1st char for identifier or reserved word. */
\r
1131 /* If so, pick it up and put it in TString ALL UPPER CASE */
\r
1134 if (is_ident(*line_ptr)) {
\r
1135 while( (isalnum(*line_ptr)) || (*line_ptr == '_') ) {
\r
1136 TString[i++] = toupper(*line_ptr++);
\r
1140 if (TReg = findreg(TString, i)) /* Register? */
\r
1141 return (Token = REGIST);
\r
1143 if (TInst = findinst(TString, i)) /* Instruction? */
\r
1144 return (Token = INSTRU);
\r
1146 if (Token = findrsvd(TString, i)) /* Reserved Word? */
\r
1150 if (TSymnum = findLsymbol(TString, i)) {
\r
1152 if (lst[TSymnum].Type & MACRO) { /* MACRO !! */
\r
1153 i = lst[TSymnum].Offs; /* get number */
\r
1154 strcpy(line_buf1, rgMacPtr[i]); /* move it in */
\r
1155 strncat(line_buf1, line_ptr, 132); /* cat rest of line */
\r
1156 line_ptr = line_buf1;
\r
1159 else return (Token = LSYMBOL);
\r
1163 if (TSymnum = findGsymbol(TString, i)) {
\r
1164 return (Token = SYMBOL);
\r
1166 else return (Token = UNKSYM);
\r
1169 /* If char was not legal for an identifier the only things left
\r
1170 are digits, special characters, and 'strings' */
\r
1172 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
1198 while ((*line_ptr) && (*line_ptr != SQUOTE) && (i < 132))
\r
1199 TString[i++] = *line_ptr++;
\r
1201 if (*line_ptr != SQUOTE)
\r
1204 line_ptr++; /* next char if this is SQUOTE */
\r
1205 TString[i] = 0; /* null terminate string */
\r
1206 CBString = i; /* Set size */
\r
1207 return(Token = STRING);
\r
1211 return(Token = ERROR);
\r
1213 } /* end switch */
\r
1216 /**************************************
\r
1217 Handles include files for INCLUDE and
\r
1219 ***************************************/
\r
1220 void DoInclude(char *pName)
\r
1222 if (level < LEVELS-1) {
\r
1225 strcpy(srcname[level], pName);
\r
1227 if(!(src_fh[level] = fopen(srcname[level], "r"))) {
\r
1229 fatal_error("Can't open INCLUDE file\n");
\r
1232 lineno[level] = 0;
\r
1235 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
1236 Column += fprintf(lst_fh, "INCLUDE: %s", srcname[level]);
\r
1240 fatal_error("EXCEEDED MAX INCLUDE DEPTH (5)");
\r
1244 /*******************************************
\r
1245 Handles SEARCH command for library search.
\r
1246 We open the PUB file given and find the
\r
1247 first filename. We save this name, then
\r
1248 run through the publics seeing if we
\r
1250 *******************************************/
\r
1251 void DoSearch(char *pName)
\r
1256 /********************************************
\r
1257 Handles DOT Commands
\r
1258 *********************************************/
\r
1259 void Command(void)
\r
1265 switch(i = Parse()) {
\r
1269 pNextAddr = &oNextData;
\r
1270 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
1271 Column += fprintf(lst_fh, "<- DSEG Begin", lst_fh);
\r
1277 pNextAddr = &oNextCode;
\r
1278 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
1279 Column += fprintf(lst_fh, "<- CSEG Begin", lst_fh);
\r
1285 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
1289 Column += fprintf(lst_fh, "<- WORD ALIGN, PAD: ", lst_fh);
\r
1292 if (oNextData & 1)
\r
1294 OutByte(0); /* EMIT byte to Data seg, value 0 */
\r
1296 Column += fprintf(lst_fh, "00 ", lst_fh);
\r
1301 if (oNextCode & 1)
\r
1303 OutByte(0x90); /* EMIT byte to Code seg, 0x90 (NOP) */
\r
1305 Column += fprintf(lst_fh, "90 ", lst_fh);
\r
1309 else if (ii == rDWORD)
\r
1312 Column += fprintf(lst_fh, "<- DWORD ALIGN, PAD: ", lst_fh);
\r
1315 while (oNextData & 3) {
\r
1316 OutByte(0); /* EMIT byte to Data seg, value 0 */
\r
1318 Column += fprintf(lst_fh, "00 ", lst_fh);
\r
1323 while (oNextCode & 3)
\r
1325 OutByte(0x90); /* EMIT byte to Code seg, 0x90 (NOP) */
\r
1327 Column += fprintf(lst_fh, "90 ", lst_fh);
\r
1331 else if (ii == rPARA)
\r
1334 Column += fprintf(lst_fh, "<- PARA(16) ALIGN, PAD: ", lst_fh);
\r
1337 while (oNextData & 0x0f) {
\r
1338 OutByte(0); /* EMIT byte to Data seg, value 0 */
\r
1340 Column += fprintf(lst_fh, "00 ", lst_fh);
\r
1345 while (oNextCode & 0x0f)
\r
1347 OutByte(0x90); /* EMIT byte to Code seg, 0x90 (NOP) */
\r
1349 Column += fprintf(lst_fh, "90 ", lst_fh);
\r
1358 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
1359 Column += fprintf(lst_fh, "<- END of Source ");
\r
1365 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
1366 Column += fprintf(lst_fh, "<- START Address ");
\r
1369 StartAddr = oNextCode;
\r
1377 Column += fprintf(lst_fh, "VIRTUAL Segment address: ");
\r
1378 if (Parse() == NUMBER) {
\r
1379 if (oNextData > 0)
\r
1383 Column += fprintf(lst_fh, "%08lX", TNumber);
\r
1384 oNextData = TNumber;
\r
1385 DataOffset = TNumber;
\r
1393 Column += fprintf(lst_fh, "VIRTUAL Segment address: ");
\r
1394 if (Parse() == NUMBER) {
\r
1395 if (oNextCode > 0)
\r
1399 Column += fprintf(lst_fh, "%08lX", TNumber);
\r
1400 oNextCode = TNumber;
\r
1401 CodeOffset = TNumber;
\r
1409 tmpname[0] = 0; /* default to null name */
\r
1410 while (isskip(*line_ptr)) line_ptr++;
\r
1412 while ((*line_ptr) && (*line_ptr != ';') && (!isskip(*line_ptr)))
\r
1413 tmpname[i++] = *line_ptr++;
\r
1414 tmpname[i] = 0; /* null terminate */
\r
1416 DoInclude(tmpname);
\r
1419 tmpname[0] = 0; /* default to null name */
\r
1420 while (isskip(*line_ptr)) line_ptr++;
\r
1422 while ((*line_ptr) && (*line_ptr != ';') && (!isskip(*line_ptr)))
\r
1423 tmpname[i++] = *line_ptr++;
\r
1424 tmpname[i] = 0; /* null terminate */
\r
1426 DoSearch(tmpname);
\r
1431 Column += fprintf(lst_fh, "Stack Total: ");
\r
1432 if (Parse() == NUMBER) {
\r
1433 StackTotal += TNumber;
\r
1435 Column += fprintf(lst_fh, "%08lX", StackTotal);
\r
1438 line_error(35); /* Invalid number or expression */
\r
1443 default: line_error(14);
\r
1448 /********************************************
\r
1449 This adds the 3 bit code for the specified
\r
1450 register to the ModRM or SIB bytes which
\r
1451 is pointed to by *modbyte. nshift is the
\r
1452 number of bits to shift the register code
\r
1453 before ORing it with *modbyte (ModRM or SIB).
\r
1454 *********************************************/
\r
1456 void EncodeRegBits(S16 regnum, S8 *modbyte, S16 nshift)
\r
1461 case rAX: /* value is 1 don't do anything */
\r
1473 *modbyte |= (1 << nshift);
\r
1481 *modbyte |= (2 << nshift);
\r
1489 *modbyte |= (3 << nshift);
\r
1494 *modbyte |= (4 << nshift);
\r
1500 *modbyte |= (5 << nshift);
\r
1508 *modbyte |= (6 << nshift);
\r
1515 *modbyte |= (7 << nshift);
\r
1517 default:; /* if it's not one of these we do nothing */
\r
1521 /********************************************
\r
1522 Add Macro to LOCAL symbol table.
\r
1523 The last symbol added to the symbol
\r
1524 table is the label for this macro.
\r
1526 *********************************************/
\r
1527 void AddMacro(void)
\r
1534 if (iMacNext >= MACBUFMAX-50)
\r
1535 fatal_error("Macro buffer overflow...");
\r
1536 if (iMacNext >= MACSMAX)
\r
1537 fatal_error("Macro table overflow...");
\r
1540 while(isskip(*line_ptr)) line_ptr++; /* skip while space */
\r
1542 /* Read the macro including white space upto EOL or comment.
\r
1543 j keeps track of the last NON-space character so we don't
\r
1544 store unneeded spaces at the end of the macro.
\r
1547 while ((*line_ptr) && (*line_ptr != SEMI)) {
\r
1548 mac[i++] = *line_ptr++;
\r
1549 if (mac[i-1] > 0x20) j = i; /* j will be length */
\r
1552 strncpy(pMacNext, mac, j);
\r
1554 /* These are all "iLSymNext-1" because the Macro label has
\r
1555 already been added to the symbol table when AddMacro
\r
1559 lst[iLSymNext-1].Type = 0; /* cancel previous type */
\r
1560 lst[iLSymNext-1].Type |= MACRO; /* initialize type */
\r
1562 rgMacPtr[iMacNext] = pMacNext; /* store mac ptr in pmac array */
\r
1563 lst[iLSymNext-1].Offs = iMacNext; /* store mac # in offset */
\r
1566 *pMacNext = 0; /* null terminate the macro */
\r