2 C Minus 32 (C-32) Compiler (DOS version)
\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
9 32 bit assembly language generation specificly for the Intel 386/486
\r
10 for the DASM assembler.
\r
12 CM-32 integer support:
\r
13 short = int = short int = 16 bits,
\r
14 long = long int = 32 bits.
\r
16 16 bit Intel addressing modes are NOT supported for code generation.
\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
25 #define U32 unsigned long
\r
27 #define U16 unsigned int
\r
29 #define U8 unsigned char
\r
37 #include "Tokens32.h"
\r
39 #include "\OSSource\MMemory.h"
\r
41 #define SCODEBUF 512000 /* 500Kb allocated buffer */
\r
44 /* Input buffer & input pointer for preprocessed lines */
\r
45 char line_in[LINE_MAX], *input_ptr;
\r
47 /* Global value storage locations (results from lexical scanner) */
\r
49 char gst[SYMBOL_SIZE+1]; /* Name if SYMBOL */
\r
50 U8 namesize; /* size of SYMBOL name */
\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
59 /* Symbol table and associated variables */
\r
61 char GPool[GBUFFSIZE]; /* Pool for symbol names (packed) */
\r
62 char LPool[LBUFFSIZE]; /* Pool for local symbol names (packed) */
\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
76 struct sym symtab[MAX_SYMBOLS]; /* SYM TABLE... */
\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
81 U32 proto_list[MAX_PROTOS], /* list of arg types for functions */
\r
84 iproto_next = 1, /* index to next available proto args (0 illegal)*/
\r
85 icrntpro = 0, /* index to arg being tested */
\r
88 local_top = MAX_SYMBOLS,
\r
89 arg_count, /* number of args so far */
\r
91 sptr, /* symbol ptr */
\r
92 fptr; /* ptr to function symbol we are in */
\r
94 /* structure definition use and control variables */
\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
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
106 dim_pool[DIM_SIZE]; /* each entry has nDims for an array */
\r
109 char literal_pool[LITER_BUFF];
\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
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
128 struct expr expstk[EXPR_DEPTH]; /* Expression Stack */
\r
132 /* Misc. global variables */
\r
137 prefix = 'L'; /* override with /P:x switch */
\r
139 U32 break_stack[LOOP_DEPTH],
\r
140 continue_stack[LOOP_DEPTH],
\r
141 switch_stack[MAX_SWITCH*2],
\r
152 begin_comment = 0, /* line that a comment starts on for errors */
\r
158 /* input/output pointers and buffer for for preprocessor */
\r
160 char buffer[LINE_MAX],
\r
164 /* macro definition: index, pool and top pointers */
\r
167 char *define_index[MACROS],
\r
168 define_pool[MAC_BUFF],
\r
171 /* macro parameter: index, pool and top pointers */
\r
173 char *parm_index[PARAMETERS],
\r
174 parm_pool[PARM_BUFF],
\r
177 /* include: line stack & count, file pointers, filename */
\r
179 incl_line[INCL_DEPTH];
\r
181 FILE *incl_fh[INCL_DEPTH],
\r
192 /* file open flags */
\r
194 char fLISTOpen = 0,
\r
199 /* misc. variables and flags */
\r
200 char comment_flag = -1,
\r
211 char *incdir = "\\CM32\\INCLUDE";
\r
215 U32 global_width = 0,
\r
222 U32 pc = 0; /* code pointer in */
\r
223 U32 pco = 0; /* code pointer out */
\r
226 #include "Optimize.h"
\r
227 #include "Proto32.h"
\r
229 /******************************************
\r
230 * Determine if a character is alphabetic
\r
231 * or is underscore.
\r
232 *******************************************/
\r
234 static char is_alpha(char chr)
\r
236 return (((chr|0x20) >= 'a') && ((chr|0x20) <= 'z'))
\r
240 /*********************************************
\r
241 * Determine if a character is a numeric digit
\r
242 **********************************************/
\r
244 static char is_digit(char chr)
\r
246 return (chr >= '0') && (chr <= '9');
\r
249 /******************************************
\r
250 * Test for valid character in a name.(MACRO)
\r
251 *******************************************/
\r
253 #define is_alnum(c) (is_alpha(c) || is_digit(c))
\r
255 static char is_alnum(char c)
\r
257 return is_alpha(c) || is_digit(c);
\r
265 static void copystring(char *dest, char *source)
\r
267 while(*dest++ = *source++);
\r
271 /***************************
\r
272 * Test for string equality
\r
273 ****************************/
\r
275 static char equal_string(char *str1, char *str2)
\r
278 if(*str1 != *str2++)
\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
289 static char skip_blanks(void)
\r
291 while((*buffin_ptr < 0x21) && (*buffin_ptr))
\r
293 return *buffin_ptr;
\r
296 /***************************************
\r
297 * Test for more macro parameters
\r
298 ****************************************/
\r
300 static long more_parms(void)
\r
304 if(((c = skip_blanks()) == ',') || (c == ')'))
\r
307 line_error("Invalid macro parameter");
\r
311 /**************************************
\r
312 * Skip ahead through a comment
\r
313 ***************************************/
\r
315 static void skip_comment(void)
\r
322 if(!(c = *buffin_ptr++)) { /* end of line_in */
\r
323 if(!fgets(buffin_ptr = buffer, LINE_MAX, source_fh)) {
\r
329 if((x = (x << 8) + c) == (('*' << 8) + '/')) /* close */
\r
331 if(x == (('/' << 8) + '*')) /* imbedded comment */
\r
337 /*****************************************************************
\r
338 * Copy a named symbol from the input buffer to the output buffer
\r
339 ******************************************************************/
\r
341 static void copy_name(void)
\r
344 *buffout_ptr++ = *buffin_ptr++;
\r
345 while(is_alnum(*buffin_ptr));
\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
354 static void copy_string(void)
\r
356 register char delim;
\r
358 if(((delim = *buffin_ptr) == '"') || (delim == 0x27)) {
\r
360 if(!(*buffout_ptr++ = *buffin_ptr)) { /* premature end */
\r
361 line_error("Unterminated string");
\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
369 /**************************************************************
\r
370 * Lookup a word from the input stream to see if it is a macro
\r
371 ***************************************************************/
\r
373 static U32 lookup_macro(char eflag)
\r
376 register char *name;
\r
378 name = buffout_ptr;
\r
380 for(i = macro - 1; i >= 0; --i) /* look it up */
\r
381 if(!strcmp(name, define_index[i]))
\r
383 if(eflag) /* not found */
\r
384 line_error("Undefined macro");
\r
388 /**************************************************************
\r
389 * Resolve a word into a macro definition (if it is defined)
\r
390 ***************************************************************/
\r
392 static void resolve_macro(void)
\r
394 char *mptr, *ptr, *old_ptr;
\r
398 old_ptr = buffout_ptr;
\r
399 if((i = lookup_macro(0)) != -1) { /* Substitution required */
\r
400 mptr = define_index[i];
\r
403 parm_ptr = parm_pool;
\r
404 if(*mptr++) { /* parameterized macro */
\r
405 if(skip_blanks() == '(') {
\r
408 parm_index[parm++] = parm_ptr;
\r
409 while(*buffin_ptr && (*buffin_ptr != ',') && (*buffin_ptr != ')'))
\r
410 *parm_ptr++ = *buffin_ptr++;
\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
419 *old_ptr++ = *mptr;
\r
422 *(buffout_ptr = old_ptr) = 0;
\r
426 /****************************************
\r
427 * Test for a string in input stream
\r
428 *****************************************/
\r
430 static unsigned long match(char *ptr)
\r
432 register char *ptr1;
\r
436 if(*ptr++ != *ptr1++) /* symbols do not match */
\r
438 if(is_alnum(*ptr1)) /* symbol continues */
\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
453 static long compareT(char *ptable, long peep)
\r
456 char *ptr1, *ptr2, c;
\r
458 for(i=0; i < OSYMBOLS; ++i)
\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
466 peep = (peep+1) % OBUF_SIZE;
\r
467 if(peep == peep_next)
\r
469 ptr1 = peep_buffer[peep]; /* next buffer entry */
\r
471 else if (c == ' ') { /* space */
\r
472 if(!isspace(*ptr1))
\r
474 while(isspace(*ptr1))
\r
476 else if(c & 0x80) { /* symbol name */
\r
480 ptr2 = symbols[*ptable & 0x7f];
\r
482 while(*ptr1 && (*ptr1 != c))
\r
483 if(*ptr1++ != *ptr2++)
\r
487 else { /* new symbol */
\r
488 while(*ptr1 && (*ptr1 != c))
\r
492 else if(c != *ptr1++) return 0; /* normal character */
\r
496 return (*ptr1) ? 0 : peep + 1;
\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
506 static void exchange(unsigned long old, char *pnew)
\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
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
528 /***********************************************
\r
529 Simulates fgets from the HUGE code buffer
\r
530 ************************************************/
\r
532 static char *fgetcode(char *pout, long maxout)
\r
540 if (pco >= pc) /* end of valid buffer data */
\r
543 while ((n < maxout-1) && (pcodebuf[pco]))
\r
546 *pout++ = pcodebuf[pco++];
\r
561 /****************************************
\r
562 * Read a line into the peephole buffer
\r
563 * from the tmpcodebuf
\r
564 *****************************************/
\r
566 static long read_line(void)
\r
570 if(fgetcode(peep_buffer[peep_next], OLINE_SIZE)) {
\r
572 /*strip CR/LF from line */
\r
573 sptr = &(peep_buffer[peep_next]);
\r
575 while (c = *sptr) {
\r
576 if (c == '\r') *sptr = '\0';
\r
577 if (c == '\n') *sptr = '\0';
\r
581 /* next peep_buf entry please... */
\r
582 peep_next = (peep_next+1) % OBUF_SIZE;
\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
594 fputs(peep_buffer[peep_top], code_fh);
\r
596 fputs(peep_buffer[peep_top], asm_fh);
\r
597 peep_top = (peep_top + 1) % OBUF_SIZE;
\r
599 fputs("\n", code_fh);
\r
601 fputs("\n", asm_fh);
\r
605 /*********************************************************
\r
606 * Peephole Optimizer function for code segment
\r
607 **********************************************************/
\r
608 static void optimize(void)
\r
614 fputs("CM32 V2.3M optimizer phase\r\n", stdout);
\r
616 /* initially fill every line in peephole buffer */
\r
621 /* keep buffer full! */
\r
622 while ( ((peep_next+1) % OBUF_SIZE) != peep_top )
\r
629 /* walk thru the whole peep_table and see if we have
\r
630 matches in the peep_buffer */
\r
632 for(i=0; ptr = peep_table[i]; i += 2) {
\r
634 j = compareT(ptr, peep_top);
\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
641 if(!j) write_line(); /* no matches, flush this line */
\r
643 if (peep_top == peep_next)
\r
644 return; /* We are done! */
\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
655 *********************************************/
\r
657 static long readline(void)
\r
660 char c, ch, fgotone;
\r
663 if(!fgets(buffin_ptr = buffer, LINE_MAX, source_fh))
\r
668 line_number = incl_line[--include];
\r
669 source_fh = incl_fh[include];
\r
673 } /* no more lines... */
\r
676 buffout_ptr = line_in;
\r
680 if ((ch = skip_blanks()) == '#')
\r
684 { /* if inline assembly */
\r
689 else if(match("#endasm"))
\r
690 { /* end of assembly */
\r
695 else if(match("#ifdef"))
\r
696 { /* if macro defined */
\r
699 ++if_flag; /* one deeper */
\r
700 else if(lookup_macro(0) == -1)
\r
706 else if(match("#ifndef"))
\r
707 { /* if macro not defined */
\r
711 else if(lookup_macro(0) != -1)
\r
717 else if(match("#else"))
\r
718 { /* reverse condition */
\r
720 if(!(if_flag & 0x7f)) /* not nested? */
\r
722 } /* XOR high bit */
\r
724 else if(match("#endif"))
\r
725 { /* end conditional */
\r
727 if(if_flag & 0x7f) /* if nested, reduce one */
\r
731 } /* else it's over */
\r
733 else if(match("#pragma"))
\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
743 if ((!fgotone) && (!if_flag))
\r
747 if(match("#define")) { /* define a new macro */
\r
748 if(macro >= MACROS) {
\r
749 fatal_error("Too many macro definitions");
\r
751 buffout_ptr = define_index[macro++] = define_ptr;
\r
752 if(!is_alpha(*buffin_ptr)) {
\r
753 line_error("Invalid macro name");
\r
755 copy_name(); /* get macro name */
\r
756 define_ptr = buffout_ptr;
\r
759 parm_ptr = parm_pool;
\r
760 if(*buffin_ptr == '(') { /* parameterized macro */
\r
764 if(parm >= PARAMETERS) {
\r
765 line_error("Too many macro parameters");
\r
767 parm_index[parm++] = buffout_ptr = parm_ptr;
\r
770 parm_ptr = buffout_ptr+1; }
\r
771 while(more_parms()); }
\r
775 while(c = *buffin_ptr) {
\r
776 buffout_ptr = define_ptr;
\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
784 define_ptr = buffout_ptr; }
\r
785 else if((c == '"') || (c == 0x27)) {
\r
787 define_ptr = buffout_ptr; }
\r
789 if((*++buffin_ptr == '*') && (c == '/')) {
\r
791 begin_comment = line_number;
\r
794 *define_ptr++ = c; }
\r
795 /* skip_blanks(); */
\r
797 *define_ptr++ = 0; }
\r
799 else if(match("#undef"))
\r
800 { /* undefine a macro */
\r
801 if((i = lookup_macro(-1)) != -1)
\r
803 if(i == (macro - 1)) /* last one, simple delete */
\r
804 define_ptr = define_index[i];
\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
812 { /* adjust index list */
\r
813 define_index[i] = define_index[i+1] - parm;
\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
832 { /* current directory */
\r
833 line_error("Invalid include file name");
\r
836 while(*++buffin_ptr && (*buffin_ptr != c))
\r
837 *buffout_ptr++ = *buffin_ptr;
\r
839 incl_fh[include] = source_fh;
\r
840 incl_line[include] = line_number;
\r
841 if(source_fh = fopen(line_in, "r"))
\r
848 line_error("Cannot open include file");
\r
849 source_fh = incl_fh[include];
\r
853 line_error("Unknown preprocessor directive");
\r
857 { /* default, perform pre-processing */
\r
859 if(asm_flag) /* inline assembly */
\r
862 while(c = *buffin_ptr)
\r
864 if(is_alpha(c)) /* symbol, could be macro */
\r
866 else if((c == '"') || (c == 0x27)) /* quoted string */
\r
870 if((*++buffin_ptr == '*') && (c == '/') && comment_flag)
\r
873 begin_comment = line_number; /* save begin line*/
\r
876 else /* nothing special, copy it */
\r
877 *buffout_ptr++ = c;
\r
885 input_ptr=line_in; /* point to start of new line */
\r
886 *buffout_ptr = 0; /* null at end of line */
\r
889 } /* !fgotone && !if_flag */
\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
903 static U32 test_exit(void)
\r
906 jump(exit_flag, -1);
\r
908 return(exit_flag = 0);
\r
913 /*********************************************
\r
914 * Output an warning message with quoted text
\r
915 **********************************************/
\r
917 static void t_warn(char *msg, char *txt)
\r
921 if (!fWarnings) return;
\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
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
939 /*********************************************
\r
940 * Output an error message with quoted text
\r
941 **********************************************/
\r
943 static void t_error(char *msg, char *txt)
\r
945 char emsg[50], *ptr;
\r
952 *ptr++ = 0x27; /* single quote */
\r
955 *ptr++ = 0x27; /* single quote */
\r
961 /***********************************************************
\r
962 * Report an error involving a freshly parsed symbol name
\r
963 ************************************************************/
\r
965 static void symbol_error(char *msg)
\r
971 /***********************************************************
\r
972 * Report a syntax error
\r
973 ************************************************************/
\r
975 static void syntax_error(void)
\r
977 line_error("Syntax error");
\r
980 /***********************************************************
\r
981 * Report incompatable types
\r
982 ************************************************************/
\r
984 static void type_error(void)
\r
986 line_error("Types mismatch");
\r
989 /***********************************************************
\r
990 * Report an error in indirection
\r
991 ************************************************************/
\r
993 static void index_error(void)
\r
995 line_error("Illegal indirection");
\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
1004 static char test_token(U32 token)
\r
1008 if((token1 = get_token()) == token)
\r
1010 unget_token(token1);
\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
1020 static void expect(U32 token)
\r
1022 if(!test_token(token))
\r
1023 t_error("Expected", tokens[token]);
\r
1026 /***************************************
\r
1027 Report a Unterminated Comment error
\r
1028 ****************************************/
\r
1030 static void UTC_error(void)
\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
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
1045 if(++error_count == MAX_ERRORS)
\r
1046 fatal_error("Too many errors");
\r
1049 /***************************************
\r
1050 * Report a compile error
\r
1051 ****************************************/
\r
1053 static void line_error(char *message)
\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
1062 fputc(' ', list_fh);
\r
1063 fputs(message, list_fh);
\r
1064 fputc('\r', list_fh);
\r
1065 fputc('\n', list_fh);
\r
1067 if(++error_count == MAX_ERRORS)
\r
1068 fatal_error("Too many errors");
\r
1071 /*******************************************
\r
1072 * Report a non-recoverable compile error
\r
1073 ********************************************/
\r
1075 static void fatal_error(char *string)
\r
1077 line_error(string);
\r
1079 /* put this out even if fQuiet */
\r
1080 fputs("Fatal error, compilation aborted\r\n", stdout);
\r
1083 fputs("Fatal error, compilation aborted\r\n", list_fh);
\r
1090 if (fASMOpen) fclose(asm_fh);
\r
1091 exit(-1); /* We are done ! */
\r
1095 /*****************************************************
\r
1096 * Check that a loop is active & setup exit condition
\r
1097 ******************************************************/
\r
1099 static void check_loop(U32 stack[])
\r
1103 exit_flag = stack[loop_ptr-1];
\r
1105 line_error("No active loop");
\r
1108 /****************************************************
\r
1109 * Check that a switch is active & allocate label
\r
1110 *****************************************************/
\r
1112 static U32 check_switch(void)
\r
1115 line_error("No active switch");
\r
1116 gen_label(++next_lab);
\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
1126 static void test_jump(U32 label)
\r
1133 /********************************************
\r
1134 * Compile a conditional jump and
\r
1135 * set up 'Z' flag if necessary.
\r
1136 *********************************************/
\r
1138 static void cond_jump(char cond, U32 label, char ljmp)
\r
1142 out_inst("AND EAX,EAX");
\r
1146 jump_if(cond ^ not_flag, label, ljmp);
\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
1156 static U32 get_number(U32 base, U32 digits)
\r
1163 if(is_digit(c = *input_ptr)) /* convert numeric digits */
\r
1165 else if(c >= 'a') /* convert lower case alphas */
\r
1167 else if(c >= 'A') /* convert upper case alphas */
\r
1171 if(c >= base) /* outside of base */
\r
1173 value = (value * base) + c; /* include in total */
\r
1175 while(--digits); /* enforce maximum digits */
\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
1184 ******************************************************************/
\r
1186 static void clean_up(void)
\r
1188 U32 type, size, i, j;
\r
1191 fatal_error("Unterminated function");
\r
1193 /* Generate all externals referenced from CSEG if NOT for DASM */
\r
1195 for(sptr = 0; sptr < global_top; ++sptr)
\r
1197 if((type = symtab[sptr].type) & (EXTERNAL))
\r
1198 if (type & REFERENCE)
\r
1199 gen_ext_data_DASM(sptr);
\r
1202 /* dump literal pool */
\r
1204 gen_literal(literal_pool, literal_top);
\r
1206 /* Generate all global variables that are not initialized */
\r
1208 for(sptr = 0; sptr < global_top; ++sptr) {
\r
1209 type = symtab[sptr].type;
\r
1210 if(!(type & (FUNCTION | INITED | EXTERNAL | TYPDEF))) {
\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
1218 else size = 1; /* should be an error maybe?? */
\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
1225 gen_global(sptr, size);
\r
1231 fwrite(databuf, pd, 1, asm_fh);
\r
1236 { /* No optimize if errors */
\r
1240 while (fgetcode(buffer, LINE_MAX))
\r
1243 fputs(buffer, code_fh);
\r
1245 fputs(buffer, asm_fh);
\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
1265 exit(0); /* We are done ! */
\r
1269 /*****************************************
\r
1270 * Read a character from the input file
\r
1271 ******************************************/
\r
1273 static char read_char(void)
\r
1277 while(!(c = *input_ptr++)) { /* end of this line */
\r
1278 if (!readline()) {
\r
1280 exit(error_count);
\r
1286 /***********************************************************
\r
1287 * Allow a single token to be returned to the input stream
\r
1288 ************************************************************/
\r
1290 static void unget_token(U32 token)
\r
1292 ungot_token = token;
\r
1296 /************************************************
\r
1297 * Read special character (with translations)
\r
1298 *************************************************/
\r
1300 static U32 read_special(char delim)
\r
1304 if((c = read_char()) == delim)
\r
1307 switch(c = read_char()) {
\r
1308 case 'n': /* newline */
\r
1311 case 'r': /* return */
\r
1314 case 't': /* tab */
\r
1317 case 'f' : /* formfeed */
\r
1320 case 'b': /* backspace */
\r
1323 case 'v': /* vertical tab */
\r
1326 case 'x' : /* hex value */
\r
1327 c = get_number(16, 2);
\r
1330 if(is_digit(c)) { /* octal value */
\r
1332 c = get_number(8, 3);
\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
1344 static U32 get_token(void)
\r
1347 char *ptr, *last_pos, chr;
\r
1349 /* if a token has been ungot, re-get it */
\r
1350 /* (gvalue & gst) will not have changed */
\r
1357 /* skip any leading whilespace */
\r
1359 chr = read_char();
\r
1361 while((chr == ' ') || (chr == '\t') ||
\r
1362 (chr == '\n') || (chr == '\r'));
\r
1367 /* lookup token in token table */
\r
1368 last_pos = input_ptr; /* remember where we were */
\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
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
1381 input_ptr = last_pos; /* reset pointer */
\r
1384 /* we didn't find a token, check out special cases */
\r
1385 input_ptr = last_pos;
\r
1387 if((chr = *input_ptr) == '"') { /* string value */
\r
1389 gvalue = literal_top; /* set to index to string */
\r
1391 if(literal_top >= LITER_BUFF)
\r
1392 fatal_error("String space exausted");
\r
1393 literal_pool[literal_top++] = i = read_special('"');
\r
1395 while(!(i & 0xff00)); /* 0xff00 returned from read_special */
\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
1407 { /* quoted value */
\r
1409 while( !((i = read_special(0x27)) & 0xff00) )
\r
1410 gvalue = i & 0xff; /* strip notify bits */
\r
1415 if(is_digit(chr)) { /* numeric constant */
\r
1418 if((*input_ptr == 'x') || (*input_ptr == 'X')) {
\r
1420 gvalue = get_number(16, 0); /* hex */
\r
1423 gvalue = get_number(8, 0); /* octal */
\r
1425 else gvalue = get_number(10, 0); /* decimal */
\r
1427 /* Look for Unsigned and Long terminal characters */
\r
1429 if((*input_ptr == 'U') || (*input_ptr == 'u')) {
\r
1431 if((*input_ptr == 'L') || (*input_ptr == 'l')) ++input_ptr;
\r
1433 else if((*input_ptr == 'L') || (*input_ptr == 'l')) ++input_ptr;
\r
1438 if(is_alpha(chr)) { /* symbol name */
\r
1440 while(is_alnum(chr = *input_ptr)) {
\r
1441 if(gvalue < SYMBOL_SIZE)
\r
1442 gst[gvalue++] = chr;
\r
1445 namesize = gvalue;
\r
1448 /* not a token or special value */
\r
1449 ++input_ptr; /* skip offending character */
\r
1450 return -1; /* report "unknown" token type */
\r
1454 /*****************************************************
\r
1455 * Locate a symbol in the local symbol table
\r
1456 ******************************************************/
\r
1458 static U32 lookup_local(void)
\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
1473 /*************************************************
\r
1474 Locate a symbol in the global symbol table.
\r
1475 **************************************************/
\r
1477 static U32 lookup_global(void)
\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
1489 /**************************************************
\r
1490 Locate a structure member in either symbol table
\r
1491 ***************************************************/
\r
1493 static U32 lookup_member(U32 CrntStruc)
\r
1495 U16 i, j, CrntStrucDef;
\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
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
1509 CrntStrucDef = symtab[CrntStruc].itypedef;
\r
1511 if (symtab[CrntStrucDef].type & GLOBAL) {
\r
1513 for(i=CrntStrucDef+1; i < global_top; i++) {
\r
1514 if (!(symtab[i].type & STRUCMEM))
\r
1516 j = symtab[i].oname;
\r
1517 if(equal_string(gst, &GPool[j]))
\r
1518 return symtab[sptr=i].type |= REFERENCE;
\r
1521 else { /* must be local */
\r
1523 for(i=CrntStrucDef-1; i > local_top-1; i--) {
\r
1524 if (!(symtab[i].type & STRUCMEM))
\r
1526 j = symtab[i].oname;
\r
1527 if(equal_string(gst, &LPool[j]))
\r
1528 return symtab[sptr=i].type |= REFERENCE;
\r
1531 return 0; /* didn't find it! */
\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
1539 static void define_symbol(U32 type, U32 dim_index)
\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
1548 gst[2] = arg_count + 65; /* A-Z */
\r
1549 gst[3] = '\0'; /* null terminate */
\r
1553 if(lookup_local()) {
\r
1554 symbol_error("Duplicate local or arg");
\r
1559 sptr = --local_top;
\r
1560 if(type & ARGUMENT) {
\r
1562 type &= ~PROTO; /* turn off proto warning */
\r
1564 /* if a prototype arg already exists, make sure it's the same */
\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
1571 else proto_list[iproto_next++] = type;
\r
1572 if(iproto_next>MAX_PROTOS)
\r
1573 fatal_error("Prototype table full");
\r
1576 index = local_stack;
\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
1591 else { /* outside of function, use 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
1601 else if (type & STRUCMEM)
\r
1603 else if ((type & STRUCDEF) &&
\r
1604 (equal_string(&structname[0], &GPool[symtab[sptr].oname])))
\r
1607 symbol_error("Duplicate global");
\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
1627 /******************************************
\r
1628 * Push a value on the expression stack
\r
1629 *******************************************/
\r
1631 static void push(U32 token, U32 value, U32 type, U32 offset)
\r
1633 if(expr_ptr >= EXPR_DEPTH)
\r
1634 fatal_error("Expression stack overflow");
\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
1643 /*********************************************
\r
1644 * Pop a value from the expression stack
\r
1645 **********************************************/
\r
1647 static void pop(U32 *token, U32 *value, U32 *type, U32 *offset)
\r
1650 fatal_error("Expression stack underflow");
\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
1660 /********************************************
\r
1661 * Get a constant value (NUMBER or STRING)
\r
1662 * which can be evaluated at compile time.
\r
1663 *********************************************/
\r
1665 static void get_constant(U32 *token, U32 *value)
\r
1670 unget_token(do_oper(SEMI)); /* do_oper gets the token... */
\r
1672 pop(token, value, &type, &offset); /* then we pop it into token */
\r
1674 if((*token != NUMBER) && (*token != STRING))
\r
1675 line_error("Constant expression required");
\r
1678 /********************************
\r
1679 * Define a variable
\r
1680 *********************************/
\r
1682 static void define_var(U32 type)
\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
1688 if(in_function > 1)
\r
1689 line_error("Declaration must preceed code");
\r
1691 /* calculate base variable size - store in j for later use if array */
\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
1699 line_error("Type specifier missing");
\r
1701 if (type&(ARGUMENT | POINTER)) size = 4; /* pointers are 32 bit offsets */
\r
1704 /* If fInStruct then this is a structure member definition.
\r
1705 NOT a structure member! */
\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
1715 /* evaluate any array indexes */
\r
1720 while(test_token(OSB)) { /* array definition */
\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
1727 size *= dim_pool[dim_top] = 1; /* dummy up unbounded array */
\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
1736 if(nDims) { /* defining an array */
\r
1738 dim_pool[iDim] = nDims;
\r
1739 if(++dim_top > DIM_SIZE)
\r
1740 fatal_error("Dimension table full");
\r
1743 if(test_token(ASSIGN)) /* initialized variable */
\r
1746 local_stack += size; /* Keep track of offset of local vars */
\r
1748 define_symbol(type, iDim); /* Create the symbol table entry */
\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
1756 if (type&(STRUCT)) {
\r
1757 symtab[sptr].itypedef = CrntStrucDef;
\r
1758 symtab[sptr].strucoff = symtab[CrntStrucDef].strucoff;
\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
1765 eflag = -1; /* Expexting initializer */
\r
1766 sDim1 = 0; /* tracks nDimensions for unbounded arrays [] */
\r
1767 eTotal = 0; /* Total elements initialized so far */
\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
1776 switch (token=get_token()) {
\r
1778 if ((nflag) && (ocbcnt == 1)) /* count for unbounded */
\r
1781 if (ocbcnt > nDims)
\r
1782 line_error("Too many open braces");
\r
1787 if (ocbcnt) --ocbcnt;
\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
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
1800 break; /* we need a comma first/ocb first */
\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
1809 eTotal+=index; /* total inited so far */
\r
1812 if (lasttoken==CCB) eflag = 0;
\r
1814 lasttoken = COMMA;
\r
1817 /* special case of char[x] = "xx"; or char[] = "xx"; */
\r
1818 if ((!ocbcnt) && (nDims==1))
\r
1824 unget_token(token); /* put it back */
\r
1825 if (eflag) { /* we are expecting a constant */
\r
1826 if ((nflag) && (ocbcnt == 1))
\r
1828 get_constant(&token, &value);
\r
1829 if((token == STRING) && !(type & POINTER)) {
\r
1831 init_static(NUMBER, literal_pool[value], j);
\r
1833 while(++value < literal_top);
\r
1834 literal_top = gvalue;
\r
1836 /* special case of char[]="xx" or char[x]="xx"; */
\r
1837 if ((!ocbcnt) && (nDims==1)) {
\r
1843 init_static(token, value, j);
\r
1845 ++eTotal; /* tracked by index if array */
\r
1850 else line_error("Improper bracketed initialization");
\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
1860 init_static(SYMBOL, sptr, j);
\r
1864 else symbol_error("Undefined");
\r
1866 else line_error("Must be pointer array");
\r
1868 else line_error("Improper bracketed initialization");
\r
1871 line_error("Improper symbol in initialization");
\r
1875 while(((ocbcnt) || (lasttoken==COMMA)) && (token!=SEMI));
\r
1876 if(ocbcnt) expect(CCB); /* make sure brackets balance!! */
\r
1878 if(nflag) /* fixup null definition */
\r
1879 dim_pool[iDim+1] = sDim1;
\r
1881 /* new we make sure all the array elements were initialized
\r
1882 to ensure we have allocated Dseg for them.
\r
1886 while (nDims) i*= dim_pool[iDim+nDims--]; /* i has total elements */
\r
1888 while (eTotal < i) { /* eTotal is total inited */
\r
1889 init_static(NUMBER, 0, j);
\r
1894 line_error("Too many initial values");
\r
1898 } /* if (INITED) */
\r
1902 /*****************************************************
\r
1903 * Check that we are within a function definition
\r
1904 ******************************************************/
\r
1906 static void check_func(void)
\r
1909 if(in_function < 2) { /* first invocation */
\r
1911 enter_func(fptr, local_stack); } }
\r
1913 line_error("Incorrect declaration");
\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
1934 static void declare(U32 token, U32 type)
\r
1940 type &= ~WORD; /* cancel WORD */
\r
1944 if (!(type&DWORD)) type |= WORD;
\r
1950 type &= ~WORD; /* cancel WORD */
\r
1954 type |= WORD; /* cancelled for char or long */
\r
1958 type |= WORD; /* this will be cancelled if it's long */
\r
1959 type &= ~UNSIGNED;
\r
1977 type |= ISR; /* ISR modified for functions */
\r
1985 case STAR: /* pointer reference */
\r
1988 while(test_token(STAR));
\r
1990 /* allow for prototype arg pointers with no symbol name */
\r
1992 if((type&ARGUMENT) && (test_token(COMMA))) {
\r
1993 define_var(type|=PROTO); /* tell 'em it may be symboless */
\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
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
2015 type &= ~STRUCDEF; /* struct variable w/tag */
\r
2020 line_error("struct tag name expected");
\r
2023 /* we didn't find the tag so it must be a new one! */
\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
2031 fInStruct = 1; /* we are in it now... */
\r
2037 if(type&ARGUMENT) {
\r
2041 if(test_token(ORB))
\r
2042 define_func(type); /* function definition */
\r
2044 define_var(type); /* variable definition */
\r
2045 if(test_token(COMMA))
\r
2048 test_token(SEMI); /* eat the semicolon if there */
\r
2050 if (fInStruct) { /* still defining struct members */
\r
2056 case OCB: /* '{' only allowed for immediate struct defs */
\r
2057 if(type & STRUCDEF) { /* Immediate struct definition */
\r
2058 copystring(gst, structname);
\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
2075 type &= ~STRUCDEF; /* struct variable */
\r
2079 if (test_token(SEMI)) /* if semicolon, eat it and return */
\r
2083 unget_token(token); /* fall thru to COMMA */
\r
2085 if(type&ARGUMENT) {
\r
2086 define_var(type|=PROTO);
\r
2094 type &= ~(POINTER | ARRAY); /* clear indirection and rg of last var */
\r
2095 token = get_token();
\r
2099 /**************************************************************
\r
2102 Notes on prototype handling:
\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
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
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
2136 ****************************************************************/
\r
2138 static void define_func(U32 type)
\r
2140 U32 token, dim_save, t, flastarg, i, stackpop;
\r
2147 /* do not allow functions or protos within functions */
\r
2150 line_error("Illegally nested function or prototype");
\r
2154 if(t = lookup_global()) { /* symbol already exists */
\r
2156 icrntpro = symtab[sptr].dindex; /* icrntpro points to arg types */
\r
2160 define_symbol(type | FUNCTION | GLOBAL, 0);
\r
2161 symtab[sptr].dindex = iproto_next;
\r
2166 /* accept variable declarations for local arguments */
\r
2167 /* These must be inside the parens -- ANSI style */
\r
2169 local_top = MAX_SYMBOLS;
\r
2170 dim_save = dim_top;
\r
2171 in_function = 1; /* indicate inside a function */
\r
2174 switch(token = get_token()) { /* define local arguments */
\r
2184 declare(token, ARGUMENT);
\r
2187 case COMMA: break;
\r
2189 proto_list[iproto_next++] = VOID;
\r
2191 symtab[fptr].type |= VARARGS;
\r
2194 if (arg_count) syntax_error(); /* fall through to default */
\r
2197 proto_list[iproto_next++] = VOID;
\r
2198 if(iproto_next>MAX_PROTOS)
\r
2199 fatal_error("Prototype table full");
\r
2201 if (token==CRB) unget_token(token);
\r
2205 } while (!flastarg);
\r
2207 token = get_token();
\r
2211 if(test_token(SEMI)) { /* a prototype function !! */
\r
2212 symtab[fptr].type |= PROTO;
\r
2217 dim_top = dim_save;
\r
2218 if (symtab[fptr].type & EXTERNAL)
\r
2219 gen_extern_DASM(fptr);
\r
2222 symtab[fptr].type &= ~PROTO;
\r
2223 symtab[fptr].type |= FUNCTION;
\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
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
2240 | 4 Bytes | Previous Frame Pointer
\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
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
2254 symtab[MAX_SYMBOLS-i].argoffset = stackpop+8; /* 8 for MMURTL */
\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
2264 end_func(stackpop);
\r
2269 dim_top = dim_save;
\r
2271 /* Error reporting when end of func is reached and certain
\r
2272 conditions exist */
\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
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
2299 code_str("OFFSET ");
\r
2301 code_str("_lit+");
\r
2305 if(type & GLOBAL) {
\r
2306 code_chr('_'); /* prefix with _ */
\r
2307 code_str(&GPool[symtab[value].oname]);
\r
2309 if(type & ARGUMENT)
\r
2311 if (symtab[fptr].type & VARARGS)
\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
2318 code_str("BYTE PTR [EBP+EDI+");
\r
2319 code_num(symtab[value].argoffset);
\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
2329 code_str("BYTE PTR [EBP+");
\r
2330 code_num(symtab[value].argoffset);
\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
2341 code_str("BYTE PTR [EBP-");
\r
2342 code_num(symtab[value].argoffset);
\r
2354 case PECX: /* pointer in other reg - indirect access */
\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
2361 code_str("BYTE PTR ");
\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
2372 code_str("[EBX+");
\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
2385 code_str("[EBX]");
\r
2392 case ION_STACK: /* shouldn't happen */
\r
2394 default: /* Unknown (error) */
\r
2396 code_str(" ERROR in write_oper\n");
\r
2401 /**************************************************
\r
2402 Places operand in code string and sends instruction
\r
2403 out to code segment.
\r
2404 **************************************************/
\r
2406 static void GenCodeOper(char *ptr, U32 token, U32 value, U32 type, U32 offset)
\r
2408 /* interpret the output string & insert the operand */
\r
2413 write_oper(token, value, type, offset);
\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
2430 static void StackEAX(void)
\r
2434 for(i=0; i < expr_ptr; ++i) {
\r
2435 if (expstk[i].token == INEAX) /* Found it */
\r
2437 for(j=0; j < expr_ptr; ++j)
\r
2439 if ((expstk[j].token == STACK_TOP) ||
\r
2440 (expstk[j].token == ISTACK_TOP))
\r
2442 out_inst("PUSH EBX");
\r
2443 if (expstk[j].token == STACK_TOP)
\r
2444 expstk[j].token = ON_STACK;
\r
2446 expstk[j].token = ION_STACK;
\r
2451 out_inst("MOV EBX,EAX");
\r
2452 expstk[i].token = STACK_TOP;
\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
2465 if (token==ION_STACK)
\r
2467 out_inst("POP EDX");
\r
2470 else if (token==ON_STACK)
\r
2472 out_inst("POP EDX");
\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
2483 static void LoadEAX(U32 token, U32 value, U32 type, U32 offset)
\r
2485 if(type & FUNCTION)
\r
2488 if(token == INEAX) { /* Already there */
\r
2493 token = CheckStack(token); /* If it's on the processor stack, get it into EDX */
\r
2495 StackEAX(); /* stack EAX if needed */
\r
2498 if((token == NUMBER) && (!value)) { /* 0 Value */
\r
2500 code_str("\tXOR EAX,EAX\n");
\r
2504 if ((type&(DWORD|POINTER)) ||
\r
2505 (token == NUMBER) ||
\r
2506 (token == INEDX) ||
\r
2507 (token == STACK_TOP) ||
\r
2510 GenCodeOper("MOV EAX,|", token, value, type, offset);
\r
2511 else if (type & WORD)
\r
2513 if (type & UNSIGNED)
\r
2514 GenCodeOper("MOVZX EAX,|", token, value, type, offset);
\r
2516 GenCodeOper("MOVSX EAX,|", token, value, type, offset);
\r
2520 if (type & UNSIGNED)
\r
2522 code_str("\tXOR EAX,EAX\n");
\r
2523 GenCodeOper("MOV AL,|", token, value, type, offset);
\r
2526 GenCodeOper("MOVSX EAX,|", token, value, type, offset);
\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
2537 static void LoadECX(U32 token, U32 value, U32 type, U32 offset)
\r
2539 if(type & FUNCTION)
\r
2542 if(token == INECX)
\r
2543 { /* Already there */
\r
2547 token = CheckStack(token); /* If it's on the processor stack, get it into EDX */
\r
2549 if ((token == NUMBER) && (!value))
\r
2551 code_str("\tXOR ECX,ECX\n");
\r
2555 if ((type&(DWORD|POINTER)) ||
\r
2556 (token == NUMBER) ||
\r
2557 (token == INEDX) ||
\r
2558 (token == STACK_TOP) ||
\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
2566 GenCodeOper("MOVSX ECX,|", token, value, type, offset);
\r
2570 if (type & UNSIGNED)
\r
2572 code_str("\tXOR ECX,ECX\n");
\r
2573 GenCodeOper("MOV CL,|", token, value, type, offset);
\r
2576 GenCodeOper("MOVSX ECX,|", token, value, type, offset);
\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
2588 static void sub_eval(U32 term)
\r
2593 if((token = do_oper(SEMI)) != COMMA) {
\r
2594 unget_token(token);
\r
2598 pop(&token, &token, &token, &token); /* throw it away */
\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
2608 static void eval(U32 term, char flag)
\r
2610 U32 token, value, type, offset;
\r
2616 pop(&token, &value, &type, &offset);
\r
2617 if((token != INEAX) || flag)
\r
2618 LoadEAX(token, value, type, offset);
\r
2621 /************************************************
\r
2622 * Write an instruction with text formatting
\r
2623 to the code tmp file
\r
2624 *************************************************/
\r
2626 static void out_inst(char *ptr)
\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
2641 static void StackTop(void)
\r
2645 for(j=0; j < expr_ptr; ++j)
\r
2647 if ((expstk[j].token == STACK_TOP) ||
\r
2648 (expstk[j].token == ISTACK_TOP))
\r
2650 out_inst("PUSH EBX");
\r
2651 if (expstk[j].token == STACK_TOP)
\r
2652 expstk[j].token = ON_STACK;
\r
2654 expstk[j].token = ION_STACK;
\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
2670 static void StackESI(void)
\r
2674 for(i=0; i < expr_ptr; ++i) {
\r
2675 if (expstk[i].token == PESI) /* Found it */
\r
2677 for(j=0; j < expr_ptr; ++j)
\r
2679 if ((expstk[j].token == STACK_TOP) ||
\r
2680 (expstk[j].token == ISTACK_TOP))
\r
2682 out_inst("PUSH EBX");
\r
2683 if (expstk[j].token == STACK_TOP)
\r
2684 expstk[j].token = ON_STACK;
\r
2686 expstk[j].token = ION_STACK;
\r
2690 out_inst("MOV EBX,ESI");
\r
2691 expstk[i].token = ISTACK_TOP;
\r
2697 /*****************************************
\r
2698 * Load index address for an array
\r
2699 ******************************************/
\r
2701 static void load_index(U32 t, U32 v, U32 tt, U32 o)
\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
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
2716 static void do_unary(U32 oper)
\r
2718 U32 token, value, type, offset;
\r
2721 pop(&token, &value, &type, &offset);
\r
2723 /* Evaluate any operations that can be performed at compile time */
\r
2724 if(token == NUMBER)
\r
2729 case SUB : /* unary minus */
\r
2732 case COM: /* ones complement */
\r
2735 case NOT: /* logical complement */
\r
2743 /* Generate code to perform operation */
\r
2748 case SUB: /* unary minus */
\r
2749 GenCodeOper("NEG |", token, value, type, offset);
\r
2751 case COM: /* ones complement */
\r
2752 GenCodeOper("NOT |", token, value, type, offset);
\r
2754 case NOT: /* logical complement */
\r
2755 LoadEAX(token, value, type, offset);
\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
2767 GenCodeOper("INC |", token, value, type, offset);
\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
2777 GenCodeOper("DEC |", token, value, type, offset);
\r
2783 push(token, value, type, offset);
\r
2787 /******************************************************
\r
2788 This evaluates array indeces for get_value.
\r
2789 *******************************************************/
\r
2791 static S8 eval_index(U32 t, U32 v, U32 tp, U32 ofs, U32 *tpRet)
\r
2794 U32 tp1, dptr, iSym, vsize, ofs1;
\r
2797 fMultiDim = FALSE; /* true when processing second or subsequent dims */
\r
2799 if(tp & ARRAY) { /* array, get # dimensions */
\r
2800 dptr = symtab[v].dindex;
\r
2801 ndim = dim_pool[dptr++];
\r
2803 else /* pointer, fake # dims as 1 */
\r
2806 iSym = v; /* save index into symtab */
\r
2808 push(t, v, tp, ofs); /* save symbol we are indexing on exp stack */
\r
2810 do { /* calculate index */
\r
2812 /* this gets the size of variable into vsize */
\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
2824 if(tp & ARRAY) /* array reference */
\r
2827 if(!(v = ndim)) /* all indices given, load pointer */
\r
2828 tp &= ~ARRAY; /* Not an array ref anymore, ptr instead */
\r
2830 vsize *= dim_pool[t++];
\r
2835 { /* pointer reference */
\r
2836 --tp; /* drop defer level by one */
\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
2848 else /* invalid indexing */
\r
2851 sub_eval(CSB); /* GET the value inside the [] */
\r
2853 /* Multiply [] by size of index */
\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
2859 if(fMultiDim) do_lr2op(ADD); /* add to last index if there */
\r
2860 fMultiDim = TRUE; /* if there is another... */
\r
2862 while(test_token(OSB));
\r
2868 /******************************************************
\r
2869 Gets the next token and perform any processing
\r
2870 required to evaluate it. This includes structure
\r
2872 *******************************************************/
\r
2874 static void get_value(void)
\r
2877 U32 i, j, size, token, t, v, tp, tp1, ofs;
\r
2878 char fMultiDim, fvarargs;
\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
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
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
2898 else /* variable, report error */
\r
2899 symbol_error("Undefined symbol");
\r
2902 v = sptr; /* symtab entry */
\r
2903 tp = symtab[v].type;
\r
2904 ofs = 0; /* offset of zero */
\r
2906 case STAR: /* pointer dereference */
\r
2908 pop(&t, &v, &tp, &ofs);
\r
2910 index_ptr(t, v, tp, ofs);
\r
2917 case AND: /* address of */
\r
2919 pop(&t, &v, &tp, &ofs);
\r
2923 code_str((tp & GLOBAL) ? "\tMOV EAX,OFFSET " : "\tLEA EAX,");
\r
2924 write_oper(t, v, tp, ofs);
\r
2927 tp = (tp + 1) & ~FUNCTION; /* tp + 1 ups the ptr ref count */
\r
2930 else if (t == PESI)
\r
2934 out_inst("MOV EAX,ESI");
\r
2935 tp = (tp + 1) & ~FUNCTION; /* tp + 1 ups the ptr ref count */
\r
2938 else if ((t == INEAX) && (tp & POINTER))
\r
2939 { /* do nothing... it's there. */ }
\r
2941 line_error("Invalid '&' operation");
\r
2943 case ORB: /* sub-expression */
\r
2945 pop(&t, &v, &tp, &ofs);
\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
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
2965 tp = DWORD; /* all constants are DWORDS */
\r
2967 push(t, v, tp, 0); /* PUSH THE "Value" ON THE EXP STACK */
\r
2972 line_error("Symbol expected");
\r
2975 line_error("'(' expected");
\r
2977 default: /* anything else (operators) */
\r
2978 get_value(); /* look for a value */
\r
2983 /* Function calls - Open Round Brackett (ORB) */
\r
2985 if(test_token(ORB))
\r
2987 iarg = symtab[v].dindex; /* index to prototyped args! */
\r
2988 push(t, v, tp, ofs);
\r
2991 if (tp & VARARGS) fvarargs = -1;
\r
2992 else fvarargs = 0;
\r
2995 if(!test_token(CRB))
\r
2996 { /* evaluate function operands */
\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
3009 out_inst("PUSH EAX");
\r
3012 if ((!fvarargs) || (fvarargs && (argtype==VOID))) {
\r
3016 while(token == COMMA);
\r
3021 pop(&t, &v, &tp, &ofs); /* get function back off the expr stack */
\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
3033 code_str("\tMOV EDI, ");
\r
3039 call(t, v, tp, ofs, ndim);
\r
3041 t = INEAX; /* set up to leave the return value in ACC */
\r
3047 /* Indexing operations - Open Square Brackett (OSB) */
\r
3050 if(test_token(OSB)) {
\r
3051 fMultiDim = eval_index(t, v, tp, ofs, &tp);
\r
3053 /* get index value token pushed by eval_index */
\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
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
3070 t = PESI; /* Let em know ESI pts to item */
\r
3073 /* Convert any [UNINDEXED] array references to address values.
\r
3074 This is done later to structures and struct members.
\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
3083 StackEAX(); /* save what's in EAX and ESI */
\r
3085 index_adr(t, v, tp, ofs); /* load address of rg into ESI */
\r
3087 StackEAX(); /* save what's in EAX if needed */
\r
3089 out_inst("MOV EAX,ESI");
\r
3094 /* handle the dereference operators . and -> for
\r
3095 structures and pointers to structures if present */
\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
3106 if (test_token(SYMBOL)) {
\r
3107 if (lookup_member(v)) {
\r
3108 memoffset = symtab[sptr].strucoff;
\r
3109 tp = symtab[sptr].type;
\r
3111 ofs = memoffset; /* NEW */
\r
3114 tp = (tp + 1) & ~ARRAY; /* tp+1 ups the ptr ref count */
\r
3115 t = PESI; /* tell em it's indirect now */
\r
3118 line_error("Not a structure member");
\r
3121 line_error("Structure member expected");
\r
3124 line_error("Pointer to Struct expected");
\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
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
3142 t = PESI; /* tell em it's indirect now */
\r
3146 line_error("Structure member expected");
\r
3149 line_error("Structure member expected");
\r
3152 line_error("Invalid structure operation");
\r
3155 /* Indexing operations for STRUCTMEMS- Open Square Brackett (OSB) */
\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
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
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
3179 load_index(t, v, tp1, ofs); /* Load base into Index reg */
\r
3181 out_inst("ADD ESI,EAX");
\r
3183 t = PESI; /* Let em know ESI pts to item */
\r
3187 /* Convert any [UNINDEXED] array references to address values
\r
3188 for struct members that are arrays.
\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
3197 StackEAX(); /* stack EAX */
\r
3198 StackESI(); /* stack ESI */
\r
3199 index_adr(t, v, tp, ofs); /* load address of rg into ESI */
\r
3201 StackEAX(); /* stack EAX if needed */
\r
3203 out_inst("MOV EAX,ESI");
\r
3208 /* handle any post operators (++ and --) if present */
\r
3210 if(test_token(INC)) { /* post '++' */
\r
3213 load_index(t, v, tp, ofs);
\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
3224 GenCodeOper("INC |", t, v, tp, ofs);
\r
3233 else if(test_token(DEC))
\r
3237 load_index(t, v, tp, ofs);
\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
3248 GenCodeOper("DEC |", t, v, tp, ofs);
\r
3256 push(t, v, tp, ofs); /* FINALLY PUSH THE "Value" ON THE EXP STACK */
\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
3266 static U32 combine(U32 type1, U32 type2)
\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
3273 if ((type1 & POINTER) >= (type2 & POINTER))
\r
3274 new_type = type1 & POINTER;
\r
3276 new_type = type2 & POINTER;
\r
3278 /* raise to lowest common type */
\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
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
3289 if (!((type1 & type2) & UNSIGNED)) /* both signed */
\r
3292 if ((type1 & UNSIGNED) && (type2 & UNSIGNED)) { /* both unsigned */
\r
3293 new_type |=UNSIGNED;
\r
3297 /* ONLY one is signed... */
\r
3299 if (((type1 & SIZEMASK) >= (type2 & SIZEMASK)) && (type2 & UNSIGNED))
\r
3300 new_type |= UNSIGNED;
\r
3303 if (((type1 & SIZEMASK) <= (type2 & SIZEMASK)) && (type1 & UNSIGNED))
\r
3304 new_type |= UNSIGNED;
\r
3310 /**********************************************************
\r
3311 * Perform an operation & all higher priority operations.
\r
3312 ***********************************************************/
\r
3314 static U32 do_oper(U32 token)
\r
3316 U32 token1, t, v, tp, tp1, ofs, ofs1, exit_lab;
\r
3318 /* Handle "special" binary operators which involve jumps */
\r
3319 if((token == DAND) || (token == DOR) || (token == QUEST))
\r
3321 pop(&t, &v, &tp, &ofs);
\r
3322 StackEAX(); /* stack EAX */
\r
3323 StackESI(); /* stack ESI */
\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
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
3340 cond_jump(FALSE, exit_lab, -1);
\r
3342 cond_jump(TRUE, exit_lab, -1);
\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
3352 get_value(); /* stack the value (number or whatever) */
\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
3357 token1 = get_token(); /* Look at next operator */
\r
3358 while((optype[token1] > 1) &&
\r
3359 (priority[token1] >= priority[token]))
\r
3361 /* if they are the same priority AND grouping == L-R */
\r
3363 if((priority[token1] == priority[token]) &&
\r
3364 (optype[token] == 2))
\r
3367 return do_oper(token1);
\r
3370 token1 = do_oper(token1);
\r
3373 /* Perform the operation */
\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
3391 static void do_lr2op(U32 oper)
\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
3397 pop(&token1, &value1, &type1, &offset1);
\r
3398 pop(&token, &value, &type, &offset);
\r
3400 uflag = swap = order = atoken = 0;
\r
3402 /* Constant numbers assume the type of the other operand */
\r
3403 if(token == NUMBER)
\r
3408 if(token1 == NUMBER)
\r
3414 ctype = combine(type, type1);
\r
3416 /* Do any operations that can be performed at compile time */
\r
3418 if((token == NUMBER) && (token1 == NUMBER) &&
\r
3419 (oper != DAND) && (oper != DOR)) {
\r
3452 value = value == value1;
\r
3455 value = value != value1;
\r
3458 value = value < value1;
\r
3460 value = value <= value1;
\r
3463 value = value > value1;
\r
3466 value = value >= value1;
\r
3474 /* Generate code to perform the operation */
\r
3477 wheretok = INEAX; /* default place for result */
\r
3479 /* Use unsigned operations if needed */
\r
3480 if((type | type1) & (POINTER | UNSIGNED))
\r
3483 /* Try and re-arrange for partial results already in ACC */
\r
3484 if(token1 == INEAX)
\r
3487 /* This first switch sets up self assignments and
\r
3488 changes the operand to the real operation to be
\r
3494 case DAND: /* logical AND and OR are done elsewhere */
\r
3496 push(token1, value1, type1, offset1);
\r
3499 atoken = token; /* nonzero atoken indicates self assignment*/
\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
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
3601 if((token1 == INEAX) && order)
\r
3602 { /* out of order - use ECX */
\r
3604 out_inst("MOV ECX,EAX");
\r
3608 if(swap && !order)
\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
3616 if(type1 & FUNCTION)
\r
3619 if (oper != ASSIGN) /* simple assignment is optimized case */
\r
3621 LoadEAX(token, value, type, offset); /* insure its loaded */
\r
3624 /* If it's on the processor stack, get it into EDX */
\r
3625 token1 = CheckStack(token1);
\r
3627 /* Now we perform the operation */
\r
3632 /* optimize away an assigment */
\r
3633 if ((token1 == token) && (value == value1))
\r
3638 if (swap) /* token to store is already in EAX */
\r
3640 store(token1, value1, type1, offset1);
\r
3642 else /* token1 may not be loaded already */
\r
3644 LoadEAX(token1, value1, type1, offset1);
\r
3645 store(token, value, type, offset);
\r
3649 if (type1&(DWORD|POINTER))
\r
3650 GenCodeOper("ADD EAX,|", token1, value1, type1, offset1);
\r
3653 LoadECX(token1, value1, type1, offset1);
\r
3654 out_inst("ADD EAX,ECX");
\r
3659 if (type1&(DWORD|POINTER))
\r
3660 GenCodeOper("SUB EAX,|", token1, value1, type1, offset1);
\r
3663 LoadECX(token1, value1, type1, offset1);
\r
3664 out_inst("SUB EAX,ECX");
\r
3669 LoadECX(token1, value1, type1, offset1);
\r
3670 if (ctype & UNSIGNED)
\r
3671 out_inst("MUL ECX");
\r
3673 out_inst("IMUL ECX");
\r
3678 LoadECX(token1, value1, type1, offset1);
\r
3679 if (ctype & UNSIGNED)
\r
3681 out_inst("XOR EDX,EDX");
\r
3682 out_inst("DIV ECX");
\r
3687 out_inst("IDIV ECX");
\r
3691 out_inst("MOV EAX,EDX");
\r
3694 if (type1 & (DWORD|POINTER))
\r
3695 GenCodeOper("AND EAX,|", token1, value1, type1, offset1);
\r
3698 LoadECX(token1, value1, type1, offset1);
\r
3699 out_inst("AND EAX,ECX");
\r
3704 if (type1 & (DWORD|POINTER))
\r
3705 GenCodeOper("OR EAX,|", token1, value1, type1, offset1);
\r
3708 LoadECX(token1, value1, type1, offset1);
\r
3709 out_inst("OR EAX,ECX");
\r
3714 if (type1 & (DWORD|POINTER))
\r
3715 GenCodeOper("XOR EAX,|", token1, value1, type1, offset1);
\r
3718 LoadECX(token1, value1, type1, offset1);
\r
3719 out_inst("XOR EAX,ECX");
\r
3724 LoadECX(token1, value1, type1, offset1);
\r
3725 out_inst("SHL EAX,CL");
\r
3727 out_inst("AND EAX,0FFFFh");
\r
3728 else if (ctype & BYTE)
\r
3729 out_inst("AND EAX,0FFh");
\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
3739 out_inst("SHR AL,CL");
\r
3742 case EQ: /* compare & test */
\r
3752 if (type1&(DWORD|POINTER))
\r
3753 GenCodeOper("CMP EAX,|", token1, value1, type1, offset1);
\r
3756 LoadECX(token1, value1, type1, offset1);
\r
3757 out_inst("CMP EAX,ECX");
\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
3772 out_inst("AND AL,AL");
\r
3779 /* for self assigns, replace value */
\r
3781 store(atoken, avalue, atype, offset);
\r
3786 push(token, value, ctype, offset);
\r
3791 /***************************************************
\r
3792 * Test for a logically negated value, and update
\r
3793 * the accumulator if one is being used.
\r
3794 ****************************************************/
\r
3796 static void test_not(void)
\r
3800 out_inst("AND EAX,EAX");
\r
3801 out_inst("SETZ AL");
\r
3802 out_inst("AND AL,AL");
\r
3809 /********************************************
\r
3810 * Store accumulator value
\r
3811 *********************************************/
\r
3813 static void store(U32 token, U32 value, U32 type, U32 offset)
\r
3816 token = CheckStack(token); /* get stack operand to EDX if needed */
\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
3830 GenCodeOper("MOV |, AL", token, value, type, offset);
\r
3834 line_error("Non-assignable");
\r
3839 /*********************************************
\r
3840 Determine if a type is a pointer to struct
\r
3841 **********************************************/
\r
3843 static U32 ispStruct(U32 type, U32 value)
\r
3845 if((type & POINTER) > 1) /* pointer to pointer */
\r
3847 if ((type & STRUCT) && (type & POINTER)) {
\r
3848 strucsize = symtab[value].strucoff;
\r
3851 return 0; /* not our pointer */
\r
3854 /*********************************************
\r
3855 Determine if a type is a pointer to 32 bits
\r
3856 **********************************************/
\r
3858 static U32 isp32(U32 type)
\r
3860 if(type & (POINTER-1)) /* pointer to pointer */
\r
3862 if(type & POINTER) /* first level pointer */
\r
3863 return (type & DWORD);
\r
3864 return 0; /* not a pointer */
\r
3867 /***********************************************
\r
3868 Determine if a type is a pointer to 16 bits
\r
3869 ************************************************/
\r
3870 static U32 isp16(U32 type)
\r
3872 if(type & POINTER) /* first level pointer */
\r
3873 return (type & WORD);
\r
3874 return 0; /* not a pointer */
\r
3878 * Output a string to the assembler followed by newline.
\r
3880 static void do_asm(char *ptr)
\r
3885 /***************************
\r
3886 Initialize static storage
\r
3887 ****************************/
\r
3889 static void init_static(U32 token, U32 value, char word)
\r
3891 char *ptr, *ptr1, *nptr;
\r
3896 if(global_width) /* continuing definition */
\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
3904 if(token == SYMBOL) { /* Symbol - MUST BE GLOBAL - NOT EXTERNAL */
\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
3914 global_width += 4; }
\r
3915 else { /* constant value */
\r
3917 global_width += 6; }
\r
3919 if (*ptr) data_str(ptr);
\r
3920 if (*ptr1) data_str(ptr1);
\r
3921 if (token!=SYMBOL)
\r
3924 nptr=&GPool[symtab[value].oname];
\r
3926 i=0; while(*nptr++) i+=1;
\r
3927 global_width += i;
\r
3930 if(global_width > 60) {
\r
3936 /********************************
\r
3937 * End static storage definition
\r
3938 *********************************/
\r
3939 static void end_static(void)
\r
3941 if(global_width) {
\r
3947 /*******************************************************************
\r
3948 * Define a global non-static variable
\r
3949 ********************************************************************/
\r
3951 static void gen_global(U32 symbol, U32 size)
\r
3953 data_global(symbol);
\r
3954 if(symtab[symbol].type & (POINTER | DWORD)) {
\r
3956 data_str(" DD 0h\n");
\r
3960 data_str(" DUP(0)\n");
\r
3964 if(symtab[symbol].type & WORD) {
\r
3966 data_str(" DW 0h\n");
\r
3970 data_str(" DUP(0)\n");
\r
3974 if(symtab[symbol].type & (BYTE|STRUCT)) {
\r
3976 data_str(" DB 0h\n");
\r
3980 data_str(" DUP(0)\n");
\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
3991 static void gen_extern_DASM (U32 symbol)
\r
3995 type = symtab[symbol].type;
\r
3998 data_str("EXTRN ");
\r
4000 data_str(&GPool[symtab[symbol].oname]);
\r
4001 data_str(" FWORD");
\r
4004 else if (type & FUNCTION)
\r
4006 code_str("EXTRN ");
\r
4008 code_str(&GPool[symtab[symbol].oname]);
\r
4010 code_str(" NEAR");
\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
4021 static void gen_ext_data_DASM (U32 symbol)
\r
4025 type = symtab[symbol].type;
\r
4027 if (!(type & FUNCTION))
\r
4029 data_str("EXTRN ");
\r
4031 data_str(&GPool[symtab[symbol].oname]);
\r
4032 if (type & (POINTER|DWORD))
\r
4034 else if (type & WORD)
\r
4042 /*******************************************************
\r
4043 * Enter function & allocate local variable stack space
\r
4044 ********************************************************/
\r
4046 static void enter_func(U32 symbol, U32 size)
\r
4048 code_global(symbol);
\r
4050 if (symtab[fptr].type & ISR)
\r
4052 out_inst("PUSHAD");
\r
4055 out_inst("PUSH EBP");
\r
4056 out_inst("MOV EBP,ESP");
\r
4058 code_str("\tSUB ESP,");
\r
4064 /************************************************
\r
4065 * Clean up the stack & end function definition
\r
4066 *************************************************/
\r
4068 static void end_func(U32 stackpop)
\r
4070 if (symtab[fptr].type & ISR)
\r
4072 out_inst("POPAD");
\r
4073 out_inst("IRETD");
\r
4077 out_inst("MOV ESP,EBP");
\r
4078 out_inst("POP EBP");
\r
4080 if (symtab[fptr].type & FAR) code_str("\tRETF ");
\r
4081 else code_str("\tRETN ");
\r
4082 code_num(stackpop);
\r
4085 else if (symtab[fptr].type & FAR) out_inst("\tRETF");
\r
4086 else out_inst("RETN");
\r
4090 /**********************************
\r
4091 Define a compiler generated label
\r
4092 ***********************************/
\r
4094 static void gen_label(U32 label)
\r
4102 /***********************
\r
4103 Define literal pool
\r
4104 ************************/
\r
4105 static void gen_literal(unsigned char *ptr, U32 size)
\r
4114 data_str((i % 16) ? "," : " DB ");
\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
4128 token = CheckStack(token);
\r
4131 code_str("\tCALL FWORD PTR ");
\r
4133 else code_str("\tCALL ");
\r
4134 if(token == NUMBER)
\r
4137 write_oper(token, value, type, offset);
\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
4152 /**********************************
\r
4153 * Unconditional jump to label
\r
4154 ***********************************/
\r
4156 static void jump(U32 label, char ljmp)
\r
4158 code_str(ljmp ? "\tJMP " : "\tJMP SHORT ");
\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
4171 if (ljmp) code_str(cond ? "\tJNZ " : "\tJZ ");
\r
4172 else code_str(cond ? "\tJNZ SHORT " : "\tJZ SHORT ");
\r
4179 /***********************************************
\r
4180 JUMP to the begining of the switch jump table
\r
4181 ************************************************/
\r
4182 static void do_switch(U32 label)
\r
4184 code_str("\tJMP ");
\r
4191 /*************************************************
\r
4192 * Build switch compare/jump table.
\r
4193 * d is the count of switch jump table entries.
\r
4194 **************************************************/
\r
4196 static void build_switch(U32 d)
\r
4198 while(switch_ptr > d) {
\r
4199 code_str("\tCMP EAX,");
\r
4200 code_num(switch_stack[--switch_ptr]);
\r
4202 code_str("\tJE ");
\r
4205 code_num(switch_stack[--switch_ptr]);
\r
4211 /********************************************
\r
4212 Load index register with a pointer value
\r
4213 *********************************************/
\r
4215 static void index_ptr(U32 token, U32 value, U32 type, U32 offset)
\r
4217 if(token == INEAX)
\r
4219 out_inst("MOV ESI,EAX");
\r
4221 else if (token==PESI)
\r
4225 token = CheckStack(token);
\r
4226 code_str("\tMOV ESI,");
\r
4227 write_oper(token, value, type, offset);
\r
4232 /************************************************
\r
4233 Load index register with the address of a symbol
\r
4234 *************************************************/
\r
4236 static void index_adr(U32 token, U32 value, U32 type, U32 offset)
\r
4238 if (token != PESI)
\r
4240 code_str((type & GLOBAL) ? "\tMOV ESI,OFFSET " : "\tLEA ESI,");
\r
4241 write_oper(token, value, type, offset);
\r
4246 /**********************************
\r
4247 * Output a global code symbol name
\r
4248 ***********************************/
\r
4250 static void code_global(U32 symbol)
\r
4253 ptr = &GPool[symtab[symbol].oname];
\r
4254 if(!(symtab[symbol].type & STATIC))
\r
4256 code_str("PUBLIC ");
\r
4262 /**********************************
\r
4263 * Output a global data symbol name
\r
4264 ***********************************/
\r
4266 static void data_global(U32 symbol)
\r
4269 ptr = &GPool[symtab[symbol].oname];
\r
4270 if(!(symtab[symbol].type & STATIC))
\r
4272 data_str("PUBLIC ");
\r
4279 /**********************************************
\r
4280 CODE FILE OUTPUT ROUTINES
\r
4281 ***********************************************/
\r
4283 /***************************************
\r
4284 Write a char to the code tmp file
\r
4285 ***************************************/
\r
4287 void code_chr(char chr)
\r
4289 pcodebuf[pc++] = chr;
\r
4290 if (pc >= 512000-1)
\r
4292 printf("Code buffer overflow... (512000 bytes)\r\n");
\r
4297 /****************************************
\r
4298 Write a string to the code tmp file
\r
4299 *****************************************/
\r
4301 void code_str(char *ptr)
\r
4307 /********************************
\r
4308 * Write a number to the code buf
\r
4309 *********************************/
\r
4311 void code_num(U32 value)
\r
4316 if(value & 0x80000000) {
\r
4322 stack[i++] = (value % 10) + '0';
\r
4323 while(value /= 10);
\r
4326 code_chr(stack[--i]);
\r
4329 /**********************************************
\r
4330 ASM FILE OUTPUT ROUTINES (INITIAL DATA SEG)
\r
4331 ***********************************************/
\r
4333 /* Write a char to the asm file (all data) */
\r
4335 void data_chr(char chr)
\r
4337 databuf[pd++] = chr;
\r
4340 fwrite(databuf, 4096, 1, asm_fh);
\r
4345 /* Write a string to the asm file (all data) */
\r
4347 void data_str(char *ptr)
\r
4353 /********************************
\r
4354 * Write a number to the data buf
\r
4355 *********************************/
\r
4357 void data_num(U32 value)
\r
4362 if(value & 0x80000000) {
\r
4368 stack[i++] = (value % 10) + '0';
\r
4369 while(value /= 10);
\r
4372 data_chr(stack[--i]);
\r
4376 /********************************
\r
4377 * Write a number to file
\r
4378 *********************************/
\r
4380 void put_num(U32 value, FILE *outfile)
\r
4385 if(value & 0x80000000) {
\r
4386 fputc('-', outfile);
\r
4391 stack[i++] = (value % 10) + '0';
\r
4392 while(value /= 10);
\r
4395 fputc(stack[--i], outfile);
\r
4398 /***************************************
\r
4399 * Process a language statement
\r
4400 ****************************************/
\r
4402 static void statement(U32 token)
\r
4406 test_exit(); /* generate any preceeding exit */
\r
4409 { /* act upon the token */
\r
4410 case SEMI: /* ';' - null statement */
\r
4413 case OCB: /* '{' - begin a block */
\r
4414 while((token = get_token()) != CCB)
\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
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
4441 statement(get_token()); }
\r
4447 gen_label(continue_stack[loop_ptr] = a = ++next_lab);
\r
4448 break_stack[loop_ptr++] = b = ++next_lab;
\r
4451 cond_jump(FALSE, b, -1);
\r
4452 statement(get_token());
\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
4466 cond_jump(TRUE, a, -1);
\r
4473 if(!test_token(SEMI)) /* initial */
\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
4479 cond_jump(FALSE, b, -1); }
\r
4480 if(!test_token(CRB))
\r
4482 jump(c = ++next_lab, 0);
\r
4483 gen_label(d = ++next_lab);
\r
4488 continue_stack[loop_ptr++] = d;
\r
4489 statement(get_token());
\r
4491 gen_label(b); /* exit */
\r
4497 break_stack[loop_ptr++] = sdefault = b = ++next_lab;
\r
4500 do_switch(c = ++next_lab);
\r
4502 statement(get_token());
\r
4506 if (sdefault!=a) jump(sdefault, -1);
\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
4521 sdefault = check_switch();
\r
4526 if(!test_token(SEMI))
\r
4530 exit_flag = exit_label ? exit_label : (exit_label = ++next_lab);
\r
4533 check_loop(break_stack);
\r
4536 check_loop(continue_stack);
\r
4540 if(get_token() != SYMBOL) {
\r
4543 if(a = lookup_local()) {
\r
4547 define_symbol(REFERENCE|GLABEL, ++next_lab);
\r
4548 jump(symtab[sptr].dindex, -1);
\r
4550 case SYMBOL: /* a symbol table entry */
\r
4551 if(!in_function) { /* global definition */
\r
4552 declare(token, 0);
\r
4554 if(*input_ptr == ':') { /* label definition */
\r
4557 if(lookup_local())
\r
4558 symtab[sptr].type &= ~EXTERNAL;
\r
4560 define_symbol(GLABEL, ++next_lab); /* sets sptr */
\r
4561 gen_label(symtab[sptr].dindex);
\r
4564 default: /* expression evaluation */
\r
4566 unget_token(token);
\r
4572 /*********************************************************
\r
4573 * Main compile loop, process statements until end of file
\r
4574 **********************************************************/
\r
4576 static void compile(void)
\r
4578 define_ptr = define_pool;
\r
4579 *(input_ptr = line_in) = 0;
\r
4581 code_str("\n\n.CODE\n");
\r
4582 data_str("\n.DATA\n");
\r
4585 statement(get_token());
\r
4588 /****************************************************
\r
4589 * Initialize I/O & execute compiler MAIN MAIN MAIN
\r
4590 *****************************************************/
\r
4592 void main(S32 argc, char *argv[])
\r
4595 char *ptr, *pname;
\r
4597 /* first, get a BIG code buffer!! */
\r
4599 erc = AllocPage(SCODEBUF/4096, &pcodebuf);
\r
4601 printf("Not enough memory to allocate %d bytes.\r\n", SCODEBUF);
\r
4603 /* extern far U32 DeAllocPage(U8 *pOrigMem, U32 nPages); */
\r
4605 /* first process any filenames and command line options */
\r
4607 list_fh = stdout; /* default the list file */
\r
4609 for(i=1; i < argc; ++i) { /* start at arg 1 */
\r
4611 if (*ptr == '/') {
\r
4614 case 'S' : /* quiet mode */
\r
4618 case 'L' : /* List file ON */
\r
4622 case 'E' : /* Embedded source mode */
\r
4626 case 'G' : /* Generate separate modules */
\r
4630 case 'N' : /* NO optimize */
\r
4634 case 'O' : /* Optimize for speed */
\r
4638 case 'W' : /* Warnings ON */
\r
4642 case 'P' : /* Prefix label character */
\r
4645 if (!is_alpha(*ptr))
\r
4646 fatal_error("Invalid label prefix character");
\r
4650 fatal_error("Invalid switch");
\r
4656 copystring(srcname, argv[i]);
\r
4657 source_fh = fopen(argv[i], "r");
\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
4667 fatal_error("Too many parameters");
\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
4687 /* Output file not explicitly named defaults to Source.asm */
\r
4690 { /* default asm name to SourceName.asm */
\r
4691 copystring(asmname, srcname);
\r
4693 while ((*pname != '.') && (*pname!= '\0')) pname++;
\r
4710 if(!(asm_fh = fopen(asmname, "w")))
\r
4712 fputs("Error: Can't open ASM file\r\n", stdout);
\r
4718 /* If -L then List file named Source.LST is generated. */
\r
4722 copystring(lstname, srcname);
\r
4724 while ((*pname != '.') && (*pname!= '\0')) pname++;
\r
4730 if(!(list_fh = fopen(lstname, "w")))
\r
4731 fatal_error("Cannot open LIST file");
\r
4732 else fLISTOpen = TRUE;
\r
4735 /* open code segment tmp file or Gen file */
\r
4739 copystring(codename, srcname);
\r
4741 while ((*pname != '.') && (*pname!= '\0')) pname++;
\r
4747 if(!(code_fh = fopen(codename, "w")))
\r
4748 fatal_error("Cannot open Code file");
\r
4749 else fCODEOpen = TRUE;
\r
4753 fputs("C Minus 32 Compiler, Version 2.3M\r\n", stdout);
\r