--- /dev/null
+/*\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