1 /***************************************************************************
5 The preprocessor is not a seperate stage but an extension to the lexical
6 analyser. This is possible and efficient since we avoid two passes of
9 ***************************************************************************/
16 // these are borrowed from lex.c
18 extern int skip_ws ();
19 extern int skip_comment ();
20 extern int skip_line ();
21 extern int enter_symbol (char*);
22 extern int enter_string (char*);
24 extern int do_yylex ();
26 static void skip_pp_line ()
28 // Skip a line but respect that newlines inside:
29 // strings, comments, char consts and
30 // escaped ones don't count
32 if (Ci
>= Clen
) return;
37 if (Cpp
[Ci
] == '*') skip_comment ();
38 else if (Cpp
[Ci
] == '/') skip_line ();
40 if (Cpp
[++Ci
] == '\n') {
46 for (++Ci
; Ci
< Clen
&& Cpp
[Ci
] != '"'; Ci
++)
47 if (Cpp
[Ci
] == '\\') ++Ci
;
48 else if (Cpp
[Ci
] == '\n') ++line
;
51 for (++Ci
; Ci
< Clen
&& Cpp
[Ci
] != '\''; Ci
++)
52 if (Cpp
[Ci
] == '\\') ++Ci
;
53 else if (Cpp
[Ci
] == '\n') ++line
;
61 static Token
*get_expanded_line ()
67 SAVE_VAR (Clen
, Ci
+1);
70 OUTSTREAM S
= new_stream ();
71 while ((t
= do_yylex ()) != THE_END
)
73 if (t
== RESERVED_defined
) {
74 if (!issymbol (t
= do_yylex ())
75 && (t
!= '(' || !issymbol (t
= do_yylex ())
76 || do_yylex () != ')'))
77 parse_error_cpp ("defined (symbol)");
78 output_itoken (S
, is_macro (t
) == -1 ? RESERVED_0
: RESERVED_1
);
79 } else if (is_macro (t
) != -1) {
80 Token
*E
= expand_macro (t
);
81 outprintf (S
, ISTR (E
), -1);
84 else jmp
: output_itoken (S
, t
);
87 return combine_output (S
);
90 /******************************************************************************
94 Search for the file in the usual places and then recurse back to yydo_file.
95 If the directive is "#uses", then enclose everything inside extern "file" {}
97 ******************************************************************************/
98 static char **hsearch
, **isearch
;
100 static char *fixpath (char *path
)
102 char *p
= path
, *s
, *e
;
109 } else if (p
[1] == '.' && p
[2] == '/' && p
> path
+ 1 && p
[-1] == '/') {
111 for (s
= p
- 2; *s
!= '/' && s
> path
; s
--);
112 p
= *s
== '/' ? ++s
: s
;
119 static char *FindHeader (char *fn
, char *ret
, bool sys
)
121 char **p
= sys
? isearch
: hsearch
;
126 if (!sys
&& (**p
!= '/' || *p
[1] != ':' && *p
[2] != '/')
127 && strchr (current_file
, '/')) {
128 strcpy (tmp
, current_file
);
129 char *t
= strrchr (tmp
, '/');
134 if (strlen (tmp
) && tmp
[strlen (tmp
) - 1] != '/') strcat (tmp
, "/");
139 if (access (tmp
, R_OK
) == 0)
140 return strcpy (ret
, tmp
);
143 fprintf (stderr
, "Could not find file %s\n", fn
);
144 fatal ("terminated");
148 static intnode
*included
;
150 static void include (bool uses
)
153 char fn
[128], path
[256];
156 closer
= Cpp
[Ci
] == '<' ? '>' : Cpp
[Ci
] == '"' ? '"' : 0;
157 if (!closer
) fatal ("#include");
159 for (++Ci
, i
= 0; Cpp
[Ci
] != closer
&& Ci
< Clen
&& i
< sizeof fn
;)
160 fn
[i
++] = Cpp
[Ci
++];
163 if (Cpp
[Ci
++] != closer
) fatal ("#include");
165 FindHeader (fn
, path
, closer
== '>');
166 t
= enter_value (path
);
168 if (!intfind (included
, t
)) {
170 intadd (&included
, t
, u
);
174 sprintf (path
, "\"%s\"", fn
);
175 outprintf (GLOBAL
, RESERVED_extern
, enter_value (path
), '{', -1);
178 if (yydo_file (path
) == -1) {
179 fprintf (stderr
, "Problematic file [%s]\n", fn
);
180 fatal ("Can't open file");;
183 if (uses
) output_itoken (GLOBAL
, '}');
187 /******************************************************************************
189 Macro Definitions && undefs
191 ******************************************************************************/
197 static intnode
*macrotree
;
199 int is_macro (Token t
)
203 if (n
= intfind (macrotree
, t
))
204 return ((macro
*) n
->v
.p
)->argc
;
206 return ISPREDEF (t
) ? 0 : -1;
209 static void define ()
211 int argc
= 0, i
, margc
= 0;
212 Token n
= do_yylex (), argv
[100], t
;
216 if (!ISSYMBOL (n
)) fatal ("#define");
220 PRINTF ("define ["COLS
"%s"COLE
"]\n", expand (n
));
224 if (Cpp
[Ci
] == '(') {
229 if (do_yylex () != ')')
230 parse_error_cpp ("#define X(arg,...) : C99 style");
233 if (!ISSYMBOL (t
)) fatal ("#define args");
237 if (t
== ELLIPSIS
) fatal ("gnu varags not supported");
238 if (t
!= ',') fatal ("#define args separator");
240 margc
= t
== ELLIPSIS
? argc
+ VARBOOST
: argc
?: VOIDARG
;
245 SAVE_VAR (Clen
, Ci
+1);
248 OUTSTREAM Def
= new_stream ();
249 while ((t
= do_yylex ()) != THE_END
) {
250 for (i
= 0; i
< argc
; i
++)
255 if (t
== RESERVED___VA_ARGS__
)
257 output_itoken (Def
, t
);
259 m
= (macro
*) malloc (sizeof *m
);
260 m
->body
= combine_output (Def
);
262 if (mn
= intfind (macrotree
, n
)) {
263 macro
*h
= (macro
*) mn
->v
.p
;
264 if (h
->argc
!= m
->argc
|| intcmp (h
->body
, m
->body
))
265 fatal ("different macro redefinition");
269 union ival u
= { .p m
};
270 intadd (¯otree
, n
, u
);
278 Token m
= do_yylex ();
279 intnode
*n
= intfind (macrotree
, m
);
282 free (((macro
*) n
->v
.p
)->body
);
283 intremove (¯otree
, n
);
288 /******************************************************************************
289 cpp expression evaluation (#if, #elif)
290 a mini-compiler inside the compiler...
292 right now works only with integers. floats and other stuff
293 evaluate to 1L. symbols evaluate to 0L
294 ******************************************************************************/
295 static Token
*eval_expr
;
298 static long long int cpp_expression ();
300 static long long int cpp_cond_getnum ()
302 Token s
= eval_expr
[eep
++];
305 case '!': return !cpp_cond_getnum ();
306 case '(': return cpp_expression ();
307 case '-': return -cpp_cond_getnum ();
308 case '~': return ~cpp_cond_getnum ();
312 return type_of_const (s
) == typeID_int
?
318 static int op_pri (int type
)
330 case EQCMP
: return 4;
334 case LEQCMP
: return 3;
346 #define CALC(operator) \
347 /* PRINTF ("calculating %lli %s %lli\n", Arr [ce-1], #operator, Arr[ce+1]); */\
348 Arr [ce - 1] = Arr [ce - 1] operator Arr [ce + 1];\
351 static long long int cpp_expressionr ()
353 long long int Arr
[64];
358 /* DO NOT TRY THIS AT HOME */
360 Arr
[Arr
[0]] = cpp_cond_getnum ();
361 pri
= op_pri (eval_expr
[eep
]);
363 if (eval_expr
[eep
] == '?' || eval_expr
[eep
] == ':')
365 else parse_error_cpp ("confusing expression in #if");
367 if (op_pri (Arr
[ce
= Arr
[0] - 1]) <= pri
) {
378 case EQCMP
: CALC (==);
379 case NEQCMP
: CALC (!=);
380 case GEQCMP
: CALC (>=);
381 case LEQCMP
: CALC (<=);
385 case ANDAND
: CALC (&&);
389 if (pri
== 9) return Arr
[1];
391 if (eval_expr
[eep
] == ANDAND
&& Arr
[1] == 0) {
392 for (++eep
; eval_expr
[eep
] != ')' && eval_expr
[eep
] != OROR
393 && eval_expr
[eep
] != -1; eep
++)
395 eep
= skip_buffer_parenthesis (eval_expr
, eep
+ 1) - 1;
396 if (eval_expr
[eep
] != OROR
) return 0;
401 if (eval_expr
[eep
] == OROR
&& Arr
[1] != 0) {
402 for (++eep
; eval_expr
[eep
] != ')' && eval_expr
[eep
] != -1; eep
++)
404 eep
= skip_buffer_parenthesis (eval_expr
, eep
+ 1) - 1;
408 Arr
[++Arr
[0]] = eval_expr
[eep
++];
413 static long long int cpp_expression ()
415 static bool expectcond
;
417 long long int rez
= cpp_expressionr ();
418 switch (eval_expr
[eep
]) {
419 case ')': ++eep
; break;
422 SAVE_VAR (expectcond
, true);
423 long long int r1
= cpp_expression ();
424 RESTOR_VAR (expectcond
);
425 rez
= rez
? r1
: cpp_expression ();
427 case ':': if (expectcond
) ++eep
;
428 else parse_error_cpp ("':' without '?'");
429 ndefault
: if (expectcond
) parse_error_cpp ("missing ':'");
434 static bool cpp_condition ()
437 eval_expr
= get_expanded_line ();
440 PRINTF ("Conditional expression :");
441 INTPRINT (eval_expr
);
446 r
= cpp_expression () != 0;
451 /******************************************************************************
452 Conditional compilation
453 don't try this at home....
454 ******************************************************************************/
455 static int conditional_pp
;
457 static void skip_to_endif (bool checkelse
)
464 if (t
!= CPP_DIRECTIVE
) {
467 parse_error_cpp ("#if without endif");
473 if (t
== RESERVED_endif
) break;
475 if (t
== RESERVED_if
|| t
== RESERVED_ifdef
|| t
== RESERVED_ifndef
) {
476 skip_to_endif (false);
480 if (!checkelse
) continue;
481 if (t
== RESERVED_else
) {
487 if (t
== RESERVED_elif
)
488 if (cpp_condition ()) {
497 Token m
= do_yylex ();
498 return is_macro (m
) != -1;
501 /******************************************************************************
503 ******************************************************************************/
504 static void cpp_error ()
509 char *msg
= (char*) alloca (2 + Ci
);
510 strncpy (msg
, Cpp
+ ii
, Ci
);
512 fprintf (stderr
, "ERROR: %s\n", msg
);
516 /******************************************************************************
518 Process a preprocessing line directive
520 ******************************************************************************/
522 void cpp_directive ()
524 if (skip_ws ()) return;
526 Token t
= do_yylex ();
529 case RESERVED_include
:
531 include (t
== RESERVED_uses
);
532 ncase RESERVED_define
:
534 ncase RESERVED_undef
:
536 ncase RESERVED_ifdef
:
537 if (ifdef ()) ++conditional_pp
;
538 else skip_to_endif (true);
539 ncase RESERVED_ifndef
:
540 if (!ifdef ()) ++conditional_pp
;
541 else skip_to_endif (true);
544 parse_error_cpp ("#else not in conditional");
546 skip_to_endif (false);
547 ncase RESERVED_endif
:
549 parse_error_cpp ("#endif without #startif");
553 if (!cpp_condition ()) skip_to_endif (true);
554 else ++conditional_pp
;
556 if (!conditional_pp
) parse_error_cpp ("#elif without #if");
558 skip_to_endif (false);
559 ncase RESERVED_error
:
564 // PRINTF ("not implemented\n");
568 void setup_cpp (int argc
, char **argv
)
573 for (id
= i
= 0; i
< argc
; i
++)
574 if (argv
[i
][0] == '-')
575 switch (argv
[i
][1]) {
577 Idir
[id
++] = argv
[i
][2] == 0 ? argv
[++i
] : argv
[i
] + 2;
580 i
= 1 + id
+ sizeof search_dirs
/ sizeof search_dirs
[0];
581 hsearch
= (char**) malloc (i
* sizeof *hsearch
);
583 for (i
= 1, j
= 0; j
< id
; j
++)
584 hsearch
[i
++] = strdup (Idir
[j
]);
585 for (j
= 0; search_dirs
[j
]; j
++)
586 hsearch
[i
++] = (char*) search_dirs
[j
];
588 isearch
= hsearch
+ 1;
591 static void freeintnode (intnode
*n
)
593 if (n
->less
) freeintnode (n
->less
);
594 if (n
->more
) freeintnode (n
->more
);
598 static void freemacronode (intnode
*n
)
600 if (n
->less
) freeintnode (n
->less
);
601 if (n
->more
) freeintnode (n
->more
);
602 free (((macro
*)n
->v
.p
)->body
);
609 if (included
) freeintnode (included
);
610 if (macrotree
) freemacronode (macrotree
);
613 /************************************************************************
617 We deviate from the standard which sais that ``macro arguments are
618 expanded *before* the macro expansion unless they're followed by
619 '#' or '##' and then there is a second rescan to reexpand'' doh
621 ************************************************************************/
623 static Token
*expand_predef (Token m
)
625 static Token timetok
;
627 Token
*ret
= mallocint (2);
631 case RESERVED___LINE__
:
632 sprintf (tmp
, "%i", line
);
633 ret
[0] = enter_value (tmp
);
634 ncase RESERVED___FILE__
:
635 sprintf (tmp
, "\"%s\"", tfile
);
636 ret
[0] = enter_string (tmp
);
637 ncase RESERVED___TIME__
:
638 case RESERVED___DATE__
:
641 sprintf (tmp
, "\"%s", ctime (&t
));
642 *(strchr (tmp
, '\n')) = '"';
643 timetok
= enter_string (tmp
);
644 if (strstr (tmp
, "Jan 1 "))
645 fputs ("Happy new year!\n", stderr
);
652 static Token
stringize (Token arg
[])
657 for (l
= 0, i
= 4; arg
[l
] != -1; l
++) {
658 i
+= strlen (s
= expand (arg
[l
])) + 1;
659 for (j
= 0; s
[j
]; j
++)
661 || s
[j
] == '"') i
++;
664 tmp
= (char*) malloc (i
);
666 for (l
= 0, i
= 1; arg
[l
] != -1; l
++) {
667 s
= expand (arg
[l
]);
669 if (*s
== '\\' || *s
== '"')
673 if (arg
[l
+ 1] != -1) tmp
[i
++] = ' ';
678 return enter_string (tmp
);
681 static Token
concat (OUTSTREAM S
, Token a1
[], Token a2
[])
686 if (a1
[i
= 0] != -1)
687 while (a1
[i
+ 1] != -1)
688 output_itoken (S
, a1
[i
++]);
690 if (a2
[0] == -1) return a1
[i
];
693 # define EXPAND(x) expand (x == -1 ? BLANKT : x)
695 tmp
= strcat (strcpy (
696 (char*) malloc (l
= strlen (EXPAND (a1
[i
])) + strlen (EXPAND (a2
[0])) + 1),
697 EXPAND (a1
[i
])), EXPAND (a2
[0]));
699 if ((ISIDENT (a1
[i
]) || a1
[i
] == -1)
700 && (ISIDENT (a2
[0]) || a2
[0] == -1))
701 con
= enter_symbol (tmp
);
705 SAVE_VAR (Clen
, l
- 1);
707 while ((t
= do_yylex ()) != THE_END
) {
708 if (con
) output_itoken (S
, con
);
717 if (a2
[1] == -1) return con
;
719 output_itoken (S
, con
);
720 for (i
= 1; a2
[i
+ 1] != -1; i
++)
721 output_itoken (S
, a2
[i
]);
726 static Token
*expanding
, *tops
;
727 static Token
*expand_macro_arglist (Token
, int, Token
*);
729 static Token
*expand_macro_argv (Token m
, Token
**argv
)
731 Token
*B
= ((macro
*) intfind (macrotree
, m
)->v
.p
)->body
;
732 Token a1
[] = { 0, -1 }, a2
[] = { 0, -1 }, *a1p
, *a2p
, b
;
734 OUTSTREAM S
= new_stream ();
736 /* stringnify and concatenate */
737 for (;(b
= *B
++) != -1;) {
741 parse_error_cpp ("'#' not followed by macro argument");
742 output_itoken (S
, stringize (argv
[b
- ARGBASE
]));
745 if (*B
== CPP_CONCAT
) {
746 while (*B
== CPP_CONCAT
) {
747 if (!ISTPLARG (b
)) a1
[0] = b
;
748 a1p
= ISTPLARG (b
) ? argv
[b
- ARGBASE
] : a1
;
750 if (b
== -1) parse_error_cpp ("'##' is last");
751 if (!ISTPLARG (b
)) a2
[0] = b
;
752 a2p
= ISTPLARG (b
) ? argv
[b
- ARGBASE
] : a2
;
753 b
= concat (S
, a1p
, a2p
);
756 output_itoken (S
, b
);
760 outprintf (S
, ISTR (argv
[b
- ARGBASE
]), -1);
761 else output_itoken (S
, b
);
764 B
= combine_output (S
);
765 for (i
= 0; B
[i
] != -1; i
++)
766 if (is_macro (B
[i
]) != -1)
767 goto further_expands
;
772 /* macro contains further macros, non-recusrive */
777 for (i
= 0; B
[i
] != -1; i
++)
778 if ((n
= is_macro (B
[i
])) == -1) noexpand
:
779 output_itoken (S
, B
[i
]);
784 for (E
= expanding
; *E
!= -1; E
++)
789 E
= expand_predef (m
);
791 E
= expand_macro_argv (m
, 0);
793 if (B
[++i
] != '(') parse_error_cpp ("No arguments to macro");
794 E
= expand_macro_arglist (m
, n
, &B
[++i
]);
795 i
= skip_buffer_parenthesis (B
, i
) - 1;
797 outprintf (S
, ISTR (E
), -1);
803 return combine_output (S
);
806 static Token
*expand_macro_arglist (Token m
, int argn
, Token
*s
)
810 NormPtr pstart
, pend
;
812 for (i
= 0, argc
= 2; s
[i
] != ')'; i
++)
813 if (s
[i
] == ',') ++argc
;
814 parg
= (Token
**) alloca (argc
* sizeof (Token
*));
816 pstart
= 0, argc
= 0;
819 while (s
[pend
] != ',' && s
[pend
] != ')')
821 pend
= skip_buffer_parenthesis (s
, pend
+ 1);
822 else if (s
[pend
] == -1)
823 parse_error_cpp ("Incomplete macro call");
825 parg
[argc
] = allocaint (2 + pend
- pstart
);
826 intextract (parg
[argc
++], s
+ pstart
, pend
- pstart
);
827 if (s
[pend
] == ')') break;
833 if (argn
< VOIDARG
|| argn
== VOIDARG
&& argc
!= 1
834 || (argn
>= VARBOOST
&& argn
- VARBOOST
> argc
))
835 parse_error_cpp ("Argument number mismatch");
837 if (argn
>= VARBOOST
) {
839 int j
= argn
- VARBOOST
;
841 for (i
= j
, l
= 10; parg
[i
]; i
++)
842 l
+= intlen (parg
[i
]) + 1;
843 varg
= allocaint (l
);
845 for (i
= j
; parg
[i
]; i
++) {
846 intcat (varg
, parg
[i
]);
847 if (parg
[i
+ 1]) intcatc (varg
, ',');
853 return expand_macro_argv (m
, parg
);
856 Token
*expand_macro (Token m
)
859 if (0&&debugflag
.CPP
)
860 PRINTF ("expanding macro "COLS
"%s"COLE
"\n", expand (m
));
863 return expand_predef (m
);
866 tops
= expanding
= rarray
;
867 int argn
= is_macro (m
);
869 if (!argn
) return expand_macro_argv (m
, 0);
871 if (do_yylex () != '(') parse_error_cpp ("No arguments to macro");
873 Token arglist
[256], t
;
876 while ((arglist
[i
++] = t
= do_yylex ()) != ')')
878 case THE_END
: parse_error_cpp ("Incomplete arglist");
881 while (po
) switch (t
= arglist
[i
++] = do_yylex ()) {
884 ncase THE_END
: parse_error_cpp ("Incomplete arglist");
889 return expand_macro_arglist (m
, argn
, arglist
);