swig/Source/Preprocessor/cpp.c
William S Fulton 31b5f36b74 Fix line number and file name reporting for some macro preprocessor warnings.
The line number of the macro argument has been corrected and the line number
of the start of the macro instead of one past the end is used. Some examples:
  file.h:11: Error: Illegal macro argument name '..'
  file.h:19: Error: Macro 'DUPLICATE' redefined,
  file.h:15: Error: previous definition of 'DUPLICATE'.
  file.h:25: Error: Variable-length macro argument must be last parameter
  file.h:32: Error: Illegal character in macro argument name
  file.i:37: Error: Macro 'SIT' expects 2 arguments

Code used for testing:
// file.h
%define SIT(ax,b)
abc(
%enddef

%define MISSING_DOT1(a,
b,
..)
xxx
%enddef

%define MISSING_DOT2(..)
xxx
%enddef

%define DUPLICATE(a,b)
abc
%enddef

%define DUPLICATE(b)
xxx
%enddef

%define VARARGS_WRONG(a,
x,
...,
 b)
xxx
%enddef

%define BAD_ARGNAME(
a,
b{c
)
xxx
%enddef

SIT(1)


git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@12195 626c5289-ae23-0410-ae9c-e8d60b6d4f22
2010-08-29 23:32:49 +00:00

1881 lines
46 KiB
C

/* -----------------------------------------------------------------------------
* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at http://www.swig.org/legal.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$";
#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 */
static int macro_level = 0;
static int macro_start_line = 0;
static const String * macro_start_file = 0;
/* 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 == '$'))
static 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(argstr), Getline(argstr), "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 {
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, argstr);
if (varargname) {
Delete(varargname);
Swig_error(Getfile(argstr), Getline(argstr), "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(argstr), Getline(argstr), "Illegal character in macro argument name\n");
goto macro_error;
}
}
if (Len(argname)) {
/* Check for varargs */
varargname = Macro_vararg_name(argname, argstr);
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");
}
}
Setline(macrovalue, line);
Setfile(macrovalue, file);
Setline(macroname, line);
Setfile(macroname, file);
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(macroname), Getline(macroname), "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 enclosed 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_unescape(fn);
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 (macro_level == 0) {
/* Store the start of the macro should the macro contain __LINE__ and __FILE__ for expansion */
macro_start_line = Getline(args);
macro_start_file = Getfile(args);
}
macro_level++;
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);
}
macro_level--;
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);
macro_level--;
return 0;
}
/* If the macro expects arguments, but none were supplied, we leave it in place */
if (!args && (margs) && Len(margs) > 0) {
macro_level--;
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;
}
macro_level--;
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 */
static 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 parenthesis 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;
} else if (Equal(kpp_LINE, id)) {
Printf(ns, "%d", macro_level > 0 ? macro_start_line : Getline(s));
state = 0;
break;
} else if (Equal(kpp_FILE, id)) {
String *fn = Copy(macro_level > 0 ? macro_start_file : Getfile(s));
Replaceall(fn, "\\", "\\\\");
Printf(ns, "\"%s\"", fn);
Delete(fn);
state = 0;
break;
} else if ((m = Getattr(symbols, id))) {
/* See if the macro is defined in the preprocessor symbol table */
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 (Equal(kpp_LINE, id)) {
Printf(ns, "%d", macro_level > 0 ? macro_start_line : Getline(s));
} else if (Equal(kpp_FILE, id)) {
String *fn = Copy(macro_level > 0 ? macro_start_file : Getfile(s));
Replaceall(fn, "\\", "\\\\");
Printf(ns, "\"%s\"", fn);
Delete(fn);
} 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 == '#') {
copy_location(s, chunk);
add_chunk(ns, chunk, allow);
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));
copy_location(m, v);
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_filename_escape(Swig_last_file()));
else if (import_all) {
Printf(ns, "%%importfile \"%s\" [\n", Swig_filename_escape(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);
copy_location(s, chunk);
add_chunk(ns, chunk, allow);
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;
copy_location(s, chunk);
add_chunk(ns, chunk, allow);
Printf(ns, "%sfile%s \"%s\" [\n", decl, opt, Swig_filename_escape(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++;
copy_location(s, chunk);
add_chunk(ns, chunk, allow);
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);
}
copy_location(s, chunk);
add_chunk(ns, chunk, allow);
/* DelScope(scp); */
Delete(decl);
Delete(id);
Delete(value);
Delete(comment);
Delete(chunk);
/* fprintf(stderr,"cpp: %d\n", Len(Getattr(cpp,"symbols"))); */
return ns;
}