* tiny
[mascara-docs.git] / compilers / bcc / linux86-0.16.17 / cpp / cpp.c
blob616cf87dc678777d28d15276db0075767b77ded1
2 #include <stdio.h>
3 #include <string.h>
4 #ifdef __STDC__
5 #include <stdlib.h>
6 #else
7 #include <malloc.h>
8 #endif
9 #include "cc.h"
11 #define CPP_DEBUG 0 /* LOTS of junk to stderr. */
14 * This file comprises the 'guts' of a C preprocessor.
16 * Functions exported from this file:
17 * gettok() Returns the next token from the source
18 * curword contains the text of the token
20 * Variables
21 * curword Contains the text of the last token parsed.
22 * curfile Currently open primary file
23 * c_fname Name of file being parsed
24 * c_lineno Current line number in file being parsed.
26 * alltok Control flag for the kind of tokens you want (C or generic)
27 * dialect Control flag to change the preprocessor for Ansi C.
29 * TODO:
30 * #asm -> asm("...") translation.
31 * ?: in #if expressions
32 * Complete #line directive.
33 * \n in "\n" in a stringized argument.
34 * Comments in stringized arguments should be deleted.
36 * Poss: Seperate current directory for #include from errors (#line).
37 * (For editors that hunt down source files)
38 * Poss: C99 Variable macro args.
41 #define KEEP_SPACE 0
42 #define SKIP_SPACE 1
44 #define EOT 4
45 #define SYN 22
47 char curword[WORDSIZE];
48 int alltok = 0;
49 int dialect = 0;
51 FILE * curfile;
52 char * c_fname;
53 int c_lineno = 0;
55 #ifdef __BCC__
56 typedef long int_type; /* Used for preprocessor expressions */
57 #else
58 typedef int int_type; /* Used for preprocessor expressions */
59 #endif
60 static int curtok = 0; /* Used for preprocessor expressions */
62 static int fi_count = 0;
63 static FILE * saved_files[MAX_INCLUDE];
64 static char * saved_fname[MAX_INCLUDE];
65 static int saved_lines[MAX_INCLUDE];
67 static char * def_ptr = 0;
68 static char * def_start = 0;
69 static struct define_item * def_ref = 0;
71 static int def_count =0;
72 static char * saved_def[MAX_DEFINE];
73 static char * saved_start[MAX_DEFINE];
74 static long saved_unputc[MAX_DEFINE];
75 static struct define_item * saved_ref[MAX_DEFINE];
77 static long unputc = 0;
79 static int last_char = '\n';
80 static int in_preproc = 0;
81 static int dont_subst = 0;
82 static int quoted_str = 0;
84 static int if_count = 0;
85 static int if_false = 0;
86 static int if_has_else = 0;
87 static int if_hidden = 0;
88 static unsigned int if_stack = 0;
90 struct arg_store {
91 char * name;
92 char * value;
93 int in_define;
96 static int chget P((void));
97 static int chget_raw P((void));
98 static void unchget P((int));
99 static int gettok_nosub P((void));
100 static int get_onetok P((int));
101 static int pgetc P((void));
102 static int do_preproc P((void));
103 static int do_proc_copy_hashline P((void));
104 static int do_proc_if P((int));
105 static void do_proc_include P((void));
106 static void do_proc_define P((void));
107 static void do_proc_undef P((void));
108 static void do_proc_else P((void));
109 static void do_proc_endif P((void));
110 static void do_proc_tail P((void));
111 static int get_if_expression P((void));
112 static int_type get_expression P((int));
113 static int_type get_exp_value P((void));
114 static void gen_substrings P((char *, char *, int, int));
115 static char * insert_substrings P((char *, struct arg_store *, int));
118 gettok()
120 int ch;
122 for(;;)
124 /* Tokenised C-Preprocessing */
125 if (!quoted_str)
127 if (alltok)
128 ch = get_onetok(KEEP_SPACE);
129 else
130 ch = get_onetok(SKIP_SPACE);
132 if( ch == '"' || ch == '\'' )
133 quoted_str = ch;
135 if( ch == TK_WORD )
137 struct token_trans *p = is_ckey(curword, strlen(curword)) ;
138 if( p )
139 return p->token;
142 if (ch == '\n') continue;
143 return ch;
146 /* Special for quoted strings */
147 *curword = '\0';
148 ch = chget();
149 if( ch == EOF ) return ch;
151 *curword = ch;
152 curword[1] = '\0';
154 if( ch == quoted_str ) {
155 if( ch == '"' )
157 if (dialect == DI_ANSI) {
158 /* Found a terminator '"' check for ansi continuation */
159 while( (ch = pgetc()) <= ' ' && ch != EOF) ;
160 if( ch == '"' ) continue;
161 unchget(ch);
162 *curword = '"';
163 curword[1] = '\0';
166 quoted_str = 0;
167 return '"';
168 } else {
169 quoted_str = 0;
170 return ch;
173 if( ch == '\n' ) {
174 quoted_str = 0;
175 unchget(ch); /* Make sure error line is right */
176 return ch;
178 if( ch == '\\' ) {
179 unchget(ch);
180 ch = get_onetok(KEEP_SPACE);
181 return ch;
183 return TK_STR;
187 static int
188 gettok_nosub()
189 { int rv; dont_subst++; rv=get_onetok(SKIP_SPACE); dont_subst--; return rv; }
191 static int
192 get_onetok(keep)
193 int keep;
195 char * p;
196 int state;
197 int ch, cc;
199 Try_again:
200 *(p=curword) = '\0';
201 state=cc=ch=0;
203 /* First skip whitespace, if the arg says so then we need to keep it */
204 while( (ch = pgetc()) == ' ' || ch == '\t' )
206 if (keep == KEEP_SPACE) {
207 if( p < curword + WORDSIZE-1 ) {
208 *p++ = ch; /* Clip to WORDSIZE */
209 *p = '\0';
214 if( ch > 0xFF ) return ch;
215 if( p != curword ) { unchget(ch); return TK_WSPACE; }
216 if( ch == '\n') return ch;
217 if( ch == EOF ) return ch;
218 if( ch >= 0 && ch < ' ' ) goto Try_again;
220 for(;;)
222 switch(state)
224 case 0: if( (ch >= 'A' && ch <= 'Z')
225 || (ch >= 'a' && ch <= 'z')
226 || ch == '_' || ch == '$' )
227 state = 1;
228 else if(ch == '0')
229 state = 2;
230 else if(ch >= '1' && ch <= '9')
231 state = 5;
232 else
233 goto break_break;
234 break;
235 case 1: if( (ch >= '0' && ch <= '9')
236 || (ch >= 'A' && ch <= 'Z')
237 || (ch >= 'a' && ch <= 'z')
238 || ch == '_' || ch == '$' )
239 break;
240 else
241 goto break_break;
242 case 2: if( ch >= '0' && ch <= '7')
243 state = 3;
244 else if( ch == 'x' || ch == 'X' )
245 state = 4;
246 else
247 goto break_break;
248 break;
249 case 3: if( ch >= '0' && ch <= '7')
250 break;
251 else
252 goto break_break;
253 case 4: if( (ch >= '0' && ch <= '9')
254 || (ch >= 'A' && ch <= 'F')
255 || (ch >= 'a' && ch <= 'f') )
256 break;
257 else
258 goto break_break;
259 case 5:
260 case 6: if( ch >= '0' && ch <= '9')
262 else if( ch == '.' && state != 6 )
263 state = 6;
264 else if( ch == 'e' || ch == 'E' )
265 state = 7;
266 else
267 goto break_break;
268 break;
269 case 7: if( ch == '+' || ch == '-' )
270 break;
271 state = 8;
272 /* FALLTHROUGH */
273 case 8: if( ch >= '0' && ch <= '9')
274 break;
275 else
276 goto break_break;
278 if( cc < WORDSIZE-1 ) *p++ = ch; /* Clip to WORDSIZE */
279 *p = '\0'; cc++;
280 ch = chget();
281 if (ch == SYN) ch = chget();
283 break_break:
284 /* Numbers */
285 if( state >= 2 )
287 if( state < 6 )
289 if( ch == 'u' || ch == 'U' )
291 if( cc < WORDSIZE-1 ) *p++ = ch; /* Clip to WORDSIZE */
292 *p = '\0'; cc++;
293 ch = chget();
295 if( ch == 'l' || ch == 'L' )
297 if( cc < WORDSIZE-1 ) *p++ = ch; /* Clip to WORDSIZE */
298 *p = '\0'; cc++;
300 else unchget(ch);
301 return TK_NUM;
303 unchget(ch);
304 return TK_FLT;
307 /* Words */
308 if( state == 1 )
310 struct define_item * ptr;
311 unchget(ch);
312 if( !dont_subst
313 && (ptr = read_entry(0, curword)) != 0
314 && !ptr->in_use
317 if ( def_count >= MAX_DEFINE ) {
318 cwarn("Preprocessor recursion overflow");
319 return TK_WORD;
320 } else if( ptr->arg_count >= 0 )
322 /* An open bracket must follow the word */
323 int ch1 = 0;
324 while ((ch = chget()) == ' ' || ch == '\t' ) ch1 = ch;
325 if (ch != '(') {
326 unchget(ch);
327 if (ch1) unchget(ch1);
328 return TK_WORD;
331 /* We have arguments to process so lets do so. */
332 gen_substrings(ptr->name, ptr->value, ptr->arg_count, ptr->varargs);
334 /* Don't mark macros with arguments as in use, it's very
335 * difficult to say what the correct result would be so
336 * I'm letting the error happen. Also if I do block
337 * recursion then it'll also block 'pseudo' recursion
338 * where the arguments have a call to this macro.
340 def_ref = ptr;
341 ptr->in_use = 1;
344 else if (ptr->value[0])
346 /* Simple direct substitution; note the shortcut (above) for
347 * macros that are defined as null */
348 saved_ref[def_count] = def_ref;
349 saved_def[def_count] = def_ptr;
350 saved_start[def_count] = def_start;
351 saved_unputc[def_count] = unputc;
352 def_count++;
353 unputc = 0;
354 def_ref = ptr;
355 def_ptr = ptr->value;
356 def_start = 0;
357 ptr->in_use = 1;
359 goto Try_again;
361 return TK_WORD;
364 /* Quoted char for preprocessor expressions */
365 if(in_preproc && ch == '\'' )
367 *p++ = ch; ch = chget();
368 for(;;)
370 if( cc < WORDSIZE-1 ) *p++ = ch; /* Clip to WORDSIZE */
371 *p = '\0'; cc++;
372 if( ch == '\'' || ch == '\n' ) break;
374 if( ch == '\\' )
376 ch = chget();
377 if( cc < WORDSIZE-1 ) *p++ = ch; /* Clip to WORDSIZE */
378 *p = '\0'; cc++;
380 ch = chget();
382 ch = TK_QUOT;
385 /* Collect and translate \xyx strings, (should probably translate these
386 * all to some standard form (eg \ooo plus \N )
388 * ___________________________________________________________________
389 * | new-line NL (LF) \n| audible alert BEL \a |
390 * | horizontal tab HT \t| question mark ? \? |
391 * | vertical tab VT \v| double quote " \" |
392 * | backspace BS \b| octal escape ooo \ooo|
393 * | carriage return CR \r| hexadecimal escape hh \xhh|
394 * | formfeed FF \f| backslash \ \\ |
395 * | single quote ' \'| |
396 * |_______________________________|_________________________________|
399 if( ch == '\\' )
401 int i;
403 *p++ = ch; ch = chget();
404 if (ch >= '0' && ch <= '7' ) {
405 for(i=0; i<3; i++) {
406 if (ch >= '0' && ch <= '7' ) {
407 *p++ = ch; ch = chget();
410 unchget(ch);
411 } else if (ch == 'x' || ch == 'X') {
412 *p++ = ch; ch = chget();
413 for(i=0; i<2; i++) {
414 if ( (ch >= '0' && ch <= '9' ) ||
415 (ch >= 'A' && ch <= 'F' ) ||
416 (ch >= 'a' && ch <= 'f' ) ) {
417 *p++ = ch; ch = chget();
420 unchget(ch);
421 } else if (ch == '?') {
422 p[-1] = '?';
423 } else if (ch != '\n' && ch != EOF) {
424 *p++ = ch;
425 } else
426 unchget(ch);
427 *p = '\0';
428 return TK_STR;
431 /* Possible composite tokens */
432 if( ch > ' ' && ch <= '~' )
434 struct token_trans *p;
435 *curword = cc = ch;
437 for(state=1; ; state++)
439 curword[state] = ch = chget();
440 if( !(p=is_ctok(curword, state+1)) )
442 unchget(ch);
443 curword[state] = '\0';
444 return cc;
446 cc=p->token;
449 return ch;
452 static int
453 pgetc()
455 int ch, ch1;
457 for(;;)
459 if ((ch = chget()) == EOF) return ch;
461 if( !in_preproc && last_char == '\n' && ch == '#' )
463 in_preproc = 1;
464 ch = do_preproc();
465 in_preproc = 0;
466 if(if_false || ch == 0) continue;
468 last_char = '\n';
469 return ch;
471 if( last_char != '\n' || (ch != ' ' && ch != '\t') )
472 last_char = ch;
474 /* Remove comments ... */
475 if( ch != '/' )
476 { if(if_false && !in_preproc) continue; return ch; }
477 ch1 = chget(); /* Allow "/\\\n*" as comment start too!? */
479 if( ch1 == '/' ) /* Double slash style comments */
481 do { ch = chget(); } while(ch != '\n' && ch != EOF);
482 return ch; /* Keep the return. */
485 if( ch1 != '*' )
487 unchget(ch1);
488 if(if_false && !in_preproc) continue;
489 return ch;
492 for(;;)
494 if( ch == '*' )
496 ch = chget();
497 if( ch == EOF ) return EOF;
498 if( ch == '/' ) break;
500 else ch = chget();
502 if (dialect == DI_ANSI)
503 return ' '; /* If comments become " " */
504 else return SYN; /* Comments become nulls, but we need a
505 * marker so I can do token concat properly. */
509 /* This function handles the first and second translation phases of Ansi-C */
510 static int
511 chget()
513 int ch, ch1;
514 for(;;) {
515 ch = chget_raw();
516 if (ch == '\\') {
517 ch1 = chget_raw();
518 if (ch1 == '\n') continue;
519 unchget(ch1);
522 /* Ansi trigraphs -- Ewww, it needs lots of 'unchget' space too. */
523 if (dialect == DI_ANSI && ch == '?') {
524 ch1 = chget_raw();
525 if (ch1 != '?')
526 unchget(ch1);
527 else {
528 static char trig1[] = "()<>/!'-=";
529 static char trig2[] = "[]{}\\|^~#";
530 char * s;
531 ch1 = chget_raw();
532 s = strchr(trig1, ch1);
533 if (s) {
534 unchget(trig2[s-trig1]); /* Unchget so that ??/ can be used as */
535 continue; /* a real backslash at EOL. */
536 } else {
537 unchget(ch1);
538 unchget('?');
543 return ch;
547 static void
548 unchget(ch)
550 #if CPP_DEBUG
551 fprintf(stderr, "\b", ch);
552 #endif
553 if(ch == 0) return; /* Hummm */
554 if(ch == EOF) ch=EOT; /* EOF is pushed back as a normal character. */
555 ch &= 0xFF;
557 if(unputc&0xFF000000)
558 cerror("Internal character pushback stack overflow");
559 else unputc = (unputc<<8) + (ch);
560 if( ch == '\n' ) c_lineno--;
563 static int
564 chget_raw()
565 #if CPP_DEBUG
567 int ch;
568 static int last_def = 0;
569 static int last_fi = 0;
570 if (last_fi != fi_count) fprintf(stderr, "<INC%d>", fi_count);
571 if (last_def != def_count) fprintf(stderr, "<DEF%d>", def_count);
572 last_def = def_count; last_fi = fi_count;
574 ch = realchget();
575 if (ch == EOF) fprintf(stderr, "<EOF>"); else fprintf(stderr, "%c", ch);
577 if (last_def != def_count) fprintf(stderr, "<DEF%d>", def_count);
578 if (last_fi != fi_count) fprintf(stderr, "<INC%d>", fi_count);
579 last_def = def_count; last_fi = fi_count;
581 return ch;
584 static int
585 realchget()
586 #endif
588 int ch;
589 for(;;)
591 if( unputc )
593 if((unputc&0xFF)==EOT && in_preproc) return '\n';
594 ch=(unputc&0xFF); unputc>>=8;
595 if( ch == EOT ) ch = EOF;
596 if( ch == '\n' ) c_lineno++;
597 return ch;
600 if( def_ptr )
602 ch = *def_ptr++; if(ch) return (unsigned char)ch;
603 if( def_start ) free(def_start);
604 if( def_ref ) def_ref->in_use = 0;
606 def_count--;
607 def_ref = saved_ref[def_count];
608 def_ptr = saved_def[def_count];
609 def_start = saved_start[def_count];
610 unputc = saved_unputc[def_count];
611 continue;
614 ch = getc(curfile);
615 if( ch == EOF && fi_count != 0)
617 fclose(curfile);
618 fi_count--;
619 curfile = saved_files[fi_count];
620 if(c_fname) free(c_fname);
621 c_fname = saved_fname[fi_count];
622 c_lineno = saved_lines[fi_count];
623 ch = '\n'; /* Ensure end of line on end of file */
625 else if( ch == '\n' ) c_lineno++;
627 /* Treat all control characters, except the standard whitespace
628 * characters of TAB and NL as completely invisible.
630 if( ch >= 0 && ch < ' ' && ch!='\n' && ch!='\t' && ch!=EOF ) continue;
632 if( ch == EOF ) { unchget(ch); return '\n'; } /* Ensure EOL before EOF */
633 return (unsigned char)ch;
637 static int
638 do_preproc()
640 int val, no_match=0;
642 if( (val=get_onetok(SKIP_SPACE)) == TK_WORD )
644 if( strcmp(curword, "ifdef") == 0 )
645 do_proc_if(0);
646 else if( strcmp(curword, "ifndef") == 0 )
647 do_proc_if(1);
648 else if( strcmp(curword, "if") == 0 )
649 do_proc_if(2);
650 else if( strcmp(curword, "elif") == 0 )
651 do_proc_if(3);
652 else if( strcmp(curword, "else") == 0 )
653 do_proc_else();
654 else if( strcmp(curword, "endif") == 0 )
655 do_proc_endif();
656 else if(if_false)
657 no_match=1;
658 else
660 if( strcmp(curword, "include") == 0 )
661 do_proc_include();
662 else if( strcmp(curword, "define") == 0 )
663 do_proc_define();
664 else if( strcmp(curword, "undef") == 0 )
665 do_proc_undef();
666 else if( strcmp(curword, "error") == 0 ) {
667 strcpy(curword, "#error");
668 do_proc_copy_hashline(); pgetc();
669 cerror(curword);
670 } else if( strcmp(curword, "warning") == 0 ) {
671 strcpy(curword, "#warning");
672 do_proc_copy_hashline(); pgetc();
673 cwarn(curword);
674 } else if( strcmp(curword, "pragma") == 0 ) {
675 do_proc_copy_hashline(); pgetc();
676 /* Ignore #pragma ? */
677 } else if( strcmp(curword, "line") == 0 ) {
678 do_proc_copy_hashline(); pgetc();
679 /* Ignore #line for now. */
680 } else if( strcmp(curword, "asm") == 0 ) {
681 alltok |= 0x100;
682 return do_proc_copy_hashline();
683 } else if( strcmp(curword, "endasm") == 0 ) {
684 alltok &= ~0x100;
685 return do_proc_copy_hashline();
686 } else
687 no_match=1;
690 else no_match=1;
692 if( no_match )
694 if(!if_false) cerror("Unknown preprocessor directive");
695 while( val != '\n' ) val = pgetc();
698 *curword = 0; /* Just in case */
699 return 0;
702 static int
703 do_proc_copy_hashline()
705 int off, ch;
707 off = strlen(curword);
709 while( (ch=pgetc()) != '\n' )
711 if( off < WORDSIZE ) curword[off++] = ch;
713 if( off == WORDSIZE )
715 cerror("Preprocessor directive too long");
716 curword[WORDSIZE-1] = '\0';
718 else
719 curword[off] = '\0';
721 unchget('\n');
722 return TK_COPY;
725 static void
726 do_proc_include()
728 int ch, ch1;
729 char * p;
730 FILE * fd;
732 ch = get_onetok(SKIP_SPACE);
733 if( ch == '<' || ch == '"' )
735 if( ch == '"' ) ch1 = ch; else ch1 = '>';
736 p = curword;
737 while(p< curword+WORDSIZE-1)
739 ch = pgetc();
740 if( ch == '\n' ) break;
741 if( ch == ch1 )
743 *p = '\0';
744 p = strdup(curword);
746 do { ch1 = pgetc(); } while(ch1 == ' ' || ch1 == '\t');
747 unchget(ch1);
748 do_proc_tail();
750 saved_files[fi_count] = curfile;
751 saved_fname[fi_count] = c_fname;
752 saved_lines[fi_count] = c_lineno;
754 fd = open_include(p, "r", (ch=='"'));
755 if( fd ) {
756 fi_count++;
757 curfile = fd;
758 } else
759 cerror("Cannot open include file");
761 return;
763 *p++ = ch;
766 cerror("Bad #include command");
767 while(ch != '\n') ch = pgetc();
768 return;
771 static void
772 do_proc_define()
774 int ch, ch1;
775 struct define_item * ptr, * old_value = 0;
776 int cc, len;
777 char name[WORDSIZE];
779 if( (ch=gettok_nosub()) == TK_WORD )
781 strcpy(name, curword);
782 ptr = read_entry(0, name);
783 if(ptr)
785 set_entry(0, name, (void*)0); /* Unset var */
786 if (ptr->in_use)
787 /* Eeeek! This shouldn't happen; so just let it leak. */
788 cwarn("macro redefined while it was in use!?");
789 else
790 old_value = ptr;
793 /* Skip blanks */
794 for(ch=ch1=pgetc(); ch == ' ' || ch == '\t' ; ch=pgetc()) ;
796 len = WORDSIZE;
797 ptr = malloc(sizeof(struct define_item) + WORDSIZE);
798 if(ptr==0) cfatal("Preprocessor out of memory");
799 ptr->value[cc=0] = '\0';
801 /* Add in arguments */
802 if( ch1 == '(' )
804 ptr->arg_count=0;
805 for(;;)
807 ch=gettok_nosub();
808 if( ptr->arg_count==0 && ch == ')' ) break;
809 if( ch == TK_WORD )
811 if( cc+strlen(curword)+4 >= len)
813 len = cc + WORDSIZE;
814 ptr = (struct define_item *) realloc(ptr, sizeof(struct define_item) + len);
815 if(ptr==0) cfatal("Preprocessor out of memory");
817 if( cc+strlen(curword) < len)
819 strcpy(ptr->value+cc, curword);
820 cc+=strlen(curword);
821 strcpy(ptr->value+cc, ",");
822 cc++;
823 ptr->arg_count++;
824 ch=gettok_nosub();
825 if( ch == TK_ELLIPSIS ) {
826 ptr->varargs = 1;
827 ch=gettok_nosub();
828 if (ch == ',') ch = '*'; /* Force error if not ')' */
830 if( ch == ')' ) break;
831 if( ch == ',' ) continue;
834 cerror("Bad #define command");
835 free(ptr);
836 while(ch != '\n') ch = pgetc();
837 set_entry(0, name, (void*)old_value); /* Return var to old. */
838 return;
840 while((ch=pgetc())==' ' || ch=='\t');
842 else ptr->arg_count = -1;
844 /* And the substitution string */
845 while(ch != '\n')
847 if( cc+4 > len )
849 len = cc + WORDSIZE;
850 ptr = (struct define_item *) realloc(ptr, sizeof(struct define_item) + len);
851 if(ptr==0) cfatal("Preprocessor out of memory");
853 ptr->value[cc++] = ch;
854 ch = pgetc();
856 if (cc)
857 ptr->value[cc++] = ' ';/* Byte of lookahead for recursive macros */
858 ptr->value[cc++] = '\0';
860 #if CPP_DEBUG
861 if (cc == 1)
862 fprintf(stderr, "\n### Define '%s' as null\n", name);
863 else if (ptr->arg_count<0)
864 fprintf(stderr, "\n### Define '%s' as '%s'\n",
865 name, ptr->value);
866 else
867 fprintf(stderr, "\n### Define '%s' as %d args '%s'\n",
868 name, ptr->arg_count, ptr->value);
869 #endif
871 /* Clip to correct size and save */
872 ptr = (struct define_item *) realloc(ptr, sizeof(struct define_item) + cc);
873 ptr->name = set_entry(0, name, ptr);
874 ptr->in_use = 0;
875 ptr->next = 0;
877 if (old_value) {
878 if (strcmp(old_value->value, ptr->value) != 0)
879 cwarn("#define redefined macro");
880 free(old_value);
883 else cerror("Bad #define command");
884 while(ch != '\n') ch = pgetc();
887 static void
888 do_proc_undef()
890 int ch;
891 struct define_item * ptr;
892 if( (ch=gettok_nosub()) == TK_WORD )
894 ptr = read_entry(0, curword);
895 if(ptr)
897 set_entry(0, curword, (void*)0); /* Unset var */
898 if (ptr->in_use)
899 /* Eeeek! This shouldn't happen; so just let it leak. */
900 cwarn("macro undefined while it was in use!?");
901 else
902 free(ptr);
904 do_proc_tail();
906 else
908 cerror("Bad #undef command");
909 while(ch != '\n') ch = pgetc();
913 static int
914 do_proc_if(type)
915 int type;
917 int ch = 0;
918 if(if_false && if_hidden)
920 if( type != 3 ) if_hidden++;
921 do_proc_tail();
922 return 0;
925 if( type == 3 )
927 if( if_count == 0 )
928 cerror("#elif without matching #if");
929 else
931 if( if_has_else )
932 cerror("#elif following #else for one #if");
933 if( if_has_else || if_false != 1 )
935 if_false=2;
936 while(ch != '\n') ch = pgetc();
937 return 0;
939 if_false=0;
941 if_has_else = 0;
943 if(if_false)
945 if( type != 3 ) if_hidden++;
946 do_proc_tail();
948 else
950 if( type != 3 )
952 if_count++;
953 if_stack <<= 1;
954 if_stack |= if_has_else;
955 if_has_else = 0;
957 if(type > 1)
959 ch = get_if_expression();
960 if_false=!ch;
962 else
964 ch = gettok_nosub();
965 if( ch == TK_WORD )
967 do_proc_tail();
968 if_false = (read_entry(0, curword) == 0);
969 if(type == 1) if_false = !if_false;
971 else
973 cerror("Bad #if command");
974 if_false = 0;
975 while(ch != '\n') ch = pgetc();
979 return 0;
982 static void
983 do_proc_else()
985 if( if_hidden == 0 )
987 if( if_count == 0 )
988 cerror("#else without matching #if");
989 else
990 if_false = (if_false^1);
991 if( if_has_else )
992 cerror("Multiple #else's for one #if");
993 if_has_else = 1;
995 do_proc_tail();
998 static void
999 do_proc_endif()
1001 if( if_hidden )
1002 if_hidden--;
1003 else
1005 if( if_count == 0 )
1006 cerror("Unmatched #endif");
1007 else
1009 if_count--;
1010 if_false=0;
1011 if_has_else = (if_stack&1);
1012 if_stack >>=1;
1015 do_proc_tail();
1018 static void
1019 do_proc_tail()
1021 int ch, flg=1;
1022 while((ch = pgetc()) != '\n') if(ch > ' ')
1024 if (!if_false && flg)
1025 cwarn("Unexpected text following preprocessor command");
1026 flg=0;
1030 static int
1031 get_if_expression()
1033 int value = get_expression(0);
1035 if (curtok != '\n')
1036 do_proc_tail();
1038 return value;
1041 static int_type
1042 get_expression(prio)
1043 int prio;
1045 int_type lvalue;
1046 int_type rvalue;
1047 int no_op = 0;
1049 curtok = get_onetok(SKIP_SPACE);
1050 lvalue = get_exp_value();
1054 switch(curtok)
1056 case '*': case '/': case '%':
1057 if (prio >= 10) return lvalue;
1058 break;
1059 case '+': case '-':
1060 if (prio >= 9) return lvalue;
1061 break;
1062 case TK_RIGHT_OP: case TK_LEFT_OP:
1063 if (prio >= 8) return lvalue;
1064 break;
1065 case '<': case '>': case TK_LE_OP: case TK_GE_OP:
1066 if (prio >= 7) return lvalue;
1067 break;
1068 case TK_EQ_OP: case TK_NE_OP:
1069 if (prio >= 6) return lvalue;
1070 break;
1071 case '&':
1072 if (prio >= 5) return lvalue;
1073 break;
1074 case '^':
1075 if (prio >= 4) return lvalue;
1076 break;
1077 case '|':
1078 if (prio >= 3) return lvalue;
1079 break;
1080 case TK_AND_OP:
1081 if (prio >= 2) return lvalue;
1082 break;
1083 case TK_OR_OP:
1084 if (prio >= 1) return lvalue;
1085 break;
1087 switch(curtok)
1089 case '*':
1090 rvalue = get_expression(10);
1091 lvalue *= rvalue;
1092 break;
1093 case '/':
1094 rvalue = get_expression(10);
1095 if (rvalue)
1096 lvalue /= rvalue;
1097 break;
1098 case '%':
1099 rvalue = get_expression(10);
1100 if (rvalue)
1101 lvalue %= rvalue;
1102 break;
1103 case '+':
1104 rvalue = get_expression(9);
1105 lvalue += rvalue;
1106 break;
1107 case '-':
1108 rvalue = get_expression(9);
1109 lvalue -= rvalue;
1110 break;
1111 case TK_RIGHT_OP:
1112 rvalue = get_expression(8);
1113 lvalue >>= rvalue;
1114 break;
1115 case TK_LEFT_OP:
1116 rvalue = get_expression(8);
1117 lvalue <<= rvalue;
1118 break;
1119 case '<':
1120 rvalue = get_expression(7);
1121 lvalue = (lvalue < rvalue);
1122 break;
1123 case '>':
1124 rvalue = get_expression(7);
1125 lvalue = (lvalue > rvalue);
1126 break;
1127 case TK_LE_OP:
1128 rvalue = get_expression(7);
1129 lvalue = (lvalue <= rvalue);
1130 break;
1131 case TK_GE_OP:
1132 rvalue = get_expression(7);
1133 lvalue = (lvalue >= rvalue);
1134 break;
1135 case TK_EQ_OP:
1136 rvalue = get_expression(6);
1137 lvalue = (lvalue == rvalue);
1138 break;
1139 case TK_NE_OP:
1140 rvalue = get_expression(6);
1141 lvalue = (lvalue != rvalue);
1142 break;
1143 case '&':
1144 rvalue = get_expression(5);
1145 lvalue = (lvalue & rvalue);
1146 break;
1147 case '^':
1148 rvalue = get_expression(4);
1149 lvalue = (lvalue ^ rvalue);
1150 break;
1151 case '|':
1152 rvalue = get_expression(3);
1153 lvalue = (lvalue | rvalue);
1154 break;
1155 case TK_AND_OP:
1156 rvalue = get_expression(2);
1157 lvalue = (lvalue && rvalue);
1158 break;
1159 case TK_OR_OP:
1160 rvalue = get_expression(1);
1161 lvalue = (lvalue || rvalue);
1162 break;
1164 case '?': /* XXX: To add */
1166 default:
1167 no_op = 1;
1170 while(prio == 0 && !no_op);
1172 return lvalue;
1175 static int_type
1176 get_exp_value()
1178 int_type value = 0;
1179 int sign = 1;
1181 if (curtok == '!') {
1182 curtok = get_onetok(SKIP_SPACE);
1183 return !get_exp_value();
1185 if (curtok == '~') {
1186 curtok = get_onetok(SKIP_SPACE);
1187 return ~get_exp_value();
1190 while (curtok == '+' || curtok == '-') {
1191 if (curtok == '-') sign = -sign;
1192 curtok = get_onetok(SKIP_SPACE);
1195 if (curtok == TK_NUM) {
1196 value = strtoul(curword, (void*)0, 0);
1197 curtok = get_onetok(SKIP_SPACE);
1198 } else if (curtok == TK_QUOT) {
1199 value = curword[1];
1200 if (value == '\\') {
1201 if (curword[2] >= '0' && curword[2] <= '7') {
1202 value = curword[2] - '0';
1203 if (curword[3] >= '0' && curword[3] <= '7') {
1204 value = (value<<3) + curword[3] - '0';
1205 if (curword[4] >= '0' && curword[4] <= '7') {
1206 value = (value<<3) + curword[4] - '0';
1209 } else switch(curword[2]) {
1210 case 'n': value = '\n'; break;
1211 case 'f': value = '\f'; break;
1212 case 't': value = '\t'; break;
1213 default: value = curword[2]; break;
1216 #ifdef NATIVE_CPP
1217 value = (char) value; /* Fix range */
1218 #elif SIGNED_CHAR
1219 value = (signed char) value;
1220 #else
1221 value = (unsigned char) value;
1222 #endif
1223 curtok = get_onetok(SKIP_SPACE);
1224 } else if (curtok == TK_WORD) {
1225 value = 0;
1226 if (strcmp("defined", curword) == 0) {
1227 curtok = gettok_nosub();
1228 if (curtok == '(' && gettok_nosub() != TK_WORD)
1229 cerror("'defined' keyword requires argument");
1230 else {
1231 value = (read_entry(0, curword) != 0);
1232 if (curtok == '(' && gettok_nosub() != ')')
1233 cerror("'defined' keyword requires closing ')'");
1234 else
1235 curtok = get_onetok(SKIP_SPACE);
1238 else
1239 curtok = get_onetok(SKIP_SPACE);
1241 } else if (curtok == '(') {
1242 value = get_expression(0);
1243 if (curtok == ')')
1244 curtok = get_onetok(SKIP_SPACE);
1245 else {
1246 curtok = '$';
1247 cerror("Expected ')'");
1251 return sign<0 ? -value: value;
1254 void
1255 gen_substrings(macname, data_str, arg_count, is_vararg)
1256 char * macname;
1257 char * data_str;
1258 int arg_count;
1259 int is_vararg;
1261 char * mac_text = 0;
1262 struct arg_store *arg_list;
1263 int ac, ch, cc, len;
1265 int paren_count = 0;
1266 int in_quote = 0;
1267 int quote_char = 0;
1268 int commas_found = 0;
1269 int args_found = 0;
1271 arg_list = malloc(sizeof(struct arg_store) * arg_count);
1272 memset(arg_list, 0, sizeof(struct arg_store) * arg_count);
1274 for(ac=0; *data_str && ac < arg_count; data_str++) {
1275 if( *data_str == ',' ) { ac++; continue; }
1277 if (arg_list[ac].name == 0) cc = len = 0;
1279 if (cc+2 >= len) {
1280 len += 20;
1281 arg_list[ac].name = realloc(arg_list[ac].name, len);
1283 arg_list[ac].name[cc++] = *data_str;
1284 arg_list[ac].name[cc] = '\0';
1287 for(;;) {
1288 if ((ch = chget()) == EOF) break;
1289 if(in_quote == 2) {
1290 in_quote = 1;
1291 } else if (in_quote) {
1292 if ( ch == quote_char ) in_quote = 0;
1293 if ( ch == '\\') in_quote = 2;
1294 } else {
1295 if ( ch == '(' ) paren_count++;
1296 if ( ch == '"' || ch == '\'' ) { in_quote = 1; quote_char = ch; }
1297 if (paren_count == 0 && ch == ',' ) {
1298 commas_found++;
1299 if (commas_found < arg_count)
1300 continue;
1302 if ( ch == ')' ) {
1303 if (paren_count == 0) break;
1304 paren_count--;
1307 args_found = 1;
1308 /* Too many args, deal with, or ignore, the rest. */
1309 if (commas_found >= arg_count) {
1310 if(arg_count == 0) continue;
1311 ac = arg_count-1;
1312 } else
1313 ac = commas_found;
1315 if (arg_list[ac].value == 0) {
1316 cc = len = 0;
1317 arg_list[ac].in_define = def_count;
1320 if (cc+2 >= len) {
1321 len += 20;
1322 arg_list[ac].value = realloc(arg_list[ac].value, len);
1325 #if 0
1326 if (ch == '\n' && cc>0 && arg_list[ac].value[cc-1] == '\n' ) {
1327 ... ?
1329 #endif
1331 arg_list[ac].value[cc++] = ch;
1332 arg_list[ac].value[cc] = '\0';
1335 if (commas_found || args_found) args_found = commas_found+1;
1337 if( arg_count == 0 && args_found != 0 )
1338 cerror("Arguments given to macro without them.");
1339 else if( !is_vararg && arg_count != args_found )
1340 cwarn("Incorrect number of macro arguments");
1342 mac_text = insert_substrings(data_str, arg_list, arg_count);
1345 * At this point 'mac_text' contains the full expansion of the macro.
1347 * So we could scan this for calls to this macro and if we find one
1348 * that _exactly_ matches this call (including arguments) then we mark
1349 * this call's in_use flag.
1351 * OTOH, it would probably be best to throw away this expansion and
1352 * pretend we never noticed this macro expansion in the first place.
1354 * Still this is mostly academic as the error trapping works and
1355 * recursive macros _with_arguments_ are both rare and unpredictable.
1358 if (arg_list) {
1359 for (ac=0; ac<arg_count; ac++) {
1360 if (arg_list[ac].name) free(arg_list[ac].name);
1361 if (arg_list[ac].value) free(arg_list[ac].value);
1363 free(arg_list);
1366 saved_ref[def_count] = def_ref;
1367 saved_def[def_count] = def_ptr;
1368 saved_start[def_count] = def_start;
1369 saved_unputc[def_count] = unputc;
1370 def_count++;
1371 unputc = 0;
1372 def_ptr = mac_text;
1373 def_start = mac_text;
1374 def_ref = 0;
1375 #if CPP_DEBUG
1376 fprintf(stderr, "\n### <DEF%d='%s'>\n", def_count, mac_text);
1377 #endif
1380 static char *
1381 insert_substrings(data_str, arg_list, arg_count)
1382 char * data_str;
1383 struct arg_store *arg_list;
1384 int arg_count;
1386 int ac, ch;
1387 char * p, * s;
1388 char * rv = 0;
1389 int len = 0;
1390 int cc = 0;
1391 int in_quote = 0;
1392 int quote_char = 0;
1393 int ansi_stringize = 0;
1395 #if CPP_DEBUG
1396 fprintf(stderr, "\n### Macro substitution in '%s'\n", data_str);
1397 for (ac=0; ac<arg_count; ac++) {
1398 fprintf(stderr, "### Argument %d (%s) = '%s'\n",
1399 ac+1, arg_list[ac].name, arg_list[ac].value);
1401 #endif
1403 rv = malloc(4); *rv = '\0'; len = 4;
1405 while(*data_str) {
1406 p = curword;
1408 if (dialect == DI_ANSI) {
1409 if (in_quote == 2)
1410 in_quote = 1;
1411 else if (in_quote) {
1412 if (*data_str == quote_char) in_quote = 0;
1413 if (*data_str == '\\') in_quote = 2;
1414 } else {
1415 if (*data_str == '"' || *data_str == '\'')
1416 { in_quote = 1; quote_char = *data_str; }
1420 if (!in_quote) for(;;) {
1421 ch = *data_str;
1422 if( (ch >= '0' && ch <= '9')
1423 || (ch >= 'A' && ch <= 'Z')
1424 || (ch >= 'a' && ch <= 'z')
1425 || ch == '_' || ch == '$' )
1426 *p++ = *data_str++;
1427 else
1428 break;
1431 if (p == curword) {
1432 /* Ansi Stringize and concat */
1433 if (*data_str == '#' && dialect != DI_KNR) {
1434 if (data_str[1] == '#') {
1435 while(cc>0 && (rv[cc-1] == ' ' || rv[cc-1] == '\t'))
1436 cc--;
1437 data_str+=2;
1438 while(*data_str == ' ' || *data_str == '\t')
1439 data_str++;
1440 if (*data_str == '\0') { /* Hummm */
1441 data_str--;
1442 cerror("'##' operator at end of macro");
1444 continue;
1446 data_str++;
1447 ansi_stringize = 1;
1448 continue;
1451 if (ansi_stringize) {
1452 ansi_stringize = 0;
1453 cerror("'#' operator should be followed by a macro argument name");
1456 /* Other characters ... */
1457 if (cc+2 > len) { len += 20; rv = realloc(rv, len); }
1458 rv[cc++] = *data_str++;
1459 continue;
1461 *p = '\0'; s = curword;
1462 for (ac=0; ac<arg_count; ac++) {
1463 if (*curword == arg_list[ac].name[0] &&
1464 strcmp(curword, arg_list[ac].name) == 0)
1466 s = arg_list[ac].value;
1467 if (!s) s = ""; else
1469 /* Ansi stringize operation, this is very messy! */
1470 if (ansi_stringize) {
1471 if (arg_list[ac].in_define) {
1472 struct define_item * ptr;
1473 if ((ptr = read_entry(0, s)) &&
1474 ptr->arg_count == -1) {
1475 s = ptr->value;
1479 rv[cc++] = '"';
1480 while(*s == ' ' || *s == '\t') s++;
1481 while (*s) {
1482 if (cc+4 > len) { len += 20; rv = realloc(rv, len); }
1483 if (*s == '"') rv[cc++] = '\\';
1484 rv[cc++] = *s++;
1486 while(cc>0 && (rv[cc-1] == ' ' || rv[cc-1] == '\t'))
1487 cc--;
1488 rv[cc++] = '"';
1489 rv[cc++] = '\0';
1490 ansi_stringize = 0;
1491 s = "";
1492 break;
1495 break;
1499 if (ansi_stringize) {
1500 ansi_stringize = 0;
1501 cerror("'#' operator should be followed by a macro argument name");
1504 if (cc+2+strlen(s) > len) { len += strlen(s)+20; rv = realloc(rv, len); }
1505 strcpy(rv+cc, s);
1506 cc = strlen(rv);
1509 rv[cc] = '\0';
1510 return rv;