2 Copyright (C) 1998 BJ Eirich (aka vecna)
\r
3 This program is free software; you can redistribute it and/or
\r
4 modify it under the terms of the GNU General Public License
\r
5 as published by the Free Software Foundation; either version 2
\r
6 of the License, or (at your option) any later version.
\r
7 This program is distributed in the hope that it will be useful,
\r
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
\r
10 See the GNU General Public Lic
\r
11 See the GNU General Public License for more details.
\r
12 You should have received a copy of the GNU General Public License
\r
13 along with this program; if not, write to the Free Software
\r
14 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
\r
17 // ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
\r
18 // ³ The VergeC Compiler version 2.01 ³
\r
19 // ³ Copyright (C)1998 BJ Eirich (aka vecna) ³
\r
20 // ³ Pre Processor module ³
\r
21 // ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
\r
23 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
\r
26 // + fixed incorrect file markers and last character omission.
\r
27 // + one more incorrect file marker fix; was not restoring correctly after
\r
29 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
\r
42 #include "lexical.h"
\r
46 static int pp_tempct = 0;
\r
65 void Process(char *filename);
\r
66 char *pp_token(char *p);
\r
68 ////////////////////////////////////////////////////////////////////////////
\r
69 // DATA ////////////////////////////////////////////////////////////////////
\r
70 ////////////////////////////////////////////////////////////////////////////
\r
72 pp_def *pp_defarr = NULL;
\r
74 int pp_num_defs = 0;
\r
75 int pp_defs_allocated = 0;
\r
76 int PP_DEFS_BLOCK = 25;
\r
78 pp_include pp_incarr[100];
\r
79 //pp_include *pp_icur = NULL; // get rid of this
\r
80 char *cur_filename=0;
\r
81 char *last_filename=0;
\r
83 int pp_num_includes = 0;
\r
86 int pp_total_lines = 0;
\r
88 const int EOF_CHAR = 0x00;
\r
90 char pp_chr_table[256];
\r
105 FILE *pp_out = NULL;
\r
108 int pp_toktype = 0;
\r
110 int pp_last_delim = 1;
\r
112 ////////////////////////////////////////////////////////////////////////////
\r
113 // CODE ////////////////////////////////////////////////////////////////////
\r
114 ////////////////////////////////////////////////////////////////////////////
\r
117 void log(char *str)
\r
121 FILE *fp = fopen("error.log", "a");
\r
128 void init_pp_chr_table()
\r
132 memset(pp_chr_table, PP_ERROR, 256);
\r
134 pp_chr_table[EOF_CHAR] = PP_EOF;
\r
136 for (x='A'; x<='Z'; x++) pp_chr_table[x] = PP_LETTER;
\r
137 for (x='a'; x<='z'; x++) pp_chr_table[x] = PP_LETTER;
\r
138 pp_chr_table['_'] = PP_LETTER;
\r
139 pp_chr_table['.'] = PP_LETTER;
\r
141 for (x='0'; x<='9'; x++) pp_chr_table[x] = PP_DIGIT;
\r
142 pp_chr_table['$'] = PP_DIGIT;
\r
143 pp_chr_table['\''] = PP_DIGIT;
\r
145 pp_chr_table['+'] = pp_chr_table['-'] = PP_PUNC;
\r
146 pp_chr_table['*'] = pp_chr_table['/'] = PP_PUNC;
\r
147 pp_chr_table['%'] = PP_PUNC;
\r
148 pp_chr_table['|'] = pp_chr_table['&'] = PP_PUNC;
\r
149 pp_chr_table['='] = pp_chr_table['^'] = PP_PUNC;
\r
150 pp_chr_table[','] = PP_PUNC;
\r
151 pp_chr_table['<'] = pp_chr_table['>'] = PP_PUNC;
\r
152 pp_chr_table['('] = pp_chr_table[')'] = PP_PUNC;
\r
153 pp_chr_table['['] = pp_chr_table[']'] = PP_PUNC;
\r
154 pp_chr_table['{'] = pp_chr_table['}'] = PP_PUNC;
\r
155 pp_chr_table[':'] = pp_chr_table[';'] = PP_PUNC;
\r
156 pp_chr_table['\\'] = pp_chr_table['!'] = PP_PUNC;
\r
158 pp_chr_table[' '] = pp_chr_table['\t'] = PP_WHITE;
\r
159 pp_chr_table['\r'] = PP_WHITE;
\r
161 pp_chr_table['\n'] = PP_NEWLINE;
\r
163 pp_chr_table['\"'] = PP_QUOTE;
\r
165 pp_chr_table['#'] = PP_DIRECTIVE;
\r
168 void pp_line_marker()
\r
170 if (pp_nomark) return;
\r
173 fwrite(&pp_line, 1, 4, pp_out);
\r
176 void pp_file_marker()
\r
178 if (pp_nomark) return;
\r
181 fwrite(cur_filename, 1, strlen(cur_filename)+1, pp_out);
\r
184 void pp_error(const char *error, ...)
\r
189 va_start (lst, error);
\r
190 vsprintf (string, error, lst);
\r
193 printf ("*preproc error* ");
\r
197 void pp_line_error(const char *error, ...)
\r
202 va_start (lst, error);
\r
203 vsprintf (string, error, lst);
\r
206 printf ("%s(%d) ", cur_filename, pp_line);
\r
210 int pp_is_punc(int c)
\r
211 { return (PP_PUNC == pp_chr_table[c]); }
\r
213 int pp_is_letter(int c)
\r
214 { return (PP_LETTER == pp_chr_table[c]); }
\r
216 int pp_is_digit(int c)
\r
217 { return (PP_DIGIT == pp_chr_table[c]); }
\r
219 int pp_is_ident(int c)
\r
220 { return (pp_is_letter(c) || pp_is_digit(c)); }
\r
222 int pp_is_white(int c)
\r
223 { return (PP_WHITE == pp_chr_table[c]); }
\r
225 int pp_is_directive(int c)
\r
226 { return (PP_DIRECTIVE == pp_chr_table[c]); }
\r
228 int pp_is_eof(int c)
\r
229 { return (PP_EOF == pp_chr_table[c]); }
\r
231 pp_def *pp_def_add(char *sym, char *resolve)
\r
236 if (!(pp_defs_allocated % PP_DEFS_BLOCK))
\r
238 pp_defs_allocated += PP_DEFS_BLOCK;
\r
240 p = (pp_def *)realloc(
\r
241 pp_defarr, pp_defs_allocated * sizeof(pp_def));
\r
242 if (!p) pp_error("unable to grow #define list");
\r
247 pp = &pp_defarr[pp_num_defs];
\r
250 pp->sym = (char *)malloc(strlen(sym) +1);
\r
252 pp_error("memory exhausted");
\r
253 strcpy(pp->sym, sym);
\r
254 pp->sym_len = strlen(sym);
\r
256 pp->resolve = (char *)malloc(strlen(resolve) +1);
\r
258 pp_error("memory exhausted");
\r
259 strcpy(pp->resolve, resolve);
\r
260 pp->resolve_len = strlen(resolve);
\r
265 pp_include *pp_include_add(char *filename)
\r
268 pp_include *pp = NULL;
\r
271 if (pp_num_includes)
\r
274 for (i=0; i<pp_num_includes; i++)
\r
276 if (!stricmp(pp_incarr[i].filename, pp_tok))
\r
277 pp_error("circular dependencies");
\r
282 pp = &pp_incarr[pp_num_includes++];
\r
284 in = fopen(filename, "rb");
\r
285 if (!in) pp_error("unable to open %s", filename);
\r
288 fseek(in, 0, SEEK_END);
\r
290 fseek(in, 0, SEEK_SET);
\r
293 pp->data = (char *)malloc((z +2) * sizeof(char));
\r
294 if (!pp->data) pp_error("memory exhausted");
\r
295 fread(pp->data, 1, z, in);
\r
298 pp->data[z++] = 32; // <aen, may 12>
\r
299 pp->data[z] = EOF_CHAR;
\r
301 pp->filename = (char *)malloc(strlen(filename) +1);
\r
302 if (!pp->filename) pp_error("memory exhausted");
\r
303 strcpy(pp->filename, filename);
\r
304 cur_filename=pp->filename;
\r
309 char *pp_skip_c_comment(char *p)
\r
312 while (*p && ('*' != *p || '/' != p[1]))
\r
319 if ('/' == *p && '*' == p[1])
\r
320 p = pp_skip_c_comment(p);
\r
328 char *pp_skip_cpp_comment(char *p)
\r
331 while (*p && '\n' != *p)
\r
344 char *pp_skipwhite(char *p)
\r
348 while (*p && PP_WHITE == pp_chr_table[(int) *p])
\r
365 case '/': p = pp_skip_cpp_comment(p); continue;
\r
366 case '*': p = pp_skip_c_comment(p); continue;
\r
376 char *pp_token_punc(char *p)
\r
382 } while (*p && pp_is_punc(*p));
\r
392 (c >= '0' && c <= '9')
\r
393 || (c >= 'A' && c <= 'F')
\r
394 || (c >= 'a' && c <= 'f'));
\r
398 char *pp_token_digit(char *p)
\r
405 if (!*p) return NULL;
\r
407 if (!*p) return NULL;
\r
409 if (!*p) return NULL;
\r
416 } while (*p && pp_is_digit(*p));
\r
423 char *pp_token_letter(char *p)
\r
429 } while (*p && pp_is_ident(*p));
\r
435 char *pp_token_directive(char *p)
\r
444 } while (pp_is_ident(*p));
\r
448 if (!strcmp(pp_tok, "include"))
\r
450 // boogly boogly boogly!
\r
454 //printf("#include detected \n");
\r
456 // any whitespace after 'include'
\r
457 p = pp_skipwhite(p);
\r
459 // skip, but don't expect, a "
\r
460 if ('\"' == *p) ++p;
\r
462 // grab the filename
\r
464 while (*p && '\"' != *p)
\r
466 // if we didn't hit eof...?
\r
469 // zero term filename
\r
474 last_filename=cur_filename; // <aen, may 14>
\r
475 l = pp_line; // save
\r
477 pp_line = l; // restore
\r
478 cur_filename=last_filename; // <aen, may 14>
\r
479 // reset file marker
\r
482 // disregard rest of line
\r
483 while (*p && '\n' != *p)
\r
485 // if we didn't hit eof...?
\r
488 // skip newline char
\r
495 // dump null token... writes nothing i think...
\r
498 //else pp_error("screw you!");
\r
502 else if (!strcmp(pp_tok, "define"))
\r
506 char resolve[1024];
\r
508 // find start of symbol
\r
509 while (' ' == *p || '\t' == *p)
\r
514 while (pp_is_ident(*p))
\r
518 // check for duplicate #defines
\r
522 int z = strlen(sym);
\r
523 for (i=0; i<pp_num_defs; i++)
\r
525 if (z == pp_defarr[i].sym_len)
\r
527 if (!stricmp(pp_defarr[i].sym, sym))
\r
528 pp_error("duplicate #define symbol");
\r
533 // find start of argument list (if any), or resolve
\r
534 while (' ' == *p || '\t' == *p)
\r
537 // found argument list; discard for now
\r
545 // find start of resolve
\r
546 while (' ' == *p || '\t' == *p)
\r
556 if (' ' == *p || '\t' == *p)
\r
560 } while (' ' == *p || '\t' == *p);
\r
563 // continuation? (multiple lines)
\r
567 while (*p && '\n' != *p)
\r
580 // special case for 'x' chars
\r
586 } while (*p && '\'' != *p);
\r
593 // special case for string literals
\r
598 } while (*p && '\"' != *p);
\r
606 // this is just the preprocessor, so i don't need
\r
607 // to get punctuation or digits in their correct form, i just
\r
608 // have to copy them over as i see them.
\r
609 if (pp_is_punc(*p) || pp_is_digit(*p))
\r
613 if ('\'' == *p || '\\' == *p)
\r
617 } while (pp_is_punc(*p) || pp_is_digit(*p));
\r
623 if (pp_is_letter(*p))
\r
625 if (!pp_last_delim)
\r
630 } while (pp_is_ident(*p));
\r
640 // update define list
\r
641 pp_def_add(sym, resolve);
\r
646 else pp_error("unknown preprocessor directive");
\r
651 char *pp_token_quote(char *p)
\r
657 while (*p && '\"' != *p)
\r
669 char *pp_token(char *p)
\r
671 p = pp_skipwhite(p);
\r
674 pp_tok[0] = '\0'; // gotta have this! (fixes last sym replication bug)
\r
678 pp_toktype = pp_chr_table[(int) *p];
\r
680 switch (pp_toktype)
\r
682 case PP_PUNC: p = pp_token_punc(p); break;
\r
683 case PP_DIGIT: p = pp_token_digit(p); break;
\r
684 case PP_LETTER: p = pp_token_letter(p); break;
\r
686 case PP_QUOTE: p = pp_token_quote(p); break;
\r
689 p = pp_token_directive(p);
\r
696 pp_line_error("unknown character <%c:%i>", *p, *p);
\r
702 void Process(char *filename)
\r
705 pp_include *ppi = NULL;
\r
707 // starts fresh for each #include file
\r
709 //pp_line_marker(); // hmm... did this kill the wat ver? i forget..
\r
712 ppi = pp_include_add(filename);
\r
720 // loop until we hit an EOF token
\r
721 while (*s && PP_EOF != pp_toktype)
\r
723 // for compactor; this is absolutely required for the parsing to
\r
724 // work correctly for hex numbers
\r
725 if (PP_LETTER == pp_toktype || PP_DIGIT == pp_toktype)
\r
727 if (!pp_last_delim)
\r
728 fputc(' ', pp_out);
\r
733 // #define replacement
\r
734 if (PP_LETTER == pp_toktype)
\r
736 pp_def *ppd = NULL;
\r
737 int pp_token_len = strlen(pp_tok);
\r
740 for (i=0; i<pp_num_defs; i++)
\r
742 ppd = pp_defarr + i;
\r
743 // first see if the lengths match, for possible quick discard
\r
744 if (ppd->sym_len == pp_token_len)
\r
746 // lengths match, compare bytes
\r
747 if (!stricmp(pp_tok, ppd->sym))
\r
749 // match! overwrite token with resolve
\r
750 memcpy(pp_tok, ppd->resolve, strlen(ppd->resolve)+1);
\r
758 // write whatever we got
\r
759 fwrite(pp_tok, 1, strlen(pp_tok), pp_out);
\r
761 pp_last_delim = (PP_LETTER != pp_toktype);
\r
767 free(ppi->filename);
\r
769 //pp_icur = &pp_incarr[pp_num_includes]; // oops! :-)
\r
771 pp_total_lines += pp_line;
\r
774 void pp_dump_output()
\r
778 sprintf(strx, "copy vcctemp.$$$ vcc%i.$$$", pp_tempct);
\r
784 void PreProcess(char *filename)
\r
786 pp_num_includes = 0;
\r
787 init_pp_chr_table();
\r
789 pp_out = fopen("VCCTEMP.$$$", "wb");
\r
790 if (!pp_out) pp_error("unable to open VCCTEMP.$$$");
\r
796 // dump preproc output?
\r