1 /*=========================================================================
3 Program: Visualization Toolkit
4 Module: vtkParsePreprocess.c
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
14 =========================================================================*/
15 /*-------------------------------------------------------------------------
16 Copyright (c) 2010 David Gobbi.
18 Contributed to the VisualizationToolkit by the author in June 2010
19 under the terms of the Visualization Toolkit 2008 copyright.
20 -------------------------------------------------------------------------*/
22 #include "vtkParsePreprocess.h"
30 This file handles preprocessor directives via a simple
31 recursive-descent parser that only evaluates integers.
34 #define PREPROC_DEBUG 0
36 /** Block size for reading files */
37 #define FILE_BUFFER_SIZE 8192
39 /** Size of hash table must be a power of two */
40 #define PREPROC_HASH_TABLE_SIZE 1024u
42 /** Hashes for preprocessor keywords */
43 #define HASH_IFDEF 0x0fa4b283u
44 #define HASH_IFNDEF 0x04407ab1u
45 #define HASH_IF 0x00597834u
46 #define HASH_ELIF 0x7c964b25u
47 #define HASH_ELSE 0x7c964c6eu
48 #define HASH_ENDIF 0x0f60b40bu
49 #define HASH_DEFINED 0x088998d4u
50 #define HASH_DEFINE 0xf8804a70u
51 #define HASH_UNDEF 0x10823b97u
52 #define HASH_INCLUDE 0x9e36af89u
53 #define HASH_ERROR 0x0f6321efu
54 #define HASH_LINE 0x7c9a15adu
55 #define HASH_PRAGMA 0x1566a9fdu
57 /** Various possible char types */
58 #define CPRE_ID 0x01 /* A-Z a-z and _ */
59 #define CPRE_DIGIT 0x02 /* 0-9 */
60 #define CPRE_IDGIT 0x03 /* 0-9 A-Z a-z and _ */
61 #define CPRE_HEX 0x04 /* 0-9A-Fa-f */
62 #define CPRE_EXP 0x08 /* EPep (exponents for floats) */
63 #define CPRE_SIGN 0x10 /* +- (sign for floats) */
64 #define CPRE_QUOTE 0x20 /* " and ' */
65 #define CPRE_HSPACE 0x40 /* space, tab, carriage return */
66 #define CPRE_VSPACE 0x80 /* newline, vertical tab, form feed */
67 #define CPRE_WHITE 0xC0 /* all whitespace characters */
70 * WS_NO_EOL treats newline as end-of-line, instead of whitespace.
71 * WS_ALL treats newlines as regular whitespace.
72 * WS_COMMENT does not treat comments as whitespace, allowing
73 * comments blocks to be returned as tokens. */
74 typedef enum _preproc_space_t
76 WS_NO_EOL = CPRE_HSPACE, /* skip horizontal whitespace only */
77 WS_ALL = CPRE_WHITE, /* skip all whitespace */
78 WS_COMMENT = (CPRE_WHITE | 0x100), /* comments as tokens */
81 /** Preprocessor tokens. */
82 typedef enum _preproc_token_t
86 TOK_CHAR, /* char literal */
87 TOK_STRING, /* string literal */
88 TOK_NUMBER, /* any numeric literal */
89 TOK_COMMENT, /* C or C++ comment */
111 TOK_DOT_STAR, /* .* */
112 TOK_ARROW_STAR,/* ->* */
113 TOK_RSHIFT_EQ, /* >>= */
114 TOK_LSHIFT_EQ, /* <<= */
115 TOK_ELLIPSIS, /* ... */
118 /** A struct for going through the input one token at a time. */
119 typedef struct _preproc_tokenizer
127 /** Extend dynamic arrays in a progression of powers of two.
128 * Whenever "n" reaches a power of two, then the array size is
129 * doubled so that "n" can be safely incremented. */
130 static void *preproc_array_check(
131 void *arraymem, size_t size, int n)
133 /* if empty, alloc for the first time */
138 /* if count is power of two, reallocate with double size */
139 else if ((n & (n-1)) == 0)
141 return realloc(arraymem, (n << 1)*size);
144 /* no reallocation, just return the original array */
148 /** Convert string to int. */
149 static preproc_int_t string_to_preproc_int(const char *cp, int base)
151 #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
152 return _strtoi64(cp, NULL, base);
154 return strtoll(cp, NULL, base);
158 /** Convert string to unsigned int. */
159 static preproc_uint_t string_to_preproc_uint(const char *cp, int base)
161 #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
162 return _strtoui64(cp, NULL, base);
164 return strtoull(cp, NULL, base);
168 /** Array for quick lookup of char types */
169 static unsigned char preproc_charbits[] = {
170 0, 0, 0, 0, 0, 0, 0, 0, 0,
171 CPRE_HSPACE, /* tab */
172 CPRE_VSPACE, CPRE_VSPACE, CPRE_VSPACE, /* newline, vtab, form feed */
173 CPRE_HSPACE, /* carriage return */
174 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
175 CPRE_HSPACE, /* ' ' */
176 0, CPRE_QUOTE, 0, 0, 0, 0, CPRE_QUOTE, 0, 0, /* !"#$%&'() */
177 0, CPRE_SIGN, 0, CPRE_SIGN, 0, 0, /* *+,-./ */
178 CPRE_DIGIT|CPRE_HEX, /* 0 */
179 CPRE_DIGIT|CPRE_HEX, CPRE_DIGIT|CPRE_HEX,
180 CPRE_DIGIT|CPRE_HEX, CPRE_DIGIT|CPRE_HEX,
181 CPRE_DIGIT|CPRE_HEX, CPRE_DIGIT|CPRE_HEX,
182 CPRE_DIGIT|CPRE_HEX, CPRE_DIGIT|CPRE_HEX,
183 CPRE_DIGIT|CPRE_HEX, /* 9 */
184 0, 0, 0, 0, 0, 0, 0, /* :;<=>?@ */
185 CPRE_ID|CPRE_HEX, /* A */
186 CPRE_ID|CPRE_HEX, CPRE_ID|CPRE_HEX, CPRE_ID|CPRE_HEX, /* BCD */
187 CPRE_ID|CPRE_HEX|CPRE_EXP, /* E */
188 CPRE_ID|CPRE_HEX, CPRE_ID, CPRE_ID, CPRE_ID, /* FGHI */
189 CPRE_ID, CPRE_ID, CPRE_ID, CPRE_ID, /* JKLM */
190 CPRE_ID, CPRE_ID, CPRE_ID|CPRE_EXP, CPRE_ID, /* NOPQ */
191 CPRE_ID, CPRE_ID, CPRE_ID, CPRE_ID, /* RSTU */
192 CPRE_ID, CPRE_ID, CPRE_ID, CPRE_ID, /* VWXY */
194 0, 0, 0, 0, /* [\\]^ */
197 CPRE_ID|CPRE_HEX, /* a */
198 CPRE_ID|CPRE_HEX, CPRE_ID|CPRE_HEX, CPRE_ID|CPRE_HEX, /* bcd */
199 CPRE_ID|CPRE_HEX|CPRE_EXP, /* e */
200 CPRE_ID|CPRE_HEX, CPRE_ID, CPRE_ID, CPRE_ID, /* fghi */
201 CPRE_ID, CPRE_ID, CPRE_ID, CPRE_ID, /* jklm */
202 CPRE_ID, CPRE_ID, CPRE_ID|CPRE_EXP, CPRE_ID, /* nopq */
203 CPRE_ID, CPRE_ID, CPRE_ID, CPRE_ID, /* rstu */
204 CPRE_ID, CPRE_ID, CPRE_ID, CPRE_ID, /* vwxy */
206 0, 0, 0, 0, /* {|}~ */
208 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
209 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
210 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
211 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
214 /** Macro to get char type */
215 #define preproc_chartype(c, bits) \
216 ((preproc_charbits[(unsigned char)(c)] & bits) != 0)
218 /** Skip over a comment. */
219 static void preproc_skip_comment(const char **cpp)
221 const char *cp = *cpp;
228 while (*cp != '\n' && *cp != '\0')
232 if (cp[1] == '\n') { cp++; }
233 else if (cp[1] == '\r' && cp[2] == '\n') { cp += 2; }
238 else if (cp[1] == '*')
243 if (cp[0] == '*' && cp[1] == '/') { cp += 2; break; }
252 /** Skip over whitespace, but not newlines unless preceded by backlash. */
253 static void preproc_skip_whitespace(
254 const char **cpp, preproc_space_t spacetype)
256 const char *cp = *cpp;
260 if (preproc_chartype(*cp, spacetype))
266 while (preproc_chartype(*cp, spacetype));
274 else if (cp[1] == '\r' && cp[2] == '\n')
283 else if (cp[0] == '/' && (spacetype & WS_COMMENT) != WS_COMMENT)
285 if (cp[1] == '/' || cp[1] == '*')
287 preproc_skip_comment(&cp);
303 /** Skip over string and char literals. */
304 static void preproc_skip_quotes(const char **cpp)
306 const char *cp = *cpp;
309 if (preproc_chartype(*cp, CPRE_QUOTE))
312 while (*cp != qc && *cp != '\n' && *cp != '\0')
316 if (cp[0] == '\r' && cp[1] == '\n') { cp += 2; }
317 else if (*cp != '\0') { cp++; }
329 /** Skip over a name. */
330 static void preproc_skip_name(const char **cpp)
332 const char *cp = *cpp;
334 if (preproc_chartype(*cp, CPRE_ID))
340 while (preproc_chartype(*cp, CPRE_IDGIT));
346 /** A simple 32-bit hash function based on "djb2". */
347 static unsigned int preproc_hash_name(const char **cpp)
349 const char *cp = (*cpp);
352 if (preproc_chartype(*cp, CPRE_ID))
354 do { h = (h << 5) + h + (unsigned char)*cp++; }
355 while (preproc_chartype(*cp, CPRE_IDGIT));
362 /** Skip over a number. */
363 static void preproc_skip_number(const char **cpp)
365 const char *cp = *cpp;
367 if (preproc_chartype(cp[0], CPRE_DIGIT) ||
368 (cp[0] == '.' && preproc_chartype(cp[1], CPRE_DIGIT)))
373 if (preproc_chartype(c, CPRE_EXP) &&
374 preproc_chartype(*cp, CPRE_SIGN))
379 while (preproc_chartype(*cp, CPRE_IDGIT) || *cp == '.');
385 /** Return the next preprocessor token, or '0' if none left. */
386 static int preproc_next(preproc_tokenizer *tokens)
388 const char *cp = tokens->text + tokens->len;
389 preproc_skip_whitespace(&cp, WS_NO_EOL);
391 if (preproc_chartype(*cp, CPRE_ID))
394 unsigned int h = preproc_hash_name(&ep);
395 tokens->tok = TOK_ID;
398 tokens->len = ep - cp;
400 else if (preproc_chartype(*cp, CPRE_QUOTE))
403 preproc_skip_quotes(&ep);
404 tokens->tok = (*cp == '\"' ? TOK_STRING : TOK_CHAR);
407 tokens->len = ep - cp;
409 else if (preproc_chartype(*cp, CPRE_DIGIT) ||
410 (cp[0] == '.' && preproc_chartype(cp[1], CPRE_DIGIT)))
413 preproc_skip_number(&ep);
414 tokens->tok = TOK_NUMBER;
417 tokens->len = ep - cp;
419 else if (cp[0] == '/' && (cp[1] == '/' || cp[1] == '*'))
422 preproc_skip_comment(&ep);
423 tokens->tok = TOK_COMMENT;
426 tokens->len = ep - cp;
436 if (cp[1] == ':') { l = 2; t = TOK_SCOPE; }
439 if (cp[1] == '.' && cp[2] == '.') { l = 3; t = TOK_ELLIPSIS; }
440 else if (cp[1] == '*') { l = 2; t = TOK_DOT_STAR; }
443 if (cp[1] == '=') { l = 2; t = TOK_EQ; }
446 if (cp[1] == '=') { l = 2; t = TOK_NE; }
449 if (cp[1] == '<' && cp[2] == '=') { l = 3; t = TOK_LSHIFT_EQ; }
450 else if (cp[1] == '<') { l = 2; t = TOK_LSHIFT; }
451 else if (cp[1] == '=') { l = 2; t = TOK_LE; }
454 if (cp[1] == '>' && cp[2] == '=') { l = 3; t = TOK_RSHIFT_EQ; }
455 else if (cp[1] == '>') { l = 2; t = TOK_RSHIFT; }
456 else if (cp[1] == '=') { l = 2; t = TOK_GE; }
459 if (cp[1] == '=') { l = 2; t = TOK_AND_EQ; }
460 else if (cp[1] == '&') { l = 2; t = TOK_AND; }
463 if (cp[1] == '=') { l = 2; t = TOK_OR_EQ; }
464 else if (cp[1] == '|') { l = 2; t = TOK_OR; }
467 if (cp[1] == '=') { l = 2; t = TOK_XOR_EQ; }
470 if (cp[1] == '=') { l = 2; t = TOK_MUL_EQ; }
473 if (cp[1] == '=') { l = 2; t = TOK_DIV_EQ; }
476 if (cp[1] == '=') { l = 2; t = TOK_MOD_EQ; }
479 if (cp[1] == '+') { l = 2; t = TOK_INCR; }
480 else if (cp[1] == '=') { l = 2; t = TOK_ADD_EQ; }
483 if (cp[1] == '>' && cp[2] == '*') { l = 3; t = TOK_ARROW_STAR; }
484 else if (cp[1] == '>') { l = 2; t = TOK_ARROW; }
485 else if (cp[1] == '-') { l = 2; t = TOK_DECR; }
486 else if (cp[1] == '=') { l = 2; t = TOK_SUB_EQ; }
489 if (cp[1] == '#') { l = 2; t = TOK_DBLHASH; }
506 /** Initialize the tokenizer. */
507 static void preproc_init(preproc_tokenizer *tokens, const char *text)
513 preproc_next(tokens);
516 /** Tokenize and compare two strings */
517 static int preproc_identical(const char *text1, const char *text2)
527 preproc_tokenizer t1;
528 preproc_tokenizer t2;
530 preproc_init(&t1, text1);
531 preproc_init(&t2, text2);
535 if (t1.tok != t2.tok ||
536 t1.hash != t2.hash ||
538 strncmp(t1.text, t2.text, t1.len) != 0)
545 while (t1.tok && t2.tok);
547 result = (t1.tok == 0 && t2.tok == 0);
554 /** Duplicate the first n bytes of a string. */
555 static const char *preproc_strndup(const char *in, size_t n)
559 res = (char *)malloc(n+1);
566 /** Create a new preprocessor macro. */
567 static MacroInfo *preproc_new_macro(
568 PreprocessInfo *info, const char *name, const char *definition)
570 MacroInfo *macro = (MacroInfo *)malloc(sizeof(MacroInfo));
571 vtkParsePreprocess_InitMacro(macro);
576 const char *cp = name;
577 preproc_skip_name(&cp);
579 macro->Name = preproc_strndup(name, n);
585 const char *cp = definition;
586 preproc_tokenizer tokens;
587 preproc_init(&tokens, cp);
591 cp = tokens.text + tokens.len;
593 while (preproc_next(&tokens));
596 macro->Definition = preproc_strndup(definition, n);
599 macro->IsExternal = info->IsExternal;
604 /** Free a preprocessor macro struct. */
605 static void preproc_free_macro(MacroInfo *info)
610 /** Find a preprocessor macro, return 0 if not found. */
611 static MacroInfo *preproc_find_macro(
612 PreprocessInfo *info, preproc_tokenizer *token)
614 unsigned int m = PREPROC_HASH_TABLE_SIZE - 1;
615 unsigned int i = (token->hash & m);
616 const char *name = token->text;
617 size_t l = token->len;
618 MacroInfo ***htable = info->MacroHashTable;
622 if (htable && ((hptr = htable[i]) != NULL) && *hptr)
626 mname = (*hptr)->Name;
627 if (mname[0] == name[0] &&
628 strncmp(mname, name, l) == 0 &&
641 /** Return the address of the macro within the hash table.
642 * If "insert" is nonzero, add a new location if macro not found. */
643 static MacroInfo **preproc_macro_location(
644 PreprocessInfo *info, preproc_tokenizer *token, int insert)
646 MacroInfo ***htable = info->MacroHashTable;
647 unsigned int m = PREPROC_HASH_TABLE_SIZE - 1;
648 unsigned int i = (token->hash & m);
649 const char *name = token->text;
650 size_t l = token->len;
662 m = PREPROC_HASH_TABLE_SIZE;
663 htable = (MacroInfo ***)malloc(m*sizeof(MacroInfo **));
664 info->MacroHashTable = htable;
665 do { *htable++ = NULL; } while (--m);
666 htable = info->MacroHashTable;
678 hptr = (MacroInfo **)malloc(2*sizeof(MacroInfo *));
685 /* see if macro is already there */
689 mname = (*hptr)->Name;
690 if (mname[0] == name[0] &&
691 strncmp(mname, name, l) == 0 &&
708 /* if n+1 is a power of two, double allocated space */
709 if (n > 0 && (n & (n+1)) == 0)
712 hptr = (MacroInfo **)realloc(hptr, (2*(n+1))*sizeof(MacroInfo *));
717 /* add a terminating null */
725 /** Remove a preprocessor macro. Returns 0 if macro not found. */
726 static int preproc_remove_macro(
727 PreprocessInfo *info, preproc_tokenizer *token)
731 hptr = preproc_macro_location(info, token, 0);
735 preproc_free_macro(*hptr);
750 /** A simple way to add a preprocessor macro definition. */
751 static MacroInfo *preproc_add_macro_definition(
752 PreprocessInfo *info, const char *name, const char *definition)
754 preproc_tokenizer token;
758 preproc_init(&token, name);
760 macro = preproc_new_macro(info, name, definition);
761 macro_p = preproc_macro_location(info, &token, 1);
765 fprintf(stderr, "duplicate macro definition %s\n", name);
773 /** Skip over parentheses, return nonzero if not closed. */
774 static int preproc_skip_parentheses(preproc_tokenizer *tokens)
778 if (tokens->tok == '(')
782 while (depth > 0 && preproc_next(tokens))
784 if (tokens->tok == '(')
788 else if (tokens->tok == ')')
795 if (tokens->tok == ')')
797 preproc_next(tokens);
802 fprintf(stderr, "syntax error %d\n", __LINE__);
804 return VTK_PARSE_SYNTAX_ERROR;
808 /** Evaluate a char literal to an integer value. */
809 static int preproc_evaluate_char(
810 const char *cp, preproc_int_t *val, int *is_unsigned)
819 else if (*cp != '\'' && *cp != '\n' && *cp != '\0')
822 if (*cp == 'a') { *val = '\a'; }
823 else if (*cp == 'b') { *val = '\b'; }
824 else if (*cp == 'f') { *val = '\f'; }
825 else if (*cp == 'n') { *val = '\n'; }
826 else if (*cp == 'r') { *val = '\r'; }
827 else if (*cp == 'b') { *val = '\b'; }
828 else if (*cp == 't') { *val = '\t'; }
829 else if (*cp == 'v') { *val = '\v'; }
830 else if (*cp == '\'') { *val = '\''; }
831 else if (*cp == '\"') { *val = '\"'; }
832 else if (*cp == '\\') { *val = '\\'; }
833 else if (*cp == '\?') { *val = '\?'; }
836 *val = string_to_preproc_int(cp, 8);
837 do { cp++; } while (*cp >= '0' && *cp <= '7');
841 *val = string_to_preproc_int(cp+1, 16);
842 do { cp++; } while (preproc_chartype(*cp, CPRE_HEX));
848 fprintf(stderr, "syntax error %d\n", __LINE__);
850 return VTK_PARSE_SYNTAX_ERROR;
858 fprintf(stderr, "syntax error %d\n", __LINE__);
860 return VTK_PARSE_SYNTAX_ERROR;
863 /* Evaluate an integer, ignoring any suffixes except 'u'. */
864 static int preproc_evaluate_integer(
865 const char *cp, preproc_int_t *val, int *is_unsigned)
871 if (cp[0] == '0' && (cp[1] == 'x' || cp[1] == 'X'))
877 while (preproc_chartype(*ep, CPRE_HEX))
882 else if (cp[0] == '0' && preproc_chartype(cp[1], CPRE_DIGIT))
888 while (*ep >= '0' && *ep <= '7')
897 while (preproc_chartype(*ep, CPRE_DIGIT))
905 if (ep[0] == 'i' && ep[1] == '6' && ep[2] == '4') { ep += 3; }
906 else if (*ep == 'u') { *is_unsigned = 1; ep++; }
907 else if (*ep == 'l' || *ep == 'L') { ep++; }
913 *val = (preproc_int_t)string_to_preproc_uint(cp, base);
917 *val = string_to_preproc_int(cp, base);
920 if (*ep == '.' || *ep == 'e' || *ep == 'E')
922 return VTK_PARSE_PREPROC_DOUBLE;
928 /* forward declaration */
929 static int preproc_evaluate_expression(
930 PreprocessInfo *info, preproc_tokenizer *tokens,
931 preproc_int_t *val, int *is_unsigned);
933 /** Evaluate a single item in an expression. */
934 static int preproc_evaluate_single(
935 PreprocessInfo *info, preproc_tokenizer *tokens,
936 preproc_int_t *val, int *is_unsigned)
938 int result = VTK_PARSE_OK;
940 while (tokens->tok == TOK_ID)
942 /* handle the "defined" keyword */
943 if (tokens->hash == HASH_DEFINED && tokens->len == 7 &&
944 strncmp("defined", tokens->text, tokens->len) == 0)
947 preproc_next(tokens);
949 if (tokens->tok == '(')
952 preproc_next(tokens);
954 if (tokens->tok != TOK_ID)
959 fprintf(stderr, "syntax error %d\n", __LINE__);
961 return VTK_PARSE_SYNTAX_ERROR;
964 /* do the name lookup */
966 *val = (preproc_find_macro(info, tokens) != 0);
968 preproc_next(tokens);
971 if (tokens->tok != ')')
974 fprintf(stderr, "syntax error %d\n", __LINE__);
976 return VTK_PARSE_SYNTAX_ERROR;
978 preproc_next(tokens);
985 /* look up and evaluate the macro */
986 MacroInfo *macro = preproc_find_macro(info, tokens);
987 const char *args = NULL;
988 const char *expansion = NULL;
990 preproc_next(tokens);
994 if (macro == NULL || macro->IsExcluded)
996 return VTK_PARSE_MACRO_UNDEFINED;
998 else if (macro->IsFunction)
1000 /* expand function macros using the arguments */
1001 args = tokens->text;
1002 if (tokens->tok != '(' ||
1003 preproc_skip_parentheses(tokens) != VTK_PARSE_OK)
1006 fprintf(stderr, "syntax error %d\n", __LINE__);
1008 return VTK_PARSE_SYNTAX_ERROR;
1011 expansion = vtkParsePreprocess_ExpandMacro(info, macro, args);
1012 if (expansion == NULL)
1016 fprintf(stderr, "syntax error %d\n", __LINE__);
1018 return (args ? VTK_PARSE_MACRO_NUMARGS : VTK_PARSE_SYNTAX_ERROR);
1021 preproc_skip_whitespace(&cp, WS_NO_EOL);
1024 macro->IsExcluded = 1;
1025 result = vtkParsePreprocess_EvaluateExpression(
1026 info, expansion, val, is_unsigned);
1027 macro->IsExcluded = 0;
1028 vtkParsePreprocess_FreeMacroExpansion(
1029 info, macro, expansion);
1032 vtkParsePreprocess_FreeMacroExpansion(info, macro, expansion);
1034 /* if macro expansion was empty, continue */
1037 if (tokens->tok == '(')
1039 preproc_next(tokens);
1040 result = preproc_evaluate_expression(info, tokens, val, is_unsigned);
1041 if ((result & VTK_PARSE_FATAL_ERROR) == 0)
1043 if (tokens->tok == ')')
1045 preproc_next(tokens);
1049 fprintf(stderr, "syntax error %d\n", __LINE__);
1051 return VTK_PARSE_SYNTAX_ERROR;
1055 else if (tokens->tok == TOK_NUMBER)
1057 result = preproc_evaluate_integer(tokens->text, val, is_unsigned);
1058 if (tokens->text[tokens->len-1] == 'f' ||
1059 tokens->text[tokens->len-1] == 'F')
1061 result = VTK_PARSE_PREPROC_FLOAT;
1063 preproc_next(tokens);
1066 else if (tokens->tok == TOK_CHAR)
1068 result = preproc_evaluate_char(tokens->text, val, is_unsigned);
1069 preproc_next(tokens);
1072 else if (tokens->tok == TOK_STRING)
1076 preproc_next(tokens);
1077 while (tokens->tok == TOK_STRING)
1079 preproc_next(tokens);
1081 return VTK_PARSE_PREPROC_STRING;
1087 fprintf(stderr, "syntax error %d \"%*.*s\"\n", __LINE__,
1088 (int)tokens->len, (int)tokens->len, tokens->text);
1090 return VTK_PARSE_SYNTAX_ERROR;
1093 static int preproc_evaluate_unary(
1094 PreprocessInfo *info, preproc_tokenizer *tokens,
1095 preproc_int_t *val, int *is_unsigned)
1097 int op = tokens->tok;
1098 int result = VTK_PARSE_OK;
1100 if (op != '+' && op != '-' && op != '~' && op != '!')
1102 return preproc_evaluate_single(info, tokens, val, is_unsigned);
1105 preproc_next(tokens);
1107 result = preproc_evaluate_unary(info, tokens, val, is_unsigned);
1108 if ((result & VTK_PARSE_FATAL_ERROR) == 0)
1110 if (op == '~') { *val = ~(*val); }
1111 else if (op == '!') { *val = !(*val); *is_unsigned = 0; }
1112 else if (op == '-') { *val = -(*val); }
1119 static int preproc_evaluate_multiply(
1120 PreprocessInfo *info, preproc_tokenizer *tokens,
1121 preproc_int_t *val, int *is_unsigned)
1128 result = preproc_evaluate_unary(info, tokens, val, is_unsigned);
1129 while ((result & VTK_PARSE_FATAL_ERROR) == 0)
1132 if (op != '*' && op != '/' && op != '%')
1137 preproc_next(tokens);
1139 result = preproc_evaluate_unary(info, tokens, &rval, &rtype);
1141 *is_unsigned = (*is_unsigned || rtype);
1147 *val = (preproc_int_t)((preproc_uint_t)*val *
1148 (preproc_uint_t)rval);
1154 *val = (preproc_int_t)((preproc_uint_t)*val /
1155 (preproc_uint_t)rval);
1166 *val = (preproc_int_t)((preproc_uint_t)*val %
1167 (preproc_uint_t)rval);
1217 static int preproc_evaluate_add(
1218 PreprocessInfo *info, preproc_tokenizer *tokens,
1219 preproc_int_t *val, int *is_unsigned)
1226 result = preproc_evaluate_multiply(info, tokens, val, is_unsigned);
1227 while ((result & VTK_PARSE_FATAL_ERROR) == 0)
1230 if (op != '+' && op != '-')
1235 preproc_next(tokens);
1237 result = preproc_evaluate_multiply(info, tokens, &rval, &rtype);
1239 *is_unsigned = (*is_unsigned || rtype);
1254 static int preproc_evaluate_bitshift(
1255 PreprocessInfo *info, preproc_tokenizer *tokens,
1256 preproc_int_t *val, int *is_unsigned)
1263 result = preproc_evaluate_add(info, tokens, val, is_unsigned);
1264 while ((result & VTK_PARSE_FATAL_ERROR) == 0)
1268 if (op != TOK_LSHIFT && op != TOK_RSHIFT)
1273 preproc_next(tokens);
1275 result = preproc_evaluate_add(info, tokens, &rval, &rtype);
1279 if (op == TOK_LSHIFT)
1281 *val = (preproc_int_t)((preproc_uint_t)*val << rval);
1283 else if (op == TOK_RSHIFT)
1285 *val = (preproc_int_t)((preproc_uint_t)*val >> rval);
1290 if (op == TOK_LSHIFT)
1292 *val = *val << rval;
1294 else if (op == TOK_RSHIFT)
1296 *val = *val >> rval;
1304 static int preproc_evaluate_compare(
1305 PreprocessInfo *info, preproc_tokenizer *tokens,
1306 preproc_int_t *val, int *is_unsigned)
1313 result = preproc_evaluate_bitshift(info, tokens, val, is_unsigned);
1314 while ((result & VTK_PARSE_FATAL_ERROR) == 0)
1317 if (op != '<' && op != '>' && op != TOK_LE && op != TOK_GE)
1322 preproc_next(tokens);
1324 result = preproc_evaluate_bitshift(info, tokens, &rval, &rtype);
1326 *is_unsigned = (*is_unsigned || rtype);
1332 *val = ((preproc_uint_t)*val <= (preproc_uint_t)rval);
1336 *val = ((preproc_uint_t)*val < (preproc_uint_t)rval);
1338 else if (op == TOK_GE)
1340 *val = ((preproc_uint_t)*val >= (preproc_uint_t)rval);
1344 *val = ((preproc_uint_t)*val > (preproc_uint_t)rval);
1351 *val = (*val <= rval);
1355 *val = (*val < rval);
1357 else if (op == TOK_GE)
1359 *val = (*val >= rval);
1363 *val = (*val > rval);
1372 static int preproc_evaluate_equal(
1373 PreprocessInfo *info, preproc_tokenizer *tokens,
1374 preproc_int_t *val, int *is_unsigned)
1381 result = preproc_evaluate_compare(info, tokens, val, is_unsigned);
1382 while ((result & VTK_PARSE_FATAL_ERROR) == 0)
1385 if (op != TOK_EQ && op != TOK_NE)
1390 preproc_next(tokens);
1392 result = preproc_evaluate_compare(info, tokens, &rval, &rtype);
1396 *val = (*val == rval);
1398 else if (op == TOK_NE)
1400 *val = (*val != rval);
1408 static int preproc_evaluate_and(
1409 PreprocessInfo *info, preproc_tokenizer *tokens,
1410 preproc_int_t *val, int *is_unsigned)
1416 result = preproc_evaluate_equal(info, tokens, val, is_unsigned);
1417 while ((result & VTK_PARSE_FATAL_ERROR) == 0)
1419 if (tokens->tok != '&')
1424 preproc_next(tokens);
1426 result = preproc_evaluate_equal(info, tokens, &rval, &rtype);
1428 *is_unsigned = (*is_unsigned || rtype);
1429 *val = (*val & rval);
1435 static int preproc_evaluate_xor(
1436 PreprocessInfo *info, preproc_tokenizer *tokens,
1437 preproc_int_t *val, int *is_unsigned)
1443 result = preproc_evaluate_and(info, tokens, val, is_unsigned);
1444 while ((result & VTK_PARSE_FATAL_ERROR) == 0)
1446 if (tokens->tok != '^')
1451 preproc_next(tokens);
1453 result = preproc_evaluate_and(info, tokens, &rval, &rtype);
1455 *is_unsigned = (*is_unsigned || rtype);
1456 *val = (*val ^ rval);
1462 static int preproc_evaluate_or(
1463 PreprocessInfo *info, preproc_tokenizer *tokens,
1464 preproc_int_t *val, int *is_unsigned)
1470 result = preproc_evaluate_xor(info, tokens, val, is_unsigned);
1471 while ((result & VTK_PARSE_FATAL_ERROR) == 0)
1473 if (tokens->tok != '|')
1478 preproc_next(tokens);
1480 result = preproc_evaluate_xor(info, tokens, &rval, &rtype);
1482 *is_unsigned = (*is_unsigned || rtype);
1483 *val = (*val | rval);
1489 static int preproc_evaluate_logic_and(
1490 PreprocessInfo *info, preproc_tokenizer *tokens,
1491 preproc_int_t *val, int *is_unsigned)
1497 result = preproc_evaluate_or(info, tokens, val, is_unsigned);
1498 while ((result & VTK_PARSE_FATAL_ERROR) == 0)
1500 if (tokens->tok != TOK_AND)
1505 preproc_next(tokens);
1510 while (tokens->tok != 0 && tokens->tok != ')' &&
1511 tokens->tok != ':' && tokens->tok != '?' &&
1512 tokens->tok != ',' && tokens->tok != TOK_OR)
1514 if (tokens->tok == '(')
1516 if (preproc_skip_parentheses(tokens) != VTK_PARSE_OK)
1519 fprintf(stderr, "syntax error %d\n", __LINE__);
1521 result = VTK_PARSE_SYNTAX_ERROR;
1526 preproc_next(tokens);
1535 result = preproc_evaluate_or(info, tokens, &rval, &rtype);
1544 static int preproc_evaluate_logic_or(
1545 PreprocessInfo *info, preproc_tokenizer *tokens,
1546 preproc_int_t *val, int *is_unsigned)
1552 result = preproc_evaluate_logic_and(info, tokens, val, is_unsigned);
1553 while ((result & VTK_PARSE_FATAL_ERROR) == 0)
1555 if (tokens->tok != TOK_OR)
1560 preproc_next(tokens);
1565 while (tokens->tok != 0 && tokens->tok != ')' &&
1566 tokens->tok != ':' && tokens->tok != '?' &&
1569 if (tokens->tok == '(')
1571 if (preproc_skip_parentheses(tokens) != VTK_PARSE_OK)
1574 fprintf(stderr, "syntax error %d\n", __LINE__);
1576 result = VTK_PARSE_SYNTAX_ERROR;
1581 preproc_next(tokens);
1590 result = preproc_evaluate_logic_and(info, tokens, &rval, &rtype);
1599 /** Evaluate an arimetic *expression. */
1600 int preproc_evaluate_expression(
1601 PreprocessInfo *info, preproc_tokenizer *tokens,
1602 preproc_int_t *val, int *is_unsigned)
1604 preproc_int_t rval, sval;
1608 result = preproc_evaluate_logic_or(info, tokens, val, is_unsigned);
1609 if ((result & VTK_PARSE_FATAL_ERROR) == 0)
1611 if (tokens->tok != '?')
1616 preproc_next(tokens);
1618 result = preproc_evaluate_expression(info, tokens, &rval, &rtype);
1619 if ((result & VTK_PARSE_FATAL_ERROR) != 0)
1624 if (tokens->tok != ':')
1627 fprintf(stderr, "syntax error %d\n", __LINE__);
1629 return VTK_PARSE_SYNTAX_ERROR;
1632 preproc_next(tokens);
1634 result = preproc_evaluate_expression(info, tokens, &sval, &stype);
1635 if ((result & VTK_PARSE_FATAL_ERROR) != 0)
1643 *is_unsigned = rtype;
1648 *is_unsigned = stype;
1655 /** Evaluate a conditional *expression.
1656 * Returns VTK_PARSE_OK if the expression is true,
1657 * or VTK_PARSE_SKIP of the expression is false. */
1658 int preproc_evaluate_conditional(
1659 PreprocessInfo *info, preproc_tokenizer *tokens)
1665 result = preproc_evaluate_expression(info, tokens, &rval, &rtype);
1666 if ((result & VTK_PARSE_FATAL_ERROR) == 0)
1668 if (tokens->tok != 0)
1671 fprintf(stderr, "syntax error %d\n", __LINE__);
1673 return VTK_PARSE_SYNTAX_ERROR;
1675 return (rval == 0 ? VTK_PARSE_SKIP : VTK_PARSE_OK);
1682 * Handle any of the following directives:
1683 * #if, #ifdef, #ifndef, #elif, #else, #endif
1684 * A return value of VTK_PARSE_SKIP means that
1685 * the following code block should be skipped.
1687 static int preproc_evaluate_if(
1688 PreprocessInfo *info, preproc_tokenizer *tokens)
1692 int result = VTK_PARSE_OK;
1694 if (tokens->hash == HASH_IF ||
1695 tokens->hash == HASH_IFDEF ||
1696 tokens->hash == HASH_IFNDEF)
1698 if (info->ConditionalDepth == 0)
1700 if (tokens->hash == HASH_IF)
1702 preproc_next(tokens);
1703 result = preproc_evaluate_conditional(info, tokens);
1707 v1 = (tokens->hash != HASH_IFNDEF);
1708 preproc_next(tokens);
1709 if (tokens->tok != TOK_ID)
1712 fprintf(stderr, "syntax error %d\n", __LINE__);
1714 return VTK_PARSE_SYNTAX_ERROR;
1716 macro = preproc_find_macro(info, tokens);
1717 v2 = (macro && !macro->IsExcluded);
1718 preproc_next(tokens);
1719 result = ( (v1 ^ v2) ? VTK_PARSE_SKIP : VTK_PARSE_OK);
1722 if (result != VTK_PARSE_SKIP)
1724 /* mark as done, so that the "else" clause is skipped */
1725 info->ConditionalDone = 1;
1729 /* mark as not done, so that "else" clause is not skipped */
1730 info->ConditionalDone = 0;
1731 /* skip the "if" clause */
1732 info->ConditionalDepth = 1;
1737 /* increase the skip depth */
1738 info->ConditionalDepth++;
1741 else if (tokens->hash == HASH_ELIF ||
1742 tokens->hash == HASH_ELSE)
1744 if (info->ConditionalDepth == 0)
1746 /* preceding clause was not skipped, so must skip this one */
1747 info->ConditionalDepth = 1;
1749 else if (info->ConditionalDepth == 1 &&
1750 info->ConditionalDone == 0)
1752 if (tokens->hash == HASH_ELIF)
1754 preproc_next(tokens);
1755 result = preproc_evaluate_conditional(info, tokens);
1759 preproc_next(tokens);
1761 if (result != VTK_PARSE_SKIP)
1763 /* do not skip this clause */
1764 info->ConditionalDepth = 0;
1765 /* make sure remaining else/elif clauses are skipped */
1766 info->ConditionalDone = 1;
1770 else if (tokens->hash == HASH_ENDIF)
1772 preproc_next(tokens);
1773 if (info->ConditionalDepth > 0)
1775 /* decrease the skip depth */
1776 info->ConditionalDepth--;
1778 if (info->ConditionalDepth == 0)
1780 /* set "done" flag for the context that is being returned to */
1781 info->ConditionalDone = 1;
1789 * Handle the #define and #undef directives.
1791 static int preproc_evaluate_define(
1792 PreprocessInfo *info, preproc_tokenizer *tokens)
1794 MacroInfo **macro_p;
1799 const char *definition = 0;
1801 const char **params = NULL;
1803 if (tokens->hash == HASH_DEFINE)
1805 preproc_next(tokens);
1806 if (tokens->tok != TOK_ID)
1809 fprintf(stderr, "syntax error %d\n", __LINE__);
1811 return VTK_PARSE_SYNTAX_ERROR;
1814 macro_p = preproc_macro_location(info, tokens, 1);
1815 name = tokens->text;
1816 namelen = tokens->len;
1817 preproc_next(tokens);
1820 if (name[namelen] == '(')
1823 preproc_next(tokens);
1824 while (tokens->tok != 0 && tokens->tok != ')')
1826 if (tokens->tok != TOK_ID && tokens->tok != TOK_ELLIPSIS)
1828 if (params) { free((char **)params); }
1830 fprintf(stderr, "syntax error %d\n", __LINE__);
1832 return VTK_PARSE_SYNTAX_ERROR;
1835 /* add to the arg list */
1836 params = (const char **)preproc_array_check(
1837 (char **)params, sizeof(char *), n);
1838 params[n++] = preproc_strndup(tokens->text, tokens->len);
1840 preproc_next(tokens);
1841 if (tokens->tok == ',')
1843 preproc_next(tokens);
1845 else if (tokens->tok != ')')
1847 if (params) { free((char **)params); }
1849 fprintf(stderr, "syntax error %d\n", __LINE__);
1851 return VTK_PARSE_SYNTAX_ERROR;
1854 preproc_next(tokens);
1859 definition = tokens->text;
1865 if (preproc_identical(macro->Definition, definition))
1867 return VTK_PARSE_OK;
1869 if (params) { free((char **)params); }
1871 fprintf(stderr, "macro redefined %d\n", __LINE__);
1873 return VTK_PARSE_MACRO_REDEFINED;
1876 macro = preproc_new_macro(info, name, definition);
1877 macro->IsFunction = is_function;
1878 macro->NumberOfParameters = n;
1879 macro->Parameters = params;
1882 return VTK_PARSE_OK;
1884 else if (tokens->hash == HASH_UNDEF)
1886 preproc_next(tokens);
1887 if (tokens->tok != TOK_ID)
1890 fprintf(stderr, "syntax error %d\n", __LINE__);
1892 return VTK_PARSE_SYNTAX_ERROR;
1894 preproc_remove_macro(info, tokens);
1895 return VTK_PARSE_OK;
1898 return VTK_PARSE_OK;
1902 * Add an include file to the list. Return 0 if it is already there.
1904 static int preproc_add_include_file(PreprocessInfo *info, const char *name)
1909 n = info->NumberOfIncludeFiles;
1910 for (i = 0; i < n; i++)
1912 if (strcmp(info->IncludeFiles[i], name) == 0)
1918 dp = (char *)malloc(strlen(name)+1);
1921 info->IncludeFiles = (const char **)preproc_array_check(
1922 (char **)info->IncludeFiles, sizeof(char *), info->NumberOfIncludeFiles);
1923 info->IncludeFiles[info->NumberOfIncludeFiles++] = dp;
1929 * Find an include file. If "cache_only" is set, then do a check to
1930 * see if the file was previously found without going to the filesystem.
1932 const char *preproc_find_include_file(
1933 PreprocessInfo *info, const char *filename, int system_first,
1939 const char *directory;
1941 size_t outputsize = 16;
1944 /* allow filename to be terminated by quote or bracket */
1946 while (filename[m] != '\"' && filename[m] != '>' &&
1947 filename[m] != '\n' && filename[m] != '\0') { m++; }
1949 /* search file system for the file */
1950 output = (char *)malloc(outputsize);
1952 if (system_first != 0)
1957 if (cache_only != 0)
1962 /* check for absolute path of form DRIVE: or /path/to/file */
1964 while (preproc_chartype(filename[j], CPRE_IDGIT)) { j++; }
1966 if (filename[j] == ':' || filename[0] == '/' || filename[0] == '\\')
1968 if (m+1 > outputsize)
1971 output = (char *)realloc(output, outputsize);
1973 strncpy(output, filename, m);
1976 nn = info->NumberOfIncludeFiles;
1977 for (ii = 0; ii < nn; ii++)
1979 if (strcmp(output, info->IncludeFiles[ii]) == 0)
1982 return info->IncludeFiles[ii];
1992 info->IncludeFiles = (const char **)preproc_array_check(
1993 (char **)info->IncludeFiles, sizeof(char *),
1994 info->NumberOfIncludeFiles);
1995 info->IncludeFiles[info->NumberOfIncludeFiles++] = output;
2000 /* Make sure the current filename is already added */
2003 preproc_add_include_file(info, info->FileName);
2006 /* Check twice. First check the cache, then stat the files. */
2007 for (count = 0; count < (2-cache_only); count++)
2009 n = info->NumberOfIncludeDirectories;
2010 for (i = 0; i < (n+1-system_first); i++)
2012 /* search the directory of the file being processed */
2013 if (i == 0 && system_first == 0)
2017 j = strlen(info->FileName);
2020 if (info->FileName[j-1] == '/') { break; }
2023 if (m+j+1 > outputsize)
2025 outputsize += m+j+1;
2026 output = (char *)realloc(output, outputsize);
2030 strncpy(output, info->FileName, j);
2032 strncpy(&output[j], filename, m);
2037 if (m+1 > outputsize)
2040 output = (char *)realloc(output, outputsize);
2042 strncpy(output, filename, m);
2046 /* check all the search paths */
2049 directory = info->IncludeDirectories[i-1+system_first];
2050 j = strlen(directory);
2051 if (j + m + 2 > outputsize)
2053 outputsize += j+m+2;
2054 output = (char *)realloc(output, outputsize);
2057 strncpy(output, directory, j);
2058 if (directory[j-1] != '/') { output[j++] = '/'; }
2059 strncpy(&output[j], filename, m);
2065 nn = info->NumberOfIncludeFiles;
2066 for (ii = 0; ii < nn; ii++)
2068 if (strcmp(output, info->IncludeFiles[ii]) == 0)
2071 return info->IncludeFiles[ii];
2075 else if (stat(output, &fs) == 0)
2077 info->IncludeFiles = (const char **)preproc_array_check(
2078 (char **)info->IncludeFiles, sizeof(char *),
2079 info->NumberOfIncludeFiles);
2080 info->IncludeFiles[info->NumberOfIncludeFiles++] = output;
2092 * Include a file. All macros defined in the included file
2093 * will have their IsExternal flag set.
2095 static int preproc_include_file(
2096 PreprocessInfo *info, const char *filename, int system_first)
2099 size_t tbuflen = FILE_BUFFER_SIZE;
2101 size_t linelen = 80;
2105 int result = VTK_PARSE_OK;
2107 const char *path = NULL;
2108 const char *save_filename;
2111 /* check to see if the file has aleady been included */
2112 path = preproc_find_include_file(info, filename, system_first, 1);
2117 while (filename[k] != '>' && filename[k] != '\"' &&
2118 filename[k] != '\n' && filename[k] != '\0') { k++; }
2119 if (filename[k] == '>')
2120 fprintf(stderr, "already loaded file <%*.*s>\n", k, k, filename);
2122 fprintf(stderr, "already loaded file \"%*.*s\"\n", k, k, filename);
2125 return VTK_PARSE_OK;
2127 /* go to the filesystem */
2128 path = preproc_find_include_file(info, filename, system_first, 0);
2133 while (filename[k] != '>' && filename[k] != '\"' &&
2134 filename[k] != '\n' && filename[k] != '\0') { k++; }
2135 if (filename[k] == '>')
2136 fprintf(stderr, "couldn't find file <%*.*s>\n", k, k, filename);
2138 fprintf(stderr, "couldn't find file \"%*.*s\"\n", k, k, filename);
2140 return VTK_PARSE_FILE_NOT_FOUND;
2144 fprintf(stderr, "including file %s\n", path);
2146 fp = fopen(path, "r");
2151 fprintf(stderr, "couldn't open file %s\n", path);
2153 return VTK_PARSE_FILE_OPEN_ERROR;
2156 save_external = info->IsExternal;
2157 save_filename = info->FileName;
2158 info->IsExternal = 1;
2159 info->FileName = path;
2161 tbuf = (char *)malloc(tbuflen+4);
2162 line = (char *)malloc(linelen);
2164 /* the buffer must hold a whole line for it to be processed */
2174 /* recycle unused lookahead chars */
2180 tbuf[0] = tbuf[tbuflen-2];
2181 tbuf[1] = tbuf[tbuflen-1];
2185 tbuf[0] = tbuf[tbuflen-1];
2189 /* read the next chunk of the file */
2193 /* still have the lookahead chars left */
2199 /* fill the remainder of the buffer */
2201 tbuflen = r + FILE_BUFFER_SIZE;
2202 while ((n = fread(&tbuf[r], 1, tbuflen-r, fp)) == 0 && ferror(fp))
2209 info->IsExternal = save_external;
2210 return VTK_PARSE_FILE_READ_ERROR;
2216 if (n + r < tbuflen)
2218 /* this only occurs if the final fread does not fill the buffer */
2224 /* set a lookahead reserve of two chars */
2229 /* guard against lookahead past last char in file */
2234 /* copy the characters until end of line is found */
2237 /* expand line buffer as necessary */
2238 while (j+4 > linelen)
2241 line = (char *)realloc(line, linelen);
2246 if (tbuf[i] == '*' && tbuf[i+1] == '/')
2248 line[j++] = tbuf[i++];
2249 line[j++] = tbuf[i++];
2254 line[j++] = tbuf[i++];
2259 if (tbuf[i] == '\"')
2261 line[j++] = tbuf[i++];
2264 else if (tbuf[i] == '\\' && tbuf[i+1] != '\0')
2266 line[j++] = tbuf[i++];
2267 line[j++] = tbuf[i++];
2271 line[j++] = tbuf[i++];
2274 else if (tbuf[i] == '/' && tbuf[i+1] == '*')
2276 line[j++] = tbuf[i++];
2277 line[j++] = tbuf[i++];
2280 else if (tbuf[i] == '\"')
2282 line[j++] = tbuf[i++];
2285 else if (tbuf[i] == '\\' && tbuf[i+1] == '\n')
2287 line[j++] = tbuf[i++];
2288 line[j++] = tbuf[i++];
2290 else if (tbuf[i] == '\\' && tbuf[i+1] == '\r' && tbuf[i+2] == '\n')
2292 line[j++] = tbuf[i++];
2293 line[j++] = tbuf[i++];
2294 line[j++] = tbuf[i++];
2296 else if (tbuf[i] != '\n' && tbuf[i] != '\0')
2298 line[j++] = tbuf[i++];
2302 line[j++] = tbuf[i++];
2307 if (i < n || n == 0)
2309 const char *cp = line;
2312 preproc_skip_whitespace(&cp, WS_NO_EOL);
2315 vtkParsePreprocess_HandleDirective(info, line);
2325 info->IsExternal = save_external;
2326 info->FileName = save_filename;
2332 * Handle the #include directive. The header file will
2333 * only go through the preprocessor.
2335 static int preproc_evaluate_include(
2336 PreprocessInfo *info, preproc_tokenizer *tokens)
2339 const char *filename;
2341 if (tokens->hash == HASH_INCLUDE)
2343 preproc_next(tokens);
2347 if (tokens->tok == TOK_ID)
2349 MacroInfo *macro = preproc_find_macro(info, tokens);
2350 if (macro && !macro->IsExcluded && macro->Definition)
2352 cp = macro->Definition;
2357 fprintf(stderr, "couldn't find macro %*.*s.\n",
2358 (int)tokens->len, (int)tokens->len, tokens->text);
2360 return VTK_PARSE_MACRO_UNDEFINED;
2367 preproc_skip_quotes(&cp);
2368 if (cp <= filename + 1 || *(cp-1) != '\"')
2370 return VTK_PARSE_SYNTAX_ERROR;
2373 return preproc_include_file(info, filename, 0);
2375 else if (*cp == '<')
2379 while (*cp != '>' && *cp != '\n' && *cp != '\0') { cp++; }
2382 return VTK_PARSE_SYNTAX_ERROR;
2385 return preproc_include_file(info, filename, 1);
2389 return VTK_PARSE_OK;
2393 * Handle any recognized directive.
2394 * Unrecognized directives are ignored.
2396 int vtkParsePreprocess_HandleDirective(
2397 PreprocessInfo *info, const char *directive)
2399 int result = VTK_PARSE_OK;
2400 preproc_tokenizer tokens;
2402 preproc_init(&tokens, directive);
2404 if (tokens.tok != '#')
2406 return VTK_PARSE_SYNTAX_ERROR;
2409 preproc_next(&tokens);
2411 if (tokens.tok == TOK_ID)
2413 if ((tokens.hash == HASH_IFDEF && tokens.len == 5 &&
2414 strncmp("ifdef", tokens.text, tokens.len) == 0) ||
2415 (tokens.hash == HASH_IFNDEF && tokens.len == 6 &&
2416 strncmp("ifndef", tokens.text, tokens.len) == 0) ||
2417 (tokens.hash == HASH_IF && tokens.len == 2 &&
2418 strncmp("if", tokens.text, tokens.len) == 0) ||
2419 (tokens.hash == HASH_ELIF && tokens.len == 4 &&
2420 strncmp("elif", tokens.text, tokens.len) == 0) ||
2421 (tokens.hash == HASH_ELSE && tokens.len == 4 &&
2422 strncmp("else", tokens.text, tokens.len) == 0) ||
2423 (tokens.hash == HASH_ENDIF && tokens.len == 5 &&
2424 strncmp("endif", tokens.text, tokens.len) == 0))
2426 result = preproc_evaluate_if(info, &tokens);
2427 while (tokens.tok) { preproc_next(&tokens); }
2430 size_t n = tokens.text - directive;
2432 if (result == VTK_PARSE_SKIP)
2434 fprintf(stderr, "SKIP: ");
2436 else if (result == VTK_PARSE_OK)
2438 fprintf(stderr, "READ: ");
2442 fprintf(stderr, "ERR%-2.2d ", result);
2444 fprintf(stderr, "%*.*s\n", (int)n, (int)n, directive);
2448 else if (info->ConditionalDepth == 0)
2450 if ((tokens.hash == HASH_DEFINE && tokens.len == 6 &&
2451 strncmp("define", tokens.text, tokens.len) == 0) ||
2452 (tokens.hash == HASH_UNDEF && tokens.len == 5 &&
2453 strncmp("undef", tokens.text, tokens.len) == 0))
2455 result = preproc_evaluate_define(info, &tokens);
2457 else if (tokens.hash == HASH_INCLUDE && tokens.len == 7 &&
2458 strncmp("include", tokens.text, tokens.len) == 0)
2460 result = preproc_evaluate_include(info, &tokens);
2465 if (info->ConditionalDepth > 0)
2467 return VTK_PARSE_SKIP;
2474 * Evaluate a preprocessor expression.
2475 * If no errors occurred, the result will be VTK_PARSE_OK.
2477 int vtkParsePreprocess_EvaluateExpression(
2478 PreprocessInfo *info, const char *text,
2479 preproc_int_t *val, int *is_unsigned)
2481 preproc_tokenizer tokens;
2482 preproc_init(&tokens, text);
2484 return preproc_evaluate_expression(info, &tokens, val, is_unsigned);
2487 /** Add a macro for defining a macro */
2488 #define PREPROC_MACRO_TO_STRING2(x) #x
2489 #define PREPROC_MACRO_TO_STRING(x) PREPROC_MACRO_TO_STRING2(x)
2490 #define PREPROC_ADD_MACRO(info, x) \
2491 preproc_add_macro_definition(info, #x, PREPROC_MACRO_TO_STRING2(x))
2494 * Add all standard preprocessory macros. Specify the platform.
2496 void vtkParsePreprocess_AddStandardMacros(
2497 PreprocessInfo *info, int platform)
2499 int save_external = info->IsExternal;
2500 info->IsExternal = 1;
2502 /* a special macro to indicate that this is the wrapper */
2503 preproc_add_macro_definition(info, "__WRAP__", "1");
2505 /* language macros - assume that we are wrapping C++ code */
2506 preproc_add_macro_definition(info, "__cplusplus", "1");
2508 /* stdc version macros */
2510 PREPROC_ADD_MACRO(info, __STDC__);
2512 #ifdef __STDC_VERSION__
2513 PREPROC_ADD_MACRO(info, __STDC_VERSION__);
2515 #ifdef __STDC_HOSTED__
2516 PREPROC_ADD_MACRO(info, __STDC_HOSTED__);
2519 if (platform == VTK_PARSE_NATIVE)
2522 PREPROC_ADD_MACRO(info, WIN32);
2525 PREPROC_ADD_MACRO(info, _WIN32);
2528 PREPROC_ADD_MACRO(info, _MSC_VER);
2532 PREPROC_ADD_MACRO(info, __BORLAND__);
2536 PREPROC_ADD_MACRO(info, __CYGWIN__);
2539 PREPROC_ADD_MACRO(info, MINGW);
2542 PREPROC_ADD_MACRO(info, __MINGW32__);
2546 PREPROC_ADD_MACRO(info, __linux__);
2549 PREPROC_ADD_MACRO(info, __LINUX__);
2553 PREPROC_ADD_MACRO(info, __APPLE__);
2556 PREPROC_ADD_MACRO(info, __MACH__);
2559 PREPROC_ADD_MACRO(info, __DARWIN__);
2563 PREPROC_ADD_MACRO(info, __GNUC__);
2566 PREPROC_ADD_MACRO(info, __LP64__);
2568 #ifdef __BIG_ENDIAN__
2569 PREPROC_ADD_MACRO(info, __BIG_ENDIAN__);
2571 #ifdef __LITTLE_ENDIAN__
2572 PREPROC_ADD_MACRO(info, __LITTLE_ENDIAN__);
2576 info->IsExternal = save_external;
2580 * Add a preprocessor macro, including a definition.
2582 int vtkParsePreprocess_AddMacro(
2583 PreprocessInfo *info, const char *name, const char *definition)
2585 preproc_tokenizer token;
2586 MacroInfo **macro_p;
2589 preproc_init(&token, name);
2590 macro_p = preproc_macro_location(info, &token, 1);
2594 if (preproc_identical(macro->Definition, definition))
2596 return VTK_PARSE_OK;
2600 return VTK_PARSE_MACRO_REDEFINED;
2604 macro = preproc_new_macro(info, name, definition);
2605 macro->IsExternal = 1;
2608 return VTK_PARSE_OK;
2612 * Return a preprocessor macro struct, or NULL if not found.
2614 MacroInfo *vtkParsePreprocess_GetMacro(
2615 PreprocessInfo *info, const char *name)
2617 preproc_tokenizer token;
2620 preproc_init(&token, name);
2621 macro = preproc_find_macro(info, &token);
2623 if (macro && !macro->IsExcluded)
2632 * Remove a preprocessor macro.
2634 int vtkParsePreprocess_RemoveMacro(
2635 PreprocessInfo *info, const char *name)
2637 preproc_tokenizer token;
2639 preproc_init(&token, name);
2641 if (preproc_remove_macro(info, &token))
2643 return VTK_PARSE_OK;
2646 return VTK_PARSE_MACRO_UNDEFINED;
2650 * Expand a macro, argstring is ignored if not a function macro
2652 const char *vtkParsePreprocess_ExpandMacro(
2653 PreprocessInfo *info, MacroInfo *macro, const char *argstring)
2655 const char *cp = argstring;
2658 const char *stack_values[8];
2659 const char **values = NULL;
2660 const char *pp = NULL;
2661 const char *dp = NULL;
2662 const char *wp = NULL;
2674 if (macro->IsFunction)
2676 if (argstring == NULL || *cp != '(')
2681 /* break the string into individual argument values */
2682 values = stack_values;
2686 while (depth > 0 && *cp != '\0')
2690 if (*cp == '\"' || *cp == '\'')
2692 preproc_skip_quotes(&cp);
2694 else if (cp[0] == '/' && (cp[1] == '*' || cp[1] == '/'))
2696 preproc_skip_comment(&cp);
2698 else if (*cp == '(')
2703 else if (*cp == ')')
2711 else if (*cp == ',')
2719 else if (*cp != '\0')
2724 if (n >= 8 && (n & (n-1)) == 0)
2726 if (values != stack_values)
2728 values = (const char **)realloc(
2729 (char **)values, 2*n*sizeof(const char **));
2733 values = (const char **)malloc(2*n*sizeof(const char **));
2734 memcpy((char **)values, stack_values, 8*sizeof(const char **));
2742 /* diagnostic: print out the values */
2744 for (j = 0; j < n; j++)
2746 size_t m = values[j+1] - values[j] - 1;
2747 fprintf(stderr, "arg %i: %*.*s\n",
2748 (int)j, (int)m, (int)m, values[j]);
2752 if (macro->NumberOfParameters == 0 && n == 1)
2754 const char *tp = values[0];
2755 preproc_skip_whitespace(&tp, WS_NO_EOL);
2756 if (tp + 1 >= values[1])
2762 if (n != macro->NumberOfParameters)
2764 if (values != stack_values) { free((char **)values); }
2766 fprintf(stderr, "wrong number of macro args to %s, %lu != %lu\n",
2767 macro->Name, n, macro->NumberOfParameters);
2773 cp = macro->Definition;
2774 cp = (cp ? cp : "");
2786 /* skip all chars that aren't part of a name */
2787 while (!preproc_chartype(*cp, CPRE_ID) && *cp != '\0')
2790 preproc_skip_whitespace(&cp, WS_NO_EOL);
2795 else if (preproc_chartype(*cp, CPRE_QUOTE))
2797 preproc_skip_quotes(&cp);
2802 else if (preproc_chartype(*cp, CPRE_DIGIT))
2804 preproc_skip_number(&cp);
2809 else if (cp[0] == '#' && cp[1] == '#')
2815 preproc_skip_whitespace(&cp, WS_NO_EOL);
2818 else if (*cp == '#')
2824 preproc_skip_whitespace(&cp, WS_NO_EOL);
2837 if (i + l + 1 >= rs)
2839 rs += rs + i + l + 1;
2842 rp = (char *)realloc(rp, rs);
2846 rp = (char *)malloc(rs);
2847 memcpy(rp, stack_rp, i);
2850 strncpy(&rp[i], pp, l);
2857 preproc_skip_name(&cp);
2861 for (j = 0; j < n; j++)
2863 /* check whether the name matches a parameter */
2864 if (strncmp(pp, macro->Parameters[j], l) == 0 &&
2865 macro->Parameters[j][l] == '\0')
2867 /* substitute the argument value */
2868 l = values[j+1] - values[j] - 1;
2870 /* remove leading whitespace from argument */
2872 while (preproc_chartype(c, CPRE_WHITE))
2877 /* remove trailing whitespace from argument */
2881 while (preproc_chartype(c, CPRE_WHITE))
2890 /* check if followed by "##" */
2892 preproc_skip_whitespace(&wp, WS_NO_EOL);
2893 if (wp[0] == '#' && wp[1] == '#')
2902 /* compute number of chars that will be added */
2904 for (k = 0; k < l; k++)
2907 if (c == '\\' || c == '\"')
2913 if (i + l + stringify + 1 >= rs)
2915 rs += rs + i + l + 1;
2918 rp = (char *)realloc(rp, rs);
2922 rp = (char *)malloc(rs);
2923 memcpy(rp, stack_rp, i);
2929 for (k = 0; k < l; k++)
2932 if (c == '\\' || c == '\"')
2942 strncpy(&rp[i], pp, l);
2947 /* process the arguments before substituting them */
2949 int is_excluded = macro->IsExcluded;
2950 macro->IsExcluded = 1;
2951 strncpy(&rp[i], pp, l);
2953 text = vtkParsePreprocess_ProcessString(info, &rp[i]);
2960 if (i + l + 1 >= rs)
2962 rs += rs + i + l + 1;
2964 rp = (char *)malloc(rs);
2967 strncpy(&rp[i], text, l);
2968 vtkParsePreprocess_FreeProcessedString(info, text);
2969 if (tp && tp != stack_rp)
2975 macro->IsExcluded = is_excluded;
2982 if (values != stack_values) { free((char **)values); }
2984 if (!macro->IsFunction && macro->Definition &&
2985 strcmp(rp, macro->Definition) == 0)
2987 if (rp != stack_rp) { free(rp); }
2988 return macro->Definition;
2993 rp = (char *)malloc(strlen(stack_rp) + 1);
2994 strcpy(rp, stack_rp);
3003 const char *vtkParsePreprocess_ProcessString(
3004 PreprocessInfo *info, const char *text)
3012 preproc_tokenizer tokens;
3013 preproc_init(&tokens, text);
3020 size_t l = tokens.len;
3022 const char *cp = tokens.text;
3025 if (tokens.tok == TOK_STRING && last_tok == TOK_STRING)
3029 do { --i; } while (i > 0 && rp[i] != '\"');
3034 if (i + l + 2 >= rs)
3036 rs += rs + i + l + 2;
3039 rp = (char *)malloc(rs);
3040 memcpy(rp, stack_rp, i);
3044 rp = (char *)realloc(rp, rs);
3048 /* copy the token, removing backslash-newline */
3051 for (j = 0; j < l; j++)
3055 if (dp[1] == '\n') { dp += 2; }
3056 else if (dp[1] == '\r' && dp[2] == '\n') { dp += 3; }
3057 else { *ep++ = *dp++; }
3066 if (tokens.tok == TOK_ID)
3068 MacroInfo *macro = preproc_find_macro(info, &tokens);
3069 if (macro && !macro->IsExcluded)
3071 const char *args = NULL;
3074 if (macro->IsFunction)
3076 /* expand function macros using the arguments */
3077 preproc_next(&tokens);
3078 if (tokens.tok == '(')
3082 while (depth > 0 && preproc_next(&tokens))
3084 if (tokens.tok == '(')
3088 else if (tokens.tok == ')')
3093 if (tokens.tok != ')')
3095 if (rp != stack_rp) { free(rp); }
3101 /* unput the last token if it isn't "(" */
3109 const char *expansion;
3110 const char *processed;
3111 expansion = vtkParsePreprocess_ExpandMacro(info, macro, args);
3112 if (expansion == NULL)
3114 if (rp != stack_rp) { free(rp); }
3117 macro->IsExcluded = 1;
3118 processed = vtkParsePreprocess_ProcessString(info, expansion);
3119 macro->IsExcluded = 0;
3120 if (processed == NULL)
3122 vtkParsePreprocess_FreeMacroExpansion(info, macro, expansion);
3123 if (rp != stack_rp) { free(rp); }
3126 l = strlen(processed);
3129 if (i + l + 2 >= rs)
3131 rs += rs + i + l + 2;
3134 rp = (char *)malloc(rs);
3135 memcpy(rp, stack_rp, i);
3139 rp = (char *)realloc(rp, rs);
3142 strncpy(&rp[i], processed, l);
3144 if (processed != expansion)
3146 vtkParsePreprocess_FreeProcessedString(info, processed);
3148 vtkParsePreprocess_FreeMacroExpansion(info, macro, expansion);
3155 last_tok = tokens.tok;
3158 if (preproc_next(&tokens) && tokens.text > cp + l)
3165 if (strcmp(rp, text) == 0)
3167 /* no change, return */
3168 if (rp != stack_rp) { free(rp); }
3173 /* string changed, recursively reprocess */
3174 const char *tp = vtkParsePreprocess_ProcessString(info, rp);
3177 if (rp != stack_rp) { free(rp); }
3182 rp = (char *)malloc(strlen(stack_rp) + 1);
3183 strcpy(rp, stack_rp);
3191 * Free a string returned by ExpandMacro
3193 void vtkParsePreprocess_FreeMacroExpansion(
3194 PreprocessInfo *info, MacroInfo *macro, const char *text)
3196 /* only free expansion if it is different from definition */
3197 if (info && text != macro->Definition)
3204 * Free a string returned by ProcessString
3206 void vtkParsePreprocess_FreeProcessedString(
3207 PreprocessInfo *info, const char *text)
3216 * Add an include directory.
3218 void vtkParsePreprocess_IncludeDirectory(
3219 PreprocessInfo *info, const char *name)
3223 n = info->NumberOfIncludeDirectories;
3224 for (i = 0; i < n; i++)
3226 if (strcmp(name, info->IncludeDirectories[i]) == 0)
3232 info->IncludeDirectories = (const char **)preproc_array_check(
3233 (char **)info->IncludeDirectories, sizeof(char *),
3234 info->NumberOfIncludeDirectories);
3235 info->IncludeDirectories[info->NumberOfIncludeDirectories++] =
3236 preproc_strndup(name, strlen(name));
3240 * Find an include file in the path. If system_first is set,
3241 * then the current directory is not searched.
3243 const char *vtkParsePreprocess_FindIncludeFile(
3244 PreprocessInfo *info, const char *filename, int system_first,
3245 int *already_loaded)
3248 cp = preproc_find_include_file(info, filename, system_first, 1);
3251 *already_loaded = 1;
3255 *already_loaded = 0;
3256 return preproc_find_include_file(info, filename, system_first, 0);
3260 * Initialize a preprocessor macro struct
3262 void vtkParsePreprocess_InitMacro(MacroInfo *macro)
3265 macro->Definition = NULL;
3266 macro->Comment = NULL;
3267 macro->NumberOfParameters = 0;
3268 macro->Parameters = NULL;
3269 macro->IsFunction = 0;
3270 macro->IsExternal = 0;
3271 macro->IsExcluded = 0;
3275 * Free a preprocessor macro struct
3277 void vtkParsePreprocess_FreeMacro(MacroInfo *macro)
3281 free((char *)macro->Name);
3282 free((char *)macro->Definition);
3283 free((char *)macro->Comment);
3285 n = macro->NumberOfParameters;
3286 for (i = 0; i < n; i++)
3288 free((char *)macro->Parameters[i]);
3290 free((char **)macro->Parameters);
3296 * Initialize a preprocessor struct
3298 void vtkParsePreprocess_Init(
3299 PreprocessInfo *info, const char *filename)
3301 info->FileName = NULL;
3302 info->MacroHashTable = NULL;
3303 info->NumberOfIncludeDirectories = 0;
3304 info->IncludeDirectories = NULL;
3305 info->NumberOfIncludeFiles = 0;
3306 info->IncludeFiles = NULL;
3307 info->IsExternal = 0;
3308 info->ConditionalDepth = 0;
3309 info->ConditionalDone = 0;
3313 info->FileName = preproc_strndup(filename, strlen(filename));
3318 * Free a preprocessor struct and its contents
3320 void vtkParsePreprocess_Free(PreprocessInfo *info)
3325 free((char *)info->FileName);
3327 if (info->MacroHashTable)
3329 n = PREPROC_HASH_TABLE_SIZE;
3330 for (i = 0; i < n; i++)
3332 mptr = info->MacroHashTable[i];
3337 vtkParsePreprocess_FreeMacro(*mptr++);
3340 free(info->MacroHashTable[i]);
3342 free(info->MacroHashTable);
3345 n = info->NumberOfIncludeDirectories;
3346 for (i = 0; i < n; i++)
3348 free((char *)info->IncludeDirectories[i]);
3350 free((char **)info->IncludeDirectories);
3352 n = info->NumberOfIncludeFiles;
3353 for (i = 0; i < n; i++)
3355 free((char *)info->IncludeFiles[i]);
3357 free((char **)info->IncludeFiles);