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 /** Extend dynamic arrays in a progression of powers of two.
58 * Whenever "n" reaches a power of two, then the array size is
59 * doubled so that "n" can be safely incremented. */
60 static void *preproc_array_check(
61 void *arraymem, size_t size, int n)
63 /* if empty, alloc for the first time */
68 /* if count is power of two, reallocate with double size */
69 else if ((n & (n-1)) == 0)
71 return realloc(arraymem, (n << 1)*size);
74 /* no reallocation, just return the original array */
78 /** Convert string to int. */
79 static preproc_int_t string_to_preproc_int(const char *cp, int base)
81 #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
82 return _strtoi64(cp, NULL, base);
84 return strtoll(cp, NULL, base);
88 /** Convert string to unsigned int. */
89 static preproc_uint_t string_to_preproc_uint(const char *cp, int base)
91 #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
92 return _strtoui64(cp, NULL, base);
94 return strtoull(cp, NULL, base);
98 /** Tokenize and compare two strings */
99 static int preproc_identical(const char *text1, const char *text2)
112 vtkParse_InitTokenizer(&t1, text1, WS_PREPROC);
113 vtkParse_InitTokenizer(&t2, text2, WS_PREPROC);
117 if (t1.tok != t2.tok ||
118 t1.hash != t2.hash ||
120 strncmp(t1.text, t2.text, t1.len) != 0)
124 vtkParse_NextToken(&t1);
125 vtkParse_NextToken(&t2);
127 while (t1.tok && t2.tok);
129 result = (t1.tok == 0 && t2.tok == 0);
136 /** Create a new preprocessor macro. */
137 static MacroInfo *preproc_new_macro(
138 PreprocessInfo *info, const char *name, const char *definition)
140 MacroInfo *macro = (MacroInfo *)malloc(sizeof(MacroInfo));
141 vtkParsePreprocess_InitMacro(macro);
145 size_t n = vtkParse_SkipId(name);
146 macro->Name = vtkParse_CacheString(info->Strings, name, n);
152 const char *cp = definition;
153 StringTokenizer tokens;
154 vtkParse_InitTokenizer(&tokens, cp, WS_PREPROC);
158 cp = tokens.text + tokens.len;
160 while (vtkParse_NextToken(&tokens));
163 macro->Definition = vtkParse_CacheString(info->Strings, definition, n);
166 macro->IsExternal = info->IsExternal;
171 /** Free a preprocessor macro struct. */
172 static void preproc_free_macro(MacroInfo *info)
177 /** Find a preprocessor macro, return 0 if not found. */
178 static MacroInfo *preproc_find_macro(
179 PreprocessInfo *info, StringTokenizer *token)
181 unsigned int m = PREPROC_HASH_TABLE_SIZE - 1;
182 unsigned int i = (token->hash & m);
183 const char *name = token->text;
184 size_t l = token->len;
185 MacroInfo ***htable = info->MacroHashTable;
189 if (htable && ((hptr = htable[i]) != NULL) && *hptr)
193 mname = (*hptr)->Name;
194 if (mname[0] == name[0] &&
195 strncmp(mname, name, l) == 0 &&
208 /** Return the address of the macro within the hash table.
209 * If "insert" is nonzero, add a new location if macro not found. */
210 static MacroInfo **preproc_macro_location(
211 PreprocessInfo *info, StringTokenizer *token, int insert)
213 MacroInfo ***htable = info->MacroHashTable;
214 unsigned int m = PREPROC_HASH_TABLE_SIZE - 1;
215 unsigned int i = (token->hash & m);
216 const char *name = token->text;
217 size_t l = token->len;
229 m = PREPROC_HASH_TABLE_SIZE;
230 htable = (MacroInfo ***)malloc(m*sizeof(MacroInfo **));
231 info->MacroHashTable = htable;
232 do { *htable++ = NULL; } while (--m);
233 htable = info->MacroHashTable;
245 hptr = (MacroInfo **)malloc(2*sizeof(MacroInfo *));
252 /* see if macro is already there */
256 mname = (*hptr)->Name;
257 if (mname[0] == name[0] &&
258 strncmp(mname, name, l) == 0 &&
275 /* if n+1 is a power of two, double allocated space */
276 if (n > 0 && (n & (n+1)) == 0)
279 hptr = (MacroInfo **)realloc(hptr, (2*(n+1))*sizeof(MacroInfo *));
284 /* add a terminating null */
292 /** Remove a preprocessor macro. Returns 0 if macro not found. */
293 static int preproc_remove_macro(
294 PreprocessInfo *info, StringTokenizer *token)
298 hptr = preproc_macro_location(info, token, 0);
302 preproc_free_macro(*hptr);
317 /** A simple way to add a preprocessor macro definition. */
318 static MacroInfo *preproc_add_macro_definition(
319 PreprocessInfo *info, const char *name, const char *definition)
321 StringTokenizer token;
325 vtkParse_InitTokenizer(&token, name, WS_PREPROC);
327 macro = preproc_new_macro(info, name, definition);
328 macro_p = preproc_macro_location(info, &token, 1);
332 fprintf(stderr, "duplicate macro definition %s\n", name);
340 /** Skip over parentheses, return nonzero if not closed. */
341 static int preproc_skip_parentheses(StringTokenizer *tokens)
345 if (tokens->tok == '(')
349 while (depth > 0 && vtkParse_NextToken(tokens))
351 if (tokens->tok == '(')
355 else if (tokens->tok == ')')
362 if (tokens->tok == ')')
364 vtkParse_NextToken(tokens);
369 fprintf(stderr, "syntax error %d\n", __LINE__);
371 return VTK_PARSE_SYNTAX_ERROR;
375 /** Evaluate a char literal to an integer value. */
376 static int preproc_evaluate_char(
377 const char *cp, preproc_int_t *val, int *is_unsigned)
386 else if (*cp != '\'' && *cp != '\n' && *cp != '\0')
389 if (*cp == 'a') { *val = '\a'; }
390 else if (*cp == 'b') { *val = '\b'; }
391 else if (*cp == 'f') { *val = '\f'; }
392 else if (*cp == 'n') { *val = '\n'; }
393 else if (*cp == 'r') { *val = '\r'; }
394 else if (*cp == 'b') { *val = '\b'; }
395 else if (*cp == 't') { *val = '\t'; }
396 else if (*cp == 'v') { *val = '\v'; }
397 else if (*cp == '\'') { *val = '\''; }
398 else if (*cp == '\"') { *val = '\"'; }
399 else if (*cp == '\\') { *val = '\\'; }
400 else if (*cp == '\?') { *val = '\?'; }
403 *val = string_to_preproc_int(cp, 8);
404 do { cp++; } while (*cp >= '0' && *cp <= '7');
408 *val = string_to_preproc_int(cp+1, 16);
409 do { cp++; } while (vtkParse_CharType(*cp, CPRE_HEX));
415 fprintf(stderr, "syntax error %d\n", __LINE__);
417 return VTK_PARSE_SYNTAX_ERROR;
425 fprintf(stderr, "syntax error %d\n", __LINE__);
427 return VTK_PARSE_SYNTAX_ERROR;
430 /* Evaluate an integer, ignoring any suffixes except 'u'. */
431 static int preproc_evaluate_integer(
432 const char *cp, preproc_int_t *val, int *is_unsigned)
438 if (cp[0] == '0' && (cp[1] == 'x' || cp[1] == 'X'))
444 while (vtkParse_CharType(*ep, CPRE_HEX))
449 else if (cp[0] == '0' && vtkParse_CharType(cp[1], CPRE_DIGIT))
455 while (*ep >= '0' && *ep <= '7')
464 while (vtkParse_CharType(*ep, CPRE_DIGIT))
472 if (ep[0] == 'i' && ep[1] == '6' && ep[2] == '4') { ep += 3; }
473 else if (*ep == 'u') { *is_unsigned = 1; ep++; }
474 else if (*ep == 'l' || *ep == 'L') { ep++; }
480 *val = (preproc_int_t)string_to_preproc_uint(cp, base);
484 *val = string_to_preproc_int(cp, base);
487 if (*ep == '.' || *ep == 'e' || *ep == 'E')
489 return VTK_PARSE_PREPROC_DOUBLE;
495 /* forward declaration */
496 static int preproc_evaluate_expression(
497 PreprocessInfo *info, StringTokenizer *tokens,
498 preproc_int_t *val, int *is_unsigned);
500 /** Evaluate a single item in an expression. */
501 static int preproc_evaluate_single(
502 PreprocessInfo *info, StringTokenizer *tokens,
503 preproc_int_t *val, int *is_unsigned)
505 int result = VTK_PARSE_OK;
507 while (tokens->tok == TOK_ID)
509 /* handle the "defined" keyword */
510 if (tokens->hash == HASH_DEFINED && tokens->len == 7 &&
511 strncmp("defined", tokens->text, tokens->len) == 0)
514 vtkParse_NextToken(tokens);
516 if (tokens->tok == '(')
519 vtkParse_NextToken(tokens);
521 if (tokens->tok != TOK_ID)
526 fprintf(stderr, "syntax error %d\n", __LINE__);
528 return VTK_PARSE_SYNTAX_ERROR;
531 /* do the name lookup */
533 *val = (preproc_find_macro(info, tokens) != 0);
535 vtkParse_NextToken(tokens);
538 if (tokens->tok != ')')
541 fprintf(stderr, "syntax error %d\n", __LINE__);
543 return VTK_PARSE_SYNTAX_ERROR;
545 vtkParse_NextToken(tokens);
552 /* look up and evaluate the macro */
553 MacroInfo *macro = preproc_find_macro(info, tokens);
554 const char *args = NULL;
555 const char *expansion = NULL;
557 vtkParse_NextToken(tokens);
561 if (macro == NULL || macro->IsExcluded)
563 return VTK_PARSE_MACRO_UNDEFINED;
565 else if (macro->IsFunction)
567 /* expand function macros using the arguments */
569 if (tokens->tok != '(' ||
570 preproc_skip_parentheses(tokens) != VTK_PARSE_OK)
573 fprintf(stderr, "syntax error %d\n", __LINE__);
575 return VTK_PARSE_SYNTAX_ERROR;
578 expansion = vtkParsePreprocess_ExpandMacro(info, macro, args);
579 if (expansion == NULL)
583 fprintf(stderr, "syntax error %d\n", __LINE__);
585 return (args ? VTK_PARSE_MACRO_NUMARGS : VTK_PARSE_SYNTAX_ERROR);
588 cp += vtkParse_SkipWhitespace(cp, WS_PREPROC);
591 macro->IsExcluded = 1;
592 result = vtkParsePreprocess_EvaluateExpression(
593 info, expansion, val, is_unsigned);
594 macro->IsExcluded = 0;
595 vtkParsePreprocess_FreeMacroExpansion(
596 info, macro, expansion);
599 vtkParsePreprocess_FreeMacroExpansion(info, macro, expansion);
601 /* if macro expansion was empty, continue */
604 if (tokens->tok == '(')
606 vtkParse_NextToken(tokens);
607 result = preproc_evaluate_expression(info, tokens, val, is_unsigned);
608 if ((result & VTK_PARSE_FATAL_ERROR) == 0)
610 if (tokens->tok == ')')
612 vtkParse_NextToken(tokens);
616 fprintf(stderr, "syntax error %d\n", __LINE__);
618 return VTK_PARSE_SYNTAX_ERROR;
622 else if (tokens->tok == TOK_NUMBER)
624 result = preproc_evaluate_integer(tokens->text, val, is_unsigned);
625 if (tokens->text[tokens->len-1] == 'f' ||
626 tokens->text[tokens->len-1] == 'F')
628 result = VTK_PARSE_PREPROC_FLOAT;
630 vtkParse_NextToken(tokens);
633 else if (tokens->tok == TOK_CHAR)
635 result = preproc_evaluate_char(tokens->text, val, is_unsigned);
636 vtkParse_NextToken(tokens);
639 else if (tokens->tok == TOK_STRING)
643 vtkParse_NextToken(tokens);
644 while (tokens->tok == TOK_STRING)
646 vtkParse_NextToken(tokens);
648 return VTK_PARSE_PREPROC_STRING;
654 fprintf(stderr, "syntax error %d \"%*.*s\"\n", __LINE__,
655 (int)tokens->len, (int)tokens->len, tokens->text);
657 return VTK_PARSE_SYNTAX_ERROR;
660 static int preproc_evaluate_unary(
661 PreprocessInfo *info, StringTokenizer *tokens,
662 preproc_int_t *val, int *is_unsigned)
664 int op = tokens->tok;
665 int result = VTK_PARSE_OK;
667 if (op != '+' && op != '-' && op != '~' && op != '!')
669 return preproc_evaluate_single(info, tokens, val, is_unsigned);
672 vtkParse_NextToken(tokens);
674 result = preproc_evaluate_unary(info, tokens, val, is_unsigned);
675 if ((result & VTK_PARSE_FATAL_ERROR) == 0)
677 if (op == '~') { *val = ~(*val); }
678 else if (op == '!') { *val = !(*val); *is_unsigned = 0; }
679 else if (op == '-') { *val = -(*val); }
686 static int preproc_evaluate_multiply(
687 PreprocessInfo *info, StringTokenizer *tokens,
688 preproc_int_t *val, int *is_unsigned)
695 result = preproc_evaluate_unary(info, tokens, val, is_unsigned);
696 while ((result & VTK_PARSE_FATAL_ERROR) == 0)
699 if (op != '*' && op != '/' && op != '%')
704 vtkParse_NextToken(tokens);
706 result = preproc_evaluate_unary(info, tokens, &rval, &rtype);
708 *is_unsigned = (*is_unsigned || rtype);
714 *val = (preproc_int_t)((preproc_uint_t)*val *
715 (preproc_uint_t)rval);
721 *val = (preproc_int_t)((preproc_uint_t)*val /
722 (preproc_uint_t)rval);
733 *val = (preproc_int_t)((preproc_uint_t)*val %
734 (preproc_uint_t)rval);
784 static int preproc_evaluate_add(
785 PreprocessInfo *info, StringTokenizer *tokens,
786 preproc_int_t *val, int *is_unsigned)
793 result = preproc_evaluate_multiply(info, tokens, val, is_unsigned);
794 while ((result & VTK_PARSE_FATAL_ERROR) == 0)
797 if (op != '+' && op != '-')
802 vtkParse_NextToken(tokens);
804 result = preproc_evaluate_multiply(info, tokens, &rval, &rtype);
806 *is_unsigned = (*is_unsigned || rtype);
821 static int preproc_evaluate_bitshift(
822 PreprocessInfo *info, StringTokenizer *tokens,
823 preproc_int_t *val, int *is_unsigned)
830 result = preproc_evaluate_add(info, tokens, val, is_unsigned);
831 while ((result & VTK_PARSE_FATAL_ERROR) == 0)
835 if (op != TOK_LSHIFT && op != TOK_RSHIFT)
840 vtkParse_NextToken(tokens);
842 result = preproc_evaluate_add(info, tokens, &rval, &rtype);
846 if (op == TOK_LSHIFT)
848 *val = (preproc_int_t)((preproc_uint_t)*val << rval);
850 else if (op == TOK_RSHIFT)
852 *val = (preproc_int_t)((preproc_uint_t)*val >> rval);
857 if (op == TOK_LSHIFT)
861 else if (op == TOK_RSHIFT)
871 static int preproc_evaluate_compare(
872 PreprocessInfo *info, StringTokenizer *tokens,
873 preproc_int_t *val, int *is_unsigned)
880 result = preproc_evaluate_bitshift(info, tokens, val, is_unsigned);
881 while ((result & VTK_PARSE_FATAL_ERROR) == 0)
884 if (op != '<' && op != '>' && op != TOK_LE && op != TOK_GE)
889 vtkParse_NextToken(tokens);
891 result = preproc_evaluate_bitshift(info, tokens, &rval, &rtype);
893 *is_unsigned = (*is_unsigned || rtype);
899 *val = ((preproc_uint_t)*val <= (preproc_uint_t)rval);
903 *val = ((preproc_uint_t)*val < (preproc_uint_t)rval);
905 else if (op == TOK_GE)
907 *val = ((preproc_uint_t)*val >= (preproc_uint_t)rval);
911 *val = ((preproc_uint_t)*val > (preproc_uint_t)rval);
918 *val = (*val <= rval);
922 *val = (*val < rval);
924 else if (op == TOK_GE)
926 *val = (*val >= rval);
930 *val = (*val > rval);
939 static int preproc_evaluate_equal(
940 PreprocessInfo *info, StringTokenizer *tokens,
941 preproc_int_t *val, int *is_unsigned)
948 result = preproc_evaluate_compare(info, tokens, val, is_unsigned);
949 while ((result & VTK_PARSE_FATAL_ERROR) == 0)
952 if (op != TOK_EQ && op != TOK_NE)
957 vtkParse_NextToken(tokens);
959 result = preproc_evaluate_compare(info, tokens, &rval, &rtype);
963 *val = (*val == rval);
965 else if (op == TOK_NE)
967 *val = (*val != rval);
975 static int preproc_evaluate_and(
976 PreprocessInfo *info, StringTokenizer *tokens,
977 preproc_int_t *val, int *is_unsigned)
983 result = preproc_evaluate_equal(info, tokens, val, is_unsigned);
984 while ((result & VTK_PARSE_FATAL_ERROR) == 0)
986 if (tokens->tok != '&')
991 vtkParse_NextToken(tokens);
993 result = preproc_evaluate_equal(info, tokens, &rval, &rtype);
995 *is_unsigned = (*is_unsigned || rtype);
996 *val = (*val & rval);
1002 static int preproc_evaluate_xor(
1003 PreprocessInfo *info, StringTokenizer *tokens,
1004 preproc_int_t *val, int *is_unsigned)
1010 result = preproc_evaluate_and(info, tokens, val, is_unsigned);
1011 while ((result & VTK_PARSE_FATAL_ERROR) == 0)
1013 if (tokens->tok != '^')
1018 vtkParse_NextToken(tokens);
1020 result = preproc_evaluate_and(info, tokens, &rval, &rtype);
1022 *is_unsigned = (*is_unsigned || rtype);
1023 *val = (*val ^ rval);
1029 static int preproc_evaluate_or(
1030 PreprocessInfo *info, StringTokenizer *tokens,
1031 preproc_int_t *val, int *is_unsigned)
1037 result = preproc_evaluate_xor(info, tokens, val, is_unsigned);
1038 while ((result & VTK_PARSE_FATAL_ERROR) == 0)
1040 if (tokens->tok != '|')
1045 vtkParse_NextToken(tokens);
1047 result = preproc_evaluate_xor(info, tokens, &rval, &rtype);
1049 *is_unsigned = (*is_unsigned || rtype);
1050 *val = (*val | rval);
1056 static int preproc_evaluate_logic_and(
1057 PreprocessInfo *info, StringTokenizer *tokens,
1058 preproc_int_t *val, int *is_unsigned)
1064 result = preproc_evaluate_or(info, tokens, val, is_unsigned);
1065 while ((result & VTK_PARSE_FATAL_ERROR) == 0)
1067 if (tokens->tok != TOK_AND)
1072 vtkParse_NextToken(tokens);
1077 while (tokens->tok != 0 && tokens->tok != ')' &&
1078 tokens->tok != ':' && tokens->tok != '?' &&
1079 tokens->tok != ',' && tokens->tok != TOK_OR)
1081 if (tokens->tok == '(')
1083 if (preproc_skip_parentheses(tokens) != VTK_PARSE_OK)
1086 fprintf(stderr, "syntax error %d\n", __LINE__);
1088 result = VTK_PARSE_SYNTAX_ERROR;
1093 vtkParse_NextToken(tokens);
1102 result = preproc_evaluate_or(info, tokens, &rval, &rtype);
1111 static int preproc_evaluate_logic_or(
1112 PreprocessInfo *info, StringTokenizer *tokens,
1113 preproc_int_t *val, int *is_unsigned)
1119 result = preproc_evaluate_logic_and(info, tokens, val, is_unsigned);
1120 while ((result & VTK_PARSE_FATAL_ERROR) == 0)
1122 if (tokens->tok != TOK_OR)
1127 vtkParse_NextToken(tokens);
1132 while (tokens->tok != 0 && tokens->tok != ')' &&
1133 tokens->tok != ':' && tokens->tok != '?' &&
1136 if (tokens->tok == '(')
1138 if (preproc_skip_parentheses(tokens) != VTK_PARSE_OK)
1141 fprintf(stderr, "syntax error %d\n", __LINE__);
1143 result = VTK_PARSE_SYNTAX_ERROR;
1148 vtkParse_NextToken(tokens);
1157 result = preproc_evaluate_logic_and(info, tokens, &rval, &rtype);
1166 /** Evaluate an arimetic *expression. */
1167 int preproc_evaluate_expression(
1168 PreprocessInfo *info, StringTokenizer *tokens,
1169 preproc_int_t *val, int *is_unsigned)
1171 preproc_int_t rval, sval;
1175 result = preproc_evaluate_logic_or(info, tokens, val, is_unsigned);
1176 if ((result & VTK_PARSE_FATAL_ERROR) == 0)
1178 if (tokens->tok != '?')
1183 vtkParse_NextToken(tokens);
1185 result = preproc_evaluate_expression(info, tokens, &rval, &rtype);
1186 if ((result & VTK_PARSE_FATAL_ERROR) != 0)
1191 if (tokens->tok != ':')
1194 fprintf(stderr, "syntax error %d\n", __LINE__);
1196 return VTK_PARSE_SYNTAX_ERROR;
1199 vtkParse_NextToken(tokens);
1201 result = preproc_evaluate_expression(info, tokens, &sval, &stype);
1202 if ((result & VTK_PARSE_FATAL_ERROR) != 0)
1210 *is_unsigned = rtype;
1215 *is_unsigned = stype;
1222 /** Evaluate a conditional *expression.
1223 * Returns VTK_PARSE_OK if the expression is true,
1224 * or VTK_PARSE_SKIP of the expression is false. */
1225 int preproc_evaluate_conditional(
1226 PreprocessInfo *info, StringTokenizer *tokens)
1232 result = preproc_evaluate_expression(info, tokens, &rval, &rtype);
1233 if ((result & VTK_PARSE_FATAL_ERROR) == 0)
1235 if (tokens->tok != 0)
1238 fprintf(stderr, "syntax error %d\n", __LINE__);
1240 return VTK_PARSE_SYNTAX_ERROR;
1242 return (rval == 0 ? VTK_PARSE_SKIP : VTK_PARSE_OK);
1249 * Handle any of the following directives:
1250 * #if, #ifdef, #ifndef, #elif, #else, #endif
1251 * A return value of VTK_PARSE_SKIP means that
1252 * the following code block should be skipped.
1254 static int preproc_evaluate_if(
1255 PreprocessInfo *info, StringTokenizer *tokens)
1259 int result = VTK_PARSE_OK;
1261 if (tokens->hash == HASH_IF ||
1262 tokens->hash == HASH_IFDEF ||
1263 tokens->hash == HASH_IFNDEF)
1265 if (info->ConditionalDepth == 0)
1267 if (tokens->hash == HASH_IF)
1269 vtkParse_NextToken(tokens);
1270 result = preproc_evaluate_conditional(info, tokens);
1274 v1 = (tokens->hash != HASH_IFNDEF);
1275 vtkParse_NextToken(tokens);
1276 if (tokens->tok != TOK_ID)
1279 fprintf(stderr, "syntax error %d\n", __LINE__);
1281 return VTK_PARSE_SYNTAX_ERROR;
1283 macro = preproc_find_macro(info, tokens);
1284 v2 = (macro && !macro->IsExcluded);
1285 vtkParse_NextToken(tokens);
1286 result = ( (v1 ^ v2) ? VTK_PARSE_SKIP : VTK_PARSE_OK);
1289 if (result != VTK_PARSE_SKIP)
1291 /* mark as done, so that the "else" clause is skipped */
1292 info->ConditionalDone = 1;
1296 /* mark as not done, so that "else" clause is not skipped */
1297 info->ConditionalDone = 0;
1298 /* skip the "if" clause */
1299 info->ConditionalDepth = 1;
1304 /* increase the skip depth */
1305 info->ConditionalDepth++;
1308 else if (tokens->hash == HASH_ELIF ||
1309 tokens->hash == HASH_ELSE)
1311 if (info->ConditionalDepth == 0)
1313 /* preceding clause was not skipped, so must skip this one */
1314 info->ConditionalDepth = 1;
1316 else if (info->ConditionalDepth == 1 &&
1317 info->ConditionalDone == 0)
1319 if (tokens->hash == HASH_ELIF)
1321 vtkParse_NextToken(tokens);
1322 result = preproc_evaluate_conditional(info, tokens);
1326 vtkParse_NextToken(tokens);
1328 if (result != VTK_PARSE_SKIP)
1330 /* do not skip this clause */
1331 info->ConditionalDepth = 0;
1332 /* make sure remaining else/elif clauses are skipped */
1333 info->ConditionalDone = 1;
1337 else if (tokens->hash == HASH_ENDIF)
1339 vtkParse_NextToken(tokens);
1340 if (info->ConditionalDepth > 0)
1342 /* decrease the skip depth */
1343 info->ConditionalDepth--;
1345 if (info->ConditionalDepth == 0)
1347 /* set "done" flag for the context that is being returned to */
1348 info->ConditionalDone = 1;
1356 * Handle the #define and #undef directives.
1358 static int preproc_evaluate_define(
1359 PreprocessInfo *info, StringTokenizer *tokens)
1361 MacroInfo **macro_p;
1367 const char *definition = 0;
1369 const char **params = NULL;
1373 if (tokens->hash == HASH_DEFINE)
1375 vtkParse_NextToken(tokens);
1376 if (tokens->tok != TOK_ID)
1379 fprintf(stderr, "syntax error %d\n", __LINE__);
1381 return VTK_PARSE_SYNTAX_ERROR;
1384 macro_p = preproc_macro_location(info, tokens, 1);
1385 name = tokens->text;
1386 namelen = tokens->len;
1387 vtkParse_NextToken(tokens);
1391 if (name[namelen] == '(')
1394 vtkParse_NextToken(tokens);
1395 while (tokens->tok != 0 && tokens->tok != ')')
1397 if (tokens->tok != TOK_ID && tokens->tok != TOK_ELLIPSIS)
1399 if (params) { free((char **)params); }
1401 fprintf(stderr, "syntax error %d\n", __LINE__);
1403 return VTK_PARSE_SYNTAX_ERROR;
1406 param = tokens->text;
1409 if (tokens->tok == TOK_ELLIPSIS)
1412 param = "__VA_ARGS__";
1416 /* add to the arg list */
1417 params = (const char **)preproc_array_check(
1418 (char **)params, sizeof(char *), n);
1419 params[n++] = vtkParse_CacheString(info->Strings, param, l);
1421 vtkParse_NextToken(tokens);
1423 /* check for gnu cpp "arg..." parameter */
1424 if (tokens->tok == TOK_ELLIPSIS)
1427 vtkParse_NextToken(tokens);
1430 if (tokens->tok == ',')
1432 vtkParse_NextToken(tokens);
1434 else if (tokens->tok != ')')
1436 if (params) { free((char **)params); }
1438 fprintf(stderr, "syntax error %d\n", __LINE__);
1440 return VTK_PARSE_SYNTAX_ERROR;
1443 vtkParse_NextToken(tokens);
1448 definition = tokens->text;
1454 if (preproc_identical(macro->Definition, definition))
1456 return VTK_PARSE_OK;
1458 if (params) { free((char **)params); }
1460 fprintf(stderr, "macro redefined %d\n", __LINE__);
1462 return VTK_PARSE_MACRO_REDEFINED;
1465 macro = preproc_new_macro(info, name, definition);
1466 macro->IsFunction = is_function;
1467 macro->IsVariadic = is_variadic;
1468 macro->NumberOfParameters = n;
1469 macro->Parameters = params;
1472 return VTK_PARSE_OK;
1474 else if (tokens->hash == HASH_UNDEF)
1476 vtkParse_NextToken(tokens);
1477 if (tokens->tok != TOK_ID)
1480 fprintf(stderr, "syntax error %d\n", __LINE__);
1482 return VTK_PARSE_SYNTAX_ERROR;
1484 preproc_remove_macro(info, tokens);
1485 return VTK_PARSE_OK;
1488 return VTK_PARSE_OK;
1492 * Add an include file to the list. Return 0 if it is already there.
1494 static int preproc_add_include_file(PreprocessInfo *info, const char *name)
1498 n = info->NumberOfIncludeFiles;
1499 for (i = 0; i < n; i++)
1501 if (strcmp(info->IncludeFiles[i], name) == 0)
1507 info->IncludeFiles = (const char **)preproc_array_check(
1508 (char **)info->IncludeFiles, sizeof(char *), info->NumberOfIncludeFiles);
1509 info->IncludeFiles[info->NumberOfIncludeFiles++] =
1510 vtkParse_CacheString(info->Strings, name, strlen(name));
1516 * Find an include file. If "cache_only" is set, then do a check to
1517 * see if the file was previously found without going to the filesystem.
1519 const char *preproc_find_include_file(
1520 PreprocessInfo *info, const char *filename, int system_first,
1526 const char *directory;
1528 size_t outputsize = 16;
1531 /* allow filename to be terminated by quote or bracket */
1533 while (filename[m] != '\"' && filename[m] != '>' &&
1534 filename[m] != '\n' && filename[m] != '\0') { m++; }
1536 /* search file system for the file */
1537 output = (char *)malloc(outputsize);
1539 if (system_first != 0)
1544 if (cache_only != 0)
1549 /* check for absolute path of form DRIVE: or /path/to/file */
1551 while (vtkParse_CharType(filename[j], CPRE_IDGIT)) { j++; }
1553 if (filename[j] == ':' || filename[0] == '/' || filename[0] == '\\')
1555 if (m+1 > outputsize)
1558 output = (char *)realloc(output, outputsize);
1560 strncpy(output, filename, m);
1563 nn = info->NumberOfIncludeFiles;
1564 for (ii = 0; ii < nn; ii++)
1566 if (strcmp(output, info->IncludeFiles[ii]) == 0)
1569 return info->IncludeFiles[ii];
1579 info->IncludeFiles = (const char **)preproc_array_check(
1580 (char **)info->IncludeFiles, sizeof(char *),
1581 info->NumberOfIncludeFiles);
1582 info->IncludeFiles[info->NumberOfIncludeFiles++] = output;
1587 /* Make sure the current filename is already added */
1590 preproc_add_include_file(info, info->FileName);
1593 /* Check twice. First check the cache, then stat the files. */
1594 for (count = 0; count < (2-cache_only); count++)
1596 n = info->NumberOfIncludeDirectories;
1597 for (i = 0; i < (n+1-system_first); i++)
1599 /* search the directory of the file being processed */
1600 if (i == 0 && system_first == 0)
1604 j = strlen(info->FileName);
1607 if (info->FileName[j-1] == '/') { break; }
1610 if (m+j+1 > outputsize)
1612 outputsize += m+j+1;
1613 output = (char *)realloc(output, outputsize);
1617 strncpy(output, info->FileName, j);
1619 strncpy(&output[j], filename, m);
1624 if (m+1 > outputsize)
1627 output = (char *)realloc(output, outputsize);
1629 strncpy(output, filename, m);
1633 /* check all the search paths */
1636 directory = info->IncludeDirectories[i-1+system_first];
1637 j = strlen(directory);
1638 if (j + m + 2 > outputsize)
1640 outputsize += j+m+2;
1641 output = (char *)realloc(output, outputsize);
1644 strncpy(output, directory, j);
1645 if (directory[j-1] != '/') { output[j++] = '/'; }
1646 strncpy(&output[j], filename, m);
1652 nn = info->NumberOfIncludeFiles;
1653 for (ii = 0; ii < nn; ii++)
1655 if (strcmp(output, info->IncludeFiles[ii]) == 0)
1658 return info->IncludeFiles[ii];
1662 else if (stat(output, &fs) == 0)
1664 nn = info->NumberOfIncludeFiles;
1665 info->IncludeFiles = (const char **)preproc_array_check(
1666 (char **)info->IncludeFiles, sizeof(char *), nn);
1667 info->IncludeFiles[info->NumberOfIncludeFiles++] =
1668 vtkParse_CacheString(info->Strings, output, strlen(output));
1670 return info->IncludeFiles[nn];
1680 * Convert a raw string into a normal string. This is a helper
1681 * function for preproc_include_file() to allow raw strings to
1682 * be used in preprocessor directives.
1684 void preproc_escape_string(
1685 char **linep, size_t *linelenp, size_t *jp, size_t d, size_t dl)
1687 char *line = *linep;
1689 size_t linelen = *linelenp;
1690 size_t l = *jp - d - 2*dl - 2;
1696 r = (char *)malloc(l);
1697 memcpy(r, &line[j+dl+1], l);
1700 /* remove the "R" prefix */
1701 if (j >= 2 && line[j-1] == '\"' && line[j-2] == 'R')
1707 for (i = 0; i < l; i++)
1709 /* expand line buffer as necessary */
1710 while (j+4 > linelen)
1713 line = (char *)realloc(line, linelen);
1716 if ((r[i] >= ' ' && r[i] <= '~') || (r[i] & 0x80) != 0)
1722 case '\a': line[j++] = '\\'; line[j++] = 'a'; break;
1723 case '\b': line[j++] = '\\'; line[j++] = 'b'; break;
1724 case '\f': line[j++] = '\\'; line[j++] = 'f'; break;
1725 case '\n': line[j++] = '\\'; line[j++] = 'n'; break;
1726 case '\r': line[j++] = '\\'; line[j++] = 'r'; break;
1727 case '\t': line[j++] = '\\'; line[j++] = 't'; break;
1728 case '\v': line[j++] = '\\'; line[j++] = 'v'; break;
1729 case '\\': line[j++] = '\\'; line[j++] = '\\'; break;
1730 case '\'': line[j++] = '\\'; line[j++] = '\''; break;
1731 case '\"': line[j++] = '\\'; line[j++] = '\"'; break;
1733 sprintf(&line[j], "\\%3.3o", r[i]);
1741 *linelenp = linelen;
1746 * Include a file. All macros defined in the included file
1747 * will have their IsExternal flag set.
1749 static int preproc_include_file(
1750 PreprocessInfo *info, const char *filename, int system_first)
1752 const char *switchchars = "\n\r\"\'\?\\/*()";
1753 char switchchar[256];
1755 size_t tbuflen = FILE_BUFFER_SIZE;
1757 size_t linelen = 80;
1762 int result = VTK_PARSE_OK;
1764 const char *path = NULL;
1765 const char *save_filename;
1768 /* check to see if the file has aleady been included */
1769 path = preproc_find_include_file(info, filename, system_first, 1);
1774 while (filename[k] != '>' && filename[k] != '\"' &&
1775 filename[k] != '\n' && filename[k] != '\0') { k++; }
1776 if (filename[k] == '>')
1777 fprintf(stderr, "already loaded file <%*.*s>\n", k, k, filename);
1779 fprintf(stderr, "already loaded file \"%*.*s\"\n", k, k, filename);
1782 return VTK_PARSE_OK;
1784 /* go to the filesystem */
1785 path = preproc_find_include_file(info, filename, system_first, 0);
1790 while (filename[k] != '>' && filename[k] != '\"' &&
1791 filename[k] != '\n' && filename[k] != '\0') { k++; }
1792 if (filename[k] == '>')
1793 fprintf(stderr, "couldn't find file <%*.*s>\n", k, k, filename);
1795 fprintf(stderr, "couldn't find file \"%*.*s\"\n", k, k, filename);
1797 return VTK_PARSE_FILE_NOT_FOUND;
1801 fprintf(stderr, "including file %s\n", path);
1803 fp = fopen(path, "r");
1808 fprintf(stderr, "couldn't open file %s\n", path);
1810 return VTK_PARSE_FILE_OPEN_ERROR;
1813 save_external = info->IsExternal;
1814 save_filename = info->FileName;
1815 info->IsExternal = 1;
1816 info->FileName = path;
1818 /* make a table of interesting characters */
1819 memset(switchchar, '\0', 256);
1820 n = strlen(switchchars) + 1;
1821 for (i = 0; i < n; i++)
1823 switchchar[(unsigned char)(switchchars[i])] = 1;
1826 tbuf = (char *)malloc(tbuflen+4);
1827 line = (char *)malloc(linelen);
1829 /* the buffer must hold a whole line for it to be processed */
1839 /* recycle unused lookahead chars */
1845 tbuf[0] = tbuf[tbuflen-2];
1846 tbuf[1] = tbuf[tbuflen-1];
1850 tbuf[0] = tbuf[tbuflen-1];
1854 /* read the next chunk of the file */
1858 /* still have the lookahead chars left */
1864 /* fill the remainder of the buffer */
1866 tbuflen = r + FILE_BUFFER_SIZE;
1867 while ((n = fread(&tbuf[r], 1, tbuflen-r, fp)) == 0 && ferror(fp))
1874 info->IsExternal = save_external;
1875 return VTK_PARSE_FILE_READ_ERROR;
1881 if (n + r < tbuflen)
1883 /* this only occurs if the final fread does not fill the buffer */
1889 /* set a lookahead reserve of two chars */
1894 /* guard against lookahead past last char in file */
1899 /* copy the characters until end of line is found */
1902 /* expand line buffer as necessary */
1903 while (j+4 > linelen)
1906 line = (char *)realloc(line, linelen);
1909 /* check for uninteresting characters first */
1910 if (!switchchar[(unsigned char)(tbuf[i])])
1912 line[j++] = tbuf[i++];
1914 else if (state == '(')
1916 /* look for end of raw string delimiter */
1922 line[j++] = tbuf[i++];
1924 else if (state == ')')
1926 /* look for end of raw string */
1927 if (tbuf[i] == '\"')
1929 if ((j - d) > 2*dn+1 && line[j-dn-1] == ')' &&
1930 strncmp(&line[d], &line[j-dn], dn) == 0)
1932 preproc_escape_string(&line, &linelen, &j, d, dn);
1936 line[j++] = tbuf[i++];
1938 #ifdef PREPROC_TRIGRAPHS
1939 else if (tbuf[i] == '?' && tbuf[i+1] == '?')
1944 case '=': tbuf[i] = '#'; break;
1945 case '/': tbuf[i] = '\\'; break;
1946 case '\'': tbuf[i] = '^'; break;
1947 case '(': tbuf[i] = '['; break;
1948 case ')': tbuf[i] = ']'; break;
1949 case '!': tbuf[i] = '|'; break;
1950 case '<': tbuf[i] = '{'; break;
1951 case '>': tbuf[i] = '}'; break;
1952 case '-': tbuf[i] = '~'; break;
1953 default: line[j++] = tbuf[--i];
1957 else if (tbuf[i] == '\\' && tbuf[i+1] == '\n')
1961 else if (tbuf[i] == '\\' && tbuf[i+1] == '\r' && tbuf[i+2] == '\n')
1965 else if (tbuf[i] == '\r' && tbuf[i+1] == '\n')
1969 else if (state == '*')
1971 if (tbuf[i] == '*' && tbuf[i+1] == '/')
1973 line[j++] = tbuf[i++];
1974 line[j++] = tbuf[i++];
1979 line[j++] = tbuf[i++];
1982 else if (state == '/' && tbuf[i] != '\n')
1984 line[j++] = tbuf[i++];
1986 else if (state == '\'' || state == '\"')
1988 if (tbuf[i] == state)
1990 line[j++] = tbuf[i++];
1993 else if (tbuf[i] == '\\' && tbuf[i+1] != '\0')
1995 line[j++] = tbuf[i++];
1996 line[j++] = tbuf[i++];
2000 line[j++] = tbuf[i++];
2003 else if (tbuf[i] == '/')
2005 if (tbuf[i+1] == '*' || tbuf[i+1] == '/')
2008 line[j++] = tbuf[i++];
2010 line[j++] = tbuf[i++];
2012 else if (tbuf[i] == '\"' || tbuf[i] == '\'')
2015 /* check for raw string prefixes */
2016 if (state == '\"' && j > 0 && line[j-1] == 'R' &&
2018 (line[j-3] == 'u' || line[j-2] == '8') &&
2020 !vtkParse_CharType(line[j-4], CPRE_IDGIT|CPRE_QUOTE))) ||
2022 (line[j-2] == 'u' || line[j-2] == 'U' || line[j-2] == 'L') &&
2024 !vtkParse_CharType(line[j-3], CPRE_IDGIT|CPRE_QUOTE))) ||
2026 !vtkParse_CharType(line[j-2], CPRE_IDGIT|CPRE_QUOTE))))
2031 line[j++] = tbuf[i++];
2033 else if (tbuf[i] != '\n' && tbuf[i] != '\0')
2035 line[j++] = tbuf[i++];
2039 line[j++] = tbuf[i++];
2044 if (i < n || n == 0)
2046 const char *cp = line;
2049 cp += vtkParse_SkipWhitespace(cp, WS_PREPROC);
2052 vtkParsePreprocess_HandleDirective(info, line);
2062 info->IsExternal = save_external;
2063 info->FileName = save_filename;
2069 * Handle the #include directive. The header file will
2070 * only go through the preprocessor.
2072 static int preproc_evaluate_include(
2073 PreprocessInfo *info, StringTokenizer *tokens)
2076 const char *filename;
2078 if (tokens->hash == HASH_INCLUDE)
2080 vtkParse_NextToken(tokens);
2084 if (tokens->tok == TOK_ID)
2086 MacroInfo *macro = preproc_find_macro(info, tokens);
2087 if (macro && !macro->IsExcluded && macro->Definition)
2089 cp = macro->Definition;
2094 fprintf(stderr, "couldn't find macro %*.*s.\n",
2095 (int)tokens->len, (int)tokens->len, tokens->text);
2097 return VTK_PARSE_MACRO_UNDEFINED;
2104 cp += vtkParse_SkipQuotes(cp);
2105 if (cp <= filename + 1 || *(cp-1) != '\"')
2107 return VTK_PARSE_SYNTAX_ERROR;
2110 return preproc_include_file(info, filename, 0);
2112 else if (*cp == '<')
2116 while (*cp != '>' && *cp != '\n' && *cp != '\0') { cp++; }
2119 return VTK_PARSE_SYNTAX_ERROR;
2122 return preproc_include_file(info, filename, 1);
2126 return VTK_PARSE_OK;
2130 * Handle any recognized directive.
2131 * Unrecognized directives are ignored.
2133 int vtkParsePreprocess_HandleDirective(
2134 PreprocessInfo *info, const char *directive)
2136 int result = VTK_PARSE_OK;
2137 StringTokenizer tokens;
2139 vtkParse_InitTokenizer(&tokens, directive, WS_PREPROC);
2141 if (tokens.tok != '#')
2143 return VTK_PARSE_SYNTAX_ERROR;
2146 vtkParse_NextToken(&tokens);
2148 if (tokens.tok == TOK_ID)
2150 if ((tokens.hash == HASH_IFDEF && tokens.len == 5 &&
2151 strncmp("ifdef", tokens.text, tokens.len) == 0) ||
2152 (tokens.hash == HASH_IFNDEF && tokens.len == 6 &&
2153 strncmp("ifndef", tokens.text, tokens.len) == 0) ||
2154 (tokens.hash == HASH_IF && tokens.len == 2 &&
2155 strncmp("if", tokens.text, tokens.len) == 0) ||
2156 (tokens.hash == HASH_ELIF && tokens.len == 4 &&
2157 strncmp("elif", tokens.text, tokens.len) == 0) ||
2158 (tokens.hash == HASH_ELSE && tokens.len == 4 &&
2159 strncmp("else", tokens.text, tokens.len) == 0) ||
2160 (tokens.hash == HASH_ENDIF && tokens.len == 5 &&
2161 strncmp("endif", tokens.text, tokens.len) == 0))
2163 result = preproc_evaluate_if(info, &tokens);
2164 while (tokens.tok) { vtkParse_NextToken(&tokens); }
2167 size_t n = tokens.text - directive;
2169 if (result == VTK_PARSE_SKIP)
2171 fprintf(stderr, "SKIP: ");
2173 else if (result == VTK_PARSE_OK)
2175 fprintf(stderr, "READ: ");
2179 fprintf(stderr, "ERR%-2.2d ", result);
2181 fprintf(stderr, "%*.*s\n", (int)n, (int)n, directive);
2185 else if (info->ConditionalDepth == 0)
2187 if ((tokens.hash == HASH_DEFINE && tokens.len == 6 &&
2188 strncmp("define", tokens.text, tokens.len) == 0) ||
2189 (tokens.hash == HASH_UNDEF && tokens.len == 5 &&
2190 strncmp("undef", tokens.text, tokens.len) == 0))
2192 result = preproc_evaluate_define(info, &tokens);
2194 else if (tokens.hash == HASH_INCLUDE && tokens.len == 7 &&
2195 strncmp("include", tokens.text, tokens.len) == 0)
2197 result = preproc_evaluate_include(info, &tokens);
2202 if (info->ConditionalDepth > 0)
2204 return VTK_PARSE_SKIP;
2211 * Evaluate a preprocessor expression.
2212 * If no errors occurred, the result will be VTK_PARSE_OK.
2214 int vtkParsePreprocess_EvaluateExpression(
2215 PreprocessInfo *info, const char *text,
2216 preproc_int_t *val, int *is_unsigned)
2218 StringTokenizer tokens;
2219 vtkParse_InitTokenizer(&tokens, text, WS_PREPROC);
2221 return preproc_evaluate_expression(info, &tokens, val, is_unsigned);
2224 /** Add a macro for defining a macro */
2225 #define PREPROC_MACRO_TO_STRING2(x) #x
2226 #define PREPROC_MACRO_TO_STRING(x) PREPROC_MACRO_TO_STRING2(x)
2227 #define PREPROC_ADD_MACRO(info, x) \
2228 preproc_add_macro_definition(info, #x, PREPROC_MACRO_TO_STRING2(x))
2231 * Add all standard preprocessory macros. Specify the platform.
2233 void vtkParsePreprocess_AddStandardMacros(
2234 PreprocessInfo *info, int platform)
2236 int save_external = info->IsExternal;
2237 info->IsExternal = 1;
2239 /* a special macro to indicate that this is the wrapper */
2240 preproc_add_macro_definition(info, "__WRAP__", "1");
2242 /* language macros - assume that we are wrapping C++ code */
2243 preproc_add_macro_definition(info, "__cplusplus", "1");
2245 /* stdc version macros */
2247 PREPROC_ADD_MACRO(info, __STDC__);
2249 #ifdef __STDC_VERSION__
2250 PREPROC_ADD_MACRO(info, __STDC_VERSION__);
2252 #ifdef __STDC_HOSTED__
2253 PREPROC_ADD_MACRO(info, __STDC_HOSTED__);
2256 if (platform == VTK_PARSE_NATIVE)
2259 PREPROC_ADD_MACRO(info, WIN32);
2262 PREPROC_ADD_MACRO(info, _WIN32);
2265 PREPROC_ADD_MACRO(info, _MSC_VER);
2269 PREPROC_ADD_MACRO(info, __BORLAND__);
2273 PREPROC_ADD_MACRO(info, __CYGWIN__);
2276 PREPROC_ADD_MACRO(info, MINGW);
2279 PREPROC_ADD_MACRO(info, __MINGW32__);
2283 PREPROC_ADD_MACRO(info, __linux__);
2286 PREPROC_ADD_MACRO(info, __LINUX__);
2290 PREPROC_ADD_MACRO(info, __APPLE__);
2293 PREPROC_ADD_MACRO(info, __MACH__);
2296 PREPROC_ADD_MACRO(info, __DARWIN__);
2300 PREPROC_ADD_MACRO(info, __GNUC__);
2303 PREPROC_ADD_MACRO(info, __LP64__);
2305 #ifdef __BIG_ENDIAN__
2306 PREPROC_ADD_MACRO(info, __BIG_ENDIAN__);
2308 #ifdef __LITTLE_ENDIAN__
2309 PREPROC_ADD_MACRO(info, __LITTLE_ENDIAN__);
2313 info->IsExternal = save_external;
2317 * Add a preprocessor macro, including a definition.
2319 int vtkParsePreprocess_AddMacro(
2320 PreprocessInfo *info, const char *name, const char *definition)
2322 StringTokenizer token;
2323 MacroInfo **macro_p;
2326 vtkParse_InitTokenizer(&token, name, WS_PREPROC);
2327 macro_p = preproc_macro_location(info, &token, 1);
2331 if (preproc_identical(macro->Definition, definition))
2333 return VTK_PARSE_OK;
2337 return VTK_PARSE_MACRO_REDEFINED;
2341 macro = preproc_new_macro(info, name, definition);
2342 macro->IsExternal = 1;
2345 return VTK_PARSE_OK;
2349 * Return a preprocessor macro struct, or NULL if not found.
2351 MacroInfo *vtkParsePreprocess_GetMacro(
2352 PreprocessInfo *info, const char *name)
2354 StringTokenizer token;
2357 vtkParse_InitTokenizer(&token, name, WS_PREPROC);
2358 macro = preproc_find_macro(info, &token);
2360 if (macro && !macro->IsExcluded)
2369 * Remove a preprocessor macro.
2371 int vtkParsePreprocess_RemoveMacro(
2372 PreprocessInfo *info, const char *name)
2374 StringTokenizer token;
2376 vtkParse_InitTokenizer(&token, name, WS_PREPROC);
2378 if (preproc_remove_macro(info, &token))
2380 return VTK_PARSE_OK;
2383 return VTK_PARSE_MACRO_UNDEFINED;
2387 * Expand a macro, argstring is ignored if not a function macro
2389 const char *vtkParsePreprocess_ExpandMacro(
2390 PreprocessInfo *info, MacroInfo *macro, const char *argstring)
2392 const char *cp = argstring;
2395 const char *stack_values[8];
2396 const char **values = NULL;
2397 const char *pp = NULL;
2398 const char *dp = NULL;
2399 const char *wp = NULL;
2408 int empty_variadic = 0;
2412 if (macro->IsFunction)
2414 if (argstring == NULL || *cp != '(')
2419 /* break the string into individual argument values */
2420 values = stack_values;
2424 while (depth > 0 && *cp != '\0')
2428 if (*cp == '\"' || *cp == '\'')
2430 cp += vtkParse_SkipQuotes(cp);
2432 else if (cp[0] == '/' && (cp[1] == '*' || cp[1] == '/'))
2434 cp += vtkParse_SkipComment(cp);
2436 else if (*cp == '(')
2441 else if (*cp == ')')
2449 else if (*cp == ',')
2457 else if (*cp != '\0')
2462 if (n >= 8 && (n & (n-1)) == 0)
2464 if (values != stack_values)
2466 values = (const char **)realloc(
2467 (char **)values, 2*n*sizeof(const char **));
2471 values = (const char **)malloc(2*n*sizeof(const char **));
2472 memcpy((char **)values, stack_values, 8*sizeof(const char **));
2480 /* diagnostic: print out the values */
2482 for (j = 0; j < n; j++)
2484 size_t m = values[j+1] - values[j] - 1;
2485 fprintf(stderr, "arg %i: %*.*s\n",
2486 (int)j, (int)m, (int)m, values[j]);
2490 /* one arg that is only whitespace can also be no args*/
2491 if (macro->NumberOfParameters == 0 && n == 1)
2493 const char *tp = values[0];
2494 tp += vtkParse_SkipWhitespace(tp, WS_PREPROC);
2495 if (tp + 1 >= values[1])
2501 /* allow the variadic arg to be empty */
2502 if (macro->IsVariadic && n == macro->NumberOfParameters-1)
2507 /* check for correct number of arguments */
2508 if (n < (macro->NumberOfParameters - empty_variadic) ||
2509 (n > macro->NumberOfParameters && !macro->IsVariadic))
2511 if (values != stack_values) { free((char **)values); }
2513 fprintf(stderr, "wrong number of macro args to %s, %lu != %lu\n",
2514 macro->Name, n, macro->NumberOfParameters);
2520 cp = macro->Definition;
2521 cp = (cp ? cp : "");
2533 /* skip all chars that aren't part of a name */
2534 while (!vtkParse_CharType(*cp, CPRE_ID) && *cp != '\0')
2537 cp += vtkParse_SkipWhitespace(cp, WS_PREPROC);
2542 else if (vtkParse_CharType(*cp, CPRE_QUOTE))
2544 cp += vtkParse_SkipQuotes(cp);
2549 else if (vtkParse_CharType(*cp, CPRE_DIGIT))
2551 cp += vtkParse_SkipNumber(cp);
2556 else if (cp[0] == '#' && cp[1] == '#')
2562 cp += vtkParse_SkipWhitespace(cp, WS_PREPROC);
2565 else if (*cp == '#')
2571 cp += vtkParse_SkipWhitespace(cp, WS_PREPROC);
2584 if (i + l + 1 >= rs)
2586 rs += rs + i + l + 1;
2589 rp = (char *)realloc(rp, rs);
2593 rp = (char *)malloc(rs);
2594 memcpy(rp, stack_rp, i);
2597 strncpy(&rp[i], pp, l);
2604 l = vtkParse_SkipId(cp);
2608 for (j = 0; j < macro->NumberOfParameters; j++)
2610 /* check whether the name matches a parameter */
2611 if (strncmp(pp, macro->Parameters[j], l) == 0 &&
2612 macro->Parameters[j][l] == '\0')
2614 if (macro->IsVariadic && j == macro->NumberOfParameters-1)
2616 /* if variadic arg, use all remaining args */
2617 pp = values[j] - empty_variadic;
2618 l = values[n] - pp - 1;
2622 /* else just get one arg */
2624 l = values[j+1] - pp - 1;
2626 /* remove leading whitespace from argument */
2628 while (vtkParse_CharType(c, CPRE_WHITE))
2633 /* remove trailing whitespace from argument */
2637 while (vtkParse_CharType(c, CPRE_WHITE))
2646 /* check if followed by "##" */
2648 wp += vtkParse_SkipWhitespace(wp, WS_PREPROC);
2649 if (wp[0] == '#' && wp[1] == '#')
2658 /* compute number of chars that will be added */
2660 for (k = 0; k < l; k++)
2663 if (c == '\\' || c == '\"')
2669 if (i + l + stringify + 1 >= rs)
2671 rs += rs + i + l + 1;
2674 rp = (char *)realloc(rp, rs);
2678 rp = (char *)malloc(rs);
2679 memcpy(rp, stack_rp, i);
2684 /* convert argument into a string, due to "#" */
2686 for (k = 0; k < l; k++)
2689 if (c == '\\' || c == '\"')
2697 else if (empty_variadic && j == macro->NumberOfParameters-1)
2699 /* remove trailing comma before empty variadic (non-standard) */
2707 while (k > 0 && vtkParse_CharType(c, CPRE_WHITE));
2716 /* do not expand args that will be concatenated with "##" */
2717 strncpy(&rp[i], pp, l);
2722 /* process the arguments before substituting them */
2724 int is_excluded = macro->IsExcluded;
2725 macro->IsExcluded = 1;
2726 strncpy(&rp[i], pp, l);
2728 text = vtkParsePreprocess_ProcessString(info, &rp[i]);
2735 if (i + l + 1 >= rs)
2737 rs += rs + i + l + 1;
2739 rp = (char *)malloc(rs);
2742 strncpy(&rp[i], text, l);
2743 vtkParsePreprocess_FreeProcessedString(info, text);
2744 if (tp && tp != stack_rp)
2750 macro->IsExcluded = is_excluded;
2757 if (values != stack_values) { free((char **)values); }
2759 if (!macro->IsFunction && macro->Definition &&
2760 strcmp(rp, macro->Definition) == 0)
2762 if (rp != stack_rp) { free(rp); }
2763 return macro->Definition;
2768 rp = (char *)malloc(strlen(stack_rp) + 1);
2769 strcpy(rp, stack_rp);
2778 const char *vtkParsePreprocess_ProcessString(
2779 PreprocessInfo *info, const char *text)
2787 StringTokenizer tokens;
2788 vtkParse_InitTokenizer(&tokens, text, WS_PREPROC);
2795 size_t l = tokens.len;
2797 const char *cp = tokens.text;
2800 if (tokens.tok == TOK_STRING && last_tok == TOK_STRING)
2804 do { --i; } while (i > 0 && rp[i] != '\"');
2806 while (*cp != '\"' && l > 1) { cp++; l--; }
2807 if (*cp == '\"' && l > 1) { cp++; l--; }
2810 if (i + l + 2 >= rs)
2812 rs += rs + i + l + 2;
2815 rp = (char *)malloc(rs);
2816 memcpy(rp, stack_rp, i);
2820 rp = (char *)realloc(rp, rs);
2824 /* copy the token, removing backslash-newline */
2827 for (j = 0; j < l; j++)
2831 if (dp[1] == '\n') { dp += 2; }
2832 else if (dp[1] == '\r' && dp[2] == '\n') { dp += 3; }
2833 else { *ep++ = *dp++; }
2842 if (tokens.tok == TOK_ID)
2844 MacroInfo *macro = preproc_find_macro(info, &tokens);
2845 if (macro && !macro->IsExcluded)
2847 const char *args = NULL;
2850 if (macro->IsFunction)
2852 /* expand function macros using the arguments */
2853 vtkParse_NextToken(&tokens);
2854 if (tokens.tok == '(')
2858 while (depth > 0 && vtkParse_NextToken(&tokens))
2860 if (tokens.tok == '(')
2864 else if (tokens.tok == ')')
2869 if (tokens.tok != ')')
2871 if (rp != stack_rp) { free(rp); }
2877 /* unput the last token if it isn't "(" */
2885 const char *expansion;
2886 const char *processed;
2887 expansion = vtkParsePreprocess_ExpandMacro(info, macro, args);
2888 if (expansion == NULL)
2890 if (rp != stack_rp) { free(rp); }
2893 macro->IsExcluded = 1;
2894 processed = vtkParsePreprocess_ProcessString(info, expansion);
2895 macro->IsExcluded = 0;
2896 if (processed == NULL)
2898 vtkParsePreprocess_FreeMacroExpansion(info, macro, expansion);
2899 if (rp != stack_rp) { free(rp); }
2902 l = strlen(processed);
2905 if (i + l + 2 >= rs)
2907 rs += rs + i + l + 2;
2910 rp = (char *)malloc(rs);
2911 memcpy(rp, stack_rp, i);
2915 rp = (char *)realloc(rp, rs);
2918 strncpy(&rp[i], processed, l);
2920 if (processed != expansion)
2922 vtkParsePreprocess_FreeProcessedString(info, processed);
2924 vtkParsePreprocess_FreeMacroExpansion(info, macro, expansion);
2931 last_tok = tokens.tok;
2934 if (vtkParse_NextToken(&tokens) && tokens.text > cp + l)
2941 if (strcmp(rp, text) == 0)
2943 /* no change, return */
2944 if (rp != stack_rp) { free(rp); }
2949 /* string changed, recursively reprocess */
2950 const char *tp = vtkParsePreprocess_ProcessString(info, rp);
2953 if (rp != stack_rp) { free(rp); }
2958 rp = (char *)malloc(strlen(stack_rp) + 1);
2959 strcpy(rp, stack_rp);
2967 * Free a string returned by ExpandMacro
2969 void vtkParsePreprocess_FreeMacroExpansion(
2970 PreprocessInfo *info, MacroInfo *macro, const char *text)
2972 /* only free expansion if it is different from definition */
2973 if (info && text != macro->Definition)
2980 * Free a string returned by ProcessString
2982 void vtkParsePreprocess_FreeProcessedString(
2983 PreprocessInfo *info, const char *text)
2992 * Add an include directory.
2994 void vtkParsePreprocess_IncludeDirectory(
2995 PreprocessInfo *info, const char *name)
2999 n = info->NumberOfIncludeDirectories;
3000 for (i = 0; i < n; i++)
3002 if (strcmp(name, info->IncludeDirectories[i]) == 0)
3008 info->IncludeDirectories = (const char **)preproc_array_check(
3009 (char **)info->IncludeDirectories, sizeof(char *),
3010 info->NumberOfIncludeDirectories);
3011 info->IncludeDirectories[info->NumberOfIncludeDirectories++] =
3012 vtkParse_CacheString(info->Strings, name, strlen(name));
3016 * Find an include file in the path. If system_first is set,
3017 * then the current directory is not searched.
3019 const char *vtkParsePreprocess_FindIncludeFile(
3020 PreprocessInfo *info, const char *filename, int system_first,
3021 int *already_loaded)
3024 cp = preproc_find_include_file(info, filename, system_first, 1);
3027 *already_loaded = 1;
3031 *already_loaded = 0;
3032 return preproc_find_include_file(info, filename, system_first, 0);
3036 * Initialize a preprocessor macro struct
3038 void vtkParsePreprocess_InitMacro(MacroInfo *macro)
3041 macro->Definition = NULL;
3042 macro->Comment = NULL;
3043 macro->NumberOfParameters = 0;
3044 macro->Parameters = NULL;
3045 macro->IsFunction = 0;
3046 macro->IsVariadic = 0;
3047 macro->IsExternal = 0;
3048 macro->IsExcluded = 0;
3052 * Free a preprocessor macro struct
3054 void vtkParsePreprocess_FreeMacro(MacroInfo *macro)
3056 free((char **)macro->Parameters);
3062 * Initialize a preprocessor struct
3064 void vtkParsePreprocess_Init(
3065 PreprocessInfo *info, const char *filename)
3067 info->FileName = NULL;
3068 info->MacroHashTable = NULL;
3069 info->NumberOfIncludeDirectories = 0;
3070 info->IncludeDirectories = NULL;
3071 info->NumberOfIncludeFiles = 0;
3072 info->IncludeFiles = NULL;
3073 info->Strings = NULL;
3074 info->IsExternal = 0;
3075 info->ConditionalDepth = 0;
3076 info->ConditionalDone = 0;
3080 char *cp = (char *)malloc(strlen(filename) + 1);
3081 strcpy(cp, filename);
3082 info->FileName = cp;
3087 * Free a preprocessor struct and its contents
3089 void vtkParsePreprocess_Free(PreprocessInfo *info)
3094 free((char *)info->FileName);
3096 if (info->MacroHashTable)
3098 n = PREPROC_HASH_TABLE_SIZE;
3099 for (i = 0; i < n; i++)
3101 mptr = info->MacroHashTable[i];
3106 vtkParsePreprocess_FreeMacro(*mptr++);
3109 free(info->MacroHashTable[i]);
3111 free(info->MacroHashTable);
3114 free((char **)info->IncludeDirectories);
3115 free((char **)info->IncludeFiles);