1 /*
2 * VARBRACE - CLISP source preprocessor
3 * Bruno Haible 15.8.1999
4
5 This preprocessor adds braces to source code, so that variable declarations
6 (introduced with the pseudo-keyword `var') can be used within blocks, like
7 in C++.
8 Example:
9 {
10 var decl1;
11 statement1;
12 var decl2;
13 statement2;
14 }
15 becomes
16 {
17 {var decl1;
18 statement1;
19 {var decl2;
20 statement2;
21 }}
22 }
23
24 Restrictions and caveats:
25 - The last line in the input file should be terminated with a newline.
26 - #line lines should not be separated into multiple lines using
27 backslash-newline.
28 - No multi-line comments should start in a preprocessor line.
29 - Closing braces should not be enclosed in #if conditionals.
30 - #if conditions are assumed to be constant from the `var' declaration to
31 the closing brace.
32 */
33
34 #include <config.h>
35
36 typedef unsigned char uintB;
37 typedef unsigned short uintW;
38 typedef unsigned long uintL;
39 typedef int boolean;
40 #define FALSE 0
41 #define TRUE 1
42
43 #include <stdlib.h>
44 #include <string.h>
45 #include <ctype.h>
46 #include <errno.h>
47 #include <stdio.h>
48
49 #ifndef NULL
50 #define NULL ((void*)0)
51 #endif
52
53 #ifdef __cplusplus
54 extern "C" void exit(int);
55 #endif
56
57 #if !(defined(__GNUC__) && !defined(__STRICT_ANSI__))
58 #define inline
59 #endif
60
61 /* g++ 3.3 doesn't accept compound expressions as initializers; as a workaround,
62 we transform "var object foo = ..." into "var object foo; foo = ...",
63 and likewise "var chart foo = ..." into "var chart foo; foo = ...". */
64 #if defined(__GNUG__) && (__GNUC__ == 3) && (__GNUC_MINOR__ == 3)
65 #define SPLIT_OBJECT_INITIALIZATIONS
66 #endif
67
68
69 /* Memory utilities. */
xmalloc(uintL count)70 static char* xmalloc (uintL count)
71 {
72 char* tmp = (char*)malloc(count);
73 if (!tmp) {
74 fprintf(stderr,"Virtual memory exhausted.\n");
75 exit(1);
76 }
77 return tmp;
78 }
79
xrealloc(void * data,uintL count)80 static char* xrealloc (void* data, uintL count)
81 {
82 char* tmp = (char*)realloc(data,count);
83 if (!tmp) {
84 fprintf(stderr,"Virtual memory exhausted.\n");
85 exit(1);
86 }
87 return tmp;
88 }
89
xfree(void * ptr)90 static inline void xfree (void* ptr)
91 {
92 free((char*)ptr);
93 }
94
95
96 /* Character utilities. */
97
98 /* Determine whether a character (not newline) is whitespace. */
is_whitespace(char c)99 static inline boolean is_whitespace (char c)
100 {
101 return (c == ' ') || (c == '\t');
102 }
103
104 /* Determine whether a charater is a digit (locale independent). */
is_digit(char c)105 static inline boolean is_digit (char c)
106 {
107 return (c >= '0') && (c <= '9');
108 }
109
110
111 /* String utilities. */
112
113 /* Returns the freshly allocated copy of a strings. */
concat1(const char * str1)114 static char* concat1 (const char* str1)
115 {
116 uintL len1 = strlen(str1);
117 char* result = xmalloc(len1+1);
118 memcpy(result+0,str1,len1+1);
119 return result;
120 }
121
122 /* Returns the freshly allocated contenation of 2 strings. */
concat2(const char * str1,const char * str2)123 static char* concat2 (const char* str1, const char* str2)
124 {
125 uintL len1 = strlen(str1);
126 uintL len2 = strlen(str2);
127 char* result = xmalloc(len1+len2+1);
128 memcpy(result+0,str1,len1);
129 memcpy(result+len1,str2,len2+1);
130 return result;
131 }
132
133 /* Returns the freshly allocated contenation of 3 strings. */
concat3(const char * str1,const char * str2,const char * str3)134 static char* concat3 (const char* str1, const char* str2, const char* str3)
135 {
136 uintL len1 = strlen(str1);
137 uintL len2 = strlen(str2);
138 uintL len3 = strlen(str3);
139 char* result = xmalloc(len1+len2+len3+1);
140 memcpy(result+0,str1,len1);
141 memcpy(result+len1,str2,len2);
142 memcpy(result+len1+len2,str3,len3+1);
143 return result;
144 }
145
146 #ifdef unused
147 /* Returns the freshly allocated contenation of 4 strings. */
concat4(const char * str1,const char * str2,const char * str3,const char * str4)148 static char* concat4 (const char* str1, const char* str2, const char* str3, const char* str4)
149 {
150 uintL len1 = strlen(str1);
151 uintL len2 = strlen(str2);
152 uintL len3 = strlen(str3);
153 uintL len4 = strlen(str4);
154 char* result = xmalloc(len1+len2+len3+len4+1);
155 memcpy(result+0,str1,len1);
156 memcpy(result+len1,str2,len2);
157 memcpy(result+len1+len2,str3,len3);
158 memcpy(result+len1+len2+len3,str4,len4+1);
159 return result;
160 }
161 #endif
162
163 /* Returns a freshly allocated substring. */
substring(const char * str,uintL index1,uintL index2)164 static char* substring (const char* str, uintL index1, uintL index2)
165 {
166 if (!(index1 <= index2)) abort();
167 if (!(index2 <= strlen(str))) abort();
168 { uintL len = index2-index1;
169 char* result = xmalloc(len+1);
170 if (len > 0) memcpy(result,str+index1,len);
171 result[len] = '\0';
172 return result;
173 } }
174
175 #ifdef unused
176 /* Returns a freshly allocated substring. */
substring_from_to(const char * p1,const char * p2)177 static char* substring_from_to (const char* p1, const char* p2)
178 {
179 uintL length = p2 - p1;
180 char* result = (char*) xmalloc(length+1);
181 memcpy(result,p1,length);
182 result[length] = '\0';
183 return result;
184 }
185 #endif
186
187 /* Compares two strings for equality. */
String_equals(const char * str1,const char * str2)188 static inline boolean String_equals (const char* str1, const char* str2)
189 {
190 return !strcmp(str1,str2);
191 }
192
193 #ifdef unused
194 /* Compares two strings for case-insensitive equality. */
String_equalsIgnoreCase(const char * str1,const char * str2)195 static boolean String_equalsIgnoreCase (const char* str1, const char* str2)
196 {
197 while (*str1 != '\0' && *str2 != '\0') {
198 unsigned char c1 = (unsigned char)(*str1++);
199 unsigned char c2 = (unsigned char)(*str2++);
200 if (c1 < 0x80) /* isascii(c1) */
201 c1 = toupper(c1);
202 if (c2 < 0x80) /* isascii(c2) */
203 c2 = toupper(c2);
204 if (c1 != c2)
205 return FALSE;
206 }
207 /* Now *str1 == '\0' || *str2 == '\0'. */
208 return (*str1 == *str2);
209 }
210 #endif
211
212
213 /* Extensible vectors. */
214
215 typedef struct {
216 uintL index;
217 uintL size;
218 const void* * data;
219 } Vector;
220
Vector_init(Vector * v)221 static inline void Vector_init (Vector* v)
222 {
223 v->size = 5;
224 v->data = (const void* *) xmalloc(v->size * sizeof(const void*));
225 v->index = 0;
226 }
227
Vector_length(const Vector * v)228 static inline uintL Vector_length (const Vector* v)
229 {
230 return v->index;
231 }
232
Vector_add(Vector * v,const void * elt)233 static void Vector_add (Vector* v, const void* elt)
234 {
235 if (v->index >= v->size) {
236 v->size = 2 * v->size;
237 v->data = (const void* *) xrealloc(v->data, v->size * sizeof(const void*));
238 }
239 v->data[v->index++] = elt;
240 }
241
Vector_element(const Vector * v,uintL i)242 static const void * Vector_element (const Vector* v, uintL i)
243 {
244 if (!(i < v->index)) {
245 fprintf(stderr,"vector index out of bounds");
246 abort();
247 }
248 return v->data[i];
249 }
250
Vector_set_element(Vector * v,uintL i,const void * elt)251 static void Vector_set_element (Vector* v, uintL i, const void* elt)
252 {
253 if (!(i < v->index)) {
254 fprintf(stderr,"vector index out of bounds");
255 abort();
256 }
257 v->data[i] = elt;
258 }
259
260 #ifdef unused
Vector_remove_element(Vector * v,uintL i)261 static void Vector_remove_element (Vector* v, uintL i)
262 {
263 if (!(i < v->index)) {
264 fprintf(stderr,"vector index out of bounds");
265 abort();
266 }
267 v->index--;
268 for (; i < v->index; i++)
269 v->data[i] = v->data[i+1];
270 }
271 #endif
272
273 #ifdef unused
Vector_init_clone(Vector * w,const Vector * v)274 static void Vector_init_clone (Vector* w, const Vector* v)
275 {
276 w->size = (v->size < 5 ? 5 : v->size);
277 w->data = (const void* *) xmalloc(w->size * sizeof(const void*));
278 memcpy(w->data,v->data,v->size * sizeof(const void*));
279 w->index = v->size;
280 }
281 #endif
282
283 #ifdef unused
Vector_clone(const Vector * v)284 static Vector* Vector_clone (const Vector* v)
285 {
286 Vector* w = (Vector*) xmalloc(sizeof(Vector));
287 Vector_init_clone(w,v);
288 return w;
289 }
290 #endif
291
292
293 /* A vector of strings. */
294
295 typedef struct {
296 Vector rep;
297 } VectorString;
298
VectorString_init(VectorString * v)299 static inline void VectorString_init (VectorString* v)
300 {
301 Vector_init(&v->rep);
302 }
303
make_VectorString()304 static VectorString* make_VectorString ()
305 {
306 VectorString* v = (VectorString*) xmalloc(sizeof(VectorString));
307 VectorString_init(v);
308 return v;
309 }
310
VectorString_length(const VectorString * v)311 static inline uintL VectorString_length (const VectorString* v)
312 {
313 return Vector_length(&v->rep);
314 }
315
VectorString_add(VectorString * v,const char * elt)316 static inline void VectorString_add (VectorString* v, const char* elt)
317 {
318 Vector_add(&v->rep,elt);
319 }
320
VectorString_element(const VectorString * v,uintL i)321 static inline const char* VectorString_element (const VectorString* v, uintL i)
322 {
323 return (const char*) Vector_element(&v->rep,i);
324 }
325
VectorString_set_element(VectorString * v,uintL i,const char * elt)326 static inline void VectorString_set_element (VectorString* v, uintL i, const char* elt)
327 {
328 Vector_set_element(&v->rep,i,elt);
329 }
330
331 #ifdef unused
VectorString_init_clone(VectorString * w,const VectorString * v)332 static inline void VectorString_init_clone (VectorString* w, const VectorString* v)
333 {
334 Vector_init_clone(&w->rep,&v->rep);
335 }
336 #endif
337
338 #ifdef unused
VectorString_clone(const VectorString * v)339 static VectorString* VectorString_clone (const VectorString* v)
340 {
341 VectorString* w = (VectorString*) xmalloc(sizeof(VectorString));
342 VectorString_init_clone(w,v);
343 return w;
344 }
345 #endif
346
347 /* Tests whether v equals w. */
VectorString_equals(const VectorString * v,const VectorString * w)348 static boolean VectorString_equals (const VectorString* v, const VectorString* w)
349 {
350 uintL n = VectorString_length(v);
351 if (VectorString_length(w) == n) {
352 uintL i;
353 for (i = 0; i < n; i++)
354 if (!String_equals(VectorString_element(v,i),VectorString_element(w,i)))
355 return FALSE;
356 return TRUE;
357 }
358 return FALSE;
359 }
360
361 #ifdef unused
362 /* Tests whether v starts with w. */
VectorString_startsWith(const VectorString * v,const VectorString * w)363 static boolean VectorString_startsWith (const VectorString* v, const VectorString* w)
364 {
365 uintL n = VectorString_length(w);
366 if (VectorString_length(v) >= n) {
367 uintL i;
368 for (i = 0; i < n; i++)
369 if (!String_equals(VectorString_element(v,i),VectorString_element(w,i)))
370 return FALSE;
371 return TRUE;
372 }
373 return FALSE;
374 }
375 #endif
376
377
378 /* A vector of vectors of strings. */
379
380 typedef struct {
381 Vector rep;
382 } VectorVectorString;
383
VectorVectorString_init(VectorVectorString * v)384 static inline void VectorVectorString_init (VectorVectorString* v)
385 {
386 Vector_init(&v->rep);
387 }
388
make_VectorVectorString()389 static VectorVectorString* make_VectorVectorString ()
390 {
391 VectorVectorString* v = (VectorVectorString*) xmalloc(sizeof(VectorVectorString));
392 VectorVectorString_init(v);
393 return v;
394 }
395
VectorVectorString_length(const VectorVectorString * v)396 static inline uintL VectorVectorString_length (const VectorVectorString* v)
397 {
398 return Vector_length(&v->rep);
399 }
400
VectorVectorString_add(VectorVectorString * v,const VectorString * elt)401 static inline void VectorVectorString_add (VectorVectorString* v, const VectorString* elt)
402 {
403 Vector_add(&v->rep,elt);
404 }
405
VectorVectorString_element(const VectorVectorString * v,uintL i)406 static inline const VectorString* VectorVectorString_element (const VectorVectorString* v, uintL i)
407 {
408 return (const VectorString*) Vector_element(&v->rep,i);
409 }
410
411 #ifdef unused
VectorVectorString_set_element(VectorVectorString * v,uintL i,const VectorString * elt)412 static inline void VectorVectorString_set_element (VectorVectorString* v, uintL i, const VectorString* elt)
413 {
414 Vector_set_element(&v->rep,i,elt);
415 }
416 #endif
417
418 #ifdef unused
VectorVectorString_init_clone(VectorVectorString * w,const VectorVectorString * v)419 static inline void VectorVectorString_init_clone (VectorVectorString* w, const VectorVectorString* v)
420 {
421 Vector_init_clone(&w->rep,&v->rep);
422 }
423 #endif
424
425 #ifdef unused
VectorVectorString_clone(const VectorVectorString * v)426 static VectorVectorString* VectorVectorString_clone (const VectorVectorString* v)
427 {
428 VectorVectorString* w = (VectorVectorString*) xmalloc(sizeof(VectorVectorString));
429 VectorVectorString_init_clone(w,v);
430 return w;
431 }
432 #endif
433
434
435 /* A stack of vectors of strings. */
436
437 typedef struct {
438 Vector rep;
439 } StackVectorString;
440
StackVectorString_init(StackVectorString * v)441 static inline void StackVectorString_init (StackVectorString* v)
442 {
443 Vector_init(&v->rep);
444 }
445
make_StackVectorString()446 static StackVectorString* make_StackVectorString ()
447 {
448 StackVectorString* v = (StackVectorString*) xmalloc(sizeof(StackVectorString));
449 StackVectorString_init(v);
450 return v;
451 }
452
StackVectorString_length(const StackVectorString * v)453 static inline uintL StackVectorString_length (const StackVectorString* v)
454 {
455 return Vector_length(&v->rep);
456 }
457
458 #ifdef unused
StackVectorString_is_empty(const StackVectorString * v)459 static inline boolean StackVectorString_is_empty (const StackVectorString* v)
460 {
461 return StackVectorString_length(v) == 0;
462 }
463 #endif
464
StackVectorString_push(StackVectorString * v,const VectorString * elt)465 static inline void StackVectorString_push (StackVectorString* v, const VectorString* elt)
466 {
467 Vector_add(&v->rep,elt);
468 }
469
StackVectorString_element(const StackVectorString * v,uintL i)470 static inline VectorString* StackVectorString_element (const StackVectorString* v, uintL i)
471 {
472 return (VectorString*) Vector_element(&v->rep,i);
473 }
474
StackVectorString_peek(StackVectorString * v)475 static VectorString* StackVectorString_peek (StackVectorString* v)
476 {
477 uintL n = StackVectorString_length(v);
478 if (n == 0) { fprintf(stderr,"stack empty\n"); exit(1); }
479 return StackVectorString_element(v,n-1);
480 }
481
StackVectorString_pop(StackVectorString * v)482 static VectorString* StackVectorString_pop (StackVectorString* v)
483 {
484 uintL n = StackVectorString_length(v);
485 if (n == 0) { fprintf(stderr,"stack empty\n"); exit(1); }
486 { VectorString* result = StackVectorString_element(v,n-1);
487 v->rep.index -= 1;
488 return result;
489 } }
490
491 #ifdef unused
492 /* Push elt, and optimize: elt can be removed if is starts with an already
493 present string sequence. If another element starts with elt, that one can
494 be removed. */
StackVectorString_push_optimize(StackVectorString * v,const VectorString * elt)495 static void StackVectorString_push_optimize (StackVectorString* v, const VectorString* elt)
496 {
497 uintL n = StackVectorString_length(v);
498 uintL i;
499 for (i = 0; i < n; i++)
500 if (VectorString_startsWith(elt,StackVectorString_element(v,i)))
501 return;
502 for (i = 0; i < n; )
503 if (VectorString_startsWith(StackVectorString_element(v,i),elt)) {
504 Vector_remove_element(&v->rep,i);
505 n--;
506 } else
507 i++;
508 Vector_add(&v->rep,elt);
509 }
510 #endif
511
512
513 /* The #if[def] stack. All the conditions are implicitly combined by &&.
514 For every #if we start a new entry in the stack, which is popped when we
515 see the corresponding #endif. This is a stack of vector of string, not a
516 stack of string, because when a #elif is seen, we add an element to the
517 stack without popping the previous one. */
518
519 static StackVectorString* ifdef_stack;
520
521 /* Operations on the #if[def] stack. */
522
do_if(const char * condition)523 static void do_if (const char * condition)
524 {
525 VectorString* v = make_VectorString();
526 VectorString_add(v,condition);
527 StackVectorString_push(ifdef_stack,v);
528 }
529
do_else()530 static void do_else ()
531 {
532 VectorString* v = StackVectorString_peek(ifdef_stack);
533 uintL i = VectorString_length(v) - 1;
534 const char* lastcondition = VectorString_element(v,i);
535 lastcondition = concat3("!(",lastcondition,")");
536 VectorString_set_element(v,i,lastcondition);
537 }
538
do_elif(const char * condition)539 static void do_elif (const char * condition)
540 {
541 VectorString* v = StackVectorString_peek(ifdef_stack);
542 uintL i = VectorString_length(v) - 1;
543 const char* lastcondition = VectorString_element(v,i);
544 lastcondition = concat3("!(",lastcondition,")");
545 VectorString_set_element(v,i,lastcondition);
546 VectorString_add(v,condition);
547 }
548
do_endif()549 static void do_endif ()
550 {
551 StackVectorString_pop(ifdef_stack);
552 }
553
554 /* Returns the current #if condition.
555 It is a vector of strings, implicitly combined by &&.
556 The vector is freshly constructed, but the strings are shared. */
557
current_condition()558 static VectorString* current_condition ()
559 {
560 VectorString* result = make_VectorString();
561 uintL n = StackVectorString_length(ifdef_stack);
562 uintL i;
563 for (i = 0; i < n; i++) {
564 const VectorString* v = StackVectorString_element(ifdef_stack,i);
565 uintL m = VectorString_length(v);
566 uintL j;
567 for (j = 0; j < m; j++)
568 VectorString_add(result,VectorString_element(v,j));
569 }
570 return result;
571 }
572
573 /* Reduces a condition modulo the current condition, i.e. removes all
574 && clauses which are already implied in the current condition. */
575
modulo_current_condition(const VectorString * condition)576 static const VectorString* modulo_current_condition (const VectorString* condition)
577 {
578 /* Quick and dirty: Just remove the start segment:
579 condition[0]==current_condition[0], ... condition[n]==current_condition[n]. */
580 VectorString* current = current_condition();
581 uintL i;
582 for (i = 0; i < VectorString_length(current) && i < VectorString_length(condition); i++)
583 if (!String_equals(VectorString_element(current,i),VectorString_element(condition,i)))
584 break;
585 if (i == 0)
586 return condition;
587 else {
588 VectorString* new_condition = make_VectorString();
589 for (; i < VectorString_length(condition); i++)
590 VectorString_add(new_condition,VectorString_element(condition,i));
591 return new_condition;
592 }
593 }
594
595
596 /* Parsing of preprocessor lines. */
597
598 /* This is required, in order to recognize that in
599 #define hello "hello world" /* some nice
600 greeting */
601 the seconds line belongs to the preprocessor command, even though
602 the first line does not end in a backslash. */
603
604 /* C lexical parsing states */
605 enum parsing_state {
606 STATE_INITIAL,
607 STATE_IN_CHARACTER_LITERAL,
608 STATE_IN_STRING_LITERAL,
609 STATE_IN_C_COMMENT,
610 STATE_IN_CXX_COMMENT
611 };
612
parsing_state_at_end_of_line(const char * line)613 static enum parsing_state parsing_state_at_end_of_line (const char *line)
614 {
615 uintL n = strlen(line);
616 uintL i = 0;
617 for (;;) {
618 /* Here we're in the initial state: not inside character literals,
619 not inside strings, not inside comments. */
620 if (i == n) return STATE_INITIAL;
621 if (line[i] == '\'') {
622 i++;
623 for (;;) {
624 /* Here we're in a character literal. */
625 if (i == n) return STATE_IN_CHARACTER_LITERAL;
626 if (line[i] == '\'') {
627 i++;
628 break;
629 }
630 if (line[i] == '\\') {
631 i++;
632 if (i == n) return STATE_IN_CHARACTER_LITERAL;
633 }
634 i++;
635 }
636 } else if (line[i] == '"') {
637 i++;
638 for (;;) {
639 /* Here we're in a string literal. */
640 if (i == n) return STATE_IN_STRING_LITERAL;
641 if (line[i] == '"') {
642 i++;
643 break;
644 }
645 if (line[i] == '\\') {
646 i++;
647 if (i == n) return STATE_IN_STRING_LITERAL;
648 }
649 i++;
650 }
651 } else if (line[i] == '/') {
652 i++;
653 if (i == n) return STATE_INITIAL;
654 if (line[i] == '*') {
655 i++;
656 for (;;) {
657 /* Here we're in a C style comment. */
658 if (i == n) return STATE_IN_C_COMMENT;
659 if (line[i] == '*') {
660 i++;
661 if (i == n) return STATE_IN_C_COMMENT;
662 if (line[i] == '/') {
663 i++;
664 break;
665 }
666 } else {
667 i++;
668 }
669 }
670 } else if (line[i] == '/') {
671 /* A C++ comment extends until the end of line. */
672 return STATE_IN_CXX_COMMENT;
673 }
674 } else {
675 i++;
676 }
677 }
678 }
679
680
681 /* Parsing of #if/#else/#elif/#endif lines. */
682
is_if(const char * line)683 static const char* is_if (const char* line)
684 {
685 uintL n = strlen(line);
686 uintL i = 0;
687 /* Skip whitespace. */
688 for (; i < n && is_whitespace(line[i]); i++) {}
689 /* Parse a '#'. */
690 if (i < n && line[i] == '#')
691 i++;
692 else
693 return NULL;
694 /* Skip whitespace. */
695 for (; i < n && is_whitespace(line[i]); i++) {}
696 /* Check for "if". */
697 if (i+2 < n
698 && line[i+0] == 'i'
699 && line[i+1] == 'f'
700 && is_whitespace(line[i+2])) {
701 i += 3;
702 for (; i < n && is_whitespace(line[i]); i++) {}
703 for (; n > i && is_whitespace(line[n-1]); n--) {}
704 return substring(line,i,n);
705 }
706 /* Check for "ifdef". */
707 if (i+5 < n
708 && line[i+0] == 'i'
709 && line[i+1] == 'f'
710 && line[i+2] == 'd'
711 && line[i+3] == 'e'
712 && line[i+4] == 'f'
713 && is_whitespace(line[i+5])) {
714 i += 6;
715 for (; i < n && is_whitespace(line[i]); i++) {}
716 for (; n > i && is_whitespace(line[n-1]); n--) {}
717 { char* term = substring(line,i,n);
718 const char* result = concat3("defined(",term,")");
719 xfree(term);
720 return result;
721 } }
722 /* Check for "ifndef". */
723 if (i+6 < n
724 && line[i+0] == 'i'
725 && line[i+1] == 'f'
726 && line[i+2] == 'n'
727 && line[i+3] == 'd'
728 && line[i+4] == 'e'
729 && line[i+5] == 'f'
730 && is_whitespace(line[i+6])) {
731 i += 7;
732 for (; i < n && is_whitespace(line[i]); i++) {}
733 for (; n > i && is_whitespace(line[n-1]); n--) {}
734 { char* term = substring(line,i,n);
735 const char* result = concat3("!defined(",term,")");
736 xfree(term);
737 return result;
738 } }
739 return NULL;
740 }
741
is_else(const char * line)742 static boolean is_else (const char* line)
743 {
744 uintL n = strlen(line);
745 uintL i = 0;
746 /* Skip whitespace. */
747 for (; i < n && is_whitespace(line[i]); i++) {}
748 /* Parse a '#'. */
749 if (i < n && line[i] == '#')
750 i++;
751 else
752 return FALSE;
753 /* Skip whitespace. */
754 for (; i < n && is_whitespace(line[i]); i++) {}
755 /* Check for "else". */
756 if (i+4 <= n
757 && line[i+0] == 'e'
758 && line[i+1] == 'l'
759 && line[i+2] == 's'
760 && line[i+3] == 'e'
761 && (i+4 == n || is_whitespace(line[i+4]))) {
762 return TRUE;
763 }
764 return FALSE;
765 }
766
is_elif(const char * line)767 static const char* is_elif (const char* line)
768 {
769 uintL n = strlen(line);
770 uintL i = 0;
771 /* Skip whitespace. */
772 for (; i < n && is_whitespace(line[i]); i++) {}
773 /* Parse a '#'. */
774 if (i < n && line[i] == '#')
775 i++;
776 else
777 return NULL;
778 /* Skip whitespace. */
779 for (; i < n && is_whitespace(line[i]); i++) {}
780 /* Check for "elif". */
781 if (i+4 < n
782 && line[i+0] == 'e'
783 && line[i+1] == 'l'
784 && line[i+2] == 'i'
785 && line[i+3] == 'f'
786 && is_whitespace(line[i+4])) {
787 i += 5;
788 for (; i < n && is_whitespace(line[i]); i++) {}
789 for (; n > i && is_whitespace(line[n-1]); n--) {}
790 return substring(line,i,n);
791 }
792 return NULL;
793 }
794
is_endif(const char * line)795 static boolean is_endif (const char* line)
796 {
797 uintL n = strlen(line);
798 uintL i = 0;
799 /* Skip whitespace. */
800 for (; i < n && is_whitespace(line[i]); i++) {}
801 /* Parse a '#'. */
802 if (i < n && line[i] == '#')
803 i++;
804 else
805 return FALSE;
806 /* Skip whitespace. */
807 for (; i < n && is_whitespace(line[i]); i++) {}
808 /* Check for "endif". */
809 if (i+5 <= n
810 && line[i+0] == 'e'
811 && line[i+1] == 'n'
812 && line[i+2] == 'd'
813 && line[i+3] == 'i'
814 && line[i+4] == 'f'
815 && (i+5 == n || is_whitespace(line[i+5]))) {
816 return TRUE;
817 }
818 return FALSE;
819 }
820
821
822 /* Print a list (cond1 && cond2 && ...) to a stream. */
print_condition_part(FILE * stream,const VectorString * condition)823 static void print_condition_part (FILE* stream, const VectorString* condition)
824 {
825 uintL n = VectorString_length(condition);
826 if (n == 0) {
827 fprintf(stream,"1");
828 return;
829 }
830 if (n == 1) {
831 fprintf(stream,"%s",VectorString_element(condition,0));
832 return;
833 }
834 {
835 uintL i;
836 for (i = 0; i < n; i++) {
837 if (i > 0)
838 fprintf(stream," && ");
839 fprintf(stream,"(%s)",VectorString_element(condition,i));
840 }
841 }
842 }
843
844 /* Tests whether a condition is equivalent to 1 (true). */
is_true_condition_part(const VectorString * condition)845 static inline boolean is_true_condition_part (const VectorString* condition)
846 {
847 uintL n = VectorString_length(condition);
848 return (n == 0);
849 }
850
851 #ifdef unused
852 /* Print a list of lists (cond1 || cond2 || ...) to a stream. */
print_condition(FILE * stream,const VectorVectorString * condition)853 static void print_condition (FILE* stream, const VectorVectorString* condition)
854 {
855 uintL n = VectorVectorString_length(condition);
856 if (n == 0) {
857 fprintf(stream,"0");
858 return;
859 }
860 if (n == 1) {
861 print_condition_part(stream,VectorVectorString_element(condition,0));
862 return;
863 }
864 {
865 uintL i;
866 for (i = 0; i < n; i++) {
867 if (i > 0)
868 fprintf(stream," || ");
869 fprintf(stream,"(");
870 print_condition_part(stream,VectorVectorString_element(condition,i));
871 fprintf(stream,")");
872 }
873 }
874 }
875 #endif
876
877 #ifdef unused
878 /* Tests whether a condition is equivalent to 0 (false). */
is_false_condition(const VectorVectorString * condition)879 static inline boolean is_false_condition (const VectorVectorString* condition)
880 {
881 uintL n = VectorVectorString_length(condition);
882 return (n == 0);
883 }
884 #endif
885
886 #ifdef unused
887 /* Tests whether a condition is equivalent to 1 (true). */
is_true_condition(const VectorVectorString * condition)888 static boolean is_true_condition (const VectorVectorString* condition)
889 {
890 uintL n = VectorVectorString_length(condition);
891 uintL i;
892 for (i = 0; i < n; i++)
893 if (is_true_condition_part(VectorVectorString_element(condition,i)))
894 return TRUE;
895 return FALSE;
896 }
897 #endif
898
899
900 #ifdef unused
901 /* Read a line, or NULL if EOF is encountered. */
get_line(FILE * fp)902 static char* get_line (FILE* fp)
903 {
904 int len = 1;
905 char* line = (char*) xmalloc(len);
906 int index = 0;
907 while (1) {
908 int c = getc(fp);
909 if (c==EOF) { if (index>0) break; else { xfree(line); return NULL; } }
910 if (c=='\n') break;
911 if (index >= len-1) {
912 len = 2*len;
913 line = (char*) xrealloc(line,len);
914 }
915 line[index++] = c;
916 }
917 line[index] = '\0';
918 return line;
919 }
920 #endif
921
922
923 /* ============================== INPUT ============================== */
924
925 static FILE* infile;
926
927 static const char* input_filename = "(stdin)";
928
929 static uintL input_line;
930
in_char(void)931 static int in_char (void)
932 {
933 int c = getc(infile);
934 if (c=='\n')
935 input_line++;
936 return c;
937 }
938
peek_char(void)939 static int peek_char (void)
940 {
941 int c = getc(infile);
942 if (c != EOF)
943 ungetc(c,infile);
944 return c;
945 }
946
947
948 /* Decode a #line directive. If the line represents a #line directive,
949 return the line number. Else return -1. */
950
decode_line_directive(const char * line)951 static int decode_line_directive (const char* line)
952 {
953 uintL n = strlen(line);
954 uintL i = 0;
955 /* Skip whitespace. */
956 for (; i < n && is_whitespace(line[i]); i++) {}
957 /* Parse a '#'. */
958 if (i < n && line[i] == '#')
959 i++;
960 else
961 return -1;
962 /* Skip whitespace. */
963 for (; i < n && is_whitespace(line[i]); i++) {}
964 /* Check for "line". */
965 if (i+4 < n
966 && line[i+0] == 'l'
967 && line[i+1] == 'i'
968 && line[i+2] == 'n'
969 && line[i+3] == 'e'
970 && is_whitespace(line[i+4])) {
971 i += 4;
972 for (; i < n && is_whitespace(line[i]); i++) {}
973 }
974 /* Check for a digit. */
975 if (!(i < n && is_digit(line[i])))
976 return -1;
977 { uintL i1 = i;
978 for (; i < n && is_digit(line[i]); i++) {}
979 { uintL i2 = i;
980 /* Convert digit string to a `long'. */
981 char* digits = substring(line,i1,i2);
982 errno = 0;
983 { long result = strtol(digits,NULL,10);
984 xfree(digits);
985 if (errno != 0) return -1;
986 if (result < 0) abort();
987 /* Check for a source file name. */
988 for (; i < n && is_whitespace(line[i]); i++) {}
989 if (i < n && line[i] == '"') {
990 uintL i3;
991 i++;
992 i3 = i;
993 for (; i < n && line[i] != '"'; i++) {}
994 if (i < n && line[i] == '"') {
995 uintL i4 = i;
996 input_filename = substring(line,i3,i4);
997 }
998 }
999 return result;
1000 } } } }
1001
1002
1003 /* ============================== OUTPUT ============================= */
1004
1005 static FILE* outfile;
1006
1007 /* Output can be buffered for a while. */
1008 enum out_mode { direct, buffered };
1009 #define MAXHEADERLEN 5000
1010 static struct {
1011 enum out_mode mode;
1012 uintB buffer[MAXHEADERLEN];
1013 uintL buffindex;
1014 } out;
1015
char_out(uintB c)1016 static inline void char_out (uintB c)
1017 {
1018 putc(c,outfile);
1019 }
1020
1021 /* Turn off output buffering. */
outbuffer_off(void)1022 static void outbuffer_off (void)
1023 {
1024 if (out.mode==buffered) {
1025 uintL index = 0;
1026 while (index < out.buffindex) {
1027 char_out(out.buffer[index]); index++;
1028 }
1029 out.mode = direct;
1030 }
1031 }
1032
1033 /* Turn off output buffering, inserting a string at a given place. */
outbuffer_off_insert(uintL insertpoint,const char * insert)1034 static void outbuffer_off_insert (uintL insertpoint, const char* insert)
1035 {
1036 if (out.mode==buffered) {
1037 uintL index = 0;
1038 while (1) {
1039 if (index==insertpoint) {
1040 while (!(*insert==0)) {
1041 char_out(*insert++);
1042 }
1043 }
1044 if (index == out.buffindex)
1045 break;
1046 char_out(out.buffer[index]); index++;
1047 }
1048 out.mode = direct;
1049 }
1050 }
1051
1052 /* Turn on output buffering. */
outbuffer_on(void)1053 static void outbuffer_on (void)
1054 {
1055 if (out.mode==direct) {
1056 out.buffindex = 0;
1057 out.mode = buffered;
1058 }
1059 }
1060
1061 /* Output a character. */
out_char(int c)1062 static void out_char (int c)
1063 {
1064 if (out.mode==buffered) {
1065 if (out.buffindex < MAXHEADERLEN)
1066 out.buffer[out.buffindex++] = c;
1067 else {
1068 /* Buffer full -> turn it off */
1069 outbuffer_off(); char_out(c);
1070 }
1071 } else {
1072 char_out(c);
1073 }
1074 }
1075
1076 /* Output a line. */
out_line(const char * line)1077 static void out_line (const char* line)
1078 {
1079 for (; *line != '\0'; line++)
1080 out_char(*line);
1081 out_char('\n');
1082 }
1083
1084
1085 /* =========================== MAIN PROGRAM ========================== */
1086
next_char(void)1087 static int next_char (void)
1088 {
1089 int c = in_char();
1090 if (c != EOF)
1091 out_char(c);
1092 return c;
1093 }
1094
next_line(void)1095 static char* next_line (void)
1096 {
1097 int len = 1;
1098 char* line = (char*) xmalloc(len);
1099 int index = 0;
1100 while (1) {
1101 int c = next_char();
1102 if (c==EOF) { if (index>0) break; else { xfree(line); return NULL; } }
1103 if (c=='\n') break;
1104 if (index >= len-1) {
1105 len = 2*len;
1106 line = (char*) xrealloc(line,len);
1107 }
1108 line[index++] = c;
1109 }
1110 line[index] = '\0';
1111 return line;
1112 }
1113
1114
1115 /* Sadly, #line directives output during a skipped portion of #if are ignored
1116 by the C preprocessor. Therefore we must re-output them after every
1117 #else/#elif/#endif line that belongs to a #if that was in effect when the
1118 line directive was seen. */
1119
1120 /* The maximum #if level that needs repeated #line directives.
1121 This is always <= StackVectorString_length(ifdef_stack). */
1122 static uintL ifdef_line_repeat;
1123
1124 /* Emit a #line note after the line number in the outfile has changed
1125 differently from the line number in the infile. */
line_emit(void)1126 static inline void line_emit (void)
1127 {
1128 fprintf(outfile,"#line %ld\n",input_line);
1129 if (ifdef_line_repeat < StackVectorString_length(ifdef_stack))
1130 ifdef_line_repeat = StackVectorString_length(ifdef_stack);
1131 }
1132
1133 /* #line treatment for the #if[def] stack. */
1134
line_repeat_else()1135 static inline void line_repeat_else ()
1136 {
1137 if (ifdef_line_repeat == StackVectorString_length(ifdef_stack)) {
1138 char buf[20];
1139 sprintf(buf,"#line %ld",input_line);
1140 out_line(buf);
1141 }
1142 }
1143
line_repeat_endif()1144 static inline void line_repeat_endif ()
1145 {
1146 if (ifdef_line_repeat > StackVectorString_length(ifdef_stack)) {
1147 char buf[20];
1148 sprintf(buf,"#line %ld",input_line);
1149 out_line(buf);
1150 ifdef_line_repeat--;
1151 }
1152 }
1153
1154
1155 enum token_type { eof, ident, number, charconst, stringconst, sep, expr };
1156 typedef struct {
1157 enum token_type type;
1158 /* if buffered: */
1159 uintL startindex;
1160 uintL endindex;
1161 /* if type==sep (operator or separator): */
1162 uintB ch;
1163 } Token;
1164
next_token(void)1165 static Token next_token (void)
1166 {
1167 Token token;
1168 restart:
1169 outbuffer_off();
1170 outbuffer_on();
1171 token.startindex = out.buffindex;
1172 {
1173 int c = next_char();
1174 switch (c) {
1175 case EOF:
1176 /* EOF */
1177 token.type = eof;
1178 goto done;
1179 case ' ': case '\v': case '\t': case '\n':
1180 /* whitespace, ignore */
1181 goto restart;
1182 case '\\':
1183 if (peek_char()=='\n') {
1184 /* backslash newline, ignore */
1185 next_char();
1186 goto restart;
1187 }
1188 goto separator;
1189 case '/':
1190 if (peek_char() == '*') {
1191 /* Comment */
1192 next_char();
1193 while (1) {
1194 c = next_char();
1195 if (c==EOF) {
1196 fprintf(stderr,"Unfinished comment\n");
1197 break;
1198 }
1199 if ((c=='*') && (peek_char()=='/')) {
1200 next_char();
1201 break;
1202 }
1203 }
1204 goto restart;
1205 }
1206 goto separator;
1207 case '*':
1208 if (peek_char() == '/')
1209 fprintf(stderr,"End of comment outside comment in line %lu\n",input_line);
1210 goto separator;
1211 case '#':
1212 /* preprocessor directive */
1213 {
1214 char* line = next_line();
1215 if (line) {
1216 char* old_line = line;
1217 line = concat2("#",line);
1218 xfree(old_line);
1219 } else {
1220 line = concat1("#");
1221 }
1222 for (;;) {
1223 boolean need_another_line = FALSE;
1224 if (line[strlen(line)-1] == '\\') {
1225 need_another_line = TRUE;
1226 } else {
1227 switch (parsing_state_at_end_of_line (line)) {
1228 case STATE_INITIAL:
1229 break;
1230 case STATE_IN_CHARACTER_LITERAL:
1231 fprintf(stderr,"End of preprocessor line within character literal in line %lu\n",input_line);
1232 break;
1233 case STATE_IN_STRING_LITERAL:
1234 fprintf(stderr,"End of preprocessor line within string literal in line %lu\n",input_line);
1235 break;
1236 case STATE_IN_C_COMMENT:
1237 need_another_line = TRUE;
1238 break;
1239 case STATE_IN_CXX_COMMENT:
1240 break;
1241 }
1242 }
1243 if (need_another_line) {
1244 char* continuation_line = next_line();
1245 line[strlen(line)-1] = '\0';
1246 if (continuation_line) {
1247 char* old_line = line;
1248 line = concat2(line,continuation_line);
1249 xfree(old_line);
1250 xfree(continuation_line);
1251 }
1252 } else
1253 break;
1254 }
1255 {
1256 const char* condition;
1257 long line_directive;
1258 if ((condition = is_if(line)) != NULL) {
1259 do_if(condition);
1260 } else if (is_else(line)) {
1261 do_else();
1262 line_repeat_else();
1263 } else if ((condition = is_elif(line)) != NULL) {
1264 do_elif(condition);
1265 line_repeat_else();
1266 } else if (is_endif(line)) {
1267 do_endif();
1268 line_repeat_endif();
1269 } else if ((line_directive = decode_line_directive(line)) >= 0)
1270 input_line = line_directive;
1271 #ifdef SPLIT_OBJECT_INITIALIZATIONS
1272 else {
1273 /* Replace "var object foo = ..." with "var object foo; foo = ..."
1274 in macros as well. */
1275 if (out.buffindex < MAXHEADERLEN) {
1276 uintB* p;
1277 out.buffer[out.buffindex] = '\0';
1278 for (p = &out.buffer[token.startindex]; ; p++) {
1279 p = (uintB*) strstr((char*)p,"var ");
1280 if (p == NULL)
1281 break;
1282 if ((strncmp((char*)p,"var object ",
1283 strlen("var object "))==0
1284 || strncmp((char*)p,"var chart ",
1285 strlen("var chart "))==0)
1286 && (p[-1] == ' ' || p[-1] == '{')) {
1287 if (strncmp((char*)p,"var object ",
1288 strlen("var object "))==0)
1289 p += strlen("var object ");
1290 else if (strncmp((char*)p,"var chart ",
1291 strlen("var chart "))==0)
1292 p += strlen("var chart ");
1293 { uintB* q = p;
1294 if ((*q >= 'A' && *q <= 'Z')
1295 || (*q >= 'a' && *q <= 'z')
1296 || *q == '_') {
1297 do q++;
1298 while ((*q >= 'A' && *q <= 'Z')
1299 || (*q >= 'a' && *q <= 'z')
1300 || (*q >= '0' && *q <= '9')
1301 || *q == '_');
1302 while (*q == ' ')
1303 q++;
1304 if (*q == '=') {
1305 uintL insertlen = 2+(q-p);
1306 if (out.buffindex + insertlen < MAXHEADERLEN) {
1307 memmove(q+insertlen,q,
1308 &out.buffer[out.buffindex]-q+1);
1309 q[0] = ';'; q[1] = ' ';
1310 memcpy(q+2, p, q-p);
1311 out.buffindex += insertlen;
1312 }
1313 }
1314 }
1315 }
1316 }
1317 }
1318 }
1319 }
1320 #endif
1321 }
1322 xfree(line);
1323 }
1324 goto separator;
1325 case '.':
1326 c = peek_char();
1327 if (!(((c>='0') && (c<='9')) || (c=='.')))
1328 goto separator;
1329 case '0': case '1': case '2': case '3': case '4':
1330 case '5': case '6': case '7': case '8': case '9':
1331 /* Digit. Continue reading as long as alphanumeric or '.'. */
1332 while (1) {
1333 c = peek_char();
1334 if (((c>='0') && (c<='9')) || ((c>='A') && (c<='Z')) || ((c>='a') && (c<='z')) || (c=='.'))
1335 next_char();
1336 else
1337 break;
1338 }
1339 token.type = number;
1340 goto done;
1341 case '\'':
1342 /* Character constant */
1343 while (1) {
1344 c = next_char();
1345 if (c==EOF) {
1346 fprintf(stderr,"Unterminated character constant\n");
1347 break;
1348 }
1349 if (c=='\'')
1350 break;
1351 if (c=='\\')
1352 c = next_char();
1353 }
1354 token.type = charconst;
1355 goto done;
1356 case '\"':
1357 /* String constant */
1358 while (1) {
1359 c = next_char();
1360 if (c==EOF) {
1361 fprintf(stderr,"Unterminated string constant\n");
1362 break;
1363 }
1364 if (c=='\"')
1365 break;
1366 if (c=='\\')
1367 c = next_char();
1368 }
1369 token.type = stringconst;
1370 goto done;
1371 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
1372 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
1373 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
1374 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
1375 case 'Y': case 'Z':
1376 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
1377 case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
1378 case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
1379 case 's': case 't': case 'u': case 'v': case 'w': case 'x':
1380 case 'y': case 'z':
1381 case '_':
1382 /* Identifier. */
1383 while (1) {
1384 c = peek_char();
1385 if (((c>='0') && (c<='9')) || ((c>='A') && (c<='Z')) || ((c>='a') && (c<='z')) || (c=='_'))
1386 next_char();
1387 else
1388 break;
1389 }
1390 token.type = ident;
1391 goto done;
1392 default:
1393 separator:
1394 token.type = sep;
1395 token.ch = c;
1396 goto done;
1397 }
1398 }
1399 done:
1400 token.endindex = out.buffindex;
1401 return token;
1402 }
1403
1404 #define MAXBRACES 1000
1405 static struct {
1406 uintL count;
1407 struct {
1408 uintB brace_type;
1409 uintL input_line;
1410 VectorString* condition;
1411 VectorVectorString* pending_conditions;
1412 } opening[MAXBRACES];
1413 } open_braces;
1414
convert(FILE * infp,FILE * outfp,const char * infilename)1415 static void convert (FILE* infp, FILE* outfp, const char* infilename)
1416 {
1417 /* Initialize input variables. */
1418 infile = infp;
1419 input_line = 1;
1420 /* Initialize output variables. */
1421 outfile = outfp;
1422 /* Initialize other variables. */
1423 ifdef_stack = make_StackVectorString();
1424 ifdef_line_repeat = 0;
1425 /* Go! */
1426 if (infilename != NULL)
1427 fprintf(outfile,"#line 1 \"%s\"\n",infilename);
1428 {boolean last_token_was_ident = FALSE;
1429 #ifdef SPLIT_OBJECT_INITIALIZATIONS
1430 boolean seen_var = FALSE;
1431 boolean seen_var_object = FALSE;
1432 boolean seen_var_object_ident = FALSE;
1433 uintL last_ident_len = 0;
1434 uintB last_ident_buf[256];
1435 #endif
1436 while (1) {
1437 Token token = next_token();
1438 switch (token.type) {
1439 case eof:
1440 if (open_braces.count > 0) {
1441 if (open_braces.count <= MAXBRACES) {
1442 fprintf(stderr,"Unclosed '%c' in line %lu\n",
1443 open_braces.opening[open_braces.count-1].brace_type,
1444 open_braces.opening[open_braces.count-1].input_line
1445 );
1446 } else
1447 fprintf(stderr,"Unclosed '(' or '{' or '['\n");
1448 }
1449 return;
1450 case sep:
1451 switch (token.ch) {
1452 case '(': case '{': case '[':
1453 if (open_braces.count < MAXBRACES) {
1454 open_braces.opening[open_braces.count].brace_type = token.ch;
1455 open_braces.opening[open_braces.count].input_line = input_line;
1456 if (token.ch == '{') {
1457 open_braces.opening[open_braces.count].condition = current_condition();
1458 open_braces.opening[open_braces.count].pending_conditions = make_VectorVectorString();
1459 }
1460 }
1461 open_braces.count++;
1462 break;
1463 case ')': case '}': case ']':
1464 if (open_braces.count > 0) {
1465 open_braces.count--;
1466 if (open_braces.count < MAXBRACES) {
1467 uintL opening_line = open_braces.opening[open_braces.count].input_line;
1468 uintL closing_line = input_line;
1469 uintB opening_ch = open_braces.opening[open_braces.count].brace_type;
1470 uintB closing_ch = token.ch;
1471 if (!( ((opening_ch == '(') && (closing_ch == ')'))
1472 || ((opening_ch == '{') && (closing_ch == '}'))
1473 || ((opening_ch == '[') && (closing_ch == ']'))
1474 ) )
1475 fprintf(stderr,"Opening delimiter '%c' in line %lu\n and closing delimiter '%c' in line %lu\n don't match.\n",
1476 opening_ch,opening_line,
1477 closing_ch,closing_line
1478 );
1479 if ((opening_ch == '{') && (closing_ch == '}')) {
1480 const VectorString* opening_condition = open_braces.opening[open_braces.count].condition;
1481 const VectorString* closing_condition = current_condition();
1482 if (VectorString_equals(opening_condition,closing_condition)) {
1483 const VectorVectorString* conditions = open_braces.opening[open_braces.count].pending_conditions;
1484 boolean did_newline = FALSE;
1485 boolean in_fresh_line = FALSE;
1486 uintL i;
1487 for (i = VectorVectorString_length(conditions); i > 0; ) {
1488 const VectorString* condition = VectorVectorString_element(conditions,--i);
1489 condition = modulo_current_condition(condition);
1490 if (!is_true_condition_part(condition)) {
1491 if (!in_fresh_line) {
1492 fprintf(outfile,"\n");
1493 in_fresh_line = TRUE;
1494 }
1495 fprintf(outfile,"#if ");
1496 print_condition_part(outfile,condition);
1497 fprintf(outfile,"\n}\n#endif\n");
1498 did_newline = TRUE;
1499 } else {
1500 fprintf(outfile,"}");
1501 in_fresh_line = FALSE;
1502 }
1503 }
1504 if (did_newline) {
1505 if (!in_fresh_line) {
1506 fprintf(outfile,"\n");
1507 in_fresh_line = TRUE;
1508 }
1509 line_emit();
1510 }
1511 } else {
1512 fprintf(stderr,"Opening brace '%c' in line %lu: #if ",opening_ch,opening_line);
1513 print_condition_part(stderr,opening_condition);
1514 fprintf(stderr,"\n and closing brace '%c' in line %lu: #if ",closing_ch,closing_line);
1515 print_condition_part(stderr,closing_condition);
1516 fprintf(stderr,"\n don't match.\n");
1517 }
1518 }
1519 }
1520 } else {
1521 fprintf(stderr,"No opening delimiter for closing delimiter '%c' in line %lu\n",
1522 token.ch,input_line
1523 );
1524 }
1525 break;
1526 default:
1527 break;
1528 }
1529 #ifdef SPLIT_OBJECT_INITIALIZATIONS
1530 if (token.ch == '=' && seen_var_object_ident) {
1531 out.buffer[token.startindex] = ';';
1532 outbuffer_off();
1533 fwrite(last_ident_buf,1,last_ident_len,outfile);
1534 fputs(" =",outfile);
1535 }
1536 seen_var = FALSE;
1537 seen_var_object = FALSE;
1538 seen_var_object_ident = FALSE;
1539 #endif
1540 break;
1541 case ident:
1542 #ifdef SPLIT_OBJECT_INITIALIZATIONS
1543 if ((token.endindex - token.startindex == 3)
1544 && (out.buffer[token.startindex ] == 'v')
1545 && (out.buffer[token.startindex+1] == 'a')
1546 && (out.buffer[token.startindex+2] == 'r')) {
1547 seen_var = TRUE;
1548 seen_var_object = FALSE;
1549 seen_var_object_ident = FALSE;
1550 } else if (seen_var
1551 && (((token.endindex - token.startindex == 6)
1552 && (out.buffer[token.startindex ] == 'o')
1553 && (out.buffer[token.startindex+1] == 'b')
1554 && (out.buffer[token.startindex+2] == 'j')
1555 && (out.buffer[token.startindex+3] == 'e')
1556 && (out.buffer[token.startindex+4] == 'c')
1557 && (out.buffer[token.startindex+5] == 't'))
1558 || ((token.endindex - token.startindex == 5)
1559 && (out.buffer[token.startindex ] == 'c')
1560 && (out.buffer[token.startindex+1] == 'h')
1561 && (out.buffer[token.startindex+2] == 'a')
1562 && (out.buffer[token.startindex+3] == 'r')
1563 && (out.buffer[token.startindex+4] == 't')))) {
1564 seen_var = FALSE;
1565 seen_var_object = TRUE;
1566 seen_var_object_ident = FALSE;
1567 } else if (seen_var_object
1568 && (token.endindex - token.startindex <= sizeof(last_ident_buf))) {
1569 seen_var = FALSE;
1570 seen_var_object = FALSE;
1571 seen_var_object_ident = TRUE;
1572 last_ident_len = token.endindex - token.startindex;
1573 memcpy(last_ident_buf,&out.buffer[token.startindex],last_ident_len);
1574 }
1575 #endif
1576 if (!last_token_was_ident /* to avoid cases like "local var x = ...;" */
1577 && (token.endindex - token.startindex == 3)
1578 && (out.buffer[token.startindex ] == 'v')
1579 && (out.buffer[token.startindex+1] == 'a')
1580 && (out.buffer[token.startindex+2] == 'r')
1581 ) {
1582 uintL braceindex;
1583 for (braceindex = open_braces.count; braceindex > 0; ) {
1584 braceindex--;
1585 if (open_braces.opening[braceindex].brace_type == '{') {
1586 VectorVectorString_add(open_braces.opening[braceindex].pending_conditions,current_condition());
1587 outbuffer_off_insert(token.startindex,"{");
1588 break;
1589 }
1590 }
1591 }
1592 break;
1593 default:
1594 #ifdef SPLIT_OBJECT_INITIALIZATIONS
1595 seen_var = FALSE;
1596 seen_var_object = FALSE;
1597 seen_var_object_ident = FALSE;
1598 #endif
1599 break;
1600 }
1601 outbuffer_off();
1602 last_token_was_ident = (token.type == ident);
1603 }
1604 }}
1605
main(int argc,char * argv[])1606 int main (int argc, char* argv[])
1607 {
1608 char* infilename;
1609 FILE* infile;
1610 FILE* outfile;
1611 /* Argument parsing. */
1612 if (argc == 2) {
1613 infilename = argv[1];
1614 infile = fopen(infilename,"r");
1615 if (infile == NULL)
1616 exit(1);
1617 input_filename = infilename;
1618 } else if (argc == 1) {
1619 infilename = NULL;
1620 infile = stdin;
1621 } else
1622 exit(1);
1623 outfile = stdout;
1624 /* Main job. */
1625 convert(infile,outfile,infilename);
1626 /* Clean up. */
1627 if (ferror(infile) || ferror(outfile) || fclose(outfile))
1628 exit(1);
1629 exit(0);
1630 }
1631
1632