summaryrefslogtreecommitdiff
path: root/Source/Preprocessor
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2009-08-18 20:56:02 +0000
committerLorry <lorry@roadtrain.codethink.co.uk>2012-09-25 16:59:08 +0000
commit9f8a09ed743cedd9547bf0661d518647966ab114 (patch)
tree9c7803d3b27a8ec22e91792ac7f7932efa128b20 /Source/Preprocessor
downloadswig-tarball-master.tar.gz
Imported from /srv/lorry/lorry-area/swig-tarball/swig-1.3.40.tar.gz.HEADswig-1.3.40master
Diffstat (limited to 'Source/Preprocessor')
-rw-r--r--Source/Preprocessor/cpp.c1854
-rw-r--r--Source/Preprocessor/expr.c436
-rw-r--r--Source/Preprocessor/preprocessor.h38
3 files changed, 2328 insertions, 0 deletions
diff --git a/Source/Preprocessor/cpp.c b/Source/Preprocessor/cpp.c
new file mode 100644
index 0000000..b456b5e
--- /dev/null
+++ b/Source/Preprocessor/cpp.c
@@ -0,0 +1,1854 @@
+/* -----------------------------------------------------------------------------
+ * See the LICENSE file for information on copyright, usage and redistribution
+ * of SWIG, and the README file for authors - http://www.swig.org/release.html.
+ *
+ * cpp.c
+ *
+ * An implementation of a C preprocessor plus some support for additional
+ * SWIG directives.
+ *
+ * - SWIG directives such as %include, %extern, and %import are handled
+ * - A new macro %define ... %enddef can be used for multiline macros
+ * - No preprocessing is performed in %{ ... %} blocks
+ * - Lines beginning with %# are stripped down to #... and passed through.
+ * ----------------------------------------------------------------------------- */
+
+char cvsroot_cpp_c[] = "$Id: cpp.c 11098 2009-01-30 10:32:59Z bhy $";
+
+#include "swig.h"
+#include "preprocessor.h"
+#include <ctype.h>
+
+static Hash *cpp = 0; /* C preprocessor data */
+static int include_all = 0; /* Follow all includes */
+static int ignore_missing = 0;
+static int import_all = 0; /* Follow all includes, but as %import statements */
+static int imported_depth = 0; /* Depth of %imported files */
+static int single_include = 1; /* Only include each file once */
+static Hash *included_files = 0;
+static List *dependencies = 0;
+static Scanner *id_scan = 0;
+static int error_as_warning = 0; /* Understand the cpp #error directive as a special #warning */
+
+/* Test a character to see if it starts an identifier */
+#define isidentifier(c) ((isalpha(c)) || (c == '_') || (c == '$'))
+
+/* Test a character to see if it valid in an identifier (after the first letter) */
+#define isidchar(c) ((isalnum(c)) || (c == '_') || (c == '$'))
+
+DOH *Preprocessor_replace(DOH *);
+
+/* Skip whitespace */
+static void skip_whitespace(String *s, String *out) {
+ int c;
+ while ((c = Getc(s)) != EOF) {
+ if (!isspace(c)) {
+ Ungetc(c, s);
+ break;
+ } else if (out)
+ Putc(c, out);
+ }
+}
+
+/* Skip to a specified character taking line breaks into account */
+static int skip_tochar(String *s, int ch, String *out) {
+ int c;
+ while ((c = Getc(s)) != EOF) {
+ if (out)
+ Putc(c, out);
+ if (c == ch)
+ break;
+ if (c == '\\') {
+ c = Getc(s);
+ if ((c != EOF) && (out))
+ Putc(c, out);
+ }
+ }
+ if (c == EOF)
+ return -1;
+ return 0;
+}
+
+static void copy_location(const DOH *s1, DOH *s2) {
+ Setfile(s2, Getfile((DOH *) s1));
+ Setline(s2, Getline((DOH *) s1));
+}
+
+static String *cpp_include(const_String_or_char_ptr fn, int sysfile) {
+ String *s = sysfile ? Swig_include_sys(fn) : Swig_include(fn);
+ if (s && single_include) {
+ String *file = Getfile(s);
+ if (Getattr(included_files, file)) {
+ Delete(s);
+ return 0;
+ }
+ Setattr(included_files, file, file);
+ }
+ if (!s) {
+ /* XXX(bhy) may not need the seek */
+ /* Seek(fn, 0, SEEK_SET); */
+ if (ignore_missing) {
+ Swig_warning(WARN_PP_MISSING_FILE, Getfile(fn), Getline(fn), "Unable to find '%s'\n", fn);
+ } else {
+ Swig_error(Getfile(fn), Getline(fn), "Unable to find '%s'\n", fn);
+ }
+ } else {
+ String *lf;
+ Seek(s, 0, SEEK_SET);
+ if (!dependencies) {
+ dependencies = NewList();
+ }
+ lf = Copy(Swig_last_file());
+ Append(dependencies, lf);
+ Delete(lf);
+ }
+ return s;
+}
+
+List *Preprocessor_depend(void) {
+ return dependencies;
+}
+
+/* -----------------------------------------------------------------------------
+ * void Preprocessor_cpp_init() - Initialize the preprocessor
+ * ----------------------------------------------------------------------------- */
+static String *kpp_args = 0;
+static String *kpp_define = 0;
+static String *kpp_defined = 0;
+static String *kpp_elif = 0;
+static String *kpp_else = 0;
+static String *kpp_endif = 0;
+static String *kpp_expanded = 0;
+static String *kpp_if = 0;
+static String *kpp_ifdef = 0;
+static String *kpp_ifndef = 0;
+static String *kpp_name = 0;
+static String *kpp_swigmacro = 0;
+static String *kpp_symbols = 0;
+static String *kpp_undef = 0;
+static String *kpp_value = 0;
+static String *kpp_varargs = 0;
+static String *kpp_error = 0;
+static String *kpp_warning = 0;
+static String *kpp_line = 0;
+static String *kpp_include = 0;
+static String *kpp_pragma = 0;
+static String *kpp_level = 0;
+
+static String *kpp_dline = 0;
+static String *kpp_ddefine = 0;
+static String *kpp_dinclude = 0;
+static String *kpp_dimport = 0;
+static String *kpp_dextern = 0;
+
+static String *kpp_LINE = 0;
+static String *kpp_FILE = 0;
+
+void Preprocessor_init(void) {
+ Hash *s;
+
+ kpp_args = NewString("args");
+ kpp_define = NewString("define");
+ kpp_defined = NewString("defined");
+ kpp_else = NewString("else");
+ kpp_elif = NewString("elif");
+ kpp_endif = NewString("endif");
+ kpp_expanded = NewString("*expanded*");
+ kpp_if = NewString("if");
+ kpp_ifdef = NewString("ifdef");
+ kpp_ifndef = NewString("ifndef");
+ kpp_name = NewString("name");
+ kpp_swigmacro = NewString("swigmacro");
+ kpp_symbols = NewString("symbols");
+ kpp_undef = NewString("undef");
+ kpp_value = NewString("value");
+ kpp_error = NewString("error");
+ kpp_warning = NewString("warning");
+ kpp_pragma = NewString("pragma");
+ kpp_level = NewString("level");
+ kpp_line = NewString("line");
+ kpp_include = NewString("include");
+ kpp_varargs = NewString("varargs");
+
+ kpp_dinclude = NewString("%include");
+ kpp_dimport = NewString("%import");
+ kpp_dextern = NewString("%extern");
+ kpp_ddefine = NewString("%define");
+ kpp_dline = NewString("%line");
+
+
+ kpp_LINE = NewString("__LINE__");
+ kpp_FILE = NewString("__FILE__");
+
+ cpp = NewHash();
+ s = NewHash();
+ Setattr(cpp, kpp_symbols, s);
+ Delete(s);
+ Preprocessor_expr_init(); /* Initialize the expression evaluator */
+ included_files = NewHash();
+
+ id_scan = NewScanner();;
+
+}
+
+void Preprocessor_delete(void) {
+ Delete(kpp_args);
+ Delete(kpp_define);
+ Delete(kpp_defined);
+ Delete(kpp_else);
+ Delete(kpp_elif);
+ Delete(kpp_endif);
+ Delete(kpp_expanded);
+ Delete(kpp_if);
+ Delete(kpp_ifdef);
+ Delete(kpp_ifndef);
+ Delete(kpp_name);
+ Delete(kpp_swigmacro);
+ Delete(kpp_symbols);
+ Delete(kpp_undef);
+ Delete(kpp_value);
+ Delete(kpp_error);
+ Delete(kpp_warning);
+ Delete(kpp_pragma);
+ Delete(kpp_level);
+ Delete(kpp_line);
+ Delete(kpp_include);
+ Delete(kpp_varargs);
+
+ Delete(kpp_dinclude);
+ Delete(kpp_dimport);
+ Delete(kpp_dextern);
+ Delete(kpp_ddefine);
+ Delete(kpp_dline);
+
+
+ Delete(kpp_LINE);
+ Delete(kpp_FILE);
+ Delete(cpp);
+ Delete(included_files);
+ Preprocessor_expr_delete();
+ DelScanner(id_scan);
+
+ Delete(dependencies);
+
+ Delete(Swig_add_directory(0));
+}
+
+/* -----------------------------------------------------------------------------
+ * void Preprocessor_include_all() - Instruct preprocessor to include all files
+ * ----------------------------------------------------------------------------- */
+void Preprocessor_include_all(int a) {
+ include_all = a;
+}
+
+void Preprocessor_import_all(int a) {
+ import_all = a;
+}
+
+void Preprocessor_ignore_missing(int a) {
+ ignore_missing = a;
+}
+
+void Preprocessor_error_as_warning(int a) {
+ error_as_warning = a;
+}
+
+
+/* -----------------------------------------------------------------------------
+ * Preprocessor_define()
+ *
+ * Defines a new C preprocessor symbol. swigmacro specifies whether or not the macro has
+ * SWIG macro semantics.
+ * ----------------------------------------------------------------------------- */
+
+
+String *Macro_vararg_name(const_String_or_char_ptr str, const_String_or_char_ptr line) {
+ String *argname;
+ String *varargname;
+ char *s, *dots;
+
+ argname = Copy(str);
+ s = Char(argname);
+ dots = strchr(s, '.');
+ if (!dots) {
+ Delete(argname);
+ return NULL;
+ }
+
+ if (strcmp(dots, "...") != 0) {
+ Swig_error(Getfile(line), Getline(line), "Illegal macro argument name '%s'\n", str);
+ Delete(argname);
+ return NULL;
+ }
+ if (dots == s) {
+ varargname = NewString("__VA_ARGS__");
+ } else {
+ *dots = '\0';
+ varargname = NewString(s);
+ }
+ Delete(argname);
+ return varargname;
+}
+
+Hash *Preprocessor_define(const_String_or_char_ptr _str, int swigmacro) {
+ String *macroname = 0, *argstr = 0, *macrovalue = 0, *file = 0, *s = 0;
+ Hash *macro = 0, *symbols = 0, *m1;
+ List *arglist = 0;
+ int c, line;
+ int varargs = 0;
+ String *str;
+
+ assert(cpp);
+ assert(_str);
+
+ /* First make sure that string is actually a string */
+ if (DohCheck(_str)) {
+ s = Copy(_str);
+ copy_location(_str, s);
+ str = s;
+ } else {
+ str = NewString((char *) _str);
+ }
+ Seek(str, 0, SEEK_SET);
+ line = Getline(str);
+ file = Getfile(str);
+
+ /* Skip over any leading whitespace */
+ skip_whitespace(str, 0);
+
+ /* Now look for a macro name */
+ macroname = NewStringEmpty();
+ while ((c = Getc(str)) != EOF) {
+ if (c == '(') {
+ argstr = NewStringEmpty();
+ copy_location(str, argstr);
+ /* It is a macro. Go extract its argument string */
+ while ((c = Getc(str)) != EOF) {
+ if (c == ')')
+ break;
+ else
+ Putc(c, argstr);
+ }
+ if (c != ')') {
+ Swig_error(Getfile(str), Getline(str), "Missing \')\' in macro parameters\n");
+ goto macro_error;
+ }
+ break;
+ } else if (isidchar(c) || (c == '%')) {
+ Putc(c, macroname);
+ } else if (isspace(c)) {
+ break;
+ } else if (c == '\\') {
+ c = Getc(str);
+ if (c != '\n') {
+ Ungetc(c, str);
+ Ungetc('\\', str);
+ break;
+ }
+ } else {
+ /*Swig_error(Getfile(str),Getline(str),"Illegal character in macro name\n");
+ goto macro_error; */
+ Ungetc(c, str);
+ break;
+ }
+ }
+ if (!swigmacro)
+ skip_whitespace(str, 0);
+ macrovalue = NewStringEmpty();
+ while ((c = Getc(str)) != EOF) {
+ Putc(c, macrovalue);
+ }
+
+ /* If there are any macro arguments, convert into a list */
+ if (argstr) {
+ String *argname, *varargname;
+ arglist = NewList();
+ Seek(argstr, 0, SEEK_SET);
+ argname = NewStringEmpty();
+ while ((c = Getc(argstr)) != EOF) {
+ if (c == ',') {
+ varargname = Macro_vararg_name(argname, str);
+ if (varargname) {
+ Delete(varargname);
+ Swig_error(Getfile(str), Getline(str), "Variable-length macro argument must be last parameter\n");
+ } else {
+ Append(arglist, argname);
+ }
+ Delete(argname);
+ argname = NewStringEmpty();
+ } else if (isidchar(c) || (c == '.')) {
+ Putc(c, argname);
+ } else if (!(isspace(c) || (c == '\\'))) {
+ Delete(argname);
+ Swig_error(Getfile(str), Getline(str), "Illegal character in macro argument name\n");
+ goto macro_error;
+ }
+ }
+ if (Len(argname)) {
+ /* Check for varargs */
+ varargname = Macro_vararg_name(argname, str);
+ if (varargname) {
+ Append(arglist, varargname);
+ Delete(varargname);
+ varargs = 1;
+ } else {
+ Append(arglist, argname);
+ }
+ }
+ Delete(argname);
+ }
+
+ if (!swigmacro) {
+ Replace(macrovalue, "\\\n", " ", DOH_REPLACE_NOQUOTE);
+ }
+
+ /* Look for special # substitutions. We only consider # that appears
+ outside of quotes and comments */
+
+ {
+ int state = 0;
+ char *cc = Char(macrovalue);
+ while (*cc) {
+ switch (state) {
+ case 0:
+ if (*cc == '#')
+ *cc = '\001';
+ else if (*cc == '/')
+ state = 10;
+ else if (*cc == '\'')
+ state = 20;
+ else if (*cc == '\"')
+ state = 30;
+ break;
+ case 10:
+ if (*cc == '*')
+ state = 11;
+ else if (*cc == '/')
+ state = 15;
+ else {
+ state = 0;
+ cc--;
+ }
+ break;
+ case 11:
+ if (*cc == '*')
+ state = 12;
+ break;
+ case 12:
+ if (*cc == '/')
+ state = 0;
+ else if (*cc != '*')
+ state = 11;
+ break;
+ case 15:
+ if (*cc == '\n')
+ state = 0;
+ break;
+ case 20:
+ if (*cc == '\'')
+ state = 0;
+ if (*cc == '\\')
+ state = 21;
+ break;
+ case 21:
+ state = 20;
+ break;
+ case 30:
+ if (*cc == '\"')
+ state = 0;
+ if (*cc == '\\')
+ state = 31;
+ break;
+ case 31:
+ state = 30;
+ break;
+ default:
+ break;
+ }
+ cc++;
+ }
+ }
+
+ /* Get rid of whitespace surrounding # */
+ /* Replace(macrovalue,"#","\001",DOH_REPLACE_NOQUOTE); */
+ while (strstr(Char(macrovalue), "\001 ")) {
+ Replace(macrovalue, "\001 ", "\001", DOH_REPLACE_ANY);
+ }
+ while (strstr(Char(macrovalue), " \001")) {
+ Replace(macrovalue, " \001", "\001", DOH_REPLACE_ANY);
+ }
+ /* Replace '##' with a special token */
+ Replace(macrovalue, "\001\001", "\002", DOH_REPLACE_ANY);
+ /* Replace '#@' with a special token */
+ Replace(macrovalue, "\001@", "\004", DOH_REPLACE_ANY);
+ /* Replace '##@' with a special token */
+ Replace(macrovalue, "\002@", "\005", DOH_REPLACE_ANY);
+
+ /* Go create the macro */
+ macro = NewHash();
+ Setattr(macro, kpp_name, macroname);
+
+ if (arglist) {
+ Setattr(macro, kpp_args, arglist);
+ Delete(arglist);
+ if (varargs) {
+ Setattr(macro, kpp_varargs, "1");
+ }
+ }
+ Setattr(macro, kpp_value, macrovalue);
+ Setline(macro, line);
+ Setfile(macro, file);
+ if (swigmacro) {
+ Setattr(macro, kpp_swigmacro, "1");
+ }
+ symbols = Getattr(cpp, kpp_symbols);
+ if ((m1 = Getattr(symbols, macroname))) {
+ if (!Checkattr(m1, kpp_value, macrovalue)) {
+ Swig_error(Getfile(str), Getline(str), "Macro '%s' redefined,\n", macroname);
+ Swig_error(Getfile(m1), Getline(m1), "previous definition of '%s'.\n", macroname);
+ goto macro_error;
+ }
+ } else {
+ Setattr(symbols, macroname, macro);
+ Delete(macro);
+ }
+
+ Delete(macroname);
+ Delete(macrovalue);
+
+ Delete(str);
+ Delete(argstr);
+ return macro;
+
+macro_error:
+ Delete(str);
+ Delete(argstr);
+ Delete(arglist);
+ Delete(macroname);
+ Delete(macrovalue);
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Preprocessor_undef()
+ *
+ * Undefines a macro.
+ * ----------------------------------------------------------------------------- */
+void Preprocessor_undef(const_String_or_char_ptr str) {
+ Hash *symbols;
+ assert(cpp);
+ symbols = Getattr(cpp, kpp_symbols);
+ Delattr(symbols, str);
+}
+
+/* -----------------------------------------------------------------------------
+ * find_args()
+ *
+ * Isolates macro arguments and returns them in a list. For each argument,
+ * leading and trailing whitespace is stripped (ala K&R, pg. 230).
+ * ----------------------------------------------------------------------------- */
+static List *find_args(String *s) {
+ List *args;
+ String *str;
+ int c, level;
+ long pos;
+
+ /* Create a new list */
+ args = NewList();
+ copy_location(s, args);
+
+ /* First look for a '(' */
+ pos = Tell(s);
+ skip_whitespace(s, 0);
+
+ /* Now see if the next character is a '(' */
+ c = Getc(s);
+ if (c != '(') {
+ /* Not a macro, bail out now! */
+ Seek(s, pos, SEEK_SET);
+ Delete(args);
+ return 0;
+ }
+ c = Getc(s);
+ /* Okay. This appears to be a macro so we will start isolating arguments */
+ while (c != EOF) {
+ if (isspace(c)) {
+ skip_whitespace(s, 0); /* Skip leading whitespace */
+ c = Getc(s);
+ }
+ str = NewStringEmpty();
+ copy_location(s, str);
+ level = 0;
+ while (c != EOF) {
+ if (c == '\"') {
+ Putc(c, str);
+ skip_tochar(s, '\"', str);
+ c = Getc(s);
+ continue;
+ } else if (c == '\'') {
+ Putc(c, str);
+ skip_tochar(s, '\'', str);
+ c = Getc(s);
+ continue;
+ }
+ if ((c == ',') && (level == 0))
+ break;
+ if ((c == ')') && (level == 0))
+ break;
+ Putc(c, str);
+ if (c == '(')
+ level++;
+ if (c == ')')
+ level--;
+ c = Getc(s);
+ }
+ if (level > 0) {
+ goto unterm;
+ }
+ Chop(str);
+ if (Len(args) || Len(str))
+ Append(args, str);
+ Delete(str);
+
+ /* if (Len(str) && (c != ')'))
+ Append(args,str); */
+
+ if (c == ')')
+ return args;
+ c = Getc(s);
+ }
+unterm:
+ Swig_error(Getfile(args), Getline(args), "Unterminated macro call.\n");
+ return args;
+}
+
+/* -----------------------------------------------------------------------------
+ * DOH *get_filename(DOH *str)
+ *
+ * Read a filename from str. A filename can be enclose in quotes, angle brackets,
+ * or bare.
+ * ----------------------------------------------------------------------------- */
+
+static String *get_filename(String *str, int *sysfile) {
+ String *fn;
+ int c;
+
+ skip_whitespace(str, 0);
+ fn = NewStringEmpty();
+ copy_location(str, fn);
+ c = Getc(str);
+ *sysfile = 0;
+ if (c == '\"') {
+ while (((c = Getc(str)) != EOF) && (c != '\"'))
+ Putc(c, fn);
+ } else if (c == '<') {
+ *sysfile = 1;
+ while (((c = Getc(str)) != EOF) && (c != '>'))
+ Putc(c, fn);
+ } else {
+ Putc(c, fn);
+ while (((c = Getc(str)) != EOF) && (!isspace(c)))
+ Putc(c, fn);
+ if (isspace(c))
+ Ungetc(c, str);
+ }
+ Swig_filename_correct(fn);
+ Seek(fn, 0, SEEK_SET);
+ return fn;
+}
+
+static String *get_options(String *str) {
+
+ int c;
+ skip_whitespace(str, 0);
+ c = Getc(str);
+ if (c == '(') {
+ String *opt;
+ int level = 1;
+ opt = NewString("(");
+ while (((c = Getc(str)) != EOF)) {
+ Putc(c, opt);
+ if (c == ')') {
+ level--;
+ if (!level)
+ return opt;
+ }
+ if (c == '(')
+ level++;
+ }
+ Delete(opt);
+ return 0;
+ } else {
+ Ungetc(c, str);
+ return 0;
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * expand_macro()
+ *
+ * Perform macro expansion and return a new string. Returns NULL if some sort
+ * of error occurred.
+ * ----------------------------------------------------------------------------- */
+
+static String *expand_macro(String *name, List *args) {
+ String *ns;
+ DOH *symbols, *macro, *margs, *mvalue, *temp, *tempa, *e;
+ int i, l;
+ int isvarargs = 0;
+
+ symbols = Getattr(cpp, kpp_symbols);
+ if (!symbols)
+ return 0;
+
+ /* See if the name is actually defined */
+ macro = Getattr(symbols, name);
+ if (!macro)
+ return 0;
+ if (Getattr(macro, kpp_expanded)) {
+ ns = NewStringEmpty();
+ Append(ns, name);
+ if (args) {
+ int lenargs = Len(args);
+ if (lenargs)
+ Putc('(', ns);
+ for (i = 0; i < lenargs; i++) {
+ Append(ns, Getitem(args, i));
+ if (i < (lenargs - 1))
+ Putc(',', ns);
+ }
+ if (i)
+ Putc(')', ns);
+ }
+ return ns;
+ }
+
+ /* Get macro arguments and value */
+ mvalue = Getattr(macro, kpp_value);
+ assert(mvalue);
+ margs = Getattr(macro, kpp_args);
+
+ if (args && Getattr(macro, kpp_varargs)) {
+ isvarargs = 1;
+ /* Variable length argument macro. We need to collect all of the extra arguments into a single argument */
+ if (Len(args) >= (Len(margs) - 1)) {
+ int i;
+ int vi, na;
+ String *vararg = NewStringEmpty();
+ vi = Len(margs) - 1;
+ na = Len(args);
+ for (i = vi; i < na; i++) {
+ Append(vararg, Getitem(args, i));
+ if ((i + 1) < na) {
+ Append(vararg, ",");
+ }
+ }
+ /* Remove arguments */
+ for (i = vi; i < na; i++) {
+ Delitem(args, vi);
+ }
+ Append(args, vararg);
+ Delete(vararg);
+ }
+ }
+ /* If there are arguments, see if they match what we were given */
+ if (args && (margs) && (Len(margs) != Len(args))) {
+ if (Len(margs) > (1 + isvarargs))
+ Swig_error(Getfile(args), Getline(args), "Macro '%s' expects %d arguments\n", name, Len(margs) - isvarargs);
+ else if (Len(margs) == (1 + isvarargs))
+ Swig_error(Getfile(args), Getline(args), "Macro '%s' expects 1 argument\n", name);
+ else
+ Swig_error(Getfile(args), Getline(args), "Macro '%s' expects no arguments\n", name);
+ return 0;
+ }
+
+ /* If the macro expects arguments, but none were supplied, we leave it in place */
+ if (!args && (margs) && Len(margs) > 0) {
+ return NewString(name);
+ }
+
+ /* Copy the macro value */
+ ns = Copy(mvalue);
+ copy_location(mvalue, ns);
+
+ /* Tag the macro as being expanded. This is to avoid recursion in
+ macro expansion */
+
+ temp = NewStringEmpty();
+ tempa = NewStringEmpty();
+ if (args && margs) {
+ l = Len(margs);
+ for (i = 0; i < l; i++) {
+ DOH *arg, *aname;
+ String *reparg;
+ arg = Getitem(args, i); /* Get an argument value */
+ reparg = Preprocessor_replace(arg);
+ aname = Getitem(margs, i); /* Get macro argument name */
+ if (strstr(Char(ns), "\001")) {
+ /* Try to replace a quoted version of the argument */
+ Clear(temp);
+ Clear(tempa);
+ Printf(temp, "\001%s", aname);
+ Printf(tempa, "\"%s\"", arg);
+ Replace(ns, temp, tempa, DOH_REPLACE_ID_END);
+ }
+ if (strstr(Char(ns), "\002")) {
+ /* Look for concatenation tokens */
+ Clear(temp);
+ Clear(tempa);
+ Printf(temp, "\002%s", aname);
+ Append(tempa, "\002\003");
+ Replace(ns, temp, tempa, DOH_REPLACE_ID_END);
+ Clear(temp);
+ Clear(tempa);
+ Printf(temp, "%s\002", aname);
+ Append(tempa, "\003\002");
+ Replace(ns, temp, tempa, DOH_REPLACE_ID_BEGIN);
+ }
+
+ /* Non-standard macro expansion. The value `x` is replaced by a quoted
+ version of the argument except that if the argument is already quoted
+ nothing happens */
+
+ if (strchr(Char(ns), '`')) {
+ String *rep;
+ char *c;
+ Clear(temp);
+ Printf(temp, "`%s`", aname);
+ c = Char(arg);
+ if (*c == '\"') {
+ rep = arg;
+ } else {
+ Clear(tempa);
+ Printf(tempa, "\"%s\"", arg);
+ rep = tempa;
+ }
+ Replace(ns, temp, rep, DOH_REPLACE_ANY);
+ }
+
+ /* Non-standard mangle expansions.
+ The #@Name is replaced by mangle_arg(Name). */
+ if (strstr(Char(ns), "\004")) {
+ String *marg = Swig_string_mangle(arg);
+ Clear(temp);
+ Printf(temp, "\004%s", aname);
+ Replace(ns, temp, marg, DOH_REPLACE_ID_END);
+ Delete(marg);
+ }
+ if (strstr(Char(ns), "\005")) {
+ String *marg = Swig_string_mangle(arg);
+ Clear(temp);
+ Clear(tempa);
+ Printf(temp, "\005%s", aname);
+ Printf(tempa, "\"%s\"", marg);
+ Replace(ns, temp, tempa, DOH_REPLACE_ID_END);
+ Delete(marg);
+ }
+
+ if (isvarargs && i == l - 1 && Len(arg) == 0) {
+ /* Zero length varargs macro argument. We search for commas that might appear before and nuke them */
+ char *a, *s, *t, *name;
+ int namelen;
+ s = Char(ns);
+ name = Char(aname);
+ namelen = Len(aname);
+ a = strstr(s, name);
+ while (a) {
+ char ca = a[namelen + 1];
+ if (!isidchar((int) ca)) {
+ /* Matched the entire vararg name, not just a prefix */
+ t = a - 1;
+ if (*t == '\002') {
+ t--;
+ while (t >= s) {
+ if (isspace((int) *t))
+ t--;
+ else if (*t == ',') {
+ *t = ' ';
+ } else
+ break;
+ }
+ }
+ }
+ a = strstr(a + namelen, name);
+ }
+ }
+ /* Replace(ns, aname, arg, DOH_REPLACE_ID); */
+ Replace(ns, aname, reparg, DOH_REPLACE_ID); /* Replace expanded args */
+ Replace(ns, "\003", arg, DOH_REPLACE_ANY); /* Replace unexpanded arg */
+ Delete(reparg);
+ }
+ }
+ Replace(ns, "\002", "", DOH_REPLACE_ANY); /* Get rid of concatenation tokens */
+ Replace(ns, "\001", "#", DOH_REPLACE_ANY); /* Put # back (non-standard C) */
+ Replace(ns, "\004", "#@", DOH_REPLACE_ANY); /* Put # back (non-standard C) */
+
+ /* Expand this macro even further */
+ Setattr(macro, kpp_expanded, "1");
+
+ e = Preprocessor_replace(ns);
+
+ Delattr(macro, kpp_expanded);
+ Delete(ns);
+
+ if (Getattr(macro, kpp_swigmacro)) {
+ String *g;
+ String *f = NewStringEmpty();
+ Seek(e, 0, SEEK_SET);
+ copy_location(macro, e);
+ g = Preprocessor_parse(e);
+
+#if 0
+ /* Drop the macro in place, but with a marker around it */
+ Printf(f, "/*@%s,%d,%s@*/%s/*@@*/", Getfile(macro), Getline(macro), name, g);
+#else
+ /* Use simplified around markers to properly count lines in cscanner.c */
+ if (strchr(Char(g), '\n')) {
+ Printf(f, "/*@SWIG:%s,%d,%s@*/%s/*@SWIG@*/", Getfile(macro), Getline(macro), name, g);
+#if 0
+ Printf(f, "/*@SWIG:%s@*/%s/*@SWIG@*/", name, g);
+#endif
+ } else {
+ Append(f, g);
+ }
+#endif
+
+ Delete(g);
+ Delete(e);
+ e = f;
+ }
+ Delete(temp);
+ Delete(tempa);
+ return e;
+}
+
+/* -----------------------------------------------------------------------------
+ * evaluate_args()
+ *
+ * Evaluate the arguments of a macro
+ * ----------------------------------------------------------------------------- */
+
+List *evaluate_args(List *x) {
+ Iterator i;
+ List *nl = NewList();
+
+ for (i = First(x); i.item; i = Next(i)) {
+ Append(nl, Preprocessor_replace(i.item));
+ }
+ return nl;
+}
+
+/* -----------------------------------------------------------------------------
+ * DOH *Preprocessor_replace(DOH *s)
+ *
+ * Performs a macro substitution on a string s. Returns a new string with
+ * substitutions applied. This function works by walking down s and looking
+ * for identifiers. When found, a check is made to see if they are macros
+ * which are then expanded.
+ * ----------------------------------------------------------------------------- */
+
+/* #define SWIG_PUT_BUFF */
+
+DOH *Preprocessor_replace(DOH *s) {
+ DOH *ns, *symbols, *m;
+ int c, i, state = 0;
+
+ String *id = NewStringEmpty();
+
+ assert(cpp);
+ symbols = Getattr(cpp, kpp_symbols);
+
+ ns = NewStringEmpty();
+ copy_location(s, ns);
+ Seek(s, 0, SEEK_SET);
+
+ /* Try to locate identifiers in s and replace them with macro replacements */
+ while ((c = Getc(s)) != EOF) {
+ switch (state) {
+ case 0:
+ if (isidentifier(c) || (c == '%')) {
+ Clear(id);
+ Putc(c, id);
+ state = 1;
+ } else if (c == '\"') {
+ Putc(c, ns);
+ skip_tochar(s, '\"', ns);
+ } else if (c == '\'') {
+ Putc(c, ns);
+ skip_tochar(s, '\'', ns);
+ } else if (c == '/') {
+ Putc(c, ns);
+ state = 10;
+ } else {
+ Putc(c, ns);
+ }
+ break;
+ case 1: /* An identifier */
+ if (isidchar(c)) {
+ Putc(c, id);
+ state = 1;
+ } else {
+ /* We found the end of a valid identifier */
+ Ungetc(c, s);
+ /* See if this is the special "defined" macro */
+ if (Equal(kpp_defined, id)) {
+ int lenargs = 0;
+ DOH *args = 0;
+ /* See whether or not a paranthesis has been used */
+ skip_whitespace(s, 0);
+ c = Getc(s);
+ if (c == '(') {
+ Ungetc(c, s);
+ args = find_args(s);
+ } else if (isidchar(c)) {
+ DOH *arg = NewStringEmpty();
+ args = NewList();
+ Putc(c, arg);
+ while (((c = Getc(s)) != EOF)) {
+ if (!isidchar(c)) {
+ Ungetc(c, s);
+ break;
+ }
+ Putc(c, arg);
+ }
+ if (Len(arg))
+ Append(args, arg);
+ Delete(arg);
+ } else {
+ Seek(s, -1, SEEK_CUR);
+ }
+ lenargs = Len(args);
+ if ((!args) || (!lenargs)) {
+ /* This is not a defined() macro. */
+ Append(ns, id);
+ state = 0;
+ break;
+ }
+ for (i = 0; i < lenargs; i++) {
+ DOH *o = Getitem(args, i);
+ if (!Getattr(symbols, o)) {
+ break;
+ }
+ }
+ if (i < lenargs)
+ Putc('0', ns);
+ else
+ Putc('1', ns);
+ Delete(args);
+ state = 0;
+ break;
+ }
+ if (Equal(kpp_LINE, id)) {
+ Printf(ns, "%d", Getline(s));
+ state = 0;
+ break;
+ }
+ if (Equal(kpp_FILE, id)) {
+ String *fn = Copy(Getfile(s));
+ Replaceall(fn, "\\", "\\\\");
+ Printf(ns, "\"%s\"", fn);
+ Delete(fn);
+ state = 0;
+ break;
+ }
+ /* See if the macro is defined in the preprocessor symbol table */
+ if ((m = Getattr(symbols, id))) {
+ DOH *args = 0;
+ DOH *e;
+ /* See if the macro expects arguments */
+ if (Getattr(m, kpp_args)) {
+ /* Yep. We need to go find the arguments and do a substitution */
+ args = find_args(s);
+ if (!Len(args)) {
+ Delete(args);
+ args = 0;
+ }
+ } else {
+ args = 0;
+ }
+ e = expand_macro(id, args);
+ if (e) {
+ Append(ns, e);
+ }
+ Delete(e);
+ Delete(args);
+ } else {
+ Append(ns, id);
+ }
+ state = 0;
+ }
+ break;
+ case 10:
+ if (c == '/')
+ state = 11;
+ else if (c == '*')
+ state = 12;
+ else {
+ Ungetc(c, s);
+ state = 0;
+ break;
+ }
+ Putc(c, ns);
+ break;
+ case 11:
+ Putc(c, ns);
+ if (c == '\n')
+ state = 0;
+ break;
+ case 12:
+ Putc(c, ns);
+ if (c == '*')
+ state = 13;
+ break;
+ case 13:
+ Putc(c, ns);
+ if (c == '/')
+ state = 0;
+ else if (c != '*')
+ state = 12;
+ break;
+ default:
+ state = 0;
+ break;
+ }
+ }
+
+ /* Identifier at the end */
+ if (state == 1) {
+ /* See if this is the special "defined" macro */
+ if (Equal(kpp_defined, id)) {
+ Swig_error(Getfile(s), Getline(s), "No arguments given to defined()\n");
+ } else if ((m = Getattr(symbols, id))) {
+ DOH *e;
+ /* Yes. There is a macro here */
+ /* See if the macro expects arguments */
+ /* if (Getattr(m,"args")) {
+ Swig_error(Getfile(id),Getline(id),"Macro arguments expected.\n");
+ } */
+ e = expand_macro(id, 0);
+ Append(ns, e);
+ Delete(e);
+ } else {
+ Append(ns, id);
+ }
+ }
+ Delete(id);
+ return ns;
+}
+
+
+/* -----------------------------------------------------------------------------
+ * int checkpp_id(DOH *s)
+ *
+ * Checks the string s to see if it contains any unresolved identifiers. This
+ * function contains the heuristic that determines whether or not a macro
+ * definition passes through the preprocessor as a constant declaration.
+ * ----------------------------------------------------------------------------- */
+static int checkpp_id(DOH *s) {
+ int c;
+ int hastok = 0;
+ Scanner *scan = id_scan;
+
+ Seek(s, 0, SEEK_SET);
+
+ Scanner_clear(scan);
+ s = Copy(s);
+ Seek(s, SEEK_SET, 0);
+ Scanner_push(scan, s);
+ while ((c = Scanner_token(scan))) {
+ hastok = 1;
+ if ((c == SWIG_TOKEN_ID) || (c == SWIG_TOKEN_LBRACE) || (c == SWIG_TOKEN_RBRACE))
+ return 1;
+ }
+ if (!hastok)
+ return 1;
+ return 0;
+}
+
+/* addline(). Utility function for adding lines to a chunk */
+static void addline(DOH *s1, DOH *s2, int allow) {
+ if (allow) {
+ Append(s1, s2);
+ } else {
+ char *c = Char(s2);
+ while (*c) {
+ if (*c == '\n')
+ Putc('\n', s1);
+ c++;
+ }
+ }
+}
+
+static void add_chunk(DOH *ns, DOH *chunk, int allow) {
+ DOH *echunk;
+ Seek(chunk, 0, SEEK_SET);
+ if (allow) {
+ echunk = Preprocessor_replace(chunk);
+ addline(ns, echunk, allow);
+ Delete(echunk);
+ } else {
+ addline(ns, chunk, 0);
+ }
+ Clear(chunk);
+}
+
+/*
+ push/pop_imported(): helper functions for defining and undefining
+ SWIGIMPORTED (when %importing a file).
+ */
+static void push_imported() {
+ if (imported_depth == 0) {
+ Preprocessor_define("SWIGIMPORTED 1", 0);
+ }
+ ++imported_depth;
+}
+
+static void pop_imported() {
+ --imported_depth;
+ if (imported_depth == 0) {
+ Preprocessor_undef("SWIGIMPORTED");
+ }
+}
+
+
+/* -----------------------------------------------------------------------------
+ * Preprocessor_parse()
+ *
+ * Parses the string s. Returns a new string containing the preprocessed version.
+ *
+ * Parsing rules :
+ * 1. Lines starting with # are C preprocessor directives
+ * 2. Macro expansion inside strings is not allowed
+ * 3. All code inside false conditionals is changed to blank lines
+ * 4. Code in %{, %} is not parsed because it may need to be
+ * included inline (with all preprocessor directives included).
+ * ----------------------------------------------------------------------------- */
+
+String *Preprocessor_parse(String *s) {
+ String *ns; /* New string containing the preprocessed text */
+ String *chunk, *decl;
+ Hash *symbols;
+ String *id = 0, *value = 0, *comment = 0;
+ int i, state, e, c;
+ int start_line = 0;
+ int allow = 1;
+ int level = 0;
+ int dlevel = 0;
+ int mask = 0;
+ int start_level = 0;
+ int cpp_lines = 0;
+ int cond_lines[256];
+
+ /* Blow away all carriage returns */
+ Replace(s, "\015", "", DOH_REPLACE_ANY);
+
+ ns = NewStringEmpty(); /* Return result */
+
+ decl = NewStringEmpty();
+ id = NewStringEmpty();
+ value = NewStringEmpty();
+ comment = NewStringEmpty();
+ chunk = NewStringEmpty();
+ copy_location(s, chunk);
+ copy_location(s, ns);
+ symbols = Getattr(cpp, kpp_symbols);
+
+ state = 0;
+ while ((c = Getc(s)) != EOF) {
+ switch (state) {
+ case 0: /* Initial state - in first column */
+ /* Look for C preprocessor directives. Otherwise, go directly to state 1 */
+ if (c == '#') {
+ add_chunk(ns, chunk, allow);
+ copy_location(s, chunk);
+ cpp_lines = 1;
+ state = 40;
+ } else if (isspace(c)) {
+ Putc(c, chunk);
+ skip_whitespace(s, chunk);
+ } else {
+ state = 1;
+ Ungetc(c, s);
+ }
+ break;
+ case 1: /* Non-preprocessor directive */
+ /* Look for SWIG directives */
+ if (c == '%') {
+ state = 100;
+ break;
+ }
+ Putc(c, chunk);
+ if (c == '\n')
+ state = 0;
+ else if (c == '\"') {
+ start_line = Getline(s);
+ if (skip_tochar(s, '\"', chunk) < 0) {
+ Swig_error(Getfile(s), -1, "Unterminated string constant starting at line %d\n", start_line);
+ }
+ } else if (c == '\'') {
+ start_line = Getline(s);
+ if (skip_tochar(s, '\'', chunk) < 0) {
+ Swig_error(Getfile(s), -1, "Unterminated character constant starting at line %d\n", start_line);
+ }
+ } else if (c == '/')
+ state = 30; /* Comment */
+ break;
+
+ case 30: /* Possibly a comment string of some sort */
+ start_line = Getline(s);
+ Putc(c, chunk);
+ if (c == '/')
+ state = 31;
+ else if (c == '*')
+ state = 32;
+ else
+ state = 1;
+ break;
+ case 31:
+ Putc(c, chunk);
+ if (c == '\n')
+ state = 0;
+ break;
+ case 32:
+ Putc(c, chunk);
+ if (c == '*')
+ state = 33;
+ break;
+ case 33:
+ Putc(c, chunk);
+ if (c == '/')
+ state = 1;
+ else if (c != '*')
+ state = 32;
+ break;
+
+ case 40: /* Start of a C preprocessor directive */
+ if (c == '\n') {
+ Putc('\n', chunk);
+ state = 0;
+ } else if (isspace(c)) {
+ state = 40;
+ } else {
+ /* Got the start of a preprocessor directive */
+ Ungetc(c, s);
+ Clear(id);
+ copy_location(s, id);
+ state = 41;
+ }
+ break;
+
+ case 41: /* Build up the name of the preprocessor directive */
+ if ((isspace(c) || (!isalpha(c)))) {
+ Clear(value);
+ Clear(comment);
+ if (c == '\n') {
+ Ungetc(c, s);
+ state = 50;
+ } else {
+ state = 42;
+ if (!isspace(c)) {
+ Ungetc(c, s);
+ }
+ }
+
+ copy_location(s, value);
+ break;
+ }
+ Putc(c, id);
+ break;
+
+ case 42: /* Strip any leading space before preprocessor value */
+ if (isspace(c)) {
+ if (c == '\n') {
+ Ungetc(c, s);
+ state = 50;
+ }
+ break;
+ }
+ state = 43;
+ /* no break intended here */
+
+ case 43:
+ /* Get preprocessor value */
+ if (c == '\n') {
+ Ungetc(c, s);
+ state = 50;
+ } else if (c == '/') {
+ state = 45;
+ } else if (c == '\"') {
+ Putc(c, value);
+ skip_tochar(s, '\"', value);
+ } else if (c == '\'') {
+ Putc(c, value);
+ skip_tochar(s, '\'', value);
+ } else {
+ Putc(c, value);
+ if (c == '\\')
+ state = 44;
+ }
+ break;
+
+ case 44:
+ if (c == '\n') {
+ Putc(c, value);
+ cpp_lines++;
+ } else {
+ Ungetc(c, s);
+ }
+ state = 43;
+ break;
+
+ /* States 45-48 are used to remove, but retain comments from macro values. The comments
+ will be placed in the output in an alternative form */
+
+ case 45:
+ if (c == '/')
+ state = 46;
+ else if (c == '*')
+ state = 47;
+ else if (c == '\n') {
+ Putc('/', value);
+ Ungetc(c, s);
+ cpp_lines++;
+ state = 50;
+ } else {
+ Putc('/', value);
+ Putc(c, value);
+ state = 43;
+ }
+ break;
+ case 46:
+ if (c == '\n') {
+ Ungetc(c, s);
+ cpp_lines++;
+ state = 50;
+ } else
+ Putc(c, comment);
+ break;
+ case 47:
+ if (c == '*')
+ state = 48;
+ else
+ Putc(c, comment);
+ break;
+ case 48:
+ if (c == '/')
+ state = 43;
+ else if (c == '*')
+ Putc(c, comment);
+ else {
+ Putc('*', comment);
+ Putc(c, comment);
+ state = 47;
+ }
+ break;
+ case 50:
+ /* Check for various preprocessor directives */
+ Chop(value);
+ if (Equal(id, kpp_define)) {
+ if (allow) {
+ DOH *m, *v, *v1;
+ Seek(value, 0, SEEK_SET);
+ m = Preprocessor_define(value, 0);
+ if ((m) && !(Getattr(m, kpp_args))) {
+ v = Copy(Getattr(m, kpp_value));
+ if (Len(v)) {
+ Swig_error_silent(1);
+ v1 = Preprocessor_replace(v);
+ Swig_error_silent(0);
+ /* Printf(stdout,"checking '%s'\n", v1); */
+ if (!checkpp_id(v1)) {
+ if (Len(comment) == 0)
+ Printf(ns, "%%constant %s = %s;\n", Getattr(m, kpp_name), v1);
+ else
+ Printf(ns, "%%constant %s = %s; /*%s*/\n", Getattr(m, kpp_name), v1, comment);
+ cpp_lines--;
+ }
+ Delete(v1);
+ }
+ Delete(v);
+ }
+ }
+ } else if (Equal(id, kpp_undef)) {
+ if (allow)
+ Preprocessor_undef(value);
+ } else if (Equal(id, kpp_ifdef)) {
+ cond_lines[level] = Getline(id);
+ level++;
+ if (allow) {
+ start_level = level;
+ /* See if the identifier is in the hash table */
+ if (!Getattr(symbols, value))
+ allow = 0;
+ mask = 1;
+ }
+ } else if (Equal(id, kpp_ifndef)) {
+ cond_lines[level] = Getline(id);
+ level++;
+ if (allow) {
+ start_level = level;
+ /* See if the identifier is in the hash table */
+ if (Getattr(symbols, value))
+ allow = 0;
+ mask = 1;
+ }
+ } else if (Equal(id, kpp_else)) {
+ if (level <= 0) {
+ Swig_error(Getfile(s), Getline(id), "Misplaced #else.\n");
+ } else {
+ cond_lines[level - 1] = Getline(id);
+ if (allow) {
+ allow = 0;
+ mask = 0;
+ } else if (level == start_level) {
+ allow = 1 * mask;
+ }
+ }
+ } else if (Equal(id, kpp_endif)) {
+ level--;
+ if (level < 0) {
+ Swig_error(Getfile(id), Getline(id), "Extraneous #endif.\n");
+ level = 0;
+ } else {
+ if (level < start_level) {
+ allow = 1;
+ start_level--;
+ }
+ }
+ } else if (Equal(id, kpp_if)) {
+ cond_lines[level] = Getline(id);
+ level++;
+ if (allow) {
+ int val;
+ String *sval = Preprocessor_replace(value);
+ start_level = level;
+ Seek(sval, 0, SEEK_SET);
+ /* Printf(stdout,"Evaluating '%s'\n", sval); */
+ val = Preprocessor_expr(sval, &e);
+ if (e) {
+ char *msg = Preprocessor_expr_error();
+ Seek(value, 0, SEEK_SET);
+ Swig_warning(WARN_PP_EVALUATION, Getfile(value), Getline(value), "Could not evaluate '%s'\n", value);
+ if (msg)
+ Swig_warning(WARN_PP_EVALUATION, Getfile(value), Getline(value), "Error: '%s'\n", msg);
+ allow = 0;
+ } else {
+ if (val == 0)
+ allow = 0;
+ }
+ mask = 1;
+ }
+ } else if (Equal(id, kpp_elif)) {
+ if (level == 0) {
+ Swig_error(Getfile(s), Getline(id), "Misplaced #elif.\n");
+ } else {
+ cond_lines[level - 1] = Getline(id);
+ if (allow) {
+ allow = 0;
+ mask = 0;
+ } else if (level == start_level) {
+ int val;
+ String *sval = Preprocessor_replace(value);
+ Seek(sval, 0, SEEK_SET);
+ val = Preprocessor_expr(sval, &e);
+ if (e) {
+ char *msg = Preprocessor_expr_error();
+ Seek(value, 0, SEEK_SET);
+ Swig_warning(WARN_PP_EVALUATION, Getfile(value), Getline(value), "Could not evaluate '%s'\n", value);
+ if (msg)
+ Swig_warning(WARN_PP_EVALUATION, Getfile(value), Getline(value), "Error: '%s'\n", msg);
+ allow = 0;
+ } else {
+ if (val)
+ allow = 1 * mask;
+ else
+ allow = 0;
+ }
+ }
+ }
+ } else if (Equal(id, kpp_warning)) {
+ if (allow) {
+ Swig_warning(WARN_PP_CPP_WARNING, Getfile(s), Getline(id), "CPP #warning, %s\n", value);
+ }
+ } else if (Equal(id, kpp_error)) {
+ if (allow) {
+ if (error_as_warning) {
+ Swig_warning(WARN_PP_CPP_ERROR, Getfile(s), Getline(id), "CPP #error \"%s\".\n", value);
+ } else {
+ Swig_error(Getfile(s), Getline(id), "CPP #error \"%s\". Use the -cpperraswarn option to continue swig processing.\n", value);
+ }
+ }
+ } else if (Equal(id, kpp_line)) {
+ } else if (Equal(id, kpp_include)) {
+ if (((include_all) || (import_all)) && (allow)) {
+ String *s1, *s2, *fn;
+ char *dirname;
+ int sysfile = 0;
+ if (include_all && import_all) {
+ Swig_warning(WARN_PP_INCLUDEALL_IMPORTALL, Getfile(s), Getline(id), "Both includeall and importall are defined: using includeall\n");
+ import_all = 0;
+ }
+ Seek(value, 0, SEEK_SET);
+ fn = get_filename(value, &sysfile);
+ s1 = cpp_include(fn, sysfile);
+ if (s1) {
+ if (include_all)
+ Printf(ns, "%%includefile \"%s\" [\n", Swig_last_file());
+ else if (import_all) {
+ Printf(ns, "%%importfile \"%s\" [\n", Swig_last_file());
+ push_imported();
+ }
+
+ /* See if the filename has a directory component */
+ dirname = Swig_file_dirname(Swig_last_file());
+ if (sysfile || !strlen(dirname))
+ dirname = 0;
+ if (dirname) {
+ dirname[strlen(dirname) - 1] = 0; /* Kill trailing directory delimiter */
+ Swig_push_directory(dirname);
+ }
+ s2 = Preprocessor_parse(s1);
+ addline(ns, s2, allow);
+ Append(ns, "\n]");
+ if (dirname) {
+ Swig_pop_directory();
+ }
+ if (import_all) {
+ pop_imported();
+ }
+ Delete(s2);
+ }
+ Delete(s1);
+ Delete(fn);
+ }
+ } else if (Equal(id, kpp_pragma)) {
+ if (Strncmp(value, "SWIG ", 5) == 0) {
+ char *c = Char(value) + 5;
+ while (*c && (isspace((int) *c)))
+ c++;
+ if (*c) {
+ if (strncmp(c, "nowarn=", 7) == 0) {
+ String *val = NewString(c + 7);
+ String *nowarn = Preprocessor_replace(val);
+ Swig_warnfilter(nowarn, 1);
+ Delete(nowarn);
+ Delete(val);
+ } else if (strncmp(c, "cpperraswarn=", 13) == 0) {
+ error_as_warning = atoi(c + 13);
+ } else {
+ Swig_error(Getfile(s), Getline(id), "Unknown SWIG pragma: %s\n", c);
+ }
+ }
+ }
+ } else if (Equal(id, kpp_level)) {
+ Swig_error(Getfile(s), Getline(id), "cpp debug: level = %d, startlevel = %d\n", level, start_level);
+ }
+ for (i = 0; i < cpp_lines; i++)
+ Putc('\n', ns);
+ state = 0;
+ break;
+
+ /* Swig directives */
+ case 100:
+ /* %{,%} block */
+ if (c == '{') {
+ start_line = Getline(s);
+ add_chunk(ns, chunk, allow);
+ copy_location(s, chunk);
+ Putc('%', chunk);
+ Putc(c, chunk);
+ state = 105;
+ }
+ /* %#cpp - an embedded C preprocessor directive (we strip off the %) */
+ else if (c == '#') {
+ add_chunk(ns, chunk, allow);
+ Putc(c, chunk);
+ state = 107;
+ } else if (isidentifier(c)) {
+ Clear(decl);
+ Putc('%', decl);
+ Putc(c, decl);
+ state = 110;
+ } else {
+ Putc('%', chunk);
+ Putc(c, chunk);
+ state = 1;
+ }
+ break;
+
+ case 105:
+ Putc(c, chunk);
+ if (c == '%')
+ state = 106;
+ break;
+
+ case 106:
+ Putc(c, chunk);
+ if (c == '}') {
+ state = 1;
+ addline(ns, chunk, allow);
+ Clear(chunk);
+ copy_location(s, chunk);
+ } else {
+ state = 105;
+ }
+ break;
+
+ case 107:
+ Putc(c, chunk);
+ if (c == '\n') {
+ addline(ns, chunk, allow);
+ Clear(chunk);
+ state = 0;
+ } else if (c == '\\') {
+ state = 108;
+ }
+ break;
+
+ case 108:
+ Putc(c, chunk);
+ state = 107;
+ break;
+
+ case 110:
+ if (!isidchar(c)) {
+ Ungetc(c, s);
+ /* Look for common Swig directives */
+ if (Equal(decl, kpp_dinclude) || Equal(decl, kpp_dimport) || Equal(decl, kpp_dextern)) {
+ /* Got some kind of file inclusion directive */
+ if (allow) {
+ DOH *s1, *s2, *fn, *opt;
+ int sysfile = 0;
+
+ if (Equal(decl, kpp_dextern)) {
+ Swig_warning(WARN_DEPRECATED_EXTERN, Getfile(s), Getline(s), "%%extern is deprecated. Use %%import instead.\n");
+ Clear(decl);
+ Append(decl, "%%import");
+ }
+ opt = get_options(s);
+ fn = get_filename(s, &sysfile);
+ s1 = cpp_include(fn, sysfile);
+ if (s1) {
+ char *dirname;
+ add_chunk(ns, chunk, allow);
+ copy_location(s, chunk);
+ Printf(ns, "%sfile%s \"%s\" [\n", decl, opt, Swig_last_file());
+ if (Equal(decl, kpp_dimport)) {
+ push_imported();
+ }
+ dirname = Swig_file_dirname(Swig_last_file());
+ if (sysfile || !strlen(dirname))
+ dirname = 0;
+ if (dirname) {
+ dirname[strlen(dirname) - 1] = 0; /* Kill trailing directory delimiter */
+ Swig_push_directory(dirname);
+ }
+ s2 = Preprocessor_parse(s1);
+ if (dirname) {
+ Swig_pop_directory();
+ }
+ if (Equal(decl, kpp_dimport)) {
+ pop_imported();
+ }
+ addline(ns, s2, allow);
+ Append(ns, "\n]");
+ Delete(s2);
+ Delete(s1);
+ }
+ Delete(fn);
+ }
+ state = 1;
+ } else if (Equal(decl, kpp_dline)) {
+ /* Got a line directive */
+ state = 1;
+ } else if (Equal(decl, kpp_ddefine)) {
+ /* Got a define directive */
+ dlevel++;
+ add_chunk(ns, chunk, allow);
+ copy_location(s, chunk);
+ Clear(value);
+ copy_location(s, value);
+ state = 150;
+ } else {
+ Append(chunk, decl);
+ state = 1;
+ }
+ } else {
+ Putc(c, decl);
+ }
+ break;
+
+ /* Searching for the end of a %define statement */
+ case 150:
+ Putc(c, value);
+ if (c == '%') {
+ const char *ed = "enddef";
+ const char *df = "define";
+ char statement[7];
+ int i = 0;
+ for (i = 0; i < 6;) {
+ c = Getc(s);
+ Putc(c, value);
+ statement[i++] = (char)c;
+ if (strncmp(statement, ed, i) && strncmp(statement, df, i))
+ break;
+ }
+ c = Getc(s);
+ Ungetc(c, s);
+ if ((i == 6) && (isspace(c))) {
+ if (strncmp(statement, df, i) == 0) {
+ ++dlevel;
+ } else {
+ if (strncmp(statement, ed, i) == 0) {
+ --dlevel;
+ if (!dlevel) {
+ /* Got the macro */
+ for (i = 0; i < 7; i++) {
+ Delitem(value, DOH_END);
+ }
+ if (allow) {
+ Seek(value, 0, SEEK_SET);
+ Preprocessor_define(value, 1);
+ }
+ /* Putc('\n',ns); */
+ addline(ns, value, 0);
+ state = 0;
+ }
+ }
+ }
+ }
+ }
+ break;
+ default:
+ Printf(stderr, "cpp: Invalid parser state %d\n", state);
+ abort();
+ break;
+ }
+ }
+ while (level > 0) {
+ Swig_error(Getfile(s), -1, "Missing #endif for conditional starting on line %d\n", cond_lines[level - 1]);
+ level--;
+ }
+ if (state == 150) {
+ Seek(value, 0, SEEK_SET);
+ Swig_error(Getfile(s), -1, "Missing %%enddef for macro starting on line %d\n", Getline(value));
+ }
+ if ((state >= 105) && (state < 107)) {
+ Swig_error(Getfile(s), -1, "Unterminated %%{ ... %%} block starting on line %d\n", start_line);
+ }
+ if ((state >= 30) && (state < 40)) {
+ Swig_error(Getfile(s), -1, "Unterminated comment starting on line %d\n", start_line);
+ }
+ add_chunk(ns, chunk, allow);
+ copy_location(s, chunk);
+
+ /* DelScope(scp); */
+ Delete(decl);
+ Delete(id);
+ Delete(value);
+ Delete(comment);
+ Delete(chunk);
+
+ /* fprintf(stderr,"cpp: %d\n", Len(Getattr(cpp,"symbols"))); */
+ return ns;
+}
diff --git a/Source/Preprocessor/expr.c b/Source/Preprocessor/expr.c
new file mode 100644
index 0000000..e6e9459
--- /dev/null
+++ b/Source/Preprocessor/expr.c
@@ -0,0 +1,436 @@
+/* -----------------------------------------------------------------------------
+ * See the LICENSE file for information on copyright, usage and redistribution
+ * of SWIG, and the README file for authors - http://www.swig.org/release.html.
+ *
+ * expr.c
+ *
+ * Integer arithmetic expression evaluator used to handle expressions
+ * encountered during preprocessing.
+ * ----------------------------------------------------------------------------- */
+
+char cvsroot_expr_c[] = "$Id: expr.c 10310 2008-03-17 00:36:35Z olly $";
+
+#include "swig.h"
+#include "preprocessor.h"
+
+static Scanner *scan = 0;
+
+typedef struct {
+ int op;
+ long value;
+ String *svalue;
+} exprval;
+
+#define EXPR_TOP 1
+#define EXPR_VALUE 2
+#define EXPR_OP 3
+#define EXPR_GROUP 4
+#define EXPR_UMINUS 100
+
+static exprval stack[256]; /* Parsing stack */
+static int sp = 0; /* Stack pointer */
+static int prec[256]; /* Precedence rules */
+static int expr_init = 0; /* Initialization flag */
+static char *errmsg = 0; /* Parsing error */
+
+/* Initialize the precedence table for various operators. Low values have higher precedence */
+static void init_precedence() {
+ prec[SWIG_TOKEN_NOT] = 10;
+ prec[EXPR_UMINUS] = 10;
+ prec[SWIG_TOKEN_STAR] = 20;
+ prec[SWIG_TOKEN_SLASH] = 20;
+ prec[SWIG_TOKEN_PERCENT] = 20;
+ prec[SWIG_TOKEN_PLUS] = 30;
+ prec[SWIG_TOKEN_MINUS] = 30;
+ prec[SWIG_TOKEN_LSHIFT] = 40;
+ prec[SWIG_TOKEN_RSHIFT] = 40;
+ prec[SWIG_TOKEN_AND] = 50;
+ prec[SWIG_TOKEN_XOR] = 60;
+ prec[SWIG_TOKEN_OR] = 70;
+ prec[SWIG_TOKEN_EQUALTO] = 80;
+ prec[SWIG_TOKEN_NOTEQUAL] = 80;
+ prec[SWIG_TOKEN_LESSTHAN] = 80;
+ prec[SWIG_TOKEN_GREATERTHAN] = 80;
+ prec[SWIG_TOKEN_LTEQUAL] = 80;
+ prec[SWIG_TOKEN_GTEQUAL] = 80;
+ prec[SWIG_TOKEN_LNOT] = 90;
+ prec[SWIG_TOKEN_LAND] = 100;
+ prec[SWIG_TOKEN_LOR] = 110;
+ expr_init = 1;
+}
+
+#define UNARY_OP(token) (((token) == SWIG_TOKEN_NOT) || \
+ ((token) == SWIG_TOKEN_LNOT) || \
+ ((token) == EXPR_UMINUS))
+
+/* Reduce a single operator on the stack */
+/* return 0 on failure, 1 on success */
+static int reduce_op() {
+ long op_token = stack[sp - 1].value;
+ assert(sp > 0);
+ assert(stack[sp - 1].op == EXPR_OP);
+ /* do some basic checking first: */
+ if (stack[sp].op != EXPR_VALUE) {
+ errmsg = "Right-hand side is not value";
+ return 0;
+ }
+ if (UNARY_OP(op_token)) {
+ if (stack[sp].svalue) {
+ errmsg = "Syntax error: attempt to apply unary operator to string";
+ return 0;
+ }
+ } else {
+ /* binary operator: */
+ if (sp == 1) {
+ /* top of stack: don't attempt to use sp-2! */
+ errmsg = "Missing left-hand side for binary operator";
+ return 0;
+ }
+ if (stack[sp].op != EXPR_VALUE) {
+ errmsg = "Left-hand side of binary operator is not a value";
+ return 0;
+ }
+ if ((!stack[sp - 2].svalue) != (!stack[sp].svalue)) {
+ errmsg = "Can't mix strings and integers in expression";
+ return 0;
+ }
+ }
+ if (stack[sp].svalue) {
+ /* A binary string expression */
+ switch (stack[sp - 1].value) {
+ case SWIG_TOKEN_EQUALTO:
+ stack[sp - 2].value = (Strcmp(stack[sp - 2].svalue, stack[sp].svalue) == 0);
+ Delete(stack[sp - 2].svalue);
+ Delete(stack[sp].svalue);
+ sp -= 2;
+ break;
+ case SWIG_TOKEN_NOTEQUAL:
+ stack[sp - 2].value = (Strcmp(stack[sp - 2].svalue, stack[sp].svalue) != 0);
+ Delete(stack[sp - 2].svalue);
+ Delete(stack[sp].svalue);
+ sp -= 2;
+ break;
+ default:
+ errmsg = "Syntax error: bad binary operator for strings";
+ return 0;
+ break;
+ }
+ } else {
+ switch (op_token) {
+ case SWIG_TOKEN_STAR:
+ stack[sp - 2].value = stack[sp - 2].value * stack[sp].value;
+ sp -= 2;
+ break;
+ case SWIG_TOKEN_EQUALTO:
+ stack[sp - 2].value = stack[sp - 2].value == stack[sp].value;
+ sp -= 2;
+ break;
+ case SWIG_TOKEN_NOTEQUAL:
+ stack[sp - 2].value = stack[sp - 2].value != stack[sp].value;
+ sp -= 2;
+ break;
+ case SWIG_TOKEN_PLUS:
+ stack[sp - 2].value = stack[sp - 2].value + stack[sp].value;
+ sp -= 2;
+ break;
+ case SWIG_TOKEN_MINUS:
+ stack[sp - 2].value = stack[sp - 2].value - stack[sp].value;
+ sp -= 2;
+ break;
+ case SWIG_TOKEN_AND:
+ stack[sp - 2].value = stack[sp - 2].value & stack[sp].value;
+ sp -= 2;
+ break;
+ case SWIG_TOKEN_LAND:
+ stack[sp - 2].value = stack[sp - 2].value && stack[sp].value;
+ sp -= 2;
+ break;
+ case SWIG_TOKEN_OR:
+ stack[sp - 2].value = stack[sp - 2].value | stack[sp].value;
+ sp -= 2;
+ break;
+ case SWIG_TOKEN_LOR:
+ stack[sp - 2].value = stack[sp - 2].value || stack[sp].value;
+ sp -= 2;
+ break;
+ case SWIG_TOKEN_XOR:
+ stack[sp - 2].value = stack[sp - 2].value ^ stack[sp].value;
+ sp -= 2;
+ break;
+ case SWIG_TOKEN_LESSTHAN:
+ stack[sp - 2].value = stack[sp - 2].value < stack[sp].value;
+ sp -= 2;
+ break;
+ case SWIG_TOKEN_GREATERTHAN:
+ stack[sp - 2].value = stack[sp - 2].value > stack[sp].value;
+ sp -= 2;
+ break;
+ case SWIG_TOKEN_LTEQUAL:
+ stack[sp - 2].value = stack[sp - 2].value <= stack[sp].value;
+ sp -= 2;
+ break;
+ case SWIG_TOKEN_GTEQUAL:
+ stack[sp - 2].value = stack[sp - 2].value >= stack[sp].value;
+ sp -= 2;
+ break;
+ case SWIG_TOKEN_NOT:
+ stack[sp - 1].value = ~stack[sp].value;
+ sp--;
+ break;
+ case SWIG_TOKEN_LNOT:
+ stack[sp - 1].value = !stack[sp].value;
+ sp--;
+ break;
+ case EXPR_UMINUS:
+ stack[sp - 1].value = -stack[sp].value;
+ sp--;
+ break;
+ case SWIG_TOKEN_SLASH:
+ stack[sp - 2].value = stack[sp - 2].value / stack[sp].value;
+ sp -= 2;
+ break;
+ case SWIG_TOKEN_PERCENT:
+ stack[sp - 2].value = stack[sp - 2].value % stack[sp].value;
+ sp -= 2;
+ break;
+ case SWIG_TOKEN_LSHIFT:
+ stack[sp - 2].value = stack[sp - 2].value << stack[sp].value;
+ sp -= 2;
+ break;
+ case SWIG_TOKEN_RSHIFT:
+ stack[sp - 2].value = stack[sp - 2].value >> stack[sp].value;
+ sp -= 2;
+ break;
+ default:
+ errmsg = "Syntax error: bad operator";
+ return 0;
+ break;
+ }
+ }
+ stack[sp].op = EXPR_VALUE;
+ stack[sp].svalue = 0; /* ensure it's not a string! */
+ return 1;
+}
+
+/* -----------------------------------------------------------------------------
+ * Preprocessor_expr_init()
+ *
+ * Initialize the expression evaluator
+ * ----------------------------------------------------------------------------- */
+
+void Preprocessor_expr_init(void) {
+ if (!expr_init)
+ init_precedence();
+ if (!scan)
+ scan = NewScanner();
+}
+
+void Preprocessor_expr_delete(void) {
+ DelScanner(scan);
+}
+
+
+/* -----------------------------------------------------------------------------
+ * Tokenizer
+ * ----------------------------------------------------------------------------- */
+
+static int expr_token(Scanner * s) {
+ int t;
+ while (1) {
+ t = Scanner_token(s);
+ if (!((t == SWIG_TOKEN_BACKSLASH) || (t == SWIG_TOKEN_ENDLINE) || (t == SWIG_TOKEN_COMMENT)))
+ break;
+ }
+ return t;
+}
+
+/* -----------------------------------------------------------------------------
+ * Preprocessor_expr()
+ *
+ * Evaluates an arithmetic expression. Returns the result and sets an error code.
+ * ----------------------------------------------------------------------------- */
+
+int Preprocessor_expr(DOH *s, int *error) {
+ int token = 0;
+ int op = 0;
+
+ sp = 0;
+ assert(s);
+ assert(scan);
+
+ Seek(s, 0, SEEK_SET);
+ /* Printf(stdout,"evaluating : '%s'\n", s); */
+ *error = 0;
+ Scanner_clear(scan);
+ Scanner_push(scan, s);
+
+ /* Put initial state onto the stack */
+ stack[sp].op = EXPR_TOP;
+ stack[sp].value = 0;
+
+ while (1) {
+ /* Look at the top of the stack */
+ switch (stack[sp].op) {
+ case EXPR_TOP:
+ /* An expression. Can be a number or another expression enclosed in parens */
+ token = expr_token(scan);
+ if (!token) {
+ errmsg = "Expected an expression";
+ *error = 1;
+ return 0;
+ }
+ if ((token == SWIG_TOKEN_INT) || (token == SWIG_TOKEN_UINT) || (token == SWIG_TOKEN_LONG) || (token == SWIG_TOKEN_ULONG)) {
+ /* A number. Reduce EXPR_TOP to an EXPR_VALUE */
+ char *c = Char(Scanner_text(scan));
+ stack[sp].value = (long) strtol(c, 0, 0);
+ stack[sp].svalue = 0;
+ /* stack[sp].value = (long) atol(Char(Scanner_text(scan))); */
+ stack[sp].op = EXPR_VALUE;
+ } else if (token == SWIG_TOKEN_PLUS) {
+ } else if ((token == SWIG_TOKEN_MINUS) || (token == SWIG_TOKEN_LNOT) || (token == SWIG_TOKEN_NOT)) {
+ if (token == SWIG_TOKEN_MINUS)
+ token = EXPR_UMINUS;
+ stack[sp].value = token;
+ stack[sp++].op = EXPR_OP;
+ stack[sp].op = EXPR_TOP;
+ stack[sp].svalue = 0;
+ } else if ((token == SWIG_TOKEN_LPAREN)) {
+ stack[sp++].op = EXPR_GROUP;
+ stack[sp].op = EXPR_TOP;
+ stack[sp].value = 0;
+ stack[sp].svalue = 0;
+ } else if (token == SWIG_TOKEN_ENDLINE) {
+ } else if ((token == SWIG_TOKEN_STRING)) {
+ stack[sp].svalue = NewString(Scanner_text(scan));
+ stack[sp].op = EXPR_VALUE;
+ } else if ((token == SWIG_TOKEN_ID)) {
+ stack[sp].value = 0;
+ stack[sp].svalue = 0;
+ stack[sp].op = EXPR_VALUE;
+ } else
+ goto syntax_error;
+ break;
+ case EXPR_VALUE:
+ /* A value is on the stack. We may reduce or evaluate depending on what the next token is */
+ token = expr_token(scan);
+ if (!token) {
+ /* End of input. Might have to reduce if an operator is on stack */
+ while (sp > 0) {
+ if (stack[sp - 1].op == EXPR_OP) {
+ if (!reduce_op())
+ goto reduce_error;
+ } else if (stack[sp - 1].op == EXPR_GROUP) {
+ errmsg = "Missing \')\'";
+ *error = 1;
+ return 0;
+ } else
+ goto syntax_error;
+ }
+ return stack[sp].value;
+ }
+ /* Token must be an operator */
+ switch (token) {
+ case SWIG_TOKEN_STAR:
+ case SWIG_TOKEN_EQUALTO:
+ case SWIG_TOKEN_NOTEQUAL:
+ case SWIG_TOKEN_PLUS:
+ case SWIG_TOKEN_MINUS:
+ case SWIG_TOKEN_AND:
+ case SWIG_TOKEN_LAND:
+ case SWIG_TOKEN_OR:
+ case SWIG_TOKEN_LOR:
+ case SWIG_TOKEN_XOR:
+ case SWIG_TOKEN_LESSTHAN:
+ case SWIG_TOKEN_GREATERTHAN:
+ case SWIG_TOKEN_LTEQUAL:
+ case SWIG_TOKEN_GTEQUAL:
+ case SWIG_TOKEN_SLASH:
+ case SWIG_TOKEN_PERCENT:
+ case SWIG_TOKEN_LSHIFT:
+ case SWIG_TOKEN_RSHIFT:
+ if ((sp == 0) || (stack[sp - 1].op == EXPR_GROUP)) {
+ /* No possibility of reduce. Push operator and expression */
+ sp++;
+ stack[sp].op = EXPR_OP;
+ stack[sp].value = token;
+ sp++;
+ stack[sp].op = EXPR_TOP;
+ stack[sp].value = 0;
+ } else {
+ if (stack[sp - 1].op != EXPR_OP)
+ goto syntax_error_expected_operator;
+ op = stack[sp - 1].value; /* Previous operator */
+
+ /* Now, depending on the precedence relationship between the last operator and the current
+ we will reduce or push */
+
+ if (prec[op] <= prec[token]) {
+ /* Reduce the previous operator */
+ if (!reduce_op())
+ goto reduce_error;
+ }
+ sp++;
+ stack[sp].op = EXPR_OP;
+ stack[sp].value = token;
+ sp++;
+ stack[sp].op = EXPR_TOP;
+ stack[sp].value = 0;
+ }
+ break;
+ case SWIG_TOKEN_RPAREN:
+ if (sp == 0)
+ goto extra_rparen;
+
+ /* Might have to reduce operators first */
+ while ((sp > 0) && (stack[sp - 1].op == EXPR_OP)) {
+ if (!reduce_op())
+ goto reduce_error;
+ }
+ if ((sp == 0) || (stack[sp - 1].op != EXPR_GROUP))
+ goto extra_rparen;
+ stack[sp - 1].op = EXPR_VALUE;
+ stack[sp - 1].value = stack[sp].value;
+ sp--;
+ break;
+ default:
+ goto syntax_error_expected_operator;
+ break;
+ }
+ break;
+
+ default:
+ fprintf(stderr, "Internal error in expression evaluator.\n");
+ abort();
+ }
+ }
+
+syntax_error:
+ errmsg = "Syntax error";
+ *error = 1;
+ return 0;
+
+syntax_error_expected_operator:
+ errmsg = "Syntax error: expected operator";
+ *error = 1;
+ return 0;
+
+reduce_error:
+ /* errmsg has been set by reduce_op */
+ *error = 1;
+ return 0;
+
+extra_rparen:
+ errmsg = "Extra \')\'";
+ *error = 1;
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Preprocessor_expr_error()
+ *
+ * Return error message set by the evaluator (if any)
+ * ----------------------------------------------------------------------------- */
+
+char *Preprocessor_expr_error() {
+ return errmsg;
+}
diff --git a/Source/Preprocessor/preprocessor.h b/Source/Preprocessor/preprocessor.h
new file mode 100644
index 0000000..2b90808
--- /dev/null
+++ b/Source/Preprocessor/preprocessor.h
@@ -0,0 +1,38 @@
+/* -----------------------------------------------------------------------------
+ * See the LICENSE file for information on copyright, usage and redistribution
+ * of SWIG, and the README file for authors - http://www.swig.org/release.html.
+ *
+ * preprocessor.h
+ *
+ * SWIG preprocessor module.
+ * ----------------------------------------------------------------------------- */
+
+/* $Id: preprocessor.h 11080 2009-01-24 13:15:51Z bhy $ */
+
+#ifndef SWIG_PREPROCESSOR_H_
+#define SWIG_PREPROCESSOR_H_
+
+#include "swigwarn.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ extern int Preprocessor_expr(String *s, int *error);
+ extern char *Preprocessor_expr_error(void);
+ extern Hash *Preprocessor_define(const_String_or_char_ptr str, int swigmacro);
+ extern void Preprocessor_undef(const_String_or_char_ptr name);
+ extern void Preprocessor_init(void);
+ extern void Preprocessor_delete(void);
+ extern String *Preprocessor_parse(String *s);
+ extern void Preprocessor_include_all(int);
+ extern void Preprocessor_import_all(int);
+ extern void Preprocessor_ignore_missing(int);
+ extern void Preprocessor_error_as_warning(int);
+ extern List *Preprocessor_depend(void);
+ extern void Preprocessor_expr_init(void);
+ extern void Preprocessor_expr_delete(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif