--- /dev/null
+/* DASMQ.c contains procedures that are stable and are not\r
+ subject to change during debugging and development. They\r
+ have been moved out of the main module to reduce SCROLL Mania...\r
+\r
+*/\r
+\r
+/******************************************\r
+* Determine if a character is alphabetic\r
+* or underscore. These can be used for first\r
+* or subsequent chars in an identifier.\r
+*******************************************/\r
+\r
+char is_ident(char chr)\r
+{\r
+ return (isalpha(chr)) || (chr == '_');\r
+}\r
+\r
+\r
+/********************************************\r
+ Determine if character is "skip" character.\r
+ All values from 0x20 down to CTRL-A are\r
+ skipped.\r
+*********************************************/\r
+\r
+char isskip(char chr)\r
+{\r
+ if ((chr > 0) && (chr <= ' ')) return(1);\r
+ else return(0);\r
+}\r
+/**************************************\r
+ Write a Hex byte to a file fout.\r
+***************************************/\r
+\r
+void put_hexb(U8 value, FILE *fout)\r
+{\r
+S8 stack[10];\r
+U16 i, j;\r
+\r
+ i = 0; j = 2;\r
+ do {\r
+ stack[i] = (value % 16) + '0';\r
+ if (stack[i] > 0x39)\r
+ stack[i] += 7;\r
+ i++;\r
+ }\r
+ while(value /= 16);\r
+ while (i < j--) { /* zero pad front end to width */\r
+ fputc('0', fout);\r
+ }\r
+ while(i) {\r
+ fputc(stack[--i], fout);\r
+ }\r
+}\r
+\r
+/**************************************\r
+ Write a Hex number to a file fout.\r
+***************************************/\r
+\r
+void put_hexw(U16 value, FILE *fout)\r
+{\r
+S8 stack[10];\r
+U16 i, j;\r
+\r
+ i = 0;\r
+ j = 4;\r
+ do {\r
+ stack[i] = (value % 16) + '0';\r
+ if (stack[i] > 0x39)\r
+ stack[i] += 7;\r
+ i++;\r
+ }\r
+ while(value /= 16);\r
+ while (i < j--) { /* zero pad front end to width */\r
+ fputc('0', fout);\r
+ }\r
+ while(i) {\r
+ fputc(stack[--i], fout);\r
+ }\r
+}\r
+\r
+/**************************************\r
+ Write a hex dword to a file fout.\r
+***************************************/\r
+\r
+void put_hexd(U32 value, FILE *fout)\r
+{\r
+S8 stack[10];\r
+U16 i, j;\r
+\r
+ i = 0;\r
+ j = 8;\r
+ do {\r
+ stack[i] = (value % 16) + '0';\r
+ if (stack[i] > 0x39)\r
+ stack[i] += 7;\r
+ i++;\r
+ }\r
+ while(value /= 16);\r
+ while (i < j--) { /* zero pad front end to width */\r
+ fputc('0', fout);\r
+ }\r
+ while(i) {\r
+ fputc(stack[--i], fout);\r
+ }\r
+}\r
+\r
+\r
+/*************************************\r
+ Acquires VALUE for Expression()\r
+*************************************/\r
+int expr4(long *val)\r
+{\r
+int k;\r
+\r
+if (Token == rOFFSET) {\r
+ fOffset = 1;\r
+ Parse();\r
+ }\r
+\r
+if (Token == OPENRND) { /* Open paren */\r
+ Parse();\r
+ k=expr1(val);\r
+ if (Token == CLOSRND) {\r
+ Parse();\r
+ }\r
+ else{\r
+ line_error(1);\r
+ return(0);\r
+ }\r
+ }\r
+else if (Token == NUMBER) {\r
+ *val = TNumber;\r
+ Parse(); /* set up for next token check */\r
+ }\r
+else if (Token == LSYMBOL) {\r
+ nExpSyms++;\r
+ *val = lst[TSymnum].Offs;\r
+ iExpSym = TSymnum; /* so we can trace symbol number came from */\r
+ ExpType = 1;\r
+ Parse(); /* set up for next token check */\r
+ }\r
+else if (Token == SYMBOL) {\r
+ nExpSyms++;\r
+ *val = gst[TSymnum].Offs;\r
+ iExpSym = TSymnum; /* so we can trace symbol number came from */\r
+ ExpType = 2;\r
+ Parse(); /* set up for next token check */\r
+ }\r
+else if (Token == UNKSYM) {\r
+ nExpSyms++;\r
+ *val = 0; /* No offset for UNKSYM */\r
+ iExpSym =0;\r
+ ExpType = 0; /* 0 means forward ref. No Assumption. */\r
+\r
+ /* Save name for forward reference */\r
+ strncpy(UString, TString, 30);\r
+ if (CBString > 30)\r
+ UCBString = 30;\r
+ else\r
+ UCBString = CBString; /* Size of Unknown label */\r
+ UString[UCBString] = '\0'; /* Null terminate */\r
+\r
+ Parse(); /* set up for next token check */\r
+ }\r
+else if (Token == DOLLAR) {\r
+ if (fDataSeg)\r
+ *val = oNextData;\r
+ else\r
+ *val = oNextCode;\r
+ ExpType = 3;\r
+ Parse(); /* set up for next token check */\r
+ }\r
+else{\r
+ line_error(2);\r
+ return(0);\r
+ }\r
+return(1);\r
+}\r
+\r
+/*****************************************\r
+ Evaluates a UNARY MINUS for Expression()\r
+*****************************************/\r
+int expr3(long *val)\r
+{\r
+int k;\r
+\r
+if (Token == MINUS) { /* Unary MINUS */\r
+ Parse(); /* set up for next token check */\r
+ k=expr4(val);\r
+ if (k) {\r
+ *val = -(*val);\r
+ return(1);\r
+ }\r
+ else {\r
+ line_error(3);\r
+ return(0);\r
+ }\r
+ }\r
+else {\r
+ k = expr4(val);\r
+ return(k);\r
+ }\r
+}\r
+\r
+\r
+/*************************************\r
+ Evaluates a * and / Expression()\r
+*************************************/\r
+int expr2(long *val)\r
+{\r
+int k;\r
+long val2;\r
+\r
+k=expr3(val);\r
+if ((Token != STAR) && (Token != SLASH))\r
+ return(k);\r
+while(1) {\r
+ if (Token == STAR) { /* MULTIPLY */\r
+ Parse(); /* set up for next token check */\r
+ if(expr2(&val2))\r
+ *val *= val2;\r
+ }\r
+ else if (Token == SLASH) { /* DIVIDE */\r
+ Parse(); /* set up for next token check */\r
+ if(expr2(&val2))\r
+ *val /= val2;\r
+ }\r
+ else return(1); /* Expr doesn't continue but it's OK to here */\r
+}\r
+}\r
+\r
+/*************************************\r
+ Evaluates a + and - for Expression()\r
+*************************************/\r
+int expr1(long *val)\r
+{\r
+int k;\r
+long val2;\r
+\r
+k=expr2(val);\r
+if ((Token != PLUS) && (Token != MINUS)) return(k);\r
+while(1) {\r
+ if (Token == PLUS) {\r
+ Parse();\r
+ if (Token==REGIST) return(1); /* allow for N+REG */\r
+ if(expr2(&val2))\r
+ *val += val2;\r
+ else return(0);\r
+ }\r
+ else if (Token == MINUS) {\r
+ Parse();\r
+ if (Token==REGIST) return(1); /* allow for N+REG */\r
+ if(expr2(&val2))\r
+ *val -= val2;\r
+ else return(0);\r
+ }\r
+ else return(1); /* Expr doesn't continue but it's OK to here */\r
+}\r
+}\r
+\r
+/*******************************************\r
+ Expression is called to evaluate a math\r
+ expression made of constants, and/or\r
+ address labels (offsets).\r
+ Uses functions expr1 - expr4 recursively\r
+ to handle parenthetical expressions\r
+ while keeping standard math operator\r
+ precedence correct. Exits with (0) if error\r
+ in expression is encountered. Exits with\r
+ 1 if value is left in TNumber. If a NON\r
+ math Token is encountered but expression\r
+ was OK to that point, it calls ReturnToken\r
+ and leaves the currenly evaluated number\r
+ as the current token.\r
+\r
+ If a single symbol or a single "current address"\r
+ opeator ($) is used in the expression, it will\r
+ return with SYMOFF as the Token type with the\r
+ offset value in TNumber, and the symbol\r
+ in TSymnum. If the OFFSET operator is used,\r
+ it will return with the offset in TNumber\r
+ and it will be a NUMOFF.\r
+ If more than 1 symbol or the\r
+ current address operator ($) and a symbol\r
+ is used it will assume a simple numeric\r
+ value from the computation and return\r
+ NUMBER as it's token.\r
+********************************************/\r
+\r
+int Expression(void)\r
+{\r
+long val;\r
+\r
+/* iExpSym = 0; */\r
+nExpSyms = 0;\r
+fOffset = 0;\r
+\r
+if (expr1(&val)) {\r
+\r
+ if (Token) /* if not EOL (EOL returns 0) */\r
+ ReturnToken(); /* give back non-expression token */\r
+ if (nExpSyms == 1) {\r
+ if (fOffset)\r
+ Token = NUMOFF; /* Derived from OFFSET cmd */\r
+ else\r
+ Token = SYMOFF; /* single address operator used (Mem Type) */\r
+ }\r
+ else\r
+ Token = NUMBER; /* Make current token a NUMBER */\r
+\r
+ TSymnum = iExpSym; /* We can tell where number came from */\r
+ TNumber = val; /* Tell em what it is */\r
+ return(1); /* Tell em they got one */\r
+}\r
+else return(0); /* Tell em they got an error */\r
+}\r
+\r
+/*****************************************************\r
+ Determines if token is 32 bit general register.\r
+*****************************************************/\r
+int is_r32(int id)\r
+{\r
+switch (id) {\r
+ case rEAX:\r
+ case rEBX:\r
+ case rECX:\r
+ case rEDX:\r
+ case rESI:\r
+ case rEDI:\r
+ case rEBP:\r
+ case rESP: return(1);\r
+ default: return(0);\r
+ }\r
+}\r
+\r
+/*****************************************************\r
+ Determines if token is 16 bit general.\r
+*****************************************************/\r
+int is_r16(int id)\r
+{\r
+switch (id) {\r
+ case rAX:\r
+ case rBX:\r
+ case rCX:\r
+ case rDX:\r
+ case rSI:\r
+ case rDI:\r
+ case rBP:\r
+ case rSP: return(1);\r
+ default: return(0);\r
+ }\r
+}\r
+\r
+/*****************************************************\r
+ Determines if token is 8 bit general register.\r
+*****************************************************/\r
+int is_r8(int id)\r
+{\r
+switch (id) {\r
+ case rAL:\r
+ case rBL:\r
+ case rCL:\r
+ case rDL:\r
+ case rAH:\r
+ case rBH:\r
+ case rCH:\r
+ case rDH: return(1);\r
+ default: return(0);\r
+ }\r
+}\r
+\r
+/*****************************************************\r
+ Determines if token is Segment Register.\r
+*****************************************************/\r
+int is_rSEG(int id)\r
+{\r
+switch (id) {\r
+ case rDS:\r
+ case rES:\r
+ case rCS:\r
+ case rFS:\r
+ case rGS:\r
+ case rSS: return(1);\r
+ default: return(0);\r
+ }\r
+}\r
+\r
+/*****************************************************\r
+ Determines if token is Debug register.\r
+*****************************************************/\r
+int is_rDRG(int id)\r
+{\r
+switch (id) {\r
+ case rDR0:\r
+ case rDR1:\r
+ case rDR2:\r
+ case rDR3:\r
+ case rDR6:\r
+ case rDR7: return(1);\r
+ default: return(0);\r
+ }\r
+}\r
+\r
+/*****************************************************\r
+ Determines if token is Control register.\r
+*****************************************************/\r
+int is_rCRG(int id)\r
+{\r
+return ((id == rCR0) || (id == rCR2) || (id == rCR3));\r
+}\r
+\r
+/*****************************************************\r
+ Determines if token is Test register.\r
+*****************************************************/\r
+int is_rTRG(int id)\r
+{\r
+return ((id == rTR6) || (id == rTR7));\r
+}\r
+\r
+/*****************************************************\r
+ Determines if operand entry in instruction (ins) is\r
+ compatible with the operand type the user gave (op).\r
+ An entry of 0 may match which means there is no\r
+ operand.\r
+*****************************************************/\r
+\r
+\r
+int is_Comp(int ins, int op)\r
+{\r
+switch (rgINS[ins][op+1]) { /* check against op type in instruction */\r
+ case 0:\r
+ if (!rgOpType[op]) return(1); /* no operand in either matches */\r
+ break;\r
+ case rel8:\r
+ if (rgOpType[op] == rel8) return(1);\r
+ break;\r
+ case relW:\r
+ if (rgOpType[op] == relW) return(1);\r
+ break;\r
+ case iSAD:\r
+ if (rgOpType[op] == r8) return(1);\r
+ break;\r
+ case r8:\r
+ if (rgOpType[op] == r8) return(1);\r
+ break;\r
+ case r16:\r
+ if (rgOpType[op] == r16) return(1);\r
+ break;\r
+ case r32:\r
+ if (rgOpType[op] == r32) return(1);\r
+ break;\r
+ case rREG:\r
+ if ((rgOpType[op] == r8) ||\r
+ (rgOpType[op] == r16) ||\r
+ (rgOpType[op] == r32)) return(1);\r
+ break;\r
+ case rRGW:\r
+ if ((rgOpType[op] == r16) ||\r
+ (rgOpType[op] == r32)) return(1);\r
+ break;\r
+ case rACC:\r
+ if (((rgOpType[op] == r8) && (rgOpReg[op] == rAL)) ||\r
+ ((rgOpType[op] == r16) && (rgOpReg[op] == rAX)) ||\r
+ ((rgOpType[op] == r32) && (rgOpReg[op] == rEAX)))\r
+ return(1);\r
+ break;\r
+ case rSEG:\r
+ if (rgOpType[op] == rSEG) return(1);\r
+ break;\r
+ case rCRG:\r
+ if (rgOpType[op] == rCRG) return(1);\r
+ break;\r
+ case rDRG:\r
+ if (rgOpType[op] == rDRG) return(1);\r
+ break;\r
+ case rTRG:\r
+ if (rgOpType[op] == rTRG) return(1);\r
+ break;\r
+ case imm8:\r
+ if (rgOpType[op] == val8)\r
+ return(1);\r
+\r
+ if ((rgOpType[op] == val16) &&\r
+ (OpImm < 256) &&\r
+ (OpImm >= 0))\r
+ return(1);\r
+\r
+ break;\r
+ case ims8: /* This is where a byte in an instruction\r
+ will be sign extended. We will only allow byte values\r
+ between -128 and 127 to be compatible here. This is because\r
+ they can put AND EAX, A0h and we have to assume they DON'T\r
+ want it extended into a negative 32 bit integer such as 0FFFFFFA0h.\r
+ */\r
+ if (rgOpType[op] == val8)\r
+ return(1);\r
+\r
+ if ((rgOpType[op] == val16) &&\r
+ (OpImm < 128) &&\r
+ (OpImm >= 0))\r
+ return(1);\r
+\r
+ break;\r
+ case imm16:\r
+ if ((rgOpType[op] == val8) ||\r
+ (rgOpType[op] == val16)) return(1);\r
+ break;\r
+ case immX:\r
+ if ((rgOpType[op] == val8) ||\r
+ (rgOpType[op] == val16) ||\r
+ (rgOpType[op] == val32)) return(1);\r
+ break;\r
+ case rm8:\r
+ if ((rgOpType[op] == r8) ||\r
+ ((rgOpType[op] == mem) && (OpSize[op] & fByte))) return(1);\r
+ break;\r
+ case rm16:\r
+ if ((rgOpType[op] == r16) ||\r
+ ((rgOpType[op] == mem) && (OpSize[op] & fWord)) ) return(1);\r
+ break;\r
+ case rRM:\r
+ if ((rgOpType[op] == r8) ||\r
+ (rgOpType[op] == r16) ||\r
+ (rgOpType[op] == r32) ||\r
+ (rgOpType[op] == mem)) return(1);\r
+ break;\r
+ case rRMW:\r
+ if (rgOpType[op] == mem)\r
+ {\r
+ if (OpSize[op] & fFWord)\r
+ return(0);\r
+ if (OpSize[op] & fByte)\r
+ return(0);\r
+ return(1);\r
+ }\r
+ if ((rgOpType[op] == r16) ||\r
+ (rgOpType[op] == r32))\r
+ return(1);\r
+ break;\r
+ case mem:\r
+ if ((rgOpType[op] == mem) && (!(OpSize[op] & fFWord))) return(1);\r
+ break;\r
+ case memF:\r
+ if ((rgOpType[op] == memF) && (OpSize[op] & fFWord)) return(1);\r
+ break;\r
+ case moff:\r
+ if ((rgOpType[op] == mem) &&\r
+ (OpMType & fDisp32) &&\r
+ ((OpMType & fIndx)==0) &&\r
+ ((OpMType & fBase)==0))\r
+ return(1);\r
+ break;\r
+ case immv3:\r
+ if ((rgOpType[op] == val8) &&\r
+ (OpImm == 3)) return(1);\r
+ break;\r
+ case immv1:\r
+ if ((rgOpType[op] == val8) &&\r
+ (OpImm == 1)) return(1);\r
+ break;\r
+ case rDX:\r
+ if ((rgOpType[op] == r16) &&\r
+ (rgOpReg[op] == rDX)) return(1);\r
+ break;\r
+ case rCL:\r
+ if ((rgOpType[op] == r8) &&\r
+ (rgOpReg[op] == rCL)) return(1);\r
+ break;\r
+ case rAL:\r
+ if ((rgOpType[op] == r8) &&\r
+ (rgOpReg[op] == rAL)) return(1);\r
+ break;\r
+ case rAX:\r
+ if ((rgOpType[op] == r16) &&\r
+ (rgOpReg[op] == rAX)) return(1);\r
+ break;\r
+ case rEAX:\r
+ if ((rgOpType[op] == r32) &&\r
+ (rgOpReg[op] == rEAX)) return(1);\r
+ break;\r
+ case rCS:\r
+ case rSS:\r
+ case rDS:\r
+ case rES:\r
+ case rFS:\r
+ case rGS:\r
+ if ((rgOpType[op] == rSEG) &&\r
+ (rgOpReg[op] == rgINS[ins][op+1])) return(1);\r
+ break;\r
+ default:;\r
+ }\r
+return(0);\r
+}\r
+\r
+/*****************************************************\r
+ Determines if entry in rgOpType is a register.\r
+*****************************************************/\r
+\r
+int is_Reg(int op)\r
+{\r
+ switch (op) { /* This should be the value from rgOpType[x] */\r
+ case r8:\r
+ case r16:\r
+ case r32:\r
+ case rCRG:\r
+ case rDRG:\r
+ case rTRG:\r
+ return(1);\r
+ default:;\r
+ }\r
+ return(0);\r
+}\r
+\r
+\r
+/*********************************************\r
+This displays the string and exits for a FATAL\r
+assembler error.\r
+**********************************************/\r
+\r
+void fatal_error(S8 *pst)\r
+{\r
+\r
+++error_count;\r
+\r
+if (fListA | fListE) {\r
+ fprintf(lst_fh, "\r\nFATAL ERROR, line %ld - %s\r\n", lineno[level], pst);\r
+\r
+/*\r
+ DumpGSymbols();\r
+ DumpLSymbols();\r
+*/\r
+ fclose(lst_fh);\r
+ }\r
+\r
+printf("\r\nFATAL ERROR, line %ld - %s\r\n", lineno[level], pst);\r
+printf("%d Errors\r\n%d Warnings\r\n", error_count, warn_count);\r
+\r
+/* close all files here and delete temps */\r
+ fclose(cs_fh);\r
+ fclose(ds_fh);\r
+\r
+exit(1);\r
+}\r
+\r
+/*********************************************\r
+This displays the string and line number for\r
+non-fatal errors.\r
+**********************************************/\r
+\r
+void line_error(int num)\r
+{\r
+S8 *p;\r
+\r
+ switch (num) {\r
+ case 1: p="Invalid expression, ')' expected"; break;\r
+ case 2: p="Invalid expression, value expected"; break;\r
+ case 3: p="Value expected after unary '-'"; break;\r
+ case 4: p="Too many digits for numeric radix"; break;\r
+ case 5: p="Invalid character in a number"; break;\r
+ case 6: p="Unterminated string"; break;\r
+ case 7: p="Unrecognized character"; break;\r
+ case 8: p="Invalid Alignment specified"; break;\r
+ case 9: p="Start command only allowed in CSEG"; break;\r
+ case 10: p="Virtual command must be first in segment"; break;\r
+ case 11: p="Invalid Virtual value"; break;\r
+ case 12: p="Starting address not found"; break;\r
+ case 13: p="Stack command not allowed in DSEG"; break;\r
+ case 14: p="Invalid command"; break;\r
+ case 15: p="Invalid Operand"; break;\r
+ case 16: p="Invalid segment register use"; break;\r
+ case 17: p="Invalid scale value 'Reg*?'"; break;\r
+ case 18: p="Scale value expected (*2,*4,*8)"; break;\r
+ case 19: p="Too many address scale values"; break;\r
+ case 20: p="Invalid register for memory operand"; break;\r
+ case 21: p="Invalid memory operand"; break;\r
+ case 22: p="Offset must be from data segment"; break;\r
+ case 23: p="Nested brackets"; break;\r
+ case 24: p="Unbalanced brackets"; break;\r
+ case 25: p="Invalid operand size attribute"; break;\r
+ case 26:\r
+ case 27:\r
+ case 28:\r
+ case 29:\r
+ case 30:\r
+ case 31: p=""; break;\r
+ case 32: p="Unknown token in operand array"; break;\r
+ case 33: p="Too many operands or extra character"; break;\r
+ case 34: p=""; break;\r
+ case 35: p="Invalid expression or numeric value"; break;\r
+ case 36: p="Operand expected before comma"; break;\r
+ case 37: p=""; break;\r
+ case 38: p="Invalid character or reserved word in operand"; break;\r
+ case 39: p="Relative jump out of range"; break;\r
+ case 40: p="Operand size NOT specified or implied"; break;\r
+ case 41: p="Instructions not allowed in data segment"; break;\r
+ case 42: p="Instruction expected after prefix"; break;\r
+ case 43: p="Operand sizes don't match"; break;\r
+ case 44: p="Wrong operand type for instruction"; break;\r
+ case 45: p="Incorrect format for memory operand"; break;\r
+ case 46: p="Strings only valid for DB storage"; break;\r
+ case 47: p="Expected '(' after 'DUP'"; break;\r
+ case 48: p="Storage expected between commas"; break;\r
+ case 49: p="':' not expected"; break;\r
+ case 50: p="DWord storage required for OFFSET"; break;\r
+ case 51: p="Invalid storage value"; break;\r
+ case 52:\r
+ case 53: p=""; break;\r
+ case 54: p="':' expected after last label"; break;\r
+ case 55: p="Macro not allowed in lexical level 0"; break;\r
+ case 56: p="EQU or Storage expected"; break;\r
+ case 57:\r
+ case 58:\r
+ case 59:\r
+ case 60:\r
+ case 61:\r
+ case 62: p=""; break;\r
+ case 63: p="Instruction expected before register name"; break;\r
+ case 64: p="Public Symbol already defined"; break;\r
+ case 65: p="Local symbol already defined"; break;\r
+ case 66: p="Number not expected"; break;\r
+ case 67: p="New symbol must follow PUBLIC keyword"; break;\r
+ case 68: p="Label, Command, Instruction, or Storage expected"; break;\r
+ case 69: p="Inconsistant redeclaration"; break;\r
+ case 70: p=""; break;\r
+ default:\r
+ break;\r
+ }\r
+\r
+ fprintf(lst_fh, "\r\nERROR: %d, line: %ld, %s\r\n", num, lineno[level], p);\r
+ *line_ptr = 0; /* this KILLS the rest of the line */\r
+ Column = 0;\r
+ ++error_count;\r
+}\r
+\r
+/*********************************************\r
+This displays the string and line number for\r
+errors dicovered AFTER we past the line.\r
+This is for non-fatal errors.\r
+**********************************************/\r
+\r
+void prev_error(S8 *pst, S16 line)\r
+{\r
+ fprintf(lst_fh, "\r\nERROR, line %d - %s\r\n", line, pst);\r
+ Column = 0;\r
+ ++error_count;\r
+}\r
+\r
+/**********************************************************\r
+ The parser calls this when it detects a digit leaving\r
+ the line_ptr* pointing to digit. It accepts base 2, 10\r
+ & 16. Base 2 numbers are suffixed with a B or b, base 16\r
+ with an h or H and base 10 with no suffix.\r
+***********************************************************/\r
+\r
+U32 get_number(void)\r
+{\r
+U32 value, base;\r
+S8 c, i;\r
+S16 len;\r
+S8 st[33];\r
+ value = 0;\r
+ len = 0;\r
+ base = 10; /* default base is 10 */\r
+\r
+ while(isxdigit(c = *line_ptr)) { /* get all the digits */\r
+ st[len++] = c;\r
+ line_ptr++;\r
+ }\r
+\r
+ if ((*line_ptr== 'h') || (*line_ptr== 'H')) { /* looks like hex */\r
+ line_ptr++;\r
+ base = 16;\r
+ }\r
+ else if ((st[len-1] == 'b') || (st[len-1] == 'B')) {\r
+ base = 2;\r
+ len--;\r
+ }\r
+ if (((base == 2) && (len > 33)) ||\r
+ ((base == 10) && (len > 10)) ||\r
+ ((base == 16) && (len > 9))) {\r
+ line_error(4);\r
+ return(0);\r
+ }\r
+ i = 0;\r
+ do {\r
+ c = st[i];\r
+ if(isdigit(c)) /* convert numeric digits */\r
+ c -= '0';\r
+ else if(c >= 'a') /* convert lower case alphas */\r
+ c -= ('a' - 10);\r
+ else if(c >= 'A') /* convert upper case alphas */\r
+ c -= ('A' - 10);\r
+ else\r
+ break;\r
+ if(c >= base) { /* outside of base */\r
+ line_error(5);\r
+ return(0);\r
+ }\r
+ value = (value * base) + c; /* include in total */\r
+ i++; }\r
+ while(i < len); /* to length of string */\r
+ return value;\r
+}\r
+\r
+/*********************************************\r
+This is a fast binary search for a reserved\r
+word that is not an instructions or a register.\r
+**********************************************/\r
+\r
+S16 findrsvd(S8 *pb, S16 cb) /* pointer to and size of string */\r
+{\r
+S16 f, m, n, k;\r
+S8 id[8];\r
+\r
+ if (cb>srsvd) return(0); /* can't be a reserved word */\r
+ strncpy(id, pb, cb); /* move string local */\r
+ id[cb] = 0; /* null terminate */\r
+\r
+ m = 0;\r
+ n = nreserved-1;\r
+ while (m<=n) {\r
+ k = m + (n-m) / 2;\r
+ f = strncmp(id, rgReserved[k], srsvd-1);\r
+ if (!f) return(k + nrsvd1); /* found it! */\r
+ else if (f > 0) /* it was less */\r
+ m = k+1;\r
+ else /* it was more */\r
+ n = k-1;\r
+ }\r
+ return(0);\r
+}\r
+\r
+/*********************************************\r
+This is a fast binary search for an instuction.\r
+It returns the number or 0 if not found.\r
+**********************************************/\r
+\r
+S16 findinst(S8 *pb, S16 cb) /* pointer to and size of parsed string */\r
+{\r
+S16 f, m, n, k;\r
+S8 id[6];\r
+\r
+ if (cb>sinst) return(0); /* can't be an instruction */\r
+ strncpy(id, pb, cb); /* move string local */\r
+ id[cb] = 0; /* null terminate */\r
+\r
+ m = 0;\r
+ n = ninst-1;\r
+ while (m<=n) {\r
+ k = m + (n-m) / 2;\r
+ f = strncmp(id, rginst[k], sinst-1);\r
+ if (!f) return(k+1); /* found it! */\r
+ else if (f > 0) /* id was less */\r
+ m = k+1;\r
+ else /* idwas more */\r
+ n = k-1;\r
+ }\r
+ return(0);\r
+}\r
+\r
+/*********************************************\r
+This is a fast binary search for a register.\r
+It returns the number or 0 if not found.\r
+**********************************************/\r
+\r
+S16 findreg(S8 *pb, S16 cb) /* pointer to, and size of parsed string */\r
+{\r
+S16 f, m, n, k;\r
+S8 id[3];\r
+\r
+ if ((cb>sregs-1) || (cb<2)) return(0); /* can't be a register */\r
+ strncpy(id, pb, cb); /* move string local */\r
+ id[cb] = 0; /* null pad */\r
+\r
+ m = 0;\r
+ n = nregs-1;\r
+ while (m<=n) {\r
+ k = m + (n-m) / 2;\r
+ f = strncmp(id, rgreg[k], sregs-1);\r
+ if (!f) return(k+nreg1); /* found it! */\r
+ else if (f > 0) /* it was less */\r
+ m = k+1;\r
+ else /* it was more */\r
+ n = k-1;\r
+ }\r
+ return(0);\r
+}\r
+\r
+/*********************************************\r
+This searches the LOCAL symbol table for the name\r
+described by pb, cb. It only compares items that\r
+are the same length (cb == TSymsize[x]).\r
+It returns the number or 0 if not found.\r
+**********************************************/\r
+\r
+S16 findLsymbol(S8 *pb, S16 cb) /* pointer to, and size of string */\r
+{\r
+S16 i;\r
+S8 name[132];\r
+\r
+strncpy(name, pb, cb); /* move name local */\r
+name[cb] = 0; /* null terminate */\r
+\r
+i = iLSymNext;\r
+while (i>1) { /* backwards through symbol table */\r
+ i--;\r
+ /* Only compare if same size */\r
+ if (lst[i].Size == cb) {\r
+ if (strncmp(name, lst[i].Ptr, cb) == 0) return(i);\r
+ }\r
+ }\r
+return(0); /* not found... */\r
+}\r
+\r
+\r
+/*********************************************\r
+This searches the symbol table for the name\r
+described by pb, cb. It only compares items that\r
+are the same length (cb == TSymsize[x]).\r
+If the include level is greater than 0 it\r
+searches the local first, then the global.\r
+If at level 0, it only searches the global.\r
+It returns the number or 0 if not found.\r
+**********************************************/\r
+\r
+S16 findGsymbol(S8 *pb, S16 cb) /* pointer to, and size of string */\r
+{\r
+S16 i;\r
+S8 name[132];\r
+\r
+strncpy(name, pb, cb); /* move name local */\r
+name[cb] = 0; /* null terminate */\r
+\r
+i = iSymNext;\r
+while (i>1) { /* backwards through symbol table */\r
+ i--;\r
+ /* Only compare if same size */\r
+ if (gst[i].Size == cb) {\r
+ if (strncmp(name, gst[i].Ptr, cb) == 0) return(i);\r
+ }\r
+ }\r
+return(0); /* not found... */\r
+}\r
+\r
+/*********************************************\r
+ DUMP SYMBOL TABLE FOR TESTING\r
+**********************************************/\r
+\r
+void DumpGSymbols(void)\r
+{\r
+S16 i;\r
+S8 name[132];\r
+\r
+fprintf(lst_fh, "PUBLIC SYMBOLS: \r\n");\r
+\r
+i = 1;\r
+while (i<iSymNext) { /* forward through symbol table */\r
+ strncpy(name, gst[i].Ptr, gst[i].Size); /* move to name */\r
+ name[gst[i].Size] = 0; /* null terminate */\r
+\r
+ fprintf(lst_fh, "Name: %s Offset %08lX ", name, gst[i].Offs);\r
+ if (gst[i].Type & CLABEL)\r
+ fprintf(lst_fh, "CSEG ");\r
+ if (gst[i].Type & DLABEL)\r
+ fprintf(lst_fh, "DSEG ");\r
+ if (gst[i].Type & sBYTE)\r
+ fprintf(lst_fh, "BYTE ");\r
+ if (gst[i].Type & sWORD)\r
+ fprintf(lst_fh, "WORD ");\r
+ if (gst[i].Type & sDWORD)\r
+ fprintf(lst_fh, "DWORD ");\r
+ if (gst[i].Type & sFWORD)\r
+ fprintf(lst_fh, "FWORD ");\r
+ if (gst[i].Type & tEXTRN)\r
+ fprintf(lst_fh, "EXTRN ");\r
+ if (gst[i].Type & tFAR)\r
+ fprintf(lst_fh, "FAR ");\r
+ if (gst[i].Type & tPUBLIC)\r
+ fprintf(lst_fh, "PUBLIC ");\r
+ if (gst[i].Type & MACRO)\r
+ fprintf(lst_fh, "MACRO ");\r
+ fprintf(lst_fh, "\r\n");\r
+ i++;\r
+ }\r
+\r
+}\r
+\r
+/*********************************************\r
+ DUMP SYMBOL TABLE FOR TESTING\r
+**********************************************/\r
+\r
+void DumpLSymbols(void)\r
+{\r
+S16 i;\r
+S8 name[132];\r
+\r
+fprintf(lst_fh, "LOCAL SYMBOLS: \r\n");\r
+\r
+i = 1;\r
+while (i<iLSymNext) { /* forward through symbol table */\r
+ strncpy(name, lst[i].Ptr, lst[i].Size); /* move to name */\r
+ name[lst[i].Size] = 0; /* null terminate */\r
+\r
+ fprintf(lst_fh, "Name: %s Offset %lX ", name, lst[i].Offs);\r
+ if (lst[i].Type & CLABEL)\r
+ fprintf(lst_fh, "CSEG ");\r
+ if (lst[i].Type & DLABEL)\r
+ fprintf(lst_fh, "DSEG ");\r
+ if (lst[i].Type & sBYTE)\r
+ fprintf(lst_fh, "BYTE ");\r
+ if (lst[i].Type & sWORD)\r
+ fprintf(lst_fh, "WORD ");\r
+ if (lst[i].Type & sDWORD)\r
+ fprintf(lst_fh, "DWORD ");\r
+ if (lst[i].Type & sFWORD)\r
+ fprintf(lst_fh, "FWORD ");\r
+ if (lst[i].Type & tEXTRN)\r
+ fprintf(lst_fh, "EXTRN ");\r
+ if (lst[i].Type & tFAR)\r
+ fprintf(lst_fh, "FAR ");\r
+ if (lst[i].Type & tPUBLIC)\r
+ fprintf(lst_fh, "PUBLIC ");\r
+ if (lst[i].Type & MACRO)\r
+ fprintf(lst_fh, "MACRO");\r
+ fprintf(lst_fh, "\r\n");\r
+ i++;\r
+ }\r
+}\r
+\r
+/*********************************************\r
+ DUMP Forward Reference Table for testing\r
+**********************************************/\r
+\r
+void DumpFRT(void)\r
+{\r
+S16 i;\r
+S8 name[132];\r
+\r
+fprintf(lst_fh, "FORWARD REFERENCES:\n");\r
+\r
+i = 0;\r
+while (i<iRefNext) { /* forward through symbol table */\r
+ strncpy(name, pfrt[i].Ptr, pfrt[i].NameSz); /* move to name */\r
+ name[pfrt[i].NameSz] = 0; /* null terminate */\r
+\r
+ fprintf(lst_fh, "Name: %s Offset: %lX Line: %d\n",\r
+ name,\r
+ pfrt[i].Offs,\r
+ pfrt[i].Line);\r
+ i++;\r
+ }\r
+\r
+}\r
+\r
+/*********************************************\r
+This sets the global variable fPutBack to TRUE\r
+and copies the current token info so save it\r
+so it can be used again. (returning a token\r
+to the stream...)\r
+**********************************************/\r
+void ReturnToken(void)\r
+{\r
+strncpy(LTString, TString, 132);\r
+LCBString = CBString;\r
+LTSymnum = TSymnum;\r
+LTNumber = TNumber;\r
+LTInst = TInst;\r
+LTReg = TReg;\r
+LToken = Token;\r
+fPutBack = 1;\r
+}\r
+\r
+\r
+/********************************************\r
+ Parse reads and identifies the next token\r
+ for the caller. See SASM.h for info on each\r
+ of the tokens it identifies.\r
+ Token type is placed in Token.\r
+ All parsed chars are placed in TString.\r
+ Size of TString is placed in CBString.\r
+ Converted numeric values are put in TNumber.\r
+ Instruction numbers are placed in TInst.\r
+ Declared symbol ID numbers are placed in TSymnum.\r
+\r
+ Unidentified strings are first checked for\r
+ macro substitution and replaced with the\r
+ stored string if found. If no macro is\r
+ found, the symbol table is searched to see if\r
+ it's a symbol. If so, it's returned. If not\r
+ a symbol, Parse assumes it may be a new one\r
+ and leaves it in TString with the TokenType\r
+ of UNKSYM.\r
+*********************************************/\r
+\r
+S16 Parse(void)\r
+{\r
+S16 i;\r
+\r
+\r
+if (fPutBack) { /* if a symbol was put back this makes it current */\r
+ strncpy(TString, LTString, 132);\r
+ CBString = LCBString;\r
+ TSymnum = LTSymnum;\r
+ TNumber = LTNumber;\r
+ TInst = LTInst;\r
+ TReg = LTReg;\r
+ Token = LToken;\r
+ fPutBack = 0;\r
+ return(Token);\r
+}\r
+\r
+begin: /* return here after MACRO substitution */\r
+ TSymnum = 0;\r
+ TInst = 0;\r
+ TReg = 0;\r
+ Token = 0;\r
+ TString[0] = 0;\r
+ CBString = 0;\r
+ TNumber = 0;\r
+\r
+ while(isskip(*line_ptr)) line_ptr++; /* skip while space */\r
+ if (!(*line_ptr)) return(0); /* end of line */\r
+\r
+ if (*line_ptr == SEMI) /* if comment */\r
+ {\r
+ *line_ptr = 0; /* kill rest of line */\r
+ return(0); /* return 0 for EOL */\r
+ }\r
+\r
+ /* See if it's a legal 1st char for identifier or reserved word. */\r
+ /* If so, pick it up and put it in TString ALL UPPER CASE */\r
+\r
+ i=0;\r
+ if (is_ident(*line_ptr)) {\r
+ while( (isalnum(*line_ptr)) || (*line_ptr == '_') ) {\r
+ TString[i++] = toupper(*line_ptr++);\r
+ }\r
+ CBString = i;\r
+\r
+ if (TReg = findreg(TString, i)) /* Register? */\r
+ return (Token = REGIST);\r
+\r
+ if (TInst = findinst(TString, i)) /* Instruction? */\r
+ return (Token = INSTRU);\r
+\r
+ if (Token = findrsvd(TString, i)) /* Reserved Word? */\r
+ return (Token);\r
+\r
+ if (level) {\r
+ if (TSymnum = findLsymbol(TString, i)) {\r
+\r
+ if (lst[TSymnum].Type & MACRO) { /* MACRO !! */\r
+ i = lst[TSymnum].Offs; /* get number */\r
+ strcpy(line_buf1, rgMacPtr[i]); /* move it in */\r
+ strncat(line_buf1, line_ptr, 132); /* cat rest of line */\r
+ line_ptr = line_buf1;\r
+ goto begin;\r
+ }\r
+ else return (Token = LSYMBOL);\r
+ }\r
+ }\r
+\r
+ if (TSymnum = findGsymbol(TString, i)) {\r
+ return (Token = SYMBOL);\r
+ }\r
+ else return (Token = UNKSYM);\r
+ }\r
+\r
+ /* If char was not legal for an identifier the only things left\r
+ are digits, special characters, and 'strings' */\r
+\r
+ if (isdigit(*line_ptr)) {\r
+ TNumber = get_number();\r
+ return (Token = NUMBER);\r
+ }\r
+ switch (*line_ptr) {\r
+ case DOLLAR:\r
+ case OPENRND:\r
+ case CLOSRND:\r
+ case STAR:\r
+ case PLUS:\r
+ case COMMA:\r
+ case MINUS:\r
+ case DOT:\r
+ case SLASH:\r
+ case COLON:\r
+ case OPENSQR:\r
+ case CLOSSQR:\r
+ {\r
+ Token = *line_ptr;\r
+ TString[0] = *line_ptr++;\r
+ TString[1] = 0;\r
+ CBString = 1;\r
+ return (Token);\r
+ }\r
+ case SQUOTE: {\r
+ line_ptr++;\r
+ while ((*line_ptr) && (*line_ptr != SQUOTE) && (i < 132))\r
+ TString[i++] = *line_ptr++;\r
+ CBString = i;\r
+ if (*line_ptr != SQUOTE)\r
+ line_error(6);\r
+ else\r
+ line_ptr++; /* next char if this is SQUOTE */\r
+ TString[i] = 0; /* null terminate string */\r
+ CBString = i; /* Set size */\r
+ return(Token = STRING);\r
+ }\r
+ default: {\r
+ line_error(7);\r
+ return(Token = ERROR);\r
+ }\r
+ } /* end switch */\r
+}\r
+\r
+/**************************************\r
+ Handles include files for INCLUDE and\r
+ SEARCH commands.\r
+***************************************/\r
+void DoInclude(char *pName)\r
+{\r
+ if (level < LEVELS-1) {\r
+ ++level;\r
+\r
+ strcpy(srcname[level], pName);\r
+\r
+ if(!(src_fh[level] = fopen(srcname[level], "r"))) {\r
+ --level;\r
+ fatal_error("Can't open INCLUDE file\n");\r
+ }\r
+ else\r
+ lineno[level] = 0;\r
+\r
+ if (fListA) {\r
+ Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
+ Column += fprintf(lst_fh, "INCLUDE: %s", srcname[level]);\r
+ }\r
+ }\r
+ else\r
+ fatal_error("EXCEEDED MAX INCLUDE DEPTH (5)");\r
+\r
+}\r
+\r
+/*******************************************\r
+ Handles SEARCH command for library search.\r
+ We open the PUB file given and find the\r
+ first filename. We save this name, then\r
+ run through the publics seeing if we\r
+ need any of them.\r
+*******************************************/\r
+void DoSearch(char *pName)\r
+{\r
+\r
+}\r
+\r
+/********************************************\r
+ Handles DOT Commands\r
+*********************************************/\r
+void Command(void)\r
+{\r
+U32 num;\r
+S16 i, ii;\r
+char tmpname[50];\r
+\r
+switch(i = Parse()) {\r
+ case rDATA:\r
+ fDataSeg = 1;\r
+ if (fListA) {\r
+ pNextAddr = &oNextData;\r
+ Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
+ Column += fprintf(lst_fh, "<- DSEG Begin", lst_fh);\r
+ }\r
+ break;\r
+ case rCODE:\r
+ fDataSeg = 0;\r
+ if (fListA) {\r
+ pNextAddr = &oNextCode;\r
+ Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
+ Column += fprintf(lst_fh, "<- CSEG Begin", lst_fh);\r
+ }\r
+ break;\r
+ case rALIGN:\r
+ ii = Parse();\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
+ if (ii == rWORD)\r
+ {\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "<- WORD ALIGN, PAD: ", lst_fh);\r
+ if (fDataSeg)\r
+ {\r
+ if (oNextData & 1)\r
+ {\r
+ OutByte(0); /* EMIT byte to Data seg, value 0 */\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "00 ", lst_fh);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (oNextCode & 1)\r
+ {\r
+ OutByte(0x90); /* EMIT byte to Code seg, 0x90 (NOP) */\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "90 ", lst_fh);\r
+ }\r
+ }\r
+ }\r
+ else if (ii == rDWORD)\r
+ {\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "<- DWORD ALIGN, PAD: ", lst_fh);\r
+ if (fDataSeg)\r
+ {\r
+ while (oNextData & 3) {\r
+ OutByte(0); /* EMIT byte to Data seg, value 0 */\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "00 ", lst_fh);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ while (oNextCode & 3)\r
+ {\r
+ OutByte(0x90); /* EMIT byte to Code seg, 0x90 (NOP) */\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "90 ", lst_fh);\r
+ }\r
+ }\r
+ }\r
+ else if (ii == rPARA)\r
+ {\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "<- PARA(16) ALIGN, PAD: ", lst_fh);\r
+ if (fDataSeg)\r
+ {\r
+ while (oNextData & 0x0f) {\r
+ OutByte(0); /* EMIT byte to Data seg, value 0 */\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "00 ", lst_fh);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ while (oNextCode & 0x0f)\r
+ {\r
+ OutByte(0x90); /* EMIT byte to Code seg, 0x90 (NOP) */\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "90 ", lst_fh);\r
+ }\r
+ }\r
+ }\r
+ else\r
+ line_error(8);\r
+ break;\r
+ case rEND:\r
+ if (fListA) {\r
+ Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
+ Column += fprintf(lst_fh, "<- END of Source ");\r
+ }\r
+ break;\r
+ case rSTART:\r
+ if (!fDataSeg) {\r
+ if (fListA) {\r
+ Column += fprintf(lst_fh, "%08lX ", *pNextAddr);\r
+ Column += fprintf(lst_fh, "<- START Address ");\r
+ }\r
+ fStart = 1;\r
+ StartAddr = oNextCode;\r
+ }\r
+ else\r
+ line_error(9);\r
+ break;\r
+ case rVIRTUAL:\r
+ if (fDataSeg) {\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "VIRTUAL Segment address: ");\r
+ if (Parse() == NUMBER) {\r
+ if (oNextData > 0)\r
+ line_error(10);\r
+ else {\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "%08lX", TNumber);\r
+ oNextData = TNumber;\r
+ DataOffset = TNumber;\r
+ }\r
+ }\r
+ else\r
+ line_error(11);\r
+ }\r
+ else {\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "VIRTUAL Segment address: ");\r
+ if (Parse() == NUMBER) {\r
+ if (oNextCode > 0)\r
+ line_error(10);\r
+ else {\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "%08lX", TNumber);\r
+ oNextCode = TNumber;\r
+ CodeOffset = TNumber;\r
+ }\r
+ }\r
+ else\r
+ line_error(11);\r
+ }\r
+ break;\r
+ case rINCLUDE:\r
+ tmpname[0] = 0; /* default to null name */\r
+ while (isskip(*line_ptr)) line_ptr++;\r
+ i=0;\r
+ while ((*line_ptr) && (*line_ptr != ';') && (!isskip(*line_ptr)))\r
+ tmpname[i++] = *line_ptr++;\r
+ tmpname[i] = 0; /* null terminate */\r
+\r
+ DoInclude(tmpname);\r
+ break;\r
+ case rSEARCH:\r
+ tmpname[0] = 0; /* default to null name */\r
+ while (isskip(*line_ptr)) line_ptr++;\r
+ i=0;\r
+ while ((*line_ptr) && (*line_ptr != ';') && (!isskip(*line_ptr)))\r
+ tmpname[i++] = *line_ptr++;\r
+ tmpname[i] = 0; /* null terminate */\r
+\r
+ DoSearch(tmpname);\r
+ break;\r
+ case rSTACK:\r
+ if (!fDataSeg) {\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "Stack Total: ");\r
+ if (Parse() == NUMBER) {\r
+ StackTotal += TNumber;\r
+ if (fListA)\r
+ Column += fprintf(lst_fh, "%08lX", StackTotal);\r
+ }\r
+ else\r
+ line_error(35); /* Invalid number or expression */\r
+ }\r
+ else\r
+ line_error(13);\r
+ break;\r
+ default: line_error(14);\r
+ return;\r
+ }\r
+ }\r
+\r
+/********************************************\r
+ This adds the 3 bit code for the specified\r
+ register to the ModRM or SIB bytes which\r
+ is pointed to by *modbyte. nshift is the\r
+ number of bits to shift the register code\r
+ before ORing it with *modbyte (ModRM or SIB).\r
+*********************************************/\r
+\r
+void EncodeRegBits(S16 regnum, S8 *modbyte, S16 nshift)\r
+{\r
+\r
+switch (regnum) {\r
+ case rAL:\r
+ case rAX: /* value is 1 don't do anything */\r
+ case rEAX:\r
+ case rES:\r
+ case rCR0:\r
+ case rDR0:\r
+ break;\r
+ case rCL:\r
+ case rCX:\r
+ case rECX:\r
+ case rCS:\r
+ case rCR1:\r
+ case rDR1:\r
+ *modbyte |= (1 << nshift);\r
+ break;\r
+ case rDL:\r
+ case rDX:\r
+ case rEDX:\r
+ case rSS:\r
+ case rCR2:\r
+ case rDR2:\r
+ *modbyte |= (2 << nshift);\r
+ break;\r
+ case rBL:\r
+ case rBX:\r
+ case rEBX:\r
+ case rDS:\r
+ case rCR3:\r
+ case rDR3:\r
+ *modbyte |= (3 << nshift);\r
+ break;\r
+ case rAH:\r
+ case rSP:\r
+ case rESP:\r
+ *modbyte |= (4 << nshift);\r
+ break;\r
+ case rCH:\r
+ case rBP:\r
+ case rEBP:\r
+ case rFS:\r
+ *modbyte |= (5 << nshift);\r
+ break;\r
+ case rDH:\r
+ case rSI:\r
+ case rESI:\r
+ case rGS:\r
+ case rTR6:\r
+ case rDR6:\r
+ *modbyte |= (6 << nshift);\r
+ break;\r
+ case rBH:\r
+ case rDI:\r
+ case rEDI:\r
+ case rTR7:\r
+ case rDR7:\r
+ *modbyte |= (7 << nshift);\r
+ break;\r
+ default:; /* if it's not one of these we do nothing */\r
+}\r
+}\r
+\r
+/********************************************\r
+ Add Macro to LOCAL symbol table.\r
+ The last symbol added to the symbol\r
+ table is the label for this macro.\r
+\r
+*********************************************/\r
+void AddMacro(void)\r
+{\r
+S16 i, j;\r
+S8 mac[100];\r
+\r
+mac[0] = 0;\r
+\r
+if (iMacNext >= MACBUFMAX-50)\r
+ fatal_error("Macro buffer overflow...");\r
+if (iMacNext >= MACSMAX)\r
+ fatal_error("Macro table overflow...");\r
+\r
+i = 0; j = 0;\r
+while(isskip(*line_ptr)) line_ptr++; /* skip while space */\r
+\r
+/* Read the macro including white space upto EOL or comment.\r
+ j keeps track of the last NON-space character so we don't\r
+ store unneeded spaces at the end of the macro.\r
+*/\r
+\r
+while ((*line_ptr) && (*line_ptr != SEMI)) {\r
+ mac[i++] = *line_ptr++;\r
+ if (mac[i-1] > 0x20) j = i; /* j will be length */\r
+}\r
+\r
+strncpy(pMacNext, mac, j);\r
+\r
+/* These are all "iLSymNext-1" because the Macro label has\r
+ already been added to the symbol table when AddMacro\r
+ is called.\r
+*/\r
+\r
+lst[iLSymNext-1].Type = 0; /* cancel previous type */\r
+lst[iLSymNext-1].Type |= MACRO; /* initialize type */\r
+\r
+rgMacPtr[iMacNext] = pMacNext; /* store mac ptr in pmac array */\r
+lst[iLSymNext-1].Offs = iMacNext; /* store mac # in offset */\r
+iMacNext++;\r
+pMacNext += j;\r
+*pMacNext = 0; /* null terminate the macro */\r
+pMacNext++;\r
+\r
+}\r