]> pd.if.org Git - mmurtl/commitdiff
autocommit for file dated 1995-02-09 16:30:42
authorRichard Burgess <>
Thu, 9 Feb 1995 16:30:42 +0000 (16:30 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Mon, 17 Oct 2016 14:03:48 +0000 (14:03 +0000)
msamples/cm32m/cm32.c [new file with mode: 0644]

diff --git a/msamples/cm32m/cm32.c b/msamples/cm32m/cm32.c
new file mode 100644 (file)
index 0000000..b65ec9c
--- /dev/null
@@ -0,0 +1,4756 @@
+/*\r
+ C Minus 32 (C-32) Compiler  (DOS version)\r
+\r
+ Derived from code Copyright (c) 1989, Dave Dunfield\r
+ Copyright (c) 1991, 1992, 1993, 1994, 1995 R.A. Burgess\r
+ Permission is required from the authors for\r
+ any commercial use of this source code.\r
+\r
+ 32 bit assembly language generation specificly for the Intel 386/486\r
+ for the DASM assembler.\r
+\r
+ CM-32 integer support:\r
+ short = int = short int = 16 bits,\r
+ long = long int = 32 bits.\r
+\r
+ 16 bit Intel addressing modes are NOT supported for code generation.\r
+\r
+*/\r
+\r
+/* These Simple defines to keep down the number of keystrokes. Also\r
+   lessens that horrible burden of portability that C is supposed to\r
+   shield you from (right...)\r
+*/\r
+\r
+#define U32 unsigned long\r
+#define S32 long\r
+#define U16 unsigned int\r
+#define S16 int\r
+#define U8 unsigned char\r
+#define S8 char\r
+\r
+#include <ctype.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <stdlib.h>\r
+#include "CM32.h"\r
+#include "Tokens32.h"\r
+\r
+#include "\OSSource\MMemory.h"\r
+\r
+#define SCODEBUF 512000                /* 500Kb allocated buffer */\r
+U8 *pcodebuf;\r
+\r
+/* Input buffer & input pointer for preprocessed lines */\r
+char line_in[LINE_MAX], *input_ptr;\r
+\r
+/* Global value storage locations (results from lexical scanner) */\r
+\r
+char gst[SYMBOL_SIZE+1];       /* Name if SYMBOL */\r
+U8  namesize;                          /* size of SYMBOL name */\r
+U32 gvalue;\r
+\r
+/*\r
+   if token = SYMBOL then gvalue is length (number of characters).\r
+   if token = NUMBER then gvalue is value of NUMBER.\r
+   if token = STRING then gvalue is index into literal pool to the string.\r
+*/\r
+\r
+/* Symbol table and associated variables */\r
+\r
+char GPool[GBUFFSIZE];  /* Pool for symbol names (packed) */\r
+char LPool[LBUFFSIZE];  /* Pool for local symbol names (packed) */\r
+\r
+struct sym {\r
+       U32 type;               /* 32 symbol type bits  */\r
+       U32 itypedef;   /* index in symtab for type definition, or zero */\r
+                                       /* If strucmem, struct it belongs to */\r
+       U32 oname;              /* offset in pool to sym name */\r
+       U32 argoffset;  /* arg offset from EBP for locals */\r
+       U32 strucoff;   /* size of strucdef (also offset for next new member), */\r
+                                       /*       if strucmem, it's member's offset in structure */\r
+       U32     dindex;         /* rg for index to dim */\r
+       };                              /* or index to proto list for arg types */\r
+                                       /* or holds labels for for local Goto */\r
+\r
+struct sym symtab[MAX_SYMBOLS];  /* SYM TABLE... */\r
+\r
+U32 oNextGName = 0;            /* offset to next new name in global pool */\r
+U32 oNextLName = 0;            /* offset to next new name in local pool */\r
+\r
+U32 proto_list[MAX_PROTOS],    /* list of arg types for functions */\r
+       global_top = 0,\r
+       global_count = 0,\r
+       iproto_next = 1,                /* index to next available proto args (0 illegal)*/\r
+       icrntpro = 0,                   /* index to arg being tested */\r
+       iarg = 0,\r
+       argtype = 0,\r
+       local_top = MAX_SYMBOLS,\r
+       arg_count,                              /* number of args so far  */\r
+       local_stack,\r
+       sptr,                                   /* symbol ptr */\r
+       fptr;                                   /* ptr to function symbol we are in */\r
+\r
+       /* structure definition use and control variables */\r
+\r
+       S8 fInStruct = 0;       /* true if currently defining struct members */\r
+    U32 CrntStrucDef;  /* iSym for Structure def we are using or working on */\r
+       char structname[12] = "0StructDef";\r
+       U8 NxtStrucNum = 0;\r
+       U32 memoffset;          /* used to calculate members offset */\r
+    U32 strucsize;          /* used for size of struct in INC and DEC */\r
+/* Literal + Dimension pools and associated variables */\r
+\r
+U32 dim_top = 0,\r
+    literal_top = 0,\r
+    dim_pool[DIM_SIZE];                /* each entry has nDims for an array */\r
+\r
+\r
+char literal_pool[LITER_BUFF];\r
+\r
+/* Expression evaluation stack. The value field contents vary\r
+   depending on what the token is. If it's a Symbol, this is\r
+   the symbol table entry. If token is a number then value is\r
+   the actual value of the number.  If it's a string, then\r
+   value is the length.\r
+   The offset is used to hold constant values for addresses\r
+   that are in the index register or on the stack. \r
+   When accessing the data pointed to, if this is NON-zero,\r
+   we use the [ESI+NUM] addressing mode (Base+Offset). */\r
+\r
+struct expr {\r
+       U32 token;              /* Number, Symbol, String, In-Accumulator, etc. */\r
+       U32 value;              /* varies depending on token */\r
+       U32 type;               /* type from symtab */\r
+       U32 offset;             /* Offset of pointer in structure for access */\r
+       };\r
+\r
+struct expr expstk[EXPR_DEPTH];  /* Expression Stack */\r
+\r
+U32 expr_ptr = 0;\r
+\r
+/* Misc. global variables */\r
+\r
+char if_flag = 0,\r
+     asm_flag = 0,\r
+     not_flag = 0,\r
+        prefix = 'L';                          /* override with /P:x switch */\r
+\r
+U32 break_stack[LOOP_DEPTH],\r
+       continue_stack[LOOP_DEPTH],\r
+       switch_stack[MAX_SWITCH*2],\r
+       exit_label = 0,\r
+       exit_used = 0,\r
+       in_function = 0,\r
+       loop_ptr = 0,\r
+       switch_ptr = 0,\r
+       define_top = 0,\r
+       sdefault = 0,\r
+       exit_flag = 0,\r
+       next_lab = 0,\r
+       line_number = 0,\r
+       begin_comment = 0,      /* line that a comment starts on for errors */\r
+       ungot_token = 0,\r
+       error_count = 0,\r
+       warn_count = 0;\r
+\r
+\r
+       /* input/output pointers and buffer for for preprocessor */\r
+\r
+char buffer[LINE_MAX],\r
+        *buffin_ptr,\r
+        *buffout_ptr;\r
+\r
+       /* macro definition: index, pool and top pointers */\r
+\r
+U32  macro = 0;\r
+char *define_index[MACROS],\r
+      define_pool[MAC_BUFF],\r
+     *define_ptr;\r
+\r
+       /* macro parameter: index, pool and top pointers */\r
+unsigned parm;\r
+char *parm_index[PARAMETERS],\r
+      parm_pool[PARM_BUFF],\r
+     *parm_ptr;\r
+\r
+       /* include: line stack & count, file pointers, filename */\r
+long include = 0,\r
+        incl_line[INCL_DEPTH];\r
+\r
+FILE *incl_fh[INCL_DEPTH],\r
+        *source_fh = 0,\r
+        *asm_fh = 0,\r
+     *code_fh = 0,\r
+        *list_fh = 0;\r
+\r
+char codename[40];\r
+char srcname[40];\r
+char asmname[40];\r
+char lstname[40];\r
+\r
+/* file open flags */\r
+\r
+char fLISTOpen = 0,\r
+     fTEMPOpen = 0,\r
+     fCODEOpen = 0,\r
+     fASMOpen = 0;\r
+\r
+       /* misc. variables and flags */\r
+char comment_flag = -1,\r
+        fQuiet = 0,\r
+     fSource = 0,\r
+     fNoOpt = 0,\r
+     fOptS = 0,\r
+     fList = 0,\r
+     fGen = 0,\r
+     fWarnings = 0;\r
+\r
+       /* inlcude path */\r
+\r
+char *incdir = "\\CM32\\INCLUDE";\r
+\r
+/* For Code Gen */\r
+\r
+U32    global_width = 0,\r
+       asmlab = 0;\r
+\r
+char zero_flag,\r
+     stack_flag = 0;\r
+\r
+U8 databuf[4096];\r
+U32 pc = 0;                    /* code pointer in */\r
+U32 pco = 0;           /* code pointer out */\r
+U32 pd = 0;\r
+\r
+#include "Optimize.h"\r
+#include "Proto32.h"\r
+\r
+/******************************************\r
+* Determine if a character is alphabetic\r
+* or is underscore.\r
+*******************************************/\r
+\r
+static char is_alpha(char chr)\r
+{\r
+       return (((chr|0x20) >= 'a') && ((chr|0x20) <= 'z'))\r
+               || (chr == '_');\r
+}\r
+\r
+/*********************************************\r
+* Determine if a character is a numeric digit\r
+**********************************************/\r
+\r
+static char is_digit(char chr)\r
+{\r
+       return (chr >= '0') && (chr <= '9');\r
+}\r
+\r
+/******************************************\r
+* Test for valid character in a name.(MACRO)\r
+*******************************************/\r
+\r
+#define is_alnum(c)    (is_alpha(c) || is_digit(c))\r
+/*\r
+static char is_alnum(char c)\r
+{\r
+       return is_alpha(c) || is_digit(c);\r
+}\r
+*/\r
+\r
+/****************\r
+* Copy a string\r
+*****************/\r
+\r
+static void copystring(char *dest, char *source)\r
+{\r
+       while(*dest++ = *source++);\r
+}\r
+\r
+\r
+/***************************\r
+* Test for string equality\r
+****************************/\r
+\r
+static char equal_string(char *str1, char *str2)\r
+{\r
+       do {\r
+               if(*str1 != *str2++)\r
+               return 0; }\r
+       while(*str1++);\r
+       return -1;\r
+}\r
+\r
+/*********************************************************\r
+ Skip to next non-blank (space, tab, CR or LF) in buffer\r
+ returning the character we find.\r
+***********************************************************/\r
+\r
+static char skip_blanks(void)\r
+{\r
+       while((*buffin_ptr < 0x21) && (*buffin_ptr))\r
+               ++buffin_ptr;\r
+       return *buffin_ptr;\r
+}\r
+\r
+/***************************************\r
+* Test for more macro parameters\r
+****************************************/\r
+\r
+static long more_parms(void)\r
+{\r
+       register char c;\r
+\r
+       if(((c = skip_blanks()) == ',') || (c == ')'))\r
+               ++buffin_ptr;\r
+       else\r
+               line_error("Invalid macro parameter");\r
+       return c == ',';\r
+}\r
+\r
+/**************************************\r
+* Skip ahead through a comment\r
+***************************************/\r
+\r
+static void skip_comment(void)\r
+{\r
+       register U16 x;\r
+       register char c;\r
+\r
+       x = 0;\r
+       for(;;) {\r
+               if(!(c = *buffin_ptr++)) {                                      /* end of line_in */\r
+                       if(!fgets(buffin_ptr = buffer, LINE_MAX, source_fh)) {\r
+                               *buffin_ptr = 0;\r
+                               UTC_error();\r
+                               return; }\r
+                       ++line_number; }\r
+               else {\r
+                       if((x = (x << 8) + c) == (('*' << 8) + '/'))    /* close */\r
+                               return;\r
+                       if(x == (('/' << 8) + '*'))                             /* imbedded comment */\r
+                               skip_comment();\r
+               }\r
+       }\r
+}\r
+\r
+/*****************************************************************\r
+* Copy a named symbol from the input buffer to the output buffer\r
+******************************************************************/\r
+\r
+static void copy_name(void)\r
+{\r
+       do\r
+               *buffout_ptr++ = *buffin_ptr++;\r
+       while(is_alnum(*buffin_ptr));\r
+       *buffout_ptr = 0;\r
+}\r
+\r
+/******************************************************************\r
+* Copy a quoted string from the input buffer to the output buffer\r
+* with regard for "protected" characters.\r
+*******************************************************************/\r
+\r
+static void copy_string(void)\r
+{\r
+       register char delim;\r
+\r
+       if(((delim = *buffin_ptr) == '"') || (delim == 0x27)) {\r
+               do {\r
+                       if(!(*buffout_ptr++ = *buffin_ptr)) {           /* premature end */\r
+                               line_error("Unterminated string");\r
+                               return; }\r
+                       if(*buffin_ptr++ == '\\')                               /* protected char */\r
+                               *buffout_ptr++ = *buffin_ptr++; }\r
+               while(*buffin_ptr != delim);\r
+               *buffout_ptr++ = *buffin_ptr++; }\r
+}\r
+\r
+/**************************************************************\r
+* Lookup a word from the input stream to see if it is a macro\r
+***************************************************************/\r
+\r
+static U32 lookup_macro(char eflag)\r
+{\r
+       register long i;\r
+       register char *name;\r
+\r
+       name = buffout_ptr;\r
+       copy_name();\r
+       for(i = macro - 1; i >= 0; --i)                 /* look it up */\r
+               if(!strcmp(name, define_index[i]))\r
+                       return i;\r
+       if(eflag)                                                               /* not found */\r
+               line_error("Undefined macro");\r
+       return -1;\r
+}\r
+\r
+/**************************************************************\r
+* Resolve a word into a macro definition (if it is defined)\r
+***************************************************************/\r
+\r
+static void resolve_macro(void)\r
+{\r
+       char *mptr, *ptr, *old_ptr;\r
+       long i;\r
+       register char c;\r
+\r
+       old_ptr = buffout_ptr;\r
+       if((i = lookup_macro(0)) != -1) {       /* Substitution required */\r
+               mptr = define_index[i];\r
+               while(*mptr++);\r
+               parm = 0;\r
+               parm_ptr = parm_pool;\r
+               if(*mptr++) {                                   /* parameterized macro */\r
+                       if(skip_blanks() == '(') {\r
+                               ++buffin_ptr;\r
+                               do {\r
+                                       parm_index[parm++] = parm_ptr;\r
+                                       while(*buffin_ptr && (*buffin_ptr != ',') && (*buffin_ptr != ')'))\r
+                                               *parm_ptr++ = *buffin_ptr++;\r
+                                       *parm_ptr++ = 0; }\r
+                               while(more_parms()); } }\r
+               while(c = *mptr) {                              /* copy over definition */\r
+                       if(c & 0x80) {                          /* parameter substitution */\r
+                               if((i = c & 0x7f) < parm) {\r
+                                       for(ptr = parm_index[i]; *ptr; ++ptr)\r
+                                               *old_ptr++ = *ptr; } }\r
+                       else\r
+                               *old_ptr++ = *mptr;\r
+                       ++mptr;\r
+               }\r
+               *(buffout_ptr = old_ptr) = 0;\r
+       }\r
+}\r
+\r
+/****************************************\r
+* Test for a string in input stream\r
+*****************************************/\r
+\r
+static unsigned long match(char *ptr)\r
+{\r
+       register char *ptr1;\r
+\r
+       ptr1 = buffin_ptr;\r
+       while(*ptr)\r
+               if(*ptr++ != *ptr1++)           /* symbols do not match */\r
+                       return 0;\r
+       if(is_alnum(*ptr1))                     /* symbol continues */\r
+               return 0;\r
+       buffin_ptr = ptr1;\r
+       skip_blanks();\r
+       return(1);\r
+}\r
+\r
+/*******************************************************\r
+* Compare all optimization table entries with the\r
+* instructions in the peephole buffer.\r
+* Return:      0       = No match\r
+*           n  = Full match begining at peep_top\r
+*                                and ending at entry 'n'\r
+********************************************************/\r
+\r
+static long compareT(char *ptable, long peep)\r
+{\r
+       int i;\r
+       char *ptr1, *ptr2, c;\r
+\r
+       for(i=0; i < OSYMBOLS; ++i)\r
+               symbols[i][0] = 0;\r
+\r
+       ptr1 = peep_buffer[peep];\r
+       while(c = *ptable) {                    /* any chars left in entry? */\r
+               if(c == '\n') {                         /* end of line in table entry */\r
+                       if(*ptr1)                               /* and no match... */\r
+                               return 0;\r
+            peep = (peep+1) % OBUF_SIZE;\r
+                       if(peep == peep_next)\r
+                               return 0;\r
+                       ptr1 = peep_buffer[peep];       /* next buffer entry */\r
+               }\r
+               else if (c == ' ')  {           /* space */\r
+                       if(!isspace(*ptr1))\r
+                               return 0;\r
+                       while(isspace(*ptr1))\r
+                               ++ptr1; }\r
+               else if(c & 0x80) {                     /* symbol name */\r
+\r
+                       c = *(ptable + 1);\r
+\r
+            ptr2 = symbols[*ptable & 0x7f];\r
+                       if(*ptr2) {\r
+                               while(*ptr1 && (*ptr1 != c))\r
+                                       if(*ptr1++ != *ptr2++)\r
+                                               return 0;\r
+                               if(*ptr2)\r
+                                       return 0; }\r
+                       else {                                                  /* new symbol */\r
+                               while(*ptr1 && (*ptr1 != c))\r
+                                       *ptr2++ = *ptr1++;\r
+                               *ptr2 = 0; } }\r
+\r
+               else if(c != *ptr1++) return 0;         /* normal character */\r
+\r
+               ++ptable;\r
+       }\r
+       return (*ptr1) ? 0 : peep + 1;\r
+}\r
+\r
+\r
+/********************************************************\r
+* Exchange new code for old code in the peephole buffer.\r
+* pnew points to the first char of the new code.\r
+* old points to last entry of buffer code to be replaced.\r
+*********************************************************/\r
+\r
+static void exchange(unsigned long old, char *pnew)\r
+{\r
+       char *ptr1, *ptr2;\r
+\r
+    peep_top = (old+(OBUF_SIZE-1)) % OBUF_SIZE;  /* last entry of replacement */\r
+       ptr2 = peep_buffer[peep_top];\r
+       while(*pnew) {                                          /* while still some new stuff left */\r
+               if(*pnew & 0x80) {                              /* output a symbol */\r
+                       ptr1 = symbols[*pnew & 0x7f];   /* ptr1 points to a symbol */\r
+                       while(*ptr1)\r
+                               *ptr2++ = *ptr1++; }\r
+               else if(*pnew == '\n') {                /* end of a new entry */\r
+                       *ptr2 = 0;                                      /* put null at end of line */\r
+            peep_top = (peep_top+(OBUF_SIZE-1)) % OBUF_SIZE;\r
+                       ptr2 = peep_buffer[peep_top]; }\r
+               else\r
+                       *ptr2++ = *pnew;\r
+               ++pnew; }\r
+       *ptr2 = 0;\r
+}\r
+\r
+\r
+/***********************************************\r
+   Simulates fgets from the HUGE code buffer\r
+************************************************/\r
+\r
+static char *fgetcode(char *pout, long maxout)\r
+{\r
+char c, *s;\r
+long n;\r
+\r
+       s = pout;\r
+       n = 0;\r
+\r
+       if (pco >= pc)          /* end of valid buffer data */\r
+               return(0);\r
+\r
+       while ((n < maxout-1) && (pcodebuf[pco]))\r
+       {\r
+               c = pcodebuf[pco];\r
+               *pout++  = pcodebuf[pco++];\r
+               n++;\r
+               if (c == 0x0A)\r
+               {\r
+            *pout = 0;\r
+                       return(s);\r
+               }\r
+       }\r
+       if (n)\r
+               return(s);\r
+       else\r
+               return(0);\r
+}\r
+\r
+\r
+/****************************************\r
+* Read a line into the peephole buffer\r
+* from the tmpcodebuf\r
+*****************************************/\r
+\r
+static long read_line(void)\r
+{\r
+char c, *sptr;\r
+\r
+       if(fgetcode(peep_buffer[peep_next], OLINE_SIZE)) {\r
+\r
+               /*strip CR/LF from line */\r
+               sptr = &(peep_buffer[peep_next]);\r
+\r
+               while (c = *sptr) {\r
+                       if (c == '\r') *sptr = '\0';\r
+                       if (c == '\n') *sptr = '\0';\r
+                       sptr++;\r
+               }\r
+\r
+               /* next peep_buf entry please... */\r
+               peep_next = (peep_next+1) % OBUF_SIZE;\r
+               return 1;\r
+       }\r
+       return 0;\r
+}\r
+\r
+/*********************************************************\r
+* Write a line from the peephole buffer to the output file\r
+**********************************************************/\r
+static void write_line(void)\r
+{\r
+       if (fGen)\r
+               fputs(peep_buffer[peep_top], code_fh);\r
+       else\r
+               fputs(peep_buffer[peep_top], asm_fh);\r
+       peep_top = (peep_top + 1) % OBUF_SIZE;\r
+       if (fGen)\r
+               fputs("\n", code_fh);\r
+       else\r
+               fputs("\n", asm_fh);\r
+}\r
+\r
+\r
+/*********************************************************\r
+* Peephole Optimizer function for code segment\r
+**********************************************************/\r
+static void optimize(void)\r
+{\r
+       long i, j;\r
+       char *ptr;\r
+\r
+       if (!fQuiet)\r
+               fputs("CM32 V2.3M optimizer phase\r\n", stdout);\r
+\r
+       /* initially fill every line in peephole buffer */\r
+\r
+       j = 0;\r
+\r
+       for(;;) {\r
+                       /* keep buffer full! */\r
+               while ( ((peep_next+1) % OBUF_SIZE) != peep_top ) \r
+               {\r
+               if (!read_line())\r
+               {\r
+                       break;\r
+                       }\r
+               }\r
+               /* walk thru the whole peep_table and see if we have\r
+                       matches in the peep_buffer  */\r
+\r
+               for(i=0; ptr = peep_table[i]; i += 2) {\r
+\r
+            j = compareT(ptr, peep_top);\r
+\r
+                       if(j) {                                                 /* we have a match, exchange it */\r
+                               exchange(j, peep_table[i+1]);\r
+                               break;                                          /* break to fill buffer again */\r
+                       }\r
+               }\r
+               if(!j) write_line();            /* no matches, flush this line */\r
+\r
+               if (peep_top == peep_next)\r
+                       return;                                 /* We are done! */\r
+       }\r
+}\r
+\r
+\r
+/********************************************\r
+ Read a line & perform pre-processing. if_flag\r
+ is used to indicate the nesting of ifs.  It\r
+ is incremented for each if found.  The high\r
+ bit is set if we are actually IN an active\r
+ macro.\r
+*********************************************/\r
+\r
+static long readline(void)\r
+{\r
+U32 i;\r
+char c, ch, fgotone;\r
+\r
+for(;;) {\r
+       if(!fgets(buffin_ptr = buffer, LINE_MAX, source_fh)) \r
+       {\r
+               if(include)\r
+               {\r
+                       fclose(source_fh);\r
+                       line_number = incl_line[--include];\r
+                       source_fh = incl_fh[include];\r
+                       continue;\r
+               }\r
+               return 0;\r
+       }               /* no more lines... */\r
+\r
+       ++line_number;\r
+       buffout_ptr = line_in;\r
+\r
+       fgotone = 0;\r
+\r
+       if ((ch = skip_blanks()) == '#') \r
+       {\r
+\r
+               if(match("#asm"))\r
+               {                                                               /* if inline assembly */\r
+                       asm_flag = -1;\r
+                       fgotone = -1;\r
+               }\r
+\r
+               else if(match("#endasm")) \r
+               {                                                               /* end of assembly */\r
+                       asm_flag = 0;\r
+                       fgotone = -1;\r
+               }\r
+\r
+               else if(match("#ifdef"))\r
+               {                                                               /* if macro defined */\r
+                       fgotone = -1;\r
+                       if(if_flag)\r
+                               ++if_flag;                                      /* one deeper */\r
+                       else if(lookup_macro(0) == -1)\r
+                       {\r
+                               if_flag = 0x80;\r
+                       }\r
+               }\r
+\r
+               else if(match("#ifndef"))\r
+               {                       /* if macro not defined */\r
+                       fgotone = -1;\r
+                       if(if_flag)\r
+                               ++if_flag;\r
+                       else if(lookup_macro(0) != -1)\r
+                       {\r
+                                       if_flag = 0x80;\r
+                       }\r
+               }\r
+\r
+               else if(match("#else"))\r
+               {                       /* reverse condition */\r
+                       fgotone = -1;\r
+                       if(!(if_flag & 0x7f))                   /* not nested? */\r
+                               if_flag ^= 0x80;\r
+               }                                                                       /* XOR high bit */\r
+\r
+               else if(match("#endif"))\r
+               {                                                                       /* end conditional */\r
+                       fgotone = -1;\r
+                       if(if_flag & 0x7f)                              /* if nested, reduce one */\r
+                               --if_flag;\r
+                       else\r
+                               if_flag = 0;\r
+               }                               /* else it's over */\r
+\r
+               else if(match("#pragma"))\r
+               {               /* later... */\r
+                               fgotone = -1;\r
+               }\r
+       }\r
+\r
+               /* If we got here, we have found # and it's not\r
+                  a conditional, so it must be a new macro.\r
+               */\r
+\r
+       if ((!fgotone) && (!if_flag))\r
+       {\r
+               if (ch == '#')\r
+               {\r
+                       if(match("#define")) {                  /* define a new macro */\r
+                               if(macro >= MACROS) {\r
+                                       fatal_error("Too many macro definitions");\r
+                                       exit(-1); }\r
+                               buffout_ptr = define_index[macro++] = define_ptr;\r
+                               if(!is_alpha(*buffin_ptr)) {\r
+                                       line_error("Invalid macro name");\r
+                                       continue; }\r
+                               copy_name();                            /* get macro name */\r
+                               define_ptr = buffout_ptr;\r
+                               *define_ptr++ = 0;\r
+                               parm = 0;\r
+                               parm_ptr = parm_pool;\r
+                               if(*buffin_ptr == '(') {        /* parameterized macro */\r
+                                       *define_ptr++ = 1;\r
+                                       ++buffin_ptr;\r
+                                       do {\r
+                                               if(parm >= PARAMETERS) {\r
+                                                       line_error("Too many macro parameters");\r
+                                                       break; }\r
+                                               parm_index[parm++] = buffout_ptr = parm_ptr;\r
+                                               skip_blanks();\r
+                                               copy_name();\r
+                                               parm_ptr = buffout_ptr+1; }\r
+                                       while(more_parms()); }\r
+                               else\r
+                                       *define_ptr++ = 0;\r
+                               skip_blanks();\r
+                               while(c = *buffin_ptr) {\r
+                                       buffout_ptr = define_ptr;\r
+                                       if(is_alpha(c)) {\r
+                                               resolve_macro();\r
+                                               for(i=0; i < parm; ++i) {\r
+                                                       if(!strcmp(define_ptr, parm_index[i])) {\r
+                                                               *define_ptr++ =  i + 0x80;\r
+                                                               buffout_ptr = define_ptr;\r
+                                                               break; } }\r
+                                               define_ptr = buffout_ptr; }\r
+                                       else if((c == '"') || (c == 0x27)) {\r
+                                               copy_string();\r
+                                               define_ptr = buffout_ptr; }\r
+                                       else {\r
+                                               if((*++buffin_ptr == '*') && (c == '/')) {\r
+                                                       ++buffin_ptr;\r
+                                                       begin_comment = line_number;\r
+                                                       skip_comment(); }\r
+                                               else\r
+                                                       *define_ptr++ = c; }\r
+                                       /* skip_blanks(); */\r
+                               }\r
+                               *define_ptr++ = 0; }\r
+\r
+                       else if(match("#undef"))\r
+                       {                       /* undefine a macro */\r
+                               if((i = lookup_macro(-1)) != -1)\r
+                               {\r
+                                       if(i == (macro - 1))            /* last one, simple delete */\r
+                                               define_ptr = define_index[i];\r
+                                       else\r
+                                       {                                               /* not last, reclaim space */\r
+                                               define_ptr -= (parm = (buffin_ptr = define_index[i+1]) -\r
+                                                       (parm_ptr = define_index[i]));\r
+                                               while(parm_ptr < define_ptr)\r
+                                                       *parm_ptr++ = *buffin_ptr++;\r
+                                               while(i < macro)\r
+                                               {               /* adjust index list */\r
+                                                       define_index[i] = define_index[i+1] - parm;\r
+                                                       ++i;\r
+                                               }\r
+                                       }\r
+                                       --macro;\r
+                               }\r
+                       }\r
+                       else if(match("#include"))\r
+                       {               /* include a file */\r
+                               if(include >= INCL_DEPTH)\r
+                                       fatal_error("Too many include files");\r
+                               if((c = skip_blanks()) == '<')\r
+                               {       /* incdir definition */\r
+                                       for(parm_ptr = incdir; *parm_ptr; ++parm_ptr)\r
+                                               *buffout_ptr++ = *parm_ptr;\r
+                                       *buffout_ptr++ = '\\';                  /*** OS dependent!!! ***/\r
+                                       c = '>';\r
+                               }\r
+                               else if(c != '"')\r
+                               {                                       /* current directory */\r
+                                       line_error("Invalid include file name");\r
+                                       continue;\r
+                               }\r
+                               while(*++buffin_ptr && (*buffin_ptr != c))\r
+                                       *buffout_ptr++ = *buffin_ptr;\r
+                               *buffout_ptr = 0;\r
+                               incl_fh[include] = source_fh;\r
+                               incl_line[include] = line_number;\r
+                               if(source_fh = fopen(line_in, "r"))\r
+                               {\r
+                                       line_number = 0;\r
+                                       ++include;\r
+                               }\r
+                               else\r
+                               {\r
+                                       line_error("Cannot open include file");\r
+                                       source_fh = incl_fh[include];\r
+                               }\r
+                       }\r
+                       else\r
+                               line_error("Unknown preprocessor directive");\r
+\r
+               }\r
+               else\r
+               {                               /* default, perform pre-processing */\r
+\r
+                       if(asm_flag)            /* inline assembly */\r
+                               do_asm(buffer);\r
+                       else\r
+                       while(c = *buffin_ptr)\r
+                       {\r
+                               if(is_alpha(c))                         /* symbol, could be macro */\r
+                                       resolve_macro();\r
+                               else if((c == '"') || (c == 0x27))              /* quoted string */\r
+                                       copy_string();\r
+                               else\r
+                               {\r
+                                       if((*++buffin_ptr == '*') && (c == '/') && comment_flag)\r
+                                       { /* comment */\r
+                                               ++buffin_ptr;\r
+                                               begin_comment = line_number; /* save begin line*/\r
+                                               skip_comment();\r
+                                       }\r
+                                       else                            /* nothing special, copy it */\r
+                                               *buffout_ptr++ = c;\r
+                               }\r
+                       }\r
+                       if (fSource)\r
+                       {\r
+                               code_chr(';');\r
+                               code_str(buffer);\r
+                       }\r
+                       input_ptr=line_in;      /* point to start of new line */\r
+                       *buffout_ptr = 0;               /* null at end of line */\r
+                       return -1;\r
+               }\r
+       }  /* !fgotone && !if_flag */\r
+} /*for*/\r
+}\r
+\r
+\r
+\r
+\r
+/***********************************************************\r
+* Test to see if the last statement compiled was an "exit"\r
+* statement, and if so, generate a jump to the appriopriate\r
+* label. This prevents generation of a spurious jump when a\r
+* "return" statement is used at the end of a function.\r
+************************************************************/\r
+\r
+static U32 test_exit(void)\r
+{\r
+       if(exit_flag) {\r
+               jump(exit_flag, -1);\r
+               exit_used = -1;\r
+               return(exit_flag = 0);\r
+               }\r
+       return -1;\r
+}\r
+\r
+/*********************************************\r
+* Output an warning message with quoted text\r
+**********************************************/\r
+\r
+static void t_warn(char *msg, char *txt)\r
+{\r
+int i;\r
+       ++warn_count;\r
+       if (!fWarnings) return;\r
+\r
+       incl_line[include] = line_number;\r
+       for(i=0; i <= include; ++i) {\r
+               put_num(incl_line[i], list_fh);\r
+               fputc(':', list_fh);\r
+               }\r
+       fputc(' ', list_fh);\r
+       fputs("Warning: ", list_fh);\r
+       fputs(msg, list_fh);\r
+       fputc(' ', list_fh);\r
+       fputc(0x27, list_fh);           /* single quote */\r
+       fputs(txt, list_fh);\r
+       fputc(0x27, list_fh);           /* single quote */\r
+       fputc('\r', list_fh);\r
+       fputc('\n', list_fh);\r
+}\r
+\r
+/*********************************************\r
+* Output an error message with quoted text\r
+**********************************************/\r
+\r
+static void t_error(char *msg, char *txt)\r
+{\r
+       char emsg[50], *ptr;\r
+\r
+       ptr = emsg;\r
+       while(*msg)\r
+               *ptr++ = *msg++;\r
+       *ptr++ = ':';\r
+       *ptr++ = ' ';\r
+       *ptr++ = 0x27;          /* single quote */\r
+       while(*txt)\r
+               *ptr++ = *txt++;\r
+       *ptr++ = 0x27;          /* single quote */\r
+       *ptr = 0;\r
+       line_error(emsg);\r
+}\r
+\r
+\r
+/***********************************************************\r
+* Report an error involving a freshly parsed symbol name\r
+************************************************************/\r
+\r
+static void symbol_error(char *msg)\r
+{\r
+       t_error(msg, gst);\r
+}\r
+\r
+\r
+/***********************************************************\r
+* Report a syntax error\r
+************************************************************/\r
+\r
+static void syntax_error(void)\r
+{\r
+       line_error("Syntax error");\r
+}\r
+\r
+/***********************************************************\r
+* Report incompatable types\r
+************************************************************/\r
+\r
+static void type_error(void)\r
+{\r
+       line_error("Types mismatch");\r
+}\r
+\r
+/***********************************************************\r
+* Report an error in indirection\r
+************************************************************/\r
+\r
+static void index_error(void)\r
+{\r
+       line_error("Illegal indirection");\r
+}\r
+\r
+\r
+/****************************************************\r
+* Test the next token in the input stream, put it\r
+* back if its not the one we are looking for.\r
+****************************************************/\r
+\r
+static char test_token(U32 token)\r
+{\r
+       U32 token1;\r
+\r
+       if((token1 = get_token()) == token)\r
+               return -1;\r
+       unget_token(token1);\r
+       return 0;\r
+}\r
+\r
+\r
+/**************************************************************\r
+* Check for a certain token occuring next in the input stream.\r
+* If it is not found, report an error.\r
+***************************************************************/\r
+\r
+static void expect(U32 token)\r
+{\r
+       if(!test_token(token))\r
+               t_error("Expected", tokens[token]);\r
+}\r
+\r
+/***************************************\r
+ Report a Unterminated Comment error\r
+****************************************/\r
+\r
+static void UTC_error(void)\r
+{\r
+       U32 i;\r
+\r
+       incl_line[include] = line_number;\r
+       for(i=0; i <= include; ++i) {\r
+               put_num(incl_line[i], list_fh);\r
+               fputc(':', list_fh);\r
+               }\r
+       fputc(' ', list_fh);\r
+       fputs("Unterminated comment from line: ", list_fh);\r
+       put_num(begin_comment, list_fh);\r
+       fputc('\r', list_fh);\r
+       fputc('\n', list_fh);\r
+\r
+       if(++error_count == MAX_ERRORS)\r
+               fatal_error("Too many errors");\r
+}\r
+\r
+/***************************************\r
+* Report a compile error\r
+****************************************/\r
+\r
+static void line_error(char *message)\r
+{\r
+       U32 i;\r
+\r
+       incl_line[include] = line_number;\r
+       for(i=0; i <= include; ++i) {\r
+               put_num(incl_line[i], list_fh);\r
+               fputc(':', list_fh);\r
+               }\r
+       fputc(' ', list_fh);\r
+       fputs(message, list_fh);\r
+       fputc('\r', list_fh);\r
+       fputc('\n', list_fh);\r
+\r
+       if(++error_count == MAX_ERRORS)\r
+               fatal_error("Too many errors");\r
+}\r
+\r
+/*******************************************\r
+* Report a non-recoverable compile error\r
+********************************************/\r
+\r
+static void fatal_error(char *string)\r
+{\r
+       line_error(string);\r
+\r
+       /* put this out even if fQuiet */\r
+       fputs("Fatal error, compilation aborted\r\n", stdout);\r
+\r
+       if (fList) {\r
+               fputs("Fatal error, compilation aborted\r\n", list_fh);\r
+               if (fLISTOpen)\r
+                       fclose(list_fh);\r
+               }\r
+\r
+       /* close files */\r
+\r
+       if (fASMOpen) fclose(asm_fh);\r
+       exit(-1);  /* We are done ! */\r
+\r
+}\r
+\r
+/*****************************************************\r
+* Check that a loop is active & setup exit condition\r
+******************************************************/\r
+\r
+static void check_loop(U32 stack[])\r
+{\r
+       expect(SEMI);\r
+       if(loop_ptr)\r
+               exit_flag = stack[loop_ptr-1];\r
+       else\r
+               line_error("No active loop");\r
+}\r
+\r
+/****************************************************\r
+* Check that a switch is active & allocate label\r
+*****************************************************/\r
+\r
+static U32 check_switch(void)\r
+{\r
+       if(!sdefault)\r
+               line_error("No active switch");\r
+       gen_label(++next_lab);\r
+       return next_lab;\r
+}\r
+\r
+/*******************************************************************\r
+* Compile a jump only if last statement compiled was not an "exit"\r
+* statement ("return", "break", or "continue"). This prevents the\r
+* generation of an unaccessable jump following these statements.\r
+********************************************************************/\r
+\r
+static void test_jump(U32 label)\r
+{\r
+       if(test_exit())\r
+               jump(label, -1);\r
+}\r
+\r
+\r
+/********************************************\r
+* Compile a conditional jump and\r
+* set up 'Z' flag if necessary.\r
+*********************************************/\r
+\r
+static void cond_jump(char cond, U32 label, char ljmp)\r
+{\r
+       if(zero_flag)\r
+       {\r
+               out_inst("AND EAX,EAX");\r
+               zero_flag = 0;\r
+       }\r
+\r
+       jump_if(cond ^ not_flag, label, ljmp);\r
+       not_flag = 0;\r
+}\r
+\r
+\r
+/**********************************************************\r
+* Get a number in a number base for a maximum # of digits\r
+* (digits = 0 means no limit)\r
+***********************************************************/\r
+\r
+static U32 get_number(U32 base, U32 digits)\r
+{\r
+       U32 value;\r
+       char c;\r
+\r
+       value = 0;\r
+       do {\r
+               if(is_digit(c = *input_ptr))            /* 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
+                       break;\r
+               value = (value * base) + c;             /* include in total */\r
+               ++input_ptr; }\r
+       while(--digits);                                        /* enforce maximum digits */\r
+       return value;\r
+}\r
+\r
+\r
+/*****************************************************************\r
+* End of file has been encountered, dump the literal pool, and\r
+* generate definitions for any external or uninitialized global\r
+* variables.\r
+******************************************************************/\r
+\r
+static void clean_up(void)\r
+{\r
+       U32 type, size, i, j;\r
+\r
+       if(in_function)\r
+               fatal_error("Unterminated function");\r
+\r
+/* Generate all externals referenced from CSEG if NOT for DASM */\r
+\r
+       for(sptr = 0; sptr < global_top; ++sptr)\r
+       {\r
+               if((type = symtab[sptr].type) & (EXTERNAL))\r
+                       if (type & REFERENCE)\r
+                               gen_ext_data_DASM(sptr);\r
+       }\r
+\r
+/* dump literal pool */\r
+\r
+       gen_literal(literal_pool, literal_top);\r
+\r
+/* Generate all global variables that are not initialized */\r
+\r
+       for(sptr = 0; sptr < global_top; ++sptr) {\r
+               type = symtab[sptr].type;\r
+               if(!(type & (FUNCTION | INITED | EXTERNAL | TYPDEF))) {\r
+\r
+                       if (type & (POINTER | DWORD)) size = 4;\r
+                       else if (type & WORD)  size = 2;\r
+                       else if (type & BYTE)  size = 1;\r
+                       else if (type & STRUCT) {\r
+                         size = symtab[sptr].strucoff;         /* contains size */\r
+                         }\r
+                       else size = 1;  /* should be an error maybe?? */\r
+\r
+                       if(type & ARRAY) {                              /* calculate size of array */\r
+                               i = symtab[sptr].dindex;    /* i = index to dimpool */\r
+                               j = dim_pool[i++];                      /* j = nDims */\r
+                               while(j--) size *= dim_pool[i++];\r
+                               }\r
+                       gen_global(sptr, size);\r
+               }\r
+       }\r
+\r
+    if (pd)\r
+    {\r
+               fwrite(databuf, pd, 1, asm_fh);\r
+               pd = 0;\r
+       }\r
+\r
+       if (!error_count)\r
+       {  /* No optimize if errors */\r
+\r
+               if (fNoOpt) {\r
+\r
+                               while (fgetcode(buffer, LINE_MAX))\r
+                               {\r
+                                       if (fGen)\r
+                                               fputs(buffer, code_fh);\r
+                                       else\r
+                                               fputs(buffer, asm_fh);\r
+                               }\r
+               }\r
+               else {\r
+                       optimize();\r
+               }\r
+       }\r
+       fclose(asm_fh);\r
+       if (fLISTOpen)\r
+               fclose(list_fh);\r
+       if (fCODEOpen)\r
+               fclose(code_fh);\r
+\r
+       if(!fQuiet) {\r
+               put_num(error_count, stdout);\r
+               fputs(" errors\r\n", stdout);\r
+               put_num(warn_count, stdout);\r
+               fputs(" warnings\r\n", stdout);\r
+               }\r
+\r
+       exit(0);  /* We are done ! */\r
+}\r
+\r
+\r
+/*****************************************\r
+* Read a character from the input file\r
+******************************************/\r
+\r
+static char read_char(void)\r
+{\r
+       char c;\r
+\r
+       while(!(c = *input_ptr++)) {            /* end of this line */\r
+               if (!readline()) {\r
+                       clean_up();\r
+                       exit(error_count);\r
+               }\r
+       }\r
+       return c;\r
+}\r
+\r
+/***********************************************************\r
+* Allow a single token to be returned to the input stream\r
+************************************************************/\r
+\r
+static void unget_token(U32 token)\r
+{\r
+       ungot_token = token;\r
+}\r
+\r
+\r
+/************************************************\r
+* Read special character (with translations)\r
+*************************************************/\r
+\r
+static U32 read_special(char delim)\r
+{\r
+       S32 c;\r
+\r
+       if((c = read_char()) == delim)\r
+               return 0xff00;\r
+       if(c == '\\')\r
+         switch(c = read_char()) {\r
+               case 'n':                               /* newline */\r
+                       c = 0x0a;\r
+                       break;\r
+               case 'r':                               /* return */\r
+                       c = 0x0d;\r
+                       break;\r
+               case 't':                               /* tab */\r
+                       c = 0x09;\r
+                       break;\r
+               case 'f' :                              /* formfeed */\r
+                       c = 0x0c;\r
+                       break;\r
+               case 'b':                               /* backspace */\r
+                       c = 0x08;\r
+                       break;\r
+               case 'v':                               /* vertical tab */\r
+                       c = 0x0b;\r
+                       break;\r
+               case 'x' :                              /* hex value */\r
+                       c = get_number(16, 2);\r
+                       break;\r
+               default:\r
+                       if(is_digit(c)) {               /* octal value */\r
+                               --input_ptr;\r
+                               c = get_number(8, 3);\r
+           }\r
+       }\r
+       return c & 0xff;\r
+}\r
+\r
+/*************************************************************************\r
+* Get a token from the input stream, and return it as a simple value\r
+* (indicating type). If it a special token type (NUMBER, STRING, SYMBOL),\r
+* global variables "gvalue" and "gst" are set to appriopriate values.\r
+**************************************************************************/\r
+\r
+static U32 get_token(void)\r
+{\r
+       U32 i;\r
+       char *ptr, *last_pos, chr;\r
+\r
+/* if a token has been ungot, re-get it */\r
+/* (gvalue & gst) will not have changed */\r
+       if(ungot_token) {\r
+               i = ungot_token;\r
+               ungot_token = 0;\r
+               return i;\r
+       }\r
+\r
+/* skip any leading whilespace  */\r
+       do {\r
+        chr = read_char();\r
+               }\r
+       while((chr == ' ') || (chr == '\t') ||\r
+               (chr == '\n') || (chr == '\r'));\r
+\r
+       --input_ptr;\r
+\r
+\r
+/* lookup token in token table */\r
+       last_pos = input_ptr;                           /* remember where we were */\r
+\r
+       if (itoken[*input_ptr] != 0) {\r
+               /* start at first match char */\r
+               for(i=itoken[*input_ptr]; ptr = tokens[i]; ++i) {\r
+                       if (*input_ptr != *ptr) break;\r
+                       while((chr = *input_ptr) && (*ptr == chr)) {\r
+                               ++ptr;\r
+                               ++input_ptr; }\r
+                       if(!*ptr) {                                             /* we found a token */\r
+                               if(is_alpha(*(ptr-1)) && is_alpha(*input_ptr))\r
+                                       continue;                                       /* not this token */\r
+                               return i; }\r
+                       input_ptr = last_pos;                   /* reset pointer */\r
+               }\r
+       }\r
+/* we didn't find a token, check out special cases */\r
+       input_ptr = last_pos;\r
+\r
+       if((chr = *input_ptr) == '"')   {       /* string value */\r
+               ++input_ptr;\r
+               gvalue = literal_top;           /* set to index to string */\r
+               do {\r
+                       if(literal_top >= LITER_BUFF)\r
+                               fatal_error("String space exausted");\r
+                       literal_pool[literal_top++] = i = read_special('"');\r
+               }\r
+               while(!(i & 0xff00));   /* 0xff00 returned from read_special */\r
+               return STRING; }\r
+\r
+       /* Quoted values (e.g., '\n') are read into gvalue.\r
+          ANSI says that multibyte character constants are\r
+          implementation dependent.  SOOO, In our case we\r
+          shift multiple bytes to the left.  '\n\r' will\r
+          make gvalue equal 0x0D0A even though the \n (0x0A) is\r
+          first.\r
+        */\r
+\r
+       if(chr == 0x27)\r
+       {                                       /* quoted value */\r
+               ++input_ptr;\r
+               while( !((i = read_special(0x27)) & 0xff00) )\r
+                       gvalue =  i & 0xff;     /* strip notify bits */\r
+               return NUMBER;\r
+       }\r
+\r
+\r
+       if(is_digit(chr)) {                                     /* numeric constant */\r
+               if(chr == '0') {\r
+                       ++input_ptr;\r
+                       if((*input_ptr == 'x') || (*input_ptr == 'X')) {\r
+                               ++input_ptr;\r
+                               gvalue = get_number(16, 0);                     /* hex */\r
+                       }\r
+                       else\r
+                               gvalue = get_number(8, 0);              /* octal */\r
+               }\r
+               else gvalue = get_number(10, 0);                        /* decimal */\r
+\r
+               /* Look for Unsigned and Long terminal characters */\r
+\r
+               if((*input_ptr == 'U') || (*input_ptr == 'u')) {\r
+                       ++input_ptr;\r
+                       if((*input_ptr == 'L') || (*input_ptr == 'l')) ++input_ptr;\r
+               }\r
+               else if((*input_ptr == 'L') || (*input_ptr == 'l')) ++input_ptr;\r
+\r
+               return NUMBER;\r
+       }\r
+\r
+       if(is_alpha(chr)) {                                     /* symbol name */\r
+               gvalue = 0;\r
+               while(is_alnum(chr = *input_ptr)) {\r
+                       if(gvalue < SYMBOL_SIZE)\r
+                               gst[gvalue++] = chr;\r
+                       ++input_ptr; }\r
+               gst[gvalue] = 0;\r
+               namesize = gvalue;\r
+               return SYMBOL; }\r
+\r
+/* not a token or special value */\r
+       ++input_ptr;                    /* skip offending character */\r
+       return -1;                              /* report "unknown" token type */\r
+}\r
+\r
+\r
+/*****************************************************\r
+* Locate a symbol in the local symbol table\r
+******************************************************/\r
+\r
+static U32 lookup_local(void)\r
+{\r
+       U16 i,j;\r
+\r
+       i = MAX_SYMBOLS-1;\r
+       while(i > local_top-1) {\r
+               j = symtab[i].oname;\r
+               if(equal_string(gst, &LPool[j]))\r
+                       return symtab[sptr=i].type |= REFERENCE;\r
+           i--;\r
+    }\r
+       return 0;\r
+}\r
+\r
+\r
+/*************************************************\r
+  Locate a symbol in the global symbol table.\r
+**************************************************/\r
+\r
+static U32 lookup_global(void)\r
+{\r
+       U16 i, j;\r
+\r
+       for(i=0; i < global_top; i++) {\r
+               j = symtab[i].oname;\r
+               if(equal_string(gst, &GPool[j]))\r
+                       return symtab[sptr=i].type |= REFERENCE;\r
+       }\r
+       return 0;\r
+}\r
+\r
+/**************************************************\r
+  Locate a structure member in either symbol table\r
+***************************************************/\r
+\r
+static U32 lookup_member(U32 CrntStruc)\r
+{\r
+       U16 i, j, CrntStrucDef;\r
+\r
+       /* structure member names were hidden in the tables\r
+          by inserting a '0' as the first char.  Now we\r
+          must make the current symbol name match\r
+          so we can find it in the tables.  It will follow\r
+          the structure definition entry for CrntStruc.\r
+       */\r
+\r
+       for (i=SYMBOL_SIZE; i > 0; i--)         /* fix member name  */\r
+           gst[i] = gst[i-1];\r
+     gst[0] = '0';                                     /* make it start with digit */\r
+     ++namesize;\r
+\r
+       CrntStrucDef = symtab[CrntStruc].itypedef;\r
+\r
+       if (symtab[CrntStrucDef].type & GLOBAL) {\r
+\r
+               for(i=CrntStrucDef+1; i < global_top; i++) {\r
+                       if (!(symtab[i].type & STRUCMEM))\r
+                               break;\r
+                       j = symtab[i].oname;\r
+                       if(equal_string(gst, &GPool[j]))\r
+                               return symtab[sptr=i].type |= REFERENCE;\r
+               }\r
+       }\r
+       else {  /* must be local */\r
+\r
+               for(i=CrntStrucDef-1; i > local_top-1; i--) {\r
+                       if (!(symtab[i].type & STRUCMEM))\r
+                               break;\r
+                       j = symtab[i].oname;\r
+                       if(equal_string(gst, &LPool[j]))\r
+                               return symtab[sptr=i].type |= REFERENCE;\r
+               }\r
+       }\r
+       return 0;               /* didn't find it! */\r
+}\r
+\r
+/***************************************************************\r
+  Enter a symbol in the symbol table with specified name & type.\r
+  Leaves global sptr with the index of the symbol just added.\r
+****************************************************************/\r
+\r
+static void define_symbol(U32 type, U32 dim_index)\r
+{\r
+       U32 index;\r
+       U16 j;\r
+\r
+       if(in_function) {               /* within a function, use local */\r
+               if (type&PROTO) {       /* give it a false name to satisfy symbol table */\r
+                       gst[0] = '_';                           /* 2 underscores */\r
+                       gst[1] = '-';\r
+                       gst[2] = arg_count + 65;        /* A-Z */\r
+                       gst[3] = '\0';                                  /* null terminate */\r
+                       namesize = 3;\r
+                       }\r
+               else {\r
+                       if(lookup_local()) {\r
+                               symbol_error("Duplicate local or arg");\r
+                               return;\r
+                               }\r
+                       }\r
+\r
+               sptr = --local_top;\r
+               if(type & ARGUMENT) {\r
+\r
+                       type &= ~PROTO;  /* turn off proto warning */\r
+\r
+                       /* if a prototype arg already exists, make sure it's the same */\r
+                       if (icrntpro) {\r
+                               if (proto_list[icrntpro++] != type) {\r
+                                 j=symtab[fptr].oname;\r
+                             t_warn("Arg not same type as prototype in ", &GPool[j]);\r
+                               }\r
+                       }\r
+                       else proto_list[iproto_next++] = type;\r
+                       if(iproto_next>MAX_PROTOS)\r
+                         fatal_error("Prototype table full");\r
+               }\r
+               else\r
+                       index = local_stack;\r
+\r
+               if(global_top > local_top)\r
+                       fatal_error("Symbol table full");\r
+               if((oNextLName+SYMBOL_SIZE) > LBUFFSIZE)\r
+                       fatal_error("Local symbol name pool full");\r
+               symtab[sptr].oname=oNextLName;\r
+               copystring(&LPool[oNextLName], gst);\r
+               oNextLName += namesize;\r
+               oNextLName++;                           /* for null */\r
+               symtab[sptr].type = type;\r
+               symtab[sptr].argoffset = index;\r
+               symtab[sptr].dindex = dim_index;\r
+\r
+       }\r
+       else {                                  /* outside of function, use global */\r
+               type |= GLOBAL;\r
+               if(index = lookup_global()) {           /* symbol already exists */\r
+                       if(index & (PROTO|FUNCTION)) {  /* re-definition */\r
+                               if((index | (INITED|REFERENCE|EXTERNAL|PROTO)) !=\r
+                                       (type | (INITED|REFERENCE|EXTERNAL|PROTO)))\r
+                                       symbol_error("Inconsistant re-declaration");\r
+                               symtab[sptr].type = type;\r
+                               return;\r
+                       }\r
+                       else if (type & STRUCMEM)\r
+                                {}             /* no error */\r
+                       else if ((type & STRUCDEF) &&\r
+                                        (equal_string(&structname[0], &GPool[symtab[sptr].oname])))\r
+                                {}             /* no error */\r
+                       else {\r
+                               symbol_error("Duplicate global");\r
+                               return; }\r
+               }\r
+               sptr = global_top++;\r
+               index = global_count++;\r
+               if(global_top > local_top)\r
+                       fatal_error("Symbol table full");\r
+               if((oNextGName+SYMBOL_SIZE) > GBUFFSIZE)\r
+                       fatal_error("Global symbol name pool full");\r
+               symtab[sptr].oname = oNextGName;\r
+               copystring(&GPool[oNextGName], gst);\r
+               oNextGName += namesize;\r
+               oNextGName++;                    /* for null */\r
+               symtab[sptr].type = type;\r
+               symtab[sptr].argoffset = index;\r
+               symtab[sptr].dindex = dim_index;\r
+       }\r
+}\r
+\r
+\r
+/******************************************\r
+* Push a value on the expression stack\r
+*******************************************/\r
+\r
+static void push(U32 token, U32 value, U32 type, U32 offset)\r
+{\r
+       if(expr_ptr >= EXPR_DEPTH)\r
+               fatal_error("Expression stack overflow");\r
+\r
+       expstk[expr_ptr].token = token;\r
+       expstk[expr_ptr].value = value;\r
+       expstk[expr_ptr].type  = type;\r
+       expstk[expr_ptr].offset = offset;\r
+       expr_ptr++;\r
+}\r
+\r
+/*********************************************\r
+* Pop a value from the expression stack\r
+**********************************************/\r
+\r
+static void pop(U32 *token, U32 *value, U32 *type, U32 *offset)\r
+{\r
+       if(!expr_ptr)\r
+               fatal_error("Expression stack underflow");\r
+\r
+    expr_ptr--;\r
+       *token  = expstk[expr_ptr].token;\r
+       *value  = expstk[expr_ptr].value;\r
+       *type   = expstk[expr_ptr].type;\r
+       *offset = expstk[expr_ptr].offset;\r
+}\r
+\r
+\r
+/********************************************\r
+* Get a constant value (NUMBER or STRING)\r
+* which can be evaluated at compile time.\r
+*********************************************/\r
+\r
+static void get_constant(U32 *token, U32 *value)\r
+{\r
+       U32 type, offset;\r
+\r
+       expr_ptr = 0;\r
+       unget_token(do_oper(SEMI));             /* do_oper gets the token... */\r
+\r
+       pop(token, value, &type, &offset);      /* then we pop it into token */\r
+\r
+       if((*token != NUMBER) && (*token != STRING))\r
+               line_error("Constant expression required");\r
+}\r
+\r
+/********************************\r
+* Define a variable\r
+*********************************/\r
+\r
+static void define_var(U32 type)\r
+{\r
+       U32 token, stype, lasttoken, value, index, size, i, j, ocbcnt;\r
+       U32 sDim1, nDims, iDim, eTotal;\r
+       char eflag, nflag;\r
+\r
+       if(in_function > 1)\r
+               line_error("Declaration must preceed code");\r
+\r
+/* calculate base variable size - store in j for later use if array */\r
+\r
+       if (type&BYTE) size = 1;\r
+       else if (type&WORD)  size = 2;\r
+       else if (type&DWORD) size = 4;\r
+       else if (type&STRUCT)\r
+               size = symtab[CrntStrucDef].strucoff;\r
+       else\r
+               line_error("Type specifier missing");\r
+\r
+       if (type&(ARGUMENT | POINTER))  size = 4; /* pointers are 32 bit offsets */\r
+       j = size;\r
+\r
+/* If fInStruct then this is a structure member definition.\r
+   NOT a structure member! */\r
+\r
+       if (fInStruct) {\r
+               type |= (STRUCMEM|TYPDEF);                      /* make it a member definition */\r
+               for (i=SYMBOL_SIZE; i > 0; i--)         /* fix member name  */\r
+            gst[i] = gst[i-1];\r
+        gst[0] = '0';                                  /* make it start with digit */\r
+        ++namesize;\r
+        }\r
+\r
+/* evaluate any array indexes */\r
+\r
+       iDim = dim_top;\r
+       nflag = 0;\r
+       nDims = 0;\r
+       while(test_token(OSB)) {                        /* array definition */\r
+               ++nDims;\r
+               ++dim_top;\r
+               if(test_token(CSB)) {           /* null definition */\r
+                       if ((nflag) || (nDims > 1))\r
+                               line_error("Null only allowed in first index");\r
+                       --nflag;\r
+                       size *= dim_pool[dim_top] = 1;  /* dummy up unbounded array */\r
+                       continue; }\r
+               get_constant(&token, &value);\r
+               if(token != NUMBER)\r
+                       line_error("Numeric constant required");\r
+               size *= dim_pool[dim_top] = value;\r
+               expect(CSB);\r
+       }\r
+\r
+       if(nDims) {                     /* defining an array */\r
+               type |= ARRAY;\r
+               dim_pool[iDim] = nDims;\r
+               if(++dim_top > DIM_SIZE)\r
+                       fatal_error("Dimension table full");\r
+       }\r
+\r
+       if(test_token(ASSIGN))          /* initialized variable */\r
+               type |= INITED;\r
+\r
+       local_stack += size;            /* Keep track of offset of local vars */\r
+\r
+       define_symbol(type, iDim);      /* Create the symbol table entry */\r
+\r
+       if (type&(STRUCMEM|TYPDEF)) {\r
+               symtab[sptr].itypedef = CrntStrucDef;\r
+               symtab[sptr].strucoff = symtab[CrntStrucDef].strucoff;\r
+           symtab[CrntStrucDef].strucoff += size;      /* add to the total */\r
+               }\r
+\r
+       if (type&(STRUCT)) {\r
+               symtab[sptr].itypedef = CrntStrucDef;\r
+               symtab[sptr].strucoff = symtab[CrntStrucDef].strucoff;\r
+               }\r
+\r
+/*\r
+   Initialization of arrays has changed with ANSI. Nested braces and\r
+   trailing commas are now allowed. We make sure the braces balance.\r
+*/\r
+       eflag = -1;             /* Expexting initializer */\r
+       sDim1 = 0;              /* tracks nDimensions for unbounded arrays [] */\r
+       eTotal = 0;             /* Total elements initialized so far */\r
+\r
+       if(type & INITED) {             /* force immediate allocation */\r
+               if ((in_function) || (fInStruct))\r
+                       line_error("Illegal initialization");\r
+               data_global(sptr);      /* generate label in DSeg */\r
+               ocbcnt = 0;     /* number of open brackets */\r
+               index = 0;              /* tracks index for current dimensions */\r
+               do {\r
+                       switch (token=get_token()) {\r
+                       case OCB:\r
+                               if ((nflag) && (ocbcnt == 1))   /* count for unbounded */\r
+                                       ++sDim1;\r
+                               ocbcnt++;\r
+                               if (ocbcnt > nDims)\r
+                                       line_error("Too many open braces");\r
+                               lasttoken = OCB;\r
+                               eflag = -1;\r
+                               break;\r
+                       case CCB:\r
+                               if (ocbcnt) --ocbcnt;\r
+                               else\r
+                                       line_error("Unbalanced braces");\r
+                               if ((nDims > 1) && (ocbcnt))  {\r
+                                       while (index < dim_pool[dim_top-1]) {\r
+                                               init_static(NUMBER, 0, j);\r
+                                               ++index;\r
+                                               }\r
+                                       }\r
+                               eTotal+=index;          /* total inited so far */\r
+                               index = 0;                      /* tracks index for current dimensions */\r
+                               eflag = 0;                      /* no constant expected now! */\r
+                               lasttoken = CCB;\r
+                               break;                          /* we need a comma first/ocb first */\r
+                       case COMMA:\r
+                               /* secial case of char[x][y] = {"abc","def","ghi"}; */\r
+                               if ((nDims > 1) && (ocbcnt==1) &&\r
+                                   (lasttoken==STRING) && !(type & POINTER)) {\r
+                                       while (index < dim_pool[dim_top-1]) {\r
+                                               init_static(NUMBER, 0, j);\r
+                                               ++index;\r
+                                               }\r
+                                       eTotal+=index;          /* total inited so far */\r
+                                       index = 0;\r
+                                       }\r
+                               if (lasttoken==CCB) eflag = 0;\r
+                               else eflag = -1;\r
+                               lasttoken = COMMA;\r
+                               break;\r
+                       case STRING:\r
+                               /* special case of char[x] = "xx"; or char[] = "xx";  */\r
+                               if ((!ocbcnt) && (nDims==1))\r
+                                       eflag = -1;\r
+                       case NUMBER:\r
+                       case SUB:\r
+                       case COM:\r
+                       case NOT:\r
+                               unget_token(token);             /* put it back */\r
+                               if (eflag) {                    /* we are expecting a constant */\r
+                                       if ((nflag) && (ocbcnt == 1))\r
+                                               ++sDim1;\r
+                                       get_constant(&token, &value);\r
+                                       if((token == STRING) && !(type & POINTER)) {\r
+                                               do {\r
+                                                       init_static(NUMBER, literal_pool[value], j);\r
+                                                       ++index;}\r
+                                               while(++value < literal_top);\r
+                                               literal_top = gvalue;\r
+\r
+                                               /* special case of char[]="xx" or char[x]="xx";  */\r
+                                               if ((!ocbcnt) && (nDims==1)) {\r
+                                                       eTotal = index;\r
+                                                       sDim1 = index;\r
+                                                       }\r
+                                               }\r
+                                       else {\r
+                                               init_static(token, value, j);\r
+                                               if (!nDims)\r
+                                                       ++eTotal;       /* tracked by index if array */\r
+                                               ++index;\r
+                                               }\r
+                                       lasttoken=token;\r
+                                       }\r
+                               else line_error("Improper bracketed initialization");\r
+                               break;\r
+                       case SYMBOL:\r
+                               lasttoken=token;\r
+                               if (eflag) {    /* we are expecting an initializer */\r
+                                       if (type&POINTER) {\r
+                                               if(stype=lookup_global()) {\r
+                                                       if (stype&(EXTERNAL|FUNCTION))\r
+                                                               symbol_error("Invalid init type");\r
+                                                       else {\r
+                                                               init_static(SYMBOL, sptr, j);\r
+                                                               index += j;\r
+                                                               }\r
+                                                       }\r
+                                               else symbol_error("Undefined");\r
+                                               }\r
+                                       else line_error("Must be pointer array");\r
+                                       }\r
+                               else line_error("Improper bracketed initialization");\r
+                               break;\r
+                       default:\r
+                               line_error("Improper symbol in initialization");\r
+                               break;\r
+                       }\r
+               }\r
+               while(((ocbcnt) || (lasttoken==COMMA)) && (token!=SEMI));\r
+               if(ocbcnt) expect(CCB);         /* make sure brackets balance!! */\r
+\r
+               if(nflag)                               /* fixup null definition */\r
+                       dim_pool[iDim+1] = sDim1;\r
+\r
+               /* new we make sure all the array elements were initialized\r
+                  to ensure we have allocated Dseg for them.\r
+               */\r
+\r
+               i=1;\r
+               while (nDims) i*= dim_pool[iDim+nDims--];       /* i has total elements */\r
+\r
+               while (eTotal < i) {            /* eTotal is total inited */\r
+                       init_static(NUMBER, 0, j);\r
+                       ++eTotal;\r
+               }\r
+\r
+               if (eTotal > i)\r
+                       line_error("Too many initial values");\r
+\r
+               end_static();\r
+\r
+       }  /* if (INITED) */\r
+\r
+}\r
+\r
+/*****************************************************\r
+* Check that we are within a function definition\r
+******************************************************/\r
+\r
+static void check_func(void)\r
+{\r
+       if(in_function) {\r
+               if(in_function < 2) {           /* first invocation */\r
+                       in_function = 2;\r
+                       enter_func(fptr, local_stack); } }\r
+       else\r
+               line_error("Incorrect declaration");\r
+}\r
+\r
+/**********************************************************\r
+* Declare a symbol (function or variable) with modifiers.\r
+  If we get here we have found a legal type specifier.\r
+  Definitions other than structures are quite simple. We\r
+  loop through eating the variables behind it adding them\r
+  to the symbol table.\r
+  Structures are handled differently because you can define\r
+  a structure with a TAG without actually allocating space.\r
+  This is actually a type definition.\r
+  In fact, you can define the structure with an optional\r
+  tag, then place the variable names right behind it.\r
+  This checks to see if we have a tag name first. If the tag\r
+  name is present, we then check to see if it's a defined\r
+  structure already, in which case we expect a new symbol\r
+  name will follow. If the tag is not already defined than\r
+  we expect {} with a structure definition in between!\r
+***********************************************************/\r
+\r
+static void declare(U32 token, U32 type)\r
+{\r
+    fInStruct = 0;\r
+       for(;;) {\r
+               switch(token) {\r
+                       case CHAR:\r
+                               type &= ~WORD;          /* cancel WORD */\r
+                               type |= BYTE;\r
+                               break;\r
+                       case INT:\r
+                               if (!(type&DWORD)) type |= WORD;\r
+                               break;\r
+                       case SHORT:\r
+                               type |= WORD;\r
+                               break;\r
+                       case LONG:\r
+                               type &= ~WORD;          /* cancel WORD */\r
+                               type |= DWORD;\r
+                               break;\r
+                       case UNSIGN:\r
+                               type |= WORD;           /* cancelled for char or long */\r
+                               type |= UNSIGNED;\r
+                               break;\r
+                       case SIGNED:\r
+                               type |= WORD;           /* this will be cancelled if it's long */\r
+                               type &= ~UNSIGNED;\r
+                               break;\r
+                       case STAT:\r
+                               type |= STATIC;\r
+                               break;\r
+                       case STRUC:\r
+                               type |= STRUCDEF;\r
+                               break;\r
+                       case CONST:\r
+                               type |= CONSTANT;\r
+                               break;\r
+                       case EXTERN:\r
+                               type |= EXTERNAL;\r
+                               break;\r
+                       case REGIS:\r
+                               type |= REGISTER;\r
+                               break;\r
+                       case INTR:\r
+                               type |= ISR;    /* ISR modified for functions */\r
+                               break;\r
+                       case VOIDD:\r
+                               type |= VOID;\r
+                               break;\r
+                       case FARR:\r
+                               type |= FAR;\r
+                               break;\r
+                       case STAR:              /* pointer reference */\r
+                               do\r
+                                       ++type;\r
+                               while(test_token(STAR));\r
+\r
+                               /* allow for prototype arg pointers with no symbol name */\r
+\r
+                               if((type&ARGUMENT) && (test_token(COMMA))) {\r
+                                       define_var(type|=PROTO); /* tell 'em it may be symboless */\r
+                                       return;\r
+                                       }\r
+                               else\r
+                               if(!test_token(SYMBOL)) syntax_error();\r
+                       case SYMBOL:            /* we have a symbol name */\r
+                               /* If STRUCDEF, MUST be a Struct Tag Name (new or existing) */\r
+                               if(type & STRUCDEF) {      /* This symbol follows "struct" */\r
+                                       if (lookup_global()) {   /* Existing tag ?? */\r
+                                               if (symtab[sptr].type & STRUCDEF) {\r
+                                   CrntStrucDef = sptr;  /* tag we just found */\r
+                                                       /* might be a pointer to a structure */\r
+                                                       if (test_token(STAR))\r
+                                                               do\r
+                                                                       ++type;\r
+                                                               while(test_token(STAR));\r
+                                                       /* now expect a new structure variable name */\r
+                                                       if(!test_token(SYMBOL)) {\r
+                                                         line_error("struct variable expected");\r
+                                                         return;\r
+                                                       }\r
+                                                       else {\r
+                                                         type &= ~STRUCDEF; /* struct variable w/tag */\r
+                                                         type |= STRUCT;\r
+                                                       }\r
+                                               }\r
+                                               else\r
+                                                 line_error("struct tag name expected");\r
+                                       }\r
+\r
+                                       /* we didn't find the tag so it must be a new one! */\r
+\r
+                                       else {     /* So add the strucdef */\r
+                                               define_symbol(type|TYPDEF, 0);\r
+                           CrntStrucDef = sptr;        /* symbol we just found */\r
+                                               if(!(test_token(OCB)))   /* expecting {          */\r
+                                                 line_error("Structure { expected");\r
+                                               else {\r
+                                               fInStruct = 1;            /* we are in it now...  */\r
+                                               type = 0;\r
+                                               break;\r
+                                               }\r
+                                       }\r
+                               }\r
+                               if(type&ARGUMENT) {\r
+                                       define_var(type);\r
+                                       return;\r
+                                       }\r
+                               if(test_token(ORB))\r
+                                       define_func(type);      /* function definition */\r
+                               else\r
+                                       define_var(type);       /* variable definition */\r
+                               if(test_token(COMMA))\r
+                                       break;\r
+\r
+                               test_token(SEMI);  /* eat the semicolon if there */\r
+\r
+                               if (fInStruct) {        /* still defining struct members */\r
+                                       type = 0;\r
+                                       break;\r
+                                       }\r
+                               else\r
+                                       return;\r
+                       case OCB:               /* '{' only allowed for immediate struct defs */\r
+                               if(type & STRUCDEF) {    /* Immediate struct definition */\r
+                                       copystring(gst, structname);\r
+                                       gvalue = 11;\r
+                                       define_symbol(type|TYPDEF, 0);\r
+                    CrntStrucDef = sptr;  /* symbol we just added */\r
+                               fInStruct = 1;            /* we are in it now...  */\r
+                               type = 0;\r
+                                       break;\r
+                                       }\r
+                               else\r
+                                       syntax_error();\r
+                               break;\r
+                       case CCB:\r
+                               if (!fInStruct) {\r
+                                       syntax_error();\r
+                                       return;\r
+                                       }\r
+                               else {\r
+                                   type &= ~STRUCDEF; /* struct variable */\r
+                                   type |= STRUCT;\r
+                                       fInStruct = 0;\r
+                                       }\r
+                               if (test_token(SEMI))  /* if semicolon, eat it and return */\r
+                                       return;\r
+                               break;\r
+                       case CRB:\r
+                               unget_token(token);             /* fall thru to COMMA */\r
+                       case COMMA:\r
+                               if(type&ARGUMENT) {\r
+                                       define_var(type|=PROTO);\r
+                                       return;\r
+                                       }\r
+                               break;\r
+                       default:\r
+                               syntax_error();\r
+\r
+                }\r
+               type &= ~(POINTER | ARRAY);  /* clear indirection and rg of last var */\r
+               token = get_token();\r
+       }\r
+}\r
+\r
+/**************************************************************\r
+Define a function\r
+\r
+Notes on prototype handling:\r
+\r
+We have an array called proto_list and an index to the list called\r
+iproto_next. For any function (external or global), we keep track\r
+of the argument types in the proto list.  We do this by assuming that the\r
+first time a function is identified, we define it as if it was a real\r
+function.  If it turns out to be a proto, we just throw away the\r
+local arguments and mark it as proto.  If we find a function that is\r
+being defined and it's args don't match the defined types, emit a warning\r
+or error (if type is not convertable).\r
+In any case, this means we now know what type of argument\r
+to expect for any function that is called. We can do the proper\r
+type manipulations and flag errors when found.\r
+This also means you must prototype all external function, and\r
+that all of them MUST have all arguments defined!!!\r
+As per ANSI - the proto MUST contain the type of each arg, and\r
+may or may not provide a name for each arg.\r
+\r
+For functions that are defined with variable parameter lists (unknown\r
+numbers of args and type), we add a single identifier in the Proto list\r
+that indicates this.  The arg definition for variable parameters is\r
+an elipse (...).\r
+All args in a function with variable args are accessed differently than\r
+those with fixed parameters.  Normally the EBP register accesses the\r
+args with a fixed offset.  When you have variable args (and becuase we\r
+push args from left to right) we won't know where the fixed args are or\r
+where the variable args begin.  To find out where they are and access them\r
+we push the number of variable args as the last arg on the stack.\r
+From this value we can determine where the variable args begin and the fixed\r
+args leave off.  We access the fixed args with [EBP+EDI+offset]\r
+to access the args.  This is because the fucntion "va_arg" will set\r
+EDI up with the proper context to access the variable required. See\r
+stdarg.c for more information.\r
+\r
+****************************************************************/\r
+\r
+static void define_func(U32 type)\r
+{\r
+       U32 token, dim_save, t, flastarg, i, stackpop;\r
+\r
+       icrntpro = 0;\r
+       flastarg = 0;\r
+       arg_count = 0;\r
+       oNextLName = 0;\r
+\r
+       /* do not allow functions or protos within functions */\r
+\r
+       if(in_function) {\r
+               line_error("Illegally nested function or prototype");\r
+               return;\r
+       }\r
+\r
+       if(t = lookup_global()) {               /* symbol already exists */\r
+               if (t & PROTO) {\r
+                       icrntpro = symtab[sptr].dindex; /* icrntpro points to arg types */\r
+               }\r
+       }\r
+       else {\r
+               define_symbol(type | FUNCTION | GLOBAL, 0);\r
+        symtab[sptr].dindex = iproto_next;\r
+       }\r
+\r
+       fptr = sptr;\r
+\r
+/* accept variable declarations for local arguments */\r
+/* These must be inside the parens -- ANSI style    */\r
+\r
+       local_top = MAX_SYMBOLS;\r
+       dim_save = dim_top;\r
+       in_function = 1;                                        /* indicate inside a function */\r
+\r
+       do {\r
+               switch(token = get_token()) {   /* define local arguments */\r
+                       case SHORT:\r
+                       case LONG:\r
+                       case INT:\r
+                       case SIGNED:\r
+                       case UNSIGN:\r
+                       case CHAR:\r
+                       case FAR:\r
+                       case CONST:\r
+                       case STRUC:\r
+                               declare(token, ARGUMENT);\r
+                               arg_count += 1;\r
+                               break;\r
+                       case COMMA: break;\r
+                       case ELIPSE:\r
+                               proto_list[iproto_next++] = VOID;\r
+                               flastarg = -1;\r
+                               symtab[fptr].type |= VARARGS;\r
+                               break;\r
+                       case VOIDD:\r
+                               if (arg_count) syntax_error();  /* fall through to default */\r
+                       default:\r
+                               if (!flastarg) {\r
+                                       proto_list[iproto_next++] = VOID;\r
+                                       if(iproto_next>MAX_PROTOS)\r
+                                         fatal_error("Prototype table full");\r
+                                       flastarg = -1;\r
+                               if (token==CRB) unget_token(token);\r
+                               }\r
+                               break;\r
+               }\r
+       } while (!flastarg);\r
+\r
+       token = get_token();\r
+       if(token != CRB)\r
+               syntax_error();\r
+\r
+       if(test_token(SEMI)) {          /* a prototype function !! */\r
+               symtab[fptr].type |= PROTO;\r
+               in_function = 0;\r
+               exit_label = 0;\r
+               exit_flag = 0;\r
+               exit_used = 0;\r
+               dim_top = dim_save;\r
+               if (symtab[fptr].type & EXTERNAL)\r
+                       gen_extern_DASM(fptr);\r
+               }\r
+       else {\r
+               symtab[fptr].type &= ~PROTO;\r
+               symtab[fptr].type |= FUNCTION;\r
+               local_stack = 0;\r
+               exit_label = 0;\r
+               exit_flag = 0;\r
+               exit_used = 0;\r
+               stackpop = 0;\r
+\r
+               /* Loop through the args putting in correct stack offsets\r
+               NOTE: For running 32 bit code in a 16 bit environment, the\r
+               value to be added to stackpop is 6 for each item on the stack.\r
+               For a 32 bit environment its 8 for each.\r
+\r
+         +-----+-----+ xx\r
+         |Last param |     The last parameter pushed is here\r
+         +-----+-----+ 06/8/0C\r
+         | n Bytes   |     Return Address (2, 4 or 8)\r
+         +-----+-----+ 04\r
+         | 4 Bytes   |     Previous Frame Pointer\r
+         +-----+-----+ 00\r
+\r
+               The Return Address is either 2, 4 or 8 bytes depending on\r
+               the environment and whether the call was Near or Far.\r
+               16 Bit segments -  n = 2 for Near, 4 for Far\r
+               32 Bit segments -  n = 4 for Near, 8 for Far\r
+\r
+               */\r
+\r
+               for(i=arg_count; i>0; i--) {\r
+                       if (symtab[fptr].type & FAR)\r
+                               symtab[MAX_SYMBOLS-i].argoffset = stackpop+12; /* 12 for 32 far */\r
+                       else\r
+                               symtab[MAX_SYMBOLS-i].argoffset = stackpop+8; /* 8 for MMURTL */\r
+                       stackpop += 4;\r
+               }\r
+               statement(token=get_token());\r
+               check_func();   /* ensure enter gets written in null func */\r
+               if((exit_label) && (exit_used))\r
+                       gen_label(exit_label);\r
+               if (symtab[fptr].type & VARARGS)\r
+                       end_func(0);\r
+               else\r
+                       end_func(stackpop);\r
+               in_function = 0;\r
+               exit_label = 0;\r
+               exit_flag = 0;\r
+               exit_used = 0;\r
+               dim_top = dim_save;\r
+\r
+               /* Error reporting when end of func is reached and certain\r
+                  conditions exist */\r
+\r
+               while(local_top < MAX_SYMBOLS) {\r
+                       if((token = symtab[local_top].type) & EXTERNAL)\r
+                               t_error("Unresolved", &LPool[symtab[local_top].oname]);\r
+                       if(!(token & REFERENCE))\r
+                               t_warn("Unreferenced", &LPool[symtab[local_top].oname]);\r
+                       ++local_top; }\r
+               return;\r
+       }\r
+}\r
+\r
+/***********************************************************************\r
+  Write an assembler string to access an operand value.\r
+  Certain types of operands may require type inducers suxh as "BYTE PTR."\r
+************************************************************************/\r
+static void write_oper(U32 token, U32 value, U32 type, U32 offset)\r
+{\r
+\r
+       switch(token) {\r
+               case INEAX:\r
+                       code_str("EAX");\r
+                       break;\r
+               case NUMBER:\r
+                       code_num(value);\r
+                       break;\r
+               case STRING:\r
+                       code_str("OFFSET ");\r
+                       code_chr(prefix);\r
+                       code_str("_lit+");\r
+                       code_num(value);\r
+                       break;\r
+               case SYMBOL:\r
+                       if(type & GLOBAL) {\r
+                               code_chr('_');          /* prefix with _ */\r
+                               code_str(&GPool[symtab[value].oname]);\r
+                               break; }\r
+                       if(type & ARGUMENT)\r
+                       {\r
+                               if (symtab[fptr].type & VARARGS)\r
+                               {\r
+                                       if (type&(DWORD|POINTER))\r
+                                               code_str("DWORD PTR [EBP+EDI+");\r
+                                       else if (type & WORD)\r
+                                               code_str("WORD PTR [EBP+EDI+");\r
+                                       else\r
+                                               code_str("BYTE PTR [EBP+EDI+");\r
+                                       code_num(symtab[value].argoffset);\r
+                                       code_chr(']');\r
+                               }\r
+                               else\r
+                               {\r
+                                       if (type&(DWORD|POINTER))\r
+                                               code_str("DWORD PTR [EBP+");\r
+                                       else if (type & WORD)\r
+                                               code_str("WORD PTR [EBP+");\r
+                                       else\r
+                                               code_str("BYTE PTR [EBP+");\r
+                                       code_num(symtab[value].argoffset);\r
+                                       code_chr(']');\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               if (type&(DWORD|POINTER))\r
+                                       code_str("DWORD PTR [EBP-");\r
+                               else if (type & WORD)\r
+                                       code_str("WORD PTR [EBP-");\r
+                               else\r
+                                       code_str("BYTE PTR [EBP-");\r
+                               code_num(symtab[value].argoffset);\r
+                               code_chr(']');\r
+                       }\r
+                       break;\r
+               case INECX:\r
+                       code_str("ECX");\r
+                       break;\r
+               case INEDX:\r
+                       code_str("EDX");\r
+                       break;\r
+               case PESI:\r
+               case PEDX:\r
+               case PECX:                      /* pointer in other reg - indirect access */\r
+               case ISTACK_TOP:\r
+                       if (type&(DWORD|POINTER))\r
+                               code_str("DWORD PTR ");\r
+                       else if (type & WORD)\r
+                               code_str("WORD PTR ");\r
+                       else\r
+                               code_str("BYTE PTR ");\r
+\r
+                       if (offset)\r
+                       {\r
+                               if (token==PESI)\r
+                                       code_str("[ESI+");\r
+                               else if (token==PECX)\r
+                                       code_str("[ECX+");\r
+                               else if (token==PEDX)\r
+                                       code_str("[EDX+");\r
+                               else\r
+                                       code_str("[EBX+");\r
+                               code_num(offset);\r
+                               code_chr(']');\r
+                       }\r
+                       else\r
+                       {\r
+                               if (token==PESI)\r
+                                       code_str("[ESI]");\r
+                               else if (token==PEDX)\r
+                                       code_str("[EDX]");\r
+                               else if (token==PECX)\r
+                                       code_str("[ECX]");\r
+                               else\r
+                                       code_str("[EBX]");\r
+                       }\r
+                       break;\r
+               case STACK_TOP:\r
+                       code_str("EBX");\r
+                       break;\r
+\r
+               case ION_STACK:         /* shouldn't happen */\r
+               case ON_STACK:\r
+               default:                /* Unknown (error) */\r
+                       code_num(token);\r
+                       code_str(" ERROR in write_oper\n");\r
+       }\r
+}\r
+\r
+\r
+/**************************************************\r
+  Places operand in code string and sends instruction\r
+  out to code segment.\r
+**************************************************/\r
+\r
+static void GenCodeOper(char *ptr, U32 token, U32 value, U32 type, U32 offset)\r
+{\r
+       /* interpret the output string & insert the operand */\r
+\r
+       code_chr('\t');\r
+       while(*ptr) {\r
+               if(*ptr == '|')\r
+                       write_oper(token, value, type, offset);\r
+               else\r
+                       code_chr(*ptr);\r
+               ++ptr;\r
+       }\r
+       code_chr('\n');\r
+}\r
+\r
+/*************************************************************\r
+  Examine the expression stack and see if any active token\r
+  is in EAX. If so, place it on the stack.\r
+  The stack top is really the EBX register. If we find\r
+  an active item in the EBX register, we must place\r
+  it on the real processor stack first and change it's\r
+  token to show where it is.\r
+**************************************************************/\r
+\r
+static void StackEAX(void)\r
+{\r
+       S32 i, j;\r
+\r
+       for(i=0; i < expr_ptr; ++i) {\r
+               if (expstk[i].token == INEAX)           /* Found it */\r
+               {\r
+                       for(j=0; j < expr_ptr; ++j)\r
+                       {\r
+                               if ((expstk[j].token == STACK_TOP) ||\r
+                                       (expstk[j].token == ISTACK_TOP))\r
+                               {\r
+                                       out_inst("PUSH EBX");\r
+                                       if (expstk[j].token == STACK_TOP)\r
+                        expstk[j].token = ON_STACK;\r
+                                       else\r
+                        expstk[j].token = ION_STACK;\r
+                                       break;\r
+                               }\r
+                       }\r
+                       test_not();\r
+                       out_inst("MOV EBX,EAX");\r
+                       expstk[i].token = STACK_TOP;\r
+               }\r
+       }\r
+}\r
+\r
+/**********************************************************\r
+ If the token we need is actually on the processor stack,\r
+ we must must pop it out so we can use it. To do this,\r
+ we pop it into EDX. EDX is only used for multiply and\r
+ divide operations otherwise.\r
+***********************************************************/\r
+static U32 CheckStack(U32 token)\r
+{\r
+       if (token==ION_STACK)\r
+       {\r
+               out_inst("POP EDX");\r
+               token = PEDX;\r
+       }\r
+       else if (token==ON_STACK)\r
+       {\r
+               out_inst("POP EDX");\r
+               token = INEDX;\r
+       }\r
+       return(token);\r
+}\r
+\r
+/**************************************************************\r
+ Get a parameter into the EAX register.\r
+ The value/register is always sign or zero extended to 32 bits!\r
+***************************************************************/\r
+\r
+static void LoadEAX(U32 token, U32 value, U32 type, U32 offset)\r
+{\r
+       if(type & FUNCTION)\r
+               type_error();\r
+\r
+       if(token == INEAX) {            /* Already there */\r
+               test_not();\r
+               return;\r
+       }\r
+\r
+       token = CheckStack(token);   /* If it's on the processor stack, get it into EDX */\r
+\r
+       StackEAX();                             /* stack EAX if needed */\r
+       not_flag = 0;\r
+\r
+       if((token == NUMBER) && (!value)) {             /* 0 Value */\r
+               test_not();\r
+               code_str("\tXOR EAX,EAX\n");\r
+               return;\r
+       }\r
+\r
+       if ((type&(DWORD|POINTER)) ||\r
+               (token == NUMBER) ||\r
+               (token == INEDX) ||\r
+               (token == STACK_TOP) ||\r
+               (token == INECX))\r
+\r
+               GenCodeOper("MOV EAX,|", token, value, type, offset);\r
+       else if (type & WORD)\r
+       {\r
+               if (type & UNSIGNED)\r
+                       GenCodeOper("MOVZX EAX,|", token, value, type, offset);\r
+               else\r
+                       GenCodeOper("MOVSX EAX,|", token, value, type, offset);\r
+       }\r
+       else\r
+       {\r
+               if (type & UNSIGNED)\r
+               {\r
+                       code_str("\tXOR EAX,EAX\n");\r
+                       GenCodeOper("MOV AL,|", token, value, type, offset);\r
+               }\r
+               else\r
+                       GenCodeOper("MOVSX EAX,|", token, value, type, offset);\r
+       }\r
+\r
+       zero_flag = -1;\r
+}\r
+\r
+/**************************************************************\r
+ Get a parameter into the ECX register.\r
+ The value/register is always sign or zero extended to 32 bits!\r
+***************************************************************/\r
+\r
+static void LoadECX(U32 token, U32 value, U32 type, U32 offset)\r
+{\r
+       if(type & FUNCTION)\r
+               type_error();\r
+\r
+       if(token == INECX)\r
+       {               /* Already there */\r
+               return;\r
+       }\r
+\r
+       token = CheckStack(token);   /* If it's on the processor stack, get it into EDX */\r
+\r
+       if ((token == NUMBER) && (!value))\r
+       {               /* 0 Value */\r
+               code_str("\tXOR ECX,ECX\n");\r
+               return;\r
+       }\r
+\r
+       if ((type&(DWORD|POINTER)) ||\r
+               (token == NUMBER) ||\r
+               (token == INEDX) ||\r
+               (token == STACK_TOP) ||\r
+               (token == INEAX))\r
+\r
+               GenCodeOper("MOV ECX,|", token, value, type, offset);\r
+       else if (type & WORD) {\r
+               if (type & UNSIGNED)\r
+                       GenCodeOper("MOVZX ECX,|", token, value, type, offset);\r
+               else\r
+                       GenCodeOper("MOVSX ECX,|", token, value, type, offset);\r
+       }\r
+       else\r
+       {\r
+               if (type & UNSIGNED)\r
+               {\r
+                       code_str("\tXOR ECX,ECX\n");\r
+                       GenCodeOper("MOV CL,|", token, value, type, offset);\r
+               }\r
+               else\r
+                       GenCodeOper("MOVSX ECX,|", token, value, type, offset);\r
+       }\r
+}\r
+\r
+\r
+/****************************************************************\r
+* Evaluate a sub expression & handle COMMA operator. This must\r
+* be done as a special case, because the function performed by\r
+* COMMA differs with the context of the expression, and can not\r
+* therefore be handled as a general operator.\r
+*****************************************************************/\r
+\r
+static void sub_eval(U32 term)\r
+{\r
+U32 token;\r
+\r
+       for(;;) {\r
+               if((token = do_oper(SEMI)) != COMMA) {\r
+                       unget_token(token);\r
+                       expect(term);\r
+                       return;\r
+               }\r
+               pop(&token, &token, &token, &token);    /* throw it away */\r
+       }\r
+}\r
+\r
+\r
+/********************************************************\r
+* Evaluate a full expression at the highest level, and\r
+* load the result into the accumulator if necessary.\r
+*********************************************************/\r
+\r
+static void eval(U32 term, char flag)\r
+{\r
+U32 token, value, type, offset;\r
+\r
+       expr_ptr = 0;\r
+       not_flag = 0;\r
+       sub_eval(term);\r
+\r
+       pop(&token, &value, &type, &offset);\r
+       if((token != INEAX) || flag)\r
+               LoadEAX(token, value, type, offset);\r
+}\r
+\r
+/************************************************\r
+* Write an instruction with text formatting\r
+  to the code tmp file\r
+*************************************************/\r
+\r
+static void out_inst(char *ptr)\r
+{\r
+       code_chr('\t');\r
+       code_str(ptr);\r
+       code_chr('\n');\r
+}\r
+\r
+\r
+/*************************************************************\r
+  Examine the expression stack and see if any active token\r
+  is in the EBX register which acts as the stack top for\r
+  fast access. If so, put it on the real stack because\r
+  we must preserve it through a call.\r
+**************************************************************/\r
+\r
+static void StackTop(void)\r
+{\r
+       S32  j;\r
+\r
+       for(j=0; j < expr_ptr; ++j)\r
+       {\r
+               if ((expstk[j].token == STACK_TOP) ||\r
+                       (expstk[j].token == ISTACK_TOP))\r
+               {\r
+                       out_inst("PUSH EBX");\r
+                       if (expstk[j].token == STACK_TOP)\r
+                       expstk[j].token = ON_STACK;\r
+                       else\r
+                   expstk[j].token = ION_STACK;\r
+                       break;\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*************************************************************\r
+  Examine the expression stack and see if any active token\r
+  is in the Index Reg. If so, place it on the stack.\r
+  The stack top is really the EBX register. If we find\r
+  an active item in the EBX register, we must place\r
+  it on the real processor stack first and change it's\r
+  token to show where it is.\r
+**************************************************************/\r
+\r
+static void StackESI(void)\r
+{\r
+       S32 i, j;\r
+\r
+       for(i=0; i < expr_ptr; ++i) {\r
+               if (expstk[i].token == PESI)            /* Found it */\r
+               {\r
+                       for(j=0; j < expr_ptr; ++j)\r
+                       {\r
+                               if ((expstk[j].token == STACK_TOP) ||\r
+                                       (expstk[j].token == ISTACK_TOP))\r
+                               {\r
+                                       out_inst("PUSH EBX");\r
+                                       if (expstk[j].token == STACK_TOP)\r
+                        expstk[j].token = ON_STACK;\r
+                                       else\r
+                        expstk[j].token = ION_STACK;\r
+                                       break;\r
+                               }\r
+                       }\r
+                       out_inst("MOV EBX,ESI");\r
+                       expstk[i].token = ISTACK_TOP;\r
+               }\r
+       }\r
+}\r
+\r
+\r
+/*****************************************\r
+* Load index address for an array\r
+******************************************/\r
+\r
+static void load_index(U32 t, U32 v, U32 tt, U32 o)\r
+{\r
+               StackESI();\r
+               if((tt & ARGUMENT) || !(tt & ARRAY))    /* pointer or argument */\r
+                       index_ptr(t, v, tt, o);\r
+               else                                                                    /* standard array */\r
+                       index_adr(t, v, tt, o);\r
+}\r
+\r
+\r
+/*************************************************************************\r
+* Evaluate a unary operation, if possible, evaluate constant expressions\r
+* into another constant. Produce code to perform operation if necessary.\r
+**************************************************************************/\r
+\r
+static void do_unary(U32 oper)\r
+{\r
+       U32 token, value, type, offset;\r
+       char flag;\r
+\r
+       pop(&token, &value, &type, &offset);\r
+       flag = 0;\r
+       /* Evaluate any operations that can be performed at compile time */\r
+       if(token == NUMBER)\r
+       {\r
+               flag = -1;\r
+               switch(oper)\r
+               {\r
+                       case SUB :              /* unary minus */\r
+                               value = -value;\r
+                               break;\r
+                       case COM:               /* ones complement */\r
+                               value = ~value;\r
+                               break;\r
+                       case NOT:               /* logical complement */\r
+                               value = !value;\r
+                               break;\r
+                       default:\r
+                               flag = 0;\r
+               }\r
+       }\r
+\r
+       /* Generate code to perform operation */\r
+       if(!flag)\r
+       {\r
+               switch(oper)\r
+               {\r
+                       case SUB:                               /* unary minus */\r
+                               GenCodeOper("NEG |", token, value, type, offset);\r
+                               break;\r
+                       case COM:                               /* ones complement */\r
+                               GenCodeOper("NOT |", token, value, type, offset);\r
+                               break;\r
+                       case NOT:                               /* logical complement */\r
+                               LoadEAX(token, value, type, offset);\r
+                               token = INEAX;\r
+                               not_flag = TRUE;\r
+                               break;\r
+                       case INC:                               /* '++' increment token & load */\r
+                               if (ispStruct(type, value))\r
+                                       GenCodeOper("ADD |,strucsize", token, value, type, offset);\r
+                               else if (isp32(type))\r
+                                       GenCodeOper("ADD |,4", token, value, type, offset);\r
+                               else if (isp16(type))\r
+                                       GenCodeOper("ADD |,2", token, value, type, offset);\r
+                               else\r
+                                       GenCodeOper("INC |", token, value, type, offset);\r
+                               break;\r
+                       case DEC:                               /* '--' decrement & store */\r
+                               if (ispStruct(type, value))\r
+                                       GenCodeOper("SUB |,strucsize", token, value, type, offset);\r
+                               else if (isp32(type))\r
+                                       GenCodeOper("SUB |,4", token, value, type, offset);\r
+                               else if (isp16(type))\r
+                                       GenCodeOper("SUB |,2", token, value, type, offset);\r
+                               else\r
+                                       GenCodeOper("DEC |", token, value, type, offset);\r
+                               break;\r
+                       default:\r
+                               syntax_error();\r
+               }\r
+       }\r
+       push(token, value, type, offset);\r
+}\r
+\r
+\r
+/******************************************************\r
+ This evaluates array indeces for get_value.\r
+*******************************************************/\r
+\r
+static S8 eval_index(U32 t, U32 v, U32 tp, U32 ofs, U32 *tpRet)\r
+{\r
+       S32 ndim;\r
+       U32 tp1, dptr, iSym, vsize, ofs1;\r
+       char fMultiDim;\r
+\r
+       fMultiDim = FALSE;      /* true when processing second or subsequent dims */\r
+\r
+       if(tp & ARRAY) {                        /* array, get # dimensions */\r
+               dptr = symtab[v].dindex;\r
+               ndim = dim_pool[dptr++];\r
+               }\r
+       else                                    /* pointer, fake # dims as 1 */\r
+               dptr = ndim = 1;\r
+\r
+       iSym = v;                       /* save index into symtab */\r
+\r
+       push(t, v, tp, ofs);    /* save symbol we are indexing on exp stack */\r
+\r
+       do {                            /* calculate index */\r
+\r
+               /* this gets the size of variable into vsize */\r
+\r
+               v = tp & (POINTER | ARRAY);\r
+               if ((v==ARRAY) || (v < 2)) {\r
+                        if (tp & BYTE) vsize = 1;\r
+                        else if (tp & WORD) vsize = 2;\r
+                        else if (tp & DWORD) vsize = 4;\r
+                        else if (tp & STRUCT)\r
+                               vsize = symtab[iSym].strucoff; /* strucoff = size of struc*/\r
+                }\r
+               else vsize = 4;\r
+               --ndim;\r
+               if(tp & ARRAY)                  /* array reference */\r
+               {\r
+                       t = ++dptr;\r
+                       if(!(v = ndim))         /* all indices given, load pointer */\r
+                               tp &= ~ARRAY;   /* Not an array ref anymore, ptr instead */\r
+                       while(v--)\r
+                               vsize *= dim_pool[t++];\r
+               }\r
+               else\r
+               {\r
+                       if(tp & POINTER)\r
+                       {               /* pointer reference */\r
+                               --tp;                           /* drop defer level by one */\r
+                               if(fMultiDim)\r
+                               {                                       /* array of pointers */\r
+                                       pop(&t, &v, &tp1, &ofs1);\r
+                                       LoadEAX(t, v, tp1, ofs1);\r
+                                       pop(&t, &v, &tp1, &ofs1);\r
+                                       load_index(t, v, tp1, ofs1);\r
+                                       out_inst("ADD ESI,EAX");\r
+                                       push(t = PESI, v, tp, ofs1);\r
+                                       fMultiDim = 0;\r
+                               }\r
+                       }\r
+                       else                                    /* invalid indexing */\r
+                               index_error();\r
+               }\r
+               sub_eval(CSB);          /* GET the value inside the [] */\r
+\r
+                       /* Multiply [] by size of index */\r
+\r
+               if(vsize != 1) {        /* optimize away size of 1 */\r
+                       push(NUMBER, vsize, DWORD, 0);\r
+                       do_lr2op(STAR);                         /* multiply by size */\r
+               }\r
+               if(fMultiDim) do_lr2op(ADD);    /* add to last index if there */\r
+               fMultiDim = TRUE;                               /* if there is another... */\r
+       }\r
+       while(test_token(OSB));\r
+\r
+       *tpRet = tp;\r
+       return fMultiDim;\r
+}\r
+\r
+/******************************************************\r
+ Gets the next token and perform any processing\r
+ required to evaluate it.  This includes structure\r
+ members.\r
+*******************************************************/\r
+\r
+static void get_value(void)\r
+{\r
+       S32 ndim, vcnt;\r
+       U32 i, j, size, token, t, v, tp, tp1, ofs;\r
+       char fMultiDim, fvarargs;\r
+\r
+       switch(token = get_token()) {\r
+               case NUMBER:                    /* a constant number */\r
+                       t = NUMBER;                     /* constant */\r
+                       v = gvalue;                     /* value of number */\r
+                       tp = DWORD;                     /* all constants are DWORDS */\r
+                       ofs = 0;                        /* no constant offset */\r
+                       break;\r
+               case STRING:                    /* a literal string */\r
+                       t = STRING;                     /* will be found in lit pool */\r
+                       v = gvalue;                     /* length of string  */\r
+                       tp = BYTE | 1;      /* 1 is level of indirection  */\r
+                       ofs = 0;                        /* offset of zero */\r
+                       break;\r
+               case SYMBOL:                    /* symbol value */\r
+                       if(!(lookup_local() || lookup_global())) {              /* not defined */\r
+                               if(test_token(ORB)) {                   /* function, but no proto! */\r
+                                       symbol_error("Function not prototyped");\r
+                               }\r
+                               else                                                    /* variable, report error */\r
+                                       symbol_error("Undefined symbol");\r
+                       }\r
+                       t = SYMBOL;\r
+                       v = sptr;                               /* symtab entry */\r
+                       tp = symtab[v].type;\r
+                       ofs = 0;                        /* offset of zero */\r
+                       break;\r
+               case STAR:                              /* pointer dereference */\r
+                       get_value();\r
+                       pop(&t, &v, &tp, &ofs);\r
+                       StackESI();\r
+                       index_ptr(t, v, tp, ofs);\r
+                       t = PESI;\r
+                       if(tp & POINTER)\r
+                               --tp;\r
+                       else\r
+                               index_error();\r
+                       break;\r
+               case AND:                               /* address of */\r
+                       get_value();\r
+                       pop(&t, &v, &tp, &ofs);\r
+                       if(t == SYMBOL)\r
+                       {\r
+                               StackEAX();\r
+                               code_str((tp & GLOBAL) ? "\tMOV EAX,OFFSET " : "\tLEA EAX,");\r
+                               write_oper(t, v, tp, ofs);\r
+                               code_chr('\n');\r
+                               not_flag=0;\r
+                               tp = (tp + 1) & ~FUNCTION;  /* tp + 1 ups the ptr ref count */\r
+                               t = INEAX;\r
+                       }\r
+                       else if (t == PESI)\r
+                       {\r
+                               StackEAX();\r
+                               not_flag=0;\r
+                               out_inst("MOV EAX,ESI");\r
+                               tp = (tp + 1) & ~FUNCTION;  /* tp + 1 ups the ptr ref count */\r
+                               t = INEAX;\r
+                       }\r
+                       else if ((t == INEAX) && (tp & POINTER))\r
+                       { /* do nothing... it's there. */ }\r
+                       else\r
+                               line_error("Invalid '&' operation");\r
+                       break;\r
+               case ORB:                               /* sub-expression */\r
+                       sub_eval(CRB);\r
+                       pop(&t, &v, &tp, &ofs);\r
+                       break;\r
+               case SIZEOF:                            /* sizeof */\r
+                       if(test_token(ORB)) {\r
+                               get_value();                    /* look for a symbol */\r
+                               pop(&t, &v, &tp, &ofs);\r
+                               if (t == SYMBOL) {\r
+                                       if (tp & POINTER) size = 4;\r
+                                       else if (tp & BYTE) size = 1;\r
+                                       else if (tp & WORD) size = 2;\r
+                                       else if (tp & DWORD) size = 4;\r
+                                       else if (tp & STRUCT)\r
+                                               size = symtab[v].strucoff; /* strucoff = size */\r
+                                       else size = 4;\r
+                                       if ((tp & ARRAY) && (!(tp & POINTER))) { /* array ref */\r
+                                               i = symtab[v].dindex;    /* i = index to dimpool */\r
+                                               j = dim_pool[i++];                      /* j = nDims */\r
+                                               while(j--) size *= dim_pool[i++];\r
+                                       }\r
+                                       t = NUMBER;\r
+                                       tp = DWORD;                     /* all constants are DWORDS */\r
+                                       v = size;\r
+                                       push(t, v, tp, 0);      /* PUSH THE "Value" ON THE EXP STACK */\r
+                                       expect(CRB);\r
+                                       return;\r
+                               }\r
+                               else\r
+                                       line_error("Symbol expected");\r
+                       }\r
+                       else\r
+                               line_error("'(' expected");\r
+                   break;\r
+               default:                                /* anything else (operators) */\r
+                       get_value();            /* look for a value */\r
+                       do_unary(token);\r
+                       return;\r
+       }\r
+\r
+/* Function calls  - Open Round Brackett (ORB) */\r
+\r
+       if(test_token(ORB))\r
+       {\r
+               iarg = symtab[v].dindex;        /* index to prototyped args! */\r
+               push(t, v, tp, ofs);\r
+               StackEAX();\r
+               StackESI();\r
+               if (tp & VARARGS) fvarargs = -1;\r
+               else fvarargs = 0;\r
+               vcnt = ndim = 0;\r
+               StackTop();\r
+               if(!test_token(CRB))\r
+               {               /* evaluate function operands */\r
+                       do {\r
+                               argtype = proto_list[iarg]; /* current arg type */\r
+                               if(!(argtype&VOID)) iarg++; /* if not end of proto args, get next*/\r
+                               token = do_oper(SEMI);          /* handle operation on arg */\r
+                               pop(&t, &v, &tp, &ofs);         /* get token arg from expstack */\r
+                               LoadEAX(t, v, tp, ofs);\r
+                               if ((t != PESI) && (ofs) && (tp&POINTER))\r
+                               {       /* offset must be added */\r
+                                       code_str("\tADD EAX,");\r
+                                       code_num(ofs);\r
+                                       code_chr('\n');\r
+                               }\r
+                               out_inst("PUSH EAX");\r
+\r
+                               ++ndim;\r
+                               if ((!fvarargs) || (fvarargs && (argtype==VOID))) {\r
+                                       ++vcnt;\r
+                               }\r
+                       }\r
+                       while(token == COMMA);\r
+                       if(token != CRB)\r
+                               syntax_error();\r
+               }\r
+               iarg = 0;\r
+               pop(&t, &v, &tp, &ofs); /* get function back off the expr stack */\r
+\r
+               /*  if the function we are about to call had variable parameters\r
+                       then put the count of bytes that were pushed into EDI as the\r
+                       code in a vararg function uses it to access the fixed args.\r
+                       Also, we leave ndim (total count of bytes push) with it's\r
+                       value so that the "call" function knows he must remove the\r
+                       data from the stack and the "end_func" function knows not\r
+                       to use the RET XX instruction.\r
+               */\r
+\r
+               if (fvarargs) {\r
+                       code_str("\tMOV EDI, ");\r
+                       code_num(vcnt*4);\r
+                       code_chr('\n');\r
+               }\r
+               else ndim = 0;\r
+\r
+               call(t, v, tp, ofs, ndim);\r
+\r
+               t = INEAX;                      /* set up to leave the return value in ACC */\r
+               tp &= ~FUNCTION;\r
+       }\r
+\r
+\r
+\r
+/* Indexing operations - Open Square Brackett (OSB) */\r
+\r
+       fMultiDim = 0;\r
+       if(test_token(OSB)) {\r
+               fMultiDim = eval_index(t, v, tp, ofs, &tp);\r
+\r
+               /* get index value token pushed by eval_index */\r
+\r
+               pop(&token, &v, &t, &ofs);\r
+               if ((token==NUMBER) & (!v))\r
+               {  /* index is 0 */\r
+                       pop(&t, &v, &tp1, &ofs);                /* Get var base */\r
+                       if ((tp1 & (POINTER|ARRAY)) && (t!=PESI))\r
+                               load_index(t, v, tp1, ofs);     /* Load base into Index reg */\r
+               }\r
+               else\r
+               {\r
+                       LoadEAX(token, v, t, ofs);      /* load it into ACC */\r
+                       pop(&t, &v, &tp1, &ofs);                /* Get var base */\r
+                       if (tp1 & (POINTER|ARRAY) && (t!=PESI))\r
+                               load_index(t, v, tp1, ofs);     /* Load base into Index reg */\r
+                       out_inst("ADD ESI,EAX");\r
+               }\r
+               t = PESI;                       /* Let em know ESI pts to item */\r
+       }\r
+\r
+/* Convert any [UNINDEXED] array references to address values.\r
+   This is done later to structures and struct members.\r
+*/\r
+\r
+       if((tp & ARRAY) && (!(tp & (STRUCT|STRUCMEM)))) {\r
+               tp = (tp + 1) & ~ARRAY;                 /* tp+1 ups the ptr ref count */\r
+               if(!(tp & ARGUMENT))\r
+               {\r
+                       if(!fMultiDim)\r
+                       {\r
+                               StackEAX();                             /* save what's in EAX and ESI */\r
+                               StackESI();\r
+                               index_adr(t, v, tp, ofs);       /* load address of rg into ESI */\r
+                       }\r
+                       StackEAX();                             /* save what's in EAX if needed */\r
+                       not_flag = 0;\r
+                       out_inst("MOV EAX,ESI");\r
+                       t = INEAX;\r
+               }\r
+       }\r
+\r
+/* handle the dereference operators . and -> for\r
+   structures and pointers to structures if present */\r
+\r
+\r
+       if(test_token(DEREF)) {\r
+               if ((tp & STRUCT) && ((tp & POINTER) || (t==PESI)) ) {\r
+                       if (t == SYMBOL) {                              /* may already be PESI */\r
+                               StackEAX();                                     /* save what's in EAX */\r
+                               StackESI();                             /* stack ESI */\r
+                           index_ptr(t, v, tp, ofs);           /* pointer base into ESI */\r
+                               t = PESI;                               /* tell em it's indirect now */\r
+                       }\r
+                   if (test_token(SYMBOL)) {\r
+                               if (lookup_member(v)) {\r
+                                   memoffset = symtab[sptr].strucoff;\r
+                                   tp = symtab[sptr].type;\r
+                               v = sptr;\r
+                                       ofs = memoffset;        /* NEW */\r
+\r
+                                       if (tp & ARRAY)\r
+                                               tp = (tp + 1) & ~ARRAY;  /* tp+1 ups the ptr ref count */\r
+                                       t = PESI;               /* tell em it's indirect now */\r
+                               }\r
+                               else\r
+                                       line_error("Not a structure member");\r
+                       }\r
+                       else\r
+                               line_error("Structure member expected");\r
+               }\r
+               else\r
+                       line_error("Pointer to Struct expected");\r
+       }\r
+\r
+       if (test_token(DOT)) {\r
+               if ((tp & STRUCT) && (!(tp & POINTER))) {\r
+                       if (t == SYMBOL) {                              /* may already be PESI */\r
+                               StackEAX();                                     /* save what's in EAX */\r
+                               StackESI();                             /* stack ESI */\r
+                           index_adr(t, v, tp, ofs);   /* ptr to base of struct into ESI */\r
+                           t = PESI;\r
+                       }\r
+               if (test_token(SYMBOL)) {\r
+                               if (lookup_member(v)) {\r
+                                       memoffset = symtab[sptr].strucoff;\r
+                                       tp = symtab[sptr].type;         /* member type */\r
+                                       v = sptr;                                       /* symtab entry of member */\r
+                                       ofs = memoffset;        /* NEW */\r
+\r
+                                       t = PESI;               /* tell em it's indirect now */\r
+\r
+                               }\r
+                               else\r
+                                       line_error("Structure member expected");\r
+                       }\r
+                       else\r
+                               line_error("Structure member expected");\r
+               }\r
+               else\r
+                       line_error("Invalid structure operation");\r
+       }\r
+\r
+/* Indexing operations for STRUCTMEMS- Open Square Brackett (OSB) */\r
+\r
+       fMultiDim = 0;\r
+       if(test_token(OSB)) {\r
+               fMultiDim = eval_index(t, v, tp, ofs, &tp);\r
+               pop(&token, &v, &t, &ofs);              /* get index value token just pushed */\r
+               if ((token==NUMBER) & (!v))\r
+               {       /* index is 0 */\r
+                       pop(&t, &v, &tp1, &ofs);        /* Get var base */\r
+                       if (tp1 & (POINTER|ARRAY) && (t!=PESI))\r
+                       {\r
+                               load_index(t, v, tp1, ofs);     /* Load base into Index reg */\r
+                               if ((t==ISTACK_TOP) &&\r
+                                       (symtab[v].type & ARRAY))\r
+                                       t=STACK_TOP;\r
+                       }\r
+               }\r
+               else {\r
+                       LoadEAX(token, v, t, ofs);      /* load it into ACC */\r
+                       pop(&t, &v, &tp1, &ofs);                        /* Get var base */\r
+                       if (tp1 & (POINTER|ARRAY) && (t!=PESI)) {\r
+                               if ((t==ISTACK_TOP) &&\r
+                                       (symtab[v].type & ARRAY))\r
+                                       t=STACK_TOP;\r
+                               load_index(t, v, tp1, ofs);     /* Load base into Index reg */\r
+                       }\r
+                       out_inst("ADD ESI,EAX");\r
+               }\r
+               t = PESI;                       /* Let em know ESI pts to item */\r
+       }\r
+\r
+\r
+/* Convert any [UNINDEXED] array references to address values\r
+   for struct members that are arrays.\r
+*/\r
+\r
+       if((tp & ARRAY) && (tp & (STRUCMEM))) {\r
+               tp = (tp + 1) & ~ARRAY;                 /* tp+1 ups the ptr ref count */\r
+               if(!(tp & ARGUMENT))\r
+               {\r
+                       if(!fMultiDim)\r
+                       {\r
+                               StackEAX();                                     /* stack EAX */\r
+                               StackESI();                             /* stack ESI */\r
+                               index_adr(t, v, tp, ofs);       /* load address of rg into ESI */\r
+                       }\r
+                       StackEAX();                                     /* stack EAX if needed */\r
+                       not_flag = 0;\r
+                       out_inst("MOV EAX,ESI");\r
+                       t = INEAX;\r
+               }\r
+       }\r
+\r
+/* handle any post operators (++ and --) if present */\r
+\r
+       if(test_token(INC)) {                   /* post '++' */\r
+               if (tp & POINTER)\r
+               {\r
+                       load_index(t, v, tp, ofs);\r
+               }\r
+               else\r
+                       LoadEAX(t, v, tp, ofs);\r
+               if (ispStruct(tp, v))\r
+                       GenCodeOper("ADD |,strucsize", t, v, tp, ofs);\r
+               else if (isp32(tp))\r
+                       GenCodeOper("ADD |,4", t, v, tp, ofs);\r
+               else if (isp16(tp))\r
+                       GenCodeOper("ADD |,2", t, v, tp, ofs);\r
+               else\r
+                       GenCodeOper("INC |", t, v, tp, ofs);\r
+               if (tp & POINTER)\r
+               {\r
+                       t = PESI;\r
+               }\r
+               else\r
+                       t = INEAX;\r
+       }\r
+\r
+       else if(test_token(DEC))\r
+       {                                                                       /* post '--' */\r
+               if (tp & POINTER)\r
+               {\r
+                       load_index(t, v, tp, ofs);\r
+               }\r
+               else\r
+                       LoadEAX(t, v, tp, ofs);\r
+               if (ispStruct(tp, v))\r
+                       GenCodeOper("SUB |,strucsize", t, v, tp, ofs);\r
+               else if (isp32(tp))\r
+                       GenCodeOper("SUB |,4", t, v, tp, ofs);\r
+               else if (isp16(tp))\r
+                       GenCodeOper("SUB |,2", t, v, tp, ofs);\r
+               else\r
+                       GenCodeOper("DEC |", t, v, tp, ofs);\r
+               if (tp & POINTER)\r
+               {\r
+                       t = PESI;\r
+               }\r
+               else\r
+                       t = INEAX;\r
+       }\r
+       push(t, v, tp, ofs);    /* FINALLY PUSH THE "Value" ON THE EXP STACK */\r
+}\r
+\r
+/****************************************************\r
+ Combine two types (For binary operations)\r
+ This raises the type to the lowest common type, or\r
+ in the case of a strucr-member operation, the type\r
+ is the type become the member's type.\r
+*****************************************************/\r
+\r
+static U32 combine(U32 type1, U32 type2)\r
+{\r
+       U32 new_type;\r
+\r
+/* preserve width and indirection if pointer operation is involved */\r
+/* if neither is pointer no harm is done with this code */\r
+\r
+       if ((type1 & POINTER) >= (type2 & POINTER))\r
+               new_type = type1 & POINTER;\r
+       else\r
+               new_type = type2 & POINTER;\r
+\r
+/* raise to lowest common type */\r
+\r
+       if ((type1 & DWORD) || (type2 & DWORD)) new_type |= DWORD;\r
+       else if ((type1 & WORD) || (type2 & WORD)) new_type |= WORD;\r
+       else new_type |= BYTE;\r
+\r
+/* ANSI says: If combining unsigned and signed types and signed var\r
+   is large enough to hold all values of unsigned then combined type\r
+   remains SIGNED, else the type becomes UNSIGNED!\r
+*/\r
+\r
+       if (!((type1 & type2) & UNSIGNED))  /* both signed */\r
+               return new_type;\r
+\r
+       if ((type1 & UNSIGNED) && (type2 & UNSIGNED)) {  /* both unsigned */\r
+               new_type |=UNSIGNED;\r
+               return new_type;\r
+       }\r
+\r
+       /* ONLY one is signed... */\r
+\r
+       if (((type1 & SIZEMASK) >= (type2 & SIZEMASK)) && (type2 & UNSIGNED))\r
+               new_type |= UNSIGNED;\r
+\r
+       else\r
+       if (((type1 & SIZEMASK) <= (type2 & SIZEMASK)) && (type1 & UNSIGNED))\r
+               new_type |= UNSIGNED;\r
+\r
+       return new_type;\r
+\r
+}\r
+\r
+/**********************************************************\r
+* Perform an operation & all higher priority operations.\r
+***********************************************************/\r
+\r
+static U32 do_oper(U32 token)\r
+{\r
+       U32 token1, t, v, tp, tp1, ofs, ofs1, exit_lab;\r
+\r
+       /* Handle "special" binary operators which involve jumps */\r
+       if((token == DAND) || (token == DOR) || (token == QUEST))\r
+       {\r
+               pop(&t, &v, &tp, &ofs);\r
+               StackEAX();                                     /* stack EAX */\r
+               StackESI();                             /* stack ESI */\r
+               if(t != INEAX)\r
+                       LoadEAX(t, v, tp, ofs);\r
+               exit_lab = ++next_lab;\r
+               if(token == QUEST)\r
+               {               /* conditional expression */\r
+                       cond_jump(FALSE, token1 = ++next_lab, 0);\r
+                       sub_eval(COLON);\r
+                       pop(&t, &v, &tp, &ofs);\r
+                       LoadEAX(t, v, tp, ofs);\r
+                       jump(exit_lab, 0);\r
+                       gen_label(token1);\r
+               }\r
+               else\r
+               {                                       /* && and || */\r
+                       test_not();\r
+                       if(token == DAND)\r
+                               cond_jump(FALSE, exit_lab, -1);\r
+                       else\r
+                               cond_jump(TRUE, exit_lab, -1);\r
+               }\r
+               token1 = do_oper(SEMI);\r
+               pop(&t, &v, &tp1, &ofs1);\r
+               LoadEAX(t, v, tp1, ofs1);\r
+               gen_label(exit_lab);\r
+               push(INEAX, v, combine(tp, tp1), ofs1);\r
+               return token1;\r
+       }\r
+\r
+       get_value();                    /* stack the value (number or whatever) */\r
+\r
+/* Handle operator precedence and grouping. optype is 2 if operator\r
+   separates two operands and grouping is L-R. It's 3 if R-L */\r
+\r
+       token1 = get_token();   /* Look at next operator */\r
+               while((optype[token1] > 1) &&\r
+                         (priority[token1] >= priority[token]))\r
+               {\r
+                       /* if they are the same priority AND grouping == L-R */\r
+\r
+                       if((priority[token1] == priority[token]) &&\r
+                          (optype[token] == 2))\r
+                       {\r
+                               do_lr2op(token);\r
+                               return do_oper(token1);\r
+                       }\r
+\r
+                       token1 = do_oper(token1);\r
+               }\r
+\r
+/* Perform the operation */\r
+       if(token!=SEMI)\r
+               do_lr2op(token);\r
+\r
+       return token1;\r
+}\r
+\r
+\r
+/*************************************************************************\r
+ Evaluates two operands for operators with L to R grouping.\r
+ if possible, evaluate constant expressions into another constant.\r
+ Produce code to perform operation if necessary.\r
+ The two operands are on the top of the expression stack and are\r
+ loaded into token and token1. The item at the top of the stack is the\r
+ second operand.  This means that if it were "A minus B", A would go into\r
+ token and B would go into token1.\r
+**************************************************************************/\r
+\r
+static void do_lr2op(U32 oper)\r
+{\r
+       U32 token, value, type, token1, value1, type1, offset, offset1;\r
+       U32 atoken, avalue, atype, temp, ctype;\r
+       U32 uflag, swap, order, wheretok;\r
+\r
+       pop(&token1, &value1, &type1, &offset1);\r
+       pop(&token, &value,  &type, &offset);\r
+\r
+       uflag = swap = order = atoken = 0;\r
+\r
+       /* Constant numbers assume the type of the other operand */\r
+       if(token == NUMBER)\r
+       {\r
+               swap = 1;\r
+               type = type1;\r
+       }\r
+       if(token1 == NUMBER)\r
+       {\r
+               swap = 0;\r
+               type1 = type;\r
+       }\r
+\r
+       ctype = combine(type, type1);\r
+\r
+       /* Do any operations that can be performed at compile time */\r
+\r
+       if((token == NUMBER) && (token1 == NUMBER) &&\r
+               (oper != DAND) && (oper != DOR)) {\r
+               switch(oper) {\r
+                       case ADD :\r
+                               value += value1;\r
+                               break;\r
+                       case SUB :\r
+                               value -= value1;\r
+                               break;\r
+                       case STAR:\r
+                               value *= value1;\r
+                               break;\r
+                       case DIV:\r
+                               value /= value1;\r
+                               break;\r
+                       case MOD:\r
+                               value %= value1;\r
+                               break;\r
+                       case AND:\r
+                               value &= value1;\r
+                               break;\r
+                       case OR:\r
+                               value |= value1;\r
+                               break;\r
+                       case XOR:\r
+                               value ^= value1;\r
+                               break;\r
+                       case SHL:\r
+                               value <<= value1;\r
+                               break;\r
+                       case SHR:\r
+                               value >>= value1;\r
+                               break;\r
+                       case EQ:\r
+                               value = value == value1;\r
+                               break;\r
+                       case NE:\r
+                               value = value != value1;\r
+                               break;\r
+                       case LT:\r
+                               value = value < value1;\r
+                       case LE:\r
+                               value = value <= value1;\r
+                               break;\r
+                       case GT:\r
+                               value = value > value1;\r
+                               break;\r
+                       case GE:\r
+                               value = value >= value1;\r
+                               break;\r
+                       default:\r
+                               syntax_error();\r
+               }\r
+       }\r
+       else\r
+       {\r
+               /* Generate code to perform the operation */\r
+               avalue = value;\r
+               atype = type;\r
+               wheretok = INEAX;               /* default place for result */\r
+\r
+               /* Use unsigned operations if needed */\r
+               if((type | type1) & (POINTER | UNSIGNED))\r
+                       uflag = 1;\r
+\r
+               /* Try and re-arrange for partial results already in ACC */\r
+               if(token1 == INEAX)\r
+                       swap = 1;\r
+\r
+               /* This first switch sets up self assignments and\r
+                  changes the operand to the real operation to be\r
+                  performed\r
+               */\r
+\r
+               switch(oper)\r
+               {\r
+                       case DAND:      /* logical AND and OR are done elsewhere */\r
+                       case DOR:\r
+                               push(token1, value1, type1, offset1);\r
+                               return;\r
+                       case ADDE:\r
+                               atoken = token; /* nonzero atoken indicates self assignment*/\r
+                               oper = ADD;\r
+                               break;\r
+                       case SUBE:\r
+                               atoken = token;\r
+                               oper = SUB;\r
+                               break;\r
+                       case STARE:\r
+                               atoken = token;\r
+                               oper = STAR;\r
+                               break;\r
+                       case DIVE:\r
+                               oper = DIV;\r
+                               atoken = token;\r
+                               break;\r
+                       case MODE:\r
+                               oper = MOD;\r
+                               atoken = token;\r
+                               break;\r
+                       case SHLE:\r
+                               oper = SHL;\r
+                               atoken = token;\r
+                               break;\r
+                       case SHRE:\r
+                               oper = SHR;\r
+                               atoken = token;\r
+                               break;\r
+                       case ANDE:\r
+                               oper = AND;\r
+                               atoken = token;\r
+                               break;\r
+                       case ORE:\r
+                               oper = OR;\r
+                               atoken = token;\r
+                               break;\r
+                       case XORE:\r
+                               oper = XOR;\r
+                               atoken = token;\r
+                               break;\r
+               }\r
+\r
+               /* this next switch looks for operations that MUST\r
+                  use special registers (such as EAX or EDX).\r
+                  Or must be in a special order for a particular\r
+                  operation.\r
+               */\r
+               switch(oper)\r
+               {\r
+                       case SUB:\r
+                       case DIV:\r
+                       case MOD:\r
+                       case SHL:\r
+                       case SHR:\r
+                               order = 1;\r
+                               break;\r
+                       case LT:\r
+                               if (swap) {\r
+                                       if (uflag)\r
+                                               oper = UGT;\r
+                                       else\r
+                                               oper = GT;\r
+                               }\r
+                               else if (uflag)\r
+                                       oper = ULT;\r
+                               break;\r
+                       case LE:\r
+                               if (swap) {\r
+                                       if (uflag)\r
+                                               oper = UGE;\r
+                                       else\r
+                                               oper = GE;\r
+                               }\r
+                               else if (uflag)\r
+                                       oper = ULE;\r
+                               break;\r
+                       case GT:\r
+                               if (swap) {\r
+                                       if (uflag)\r
+                                               oper = ULT;\r
+                                       else\r
+                                               oper = LT;\r
+                               }\r
+                               else if (uflag)\r
+                                       oper = UGT;\r
+                               break;\r
+                       case GE:\r
+                               if (swap) {\r
+                                       if (uflag)\r
+                                               oper = ULE;\r
+                                       else\r
+                                               oper = LE;\r
+                               }\r
+                               else if (uflag)\r
+                                       oper = UGE;\r
+                               break;\r
+               }\r
+\r
+               /* Now we can use the flags to set up a swap of operands if\r
+                  indicated so long as ordering was not important (order flag).\r
+                  Some operations require the use of EAX.\r
+               */\r
+\r
+               if((token1 == INEAX) && order)\r
+               {       /* out of order - use ECX */\r
+                       test_not();\r
+                       out_inst("MOV ECX,EAX");\r
+                       token1 = INECX;\r
+               }\r
+\r
+               if(swap && !order)\r
+               {\r
+                       temp = token;  token = token1;   token1 = temp;\r
+                       temp = value;  value = value1;   value1 = temp;\r
+                       temp = type;   type  = type1;    type1  = temp;\r
+                       temp = offset; offset = offset1; offset1 = temp;\r
+               }\r
+\r
+               if(type1 & FUNCTION)\r
+                       type_error();\r
+\r
+               if (oper != ASSIGN)  /* simple assignment is optimized case */\r
+               {\r
+                       LoadEAX(token, value, type, offset);    /* insure its loaded */\r
+               }\r
+\r
+               /* If it's on the processor stack, get it into EDX */\r
+               token1 = CheckStack(token1);\r
+\r
+               /* Now we perform the operation */\r
+\r
+               switch(oper)\r
+               {\r
+                       case ASSIGN:\r
+                               /* optimize away an assigment */\r
+                               if ((token1 == token) && (value == value1))\r
+                               {\r
+                    wheretok = token;\r
+                                       break;\r
+                               }\r
+                               if (swap)       /* token to store is already in EAX */\r
+                               {\r
+                                       store(token1, value1, type1, offset1);\r
+                               }\r
+                               else  /* token1 may not be loaded already */\r
+                               {\r
+                                       LoadEAX(token1, value1, type1, offset1);\r
+                                       store(token, value, type, offset);\r
+                               }\r
+                               break;\r
+                       case ADD:\r
+                               if (type1&(DWORD|POINTER))\r
+                                       GenCodeOper("ADD EAX,|", token1, value1, type1, offset1);\r
+                               else\r
+                               {\r
+                                       LoadECX(token1, value1, type1, offset1);\r
+                                       out_inst("ADD EAX,ECX");\r
+                               }\r
+                               zero_flag = 0;\r
+                               break;\r
+                       case SUB:\r
+                               if (type1&(DWORD|POINTER))\r
+                                       GenCodeOper("SUB EAX,|", token1, value1, type1, offset1);\r
+                               else\r
+                               {\r
+                                       LoadECX(token1, value1, type1, offset1);\r
+                                       out_inst("SUB EAX,ECX");\r
+                               }\r
+                               zero_flag = 0;\r
+                               break;\r
+                       case STAR:\r
+                               LoadECX(token1, value1, type1, offset1);\r
+                               if (ctype & UNSIGNED)\r
+                                       out_inst("MUL ECX");\r
+                               else\r
+                                       out_inst("IMUL ECX");\r
+                               zero_flag = 1;\r
+                               break;\r
+                       case DIV:\r
+                       case MOD:\r
+                               LoadECX(token1, value1, type1, offset1);\r
+                               if (ctype & UNSIGNED)\r
+                               {\r
+                                       out_inst("XOR EDX,EDX");\r
+                                       out_inst("DIV ECX");\r
+                               }\r
+                               else\r
+                               {\r
+                                       out_inst("CDQ");\r
+                                       out_inst("IDIV ECX");\r
+                               }\r
+                               zero_flag = -1;\r
+                               if (oper == MOD)\r
+                                       out_inst("MOV EAX,EDX");\r
+                               break;\r
+                       case AND:\r
+                               if (type1 & (DWORD|POINTER))\r
+                                       GenCodeOper("AND EAX,|", token1, value1, type1, offset1);\r
+                               else\r
+                               {\r
+                                       LoadECX(token1, value1, type1, offset1);\r
+                                       out_inst("AND EAX,ECX");\r
+                               }\r
+                               zero_flag = 0;\r
+                               break;\r
+                       case OR:\r
+                               if (type1 & (DWORD|POINTER))\r
+                                       GenCodeOper("OR EAX,|", token1, value1, type1, offset1);\r
+                               else\r
+                               {\r
+                                       LoadECX(token1, value1, type1, offset1);\r
+                                       out_inst("OR EAX,ECX");\r
+                               }\r
+                               zero_flag = 0;\r
+                               break;\r
+                       case XOR:\r
+                               if (type1 & (DWORD|POINTER))\r
+                                       GenCodeOper("XOR EAX,|", token1, value1, type1, offset1);\r
+                               else\r
+                               {\r
+                                       LoadECX(token1, value1, type1, offset1);\r
+                                       out_inst("XOR EAX,ECX");\r
+                               }\r
+                               zero_flag = 0;\r
+                               break;\r
+                       case SHL:\r
+                               LoadECX(token1, value1, type1, offset1);\r
+                               out_inst("SHL EAX,CL");\r
+                               if(ctype & WORD)\r
+                                       out_inst("AND EAX,0FFFFh");\r
+                               else if (ctype & BYTE)\r
+                                       out_inst("AND EAX,0FFh");\r
+                               zero_flag = 0;\r
+                               break;\r
+                       case SHR:\r
+                               LoadECX(token1, value1, type1, offset1);\r
+                               if (ctype & (DWORD | POINTER))\r
+                                       out_inst("SHR EAX,CL");\r
+                               else if (ctype & WORD)\r
+                                       out_inst("SHR AX,CL");\r
+                               else\r
+                                       out_inst("SHR AL,CL");\r
+                               zero_flag = 0;\r
+                               break;\r
+                       case EQ:                /* compare & test */\r
+                       case NE:\r
+                       case LT:\r
+                       case LE:\r
+                       case GT:\r
+                       case GE:\r
+                       case ULT:\r
+                       case ULE:\r
+                       case UGT:\r
+                       case UGE:\r
+                               if (type1&(DWORD|POINTER))\r
+                                       GenCodeOper("CMP EAX,|", token1, value1, type1, offset1);\r
+                               else\r
+                               {\r
+                                       LoadECX(token1, value1, type1, offset1);\r
+                                       out_inst("CMP EAX,ECX");\r
+                               }\r
+                               switch(oper)\r
+                               {\r
+                                       case EQ:  out_inst("SETE AL");  break;\r
+                                       case NE:  out_inst("SETNE AL");  break;\r
+                                       case LT:  out_inst("SETL AL");  break;\r
+                                       case LE:  out_inst("SETLE AL");  break;\r
+                                       case GT:  out_inst("SETG AL");  break;\r
+                                       case GE:  out_inst("SETGE AL");  break;\r
+                                       case ULT: out_inst("SETB AL");  break;\r
+                                       case ULE: out_inst("SETBE AL");  break;\r
+                                       case UGT: out_inst("SETA AL");  break;\r
+                                       case UGE: out_inst("SETAE AL");  break;\r
+                               }\r
+                               out_inst("AND AL,AL");\r
+                               zero_flag = 0;\r
+                               break;\r
+                       default:\r
+                               syntax_error();\r
+               }\r
+\r
+               /* for self assigns, replace value */\r
+               if(atoken)\r
+                       store(atoken, avalue, atype, offset);\r
+\r
+               token = wheretok;\r
+       }\r
+\r
+       push(token, value, ctype, offset);\r
+}\r
+\r
+\r
+\r
+/***************************************************\r
+* Test for a logically negated value, and update\r
+* the accumulator if one is being used.\r
+****************************************************/\r
+\r
+static void test_not(void)\r
+{\r
+       if(not_flag)\r
+       {\r
+               out_inst("AND EAX,EAX");\r
+               out_inst("SETZ AL");\r
+               out_inst("AND AL,AL");\r
+               not_flag = 0;\r
+               zero_flag = 0;\r
+       }\r
+}\r
+\r
+\r
+/********************************************\r
+* Store accumulator value\r
+*********************************************/\r
+\r
+static void store(U32 token, U32 value, U32 type, U32 offset)\r
+{\r
+\r
+       token = CheckStack(token);      /* get stack operand to EDX if needed */\r
+\r
+       switch(token) {\r
+               case SYMBOL:\r
+               case PESI:\r
+               case PECX:\r
+               case PEDX:\r
+               case ISTACK_TOP:\r
+                       token = CheckStack(token);      /* get stack operand to EDX if needed */\r
+                       if(type & (DWORD | POINTER))\r
+                               GenCodeOper("MOV |, EAX", token, value, type, offset);\r
+                       else if (type & WORD)\r
+                               GenCodeOper("MOV |, AX", token, value, type, offset);\r
+                       else\r
+                               GenCodeOper("MOV |, AL", token, value, type, offset);\r
+                       zero_flag = -1;\r
+                       break;\r
+               default:\r
+                       line_error("Non-assignable");\r
+       }\r
+}\r
+\r
+\r
+/*********************************************\r
+ Determine if a type is a pointer to struct\r
+**********************************************/\r
+\r
+static U32 ispStruct(U32 type, U32 value)\r
+{\r
+       if((type & POINTER) > 1)        /* pointer to pointer */\r
+               return 0;\r
+       if ((type & STRUCT) && (type & POINTER)) {\r
+               strucsize = symtab[value].strucoff;\r
+               return 1;\r
+       }\r
+       return 0;                                       /* not our pointer */\r
+}\r
+\r
+/*********************************************\r
+ Determine if a type is a pointer to 32 bits\r
+**********************************************/\r
+\r
+static U32 isp32(U32 type)\r
+{\r
+       if(type & (POINTER-1))          /* pointer to pointer */\r
+               return 1;\r
+       if(type & POINTER)                      /* first level pointer */\r
+               return (type & DWORD);\r
+       return 0;                                       /* not a pointer */\r
+}\r
+\r
+/***********************************************\r
+ Determine if a type is a pointer to 16 bits\r
+************************************************/\r
+static U32 isp16(U32 type)\r
+{\r
+       if(type & POINTER)                      /* first level pointer */\r
+               return (type & WORD);\r
+       return 0;                                       /* not a pointer */\r
+}\r
+\r
+/*\r
+ * Output a string to the assembler followed by newline.\r
+ */\r
+static void do_asm(char *ptr)\r
+{\r
+       code_str(ptr);\r
+}\r
+\r
+/***************************\r
+ Initialize static storage\r
+****************************/\r
+\r
+static void init_static(U32 token, U32 value, char word)\r
+{\r
+       char *ptr, *ptr1, *nptr;\r
+       U32  i;\r
+\r
+       ptr = "";\r
+\r
+       if(global_width)                /* continuing definition */\r
+               ptr = ",";\r
+       else {                                  /* new definition */\r
+               if      (word==1) ptr = " DB ";\r
+               else if (word==2) ptr = " DW ";\r
+               else if (word==4) ptr = " DD ";\r
+       }\r
+\r
+       if(token == SYMBOL) {           /* Symbol - MUST BE GLOBAL - NOT EXTERNAL */\r
+               ptr1 = "OFFSET ";\r
+               global_width += 7; }\r
+       else if(token == STRING) {              /* literal pool entry */\r
+               ptr1 = "OFFSET L_lit+";\r
+               *(ptr1+7) = prefix;\r
+               global_width += 23; }\r
+       else if(token == LABEL) {       /* instruction label */\r
+               ptr1 = "L_";\r
+               *ptr1 = prefix;\r
+               global_width += 4; }\r
+       else {                                          /* constant value */\r
+               ptr1 = "";\r
+               global_width += 6; }\r
+\r
+       if (*ptr) data_str(ptr);\r
+       if (*ptr1) data_str(ptr1);\r
+       if (token!=SYMBOL)\r
+               data_num(value);\r
+       else {\r
+               nptr=&GPool[symtab[value].oname];\r
+               data_str(nptr);\r
+               i=0; while(*nptr++) i+=1;\r
+               global_width += i;\r
+        }\r
+\r
+       if(global_width > 60) {\r
+               global_width = 0;\r
+               data_chr('\n');\r
+               }\r
+}\r
+\r
+/********************************\r
+* End static storage definition\r
+*********************************/\r
+static void end_static(void)\r
+{\r
+       if(global_width) {\r
+               data_chr('\n');\r
+               global_width = 0;\r
+       }\r
+}\r
+\r
+/*******************************************************************\r
+* Define a global non-static variable\r
+********************************************************************/\r
+\r
+static void gen_global(U32 symbol, U32 size)\r
+{\r
+       data_global(symbol);\r
+       if(symtab[symbol].type & (POINTER | DWORD)) {\r
+               if (size==4)\r
+                       data_str(" DD 0h\n");\r
+               else {\r
+                       data_str(" DD ");\r
+                       data_num(size/4);\r
+                       data_str(" DUP(0)\n");\r
+                       }\r
+               }\r
+       else\r
+       if(symtab[symbol].type & WORD) {\r
+               if (size==2)\r
+                       data_str(" DW 0h\n");\r
+               else {\r
+                       data_str(" DW ");\r
+                       data_num(size/2);\r
+                       data_str(" DUP(0)\n");\r
+                       }\r
+               }\r
+       else\r
+       if(symtab[symbol].type & (BYTE|STRUCT)) {\r
+               if (size==1)\r
+                       data_str(" DB 0h\n");\r
+               else {\r
+                       data_str(" DB ");\r
+                       data_num(size);\r
+                       data_str(" DUP(0)\n");\r
+                       }\r
+               }\r
+}\r
+\r
+/****************************************************\r
+  Define an external label for DASM near or FAR call\r
+  Print EXTRN _Symname: NEAR in CSeg if NEAR function.\r
+  Print EXTRN _Symname  FWORD in DSeg if FAR function.\r
+*****************************************************/\r
+\r
+static void gen_extern_DASM (U32 symbol)\r
+{\r
+       U32 type;\r
+\r
+       type = symtab[symbol].type;\r
+\r
+       if (type & FAR) {\r
+               data_str("EXTRN ");\r
+               data_chr('_');\r
+               data_str(&GPool[symtab[symbol].oname]);\r
+               data_str(" FWORD");\r
+               data_chr('\n');\r
+       }\r
+       else if (type & FUNCTION)\r
+       {\r
+               code_str("EXTRN ");\r
+               code_chr('_');\r
+               code_str(&GPool[symtab[symbol].oname]);\r
+               code_chr(':');\r
+               code_str(" NEAR");\r
+               code_chr('\n');\r
+       }\r
+\r
+}\r
+\r
+/****************************************************\r
+  Define an external label for DASM data references.\r
+  Print EXTRN _Symname DB (DW or DD) if NOT function.\r
+*****************************************************/\r
+\r
+static void gen_ext_data_DASM (U32 symbol)\r
+{\r
+       U32 type;\r
+\r
+       type = symtab[symbol].type;\r
+\r
+       if (!(type & FUNCTION))\r
+       {\r
+               data_str("EXTRN ");\r
+               data_chr('_');\r
+               data_str(&GPool[symtab[symbol].oname]);\r
+               if (type & (POINTER|DWORD))\r
+                       data_str(" DD");\r
+               else if (type & WORD)\r
+                       data_str(" DW");\r
+               else\r
+                       data_str(" DB");\r
+               data_chr('\n');\r
+       }\r
+}\r
+\r
+/*******************************************************\r
+* Enter function & allocate local variable stack space\r
+********************************************************/\r
+\r
+static void enter_func(U32 symbol, U32 size)\r
+{\r
+       code_global(symbol);\r
+       code_str(":\n");\r
+       if (symtab[fptr].type & ISR)\r
+       {\r
+               out_inst("PUSHAD");\r
+       }\r
+       else {\r
+               out_inst("PUSH EBP");\r
+               out_inst("MOV EBP,ESP");\r
+               if(size) {\r
+                       code_str("\tSUB ESP,");\r
+                       code_num(size);\r
+                       code_chr('\n'); }\r
+       }\r
+}\r
+\r
+/************************************************\r
+* Clean up the stack & end function definition\r
+*************************************************/\r
+\r
+static void end_func(U32 stackpop)\r
+{\r
+       if (symtab[fptr].type & ISR)\r
+       {\r
+                       out_inst("POPAD");\r
+                       out_inst("IRETD");\r
+       }\r
+       else {\r
+               if(local_stack)\r
+                       out_inst("MOV ESP,EBP");\r
+               out_inst("POP EBP");\r
+               if (stackpop) {\r
+                       if (symtab[fptr].type & FAR) code_str("\tRETF ");\r
+                       else code_str("\tRETN ");\r
+                       code_num(stackpop);\r
+               code_chr('\n');\r
+               }\r
+               else if (symtab[fptr].type & FAR) out_inst("\tRETF");\r
+               else out_inst("RETN");\r
+       }\r
+}\r
+\r
+/**********************************\r
+ Define a compiler generated label\r
+***********************************/\r
+\r
+static void gen_label(U32 label)\r
+{\r
+       code_chr(prefix);\r
+       code_chr('_');\r
+       code_num(label);\r
+       code_str(":\n");\r
+}\r
+\r
+/***********************\r
+ Define literal pool\r
+************************/\r
+static void gen_literal(unsigned char *ptr, U32 size)\r
+{\r
+       U32 i;\r
+\r
+       if(size) {\r
+               i = 0;\r
+               data_chr(prefix);\r
+               data_str("_lit");\r
+               while(i < size) {\r
+                       data_str((i % 16) ? "," : " DB ");\r
+                       data_num(*ptr++);\r
+                       if(!(++i % 16))\r
+                       data_chr('\n'); }\r
+               if(i % 16)\r
+                       data_chr('\n'); }\r
+}\r
+\r
+/***********************************\r
+* Call a function by name\r
+************************************/\r
+static void call(U32 token, U32 value, U32 type, U32 offset, U32 clean)\r
+{\r
+\r
+       token = CheckStack(token);\r
+       if (type & FAR)\r
+       {\r
+                       code_str("\tCALL FWORD PTR ");\r
+       }\r
+       else code_str("\tCALL ");\r
+       if(token == NUMBER)\r
+               code_num(value);\r
+       else\r
+               write_oper(token, value, type, offset);\r
+       code_chr('\n');\r
+\r
+       if(clean)\r
+       {       /* clean up stack following function call */\r
+               clean *=4;                              /* each stack operand is 4 bytes */\r
+               code_str("\tADD ESP,");\r
+               code_num(clean);\r
+               code_chr('\n');\r
+       }\r
+\r
+       zero_flag = -1;\r
+\r
+}\r
+\r
+/**********************************\r
+* Unconditional jump to label\r
+***********************************/\r
+\r
+static void jump(U32 label, char ljmp)\r
+{\r
+       code_str(ljmp ? "\tJMP " : "\tJMP SHORT ");\r
+       code_chr(prefix);\r
+       code_chr('_');\r
+       code_num(label);\r
+       code_chr('\n');\r
+}\r
+\r
+/****************************************\r
+* Conditional jump to label\r
+*****************************************/\r
+static void jump_if(char cond, U32 label, char ljmp)\r
+            /* condition TRUE or FALSE, destination, long jump required */\r
+{\r
+       if (ljmp) code_str(cond ? "\tJNZ " : "\tJZ ");\r
+       else code_str(cond ? "\tJNZ SHORT " : "\tJZ SHORT ");\r
+       code_chr(prefix);\r
+       code_chr('_');\r
+       code_num(label);\r
+       code_chr('\n');\r
+}\r
+\r
+/***********************************************\r
+ JUMP to the begining of the switch jump table\r
+************************************************/\r
+static void do_switch(U32 label)\r
+{\r
+       code_str("\tJMP ");\r
+       code_chr(prefix);\r
+       code_chr('_');\r
+       code_num(label);\r
+       code_chr('\n');\r
+}\r
+\r
+/*************************************************\r
+* Build switch compare/jump table.\r
+* d is the count of switch jump table entries.\r
+**************************************************/\r
+\r
+static void build_switch(U32 d)\r
+{\r
+       while(switch_ptr > d) {\r
+               code_str("\tCMP EAX,");\r
+               code_num(switch_stack[--switch_ptr]);\r
+               code_chr('\n');\r
+               code_str("\tJE ");\r
+               code_chr(prefix);\r
+               code_chr('_');\r
+               code_num(switch_stack[--switch_ptr]);\r
+               code_chr('\n');\r
+       }\r
+}\r
+\r
+\r
+/********************************************\r
+ Load index register with a pointer value\r
+*********************************************/\r
+\r
+static void index_ptr(U32 token, U32 value, U32 type, U32 offset)\r
+{\r
+       if(token == INEAX)\r
+       {\r
+               out_inst("MOV ESI,EAX");\r
+       }\r
+       else if (token==PESI)\r
+               return;\r
+       else\r
+       {\r
+               token = CheckStack(token);\r
+               code_str("\tMOV ESI,");\r
+               write_oper(token, value, type, offset);\r
+               code_str("\n");\r
+       }\r
+}\r
+\r
+/************************************************\r
+ Load index register with the address of a symbol\r
+*************************************************/\r
+\r
+static void index_adr(U32 token, U32 value, U32 type, U32 offset)\r
+{\r
+       if (token != PESI)\r
+       {\r
+               code_str((type & GLOBAL) ? "\tMOV ESI,OFFSET " : "\tLEA ESI,");\r
+               write_oper(token, value, type, offset);\r
+               code_str("\n");\r
+       }\r
+}\r
+\r
+/**********************************\r
+* Output a global code symbol name\r
+***********************************/\r
+\r
+static void code_global(U32 symbol)\r
+{\r
+char *ptr;\r
+       ptr = &GPool[symtab[symbol].oname];\r
+       if(!(symtab[symbol].type & STATIC))\r
+       {\r
+               code_str("PUBLIC ");\r
+       }\r
+       code_chr('_');\r
+       code_str(ptr);\r
+}\r
+\r
+/**********************************\r
+* Output a global data symbol name\r
+***********************************/\r
+\r
+static void data_global(U32 symbol)\r
+{\r
+char *ptr;\r
+       ptr = &GPool[symtab[symbol].oname];\r
+       if(!(symtab[symbol].type & STATIC))\r
+       {\r
+               data_str("PUBLIC ");\r
+       }\r
+       data_chr('_');\r
+       data_str(ptr);\r
+}\r
+\r
+\r
+/**********************************************\r
+ CODE FILE OUTPUT ROUTINES\r
+***********************************************/\r
+\r
+/***************************************\r
+ Write a char to the code tmp file\r
+***************************************/\r
+\r
+void code_chr(char chr)\r
+{\r
+    pcodebuf[pc++] = chr;\r
+    if (pc >= 512000-1)\r
+    {\r
+               printf("Code buffer overflow... (512000 bytes)\r\n");\r
+               exit(1);\r
+       }\r
+}\r
+\r
+/****************************************\r
+  Write a string to the code tmp file \r
+*****************************************/\r
+\r
+void code_str(char *ptr)\r
+{\r
+       while(*ptr)\r
+               code_chr(*ptr++);\r
+}\r
+\r
+/********************************\r
+* Write a number to the code buf\r
+*********************************/\r
+\r
+void code_num(U32 value)\r
+{\r
+       char stack[10];\r
+       U32 i;\r
+\r
+       if(value & 0x80000000) {\r
+               code_chr('-');\r
+               value = -value; }\r
+\r
+       i = 0;\r
+       do\r
+               stack[i++] = (value % 10) + '0';\r
+       while(value /= 10);\r
+\r
+       while(i)\r
+               code_chr(stack[--i]);\r
+}\r
+\r
+/**********************************************\r
+ ASM FILE OUTPUT ROUTINES (INITIAL DATA SEG)\r
+***********************************************/\r
+\r
+/* Write a char to the asm file (all data) */\r
+\r
+void data_chr(char chr)\r
+{\r
+    databuf[pd++] = chr;\r
+    if (pd > 4095)\r
+    {\r
+               fwrite(databuf, 4096, 1, asm_fh);\r
+               pd = 0;\r
+       }\r
+}\r
+\r
+/* Write a string to the asm file (all data) */\r
+\r
+void data_str(char *ptr)\r
+{\r
+       while(*ptr)\r
+               data_chr(*ptr++);\r
+}\r
+\r
+/********************************\r
+* Write a number to the data buf\r
+*********************************/\r
+\r
+void data_num(U32 value)\r
+{\r
+       char stack[10];\r
+       U32 i;\r
+\r
+       if(value & 0x80000000) {\r
+               data_chr('-');\r
+               value = -value; }\r
+\r
+       i = 0;\r
+       do\r
+               stack[i++] = (value % 10) + '0';\r
+       while(value /= 10);\r
+\r
+       while(i)\r
+               data_chr(stack[--i]);\r
+}\r
+\r
+\r
+/********************************\r
+* Write a number to file\r
+*********************************/\r
+\r
+void put_num(U32 value, FILE *outfile)\r
+{\r
+       char stack[10];\r
+       U32 i;\r
+\r
+       if(value & 0x80000000) {\r
+               fputc('-', outfile);\r
+               value = -value; }\r
+\r
+       i = 0;\r
+       do\r
+               stack[i++] = (value % 10) + '0';\r
+       while(value /= 10);\r
+\r
+       while(i)\r
+               fputc(stack[--i], outfile);\r
+}\r
+\r
+/***************************************\r
+* Process a language statement\r
+****************************************/\r
+\r
+static void statement(U32 token)\r
+{\r
+       U32 a, b, c, d;\r
+\r
+       test_exit();            /* generate any preceeding exit */\r
+\r
+       switch(token) \r
+       {               /* act upon the token */\r
+               case SEMI:              /* ';' - null statement */\r
+                       check_func();\r
+                       return;\r
+               case OCB:               /* '{' - begin a block */\r
+                       while((token = get_token()) != CCB)\r
+                               statement(token);\r
+                       break;\r
+               case INT:               /* 16/32 integer variable declaration */\r
+               case CHAR:              /* 8 bit variable declaration */\r
+               case SHORT:             /* 16 bit variable declaration */\r
+               case LONG:              /* 32 bit variable declaration */\r
+               case SIGNED:    /* signed variable declaration (the default anyway)*/\r
+               case UNSIGN:    /* unsigned variable declaration */\r
+               case STAT:              /* static modifier */\r
+               case STRUC:             /* structure declaration */\r
+               case EXTERN:    /* external modifier */\r
+               case REGIS:             /* register modifier */\r
+               case INTR:              /* interrupt modifier for functions */\r
+               case VOIDD:             /* void for function, and empty args */\r
+                       declare(token, 0);\r
+                       break;\r
+               case IF:\r
+                       check_func();\r
+                       expect(ORB);\r
+                       eval(CRB, 0);\r
+                       cond_jump(FALSE, a = ++next_lab, -1);\r
+                       statement(get_token());\r
+                       if(test_token(ELSE)) {\r
+                               test_jump(b = ++next_lab);\r
+                               gen_label(a);\r
+                               a = b;\r
+                               statement(get_token()); }\r
+                       test_exit();\r
+                       gen_label(a);\r
+                       break;\r
+               case WHILE:\r
+                       check_func();\r
+                       gen_label(continue_stack[loop_ptr] = a = ++next_lab);\r
+                       break_stack[loop_ptr++] = b = ++next_lab;\r
+                       expect(ORB);\r
+                       eval(CRB, 0);\r
+                       cond_jump(FALSE, b, -1);\r
+                       statement(get_token());\r
+                       test_jump(a);\r
+                       gen_label(b);\r
+                       --loop_ptr;\r
+                       break;\r
+               case DO:\r
+                       check_func();\r
+                       gen_label(a = ++next_lab);\r
+                       continue_stack[loop_ptr] = b = ++next_lab;\r
+                       break_stack[loop_ptr++] = c = ++next_lab;\r
+                       statement(get_token());\r
+                       gen_label(b);\r
+                       expect(WHILE);\r
+                       eval(SEMI, 0);\r
+                       cond_jump(TRUE, a, -1);\r
+                       gen_label(c);\r
+                       --loop_ptr;\r
+                       break;\r
+               case FOR:\r
+                       check_func();\r
+                       expect(ORB);\r
+                       if(!test_token(SEMI))                   /* initial */\r
+                               eval(SEMI, -1);\r
+                       gen_label(d = a = ++next_lab);\r
+                       break_stack[loop_ptr] = b = ++next_lab;\r
+                       if(!test_token(SEMI)) {                 /* test */\r
+                               eval(SEMI, 0);\r
+                               cond_jump(FALSE, b, -1); }\r
+                       if(!test_token(CRB)) \r
+                       {                       /* end */\r
+                               jump(c = ++next_lab, 0);\r
+                               gen_label(d = ++next_lab);\r
+                               eval(CRB, -1);\r
+                               jump(a, 0);\r
+                               gen_label(c); \r
+                       }\r
+                       continue_stack[loop_ptr++] = d;\r
+                       statement(get_token());\r
+                       test_jump(d);\r
+                       gen_label(b);                                   /* exit */\r
+                       --loop_ptr;\r
+                       break;\r
+               case SWITCH:\r
+                       check_func();\r
+                       a = sdefault;\r
+                       break_stack[loop_ptr++] = sdefault = b = ++next_lab;\r
+                       expect(ORB);\r
+                       eval(CRB, -1);\r
+                       do_switch(c = ++next_lab);\r
+                       d = switch_ptr;\r
+                       statement(get_token());\r
+                       test_jump(b);\r
+                       gen_label(c);\r
+                       build_switch(d);\r
+                       if (sdefault!=a) jump(sdefault, -1);\r
+                       gen_label(b);\r
+                       --loop_ptr;\r
+                       sdefault = a;\r
+                       break;\r
+               case CASE:\r
+                       a = check_switch();\r
+                       get_constant(&b, &c);\r
+                       switch_stack[switch_ptr++] = a;  /* RAB reversed a & c */\r
+                       switch_stack[switch_ptr++] = c;\r
+                       if(switch_ptr >= (MAX_SWITCH*2))\r
+                               fatal_error("Too many active cases");\r
+                       expect(COLON);\r
+                       break;\r
+               case DEFAULT:\r
+                       sdefault = check_switch();\r
+                       expect(COLON);\r
+                       break;\r
+               case RETURN:\r
+                       check_func();\r
+                       if(!test_token(SEMI))\r
+                       {\r
+                               eval(SEMI, -1);\r
+                       }\r
+                       exit_flag = exit_label ? exit_label : (exit_label = ++next_lab);\r
+                       break;\r
+               case BREAK:\r
+                       check_loop(break_stack);\r
+                       break;\r
+               case CONTIN:\r
+                       check_loop(continue_stack);\r
+                       break;\r
+               case GOTO:\r
+                       check_func();\r
+                       if(get_token() != SYMBOL) {\r
+                               syntax_error();\r
+                               break; }\r
+                       if(a = lookup_local()) {\r
+                               if(!(a & GLABEL))\r
+                                       type_error(); }\r
+                       else\r
+                               define_symbol(REFERENCE|GLABEL, ++next_lab);\r
+                       jump(symtab[sptr].dindex, -1);\r
+                       break;\r
+               case SYMBOL:    /* a symbol table entry */\r
+                       if(!in_function) {              /* global definition */\r
+                               declare(token, 0);\r
+                               break; }\r
+                       if(*input_ptr == ':') {         /* label definition */\r
+                               check_func();\r
+                               ++input_ptr;\r
+                               if(lookup_local())\r
+                                       symtab[sptr].type &= ~EXTERNAL;\r
+                               else\r
+                                       define_symbol(GLABEL, ++next_lab); /* sets sptr */\r
+                               gen_label(symtab[sptr].dindex);\r
+                               break;\r
+                        }\r
+               default:                /* expression evaluation */\r
+                       check_func();\r
+                       unget_token(token);\r
+                       eval(SEMI, -1);\r
+       }\r
+}\r
+\r
+\r
+/*********************************************************\r
+* Main compile loop, process statements until end of file\r
+**********************************************************/\r
+\r
+static void compile(void)\r
+{\r
+       define_ptr = define_pool;\r
+       *(input_ptr = line_in) = 0;\r
+       if (!fGen) {\r
+               code_str("\n\n.CODE\n");\r
+               data_str("\n.DATA\n");\r
+               }\r
+       for(;;)\r
+               statement(get_token());\r
+}\r
+\r
+/****************************************************\r
+* Initialize I/O & execute compiler  MAIN MAIN MAIN\r
+*****************************************************/\r
+\r
+void main(S32 argc, char *argv[])\r
+{\r
+       U32 i, erc;\r
+       char *ptr, *pname;\r
+\r
+/* first, get a BIG code buffer!! */\r
+\r
+       erc = AllocPage(SCODEBUF/4096, &pcodebuf);\r
+       if (erc)\r
+               printf("Not enough memory to allocate %d bytes.\r\n", SCODEBUF);\r
+\r
+       /* extern far U32 DeAllocPage(U8 *pOrigMem, U32 nPages); */\r
+\r
+/* first process any filenames and command line options */\r
+\r
+       list_fh = stdout;       /* default the list file */\r
+\r
+       for(i=1; i < argc; ++i) {       /* start at arg 1 */\r
+               ptr = argv[i];\r
+               if (*ptr == '/') {\r
+                 ptr++;\r
+                 switch(*ptr) {\r
+                       case 'S' :                      /* quiet mode */\r
+                       case 's' :\r
+                               fQuiet = 1;\r
+                               break;\r
+                       case 'L' :                      /* List file ON */\r
+                       case 'l' :\r
+                               fList = 1;\r
+                               break;\r
+                       case 'E' :                      /* Embedded source mode */\r
+                       case 'e' :\r
+                               fSource = 1;\r
+                               break;\r
+                       case 'G' :                      /* Generate separate modules */\r
+                       case 'g' :\r
+                               fGen = 1;\r
+                               break;\r
+                       case 'N' :                      /* NO optimize */\r
+                       case 'n' :\r
+                               fNoOpt = 1;\r
+                               break;\r
+                       case 'O' :                      /* Optimize for speed */\r
+                       case 'o' :\r
+                               fOptS = 1;\r
+                               break;\r
+                       case 'W' :                      /* Warnings ON */\r
+                       case 'w' :\r
+                               fWarnings = 1;\r
+                               break;\r
+                       case 'P' :                      /* Prefix label character */\r
+                       case 'p' :\r
+                               ptr++;\r
+                               if (!is_alpha(*ptr))\r
+                                       fatal_error("Invalid label prefix character");\r
+                               prefix = *ptr;\r
+                               break;\r
+                       default:\r
+                               fatal_error("Invalid switch");\r
+                               break;\r
+                 }\r
+               }\r
+               else {\r
+                       if(!source_fh) {\r
+                               copystring(srcname, argv[i]);\r
+                               source_fh = fopen(argv[i], "r");\r
+                               }\r
+                       else if(!asm_fh) {\r
+                               copystring(asmname, argv[i]);\r
+                               if(!(asm_fh = fopen(argv[i], "w"))) {\r
+                                 fputs("Error: Can't open ASM file\n", stdout);\r
+                                 exit(-1);\r
+                                 }\r
+                               }\r
+                       else\r
+                               fatal_error("Too many parameters");\r
+          }\r
+       }\r
+\r
+/* Input file not explicitly named errors out */\r
+       if(!source_fh) {                                /* default to standard input */\r
+               fputs("C Minus 32 Compiler, Version 2.3M\r\n", stdout);\r
+               fputs("Usage: SourceFile [AsmFile] /S /E /G /L /W /Px\r\n", stdout);\r
+               fputs("/S  Suppress screen output (e.g., herald)\r\n", stdout);\r
+               fputs("/E  Embed source in ASM output\r\n", stdout);\r
+               fputs("/G  Generate separate Code & Data files\r\n", stdout);\r
+               fputs("/L  List file generated for errors\r\n", stdout);\r
+               fputs("/N  No optimization\r\n", stdout);\r
+               fputs("/O  Optimize for speed.\r\n", stdout);\r
+               fputs("/W  Warnings ON\r\n", stdout);\r
+               fputs("/Px Label prefix character (x=Label char)\r\n\n", stdout);\r
+               fputs("Error: Source filename required\r\n", stdout);\r
+               exit(-1);\r
+               }\r
+\r
+/* Output file not explicitly named defaults to Source.asm */\r
+\r
+       if(!asm_fh)     \r
+       {                                       /* default asm name to SourceName.asm */\r
+               copystring(asmname, srcname);\r
+               pname=asmname;\r
+               while ((*pname != '.') && (*pname!= '\0')) pname++;\r
+\r
+               if (fGen)\r
+               {\r
+                       *pname++ = '.';\r
+                       *pname++ = 'D';\r
+                       *pname++ = 'A';\r
+                       *pname++ = 'S';\r
+               }\r
+               else\r
+               {\r
+                       *pname++ = '.';\r
+                       *pname++ = 'A';\r
+                       *pname++ = 'S';\r
+                       *pname++ = 'M';\r
+               }\r
+               *pname   = '\0';\r
+               if(!(asm_fh = fopen(asmname, "w"))) \r
+               {\r
+                       fputs("Error: Can't open ASM file\r\n", stdout);\r
+                       exit(-1);\r
+               }\r
+       }\r
+       fASMOpen = TRUE;\r
+\r
+/* If -L then List file named Source.LST is generated. */\r
+\r
+       if (fList)\r
+       {\r
+               copystring(lstname, srcname);\r
+               pname=lstname;\r
+               while ((*pname != '.') && (*pname!= '\0')) pname++;\r
+               *pname++ = '.';\r
+               *pname++ = 'L';\r
+               *pname++ = 'S';\r
+               *pname++ = 'T';\r
+               *pname   = '\0';\r
+               if(!(list_fh = fopen(lstname, "w")))\r
+                                       fatal_error("Cannot open LIST file");\r
+               else fLISTOpen = TRUE;\r
+       }\r
+\r
+       /* open code segment tmp file  or Gen file */\r
+\r
+       if (fGen)\r
+       {\r
+               copystring(codename, srcname);\r
+               pname=codename;\r
+               while ((*pname != '.') && (*pname!= '\0')) pname++;\r
+               *pname++ = '.';\r
+               *pname++ = 'C';\r
+               *pname++ = 'A';\r
+               *pname++ = 'S';\r
+               *pname   = '\0';\r
+               if(!(code_fh = fopen(codename, "w")))\r
+                                       fatal_error("Cannot open Code file");\r
+               else fCODEOpen = TRUE;\r
+       }\r
+\r
+       if(!fQuiet)\r
+               fputs("C Minus 32 Compiler, Version 2.3M\r\n", stdout);\r
+\r
+       compile();\r
+}\r