]> pd.if.org Git - mmurtl/commitdiff
autocommit for file dated 1995-01-26 12:55:50
authorRichard Burgess <>
Thu, 26 Jan 1995 12:55:50 +0000 (12:55 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Mon, 17 Oct 2016 14:03:47 +0000 (14:03 +0000)
dasm/source/dasmq.c [new file with mode: 0644]

diff --git a/dasm/source/dasmq.c b/dasm/source/dasmq.c
new file mode 100644 (file)
index 0000000..64d12bf
--- /dev/null
@@ -0,0 +1,1569 @@
+/* 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