]> pd.if.org Git - mmurtl/blob - msamples/cm32m/cm32.c
autocommit for file dated 1995-02-09 16:30:42
[mmurtl] / msamples / cm32m / cm32.c
1 /*\r
2  C Minus 32 (C-32) Compiler  (DOS version)\r
3 \r
4  Derived from code Copyright (c) 1989, Dave Dunfield\r
5  Copyright (c) 1991, 1992, 1993, 1994, 1995 R.A. Burgess\r
6  Permission is required from the authors for\r
7  any commercial use of this source code.\r
8 \r
9  32 bit assembly language generation specificly for the Intel 386/486\r
10  for the DASM assembler.\r
11 \r
12  CM-32 integer support:\r
13  short = int = short int = 16 bits,\r
14  long = long int = 32 bits.\r
15 \r
16  16 bit Intel addressing modes are NOT supported for code generation.\r
17 \r
18 */\r
19 \r
20 /* These Simple defines to keep down the number of keystrokes. Also\r
21    lessens that horrible burden of portability that C is supposed to\r
22    shield you from (right...)\r
23 */\r
24 \r
25 #define U32 unsigned long\r
26 #define S32 long\r
27 #define U16 unsigned int\r
28 #define S16 int\r
29 #define U8 unsigned char\r
30 #define S8 char\r
31 \r
32 #include <ctype.h>\r
33 #include <stdio.h>\r
34 #include <string.h>\r
35 #include <stdlib.h>\r
36 #include "CM32.h"\r
37 #include "Tokens32.h"\r
38 \r
39 #include "\OSSource\MMemory.h"\r
40 \r
41 #define SCODEBUF 512000         /* 500Kb allocated buffer */\r
42 U8 *pcodebuf;\r
43 \r
44 /* Input buffer & input pointer for preprocessed lines */\r
45 char line_in[LINE_MAX], *input_ptr;\r
46 \r
47 /* Global value storage locations (results from lexical scanner) */\r
48 \r
49 char gst[SYMBOL_SIZE+1];        /* Name if SYMBOL */\r
50 U8  namesize;                           /* size of SYMBOL name */\r
51 U32 gvalue;\r
52 \r
53 /*\r
54    if token = SYMBOL then gvalue is length (number of characters).\r
55    if token = NUMBER then gvalue is value of NUMBER.\r
56    if token = STRING then gvalue is index into literal pool to the string.\r
57 */\r
58 \r
59 /* Symbol table and associated variables */\r
60 \r
61 char GPool[GBUFFSIZE];  /* Pool for symbol names (packed) */\r
62 char LPool[LBUFFSIZE];  /* Pool for local symbol names (packed) */\r
63 \r
64 struct sym {\r
65         U32 type;               /* 32 symbol type bits  */\r
66         U32 itypedef;   /* index in symtab for type definition, or zero */\r
67                                         /* If strucmem, struct it belongs to */\r
68         U32 oname;              /* offset in pool to sym name */\r
69         U32 argoffset;  /* arg offset from EBP for locals */\r
70         U32 strucoff;   /* size of strucdef (also offset for next new member), */\r
71                                         /*       if strucmem, it's member's offset in structure */\r
72         U32     dindex;         /* rg for index to dim */\r
73         };                              /* or index to proto list for arg types */\r
74                                         /* or holds labels for for local Goto */\r
75 \r
76 struct sym symtab[MAX_SYMBOLS];  /* SYM TABLE... */\r
77 \r
78 U32 oNextGName = 0;             /* offset to next new name in global pool */\r
79 U32 oNextLName = 0;             /* offset to next new name in local pool */\r
80 \r
81 U32 proto_list[MAX_PROTOS],     /* list of arg types for functions */\r
82         global_top = 0,\r
83         global_count = 0,\r
84         iproto_next = 1,                /* index to next available proto args (0 illegal)*/\r
85         icrntpro = 0,                   /* index to arg being tested */\r
86         iarg = 0,\r
87         argtype = 0,\r
88         local_top = MAX_SYMBOLS,\r
89         arg_count,                              /* number of args so far  */\r
90         local_stack,\r
91         sptr,                                   /* symbol ptr */\r
92         fptr;                                   /* ptr to function symbol we are in */\r
93 \r
94         /* structure definition use and control variables */\r
95 \r
96         S8 fInStruct = 0;       /* true if currently defining struct members */\r
97     U32 CrntStrucDef;   /* iSym for Structure def we are using or working on */\r
98         char structname[12] = "0StructDef";\r
99         U8 NxtStrucNum = 0;\r
100         U32 memoffset;          /* used to calculate members offset */\r
101     U32 strucsize;          /* used for size of struct in INC and DEC */\r
102 /* Literal + Dimension pools and associated variables */\r
103 \r
104 U32 dim_top = 0,\r
105     literal_top = 0,\r
106     dim_pool[DIM_SIZE];         /* each entry has nDims for an array */\r
107 \r
108 \r
109 char literal_pool[LITER_BUFF];\r
110 \r
111 /* Expression evaluation stack. The value field contents vary\r
112    depending on what the token is. If it's a Symbol, this is\r
113    the symbol table entry. If token is a number then value is\r
114    the actual value of the number.  If it's a string, then\r
115    value is the length.\r
116    The offset is used to hold constant values for addresses\r
117    that are in the index register or on the stack. \r
118    When accessing the data pointed to, if this is NON-zero,\r
119    we use the [ESI+NUM] addressing mode (Base+Offset). */\r
120 \r
121 struct expr {\r
122         U32 token;              /* Number, Symbol, String, In-Accumulator, etc. */\r
123         U32 value;              /* varies depending on token */\r
124         U32 type;               /* type from symtab */\r
125         U32 offset;             /* Offset of pointer in structure for access */\r
126         };\r
127 \r
128 struct expr expstk[EXPR_DEPTH];  /* Expression Stack */\r
129 \r
130 U32 expr_ptr = 0;\r
131 \r
132 /* Misc. global variables */\r
133 \r
134 char if_flag = 0,\r
135      asm_flag = 0,\r
136      not_flag = 0,\r
137          prefix = 'L';                          /* override with /P:x switch */\r
138 \r
139 U32 break_stack[LOOP_DEPTH],\r
140         continue_stack[LOOP_DEPTH],\r
141         switch_stack[MAX_SWITCH*2],\r
142         exit_label = 0,\r
143         exit_used = 0,\r
144         in_function = 0,\r
145         loop_ptr = 0,\r
146         switch_ptr = 0,\r
147         define_top = 0,\r
148         sdefault = 0,\r
149         exit_flag = 0,\r
150         next_lab = 0,\r
151         line_number = 0,\r
152         begin_comment = 0,      /* line that a comment starts on for errors */\r
153         ungot_token = 0,\r
154         error_count = 0,\r
155         warn_count = 0;\r
156 \r
157 \r
158         /* input/output pointers and buffer for for preprocessor */\r
159 \r
160 char buffer[LINE_MAX],\r
161          *buffin_ptr,\r
162          *buffout_ptr;\r
163 \r
164         /* macro definition: index, pool and top pointers */\r
165 \r
166 U32  macro = 0;\r
167 char *define_index[MACROS],\r
168       define_pool[MAC_BUFF],\r
169      *define_ptr;\r
170 \r
171         /* macro parameter: index, pool and top pointers */\r
172 unsigned parm;\r
173 char *parm_index[PARAMETERS],\r
174       parm_pool[PARM_BUFF],\r
175      *parm_ptr;\r
176 \r
177         /* include: line stack & count, file pointers, filename */\r
178 long include = 0,\r
179          incl_line[INCL_DEPTH];\r
180 \r
181 FILE *incl_fh[INCL_DEPTH],\r
182          *source_fh = 0,\r
183          *asm_fh = 0,\r
184      *code_fh = 0,\r
185          *list_fh = 0;\r
186 \r
187 char codename[40];\r
188 char srcname[40];\r
189 char asmname[40];\r
190 char lstname[40];\r
191 \r
192 /* file open flags */\r
193 \r
194 char fLISTOpen = 0,\r
195      fTEMPOpen = 0,\r
196      fCODEOpen = 0,\r
197      fASMOpen = 0;\r
198 \r
199         /* misc. variables and flags */\r
200 char comment_flag = -1,\r
201          fQuiet = 0,\r
202      fSource = 0,\r
203      fNoOpt = 0,\r
204      fOptS = 0,\r
205      fList = 0,\r
206      fGen = 0,\r
207      fWarnings = 0;\r
208 \r
209         /* inlcude path */\r
210 \r
211 char *incdir = "\\CM32\\INCLUDE";\r
212 \r
213 /* For Code Gen */\r
214 \r
215 U32     global_width = 0,\r
216         asmlab = 0;\r
217 \r
218 char zero_flag,\r
219      stack_flag = 0;\r
220 \r
221 U8 databuf[4096];\r
222 U32 pc = 0;                     /* code pointer in */\r
223 U32 pco = 0;            /* code pointer out */\r
224 U32 pd = 0;\r
225 \r
226 #include "Optimize.h"\r
227 #include "Proto32.h"\r
228 \r
229 /******************************************\r
230 * Determine if a character is alphabetic\r
231 * or is underscore.\r
232 *******************************************/\r
233 \r
234 static char is_alpha(char chr)\r
235 {\r
236         return (((chr|0x20) >= 'a') && ((chr|0x20) <= 'z'))\r
237                 || (chr == '_');\r
238 }\r
239 \r
240 /*********************************************\r
241 * Determine if a character is a numeric digit\r
242 **********************************************/\r
243 \r
244 static char is_digit(char chr)\r
245 {\r
246         return (chr >= '0') && (chr <= '9');\r
247 }\r
248 \r
249 /******************************************\r
250 * Test for valid character in a name.(MACRO)\r
251 *******************************************/\r
252 \r
253 #define is_alnum(c)     (is_alpha(c) || is_digit(c))\r
254 /*\r
255 static char is_alnum(char c)\r
256 {\r
257         return is_alpha(c) || is_digit(c);\r
258 }\r
259 */\r
260 \r
261 /****************\r
262 * Copy a string\r
263 *****************/\r
264 \r
265 static void copystring(char *dest, char *source)\r
266 {\r
267         while(*dest++ = *source++);\r
268 }\r
269 \r
270 \r
271 /***************************\r
272 * Test for string equality\r
273 ****************************/\r
274 \r
275 static char equal_string(char *str1, char *str2)\r
276 {\r
277         do {\r
278                 if(*str1 != *str2++)\r
279                 return 0; }\r
280         while(*str1++);\r
281         return -1;\r
282 }\r
283 \r
284 /*********************************************************\r
285  Skip to next non-blank (space, tab, CR or LF) in buffer\r
286  returning the character we find.\r
287 ***********************************************************/\r
288 \r
289 static char skip_blanks(void)\r
290 {\r
291         while((*buffin_ptr < 0x21) && (*buffin_ptr))\r
292                 ++buffin_ptr;\r
293         return *buffin_ptr;\r
294 }\r
295 \r
296 /***************************************\r
297 * Test for more macro parameters\r
298 ****************************************/\r
299 \r
300 static long more_parms(void)\r
301 {\r
302         register char c;\r
303 \r
304         if(((c = skip_blanks()) == ',') || (c == ')'))\r
305                 ++buffin_ptr;\r
306         else\r
307                 line_error("Invalid macro parameter");\r
308         return c == ',';\r
309 }\r
310 \r
311 /**************************************\r
312 * Skip ahead through a comment\r
313 ***************************************/\r
314 \r
315 static void skip_comment(void)\r
316 {\r
317         register U16 x;\r
318         register char c;\r
319 \r
320         x = 0;\r
321         for(;;) {\r
322                 if(!(c = *buffin_ptr++)) {                                      /* end of line_in */\r
323                         if(!fgets(buffin_ptr = buffer, LINE_MAX, source_fh)) {\r
324                                 *buffin_ptr = 0;\r
325                                 UTC_error();\r
326                                 return; }\r
327                         ++line_number; }\r
328                 else {\r
329                         if((x = (x << 8) + c) == (('*' << 8) + '/'))    /* close */\r
330                                 return;\r
331                         if(x == (('/' << 8) + '*'))                             /* imbedded comment */\r
332                                 skip_comment();\r
333                 }\r
334         }\r
335 }\r
336 \r
337 /*****************************************************************\r
338 * Copy a named symbol from the input buffer to the output buffer\r
339 ******************************************************************/\r
340 \r
341 static void copy_name(void)\r
342 {\r
343         do\r
344                 *buffout_ptr++ = *buffin_ptr++;\r
345         while(is_alnum(*buffin_ptr));\r
346         *buffout_ptr = 0;\r
347 }\r
348 \r
349 /******************************************************************\r
350 * Copy a quoted string from the input buffer to the output buffer\r
351 * with regard for "protected" characters.\r
352 *******************************************************************/\r
353 \r
354 static void copy_string(void)\r
355 {\r
356         register char delim;\r
357 \r
358         if(((delim = *buffin_ptr) == '"') || (delim == 0x27)) {\r
359                 do {\r
360                         if(!(*buffout_ptr++ = *buffin_ptr)) {           /* premature end */\r
361                                 line_error("Unterminated string");\r
362                                 return; }\r
363                         if(*buffin_ptr++ == '\\')                               /* protected char */\r
364                                 *buffout_ptr++ = *buffin_ptr++; }\r
365                 while(*buffin_ptr != delim);\r
366                 *buffout_ptr++ = *buffin_ptr++; }\r
367 }\r
368 \r
369 /**************************************************************\r
370 * Lookup a word from the input stream to see if it is a macro\r
371 ***************************************************************/\r
372 \r
373 static U32 lookup_macro(char eflag)\r
374 {\r
375         register long i;\r
376         register char *name;\r
377 \r
378         name = buffout_ptr;\r
379         copy_name();\r
380         for(i = macro - 1; i >= 0; --i)                 /* look it up */\r
381                 if(!strcmp(name, define_index[i]))\r
382                         return i;\r
383         if(eflag)                                                               /* not found */\r
384                 line_error("Undefined macro");\r
385         return -1;\r
386 }\r
387 \r
388 /**************************************************************\r
389 * Resolve a word into a macro definition (if it is defined)\r
390 ***************************************************************/\r
391 \r
392 static void resolve_macro(void)\r
393 {\r
394         char *mptr, *ptr, *old_ptr;\r
395         long i;\r
396         register char c;\r
397 \r
398         old_ptr = buffout_ptr;\r
399         if((i = lookup_macro(0)) != -1) {       /* Substitution required */\r
400                 mptr = define_index[i];\r
401                 while(*mptr++);\r
402                 parm = 0;\r
403                 parm_ptr = parm_pool;\r
404                 if(*mptr++) {                                   /* parameterized macro */\r
405                         if(skip_blanks() == '(') {\r
406                                 ++buffin_ptr;\r
407                                 do {\r
408                                         parm_index[parm++] = parm_ptr;\r
409                                         while(*buffin_ptr && (*buffin_ptr != ',') && (*buffin_ptr != ')'))\r
410                                                 *parm_ptr++ = *buffin_ptr++;\r
411                                         *parm_ptr++ = 0; }\r
412                                 while(more_parms()); } }\r
413                 while(c = *mptr) {                              /* copy over definition */\r
414                         if(c & 0x80) {                          /* parameter substitution */\r
415                                 if((i = c & 0x7f) < parm) {\r
416                                         for(ptr = parm_index[i]; *ptr; ++ptr)\r
417                                                 *old_ptr++ = *ptr; } }\r
418                         else\r
419                                 *old_ptr++ = *mptr;\r
420                         ++mptr;\r
421                 }\r
422                 *(buffout_ptr = old_ptr) = 0;\r
423         }\r
424 }\r
425 \r
426 /****************************************\r
427 * Test for a string in input stream\r
428 *****************************************/\r
429 \r
430 static unsigned long match(char *ptr)\r
431 {\r
432         register char *ptr1;\r
433 \r
434         ptr1 = buffin_ptr;\r
435         while(*ptr)\r
436                 if(*ptr++ != *ptr1++)           /* symbols do not match */\r
437                         return 0;\r
438         if(is_alnum(*ptr1))                     /* symbol continues */\r
439                 return 0;\r
440         buffin_ptr = ptr1;\r
441         skip_blanks();\r
442         return(1);\r
443 }\r
444 \r
445 /*******************************************************\r
446 * Compare all optimization table entries with the\r
447 * instructions in the peephole buffer.\r
448 * Return:       0       = No match\r
449 *           n   = Full match begining at peep_top\r
450 *                                 and ending at entry 'n'\r
451 ********************************************************/\r
452 \r
453 static long compareT(char *ptable, long peep)\r
454 {\r
455         int i;\r
456         char *ptr1, *ptr2, c;\r
457 \r
458         for(i=0; i < OSYMBOLS; ++i)\r
459                 symbols[i][0] = 0;\r
460 \r
461         ptr1 = peep_buffer[peep];\r
462         while(c = *ptable) {                    /* any chars left in entry? */\r
463                 if(c == '\n') {                         /* end of line in table entry */\r
464                         if(*ptr1)                               /* and no match... */\r
465                                 return 0;\r
466             peep = (peep+1) % OBUF_SIZE;\r
467                         if(peep == peep_next)\r
468                                 return 0;\r
469                         ptr1 = peep_buffer[peep];       /* next buffer entry */\r
470                 }\r
471                 else if (c == ' ')  {           /* space */\r
472                         if(!isspace(*ptr1))\r
473                                 return 0;\r
474                         while(isspace(*ptr1))\r
475                                 ++ptr1; }\r
476                 else if(c & 0x80) {                     /* symbol name */\r
477 \r
478                         c = *(ptable + 1);\r
479 \r
480             ptr2 = symbols[*ptable & 0x7f];\r
481                         if(*ptr2) {\r
482                                 while(*ptr1 && (*ptr1 != c))\r
483                                         if(*ptr1++ != *ptr2++)\r
484                                                 return 0;\r
485                                 if(*ptr2)\r
486                                         return 0; }\r
487                         else {                                                  /* new symbol */\r
488                                 while(*ptr1 && (*ptr1 != c))\r
489                                         *ptr2++ = *ptr1++;\r
490                                 *ptr2 = 0; } }\r
491 \r
492                 else if(c != *ptr1++) return 0;         /* normal character */\r
493 \r
494                 ++ptable;\r
495         }\r
496         return (*ptr1) ? 0 : peep + 1;\r
497 }\r
498 \r
499 \r
500 /********************************************************\r
501 * Exchange new code for old code in the peephole buffer.\r
502 * pnew points to the first char of the new code.\r
503 * old points to last entry of buffer code to be replaced.\r
504 *********************************************************/\r
505 \r
506 static void exchange(unsigned long old, char *pnew)\r
507 {\r
508         char *ptr1, *ptr2;\r
509 \r
510     peep_top = (old+(OBUF_SIZE-1)) % OBUF_SIZE;  /* last entry of replacement */\r
511         ptr2 = peep_buffer[peep_top];\r
512         while(*pnew) {                                          /* while still some new stuff left */\r
513                 if(*pnew & 0x80) {                              /* output a symbol */\r
514                         ptr1 = symbols[*pnew & 0x7f];   /* ptr1 points to a symbol */\r
515                         while(*ptr1)\r
516                                 *ptr2++ = *ptr1++; }\r
517                 else if(*pnew == '\n') {                /* end of a new entry */\r
518                         *ptr2 = 0;                                      /* put null at end of line */\r
519             peep_top = (peep_top+(OBUF_SIZE-1)) % OBUF_SIZE;\r
520                         ptr2 = peep_buffer[peep_top]; }\r
521                 else\r
522                         *ptr2++ = *pnew;\r
523                 ++pnew; }\r
524         *ptr2 = 0;\r
525 }\r
526 \r
527 \r
528 /***********************************************\r
529    Simulates fgets from the HUGE code buffer\r
530 ************************************************/\r
531 \r
532 static char *fgetcode(char *pout, long maxout)\r
533 {\r
534 char c, *s;\r
535 long n;\r
536 \r
537         s = pout;\r
538         n = 0;\r
539 \r
540         if (pco >= pc)          /* end of valid buffer data */\r
541                 return(0);\r
542 \r
543         while ((n < maxout-1) && (pcodebuf[pco]))\r
544         {\r
545                 c = pcodebuf[pco];\r
546                 *pout++  = pcodebuf[pco++];\r
547                 n++;\r
548                 if (c == 0x0A)\r
549                 {\r
550             *pout = 0;\r
551                         return(s);\r
552                 }\r
553         }\r
554         if (n)\r
555                 return(s);\r
556         else\r
557                 return(0);\r
558 }\r
559 \r
560 \r
561 /****************************************\r
562 * Read a line into the peephole buffer\r
563 * from the tmpcodebuf\r
564 *****************************************/\r
565 \r
566 static long read_line(void)\r
567 {\r
568 char c, *sptr;\r
569 \r
570         if(fgetcode(peep_buffer[peep_next], OLINE_SIZE)) {\r
571 \r
572                 /*strip CR/LF from line */\r
573                 sptr = &(peep_buffer[peep_next]);\r
574 \r
575                 while (c = *sptr) {\r
576                         if (c == '\r') *sptr = '\0';\r
577                         if (c == '\n') *sptr = '\0';\r
578                         sptr++;\r
579                 }\r
580 \r
581                 /* next peep_buf entry please... */\r
582                 peep_next = (peep_next+1) % OBUF_SIZE;\r
583                 return 1;\r
584         }\r
585         return 0;\r
586 }\r
587 \r
588 /*********************************************************\r
589 * Write a line from the peephole buffer to the output file\r
590 **********************************************************/\r
591 static void write_line(void)\r
592 {\r
593         if (fGen)\r
594                 fputs(peep_buffer[peep_top], code_fh);\r
595         else\r
596                 fputs(peep_buffer[peep_top], asm_fh);\r
597         peep_top = (peep_top + 1) % OBUF_SIZE;\r
598         if (fGen)\r
599                 fputs("\n", code_fh);\r
600         else\r
601                 fputs("\n", asm_fh);\r
602 }\r
603 \r
604 \r
605 /*********************************************************\r
606 * Peephole Optimizer function for code segment\r
607 **********************************************************/\r
608 static void optimize(void)\r
609 {\r
610         long i, j;\r
611         char *ptr;\r
612 \r
613         if (!fQuiet)\r
614                 fputs("CM32 V2.3M optimizer phase\r\n", stdout);\r
615 \r
616         /* initially fill every line in peephole buffer */\r
617 \r
618         j = 0;\r
619 \r
620         for(;;) {\r
621                         /* keep buffer full! */\r
622                 while ( ((peep_next+1) % OBUF_SIZE) != peep_top ) \r
623                 {\r
624                 if (!read_line())\r
625                 {\r
626                         break;\r
627                         }\r
628                 }\r
629                 /* walk thru the whole peep_table and see if we have\r
630                         matches in the peep_buffer  */\r
631 \r
632                 for(i=0; ptr = peep_table[i]; i += 2) {\r
633 \r
634             j = compareT(ptr, peep_top);\r
635 \r
636                         if(j) {                                                 /* we have a match, exchange it */\r
637                                 exchange(j, peep_table[i+1]);\r
638                                 break;                                          /* break to fill buffer again */\r
639                         }\r
640                 }\r
641                 if(!j) write_line();            /* no matches, flush this line */\r
642 \r
643                 if (peep_top == peep_next)\r
644                         return;                                 /* We are done! */\r
645         }\r
646 }\r
647 \r
648 \r
649 /********************************************\r
650  Read a line & perform pre-processing. if_flag\r
651  is used to indicate the nesting of ifs.  It\r
652  is incremented for each if found.  The high\r
653  bit is set if we are actually IN an active\r
654  macro.\r
655 *********************************************/\r
656 \r
657 static long readline(void)\r
658 {\r
659 U32 i;\r
660 char c, ch, fgotone;\r
661 \r
662 for(;;) {\r
663         if(!fgets(buffin_ptr = buffer, LINE_MAX, source_fh)) \r
664         {\r
665                 if(include)\r
666                 {\r
667                         fclose(source_fh);\r
668                         line_number = incl_line[--include];\r
669                         source_fh = incl_fh[include];\r
670                         continue;\r
671                 }\r
672                 return 0;\r
673         }               /* no more lines... */\r
674 \r
675         ++line_number;\r
676         buffout_ptr = line_in;\r
677 \r
678         fgotone = 0;\r
679 \r
680         if ((ch = skip_blanks()) == '#') \r
681         {\r
682 \r
683                 if(match("#asm"))\r
684                 {                                                               /* if inline assembly */\r
685                         asm_flag = -1;\r
686                         fgotone = -1;\r
687                 }\r
688 \r
689                 else if(match("#endasm")) \r
690                 {                                                               /* end of assembly */\r
691                         asm_flag = 0;\r
692                         fgotone = -1;\r
693                 }\r
694 \r
695                 else if(match("#ifdef"))\r
696                 {                                                               /* if macro defined */\r
697                         fgotone = -1;\r
698                         if(if_flag)\r
699                                 ++if_flag;                                      /* one deeper */\r
700                         else if(lookup_macro(0) == -1)\r
701                         {\r
702                                 if_flag = 0x80;\r
703                         }\r
704                 }\r
705 \r
706                 else if(match("#ifndef"))\r
707                 {                       /* if macro not defined */\r
708                         fgotone = -1;\r
709                         if(if_flag)\r
710                                 ++if_flag;\r
711                         else if(lookup_macro(0) != -1)\r
712                         {\r
713                                         if_flag = 0x80;\r
714                         }\r
715                 }\r
716 \r
717                 else if(match("#else"))\r
718                 {                       /* reverse condition */\r
719                         fgotone = -1;\r
720                         if(!(if_flag & 0x7f))                   /* not nested? */\r
721                                 if_flag ^= 0x80;\r
722                 }                                                                       /* XOR high bit */\r
723 \r
724                 else if(match("#endif"))\r
725                 {                                                                       /* end conditional */\r
726                         fgotone = -1;\r
727                         if(if_flag & 0x7f)                              /* if nested, reduce one */\r
728                                 --if_flag;\r
729                         else\r
730                                 if_flag = 0;\r
731                 }                               /* else it's over */\r
732 \r
733                 else if(match("#pragma"))\r
734                 {               /* later... */\r
735                                 fgotone = -1;\r
736                 }\r
737         }\r
738 \r
739                 /* If we got here, we have found # and it's not\r
740                    a conditional, so it must be a new macro.\r
741                 */\r
742 \r
743         if ((!fgotone) && (!if_flag))\r
744         {\r
745                 if (ch == '#')\r
746                 {\r
747                         if(match("#define")) {                  /* define a new macro */\r
748                                 if(macro >= MACROS) {\r
749                                         fatal_error("Too many macro definitions");\r
750                                         exit(-1); }\r
751                                 buffout_ptr = define_index[macro++] = define_ptr;\r
752                                 if(!is_alpha(*buffin_ptr)) {\r
753                                         line_error("Invalid macro name");\r
754                                         continue; }\r
755                                 copy_name();                            /* get macro name */\r
756                                 define_ptr = buffout_ptr;\r
757                                 *define_ptr++ = 0;\r
758                                 parm = 0;\r
759                                 parm_ptr = parm_pool;\r
760                                 if(*buffin_ptr == '(') {        /* parameterized macro */\r
761                                         *define_ptr++ = 1;\r
762                                         ++buffin_ptr;\r
763                                         do {\r
764                                                 if(parm >= PARAMETERS) {\r
765                                                         line_error("Too many macro parameters");\r
766                                                         break; }\r
767                                                 parm_index[parm++] = buffout_ptr = parm_ptr;\r
768                                                 skip_blanks();\r
769                                                 copy_name();\r
770                                                 parm_ptr = buffout_ptr+1; }\r
771                                         while(more_parms()); }\r
772                                 else\r
773                                         *define_ptr++ = 0;\r
774                                 skip_blanks();\r
775                                 while(c = *buffin_ptr) {\r
776                                         buffout_ptr = define_ptr;\r
777                                         if(is_alpha(c)) {\r
778                                                 resolve_macro();\r
779                                                 for(i=0; i < parm; ++i) {\r
780                                                         if(!strcmp(define_ptr, parm_index[i])) {\r
781                                                                 *define_ptr++ =  i + 0x80;\r
782                                                                 buffout_ptr = define_ptr;\r
783                                                                 break; } }\r
784                                                 define_ptr = buffout_ptr; }\r
785                                         else if((c == '"') || (c == 0x27)) {\r
786                                                 copy_string();\r
787                                                 define_ptr = buffout_ptr; }\r
788                                         else {\r
789                                                 if((*++buffin_ptr == '*') && (c == '/')) {\r
790                                                         ++buffin_ptr;\r
791                                                         begin_comment = line_number;\r
792                                                         skip_comment(); }\r
793                                                 else\r
794                                                         *define_ptr++ = c; }\r
795                                         /* skip_blanks(); */\r
796                                 }\r
797                                 *define_ptr++ = 0; }\r
798 \r
799                         else if(match("#undef"))\r
800                         {                       /* undefine a macro */\r
801                                 if((i = lookup_macro(-1)) != -1)\r
802                                 {\r
803                                         if(i == (macro - 1))            /* last one, simple delete */\r
804                                                 define_ptr = define_index[i];\r
805                                         else\r
806                                         {                                               /* not last, reclaim space */\r
807                                                 define_ptr -= (parm = (buffin_ptr = define_index[i+1]) -\r
808                                                         (parm_ptr = define_index[i]));\r
809                                                 while(parm_ptr < define_ptr)\r
810                                                         *parm_ptr++ = *buffin_ptr++;\r
811                                                 while(i < macro)\r
812                                                 {               /* adjust index list */\r
813                                                         define_index[i] = define_index[i+1] - parm;\r
814                                                         ++i;\r
815                                                 }\r
816                                         }\r
817                                         --macro;\r
818                                 }\r
819                         }\r
820                         else if(match("#include"))\r
821                         {               /* include a file */\r
822                                 if(include >= INCL_DEPTH)\r
823                                         fatal_error("Too many include files");\r
824                                 if((c = skip_blanks()) == '<')\r
825                                 {       /* incdir definition */\r
826                                         for(parm_ptr = incdir; *parm_ptr; ++parm_ptr)\r
827                                                 *buffout_ptr++ = *parm_ptr;\r
828                                         *buffout_ptr++ = '\\';                  /*** OS dependent!!! ***/\r
829                                         c = '>';\r
830                                 }\r
831                                 else if(c != '"')\r
832                                 {                                       /* current directory */\r
833                                         line_error("Invalid include file name");\r
834                                         continue;\r
835                                 }\r
836                                 while(*++buffin_ptr && (*buffin_ptr != c))\r
837                                         *buffout_ptr++ = *buffin_ptr;\r
838                                 *buffout_ptr = 0;\r
839                                 incl_fh[include] = source_fh;\r
840                                 incl_line[include] = line_number;\r
841                                 if(source_fh = fopen(line_in, "r"))\r
842                                 {\r
843                                         line_number = 0;\r
844                                         ++include;\r
845                                 }\r
846                                 else\r
847                                 {\r
848                                         line_error("Cannot open include file");\r
849                                         source_fh = incl_fh[include];\r
850                                 }\r
851                         }\r
852                         else\r
853                                 line_error("Unknown preprocessor directive");\r
854 \r
855                 }\r
856                 else\r
857                 {                               /* default, perform pre-processing */\r
858 \r
859                         if(asm_flag)            /* inline assembly */\r
860                                 do_asm(buffer);\r
861                         else\r
862                         while(c = *buffin_ptr)\r
863                         {\r
864                                 if(is_alpha(c))                         /* symbol, could be macro */\r
865                                         resolve_macro();\r
866                                 else if((c == '"') || (c == 0x27))              /* quoted string */\r
867                                         copy_string();\r
868                                 else\r
869                                 {\r
870                                         if((*++buffin_ptr == '*') && (c == '/') && comment_flag)\r
871                                         { /* comment */\r
872                                                 ++buffin_ptr;\r
873                                                 begin_comment = line_number; /* save begin line*/\r
874                                                 skip_comment();\r
875                                         }\r
876                                         else                            /* nothing special, copy it */\r
877                                                 *buffout_ptr++ = c;\r
878                                 }\r
879                         }\r
880                         if (fSource)\r
881                         {\r
882                                 code_chr(';');\r
883                                 code_str(buffer);\r
884                         }\r
885                         input_ptr=line_in;      /* point to start of new line */\r
886                         *buffout_ptr = 0;               /* null at end of line */\r
887                         return -1;\r
888                 }\r
889         }  /* !fgotone && !if_flag */\r
890 } /*for*/\r
891 }\r
892 \r
893 \r
894 \r
895 \r
896 /***********************************************************\r
897 * Test to see if the last statement compiled was an "exit"\r
898 * statement, and if so, generate a jump to the appriopriate\r
899 * label. This prevents generation of a spurious jump when a\r
900 * "return" statement is used at the end of a function.\r
901 ************************************************************/\r
902 \r
903 static U32 test_exit(void)\r
904 {\r
905         if(exit_flag) {\r
906                 jump(exit_flag, -1);\r
907                 exit_used = -1;\r
908                 return(exit_flag = 0);\r
909                 }\r
910         return -1;\r
911 }\r
912 \r
913 /*********************************************\r
914 * Output an warning message with quoted text\r
915 **********************************************/\r
916 \r
917 static void t_warn(char *msg, char *txt)\r
918 {\r
919 int i;\r
920         ++warn_count;\r
921         if (!fWarnings) return;\r
922 \r
923         incl_line[include] = line_number;\r
924         for(i=0; i <= include; ++i) {\r
925                 put_num(incl_line[i], list_fh);\r
926                 fputc(':', list_fh);\r
927                 }\r
928         fputc(' ', list_fh);\r
929         fputs("Warning: ", list_fh);\r
930         fputs(msg, list_fh);\r
931         fputc(' ', list_fh);\r
932         fputc(0x27, list_fh);           /* single quote */\r
933         fputs(txt, list_fh);\r
934         fputc(0x27, list_fh);           /* single quote */\r
935         fputc('\r', list_fh);\r
936         fputc('\n', list_fh);\r
937 }\r
938 \r
939 /*********************************************\r
940 * Output an error message with quoted text\r
941 **********************************************/\r
942 \r
943 static void t_error(char *msg, char *txt)\r
944 {\r
945         char emsg[50], *ptr;\r
946 \r
947         ptr = emsg;\r
948         while(*msg)\r
949                 *ptr++ = *msg++;\r
950         *ptr++ = ':';\r
951         *ptr++ = ' ';\r
952         *ptr++ = 0x27;          /* single quote */\r
953         while(*txt)\r
954                 *ptr++ = *txt++;\r
955         *ptr++ = 0x27;          /* single quote */\r
956         *ptr = 0;\r
957         line_error(emsg);\r
958 }\r
959 \r
960 \r
961 /***********************************************************\r
962 * Report an error involving a freshly parsed symbol name\r
963 ************************************************************/\r
964 \r
965 static void symbol_error(char *msg)\r
966 {\r
967         t_error(msg, gst);\r
968 }\r
969 \r
970 \r
971 /***********************************************************\r
972 * Report a syntax error\r
973 ************************************************************/\r
974 \r
975 static void syntax_error(void)\r
976 {\r
977         line_error("Syntax error");\r
978 }\r
979 \r
980 /***********************************************************\r
981 * Report incompatable types\r
982 ************************************************************/\r
983 \r
984 static void type_error(void)\r
985 {\r
986         line_error("Types mismatch");\r
987 }\r
988 \r
989 /***********************************************************\r
990 * Report an error in indirection\r
991 ************************************************************/\r
992 \r
993 static void index_error(void)\r
994 {\r
995         line_error("Illegal indirection");\r
996 }\r
997 \r
998 \r
999 /****************************************************\r
1000 * Test the next token in the input stream, put it\r
1001 * back if its not the one we are looking for.\r
1002 ****************************************************/\r
1003 \r
1004 static char test_token(U32 token)\r
1005 {\r
1006         U32 token1;\r
1007 \r
1008         if((token1 = get_token()) == token)\r
1009                 return -1;\r
1010         unget_token(token1);\r
1011         return 0;\r
1012 }\r
1013 \r
1014 \r
1015 /**************************************************************\r
1016 * Check for a certain token occuring next in the input stream.\r
1017 * If it is not found, report an error.\r
1018 ***************************************************************/\r
1019 \r
1020 static void expect(U32 token)\r
1021 {\r
1022         if(!test_token(token))\r
1023                 t_error("Expected", tokens[token]);\r
1024 }\r
1025 \r
1026 /***************************************\r
1027  Report a Unterminated Comment error\r
1028 ****************************************/\r
1029 \r
1030 static void UTC_error(void)\r
1031 {\r
1032         U32 i;\r
1033 \r
1034         incl_line[include] = line_number;\r
1035         for(i=0; i <= include; ++i) {\r
1036                 put_num(incl_line[i], list_fh);\r
1037                 fputc(':', list_fh);\r
1038                 }\r
1039         fputc(' ', list_fh);\r
1040         fputs("Unterminated comment from line: ", list_fh);\r
1041         put_num(begin_comment, list_fh);\r
1042         fputc('\r', list_fh);\r
1043         fputc('\n', list_fh);\r
1044 \r
1045         if(++error_count == MAX_ERRORS)\r
1046                 fatal_error("Too many errors");\r
1047 }\r
1048 \r
1049 /***************************************\r
1050 * Report a compile error\r
1051 ****************************************/\r
1052 \r
1053 static void line_error(char *message)\r
1054 {\r
1055         U32 i;\r
1056 \r
1057         incl_line[include] = line_number;\r
1058         for(i=0; i <= include; ++i) {\r
1059                 put_num(incl_line[i], list_fh);\r
1060                 fputc(':', list_fh);\r
1061                 }\r
1062         fputc(' ', list_fh);\r
1063         fputs(message, list_fh);\r
1064         fputc('\r', list_fh);\r
1065         fputc('\n', list_fh);\r
1066 \r
1067         if(++error_count == MAX_ERRORS)\r
1068                 fatal_error("Too many errors");\r
1069 }\r
1070 \r
1071 /*******************************************\r
1072 * Report a non-recoverable compile error\r
1073 ********************************************/\r
1074 \r
1075 static void fatal_error(char *string)\r
1076 {\r
1077         line_error(string);\r
1078 \r
1079         /* put this out even if fQuiet */\r
1080         fputs("Fatal error, compilation aborted\r\n", stdout);\r
1081 \r
1082         if (fList) {\r
1083                 fputs("Fatal error, compilation aborted\r\n", list_fh);\r
1084                 if (fLISTOpen)\r
1085                         fclose(list_fh);\r
1086                 }\r
1087 \r
1088         /* close files */\r
1089 \r
1090         if (fASMOpen) fclose(asm_fh);\r
1091         exit(-1);  /* We are done ! */\r
1092 \r
1093 }\r
1094 \r
1095 /*****************************************************\r
1096 * Check that a loop is active & setup exit condition\r
1097 ******************************************************/\r
1098 \r
1099 static void check_loop(U32 stack[])\r
1100 {\r
1101         expect(SEMI);\r
1102         if(loop_ptr)\r
1103                 exit_flag = stack[loop_ptr-1];\r
1104         else\r
1105                 line_error("No active loop");\r
1106 }\r
1107 \r
1108 /****************************************************\r
1109 * Check that a switch is active & allocate label\r
1110 *****************************************************/\r
1111 \r
1112 static U32 check_switch(void)\r
1113 {\r
1114         if(!sdefault)\r
1115                 line_error("No active switch");\r
1116         gen_label(++next_lab);\r
1117         return next_lab;\r
1118 }\r
1119 \r
1120 /*******************************************************************\r
1121 * Compile a jump only if last statement compiled was not an "exit"\r
1122 * statement ("return", "break", or "continue"). This prevents the\r
1123 * generation of an unaccessable jump following these statements.\r
1124 ********************************************************************/\r
1125 \r
1126 static void test_jump(U32 label)\r
1127 {\r
1128         if(test_exit())\r
1129                 jump(label, -1);\r
1130 }\r
1131 \r
1132 \r
1133 /********************************************\r
1134 * Compile a conditional jump and\r
1135 * set up 'Z' flag if necessary.\r
1136 *********************************************/\r
1137 \r
1138 static void cond_jump(char cond, U32 label, char ljmp)\r
1139 {\r
1140         if(zero_flag)\r
1141         {\r
1142                 out_inst("AND EAX,EAX");\r
1143                 zero_flag = 0;\r
1144         }\r
1145 \r
1146         jump_if(cond ^ not_flag, label, ljmp);\r
1147         not_flag = 0;\r
1148 }\r
1149 \r
1150 \r
1151 /**********************************************************\r
1152 * Get a number in a number base for a maximum # of digits\r
1153 * (digits = 0 means no limit)\r
1154 ***********************************************************/\r
1155 \r
1156 static U32 get_number(U32 base, U32 digits)\r
1157 {\r
1158         U32 value;\r
1159         char c;\r
1160 \r
1161         value = 0;\r
1162         do {\r
1163                 if(is_digit(c = *input_ptr))            /* convert numeric digits */\r
1164                         c -= '0';\r
1165                 else if(c >= 'a')                               /* convert lower case alphas */\r
1166                         c -= ('a' - 10);\r
1167                 else if(c >= 'A')                               /* convert upper case alphas */\r
1168                         c -= ('A' - 10);\r
1169                 else\r
1170                         break;\r
1171                 if(c >= base)                                   /* outside of base */\r
1172                         break;\r
1173                 value = (value * base) + c;             /* include in total */\r
1174                 ++input_ptr; }\r
1175         while(--digits);                                        /* enforce maximum digits */\r
1176         return value;\r
1177 }\r
1178 \r
1179 \r
1180 /*****************************************************************\r
1181 * End of file has been encountered, dump the literal pool, and\r
1182 * generate definitions for any external or uninitialized global\r
1183 * variables.\r
1184 ******************************************************************/\r
1185 \r
1186 static void clean_up(void)\r
1187 {\r
1188         U32 type, size, i, j;\r
1189 \r
1190         if(in_function)\r
1191                 fatal_error("Unterminated function");\r
1192 \r
1193 /* Generate all externals referenced from CSEG if NOT for DASM */\r
1194 \r
1195         for(sptr = 0; sptr < global_top; ++sptr)\r
1196         {\r
1197                 if((type = symtab[sptr].type) & (EXTERNAL))\r
1198                         if (type & REFERENCE)\r
1199                                 gen_ext_data_DASM(sptr);\r
1200         }\r
1201 \r
1202 /* dump literal pool */\r
1203 \r
1204         gen_literal(literal_pool, literal_top);\r
1205 \r
1206 /* Generate all global variables that are not initialized */\r
1207 \r
1208         for(sptr = 0; sptr < global_top; ++sptr) {\r
1209                 type = symtab[sptr].type;\r
1210                 if(!(type & (FUNCTION | INITED | EXTERNAL | TYPDEF))) {\r
1211 \r
1212                         if (type & (POINTER | DWORD)) size = 4;\r
1213                         else if (type & WORD)  size = 2;\r
1214                         else if (type & BYTE)  size = 1;\r
1215                         else if (type & STRUCT) {\r
1216                           size = symtab[sptr].strucoff;         /* contains size */\r
1217                           }\r
1218                         else size = 1;  /* should be an error maybe?? */\r
1219 \r
1220                         if(type & ARRAY) {                              /* calculate size of array */\r
1221                                 i = symtab[sptr].dindex;    /* i = index to dimpool */\r
1222                                 j = dim_pool[i++];                      /* j = nDims */\r
1223                                 while(j--) size *= dim_pool[i++];\r
1224                                 }\r
1225                         gen_global(sptr, size);\r
1226                 }\r
1227         }\r
1228 \r
1229     if (pd)\r
1230     {\r
1231                 fwrite(databuf, pd, 1, asm_fh);\r
1232                 pd = 0;\r
1233         }\r
1234 \r
1235         if (!error_count)\r
1236         {  /* No optimize if errors */\r
1237 \r
1238                 if (fNoOpt) {\r
1239 \r
1240                                 while (fgetcode(buffer, LINE_MAX))\r
1241                                 {\r
1242                                         if (fGen)\r
1243                                                 fputs(buffer, code_fh);\r
1244                                         else\r
1245                                                 fputs(buffer, asm_fh);\r
1246                                 }\r
1247                 }\r
1248                 else {\r
1249                         optimize();\r
1250                 }\r
1251         }\r
1252         fclose(asm_fh);\r
1253         if (fLISTOpen)\r
1254                 fclose(list_fh);\r
1255         if (fCODEOpen)\r
1256                 fclose(code_fh);\r
1257 \r
1258         if(!fQuiet) {\r
1259                 put_num(error_count, stdout);\r
1260                 fputs(" errors\r\n", stdout);\r
1261                 put_num(warn_count, stdout);\r
1262                 fputs(" warnings\r\n", stdout);\r
1263                 }\r
1264 \r
1265         exit(0);  /* We are done ! */\r
1266 }\r
1267 \r
1268 \r
1269 /*****************************************\r
1270 * Read a character from the input file\r
1271 ******************************************/\r
1272 \r
1273 static char read_char(void)\r
1274 {\r
1275         char c;\r
1276 \r
1277         while(!(c = *input_ptr++)) {            /* end of this line */\r
1278                 if (!readline()) {\r
1279                         clean_up();\r
1280                         exit(error_count);\r
1281                 }\r
1282         }\r
1283         return c;\r
1284 }\r
1285 \r
1286 /***********************************************************\r
1287 * Allow a single token to be returned to the input stream\r
1288 ************************************************************/\r
1289 \r
1290 static void unget_token(U32 token)\r
1291 {\r
1292         ungot_token = token;\r
1293 }\r
1294 \r
1295 \r
1296 /************************************************\r
1297 * Read special character (with translations)\r
1298 *************************************************/\r
1299 \r
1300 static U32 read_special(char delim)\r
1301 {\r
1302         S32 c;\r
1303 \r
1304         if((c = read_char()) == delim)\r
1305                 return 0xff00;\r
1306         if(c == '\\')\r
1307           switch(c = read_char()) {\r
1308                 case 'n':                               /* newline */\r
1309                         c = 0x0a;\r
1310                         break;\r
1311                 case 'r':                               /* return */\r
1312                         c = 0x0d;\r
1313                         break;\r
1314                 case 't':                               /* tab */\r
1315                         c = 0x09;\r
1316                         break;\r
1317                 case 'f' :                              /* formfeed */\r
1318                         c = 0x0c;\r
1319                         break;\r
1320                 case 'b':                               /* backspace */\r
1321                         c = 0x08;\r
1322                         break;\r
1323                 case 'v':                               /* vertical tab */\r
1324                         c = 0x0b;\r
1325                         break;\r
1326                 case 'x' :                              /* hex value */\r
1327                         c = get_number(16, 2);\r
1328                         break;\r
1329                 default:\r
1330                         if(is_digit(c)) {               /* octal value */\r
1331                                 --input_ptr;\r
1332                                 c = get_number(8, 3);\r
1333             }\r
1334         }\r
1335         return c & 0xff;\r
1336 }\r
1337 \r
1338 /*************************************************************************\r
1339 * Get a token from the input stream, and return it as a simple value\r
1340 * (indicating type). If it a special token type (NUMBER, STRING, SYMBOL),\r
1341 * global variables "gvalue" and "gst" are set to appriopriate values.\r
1342 **************************************************************************/\r
1343 \r
1344 static U32 get_token(void)\r
1345 {\r
1346         U32 i;\r
1347         char *ptr, *last_pos, chr;\r
1348 \r
1349 /* if a token has been ungot, re-get it */\r
1350 /* (gvalue & gst) will not have changed */\r
1351         if(ungot_token) {\r
1352                 i = ungot_token;\r
1353                 ungot_token = 0;\r
1354                 return i;\r
1355         }\r
1356 \r
1357 /* skip any leading whilespace  */\r
1358         do {\r
1359         chr = read_char();\r
1360                 }\r
1361         while((chr == ' ') || (chr == '\t') ||\r
1362                 (chr == '\n') || (chr == '\r'));\r
1363 \r
1364         --input_ptr;\r
1365 \r
1366 \r
1367 /* lookup token in token table */\r
1368         last_pos = input_ptr;                           /* remember where we were */\r
1369 \r
1370         if (itoken[*input_ptr] != 0) {\r
1371                 /* start at first match char */\r
1372                 for(i=itoken[*input_ptr]; ptr = tokens[i]; ++i) {\r
1373                         if (*input_ptr != *ptr) break;\r
1374                         while((chr = *input_ptr) && (*ptr == chr)) {\r
1375                                 ++ptr;\r
1376                                 ++input_ptr; }\r
1377                         if(!*ptr) {                                             /* we found a token */\r
1378                                 if(is_alpha(*(ptr-1)) && is_alpha(*input_ptr))\r
1379                                         continue;                                       /* not this token */\r
1380                                 return i; }\r
1381                         input_ptr = last_pos;                   /* reset pointer */\r
1382                 }\r
1383         }\r
1384 /* we didn't find a token, check out special cases */\r
1385         input_ptr = last_pos;\r
1386 \r
1387         if((chr = *input_ptr) == '"')   {       /* string value */\r
1388                 ++input_ptr;\r
1389                 gvalue = literal_top;           /* set to index to string */\r
1390                 do {\r
1391                         if(literal_top >= LITER_BUFF)\r
1392                                 fatal_error("String space exausted");\r
1393                         literal_pool[literal_top++] = i = read_special('"');\r
1394                 }\r
1395                 while(!(i & 0xff00));   /* 0xff00 returned from read_special */\r
1396                 return STRING; }\r
1397 \r
1398         /* Quoted values (e.g., '\n') are read into gvalue.\r
1399            ANSI says that multibyte character constants are\r
1400            implementation dependent.  SOOO, In our case we\r
1401            shift multiple bytes to the left.  '\n\r' will\r
1402            make gvalue equal 0x0D0A even though the \n (0x0A) is\r
1403            first.\r
1404          */\r
1405 \r
1406         if(chr == 0x27)\r
1407         {                                       /* quoted value */\r
1408                 ++input_ptr;\r
1409                 while( !((i = read_special(0x27)) & 0xff00) )\r
1410                         gvalue =  i & 0xff;     /* strip notify bits */\r
1411                 return NUMBER;\r
1412         }\r
1413 \r
1414 \r
1415         if(is_digit(chr)) {                                     /* numeric constant */\r
1416                 if(chr == '0') {\r
1417                         ++input_ptr;\r
1418                         if((*input_ptr == 'x') || (*input_ptr == 'X')) {\r
1419                                 ++input_ptr;\r
1420                                 gvalue = get_number(16, 0);                     /* hex */\r
1421                         }\r
1422                         else\r
1423                                 gvalue = get_number(8, 0);              /* octal */\r
1424                 }\r
1425                 else gvalue = get_number(10, 0);                        /* decimal */\r
1426 \r
1427                 /* Look for Unsigned and Long terminal characters */\r
1428 \r
1429                 if((*input_ptr == 'U') || (*input_ptr == 'u')) {\r
1430                         ++input_ptr;\r
1431                         if((*input_ptr == 'L') || (*input_ptr == 'l')) ++input_ptr;\r
1432                 }\r
1433                 else if((*input_ptr == 'L') || (*input_ptr == 'l')) ++input_ptr;\r
1434 \r
1435                 return NUMBER;\r
1436         }\r
1437 \r
1438         if(is_alpha(chr)) {                                     /* symbol name */\r
1439                 gvalue = 0;\r
1440                 while(is_alnum(chr = *input_ptr)) {\r
1441                         if(gvalue < SYMBOL_SIZE)\r
1442                                 gst[gvalue++] = chr;\r
1443                         ++input_ptr; }\r
1444                 gst[gvalue] = 0;\r
1445                 namesize = gvalue;\r
1446                 return SYMBOL; }\r
1447 \r
1448 /* not a token or special value */\r
1449         ++input_ptr;                    /* skip offending character */\r
1450         return -1;                              /* report "unknown" token type */\r
1451 }\r
1452 \r
1453 \r
1454 /*****************************************************\r
1455 * Locate a symbol in the local symbol table\r
1456 ******************************************************/\r
1457 \r
1458 static U32 lookup_local(void)\r
1459 {\r
1460         U16 i,j;\r
1461 \r
1462         i = MAX_SYMBOLS-1;\r
1463         while(i > local_top-1) {\r
1464                 j = symtab[i].oname;\r
1465                 if(equal_string(gst, &LPool[j]))\r
1466                         return symtab[sptr=i].type |= REFERENCE;\r
1467             i--;\r
1468     }\r
1469         return 0;\r
1470 }\r
1471 \r
1472 \r
1473 /*************************************************\r
1474   Locate a symbol in the global symbol table.\r
1475 **************************************************/\r
1476 \r
1477 static U32 lookup_global(void)\r
1478 {\r
1479         U16 i, j;\r
1480 \r
1481         for(i=0; i < global_top; i++) {\r
1482                 j = symtab[i].oname;\r
1483                 if(equal_string(gst, &GPool[j]))\r
1484                         return symtab[sptr=i].type |= REFERENCE;\r
1485         }\r
1486         return 0;\r
1487 }\r
1488 \r
1489 /**************************************************\r
1490   Locate a structure member in either symbol table\r
1491 ***************************************************/\r
1492 \r
1493 static U32 lookup_member(U32 CrntStruc)\r
1494 {\r
1495         U16 i, j, CrntStrucDef;\r
1496 \r
1497         /* structure member names were hidden in the tables\r
1498            by inserting a '0' as the first char.  Now we\r
1499            must make the current symbol name match\r
1500            so we can find it in the tables.  It will follow\r
1501            the structure definition entry for CrntStruc.\r
1502         */\r
1503 \r
1504         for (i=SYMBOL_SIZE; i > 0; i--)         /* fix member name  */\r
1505            gst[i] = gst[i-1];\r
1506      gst[0] = '0';                                      /* make it start with digit */\r
1507      ++namesize;\r
1508 \r
1509         CrntStrucDef = symtab[CrntStruc].itypedef;\r
1510 \r
1511         if (symtab[CrntStrucDef].type & GLOBAL) {\r
1512 \r
1513                 for(i=CrntStrucDef+1; i < global_top; i++) {\r
1514                         if (!(symtab[i].type & STRUCMEM))\r
1515                                 break;\r
1516                         j = symtab[i].oname;\r
1517                         if(equal_string(gst, &GPool[j]))\r
1518                                 return symtab[sptr=i].type |= REFERENCE;\r
1519                 }\r
1520         }\r
1521         else {  /* must be local */\r
1522 \r
1523                 for(i=CrntStrucDef-1; i > local_top-1; i--) {\r
1524                         if (!(symtab[i].type & STRUCMEM))\r
1525                                 break;\r
1526                         j = symtab[i].oname;\r
1527                         if(equal_string(gst, &LPool[j]))\r
1528                                 return symtab[sptr=i].type |= REFERENCE;\r
1529                 }\r
1530         }\r
1531         return 0;               /* didn't find it! */\r
1532 }\r
1533 \r
1534 /***************************************************************\r
1535   Enter a symbol in the symbol table with specified name & type.\r
1536   Leaves global sptr with the index of the symbol just added.\r
1537 ****************************************************************/\r
1538 \r
1539 static void define_symbol(U32 type, U32 dim_index)\r
1540 {\r
1541         U32 index;\r
1542         U16 j;\r
1543 \r
1544         if(in_function) {               /* within a function, use local */\r
1545                 if (type&PROTO) {       /* give it a false name to satisfy symbol table */\r
1546                         gst[0] = '_';                           /* 2 underscores */\r
1547                         gst[1] = '-';\r
1548                         gst[2] = arg_count + 65;        /* A-Z */\r
1549                         gst[3] = '\0';                                  /* null terminate */\r
1550                         namesize = 3;\r
1551                         }\r
1552                 else {\r
1553                         if(lookup_local()) {\r
1554                                 symbol_error("Duplicate local or arg");\r
1555                                 return;\r
1556                                 }\r
1557                         }\r
1558 \r
1559                 sptr = --local_top;\r
1560                 if(type & ARGUMENT) {\r
1561 \r
1562                         type &= ~PROTO;  /* turn off proto warning */\r
1563 \r
1564                         /* if a prototype arg already exists, make sure it's the same */\r
1565                         if (icrntpro) {\r
1566                                 if (proto_list[icrntpro++] != type) {\r
1567                                   j=symtab[fptr].oname;\r
1568                               t_warn("Arg not same type as prototype in ", &GPool[j]);\r
1569                                 }\r
1570                         }\r
1571                         else proto_list[iproto_next++] = type;\r
1572                         if(iproto_next>MAX_PROTOS)\r
1573                           fatal_error("Prototype table full");\r
1574                 }\r
1575                 else\r
1576                         index = local_stack;\r
1577 \r
1578                 if(global_top > local_top)\r
1579                         fatal_error("Symbol table full");\r
1580                 if((oNextLName+SYMBOL_SIZE) > LBUFFSIZE)\r
1581                         fatal_error("Local symbol name pool full");\r
1582                 symtab[sptr].oname=oNextLName;\r
1583                 copystring(&LPool[oNextLName], gst);\r
1584                 oNextLName += namesize;\r
1585                 oNextLName++;                           /* for null */\r
1586                 symtab[sptr].type = type;\r
1587                 symtab[sptr].argoffset = index;\r
1588                 symtab[sptr].dindex = dim_index;\r
1589 \r
1590         }\r
1591         else {                                  /* outside of function, use global */\r
1592                 type |= GLOBAL;\r
1593                 if(index = lookup_global()) {           /* symbol already exists */\r
1594                         if(index & (PROTO|FUNCTION)) {  /* re-definition */\r
1595                                 if((index | (INITED|REFERENCE|EXTERNAL|PROTO)) !=\r
1596                                         (type | (INITED|REFERENCE|EXTERNAL|PROTO)))\r
1597                                         symbol_error("Inconsistant re-declaration");\r
1598                                 symtab[sptr].type = type;\r
1599                                 return;\r
1600                         }\r
1601                         else if (type & STRUCMEM)\r
1602                                  {}             /* no error */\r
1603                         else if ((type & STRUCDEF) &&\r
1604                                          (equal_string(&structname[0], &GPool[symtab[sptr].oname])))\r
1605                                  {}             /* no error */\r
1606                         else {\r
1607                                 symbol_error("Duplicate global");\r
1608                                 return; }\r
1609                 }\r
1610                 sptr = global_top++;\r
1611                 index = global_count++;\r
1612                 if(global_top > local_top)\r
1613                         fatal_error("Symbol table full");\r
1614                 if((oNextGName+SYMBOL_SIZE) > GBUFFSIZE)\r
1615                         fatal_error("Global symbol name pool full");\r
1616                 symtab[sptr].oname = oNextGName;\r
1617                 copystring(&GPool[oNextGName], gst);\r
1618                 oNextGName += namesize;\r
1619                 oNextGName++;                    /* for null */\r
1620                 symtab[sptr].type = type;\r
1621                 symtab[sptr].argoffset = index;\r
1622                 symtab[sptr].dindex = dim_index;\r
1623         }\r
1624 }\r
1625 \r
1626 \r
1627 /******************************************\r
1628 * Push a value on the expression stack\r
1629 *******************************************/\r
1630 \r
1631 static void push(U32 token, U32 value, U32 type, U32 offset)\r
1632 {\r
1633         if(expr_ptr >= EXPR_DEPTH)\r
1634                 fatal_error("Expression stack overflow");\r
1635 \r
1636         expstk[expr_ptr].token = token;\r
1637         expstk[expr_ptr].value = value;\r
1638         expstk[expr_ptr].type  = type;\r
1639         expstk[expr_ptr].offset = offset;\r
1640         expr_ptr++;\r
1641 }\r
1642 \r
1643 /*********************************************\r
1644 * Pop a value from the expression stack\r
1645 **********************************************/\r
1646 \r
1647 static void pop(U32 *token, U32 *value, U32 *type, U32 *offset)\r
1648 {\r
1649         if(!expr_ptr)\r
1650                 fatal_error("Expression stack underflow");\r
1651 \r
1652     expr_ptr--;\r
1653         *token  = expstk[expr_ptr].token;\r
1654         *value  = expstk[expr_ptr].value;\r
1655         *type   = expstk[expr_ptr].type;\r
1656         *offset = expstk[expr_ptr].offset;\r
1657 }\r
1658 \r
1659 \r
1660 /********************************************\r
1661 * Get a constant value (NUMBER or STRING)\r
1662 * which can be evaluated at compile time.\r
1663 *********************************************/\r
1664 \r
1665 static void get_constant(U32 *token, U32 *value)\r
1666 {\r
1667         U32 type, offset;\r
1668 \r
1669         expr_ptr = 0;\r
1670         unget_token(do_oper(SEMI));             /* do_oper gets the token... */\r
1671 \r
1672         pop(token, value, &type, &offset);      /* then we pop it into token */\r
1673 \r
1674         if((*token != NUMBER) && (*token != STRING))\r
1675                 line_error("Constant expression required");\r
1676 }\r
1677 \r
1678 /********************************\r
1679 * Define a variable\r
1680 *********************************/\r
1681 \r
1682 static void define_var(U32 type)\r
1683 {\r
1684         U32 token, stype, lasttoken, value, index, size, i, j, ocbcnt;\r
1685         U32 sDim1, nDims, iDim, eTotal;\r
1686         char eflag, nflag;\r
1687 \r
1688         if(in_function > 1)\r
1689                 line_error("Declaration must preceed code");\r
1690 \r
1691 /* calculate base variable size - store in j for later use if array */\r
1692 \r
1693         if (type&BYTE) size = 1;\r
1694         else if (type&WORD)  size = 2;\r
1695         else if (type&DWORD) size = 4;\r
1696         else if (type&STRUCT)\r
1697                 size = symtab[CrntStrucDef].strucoff;\r
1698         else\r
1699                 line_error("Type specifier missing");\r
1700 \r
1701         if (type&(ARGUMENT | POINTER))  size = 4; /* pointers are 32 bit offsets */\r
1702         j = size;\r
1703 \r
1704 /* If fInStruct then this is a structure member definition.\r
1705    NOT a structure member! */\r
1706 \r
1707         if (fInStruct) {\r
1708                 type |= (STRUCMEM|TYPDEF);                      /* make it a member definition */\r
1709                 for (i=SYMBOL_SIZE; i > 0; i--)         /* fix member name  */\r
1710             gst[i] = gst[i-1];\r
1711         gst[0] = '0';                                   /* make it start with digit */\r
1712         ++namesize;\r
1713         }\r
1714 \r
1715 /* evaluate any array indexes */\r
1716 \r
1717         iDim = dim_top;\r
1718         nflag = 0;\r
1719         nDims = 0;\r
1720         while(test_token(OSB)) {                        /* array definition */\r
1721                 ++nDims;\r
1722                 ++dim_top;\r
1723                 if(test_token(CSB)) {           /* null definition */\r
1724                         if ((nflag) || (nDims > 1))\r
1725                                 line_error("Null only allowed in first index");\r
1726                         --nflag;\r
1727                         size *= dim_pool[dim_top] = 1;  /* dummy up unbounded array */\r
1728                         continue; }\r
1729                 get_constant(&token, &value);\r
1730                 if(token != NUMBER)\r
1731                         line_error("Numeric constant required");\r
1732                 size *= dim_pool[dim_top] = value;\r
1733                 expect(CSB);\r
1734         }\r
1735 \r
1736         if(nDims) {                     /* defining an array */\r
1737                 type |= ARRAY;\r
1738                 dim_pool[iDim] = nDims;\r
1739                 if(++dim_top > DIM_SIZE)\r
1740                         fatal_error("Dimension table full");\r
1741         }\r
1742 \r
1743         if(test_token(ASSIGN))          /* initialized variable */\r
1744                 type |= INITED;\r
1745 \r
1746         local_stack += size;            /* Keep track of offset of local vars */\r
1747 \r
1748         define_symbol(type, iDim);      /* Create the symbol table entry */\r
1749 \r
1750         if (type&(STRUCMEM|TYPDEF)) {\r
1751                 symtab[sptr].itypedef = CrntStrucDef;\r
1752                 symtab[sptr].strucoff = symtab[CrntStrucDef].strucoff;\r
1753             symtab[CrntStrucDef].strucoff += size;      /* add to the total */\r
1754                 }\r
1755 \r
1756         if (type&(STRUCT)) {\r
1757                 symtab[sptr].itypedef = CrntStrucDef;\r
1758                 symtab[sptr].strucoff = symtab[CrntStrucDef].strucoff;\r
1759                 }\r
1760 \r
1761 /*\r
1762    Initialization of arrays has changed with ANSI. Nested braces and\r
1763    trailing commas are now allowed. We make sure the braces balance.\r
1764 */\r
1765         eflag = -1;             /* Expexting initializer */\r
1766         sDim1 = 0;              /* tracks nDimensions for unbounded arrays [] */\r
1767         eTotal = 0;             /* Total elements initialized so far */\r
1768 \r
1769         if(type & INITED) {             /* force immediate allocation */\r
1770                 if ((in_function) || (fInStruct))\r
1771                         line_error("Illegal initialization");\r
1772                 data_global(sptr);      /* generate label in DSeg */\r
1773                 ocbcnt = 0;     /* number of open brackets */\r
1774                 index = 0;              /* tracks index for current dimensions */\r
1775                 do {\r
1776                         switch (token=get_token()) {\r
1777                         case OCB:\r
1778                                 if ((nflag) && (ocbcnt == 1))   /* count for unbounded */\r
1779                                         ++sDim1;\r
1780                                 ocbcnt++;\r
1781                                 if (ocbcnt > nDims)\r
1782                                         line_error("Too many open braces");\r
1783                                 lasttoken = OCB;\r
1784                                 eflag = -1;\r
1785                                 break;\r
1786                         case CCB:\r
1787                                 if (ocbcnt) --ocbcnt;\r
1788                                 else\r
1789                                         line_error("Unbalanced braces");\r
1790                                 if ((nDims > 1) && (ocbcnt))  {\r
1791                                         while (index < dim_pool[dim_top-1]) {\r
1792                                                 init_static(NUMBER, 0, j);\r
1793                                                 ++index;\r
1794                                                 }\r
1795                                         }\r
1796                                 eTotal+=index;          /* total inited so far */\r
1797                                 index = 0;                      /* tracks index for current dimensions */\r
1798                                 eflag = 0;                      /* no constant expected now! */\r
1799                                 lasttoken = CCB;\r
1800                                 break;                          /* we need a comma first/ocb first */\r
1801                         case COMMA:\r
1802                                 /* secial case of char[x][y] = {"abc","def","ghi"}; */\r
1803                                 if ((nDims > 1) && (ocbcnt==1) &&\r
1804                                     (lasttoken==STRING) && !(type & POINTER)) {\r
1805                                         while (index < dim_pool[dim_top-1]) {\r
1806                                                 init_static(NUMBER, 0, j);\r
1807                                                 ++index;\r
1808                                                 }\r
1809                                         eTotal+=index;          /* total inited so far */\r
1810                                         index = 0;\r
1811                                         }\r
1812                                 if (lasttoken==CCB) eflag = 0;\r
1813                                 else eflag = -1;\r
1814                                 lasttoken = COMMA;\r
1815                                 break;\r
1816                         case STRING:\r
1817                                 /* special case of char[x] = "xx"; or char[] = "xx";  */\r
1818                                 if ((!ocbcnt) && (nDims==1))\r
1819                                         eflag = -1;\r
1820                         case NUMBER:\r
1821                         case SUB:\r
1822                         case COM:\r
1823                         case NOT:\r
1824                                 unget_token(token);             /* put it back */\r
1825                                 if (eflag) {                    /* we are expecting a constant */\r
1826                                         if ((nflag) && (ocbcnt == 1))\r
1827                                                 ++sDim1;\r
1828                                         get_constant(&token, &value);\r
1829                                         if((token == STRING) && !(type & POINTER)) {\r
1830                                                 do {\r
1831                                                         init_static(NUMBER, literal_pool[value], j);\r
1832                                                         ++index;}\r
1833                                                 while(++value < literal_top);\r
1834                                                 literal_top = gvalue;\r
1835 \r
1836                                                 /* special case of char[]="xx" or char[x]="xx";  */\r
1837                                                 if ((!ocbcnt) && (nDims==1)) {\r
1838                                                         eTotal = index;\r
1839                                                         sDim1 = index;\r
1840                                                         }\r
1841                                                 }\r
1842                                         else {\r
1843                                                 init_static(token, value, j);\r
1844                                                 if (!nDims)\r
1845                                                         ++eTotal;       /* tracked by index if array */\r
1846                                                 ++index;\r
1847                                                 }\r
1848                                         lasttoken=token;\r
1849                                         }\r
1850                                 else line_error("Improper bracketed initialization");\r
1851                                 break;\r
1852                         case SYMBOL:\r
1853                                 lasttoken=token;\r
1854                                 if (eflag) {    /* we are expecting an initializer */\r
1855                                         if (type&POINTER) {\r
1856                                                 if(stype=lookup_global()) {\r
1857                                                         if (stype&(EXTERNAL|FUNCTION))\r
1858                                                                 symbol_error("Invalid init type");\r
1859                                                         else {\r
1860                                                                 init_static(SYMBOL, sptr, j);\r
1861                                                                 index += j;\r
1862                                                                 }\r
1863                                                         }\r
1864                                                 else symbol_error("Undefined");\r
1865                                                 }\r
1866                                         else line_error("Must be pointer array");\r
1867                                         }\r
1868                                 else line_error("Improper bracketed initialization");\r
1869                                 break;\r
1870                         default:\r
1871                                 line_error("Improper symbol in initialization");\r
1872                                 break;\r
1873                         }\r
1874                 }\r
1875                 while(((ocbcnt) || (lasttoken==COMMA)) && (token!=SEMI));\r
1876                 if(ocbcnt) expect(CCB);         /* make sure brackets balance!! */\r
1877 \r
1878                 if(nflag)                               /* fixup null definition */\r
1879                         dim_pool[iDim+1] = sDim1;\r
1880 \r
1881                 /* new we make sure all the array elements were initialized\r
1882                    to ensure we have allocated Dseg for them.\r
1883                 */\r
1884 \r
1885                 i=1;\r
1886                 while (nDims) i*= dim_pool[iDim+nDims--];       /* i has total elements */\r
1887 \r
1888                 while (eTotal < i) {            /* eTotal is total inited */\r
1889                         init_static(NUMBER, 0, j);\r
1890                         ++eTotal;\r
1891                 }\r
1892 \r
1893                 if (eTotal > i)\r
1894                         line_error("Too many initial values");\r
1895 \r
1896                 end_static();\r
1897 \r
1898         }  /* if (INITED) */\r
1899 \r
1900 }\r
1901 \r
1902 /*****************************************************\r
1903 * Check that we are within a function definition\r
1904 ******************************************************/\r
1905 \r
1906 static void check_func(void)\r
1907 {\r
1908         if(in_function) {\r
1909                 if(in_function < 2) {           /* first invocation */\r
1910                         in_function = 2;\r
1911                         enter_func(fptr, local_stack); } }\r
1912         else\r
1913                 line_error("Incorrect declaration");\r
1914 }\r
1915 \r
1916 /**********************************************************\r
1917 * Declare a symbol (function or variable) with modifiers.\r
1918   If we get here we have found a legal type specifier.\r
1919   Definitions other than structures are quite simple. We\r
1920   loop through eating the variables behind it adding them\r
1921   to the symbol table.\r
1922   Structures are handled differently because you can define\r
1923   a structure with a TAG without actually allocating space.\r
1924   This is actually a type definition.\r
1925   In fact, you can define the structure with an optional\r
1926   tag, then place the variable names right behind it.\r
1927   This checks to see if we have a tag name first. If the tag\r
1928   name is present, we then check to see if it's a defined\r
1929   structure already, in which case we expect a new symbol\r
1930   name will follow. If the tag is not already defined than\r
1931   we expect {} with a structure definition in between!\r
1932 ***********************************************************/\r
1933 \r
1934 static void declare(U32 token, U32 type)\r
1935 {\r
1936     fInStruct = 0;\r
1937         for(;;) {\r
1938                 switch(token) {\r
1939                         case CHAR:\r
1940                                 type &= ~WORD;          /* cancel WORD */\r
1941                                 type |= BYTE;\r
1942                                 break;\r
1943                         case INT:\r
1944                                 if (!(type&DWORD)) type |= WORD;\r
1945                                 break;\r
1946                         case SHORT:\r
1947                                 type |= WORD;\r
1948                                 break;\r
1949                         case LONG:\r
1950                                 type &= ~WORD;          /* cancel WORD */\r
1951                                 type |= DWORD;\r
1952                                 break;\r
1953                         case UNSIGN:\r
1954                                 type |= WORD;           /* cancelled for char or long */\r
1955                                 type |= UNSIGNED;\r
1956                                 break;\r
1957                         case SIGNED:\r
1958                                 type |= WORD;           /* this will be cancelled if it's long */\r
1959                                 type &= ~UNSIGNED;\r
1960                                 break;\r
1961                         case STAT:\r
1962                                 type |= STATIC;\r
1963                                 break;\r
1964                         case STRUC:\r
1965                                 type |= STRUCDEF;\r
1966                                 break;\r
1967                         case CONST:\r
1968                                 type |= CONSTANT;\r
1969                                 break;\r
1970                         case EXTERN:\r
1971                                 type |= EXTERNAL;\r
1972                                 break;\r
1973                         case REGIS:\r
1974                                 type |= REGISTER;\r
1975                                 break;\r
1976                         case INTR:\r
1977                                 type |= ISR;    /* ISR modified for functions */\r
1978                                 break;\r
1979                         case VOIDD:\r
1980                                 type |= VOID;\r
1981                                 break;\r
1982                         case FARR:\r
1983                                 type |= FAR;\r
1984                                 break;\r
1985                         case STAR:              /* pointer reference */\r
1986                                 do\r
1987                                         ++type;\r
1988                                 while(test_token(STAR));\r
1989 \r
1990                                 /* allow for prototype arg pointers with no symbol name */\r
1991 \r
1992                                 if((type&ARGUMENT) && (test_token(COMMA))) {\r
1993                                         define_var(type|=PROTO); /* tell 'em it may be symboless */\r
1994                                         return;\r
1995                                         }\r
1996                                 else\r
1997                                 if(!test_token(SYMBOL)) syntax_error();\r
1998                         case SYMBOL:            /* we have a symbol name */\r
1999                                 /* If STRUCDEF, MUST be a Struct Tag Name (new or existing) */\r
2000                                 if(type & STRUCDEF) {      /* This symbol follows "struct" */\r
2001                                         if (lookup_global()) {   /* Existing tag ?? */\r
2002                                                 if (symtab[sptr].type & STRUCDEF) {\r
2003                                     CrntStrucDef = sptr;  /* tag we just found */\r
2004                                                         /* might be a pointer to a structure */\r
2005                                                         if (test_token(STAR))\r
2006                                                                 do\r
2007                                                                         ++type;\r
2008                                                                 while(test_token(STAR));\r
2009                                                         /* now expect a new structure variable name */\r
2010                                                         if(!test_token(SYMBOL)) {\r
2011                                                           line_error("struct variable expected");\r
2012                                                           return;\r
2013                                                         }\r
2014                                                         else {\r
2015                                                           type &= ~STRUCDEF; /* struct variable w/tag */\r
2016                                                           type |= STRUCT;\r
2017                                                         }\r
2018                                                 }\r
2019                                                 else\r
2020                                                   line_error("struct tag name expected");\r
2021                                         }\r
2022 \r
2023                                         /* we didn't find the tag so it must be a new one! */\r
2024 \r
2025                                         else {     /* So add the strucdef */\r
2026                                                 define_symbol(type|TYPDEF, 0);\r
2027                             CrntStrucDef = sptr;        /* symbol we just found */\r
2028                                                 if(!(test_token(OCB)))   /* expecting {          */\r
2029                                                   line_error("Structure { expected");\r
2030                                                 else {\r
2031                                                 fInStruct = 1;            /* we are in it now...  */\r
2032                                                 type = 0;\r
2033                                                 break;\r
2034                                                 }\r
2035                                         }\r
2036                                 }\r
2037                                 if(type&ARGUMENT) {\r
2038                                         define_var(type);\r
2039                                         return;\r
2040                                         }\r
2041                                 if(test_token(ORB))\r
2042                                         define_func(type);      /* function definition */\r
2043                                 else\r
2044                                         define_var(type);       /* variable definition */\r
2045                                 if(test_token(COMMA))\r
2046                                         break;\r
2047 \r
2048                                 test_token(SEMI);  /* eat the semicolon if there */\r
2049 \r
2050                                 if (fInStruct) {        /* still defining struct members */\r
2051                                         type = 0;\r
2052                                         break;\r
2053                                         }\r
2054                                 else\r
2055                                         return;\r
2056                         case OCB:               /* '{' only allowed for immediate struct defs */\r
2057                                 if(type & STRUCDEF) {    /* Immediate struct definition */\r
2058                                         copystring(gst, structname);\r
2059                                         gvalue = 11;\r
2060                                         define_symbol(type|TYPDEF, 0);\r
2061                     CrntStrucDef = sptr;  /* symbol we just added */\r
2062                                 fInStruct = 1;            /* we are in it now...  */\r
2063                                 type = 0;\r
2064                                         break;\r
2065                                         }\r
2066                                 else\r
2067                                         syntax_error();\r
2068                                 break;\r
2069                         case CCB:\r
2070                                 if (!fInStruct) {\r
2071                                         syntax_error();\r
2072                                         return;\r
2073                                         }\r
2074                                 else {\r
2075                                     type &= ~STRUCDEF; /* struct variable */\r
2076                                     type |= STRUCT;\r
2077                                         fInStruct = 0;\r
2078                                         }\r
2079                                 if (test_token(SEMI))  /* if semicolon, eat it and return */\r
2080                                         return;\r
2081                                 break;\r
2082                         case CRB:\r
2083                                 unget_token(token);             /* fall thru to COMMA */\r
2084                         case COMMA:\r
2085                                 if(type&ARGUMENT) {\r
2086                                         define_var(type|=PROTO);\r
2087                                         return;\r
2088                                         }\r
2089                                 break;\r
2090                         default:\r
2091                                 syntax_error();\r
2092 \r
2093                  }\r
2094                 type &= ~(POINTER | ARRAY);  /* clear indirection and rg of last var */\r
2095                 token = get_token();\r
2096         }\r
2097 }\r
2098 \r
2099 /**************************************************************\r
2100 Define a function\r
2101 \r
2102 Notes on prototype handling:\r
2103 \r
2104 We have an array called proto_list and an index to the list called\r
2105 iproto_next. For any function (external or global), we keep track\r
2106 of the argument types in the proto list.  We do this by assuming that the\r
2107 first time a function is identified, we define it as if it was a real\r
2108 function.  If it turns out to be a proto, we just throw away the\r
2109 local arguments and mark it as proto.  If we find a function that is\r
2110 being defined and it's args don't match the defined types, emit a warning\r
2111 or error (if type is not convertable).\r
2112 In any case, this means we now know what type of argument\r
2113 to expect for any function that is called. We can do the proper\r
2114 type manipulations and flag errors when found.\r
2115 This also means you must prototype all external function, and\r
2116 that all of them MUST have all arguments defined!!!\r
2117 As per ANSI - the proto MUST contain the type of each arg, and\r
2118 may or may not provide a name for each arg.\r
2119 \r
2120 For functions that are defined with variable parameter lists (unknown\r
2121 numbers of args and type), we add a single identifier in the Proto list\r
2122 that indicates this.  The arg definition for variable parameters is\r
2123 an elipse (...).\r
2124 All args in a function with variable args are accessed differently than\r
2125 those with fixed parameters.  Normally the EBP register accesses the\r
2126 args with a fixed offset.  When you have variable args (and becuase we\r
2127 push args from left to right) we won't know where the fixed args are or\r
2128 where the variable args begin.  To find out where they are and access them\r
2129 we push the number of variable args as the last arg on the stack.\r
2130 From this value we can determine where the variable args begin and the fixed\r
2131 args leave off.  We access the fixed args with [EBP+EDI+offset]\r
2132 to access the args.  This is because the fucntion "va_arg" will set\r
2133 EDI up with the proper context to access the variable required. See\r
2134 stdarg.c for more information.\r
2135 \r
2136 ****************************************************************/\r
2137 \r
2138 static void define_func(U32 type)\r
2139 {\r
2140         U32 token, dim_save, t, flastarg, i, stackpop;\r
2141 \r
2142         icrntpro = 0;\r
2143         flastarg = 0;\r
2144         arg_count = 0;\r
2145         oNextLName = 0;\r
2146 \r
2147         /* do not allow functions or protos within functions */\r
2148 \r
2149         if(in_function) {\r
2150                 line_error("Illegally nested function or prototype");\r
2151                 return;\r
2152         }\r
2153 \r
2154         if(t = lookup_global()) {               /* symbol already exists */\r
2155                 if (t & PROTO) {\r
2156                         icrntpro = symtab[sptr].dindex; /* icrntpro points to arg types */\r
2157                 }\r
2158         }\r
2159         else {\r
2160                 define_symbol(type | FUNCTION | GLOBAL, 0);\r
2161         symtab[sptr].dindex = iproto_next;\r
2162         }\r
2163 \r
2164         fptr = sptr;\r
2165 \r
2166 /* accept variable declarations for local arguments */\r
2167 /* These must be inside the parens -- ANSI style    */\r
2168 \r
2169         local_top = MAX_SYMBOLS;\r
2170         dim_save = dim_top;\r
2171         in_function = 1;                                        /* indicate inside a function */\r
2172 \r
2173         do {\r
2174                 switch(token = get_token()) {   /* define local arguments */\r
2175                         case SHORT:\r
2176                         case LONG:\r
2177                         case INT:\r
2178                         case SIGNED:\r
2179                         case UNSIGN:\r
2180                         case CHAR:\r
2181                         case FAR:\r
2182                         case CONST:\r
2183                         case STRUC:\r
2184                                 declare(token, ARGUMENT);\r
2185                                 arg_count += 1;\r
2186                                 break;\r
2187                         case COMMA: break;\r
2188                         case ELIPSE:\r
2189                                 proto_list[iproto_next++] = VOID;\r
2190                                 flastarg = -1;\r
2191                                 symtab[fptr].type |= VARARGS;\r
2192                                 break;\r
2193                         case VOIDD:\r
2194                                 if (arg_count) syntax_error();  /* fall through to default */\r
2195                         default:\r
2196                                 if (!flastarg) {\r
2197                                         proto_list[iproto_next++] = VOID;\r
2198                                         if(iproto_next>MAX_PROTOS)\r
2199                                           fatal_error("Prototype table full");\r
2200                                         flastarg = -1;\r
2201                                 if (token==CRB) unget_token(token);\r
2202                                 }\r
2203                                 break;\r
2204                 }\r
2205         } while (!flastarg);\r
2206 \r
2207         token = get_token();\r
2208         if(token != CRB)\r
2209                 syntax_error();\r
2210 \r
2211         if(test_token(SEMI)) {          /* a prototype function !! */\r
2212                 symtab[fptr].type |= PROTO;\r
2213                 in_function = 0;\r
2214                 exit_label = 0;\r
2215                 exit_flag = 0;\r
2216                 exit_used = 0;\r
2217                 dim_top = dim_save;\r
2218                 if (symtab[fptr].type & EXTERNAL)\r
2219                         gen_extern_DASM(fptr);\r
2220                 }\r
2221         else {\r
2222                 symtab[fptr].type &= ~PROTO;\r
2223                 symtab[fptr].type |= FUNCTION;\r
2224                 local_stack = 0;\r
2225                 exit_label = 0;\r
2226                 exit_flag = 0;\r
2227                 exit_used = 0;\r
2228                 stackpop = 0;\r
2229 \r
2230                 /* Loop through the args putting in correct stack offsets\r
2231                 NOTE: For running 32 bit code in a 16 bit environment, the\r
2232                 value to be added to stackpop is 6 for each item on the stack.\r
2233                 For a 32 bit environment its 8 for each.\r
2234 \r
2235          +-----+-----+ xx\r
2236          |Last param |     The last parameter pushed is here\r
2237          +-----+-----+ 06/8/0C\r
2238          | n Bytes   |     Return Address (2, 4 or 8)\r
2239          +-----+-----+ 04\r
2240          | 4 Bytes   |     Previous Frame Pointer\r
2241          +-----+-----+ 00\r
2242 \r
2243                 The Return Address is either 2, 4 or 8 bytes depending on\r
2244                 the environment and whether the call was Near or Far.\r
2245                 16 Bit segments -  n = 2 for Near, 4 for Far\r
2246                 32 Bit segments -  n = 4 for Near, 8 for Far\r
2247 \r
2248                 */\r
2249 \r
2250                 for(i=arg_count; i>0; i--) {\r
2251                         if (symtab[fptr].type & FAR)\r
2252                                 symtab[MAX_SYMBOLS-i].argoffset = stackpop+12; /* 12 for 32 far */\r
2253                         else\r
2254                                 symtab[MAX_SYMBOLS-i].argoffset = stackpop+8; /* 8 for MMURTL */\r
2255                         stackpop += 4;\r
2256                 }\r
2257                 statement(token=get_token());\r
2258                 check_func();   /* ensure enter gets written in null func */\r
2259                 if((exit_label) && (exit_used))\r
2260                         gen_label(exit_label);\r
2261                 if (symtab[fptr].type & VARARGS)\r
2262                         end_func(0);\r
2263                 else\r
2264                         end_func(stackpop);\r
2265                 in_function = 0;\r
2266                 exit_label = 0;\r
2267                 exit_flag = 0;\r
2268                 exit_used = 0;\r
2269                 dim_top = dim_save;\r
2270 \r
2271                 /* Error reporting when end of func is reached and certain\r
2272                    conditions exist */\r
2273 \r
2274                 while(local_top < MAX_SYMBOLS) {\r
2275                         if((token = symtab[local_top].type) & EXTERNAL)\r
2276                                 t_error("Unresolved", &LPool[symtab[local_top].oname]);\r
2277                         if(!(token & REFERENCE))\r
2278                                 t_warn("Unreferenced", &LPool[symtab[local_top].oname]);\r
2279                         ++local_top; }\r
2280                 return;\r
2281         }\r
2282 }\r
2283 \r
2284 /***********************************************************************\r
2285   Write an assembler string to access an operand value.\r
2286   Certain types of operands may require type inducers suxh as "BYTE PTR."\r
2287 ************************************************************************/\r
2288 static void write_oper(U32 token, U32 value, U32 type, U32 offset)\r
2289 {\r
2290 \r
2291         switch(token) {\r
2292                 case INEAX:\r
2293                         code_str("EAX");\r
2294                         break;\r
2295                 case NUMBER:\r
2296                         code_num(value);\r
2297                         break;\r
2298                 case STRING:\r
2299                         code_str("OFFSET ");\r
2300                         code_chr(prefix);\r
2301                         code_str("_lit+");\r
2302                         code_num(value);\r
2303                         break;\r
2304                 case SYMBOL:\r
2305                         if(type & GLOBAL) {\r
2306                                 code_chr('_');          /* prefix with _ */\r
2307                                 code_str(&GPool[symtab[value].oname]);\r
2308                                 break; }\r
2309                         if(type & ARGUMENT)\r
2310                         {\r
2311                                 if (symtab[fptr].type & VARARGS)\r
2312                                 {\r
2313                                         if (type&(DWORD|POINTER))\r
2314                                                 code_str("DWORD PTR [EBP+EDI+");\r
2315                                         else if (type & WORD)\r
2316                                                 code_str("WORD PTR [EBP+EDI+");\r
2317                                         else\r
2318                                                 code_str("BYTE PTR [EBP+EDI+");\r
2319                                         code_num(symtab[value].argoffset);\r
2320                                         code_chr(']');\r
2321                                 }\r
2322                                 else\r
2323                                 {\r
2324                                         if (type&(DWORD|POINTER))\r
2325                                                 code_str("DWORD PTR [EBP+");\r
2326                                         else if (type & WORD)\r
2327                                                 code_str("WORD PTR [EBP+");\r
2328                                         else\r
2329                                                 code_str("BYTE PTR [EBP+");\r
2330                                         code_num(symtab[value].argoffset);\r
2331                                         code_chr(']');\r
2332                                 }\r
2333                         }\r
2334                         else\r
2335                         {\r
2336                                 if (type&(DWORD|POINTER))\r
2337                                         code_str("DWORD PTR [EBP-");\r
2338                                 else if (type & WORD)\r
2339                                         code_str("WORD PTR [EBP-");\r
2340                                 else\r
2341                                         code_str("BYTE PTR [EBP-");\r
2342                                 code_num(symtab[value].argoffset);\r
2343                                 code_chr(']');\r
2344                         }\r
2345                         break;\r
2346                 case INECX:\r
2347                         code_str("ECX");\r
2348                         break;\r
2349                 case INEDX:\r
2350                         code_str("EDX");\r
2351                         break;\r
2352                 case PESI:\r
2353                 case PEDX:\r
2354                 case PECX:                      /* pointer in other reg - indirect access */\r
2355                 case ISTACK_TOP:\r
2356                         if (type&(DWORD|POINTER))\r
2357                                 code_str("DWORD PTR ");\r
2358                         else if (type & WORD)\r
2359                                 code_str("WORD PTR ");\r
2360                         else\r
2361                                 code_str("BYTE PTR ");\r
2362 \r
2363                         if (offset)\r
2364                         {\r
2365                                 if (token==PESI)\r
2366                                         code_str("[ESI+");\r
2367                                 else if (token==PECX)\r
2368                                         code_str("[ECX+");\r
2369                                 else if (token==PEDX)\r
2370                                         code_str("[EDX+");\r
2371                                 else\r
2372                                         code_str("[EBX+");\r
2373                                 code_num(offset);\r
2374                                 code_chr(']');\r
2375                         }\r
2376                         else\r
2377                         {\r
2378                                 if (token==PESI)\r
2379                                         code_str("[ESI]");\r
2380                                 else if (token==PEDX)\r
2381                                         code_str("[EDX]");\r
2382                                 else if (token==PECX)\r
2383                                         code_str("[ECX]");\r
2384                                 else\r
2385                                         code_str("[EBX]");\r
2386                         }\r
2387                         break;\r
2388                 case STACK_TOP:\r
2389                         code_str("EBX");\r
2390                         break;\r
2391 \r
2392                 case ION_STACK:         /* shouldn't happen */\r
2393                 case ON_STACK:\r
2394                 default:                /* Unknown (error) */\r
2395                         code_num(token);\r
2396                         code_str(" ERROR in write_oper\n");\r
2397         }\r
2398 }\r
2399 \r
2400 \r
2401 /**************************************************\r
2402   Places operand in code string and sends instruction\r
2403   out to code segment.\r
2404 **************************************************/\r
2405 \r
2406 static void GenCodeOper(char *ptr, U32 token, U32 value, U32 type, U32 offset)\r
2407 {\r
2408         /* interpret the output string & insert the operand */\r
2409 \r
2410         code_chr('\t');\r
2411         while(*ptr) {\r
2412                 if(*ptr == '|')\r
2413                         write_oper(token, value, type, offset);\r
2414                 else\r
2415                         code_chr(*ptr);\r
2416                 ++ptr;\r
2417         }\r
2418         code_chr('\n');\r
2419 }\r
2420 \r
2421 /*************************************************************\r
2422   Examine the expression stack and see if any active token\r
2423   is in EAX. If so, place it on the stack.\r
2424   The stack top is really the EBX register. If we find\r
2425   an active item in the EBX register, we must place\r
2426   it on the real processor stack first and change it's\r
2427   token to show where it is.\r
2428 **************************************************************/\r
2429 \r
2430 static void StackEAX(void)\r
2431 {\r
2432         S32 i, j;\r
2433 \r
2434         for(i=0; i < expr_ptr; ++i) {\r
2435                 if (expstk[i].token == INEAX)           /* Found it */\r
2436                 {\r
2437                         for(j=0; j < expr_ptr; ++j)\r
2438                         {\r
2439                                 if ((expstk[j].token == STACK_TOP) ||\r
2440                                         (expstk[j].token == ISTACK_TOP))\r
2441                                 {\r
2442                                         out_inst("PUSH EBX");\r
2443                                         if (expstk[j].token == STACK_TOP)\r
2444                         expstk[j].token = ON_STACK;\r
2445                                         else\r
2446                         expstk[j].token = ION_STACK;\r
2447                                         break;\r
2448                                 }\r
2449                         }\r
2450                         test_not();\r
2451                         out_inst("MOV EBX,EAX");\r
2452                         expstk[i].token = STACK_TOP;\r
2453                 }\r
2454         }\r
2455 }\r
2456 \r
2457 /**********************************************************\r
2458  If the token we need is actually on the processor stack,\r
2459  we must must pop it out so we can use it. To do this,\r
2460  we pop it into EDX. EDX is only used for multiply and\r
2461  divide operations otherwise.\r
2462 ***********************************************************/\r
2463 static U32 CheckStack(U32 token)\r
2464 {\r
2465         if (token==ION_STACK)\r
2466         {\r
2467                 out_inst("POP EDX");\r
2468                 token = PEDX;\r
2469         }\r
2470         else if (token==ON_STACK)\r
2471         {\r
2472                 out_inst("POP EDX");\r
2473                 token = INEDX;\r
2474         }\r
2475         return(token);\r
2476 }\r
2477 \r
2478 /**************************************************************\r
2479  Get a parameter into the EAX register.\r
2480  The value/register is always sign or zero extended to 32 bits!\r
2481 ***************************************************************/\r
2482 \r
2483 static void LoadEAX(U32 token, U32 value, U32 type, U32 offset)\r
2484 {\r
2485         if(type & FUNCTION)\r
2486                 type_error();\r
2487 \r
2488         if(token == INEAX) {            /* Already there */\r
2489                 test_not();\r
2490                 return;\r
2491         }\r
2492 \r
2493         token = CheckStack(token);   /* If it's on the processor stack, get it into EDX */\r
2494 \r
2495         StackEAX();                             /* stack EAX if needed */\r
2496         not_flag = 0;\r
2497 \r
2498         if((token == NUMBER) && (!value)) {             /* 0 Value */\r
2499                 test_not();\r
2500                 code_str("\tXOR EAX,EAX\n");\r
2501                 return;\r
2502         }\r
2503 \r
2504         if ((type&(DWORD|POINTER)) ||\r
2505                 (token == NUMBER) ||\r
2506                 (token == INEDX) ||\r
2507                 (token == STACK_TOP) ||\r
2508                 (token == INECX))\r
2509 \r
2510                 GenCodeOper("MOV EAX,|", token, value, type, offset);\r
2511         else if (type & WORD)\r
2512         {\r
2513                 if (type & UNSIGNED)\r
2514                         GenCodeOper("MOVZX EAX,|", token, value, type, offset);\r
2515                 else\r
2516                         GenCodeOper("MOVSX EAX,|", token, value, type, offset);\r
2517         }\r
2518         else\r
2519         {\r
2520                 if (type & UNSIGNED)\r
2521                 {\r
2522                         code_str("\tXOR EAX,EAX\n");\r
2523                         GenCodeOper("MOV AL,|", token, value, type, offset);\r
2524                 }\r
2525                 else\r
2526                         GenCodeOper("MOVSX EAX,|", token, value, type, offset);\r
2527         }\r
2528 \r
2529         zero_flag = -1;\r
2530 }\r
2531 \r
2532 /**************************************************************\r
2533  Get a parameter into the ECX register.\r
2534  The value/register is always sign or zero extended to 32 bits!\r
2535 ***************************************************************/\r
2536 \r
2537 static void LoadECX(U32 token, U32 value, U32 type, U32 offset)\r
2538 {\r
2539         if(type & FUNCTION)\r
2540                 type_error();\r
2541 \r
2542         if(token == INECX)\r
2543         {               /* Already there */\r
2544                 return;\r
2545         }\r
2546 \r
2547         token = CheckStack(token);   /* If it's on the processor stack, get it into EDX */\r
2548 \r
2549         if ((token == NUMBER) && (!value))\r
2550         {               /* 0 Value */\r
2551                 code_str("\tXOR ECX,ECX\n");\r
2552                 return;\r
2553         }\r
2554 \r
2555         if ((type&(DWORD|POINTER)) ||\r
2556                 (token == NUMBER) ||\r
2557                 (token == INEDX) ||\r
2558                 (token == STACK_TOP) ||\r
2559                 (token == INEAX))\r
2560 \r
2561                 GenCodeOper("MOV ECX,|", token, value, type, offset);\r
2562         else if (type & WORD) {\r
2563                 if (type & UNSIGNED)\r
2564                         GenCodeOper("MOVZX ECX,|", token, value, type, offset);\r
2565                 else\r
2566                         GenCodeOper("MOVSX ECX,|", token, value, type, offset);\r
2567         }\r
2568         else\r
2569         {\r
2570                 if (type & UNSIGNED)\r
2571                 {\r
2572                         code_str("\tXOR ECX,ECX\n");\r
2573                         GenCodeOper("MOV CL,|", token, value, type, offset);\r
2574                 }\r
2575                 else\r
2576                         GenCodeOper("MOVSX ECX,|", token, value, type, offset);\r
2577         }\r
2578 }\r
2579 \r
2580 \r
2581 /****************************************************************\r
2582 * Evaluate a sub expression & handle COMMA operator. This must\r
2583 * be done as a special case, because the function performed by\r
2584 * COMMA differs with the context of the expression, and can not\r
2585 * therefore be handled as a general operator.\r
2586 *****************************************************************/\r
2587 \r
2588 static void sub_eval(U32 term)\r
2589 {\r
2590 U32 token;\r
2591 \r
2592         for(;;) {\r
2593                 if((token = do_oper(SEMI)) != COMMA) {\r
2594                         unget_token(token);\r
2595                         expect(term);\r
2596                         return;\r
2597                 }\r
2598                 pop(&token, &token, &token, &token);    /* throw it away */\r
2599         }\r
2600 }\r
2601 \r
2602 \r
2603 /********************************************************\r
2604 * Evaluate a full expression at the highest level, and\r
2605 * load the result into the accumulator if necessary.\r
2606 *********************************************************/\r
2607 \r
2608 static void eval(U32 term, char flag)\r
2609 {\r
2610 U32 token, value, type, offset;\r
2611 \r
2612         expr_ptr = 0;\r
2613         not_flag = 0;\r
2614         sub_eval(term);\r
2615 \r
2616         pop(&token, &value, &type, &offset);\r
2617         if((token != INEAX) || flag)\r
2618                 LoadEAX(token, value, type, offset);\r
2619 }\r
2620 \r
2621 /************************************************\r
2622 * Write an instruction with text formatting\r
2623   to the code tmp file\r
2624 *************************************************/\r
2625 \r
2626 static void out_inst(char *ptr)\r
2627 {\r
2628         code_chr('\t');\r
2629         code_str(ptr);\r
2630         code_chr('\n');\r
2631 }\r
2632 \r
2633 \r
2634 /*************************************************************\r
2635   Examine the expression stack and see if any active token\r
2636   is in the EBX register which acts as the stack top for\r
2637   fast access. If so, put it on the real stack because\r
2638   we must preserve it through a call.\r
2639 **************************************************************/\r
2640 \r
2641 static void StackTop(void)\r
2642 {\r
2643         S32  j;\r
2644 \r
2645         for(j=0; j < expr_ptr; ++j)\r
2646         {\r
2647                 if ((expstk[j].token == STACK_TOP) ||\r
2648                         (expstk[j].token == ISTACK_TOP))\r
2649                 {\r
2650                         out_inst("PUSH EBX");\r
2651                         if (expstk[j].token == STACK_TOP)\r
2652                         expstk[j].token = ON_STACK;\r
2653                         else\r
2654                     expstk[j].token = ION_STACK;\r
2655                         break;\r
2656                 }\r
2657         }\r
2658 }\r
2659 \r
2660 \r
2661 /*************************************************************\r
2662   Examine the expression stack and see if any active token\r
2663   is in the Index Reg. If so, place it on the stack.\r
2664   The stack top is really the EBX register. If we find\r
2665   an active item in the EBX register, we must place\r
2666   it on the real processor stack first and change it's\r
2667   token to show where it is.\r
2668 **************************************************************/\r
2669 \r
2670 static void StackESI(void)\r
2671 {\r
2672         S32 i, j;\r
2673 \r
2674         for(i=0; i < expr_ptr; ++i) {\r
2675                 if (expstk[i].token == PESI)            /* Found it */\r
2676                 {\r
2677                         for(j=0; j < expr_ptr; ++j)\r
2678                         {\r
2679                                 if ((expstk[j].token == STACK_TOP) ||\r
2680                                         (expstk[j].token == ISTACK_TOP))\r
2681                                 {\r
2682                                         out_inst("PUSH EBX");\r
2683                                         if (expstk[j].token == STACK_TOP)\r
2684                         expstk[j].token = ON_STACK;\r
2685                                         else\r
2686                         expstk[j].token = ION_STACK;\r
2687                                         break;\r
2688                                 }\r
2689                         }\r
2690                         out_inst("MOV EBX,ESI");\r
2691                         expstk[i].token = ISTACK_TOP;\r
2692                 }\r
2693         }\r
2694 }\r
2695 \r
2696 \r
2697 /*****************************************\r
2698 * Load index address for an array\r
2699 ******************************************/\r
2700 \r
2701 static void load_index(U32 t, U32 v, U32 tt, U32 o)\r
2702 {\r
2703                 StackESI();\r
2704                 if((tt & ARGUMENT) || !(tt & ARRAY))    /* pointer or argument */\r
2705                         index_ptr(t, v, tt, o);\r
2706                 else                                                                    /* standard array */\r
2707                         index_adr(t, v, tt, o);\r
2708 }\r
2709 \r
2710 \r
2711 /*************************************************************************\r
2712 * Evaluate a unary operation, if possible, evaluate constant expressions\r
2713 * into another constant. Produce code to perform operation if necessary.\r
2714 **************************************************************************/\r
2715 \r
2716 static void do_unary(U32 oper)\r
2717 {\r
2718         U32 token, value, type, offset;\r
2719         char flag;\r
2720 \r
2721         pop(&token, &value, &type, &offset);\r
2722         flag = 0;\r
2723         /* Evaluate any operations that can be performed at compile time */\r
2724         if(token == NUMBER)\r
2725         {\r
2726                 flag = -1;\r
2727                 switch(oper)\r
2728                 {\r
2729                         case SUB :              /* unary minus */\r
2730                                 value = -value;\r
2731                                 break;\r
2732                         case COM:               /* ones complement */\r
2733                                 value = ~value;\r
2734                                 break;\r
2735                         case NOT:               /* logical complement */\r
2736                                 value = !value;\r
2737                                 break;\r
2738                         default:\r
2739                                 flag = 0;\r
2740                 }\r
2741         }\r
2742 \r
2743         /* Generate code to perform operation */\r
2744         if(!flag)\r
2745         {\r
2746                 switch(oper)\r
2747                 {\r
2748                         case SUB:                               /* unary minus */\r
2749                                 GenCodeOper("NEG |", token, value, type, offset);\r
2750                                 break;\r
2751                         case COM:                               /* ones complement */\r
2752                                 GenCodeOper("NOT |", token, value, type, offset);\r
2753                                 break;\r
2754                         case NOT:                               /* logical complement */\r
2755                                 LoadEAX(token, value, type, offset);\r
2756                                 token = INEAX;\r
2757                                 not_flag = TRUE;\r
2758                                 break;\r
2759                         case INC:                               /* '++' increment token & load */\r
2760                                 if (ispStruct(type, value))\r
2761                                         GenCodeOper("ADD |,strucsize", token, value, type, offset);\r
2762                                 else if (isp32(type))\r
2763                                         GenCodeOper("ADD |,4", token, value, type, offset);\r
2764                                 else if (isp16(type))\r
2765                                         GenCodeOper("ADD |,2", token, value, type, offset);\r
2766                                 else\r
2767                                         GenCodeOper("INC |", token, value, type, offset);\r
2768                                 break;\r
2769                         case DEC:                               /* '--' decrement & store */\r
2770                                 if (ispStruct(type, value))\r
2771                                         GenCodeOper("SUB |,strucsize", token, value, type, offset);\r
2772                                 else if (isp32(type))\r
2773                                         GenCodeOper("SUB |,4", token, value, type, offset);\r
2774                                 else if (isp16(type))\r
2775                                         GenCodeOper("SUB |,2", token, value, type, offset);\r
2776                                 else\r
2777                                         GenCodeOper("DEC |", token, value, type, offset);\r
2778                                 break;\r
2779                         default:\r
2780                                 syntax_error();\r
2781                 }\r
2782         }\r
2783         push(token, value, type, offset);\r
2784 }\r
2785 \r
2786 \r
2787 /******************************************************\r
2788  This evaluates array indeces for get_value.\r
2789 *******************************************************/\r
2790 \r
2791 static S8 eval_index(U32 t, U32 v, U32 tp, U32 ofs, U32 *tpRet)\r
2792 {\r
2793         S32 ndim;\r
2794         U32 tp1, dptr, iSym, vsize, ofs1;\r
2795         char fMultiDim;\r
2796 \r
2797         fMultiDim = FALSE;      /* true when processing second or subsequent dims */\r
2798 \r
2799         if(tp & ARRAY) {                        /* array, get # dimensions */\r
2800                 dptr = symtab[v].dindex;\r
2801                 ndim = dim_pool[dptr++];\r
2802                 }\r
2803         else                                    /* pointer, fake # dims as 1 */\r
2804                 dptr = ndim = 1;\r
2805 \r
2806         iSym = v;                       /* save index into symtab */\r
2807 \r
2808         push(t, v, tp, ofs);    /* save symbol we are indexing on exp stack */\r
2809 \r
2810         do {                            /* calculate index */\r
2811 \r
2812                 /* this gets the size of variable into vsize */\r
2813 \r
2814                 v = tp & (POINTER | ARRAY);\r
2815                 if ((v==ARRAY) || (v < 2)) {\r
2816                          if (tp & BYTE) vsize = 1;\r
2817                          else if (tp & WORD) vsize = 2;\r
2818                          else if (tp & DWORD) vsize = 4;\r
2819                          else if (tp & STRUCT)\r
2820                                 vsize = symtab[iSym].strucoff; /* strucoff = size of struc*/\r
2821                  }\r
2822                 else vsize = 4;\r
2823                 --ndim;\r
2824                 if(tp & ARRAY)                  /* array reference */\r
2825                 {\r
2826                         t = ++dptr;\r
2827                         if(!(v = ndim))         /* all indices given, load pointer */\r
2828                                 tp &= ~ARRAY;   /* Not an array ref anymore, ptr instead */\r
2829                         while(v--)\r
2830                                 vsize *= dim_pool[t++];\r
2831                 }\r
2832                 else\r
2833                 {\r
2834                         if(tp & POINTER)\r
2835                         {               /* pointer reference */\r
2836                                 --tp;                           /* drop defer level by one */\r
2837                                 if(fMultiDim)\r
2838                                 {                                       /* array of pointers */\r
2839                                         pop(&t, &v, &tp1, &ofs1);\r
2840                                         LoadEAX(t, v, tp1, ofs1);\r
2841                                         pop(&t, &v, &tp1, &ofs1);\r
2842                                         load_index(t, v, tp1, ofs1);\r
2843                                         out_inst("ADD ESI,EAX");\r
2844                                         push(t = PESI, v, tp, ofs1);\r
2845                                         fMultiDim = 0;\r
2846                                 }\r
2847                         }\r
2848                         else                                    /* invalid indexing */\r
2849                                 index_error();\r
2850                 }\r
2851                 sub_eval(CSB);          /* GET the value inside the [] */\r
2852 \r
2853                         /* Multiply [] by size of index */\r
2854 \r
2855                 if(vsize != 1) {        /* optimize away size of 1 */\r
2856                         push(NUMBER, vsize, DWORD, 0);\r
2857                         do_lr2op(STAR);                         /* multiply by size */\r
2858                 }\r
2859                 if(fMultiDim) do_lr2op(ADD);    /* add to last index if there */\r
2860                 fMultiDim = TRUE;                               /* if there is another... */\r
2861         }\r
2862         while(test_token(OSB));\r
2863 \r
2864         *tpRet = tp;\r
2865         return fMultiDim;\r
2866 }\r
2867 \r
2868 /******************************************************\r
2869  Gets the next token and perform any processing\r
2870  required to evaluate it.  This includes structure\r
2871  members.\r
2872 *******************************************************/\r
2873 \r
2874 static void get_value(void)\r
2875 {\r
2876         S32 ndim, vcnt;\r
2877         U32 i, j, size, token, t, v, tp, tp1, ofs;\r
2878         char fMultiDim, fvarargs;\r
2879 \r
2880         switch(token = get_token()) {\r
2881                 case NUMBER:                    /* a constant number */\r
2882                         t = NUMBER;                     /* constant */\r
2883                         v = gvalue;                     /* value of number */\r
2884                         tp = DWORD;                     /* all constants are DWORDS */\r
2885                         ofs = 0;                        /* no constant offset */\r
2886                         break;\r
2887                 case STRING:                    /* a literal string */\r
2888                         t = STRING;                     /* will be found in lit pool */\r
2889                         v = gvalue;                     /* length of string  */\r
2890                         tp = BYTE | 1;      /* 1 is level of indirection  */\r
2891                         ofs = 0;                        /* offset of zero */\r
2892                         break;\r
2893                 case SYMBOL:                    /* symbol value */\r
2894                         if(!(lookup_local() || lookup_global())) {              /* not defined */\r
2895                                 if(test_token(ORB)) {                   /* function, but no proto! */\r
2896                                         symbol_error("Function not prototyped");\r
2897                                 }\r
2898                                 else                                                    /* variable, report error */\r
2899                                         symbol_error("Undefined symbol");\r
2900                         }\r
2901                         t = SYMBOL;\r
2902                         v = sptr;                               /* symtab entry */\r
2903                         tp = symtab[v].type;\r
2904                         ofs = 0;                        /* offset of zero */\r
2905                         break;\r
2906                 case STAR:                              /* pointer dereference */\r
2907                         get_value();\r
2908                         pop(&t, &v, &tp, &ofs);\r
2909                         StackESI();\r
2910                         index_ptr(t, v, tp, ofs);\r
2911                         t = PESI;\r
2912                         if(tp & POINTER)\r
2913                                 --tp;\r
2914                         else\r
2915                                 index_error();\r
2916                         break;\r
2917                 case AND:                               /* address of */\r
2918                         get_value();\r
2919                         pop(&t, &v, &tp, &ofs);\r
2920                         if(t == SYMBOL)\r
2921                         {\r
2922                                 StackEAX();\r
2923                                 code_str((tp & GLOBAL) ? "\tMOV EAX,OFFSET " : "\tLEA EAX,");\r
2924                                 write_oper(t, v, tp, ofs);\r
2925                                 code_chr('\n');\r
2926                                 not_flag=0;\r
2927                                 tp = (tp + 1) & ~FUNCTION;  /* tp + 1 ups the ptr ref count */\r
2928                                 t = INEAX;\r
2929                         }\r
2930                         else if (t == PESI)\r
2931                         {\r
2932                                 StackEAX();\r
2933                                 not_flag=0;\r
2934                                 out_inst("MOV EAX,ESI");\r
2935                                 tp = (tp + 1) & ~FUNCTION;  /* tp + 1 ups the ptr ref count */\r
2936                                 t = INEAX;\r
2937                         }\r
2938                         else if ((t == INEAX) && (tp & POINTER))\r
2939                         { /* do nothing... it's there. */ }\r
2940                         else\r
2941                                 line_error("Invalid '&' operation");\r
2942                         break;\r
2943                 case ORB:                               /* sub-expression */\r
2944                         sub_eval(CRB);\r
2945                         pop(&t, &v, &tp, &ofs);\r
2946                         break;\r
2947                 case SIZEOF:                            /* sizeof */\r
2948                         if(test_token(ORB)) {\r
2949                                 get_value();                    /* look for a symbol */\r
2950                                 pop(&t, &v, &tp, &ofs);\r
2951                                 if (t == SYMBOL) {\r
2952                                         if (tp & POINTER) size = 4;\r
2953                                         else if (tp & BYTE) size = 1;\r
2954                                         else if (tp & WORD) size = 2;\r
2955                                         else if (tp & DWORD) size = 4;\r
2956                                         else if (tp & STRUCT)\r
2957                                                 size = symtab[v].strucoff; /* strucoff = size */\r
2958                                         else size = 4;\r
2959                                         if ((tp & ARRAY) && (!(tp & POINTER))) { /* array ref */\r
2960                                                 i = symtab[v].dindex;    /* i = index to dimpool */\r
2961                                                 j = dim_pool[i++];                      /* j = nDims */\r
2962                                                 while(j--) size *= dim_pool[i++];\r
2963                                         }\r
2964                                         t = NUMBER;\r
2965                                         tp = DWORD;                     /* all constants are DWORDS */\r
2966                                         v = size;\r
2967                                         push(t, v, tp, 0);      /* PUSH THE "Value" ON THE EXP STACK */\r
2968                                         expect(CRB);\r
2969                                         return;\r
2970                                 }\r
2971                                 else\r
2972                                         line_error("Symbol expected");\r
2973                         }\r
2974                         else\r
2975                                 line_error("'(' expected");\r
2976                     break;\r
2977                 default:                                /* anything else (operators) */\r
2978                         get_value();            /* look for a value */\r
2979                         do_unary(token);\r
2980                         return;\r
2981         }\r
2982 \r
2983 /* Function calls  - Open Round Brackett (ORB) */\r
2984 \r
2985         if(test_token(ORB))\r
2986         {\r
2987                 iarg = symtab[v].dindex;        /* index to prototyped args! */\r
2988                 push(t, v, tp, ofs);\r
2989                 StackEAX();\r
2990                 StackESI();\r
2991                 if (tp & VARARGS) fvarargs = -1;\r
2992                 else fvarargs = 0;\r
2993                 vcnt = ndim = 0;\r
2994                 StackTop();\r
2995                 if(!test_token(CRB))\r
2996                 {               /* evaluate function operands */\r
2997                         do {\r
2998                                 argtype = proto_list[iarg]; /* current arg type */\r
2999                                 if(!(argtype&VOID)) iarg++; /* if not end of proto args, get next*/\r
3000                                 token = do_oper(SEMI);          /* handle operation on arg */\r
3001                                 pop(&t, &v, &tp, &ofs);         /* get token arg from expstack */\r
3002                                 LoadEAX(t, v, tp, ofs);\r
3003                                 if ((t != PESI) && (ofs) && (tp&POINTER))\r
3004                                 {       /* offset must be added */\r
3005                                         code_str("\tADD EAX,");\r
3006                                         code_num(ofs);\r
3007                                         code_chr('\n');\r
3008                                 }\r
3009                                 out_inst("PUSH EAX");\r
3010 \r
3011                                 ++ndim;\r
3012                                 if ((!fvarargs) || (fvarargs && (argtype==VOID))) {\r
3013                                         ++vcnt;\r
3014                                 }\r
3015                         }\r
3016                         while(token == COMMA);\r
3017                         if(token != CRB)\r
3018                                 syntax_error();\r
3019                 }\r
3020                 iarg = 0;\r
3021                 pop(&t, &v, &tp, &ofs); /* get function back off the expr stack */\r
3022 \r
3023                 /*  if the function we are about to call had variable parameters\r
3024                         then put the count of bytes that were pushed into EDI as the\r
3025                         code in a vararg function uses it to access the fixed args.\r
3026                         Also, we leave ndim (total count of bytes push) with it's\r
3027                         value so that the "call" function knows he must remove the\r
3028                         data from the stack and the "end_func" function knows not\r
3029                         to use the RET XX instruction.\r
3030                 */\r
3031 \r
3032                 if (fvarargs) {\r
3033                         code_str("\tMOV EDI, ");\r
3034                         code_num(vcnt*4);\r
3035                         code_chr('\n');\r
3036                 }\r
3037                 else ndim = 0;\r
3038 \r
3039                 call(t, v, tp, ofs, ndim);\r
3040 \r
3041                 t = INEAX;                      /* set up to leave the return value in ACC */\r
3042                 tp &= ~FUNCTION;\r
3043         }\r
3044 \r
3045 \r
3046 \r
3047 /* Indexing operations - Open Square Brackett (OSB) */\r
3048 \r
3049         fMultiDim = 0;\r
3050         if(test_token(OSB)) {\r
3051                 fMultiDim = eval_index(t, v, tp, ofs, &tp);\r
3052 \r
3053                 /* get index value token pushed by eval_index */\r
3054 \r
3055                 pop(&token, &v, &t, &ofs);\r
3056                 if ((token==NUMBER) & (!v))\r
3057                 {  /* index is 0 */\r
3058                         pop(&t, &v, &tp1, &ofs);                /* Get var base */\r
3059                         if ((tp1 & (POINTER|ARRAY)) && (t!=PESI))\r
3060                                 load_index(t, v, tp1, ofs);     /* Load base into Index reg */\r
3061                 }\r
3062                 else\r
3063                 {\r
3064                         LoadEAX(token, v, t, ofs);      /* load it into ACC */\r
3065                         pop(&t, &v, &tp1, &ofs);                /* Get var base */\r
3066                         if (tp1 & (POINTER|ARRAY) && (t!=PESI))\r
3067                                 load_index(t, v, tp1, ofs);     /* Load base into Index reg */\r
3068                         out_inst("ADD ESI,EAX");\r
3069                 }\r
3070                 t = PESI;                       /* Let em know ESI pts to item */\r
3071         }\r
3072 \r
3073 /* Convert any [UNINDEXED] array references to address values.\r
3074    This is done later to structures and struct members.\r
3075 */\r
3076 \r
3077         if((tp & ARRAY) && (!(tp & (STRUCT|STRUCMEM)))) {\r
3078                 tp = (tp + 1) & ~ARRAY;                 /* tp+1 ups the ptr ref count */\r
3079                 if(!(tp & ARGUMENT))\r
3080                 {\r
3081                         if(!fMultiDim)\r
3082                         {\r
3083                                 StackEAX();                             /* save what's in EAX and ESI */\r
3084                                 StackESI();\r
3085                                 index_adr(t, v, tp, ofs);       /* load address of rg into ESI */\r
3086                         }\r
3087                         StackEAX();                             /* save what's in EAX if needed */\r
3088                         not_flag = 0;\r
3089                         out_inst("MOV EAX,ESI");\r
3090                         t = INEAX;\r
3091                 }\r
3092         }\r
3093 \r
3094 /* handle the dereference operators . and -> for\r
3095    structures and pointers to structures if present */\r
3096 \r
3097 \r
3098         if(test_token(DEREF)) {\r
3099                 if ((tp & STRUCT) && ((tp & POINTER) || (t==PESI)) ) {\r
3100                         if (t == SYMBOL) {                              /* may already be PESI */\r
3101                                 StackEAX();                                     /* save what's in EAX */\r
3102                                 StackESI();                             /* stack ESI */\r
3103                             index_ptr(t, v, tp, ofs);           /* pointer base into ESI */\r
3104                                 t = PESI;                               /* tell em it's indirect now */\r
3105                         }\r
3106                     if (test_token(SYMBOL)) {\r
3107                                 if (lookup_member(v)) {\r
3108                                     memoffset = symtab[sptr].strucoff;\r
3109                                     tp = symtab[sptr].type;\r
3110                                 v = sptr;\r
3111                                         ofs = memoffset;        /* NEW */\r
3112 \r
3113                                         if (tp & ARRAY)\r
3114                                                 tp = (tp + 1) & ~ARRAY;  /* tp+1 ups the ptr ref count */\r
3115                                         t = PESI;               /* tell em it's indirect now */\r
3116                                 }\r
3117                                 else\r
3118                                         line_error("Not a structure member");\r
3119                         }\r
3120                         else\r
3121                                 line_error("Structure member expected");\r
3122                 }\r
3123                 else\r
3124                         line_error("Pointer to Struct expected");\r
3125         }\r
3126 \r
3127         if (test_token(DOT)) {\r
3128                 if ((tp & STRUCT) && (!(tp & POINTER))) {\r
3129                         if (t == SYMBOL) {                              /* may already be PESI */\r
3130                                 StackEAX();                                     /* save what's in EAX */\r
3131                                 StackESI();                             /* stack ESI */\r
3132                             index_adr(t, v, tp, ofs);   /* ptr to base of struct into ESI */\r
3133                             t = PESI;\r
3134                         }\r
3135                 if (test_token(SYMBOL)) {\r
3136                                 if (lookup_member(v)) {\r
3137                                         memoffset = symtab[sptr].strucoff;\r
3138                                         tp = symtab[sptr].type;         /* member type */\r
3139                                         v = sptr;                                       /* symtab entry of member */\r
3140                                         ofs = memoffset;        /* NEW */\r
3141 \r
3142                                         t = PESI;               /* tell em it's indirect now */\r
3143 \r
3144                                 }\r
3145                                 else\r
3146                                         line_error("Structure member expected");\r
3147                         }\r
3148                         else\r
3149                                 line_error("Structure member expected");\r
3150                 }\r
3151                 else\r
3152                         line_error("Invalid structure operation");\r
3153         }\r
3154 \r
3155 /* Indexing operations for STRUCTMEMS- Open Square Brackett (OSB) */\r
3156 \r
3157         fMultiDim = 0;\r
3158         if(test_token(OSB)) {\r
3159                 fMultiDim = eval_index(t, v, tp, ofs, &tp);\r
3160                 pop(&token, &v, &t, &ofs);              /* get index value token just pushed */\r
3161                 if ((token==NUMBER) & (!v))\r
3162                 {       /* index is 0 */\r
3163                         pop(&t, &v, &tp1, &ofs);        /* Get var base */\r
3164                         if (tp1 & (POINTER|ARRAY) && (t!=PESI))\r
3165                         {\r
3166                                 load_index(t, v, tp1, ofs);     /* Load base into Index reg */\r
3167                                 if ((t==ISTACK_TOP) &&\r
3168                                         (symtab[v].type & ARRAY))\r
3169                                         t=STACK_TOP;\r
3170                         }\r
3171                 }\r
3172                 else {\r
3173                         LoadEAX(token, v, t, ofs);      /* load it into ACC */\r
3174                         pop(&t, &v, &tp1, &ofs);                        /* Get var base */\r
3175                         if (tp1 & (POINTER|ARRAY) && (t!=PESI)) {\r
3176                                 if ((t==ISTACK_TOP) &&\r
3177                                         (symtab[v].type & ARRAY))\r
3178                                         t=STACK_TOP;\r
3179                                 load_index(t, v, tp1, ofs);     /* Load base into Index reg */\r
3180                         }\r
3181                         out_inst("ADD ESI,EAX");\r
3182                 }\r
3183                 t = PESI;                       /* Let em know ESI pts to item */\r
3184         }\r
3185 \r
3186 \r
3187 /* Convert any [UNINDEXED] array references to address values\r
3188    for struct members that are arrays.\r
3189 */\r
3190 \r
3191         if((tp & ARRAY) && (tp & (STRUCMEM))) {\r
3192                 tp = (tp + 1) & ~ARRAY;                 /* tp+1 ups the ptr ref count */\r
3193                 if(!(tp & ARGUMENT))\r
3194                 {\r
3195                         if(!fMultiDim)\r
3196                         {\r
3197                                 StackEAX();                                     /* stack EAX */\r
3198                                 StackESI();                             /* stack ESI */\r
3199                                 index_adr(t, v, tp, ofs);       /* load address of rg into ESI */\r
3200                         }\r
3201                         StackEAX();                                     /* stack EAX if needed */\r
3202                         not_flag = 0;\r
3203                         out_inst("MOV EAX,ESI");\r
3204                         t = INEAX;\r
3205                 }\r
3206         }\r
3207 \r
3208 /* handle any post operators (++ and --) if present */\r
3209 \r
3210         if(test_token(INC)) {                   /* post '++' */\r
3211                 if (tp & POINTER)\r
3212                 {\r
3213                         load_index(t, v, tp, ofs);\r
3214                 }\r
3215                 else\r
3216                         LoadEAX(t, v, tp, ofs);\r
3217                 if (ispStruct(tp, v))\r
3218                         GenCodeOper("ADD |,strucsize", t, v, tp, ofs);\r
3219                 else if (isp32(tp))\r
3220                         GenCodeOper("ADD |,4", t, v, tp, ofs);\r
3221                 else if (isp16(tp))\r
3222                         GenCodeOper("ADD |,2", t, v, tp, ofs);\r
3223                 else\r
3224                         GenCodeOper("INC |", t, v, tp, ofs);\r
3225                 if (tp & POINTER)\r
3226                 {\r
3227                         t = PESI;\r
3228                 }\r
3229                 else\r
3230                         t = INEAX;\r
3231         }\r
3232 \r
3233         else if(test_token(DEC))\r
3234         {                                                                       /* post '--' */\r
3235                 if (tp & POINTER)\r
3236                 {\r
3237                         load_index(t, v, tp, ofs);\r
3238                 }\r
3239                 else\r
3240                         LoadEAX(t, v, tp, ofs);\r
3241                 if (ispStruct(tp, v))\r
3242                         GenCodeOper("SUB |,strucsize", t, v, tp, ofs);\r
3243                 else if (isp32(tp))\r
3244                         GenCodeOper("SUB |,4", t, v, tp, ofs);\r
3245                 else if (isp16(tp))\r
3246                         GenCodeOper("SUB |,2", t, v, tp, ofs);\r
3247                 else\r
3248                         GenCodeOper("DEC |", t, v, tp, ofs);\r
3249                 if (tp & POINTER)\r
3250                 {\r
3251                         t = PESI;\r
3252                 }\r
3253                 else\r
3254                         t = INEAX;\r
3255         }\r
3256         push(t, v, tp, ofs);    /* FINALLY PUSH THE "Value" ON THE EXP STACK */\r
3257 }\r
3258 \r
3259 /****************************************************\r
3260  Combine two types (For binary operations)\r
3261  This raises the type to the lowest common type, or\r
3262  in the case of a strucr-member operation, the type\r
3263  is the type become the member's type.\r
3264 *****************************************************/\r
3265 \r
3266 static U32 combine(U32 type1, U32 type2)\r
3267 {\r
3268         U32 new_type;\r
3269 \r
3270 /* preserve width and indirection if pointer operation is involved */\r
3271 /* if neither is pointer no harm is done with this code */\r
3272 \r
3273         if ((type1 & POINTER) >= (type2 & POINTER))\r
3274                 new_type = type1 & POINTER;\r
3275         else\r
3276                 new_type = type2 & POINTER;\r
3277 \r
3278 /* raise to lowest common type */\r
3279 \r
3280         if ((type1 & DWORD) || (type2 & DWORD)) new_type |= DWORD;\r
3281         else if ((type1 & WORD) || (type2 & WORD)) new_type |= WORD;\r
3282         else new_type |= BYTE;\r
3283 \r
3284 /* ANSI says: If combining unsigned and signed types and signed var\r
3285    is large enough to hold all values of unsigned then combined type\r
3286    remains SIGNED, else the type becomes UNSIGNED!\r
3287 */\r
3288 \r
3289         if (!((type1 & type2) & UNSIGNED))  /* both signed */\r
3290                 return new_type;\r
3291 \r
3292         if ((type1 & UNSIGNED) && (type2 & UNSIGNED)) {  /* both unsigned */\r
3293                 new_type |=UNSIGNED;\r
3294                 return new_type;\r
3295         }\r
3296 \r
3297         /* ONLY one is signed... */\r
3298 \r
3299         if (((type1 & SIZEMASK) >= (type2 & SIZEMASK)) && (type2 & UNSIGNED))\r
3300                 new_type |= UNSIGNED;\r
3301 \r
3302         else\r
3303         if (((type1 & SIZEMASK) <= (type2 & SIZEMASK)) && (type1 & UNSIGNED))\r
3304                 new_type |= UNSIGNED;\r
3305 \r
3306         return new_type;\r
3307 \r
3308 }\r
3309 \r
3310 /**********************************************************\r
3311 * Perform an operation & all higher priority operations.\r
3312 ***********************************************************/\r
3313 \r
3314 static U32 do_oper(U32 token)\r
3315 {\r
3316         U32 token1, t, v, tp, tp1, ofs, ofs1, exit_lab;\r
3317 \r
3318         /* Handle "special" binary operators which involve jumps */\r
3319         if((token == DAND) || (token == DOR) || (token == QUEST))\r
3320         {\r
3321                 pop(&t, &v, &tp, &ofs);\r
3322                 StackEAX();                                     /* stack EAX */\r
3323                 StackESI();                             /* stack ESI */\r
3324                 if(t != INEAX)\r
3325                         LoadEAX(t, v, tp, ofs);\r
3326                 exit_lab = ++next_lab;\r
3327                 if(token == QUEST)\r
3328                 {               /* conditional expression */\r
3329                         cond_jump(FALSE, token1 = ++next_lab, 0);\r
3330                         sub_eval(COLON);\r
3331                         pop(&t, &v, &tp, &ofs);\r
3332                         LoadEAX(t, v, tp, ofs);\r
3333                         jump(exit_lab, 0);\r
3334                         gen_label(token1);\r
3335                 }\r
3336                 else\r
3337                 {                                       /* && and || */\r
3338                         test_not();\r
3339                         if(token == DAND)\r
3340                                 cond_jump(FALSE, exit_lab, -1);\r
3341                         else\r
3342                                 cond_jump(TRUE, exit_lab, -1);\r
3343                 }\r
3344                 token1 = do_oper(SEMI);\r
3345                 pop(&t, &v, &tp1, &ofs1);\r
3346                 LoadEAX(t, v, tp1, ofs1);\r
3347                 gen_label(exit_lab);\r
3348                 push(INEAX, v, combine(tp, tp1), ofs1);\r
3349                 return token1;\r
3350         }\r
3351 \r
3352         get_value();                    /* stack the value (number or whatever) */\r
3353 \r
3354 /* Handle operator precedence and grouping. optype is 2 if operator\r
3355    separates two operands and grouping is L-R. It's 3 if R-L */\r
3356 \r
3357         token1 = get_token();   /* Look at next operator */\r
3358                 while((optype[token1] > 1) &&\r
3359                           (priority[token1] >= priority[token]))\r
3360                 {\r
3361                         /* if they are the same priority AND grouping == L-R */\r
3362 \r
3363                         if((priority[token1] == priority[token]) &&\r
3364                            (optype[token] == 2))\r
3365                         {\r
3366                                 do_lr2op(token);\r
3367                                 return do_oper(token1);\r
3368                         }\r
3369 \r
3370                         token1 = do_oper(token1);\r
3371                 }\r
3372 \r
3373 /* Perform the operation */\r
3374         if(token!=SEMI)\r
3375                 do_lr2op(token);\r
3376 \r
3377         return token1;\r
3378 }\r
3379 \r
3380 \r
3381 /*************************************************************************\r
3382  Evaluates two operands for operators with L to R grouping.\r
3383  if possible, evaluate constant expressions into another constant.\r
3384  Produce code to perform operation if necessary.\r
3385  The two operands are on the top of the expression stack and are\r
3386  loaded into token and token1. The item at the top of the stack is the\r
3387  second operand.  This means that if it were "A minus B", A would go into\r
3388  token and B would go into token1.\r
3389 **************************************************************************/\r
3390 \r
3391 static void do_lr2op(U32 oper)\r
3392 {\r
3393         U32 token, value, type, token1, value1, type1, offset, offset1;\r
3394         U32 atoken, avalue, atype, temp, ctype;\r
3395         U32 uflag, swap, order, wheretok;\r
3396 \r
3397         pop(&token1, &value1, &type1, &offset1);\r
3398         pop(&token, &value,  &type, &offset);\r
3399 \r
3400         uflag = swap = order = atoken = 0;\r
3401 \r
3402         /* Constant numbers assume the type of the other operand */\r
3403         if(token == NUMBER)\r
3404         {\r
3405                 swap = 1;\r
3406                 type = type1;\r
3407         }\r
3408         if(token1 == NUMBER)\r
3409         {\r
3410                 swap = 0;\r
3411                 type1 = type;\r
3412         }\r
3413 \r
3414         ctype = combine(type, type1);\r
3415 \r
3416         /* Do any operations that can be performed at compile time */\r
3417 \r
3418         if((token == NUMBER) && (token1 == NUMBER) &&\r
3419                 (oper != DAND) && (oper != DOR)) {\r
3420                 switch(oper) {\r
3421                         case ADD :\r
3422                                 value += value1;\r
3423                                 break;\r
3424                         case SUB :\r
3425                                 value -= value1;\r
3426                                 break;\r
3427                         case STAR:\r
3428                                 value *= value1;\r
3429                                 break;\r
3430                         case DIV:\r
3431                                 value /= value1;\r
3432                                 break;\r
3433                         case MOD:\r
3434                                 value %= value1;\r
3435                                 break;\r
3436                         case AND:\r
3437                                 value &= value1;\r
3438                                 break;\r
3439                         case OR:\r
3440                                 value |= value1;\r
3441                                 break;\r
3442                         case XOR:\r
3443                                 value ^= value1;\r
3444                                 break;\r
3445                         case SHL:\r
3446                                 value <<= value1;\r
3447                                 break;\r
3448                         case SHR:\r
3449                                 value >>= value1;\r
3450                                 break;\r
3451                         case EQ:\r
3452                                 value = value == value1;\r
3453                                 break;\r
3454                         case NE:\r
3455                                 value = value != value1;\r
3456                                 break;\r
3457                         case LT:\r
3458                                 value = value < value1;\r
3459                         case LE:\r
3460                                 value = value <= value1;\r
3461                                 break;\r
3462                         case GT:\r
3463                                 value = value > value1;\r
3464                                 break;\r
3465                         case GE:\r
3466                                 value = value >= value1;\r
3467                                 break;\r
3468                         default:\r
3469                                 syntax_error();\r
3470                 }\r
3471         }\r
3472         else\r
3473         {\r
3474                 /* Generate code to perform the operation */\r
3475                 avalue = value;\r
3476                 atype = type;\r
3477                 wheretok = INEAX;               /* default place for result */\r
3478 \r
3479                 /* Use unsigned operations if needed */\r
3480                 if((type | type1) & (POINTER | UNSIGNED))\r
3481                         uflag = 1;\r
3482 \r
3483                 /* Try and re-arrange for partial results already in ACC */\r
3484                 if(token1 == INEAX)\r
3485                         swap = 1;\r
3486 \r
3487                 /* This first switch sets up self assignments and\r
3488                    changes the operand to the real operation to be\r
3489                    performed\r
3490                 */\r
3491 \r
3492                 switch(oper)\r
3493                 {\r
3494                         case DAND:      /* logical AND and OR are done elsewhere */\r
3495                         case DOR:\r
3496                                 push(token1, value1, type1, offset1);\r
3497                                 return;\r
3498                         case ADDE:\r
3499                                 atoken = token; /* nonzero atoken indicates self assignment*/\r
3500                                 oper = ADD;\r
3501                                 break;\r
3502                         case SUBE:\r
3503                                 atoken = token;\r
3504                                 oper = SUB;\r
3505                                 break;\r
3506                         case STARE:\r
3507                                 atoken = token;\r
3508                                 oper = STAR;\r
3509                                 break;\r
3510                         case DIVE:\r
3511                                 oper = DIV;\r
3512                                 atoken = token;\r
3513                                 break;\r
3514                         case MODE:\r
3515                                 oper = MOD;\r
3516                                 atoken = token;\r
3517                                 break;\r
3518                         case SHLE:\r
3519                                 oper = SHL;\r
3520                                 atoken = token;\r
3521                                 break;\r
3522                         case SHRE:\r
3523                                 oper = SHR;\r
3524                                 atoken = token;\r
3525                                 break;\r
3526                         case ANDE:\r
3527                                 oper = AND;\r
3528                                 atoken = token;\r
3529                                 break;\r
3530                         case ORE:\r
3531                                 oper = OR;\r
3532                                 atoken = token;\r
3533                                 break;\r
3534                         case XORE:\r
3535                                 oper = XOR;\r
3536                                 atoken = token;\r
3537                                 break;\r
3538                 }\r
3539 \r
3540                 /* this next switch looks for operations that MUST\r
3541                    use special registers (such as EAX or EDX).\r
3542                    Or must be in a special order for a particular\r
3543                    operation.\r
3544                 */\r
3545                 switch(oper)\r
3546                 {\r
3547                         case SUB:\r
3548                         case DIV:\r
3549                         case MOD:\r
3550                         case SHL:\r
3551                         case SHR:\r
3552                                 order = 1;\r
3553                                 break;\r
3554                         case LT:\r
3555                                 if (swap) {\r
3556                                         if (uflag)\r
3557                                                 oper = UGT;\r
3558                                         else\r
3559                                                 oper = GT;\r
3560                                 }\r
3561                                 else if (uflag)\r
3562                                         oper = ULT;\r
3563                                 break;\r
3564                         case LE:\r
3565                                 if (swap) {\r
3566                                         if (uflag)\r
3567                                                 oper = UGE;\r
3568                                         else\r
3569                                                 oper = GE;\r
3570                                 }\r
3571                                 else if (uflag)\r
3572                                         oper = ULE;\r
3573                                 break;\r
3574                         case GT:\r
3575                                 if (swap) {\r
3576                                         if (uflag)\r
3577                                                 oper = ULT;\r
3578                                         else\r
3579                                                 oper = LT;\r
3580                                 }\r
3581                                 else if (uflag)\r
3582                                         oper = UGT;\r
3583                                 break;\r
3584                         case GE:\r
3585                                 if (swap) {\r
3586                                         if (uflag)\r
3587                                                 oper = ULE;\r
3588                                         else\r
3589                                                 oper = LE;\r
3590                                 }\r
3591                                 else if (uflag)\r
3592                                         oper = UGE;\r
3593                                 break;\r
3594                 }\r
3595 \r
3596                 /* Now we can use the flags to set up a swap of operands if\r
3597                    indicated so long as ordering was not important (order flag).\r
3598                    Some operations require the use of EAX.\r
3599                 */\r
3600 \r
3601                 if((token1 == INEAX) && order)\r
3602                 {       /* out of order - use ECX */\r
3603                         test_not();\r
3604                         out_inst("MOV ECX,EAX");\r
3605                         token1 = INECX;\r
3606                 }\r
3607 \r
3608                 if(swap && !order)\r
3609                 {\r
3610                         temp = token;  token = token1;   token1 = temp;\r
3611                         temp = value;  value = value1;   value1 = temp;\r
3612                         temp = type;   type  = type1;    type1  = temp;\r
3613                         temp = offset; offset = offset1; offset1 = temp;\r
3614                 }\r
3615 \r
3616                 if(type1 & FUNCTION)\r
3617                         type_error();\r
3618 \r
3619                 if (oper != ASSIGN)  /* simple assignment is optimized case */\r
3620                 {\r
3621                         LoadEAX(token, value, type, offset);    /* insure its loaded */\r
3622                 }\r
3623 \r
3624                 /* If it's on the processor stack, get it into EDX */\r
3625                 token1 = CheckStack(token1);\r
3626 \r
3627                 /* Now we perform the operation */\r
3628 \r
3629                 switch(oper)\r
3630                 {\r
3631                         case ASSIGN:\r
3632                                 /* optimize away an assigment */\r
3633                                 if ((token1 == token) && (value == value1))\r
3634                                 {\r
3635                     wheretok = token;\r
3636                                         break;\r
3637                                 }\r
3638                                 if (swap)       /* token to store is already in EAX */\r
3639                                 {\r
3640                                         store(token1, value1, type1, offset1);\r
3641                                 }\r
3642                                 else  /* token1 may not be loaded already */\r
3643                                 {\r
3644                                         LoadEAX(token1, value1, type1, offset1);\r
3645                                         store(token, value, type, offset);\r
3646                                 }\r
3647                                 break;\r
3648                         case ADD:\r
3649                                 if (type1&(DWORD|POINTER))\r
3650                                         GenCodeOper("ADD EAX,|", token1, value1, type1, offset1);\r
3651                                 else\r
3652                                 {\r
3653                                         LoadECX(token1, value1, type1, offset1);\r
3654                                         out_inst("ADD EAX,ECX");\r
3655                                 }\r
3656                                 zero_flag = 0;\r
3657                                 break;\r
3658                         case SUB:\r
3659                                 if (type1&(DWORD|POINTER))\r
3660                                         GenCodeOper("SUB EAX,|", token1, value1, type1, offset1);\r
3661                                 else\r
3662                                 {\r
3663                                         LoadECX(token1, value1, type1, offset1);\r
3664                                         out_inst("SUB EAX,ECX");\r
3665                                 }\r
3666                                 zero_flag = 0;\r
3667                                 break;\r
3668                         case STAR:\r
3669                                 LoadECX(token1, value1, type1, offset1);\r
3670                                 if (ctype & UNSIGNED)\r
3671                                         out_inst("MUL ECX");\r
3672                                 else\r
3673                                         out_inst("IMUL ECX");\r
3674                                 zero_flag = 1;\r
3675                                 break;\r
3676                         case DIV:\r
3677                         case MOD:\r
3678                                 LoadECX(token1, value1, type1, offset1);\r
3679                                 if (ctype & UNSIGNED)\r
3680                                 {\r
3681                                         out_inst("XOR EDX,EDX");\r
3682                                         out_inst("DIV ECX");\r
3683                                 }\r
3684                                 else\r
3685                                 {\r
3686                                         out_inst("CDQ");\r
3687                                         out_inst("IDIV ECX");\r
3688                                 }\r
3689                                 zero_flag = -1;\r
3690                                 if (oper == MOD)\r
3691                                         out_inst("MOV EAX,EDX");\r
3692                                 break;\r
3693                         case AND:\r
3694                                 if (type1 & (DWORD|POINTER))\r
3695                                         GenCodeOper("AND EAX,|", token1, value1, type1, offset1);\r
3696                                 else\r
3697                                 {\r
3698                                         LoadECX(token1, value1, type1, offset1);\r
3699                                         out_inst("AND EAX,ECX");\r
3700                                 }\r
3701                                 zero_flag = 0;\r
3702                                 break;\r
3703                         case OR:\r
3704                                 if (type1 & (DWORD|POINTER))\r
3705                                         GenCodeOper("OR EAX,|", token1, value1, type1, offset1);\r
3706                                 else\r
3707                                 {\r
3708                                         LoadECX(token1, value1, type1, offset1);\r
3709                                         out_inst("OR EAX,ECX");\r
3710                                 }\r
3711                                 zero_flag = 0;\r
3712                                 break;\r
3713                         case XOR:\r
3714                                 if (type1 & (DWORD|POINTER))\r
3715                                         GenCodeOper("XOR EAX,|", token1, value1, type1, offset1);\r
3716                                 else\r
3717                                 {\r
3718                                         LoadECX(token1, value1, type1, offset1);\r
3719                                         out_inst("XOR EAX,ECX");\r
3720                                 }\r
3721                                 zero_flag = 0;\r
3722                                 break;\r
3723                         case SHL:\r
3724                                 LoadECX(token1, value1, type1, offset1);\r
3725                                 out_inst("SHL EAX,CL");\r
3726                                 if(ctype & WORD)\r
3727                                         out_inst("AND EAX,0FFFFh");\r
3728                                 else if (ctype & BYTE)\r
3729                                         out_inst("AND EAX,0FFh");\r
3730                                 zero_flag = 0;\r
3731                                 break;\r
3732                         case SHR:\r
3733                                 LoadECX(token1, value1, type1, offset1);\r
3734                                 if (ctype & (DWORD | POINTER))\r
3735                                         out_inst("SHR EAX,CL");\r
3736                                 else if (ctype & WORD)\r
3737                                         out_inst("SHR AX,CL");\r
3738                                 else\r
3739                                         out_inst("SHR AL,CL");\r
3740                                 zero_flag = 0;\r
3741                                 break;\r
3742                         case EQ:                /* compare & test */\r
3743                         case NE:\r
3744                         case LT:\r
3745                         case LE:\r
3746                         case GT:\r
3747                         case GE:\r
3748                         case ULT:\r
3749                         case ULE:\r
3750                         case UGT:\r
3751                         case UGE:\r
3752                                 if (type1&(DWORD|POINTER))\r
3753                                         GenCodeOper("CMP EAX,|", token1, value1, type1, offset1);\r
3754                                 else\r
3755                                 {\r
3756                                         LoadECX(token1, value1, type1, offset1);\r
3757                                         out_inst("CMP EAX,ECX");\r
3758                                 }\r
3759                                 switch(oper)\r
3760                                 {\r
3761                                         case EQ:  out_inst("SETE AL");  break;\r
3762                                         case NE:  out_inst("SETNE AL");  break;\r
3763                                         case LT:  out_inst("SETL AL");  break;\r
3764                                         case LE:  out_inst("SETLE AL");  break;\r
3765                                         case GT:  out_inst("SETG AL");  break;\r
3766                                         case GE:  out_inst("SETGE AL");  break;\r
3767                                         case ULT: out_inst("SETB AL");  break;\r
3768                                         case ULE: out_inst("SETBE AL");  break;\r
3769                                         case UGT: out_inst("SETA AL");  break;\r
3770                                         case UGE: out_inst("SETAE AL");  break;\r
3771                                 }\r
3772                                 out_inst("AND AL,AL");\r
3773                                 zero_flag = 0;\r
3774                                 break;\r
3775                         default:\r
3776                                 syntax_error();\r
3777                 }\r
3778 \r
3779                 /* for self assigns, replace value */\r
3780                 if(atoken)\r
3781                         store(atoken, avalue, atype, offset);\r
3782 \r
3783                 token = wheretok;\r
3784         }\r
3785 \r
3786         push(token, value, ctype, offset);\r
3787 }\r
3788 \r
3789 \r
3790 \r
3791 /***************************************************\r
3792 * Test for a logically negated value, and update\r
3793 * the accumulator if one is being used.\r
3794 ****************************************************/\r
3795 \r
3796 static void test_not(void)\r
3797 {\r
3798         if(not_flag)\r
3799         {\r
3800                 out_inst("AND EAX,EAX");\r
3801                 out_inst("SETZ AL");\r
3802                 out_inst("AND AL,AL");\r
3803                 not_flag = 0;\r
3804                 zero_flag = 0;\r
3805         }\r
3806 }\r
3807 \r
3808 \r
3809 /********************************************\r
3810 * Store accumulator value\r
3811 *********************************************/\r
3812 \r
3813 static void store(U32 token, U32 value, U32 type, U32 offset)\r
3814 {\r
3815 \r
3816         token = CheckStack(token);      /* get stack operand to EDX if needed */\r
3817 \r
3818         switch(token) {\r
3819                 case SYMBOL:\r
3820                 case PESI:\r
3821                 case PECX:\r
3822                 case PEDX:\r
3823                 case ISTACK_TOP:\r
3824                         token = CheckStack(token);      /* get stack operand to EDX if needed */\r
3825                         if(type & (DWORD | POINTER))\r
3826                                 GenCodeOper("MOV |, EAX", token, value, type, offset);\r
3827                         else if (type & WORD)\r
3828                                 GenCodeOper("MOV |, AX", token, value, type, offset);\r
3829                         else\r
3830                                 GenCodeOper("MOV |, AL", token, value, type, offset);\r
3831                         zero_flag = -1;\r
3832                         break;\r
3833                 default:\r
3834                         line_error("Non-assignable");\r
3835         }\r
3836 }\r
3837 \r
3838 \r
3839 /*********************************************\r
3840  Determine if a type is a pointer to struct\r
3841 **********************************************/\r
3842 \r
3843 static U32 ispStruct(U32 type, U32 value)\r
3844 {\r
3845         if((type & POINTER) > 1)        /* pointer to pointer */\r
3846                 return 0;\r
3847         if ((type & STRUCT) && (type & POINTER)) {\r
3848                 strucsize = symtab[value].strucoff;\r
3849                 return 1;\r
3850         }\r
3851         return 0;                                       /* not our pointer */\r
3852 }\r
3853 \r
3854 /*********************************************\r
3855  Determine if a type is a pointer to 32 bits\r
3856 **********************************************/\r
3857 \r
3858 static U32 isp32(U32 type)\r
3859 {\r
3860         if(type & (POINTER-1))          /* pointer to pointer */\r
3861                 return 1;\r
3862         if(type & POINTER)                      /* first level pointer */\r
3863                 return (type & DWORD);\r
3864         return 0;                                       /* not a pointer */\r
3865 }\r
3866 \r
3867 /***********************************************\r
3868  Determine if a type is a pointer to 16 bits\r
3869 ************************************************/\r
3870 static U32 isp16(U32 type)\r
3871 {\r
3872         if(type & POINTER)                      /* first level pointer */\r
3873                 return (type & WORD);\r
3874         return 0;                                       /* not a pointer */\r
3875 }\r
3876 \r
3877 /*\r
3878  * Output a string to the assembler followed by newline.\r
3879  */\r
3880 static void do_asm(char *ptr)\r
3881 {\r
3882         code_str(ptr);\r
3883 }\r
3884 \r
3885 /***************************\r
3886  Initialize static storage\r
3887 ****************************/\r
3888 \r
3889 static void init_static(U32 token, U32 value, char word)\r
3890 {\r
3891         char *ptr, *ptr1, *nptr;\r
3892         U32  i;\r
3893 \r
3894         ptr = "";\r
3895 \r
3896         if(global_width)                /* continuing definition */\r
3897                 ptr = ",";\r
3898         else {                                  /* new definition */\r
3899                 if      (word==1) ptr = " DB ";\r
3900                 else if (word==2) ptr = " DW ";\r
3901                 else if (word==4) ptr = " DD ";\r
3902         }\r
3903 \r
3904         if(token == SYMBOL) {           /* Symbol - MUST BE GLOBAL - NOT EXTERNAL */\r
3905                 ptr1 = "OFFSET ";\r
3906                 global_width += 7; }\r
3907         else if(token == STRING) {              /* literal pool entry */\r
3908                 ptr1 = "OFFSET L_lit+";\r
3909                 *(ptr1+7) = prefix;\r
3910                 global_width += 23; }\r
3911         else if(token == LABEL) {       /* instruction label */\r
3912                 ptr1 = "L_";\r
3913                 *ptr1 = prefix;\r
3914                 global_width += 4; }\r
3915         else {                                          /* constant value */\r
3916                 ptr1 = "";\r
3917                 global_width += 6; }\r
3918 \r
3919         if (*ptr) data_str(ptr);\r
3920         if (*ptr1) data_str(ptr1);\r
3921         if (token!=SYMBOL)\r
3922                 data_num(value);\r
3923         else {\r
3924                 nptr=&GPool[symtab[value].oname];\r
3925                 data_str(nptr);\r
3926                 i=0; while(*nptr++) i+=1;\r
3927                 global_width += i;\r
3928          }\r
3929 \r
3930         if(global_width > 60) {\r
3931                 global_width = 0;\r
3932                 data_chr('\n');\r
3933                 }\r
3934 }\r
3935 \r
3936 /********************************\r
3937 * End static storage definition\r
3938 *********************************/\r
3939 static void end_static(void)\r
3940 {\r
3941         if(global_width) {\r
3942                 data_chr('\n');\r
3943                 global_width = 0;\r
3944         }\r
3945 }\r
3946 \r
3947 /*******************************************************************\r
3948 * Define a global non-static variable\r
3949 ********************************************************************/\r
3950 \r
3951 static void gen_global(U32 symbol, U32 size)\r
3952 {\r
3953         data_global(symbol);\r
3954         if(symtab[symbol].type & (POINTER | DWORD)) {\r
3955                 if (size==4)\r
3956                         data_str(" DD 0h\n");\r
3957                 else {\r
3958                         data_str(" DD ");\r
3959                         data_num(size/4);\r
3960                         data_str(" DUP(0)\n");\r
3961                         }\r
3962                 }\r
3963         else\r
3964         if(symtab[symbol].type & WORD) {\r
3965                 if (size==2)\r
3966                         data_str(" DW 0h\n");\r
3967                 else {\r
3968                         data_str(" DW ");\r
3969                         data_num(size/2);\r
3970                         data_str(" DUP(0)\n");\r
3971                         }\r
3972                 }\r
3973         else\r
3974         if(symtab[symbol].type & (BYTE|STRUCT)) {\r
3975                 if (size==1)\r
3976                         data_str(" DB 0h\n");\r
3977                 else {\r
3978                         data_str(" DB ");\r
3979                         data_num(size);\r
3980                         data_str(" DUP(0)\n");\r
3981                         }\r
3982                 }\r
3983 }\r
3984 \r
3985 /****************************************************\r
3986   Define an external label for DASM near or FAR call\r
3987   Print EXTRN _Symname: NEAR in CSeg if NEAR function.\r
3988   Print EXTRN _Symname  FWORD in DSeg if FAR function.\r
3989 *****************************************************/\r
3990 \r
3991 static void gen_extern_DASM (U32 symbol)\r
3992 {\r
3993         U32 type;\r
3994 \r
3995         type = symtab[symbol].type;\r
3996 \r
3997         if (type & FAR) {\r
3998                 data_str("EXTRN ");\r
3999                 data_chr('_');\r
4000                 data_str(&GPool[symtab[symbol].oname]);\r
4001                 data_str(" FWORD");\r
4002                 data_chr('\n');\r
4003         }\r
4004         else if (type & FUNCTION)\r
4005         {\r
4006                 code_str("EXTRN ");\r
4007                 code_chr('_');\r
4008                 code_str(&GPool[symtab[symbol].oname]);\r
4009                 code_chr(':');\r
4010                 code_str(" NEAR");\r
4011                 code_chr('\n');\r
4012         }\r
4013 \r
4014 }\r
4015 \r
4016 /****************************************************\r
4017   Define an external label for DASM data references.\r
4018   Print EXTRN _Symname DB (DW or DD) if NOT function.\r
4019 *****************************************************/\r
4020 \r
4021 static void gen_ext_data_DASM (U32 symbol)\r
4022 {\r
4023         U32 type;\r
4024 \r
4025         type = symtab[symbol].type;\r
4026 \r
4027         if (!(type & FUNCTION))\r
4028         {\r
4029                 data_str("EXTRN ");\r
4030                 data_chr('_');\r
4031                 data_str(&GPool[symtab[symbol].oname]);\r
4032                 if (type & (POINTER|DWORD))\r
4033                         data_str(" DD");\r
4034                 else if (type & WORD)\r
4035                         data_str(" DW");\r
4036                 else\r
4037                         data_str(" DB");\r
4038                 data_chr('\n');\r
4039         }\r
4040 }\r
4041 \r
4042 /*******************************************************\r
4043 * Enter function & allocate local variable stack space\r
4044 ********************************************************/\r
4045 \r
4046 static void enter_func(U32 symbol, U32 size)\r
4047 {\r
4048         code_global(symbol);\r
4049         code_str(":\n");\r
4050         if (symtab[fptr].type & ISR)\r
4051         {\r
4052                 out_inst("PUSHAD");\r
4053         }\r
4054         else {\r
4055                 out_inst("PUSH EBP");\r
4056                 out_inst("MOV EBP,ESP");\r
4057                 if(size) {\r
4058                         code_str("\tSUB ESP,");\r
4059                         code_num(size);\r
4060                         code_chr('\n'); }\r
4061         }\r
4062 }\r
4063 \r
4064 /************************************************\r
4065 * Clean up the stack & end function definition\r
4066 *************************************************/\r
4067 \r
4068 static void end_func(U32 stackpop)\r
4069 {\r
4070         if (symtab[fptr].type & ISR)\r
4071         {\r
4072                         out_inst("POPAD");\r
4073                         out_inst("IRETD");\r
4074         }\r
4075         else {\r
4076                 if(local_stack)\r
4077                         out_inst("MOV ESP,EBP");\r
4078                 out_inst("POP EBP");\r
4079                 if (stackpop) {\r
4080                         if (symtab[fptr].type & FAR) code_str("\tRETF ");\r
4081                         else code_str("\tRETN ");\r
4082                         code_num(stackpop);\r
4083                 code_chr('\n');\r
4084                 }\r
4085                 else if (symtab[fptr].type & FAR) out_inst("\tRETF");\r
4086                 else out_inst("RETN");\r
4087         }\r
4088 }\r
4089 \r
4090 /**********************************\r
4091  Define a compiler generated label\r
4092 ***********************************/\r
4093 \r
4094 static void gen_label(U32 label)\r
4095 {\r
4096         code_chr(prefix);\r
4097         code_chr('_');\r
4098         code_num(label);\r
4099         code_str(":\n");\r
4100 }\r
4101 \r
4102 /***********************\r
4103  Define literal pool\r
4104 ************************/\r
4105 static void gen_literal(unsigned char *ptr, U32 size)\r
4106 {\r
4107         U32 i;\r
4108 \r
4109         if(size) {\r
4110                 i = 0;\r
4111                 data_chr(prefix);\r
4112                 data_str("_lit");\r
4113                 while(i < size) {\r
4114                         data_str((i % 16) ? "," : " DB ");\r
4115                         data_num(*ptr++);\r
4116                         if(!(++i % 16))\r
4117                         data_chr('\n'); }\r
4118                 if(i % 16)\r
4119                         data_chr('\n'); }\r
4120 }\r
4121 \r
4122 /***********************************\r
4123 * Call a function by name\r
4124 ************************************/\r
4125 static void call(U32 token, U32 value, U32 type, U32 offset, U32 clean)\r
4126 {\r
4127 \r
4128         token = CheckStack(token);\r
4129         if (type & FAR)\r
4130         {\r
4131                         code_str("\tCALL FWORD PTR ");\r
4132         }\r
4133         else code_str("\tCALL ");\r
4134         if(token == NUMBER)\r
4135                 code_num(value);\r
4136         else\r
4137                 write_oper(token, value, type, offset);\r
4138         code_chr('\n');\r
4139 \r
4140         if(clean)\r
4141         {       /* clean up stack following function call */\r
4142                 clean *=4;                              /* each stack operand is 4 bytes */\r
4143                 code_str("\tADD ESP,");\r
4144                 code_num(clean);\r
4145                 code_chr('\n');\r
4146         }\r
4147 \r
4148         zero_flag = -1;\r
4149 \r
4150 }\r
4151 \r
4152 /**********************************\r
4153 * Unconditional jump to label\r
4154 ***********************************/\r
4155 \r
4156 static void jump(U32 label, char ljmp)\r
4157 {\r
4158         code_str(ljmp ? "\tJMP " : "\tJMP SHORT ");\r
4159         code_chr(prefix);\r
4160         code_chr('_');\r
4161         code_num(label);\r
4162         code_chr('\n');\r
4163 }\r
4164 \r
4165 /****************************************\r
4166 * Conditional jump to label\r
4167 *****************************************/\r
4168 static void jump_if(char cond, U32 label, char ljmp)\r
4169             /* condition TRUE or FALSE, destination, long jump required */\r
4170 {\r
4171         if (ljmp) code_str(cond ? "\tJNZ " : "\tJZ ");\r
4172         else code_str(cond ? "\tJNZ SHORT " : "\tJZ SHORT ");\r
4173         code_chr(prefix);\r
4174         code_chr('_');\r
4175         code_num(label);\r
4176         code_chr('\n');\r
4177 }\r
4178 \r
4179 /***********************************************\r
4180  JUMP to the begining of the switch jump table\r
4181 ************************************************/\r
4182 static void do_switch(U32 label)\r
4183 {\r
4184         code_str("\tJMP ");\r
4185         code_chr(prefix);\r
4186         code_chr('_');\r
4187         code_num(label);\r
4188         code_chr('\n');\r
4189 }\r
4190 \r
4191 /*************************************************\r
4192 * Build switch compare/jump table.\r
4193 * d is the count of switch jump table entries.\r
4194 **************************************************/\r
4195 \r
4196 static void build_switch(U32 d)\r
4197 {\r
4198         while(switch_ptr > d) {\r
4199                 code_str("\tCMP EAX,");\r
4200                 code_num(switch_stack[--switch_ptr]);\r
4201                 code_chr('\n');\r
4202                 code_str("\tJE ");\r
4203                 code_chr(prefix);\r
4204                 code_chr('_');\r
4205                 code_num(switch_stack[--switch_ptr]);\r
4206                 code_chr('\n');\r
4207         }\r
4208 }\r
4209 \r
4210 \r
4211 /********************************************\r
4212  Load index register with a pointer value\r
4213 *********************************************/\r
4214 \r
4215 static void index_ptr(U32 token, U32 value, U32 type, U32 offset)\r
4216 {\r
4217         if(token == INEAX)\r
4218         {\r
4219                 out_inst("MOV ESI,EAX");\r
4220         }\r
4221         else if (token==PESI)\r
4222                 return;\r
4223         else\r
4224         {\r
4225                 token = CheckStack(token);\r
4226                 code_str("\tMOV ESI,");\r
4227                 write_oper(token, value, type, offset);\r
4228                 code_str("\n");\r
4229         }\r
4230 }\r
4231 \r
4232 /************************************************\r
4233  Load index register with the address of a symbol\r
4234 *************************************************/\r
4235 \r
4236 static void index_adr(U32 token, U32 value, U32 type, U32 offset)\r
4237 {\r
4238         if (token != PESI)\r
4239         {\r
4240                 code_str((type & GLOBAL) ? "\tMOV ESI,OFFSET " : "\tLEA ESI,");\r
4241                 write_oper(token, value, type, offset);\r
4242                 code_str("\n");\r
4243         }\r
4244 }\r
4245 \r
4246 /**********************************\r
4247 * Output a global code symbol name\r
4248 ***********************************/\r
4249 \r
4250 static void code_global(U32 symbol)\r
4251 {\r
4252 char *ptr;\r
4253         ptr = &GPool[symtab[symbol].oname];\r
4254         if(!(symtab[symbol].type & STATIC))\r
4255         {\r
4256                 code_str("PUBLIC ");\r
4257         }\r
4258         code_chr('_');\r
4259         code_str(ptr);\r
4260 }\r
4261 \r
4262 /**********************************\r
4263 * Output a global data symbol name\r
4264 ***********************************/\r
4265 \r
4266 static void data_global(U32 symbol)\r
4267 {\r
4268 char *ptr;\r
4269         ptr = &GPool[symtab[symbol].oname];\r
4270         if(!(symtab[symbol].type & STATIC))\r
4271         {\r
4272                 data_str("PUBLIC ");\r
4273         }\r
4274         data_chr('_');\r
4275         data_str(ptr);\r
4276 }\r
4277 \r
4278 \r
4279 /**********************************************\r
4280  CODE FILE OUTPUT ROUTINES\r
4281 ***********************************************/\r
4282 \r
4283 /***************************************\r
4284  Write a char to the code tmp file\r
4285 ***************************************/\r
4286 \r
4287 void code_chr(char chr)\r
4288 {\r
4289     pcodebuf[pc++] = chr;\r
4290     if (pc >= 512000-1)\r
4291     {\r
4292                 printf("Code buffer overflow... (512000 bytes)\r\n");\r
4293                 exit(1);\r
4294         }\r
4295 }\r
4296 \r
4297 /****************************************\r
4298   Write a string to the code tmp file \r
4299 *****************************************/\r
4300 \r
4301 void code_str(char *ptr)\r
4302 {\r
4303         while(*ptr)\r
4304                 code_chr(*ptr++);\r
4305 }\r
4306 \r
4307 /********************************\r
4308 * Write a number to the code buf\r
4309 *********************************/\r
4310 \r
4311 void code_num(U32 value)\r
4312 {\r
4313         char stack[10];\r
4314         U32 i;\r
4315 \r
4316         if(value & 0x80000000) {\r
4317                 code_chr('-');\r
4318                 value = -value; }\r
4319 \r
4320         i = 0;\r
4321         do\r
4322                 stack[i++] = (value % 10) + '0';\r
4323         while(value /= 10);\r
4324 \r
4325         while(i)\r
4326                 code_chr(stack[--i]);\r
4327 }\r
4328 \r
4329 /**********************************************\r
4330  ASM FILE OUTPUT ROUTINES (INITIAL DATA SEG)\r
4331 ***********************************************/\r
4332 \r
4333 /* Write a char to the asm file (all data) */\r
4334 \r
4335 void data_chr(char chr)\r
4336 {\r
4337     databuf[pd++] = chr;\r
4338     if (pd > 4095)\r
4339     {\r
4340                 fwrite(databuf, 4096, 1, asm_fh);\r
4341                 pd = 0;\r
4342         }\r
4343 }\r
4344 \r
4345 /* Write a string to the asm file (all data) */\r
4346 \r
4347 void data_str(char *ptr)\r
4348 {\r
4349         while(*ptr)\r
4350                 data_chr(*ptr++);\r
4351 }\r
4352 \r
4353 /********************************\r
4354 * Write a number to the data buf\r
4355 *********************************/\r
4356 \r
4357 void data_num(U32 value)\r
4358 {\r
4359         char stack[10];\r
4360         U32 i;\r
4361 \r
4362         if(value & 0x80000000) {\r
4363                 data_chr('-');\r
4364                 value = -value; }\r
4365 \r
4366         i = 0;\r
4367         do\r
4368                 stack[i++] = (value % 10) + '0';\r
4369         while(value /= 10);\r
4370 \r
4371         while(i)\r
4372                 data_chr(stack[--i]);\r
4373 }\r
4374 \r
4375 \r
4376 /********************************\r
4377 * Write a number to file\r
4378 *********************************/\r
4379 \r
4380 void put_num(U32 value, FILE *outfile)\r
4381 {\r
4382         char stack[10];\r
4383         U32 i;\r
4384 \r
4385         if(value & 0x80000000) {\r
4386                 fputc('-', outfile);\r
4387                 value = -value; }\r
4388 \r
4389         i = 0;\r
4390         do\r
4391                 stack[i++] = (value % 10) + '0';\r
4392         while(value /= 10);\r
4393 \r
4394         while(i)\r
4395                 fputc(stack[--i], outfile);\r
4396 }\r
4397 \r
4398 /***************************************\r
4399 * Process a language statement\r
4400 ****************************************/\r
4401 \r
4402 static void statement(U32 token)\r
4403 {\r
4404         U32 a, b, c, d;\r
4405 \r
4406         test_exit();            /* generate any preceeding exit */\r
4407 \r
4408         switch(token) \r
4409         {               /* act upon the token */\r
4410                 case SEMI:              /* ';' - null statement */\r
4411                         check_func();\r
4412                         return;\r
4413                 case OCB:               /* '{' - begin a block */\r
4414                         while((token = get_token()) != CCB)\r
4415                                 statement(token);\r
4416                         break;\r
4417                 case INT:               /* 16/32 integer variable declaration */\r
4418                 case CHAR:              /* 8 bit variable declaration */\r
4419                 case SHORT:             /* 16 bit variable declaration */\r
4420                 case LONG:              /* 32 bit variable declaration */\r
4421                 case SIGNED:    /* signed variable declaration (the default anyway)*/\r
4422                 case UNSIGN:    /* unsigned variable declaration */\r
4423                 case STAT:              /* static modifier */\r
4424                 case STRUC:             /* structure declaration */\r
4425                 case EXTERN:    /* external modifier */\r
4426                 case REGIS:             /* register modifier */\r
4427                 case INTR:              /* interrupt modifier for functions */\r
4428                 case VOIDD:             /* void for function, and empty args */\r
4429                         declare(token, 0);\r
4430                         break;\r
4431                 case IF:\r
4432                         check_func();\r
4433                         expect(ORB);\r
4434                         eval(CRB, 0);\r
4435                         cond_jump(FALSE, a = ++next_lab, -1);\r
4436                         statement(get_token());\r
4437                         if(test_token(ELSE)) {\r
4438                                 test_jump(b = ++next_lab);\r
4439                                 gen_label(a);\r
4440                                 a = b;\r
4441                                 statement(get_token()); }\r
4442                         test_exit();\r
4443                         gen_label(a);\r
4444                         break;\r
4445                 case WHILE:\r
4446                         check_func();\r
4447                         gen_label(continue_stack[loop_ptr] = a = ++next_lab);\r
4448                         break_stack[loop_ptr++] = b = ++next_lab;\r
4449                         expect(ORB);\r
4450                         eval(CRB, 0);\r
4451                         cond_jump(FALSE, b, -1);\r
4452                         statement(get_token());\r
4453                         test_jump(a);\r
4454                         gen_label(b);\r
4455                         --loop_ptr;\r
4456                         break;\r
4457                 case DO:\r
4458                         check_func();\r
4459                         gen_label(a = ++next_lab);\r
4460                         continue_stack[loop_ptr] = b = ++next_lab;\r
4461                         break_stack[loop_ptr++] = c = ++next_lab;\r
4462                         statement(get_token());\r
4463                         gen_label(b);\r
4464                         expect(WHILE);\r
4465                         eval(SEMI, 0);\r
4466                         cond_jump(TRUE, a, -1);\r
4467                         gen_label(c);\r
4468                         --loop_ptr;\r
4469                         break;\r
4470                 case FOR:\r
4471                         check_func();\r
4472                         expect(ORB);\r
4473                         if(!test_token(SEMI))                   /* initial */\r
4474                                 eval(SEMI, -1);\r
4475                         gen_label(d = a = ++next_lab);\r
4476                         break_stack[loop_ptr] = b = ++next_lab;\r
4477                         if(!test_token(SEMI)) {                 /* test */\r
4478                                 eval(SEMI, 0);\r
4479                                 cond_jump(FALSE, b, -1); }\r
4480                         if(!test_token(CRB)) \r
4481                         {                       /* end */\r
4482                                 jump(c = ++next_lab, 0);\r
4483                                 gen_label(d = ++next_lab);\r
4484                                 eval(CRB, -1);\r
4485                                 jump(a, 0);\r
4486                                 gen_label(c); \r
4487                         }\r
4488                         continue_stack[loop_ptr++] = d;\r
4489                         statement(get_token());\r
4490                         test_jump(d);\r
4491                         gen_label(b);                                   /* exit */\r
4492                         --loop_ptr;\r
4493                         break;\r
4494                 case SWITCH:\r
4495                         check_func();\r
4496                         a = sdefault;\r
4497                         break_stack[loop_ptr++] = sdefault = b = ++next_lab;\r
4498                         expect(ORB);\r
4499                         eval(CRB, -1);\r
4500                         do_switch(c = ++next_lab);\r
4501                         d = switch_ptr;\r
4502                         statement(get_token());\r
4503                         test_jump(b);\r
4504                         gen_label(c);\r
4505                         build_switch(d);\r
4506                         if (sdefault!=a) jump(sdefault, -1);\r
4507                         gen_label(b);\r
4508                         --loop_ptr;\r
4509                         sdefault = a;\r
4510                         break;\r
4511                 case CASE:\r
4512                         a = check_switch();\r
4513                         get_constant(&b, &c);\r
4514                         switch_stack[switch_ptr++] = a;  /* RAB reversed a & c */\r
4515                         switch_stack[switch_ptr++] = c;\r
4516                         if(switch_ptr >= (MAX_SWITCH*2))\r
4517                                 fatal_error("Too many active cases");\r
4518                         expect(COLON);\r
4519                         break;\r
4520                 case DEFAULT:\r
4521                         sdefault = check_switch();\r
4522                         expect(COLON);\r
4523                         break;\r
4524                 case RETURN:\r
4525                         check_func();\r
4526                         if(!test_token(SEMI))\r
4527                         {\r
4528                                 eval(SEMI, -1);\r
4529                         }\r
4530                         exit_flag = exit_label ? exit_label : (exit_label = ++next_lab);\r
4531                         break;\r
4532                 case BREAK:\r
4533                         check_loop(break_stack);\r
4534                         break;\r
4535                 case CONTIN:\r
4536                         check_loop(continue_stack);\r
4537                         break;\r
4538                 case GOTO:\r
4539                         check_func();\r
4540                         if(get_token() != SYMBOL) {\r
4541                                 syntax_error();\r
4542                                 break; }\r
4543                         if(a = lookup_local()) {\r
4544                                 if(!(a & GLABEL))\r
4545                                         type_error(); }\r
4546                         else\r
4547                                 define_symbol(REFERENCE|GLABEL, ++next_lab);\r
4548                         jump(symtab[sptr].dindex, -1);\r
4549                         break;\r
4550                 case SYMBOL:    /* a symbol table entry */\r
4551                         if(!in_function) {              /* global definition */\r
4552                                 declare(token, 0);\r
4553                                 break; }\r
4554                         if(*input_ptr == ':') {         /* label definition */\r
4555                                 check_func();\r
4556                                 ++input_ptr;\r
4557                                 if(lookup_local())\r
4558                                         symtab[sptr].type &= ~EXTERNAL;\r
4559                                 else\r
4560                                         define_symbol(GLABEL, ++next_lab); /* sets sptr */\r
4561                                 gen_label(symtab[sptr].dindex);\r
4562                                 break;\r
4563                          }\r
4564                 default:                /* expression evaluation */\r
4565                         check_func();\r
4566                         unget_token(token);\r
4567                         eval(SEMI, -1);\r
4568         }\r
4569 }\r
4570 \r
4571 \r
4572 /*********************************************************\r
4573 * Main compile loop, process statements until end of file\r
4574 **********************************************************/\r
4575 \r
4576 static void compile(void)\r
4577 {\r
4578         define_ptr = define_pool;\r
4579         *(input_ptr = line_in) = 0;\r
4580         if (!fGen) {\r
4581                 code_str("\n\n.CODE\n");\r
4582                 data_str("\n.DATA\n");\r
4583                 }\r
4584         for(;;)\r
4585                 statement(get_token());\r
4586 }\r
4587 \r
4588 /****************************************************\r
4589 * Initialize I/O & execute compiler  MAIN MAIN MAIN\r
4590 *****************************************************/\r
4591 \r
4592 void main(S32 argc, char *argv[])\r
4593 {\r
4594         U32 i, erc;\r
4595         char *ptr, *pname;\r
4596 \r
4597 /* first, get a BIG code buffer!! */\r
4598 \r
4599         erc = AllocPage(SCODEBUF/4096, &pcodebuf);\r
4600         if (erc)\r
4601                 printf("Not enough memory to allocate %d bytes.\r\n", SCODEBUF);\r
4602 \r
4603         /* extern far U32 DeAllocPage(U8 *pOrigMem, U32 nPages); */\r
4604 \r
4605 /* first process any filenames and command line options */\r
4606 \r
4607         list_fh = stdout;       /* default the list file */\r
4608 \r
4609         for(i=1; i < argc; ++i) {       /* start at arg 1 */\r
4610                 ptr = argv[i];\r
4611                 if (*ptr == '/') {\r
4612                   ptr++;\r
4613                   switch(*ptr) {\r
4614                         case 'S' :                      /* quiet mode */\r
4615                         case 's' :\r
4616                                 fQuiet = 1;\r
4617                                 break;\r
4618                         case 'L' :                      /* List file ON */\r
4619                         case 'l' :\r
4620                                 fList = 1;\r
4621                                 break;\r
4622                         case 'E' :                      /* Embedded source mode */\r
4623                         case 'e' :\r
4624                                 fSource = 1;\r
4625                                 break;\r
4626                         case 'G' :                      /* Generate separate modules */\r
4627                         case 'g' :\r
4628                                 fGen = 1;\r
4629                                 break;\r
4630                         case 'N' :                      /* NO optimize */\r
4631                         case 'n' :\r
4632                                 fNoOpt = 1;\r
4633                                 break;\r
4634                         case 'O' :                      /* Optimize for speed */\r
4635                         case 'o' :\r
4636                                 fOptS = 1;\r
4637                                 break;\r
4638                         case 'W' :                      /* Warnings ON */\r
4639                         case 'w' :\r
4640                                 fWarnings = 1;\r
4641                                 break;\r
4642                         case 'P' :                      /* Prefix label character */\r
4643                         case 'p' :\r
4644                                 ptr++;\r
4645                                 if (!is_alpha(*ptr))\r
4646                                         fatal_error("Invalid label prefix character");\r
4647                                 prefix = *ptr;\r
4648                                 break;\r
4649                         default:\r
4650                                 fatal_error("Invalid switch");\r
4651                                 break;\r
4652                   }\r
4653                 }\r
4654                 else {\r
4655                         if(!source_fh) {\r
4656                                 copystring(srcname, argv[i]);\r
4657                                 source_fh = fopen(argv[i], "r");\r
4658                                 }\r
4659                         else if(!asm_fh) {\r
4660                                 copystring(asmname, argv[i]);\r
4661                                 if(!(asm_fh = fopen(argv[i], "w"))) {\r
4662                                   fputs("Error: Can't open ASM file\n", stdout);\r
4663                                   exit(-1);\r
4664                                   }\r
4665                                 }\r
4666                         else\r
4667                                 fatal_error("Too many parameters");\r
4668            }\r
4669         }\r
4670 \r
4671 /* Input file not explicitly named errors out */\r
4672         if(!source_fh) {                                /* default to standard input */\r
4673                 fputs("C Minus 32 Compiler, Version 2.3M\r\n", stdout);\r
4674                 fputs("Usage: SourceFile [AsmFile] /S /E /G /L /W /Px\r\n", stdout);\r
4675                 fputs("/S  Suppress screen output (e.g., herald)\r\n", stdout);\r
4676                 fputs("/E  Embed source in ASM output\r\n", stdout);\r
4677                 fputs("/G  Generate separate Code & Data files\r\n", stdout);\r
4678                 fputs("/L  List file generated for errors\r\n", stdout);\r
4679                 fputs("/N  No optimization\r\n", stdout);\r
4680                 fputs("/O  Optimize for speed.\r\n", stdout);\r
4681                 fputs("/W  Warnings ON\r\n", stdout);\r
4682                 fputs("/Px Label prefix character (x=Label char)\r\n\n", stdout);\r
4683                 fputs("Error: Source filename required\r\n", stdout);\r
4684                 exit(-1);\r
4685                 }\r
4686 \r
4687 /* Output file not explicitly named defaults to Source.asm */\r
4688 \r
4689         if(!asm_fh)     \r
4690         {                                       /* default asm name to SourceName.asm */\r
4691                 copystring(asmname, srcname);\r
4692                 pname=asmname;\r
4693                 while ((*pname != '.') && (*pname!= '\0')) pname++;\r
4694 \r
4695                 if (fGen)\r
4696                 {\r
4697                         *pname++ = '.';\r
4698                         *pname++ = 'D';\r
4699                         *pname++ = 'A';\r
4700                         *pname++ = 'S';\r
4701                 }\r
4702                 else\r
4703                 {\r
4704                         *pname++ = '.';\r
4705                         *pname++ = 'A';\r
4706                         *pname++ = 'S';\r
4707                         *pname++ = 'M';\r
4708                 }\r
4709                 *pname   = '\0';\r
4710                 if(!(asm_fh = fopen(asmname, "w"))) \r
4711                 {\r
4712                         fputs("Error: Can't open ASM file\r\n", stdout);\r
4713                         exit(-1);\r
4714                 }\r
4715         }\r
4716         fASMOpen = TRUE;\r
4717 \r
4718 /* If -L then List file named Source.LST is generated. */\r
4719 \r
4720         if (fList)\r
4721         {\r
4722                 copystring(lstname, srcname);\r
4723                 pname=lstname;\r
4724                 while ((*pname != '.') && (*pname!= '\0')) pname++;\r
4725                 *pname++ = '.';\r
4726                 *pname++ = 'L';\r
4727                 *pname++ = 'S';\r
4728                 *pname++ = 'T';\r
4729                 *pname   = '\0';\r
4730                 if(!(list_fh = fopen(lstname, "w")))\r
4731                                         fatal_error("Cannot open LIST file");\r
4732                 else fLISTOpen = TRUE;\r
4733         }\r
4734 \r
4735         /* open code segment tmp file  or Gen file */\r
4736 \r
4737         if (fGen)\r
4738         {\r
4739                 copystring(codename, srcname);\r
4740                 pname=codename;\r
4741                 while ((*pname != '.') && (*pname!= '\0')) pname++;\r
4742                 *pname++ = '.';\r
4743                 *pname++ = 'C';\r
4744                 *pname++ = 'A';\r
4745                 *pname++ = 'S';\r
4746                 *pname   = '\0';\r
4747                 if(!(code_fh = fopen(codename, "w")))\r
4748                                         fatal_error("Cannot open Code file");\r
4749                 else fCODEOpen = TRUE;\r
4750         }\r
4751 \r
4752         if(!fQuiet)\r
4753                 fputs("C Minus 32 Compiler, Version 2.3M\r\n", stdout);\r
4754 \r
4755         compile();\r
4756 }\r