Commit 4a8b64c5 authored by David Gobbi's avatar David Gobbi
Browse files

ENH: Macro expansion for VTK wrappers.

Allow the wrapper's preprocessor to perform macro expansion.  Prior
to this change, only a few function macros that were hard-coded into
the wrappers could be used in the VTK headers.  Custom macros would
previously cause the wrapper generation to fail.

Some macros are not expanded for the sake of backwards compatibility:
1) VTK_* macro constants are not expanded, since these are recognized
by some of the later stages of the wrapper processing.
2) vtkDataArray, if defined as a macro, is not expanded in order to
allow the vtkDataArrayTemplate superclass trick work as before.
3) All previously hard-coded macros such as the vtkSet/Get macros are
still hard-coded for now, to ensure backwards compatiblity

Change-Id: I96deec4b9c98badfed88831027011904d197840f
parent e95d5cb7
......@@ -235,9 +235,7 @@ class vtkVector2i : public vtkVector2<int>
public:
vtkVector2i(int x = 0, int y = 0) : vtkVector2<int>(x, y) {}
explicit vtkVector2i(const int *init) : vtkVector2<int>(init) {}
#ifndef __WRAP__
vtkVectorDerivedMacro(vtkVector2i, int, 2)
#endif
};
class vtkVector2f : public vtkVector2<float>
......@@ -245,9 +243,7 @@ class vtkVector2f : public vtkVector2<float>
public:
vtkVector2f(float x = 0.0, float y = 0.0) : vtkVector2<float>(x, y) {}
vtkVector2f(const float* i) : vtkVector2<float>(i) {}
#ifndef __WRAP__
vtkVectorDerivedMacro(vtkVector2f, float, 2)
#endif
};
class vtkVector2d : public vtkVector2<double>
......@@ -255,9 +251,7 @@ class vtkVector2d : public vtkVector2<double>
public:
vtkVector2d(double x = 0.0, double y = 0.0) : vtkVector2<double>(x, y) {}
explicit vtkVector2d(const double *init) : vtkVector2<double>(init) {}
#ifndef __WRAP__
vtkVectorDerivedMacro(vtkVector2d, double, 2)
#endif
};
#define vtkVector3Cross(vectorType, type) \
......@@ -271,10 +265,8 @@ class vtkVector3i : public vtkVector3<int>
public:
vtkVector3i(int x = 0, int y = 0, int z = 0) : vtkVector3<int>(x, y, z) {}
explicit vtkVector3i(const int *init) : vtkVector3<int>(init) {}
#ifndef __WRAP__
vtkVectorDerivedMacro(vtkVector3i, int, 3)
vtkVector3Cross(vtkVector3i, int)
#endif
};
class vtkVector3f : public vtkVector3<float>
......@@ -283,10 +275,8 @@ public:
vtkVector3f(float x = 0.0, float y = 0.0, float z = 0.0)
: vtkVector3<float>(x, y, z) {}
explicit vtkVector3f(const float *init) : vtkVector3<float>(init) {}
#ifndef __WRAP__
vtkVectorDerivedMacro(vtkVector3f, float, 3)
vtkVector3Cross(vtkVector3f, float)
#endif
};
class vtkVector3d : public vtkVector3<double>
......@@ -295,10 +285,8 @@ public:
vtkVector3d(double x = 0.0, double y = 0.0, double z = 0.0)
: vtkVector3<double>(x, y, z) {}
explicit vtkVector3d(const double *init) : vtkVector3<double>(init) {}
#ifndef __WRAP__
vtkVectorDerivedMacro(vtkVector3d, double, 3)
vtkVector3Cross(vtkVector3d, double)
#endif
};
#endif // __vtkVector_h
This diff is collapsed.
......@@ -7,23 +7,19 @@ This file must be translated to C and modified to build everywhere.
Run flex like this:
flex --nounput --nodefault -olex.yy.c vtkParse.l
flex --nodefault -olex.yy.c vtkParse.l
Modify lex.yy.c:
- convert tabs to spaces (8 spaces per tab)
- remove extra space from end of lines
- remove blank lines from end of file
- change yy_n_chars declarations from "int yy_n_chars;" to
"size_t yy_n_chars;" in both the yy_buffer_state structure
and the global scope.
- in YY_INPUT change "int n" to "size_t n"
- replace "int yyl" with "yy_size_t yyl"
- compile with gcc and "-Wsign-compare", there should be no warnings
*/
/* We do not care of interactive mode */
#define YY_NEVER_INTERACTIVE 1
#define YY_NO_UNPUT 1
/* Do not include unistd.h in generated source. */
#define YY_NO_UNISTD_H
......@@ -56,7 +52,12 @@ static int skip_ahead_multi(const char *strings[]);
static int skip_ahead_until(const char *text);
static int skip_to_next_directive();
static int skip_conditional_block();
static void print_preprocessor_error(int result, const char *cp, size_t n);
static const char *get_macro_arguments();
static void push_buffer();
static int pop_buffer();
%}
......@@ -137,13 +138,18 @@ static void print_preprocessor_error(int result, const char *cp, size_t n);
[A-Za-z0-9_]*"_EXPORT" ;
"vtkNotUsed"[ ]*"("[^)]*")" {
"vtkNotUsed"([ \t]*"("[^)]*")")? {
size_t i; size_t j = 0;
while (yytext[j]!='(') { j++; }
j++; i = j;
while (yytext[j]!=')') { j++; }
yylval.str = vtkstrndup(&yytext[i], j-i);
return(ID);
yylval.str = "";
if (yytext[yyleng-1] == ')')
{
while (yytext[j]!='(') { j++; }
while (yytext[j]==' ' || yytext[j]=='\t') { j++; }
j++; i = j;
while (yytext[j]!=')' && yytext[j] != ' ' && yytext[j] != '\t') { j++; }
yylval.str = vtkstrndup(&yytext[i], j-i);
return(ID);
}
};
("friend"[\t\n\r ]+)?("template"[\t\n\r ]*"<"[^>]*">"[\t\n\r ]*)?"class"[\t\n\r ]+[a-zA-Z_][a-zA-Z0-9_]*("::"[a-zA-Z_][a-zA-Z0-9_]*)*[\t\n\r ]*";" {
......@@ -400,24 +406,71 @@ static void print_preprocessor_error(int result, const char *cp, size_t n);
yylval.str = vtkstrndup(yytext, yyleng);
return(ISTREAM); }
("vtkStdString"|("vtkstd::"|"std::")?"string") {
("vtkStdString"|("vtkstd::"|"std::")?"string"\[^a-zA-Z_]) {
yylval.str = vtkstrndup(yytext, yyleng);
return(StdString); }
"vtkUnicodeString" { yylval.str = vtkstrndup(yytext, yyleng);
return(UnicodeString); }
"vtk"[0-9a-zA-Z_]* { yylval.str = vtkstrndup(yytext, yyleng);
return(VTK_ID); }
"vtkDataArray" { yylval.str = vtkstrdup("vtkDataArray"); return(VTK_ID); }
"Q"[A-Z][0-9a-zA-Z_]* { yylval.str = vtkstrndup(yytext, yyleng);
return(QT_ID); }
"VTK_"[0-9a-zA-Z_]* { yylval.str = vtkstrndup(yytext, yyleng);
return(ID); }
"Qt::"[0-9a-zA-Z_]* { yylval.str = vtkstrndup(yytext, yyleng);
return(QT_ID); }
[a-zA-Z_][0-9a-zA-Z_]* { yylval.str = vtkstrndup(yytext, yyleng);
return(ID); }
"__attribute__" { get_macro_arguments(); };
[a-zA-Z_][0-9a-zA-Z_]* {
const char *name = vtkstrndup(yytext, yyleng);
MacroInfo *macro = vtkParsePreprocess_GetMacro(&preprocessor, name);
int expanded = 0;
if (macro)
{
if (macro->IsFunction)
{
const char *args = get_macro_arguments();
const char *emacro = NULL;
if (args)
{
emacro = vtkParsePreprocess_ExpandMacro(macro, args);
free((char *)args);
}
if (emacro)
{
push_buffer();
yy_switch_to_buffer(yy_scan_string(emacro));
vtkParsePreprocess_FreeExpandedMacro(emacro);
expanded = 1;
}
}
else if (macro->Definition)
{
push_buffer();
yy_switch_to_buffer(yy_scan_string(macro->Definition));
expanded = 1;
}
}
if (!expanded)
{
yylval.str = name;
if (yyleng > 3 && name[0] == 'v' && name[1] == 't' && name[2] == 'k')
{
return(VTK_ID);
}
else if (name[0] == 'Q')
{
return(QT_ID);
}
else
{
return(ID);
}
}
};
[0-9]+"."[0-9]*([eE][+-]?[0-9]+)?[a-zA-Z_]* {
yylval.str = vtkstrndup(yytext, yyleng);
......@@ -438,6 +491,8 @@ static void print_preprocessor_error(int result, const char *cp, size_t n);
"0" { yylval.str = vtkstrndup(yytext, yyleng);
return(ZERO); };
"\\\n" ;
"\\\r\n" ;
[\t\n\r ] ;
"<<=" return(OP_LSHIFT_EQ);
......@@ -472,9 +527,160 @@ static void print_preprocessor_error(int result, const char *cp, size_t n);
[~{}()<>:;*/%=,&.!+|^\-] { return(yytext[0]); }
. return(OTHER);
<<EOF>> { if (!pop_buffer()) { yyterminate(); } }
. { return(OTHER); }
%%
/*
* Return a parenthetical macro arg list as a new string.
*/
const char *get_macro_arguments()
{
char *cp = NULL;
size_t i = 0;
int depth;
int ws = 0;
int sl = 0;
int c1 = input();
while (c1 == ' ' || c1 == '\t' || c1 == '\r' || c1 == '\n')
{
c1 = input();
}
cp = (char *)malloc(4);
if (c1 != '(')
{
unput(c1);
return NULL;
}
cp[i++] = '(';
depth = 1;
c1 = input();
for (;;)
{
ws = 0;
sl = 0;
/* skip all whitespace */
while (c1 == ' ' || c1 == '\t' || c1 == '\r' || c1 == '\n')
{
ws = 1;
c1 = input();
}
if (c1 == '/')
{
c1 = input();
if (c1 == '*')
{
/* skip a C style comment */
ws = 1;
if (skip_comment() == 0)
{
return NULL;
}
c1 = input();
}
else if (c1 == '/')
{
/* skip a C++ style comment */
ws = 1;
do { c1 = input(); }
while (c1 != '\n' && c1 != '\0');
if (c1 == '\0')
{
return NULL;
}
c1 = input();
}
else
{
sl = 1;
}
}
if (ws)
{
/* add a single space to replace any whitespace */
cp[i++] = ' ';
if (i >= 4 && (i & (i-1)) == 0)
{
cp = (char *)realloc(cp, 2*i);
}
}
if (sl)
{
/* add a single space to replace any whitespace */
cp[i++] = '/';
if (i >= 4 && (i & (i-1)) == 0)
{
cp = (char *)realloc(cp, 2*i);
}
}
if (c1 == '\"' || c1 == '\'')
{
int c2 = c1;
int escaped = 2;
int firstloop = 1;
do
{
if (escaped)
{
--escaped;
}
if (!firstloop)
{
c1 = input();
}
firstloop = 0;
if (c1 == '\0')
{
break;
}
if (escaped == 0 && c1 == '\\')
{
escaped = 2;
}
cp[i++] = (char)c1;
if (i >= 4 && (i & (i-1)) == 0)
{
cp = (char *)realloc(cp, 2*i);
}
}
while (c1 != c2 || escaped);
}
else if (c1 != '\0')
{
cp[i++] = (char)c1;
if (i >= 4 && (i & (i-1)) == 0)
{
cp = (char *)realloc(cp, 2*i);
}
cp[i] = '\0';
if (c1 == '(')
{
depth++;
}
if (c1 == ')')
{
if (--depth == 0)
{
break;
}
}
}
else
{
return NULL;
}
c1 = input();
}
return cp;
}
/*
* Skip a C-style comment, return 0 if unterminated.
*/
......@@ -694,6 +900,45 @@ int skip_ahead_until(const char *text)
return skip_ahead_multi(strings);
}
/*
* buffer stack, used for macro expansion and include files
*/
static size_t buffer_stack_size = 0;
static YY_BUFFER_STATE *buffer_stack = NULL;
/*
* push the current buffer onto the buffer stack.
*/
void push_buffer()
{
size_t n = buffer_stack_size;
if (buffer_stack == NULL)
{
buffer_stack = (YY_BUFFER_STATE *)malloc(4*sizeof(YY_BUFFER_STATE));
}
// grow the stack whenever size reaches a power of two
else if (n >= 4 && (n & (n-1)) == 0)
{
buffer_stack = (YY_BUFFER_STATE *)realloc(
buffer_stack, 2*n*sizeof(YY_BUFFER_STATE));
}
buffer_stack[buffer_stack_size++] = YY_CURRENT_BUFFER;
}
/*
* pop the buffer stack and restore the previous buffer
*/
int pop_buffer()
{
if (buffer_stack_size == 0)
{
return 0;
}
yy_delete_buffer(YY_CURRENT_BUFFER);
yy_switch_to_buffer(buffer_stack[--buffer_stack_size]);
return 1;
}
/*
* print an error with filename and line number.
*/
......@@ -749,6 +994,6 @@ void print_preprocessor_error(int result, const char *cp, size_t n)
while (j > 0 && data.FileName[j-1] != '/') { j--; }
fn = &data.FileName[j];
}
fprintf(yyout, "%s:%i: %s:\n", fn, yylineno, text);
fprintf(yyout, "In %s:%i: %s: ", fn, yylineno, text);
fprintf(yyout, "%*.*s\n", (int)n, (int)n, cp);
}
......@@ -2262,6 +2262,290 @@ int vtkParsePreprocess_RemoveMacro(
return VTK_PARSE_MACRO_UNDEFINED;
}
/**
* Expand a function macro
*/
const char *vtkParsePreprocess_ExpandMacro(
MacroInfo *macro, const char *argstring)
{
const char *cp = argstring;
int n = 0;
int j = 0;
const char **values = NULL;
const char *pp = NULL;
const char *dp = NULL;
char *rp = NULL;
size_t rs = 0;
size_t i = 0;
size_t l = 0;
size_t k = 0;
int stringify = 0;
int depth = 1;
int c;
if (argstring == NULL || *cp != '(')
{
return NULL;
}
/* break the string into individual argument values */
values = (const char **)malloc(4*sizeof(const char **));
cp++;
values[n++] = cp;
while (depth > 0 && *cp != '\0')
{
while (*cp != '\0')
{
if (*cp == '\"' || *cp == '\'')
{
preproc_skip_quotes(&cp);
}
else if (cp[0] == '/' && (cp[1] == '*' || cp[1] == '/'))
{
preproc_skip_comment(&cp);
}
else if (*cp == '(')
{
cp++;
depth++;
}
else if (*cp == ')')
{
cp++;
if (--depth == 0)
{
break;
}
}
else if (*cp == ',')
{
cp++;
if (depth == 1)
{
break;
}
}
else if (*cp != '\0')
{
cp++;
}
}
if (n >= 4 && (n & (n-1)) == 0)
{
values = (const char **)realloc(
(char **)values, 2*n*sizeof(const char **));
}
values[n++] = cp;
}
--n;
/* diagnostic: print out the values */
#if PREPROC_DEBUG
for (j = 0; j < n; j++)
{
size_t m = values[j+1] - values[j] - 1;
fprintf(stderr, "arg %i: %*.*s\n", (int)j, (int)m, (int)m, values[j]);
}
#endif
/* allow whitespace as "no argument" */
if (macro->NumberOfArguments == 0 && n == 1)
{
cp = values[0];
c = *cp;
while (c == ' ' || c == '\n' || c == '\t' || c == '\r')
{
c = *(++cp);
}
if (cp + 1 == values[1])
{
n = 0;
}
}
if (n != macro->NumberOfArguments)
{
free((char **)values);
fprintf(stderr, "wrong number of macro args to %s, %d != %d\n",
macro->Name, n, macro->NumberOfArguments);
return NULL;
}
cp = macro->Definition;
dp = cp;
if (cp == NULL)
{
free((char **)values);
return NULL;
}
rp = (char *)malloc(128);
rp[0] = '\0';
rs = 128;
while (*cp != '\0')
{
pp = cp;
stringify = 0;
/* skip all chars that aren't part of a name */
while ((*cp < 'a' || *cp > 'z') &&
(*cp < 'A' || *cp > 'Z') &&
*cp != '_' && *cp != '\0')
{
if (*cp == '\'' || *cp == '\"')
{
preproc_skip_quotes(&cp);
dp = cp;
}
else if (*cp >= '0' && *cp <= '9')
{
preproc_skip_number(&cp);
dp = cp;
}
else if (*cp == '/' && (cp[1] == '/' || cp[1] == '*'))
{
preproc_skip_comment(&cp);
dp = cp;
}
else if (cp[0] == '#' && cp[1] == '#')
{
dp = cp;
while (dp > pp && (dp[-1] == ' ' || dp[-1] == '\t' ||
dp[-1] == '\r' || dp[-1] == '\n'))
{
--dp;
}
cp += 2;
while (*cp == ' ' || *cp == '\t' || *cp == '\r' || *cp == '\n')
{
cp++;
}
break;
}
else if (*cp == '#')
{
stringify = 1;
dp = cp;
cp++;
while (*cp == ' ' || *cp == '\t' || *cp == '\r' || *cp == '\n')
{
cp++;
}
break;
}
else
{
cp++;
dp = cp;
}
}
l = dp - pp;
if (l > 0)
{
if (i + l + 1 >= rs)
{
rs += rs + i + l + 1;
rp = (char *)realloc(rp, rs);
}
strncpy(&rp[i], pp, l);
i += l;
rp[i] = '\0';
}
/* get the name */
pp = cp;
preproc_skip_name(&cp);
l = cp - pp;
if (l > 0)
{
for (j = 0; j < n; j++)
{
/* check whether the name matches an argument */
if (strncmp(pp, macro->Arguments[j], l) == 0 &&
macro->Arguments[j][l] == '\0')
{
/* substitute the argument value */
l = values[j+1] - values[j] - 1;
pp = values[j];