The swig.swg file contains global configuration information. In addition, this file defines many of SWIG's standard directives as macros. For instance, part of of swig.swg looks like this:%include "swig.swg" // Global SWIG configuration %include "langconfig.swg" // Language specific configuration %include "yourinterface.i" // Your interface file
The fact that most of the standard SWIG directives are macros is intended to simplify the implementation of the parser. For instance, rather than having to support dozens of special grammar rules, it is easier to have a few basic primitives such as %feature or %insert.... /* Code insertion directives such as %wrapper %{ ... %} */ #define %init %insert("init") #define %wrapper %insert("wrapper") #define %header %insert("header") #define %runtime %insert("runtime") /* Access control directives */ #define %immutable %feature("immutable","1") #define %mutable %feature("immutable") /* Directives for callback functions */ #define %callback(x) %feature("callback") `x`; #define %nocallback %feature("callback"); /* %ignore directive */ #define %ignore %rename($ignore) #define %ignorewarn(x) %rename("$ignore:" x) ...
The langconfig.swg file is supplied by the target language. This file contains language-specific configuration information. More often than not, this file provides run-time wrapper support code (e.g., the type-checker) as well as a collection of typemaps that define the default wrapping behavior. Note: the name of this file depends on the target language and is usually something like python.swg or perl5.swg.
As a debugging aide, the text that SWIG feeds to its C++ parser can be obtained by running swig -E interface.i. This output probably isn't too useful in general, but it will show how macros have been expanded as well as everything else that goes into the low-level construction of the wrapper code.
storage is a keyword such as extern, static, typedef, or virtual. type is a primitive datatype such as int or void. type may be optionally qualified with a qualifier such as const or volatile. declarator is a name with additional type-construction modifiers attached to it (pointers, arrays, references, functions, etc.). Examples of declarators include *x, **x, x[20], and (*x)(int,double). The initializer may be a value assigned using = or body of code enclosed in braces { ... }.storage type declarator initializer;
This declaration format covers most common C++ declarations. However, the C++ standard is somewhat more flexible in the placement of the pieces. For example, it is technically legal, although unusual to write something like int typedef const a in your program. SWIG simply doesn't bother to deal with this (although it could probably be modified if there is sufficient demand).
The other significant difference between C++ and SWIG is in the treatment of typenames. In C++, if you have a declaration like this,
it won't parse correctly unless Foo and Bar have been previously defined as types either using a class definition or a typedef. The reasons for this are subtle, but this treatment of typenames is normally integrated at the level of the C tokenizer---when a typename appears, a different token is returned to the parser instead of an identifier.int blah(Foo *x, Bar *y);
SWIG does not operate in this manner--any legal identifier can be used as a type name. The reason for this is primarily motivated by the use of SWIG with partially defined data. Specifically, SWIG is supposed to be easy to use on interfaces with missing type information. On a more practical level however, the introduction of typenames would greatly complicate other parts of SWIG such as the parsing of SWIG directives (many of which also rely upon identifier names).
Because of the different treatment of typenames, the most serious limitation of the SWIG parser is that it can't process type declarations in which an extra (and unnecessary) grouping operator is used. For example:
The placing of extra parentheses in type declarations like this is already recognized by the C++ community as a potential source of strange programming errors. For example, Scott Meyers "Effective STL" discusses this problem in a section on avoiding C++'s "most vexing parse."int (x); /* A variable x */ int (y)(int); /* A function y */
The parser is also unable to handle declarations with no return type or bare argument names. For example, in an old C program, you might see things like this:
In this case, the return type as well as the types of the arguments are taken by the C compiler to be an int. However, SWIG interprets the above code as an abstract declarator for a function returning a foo and taking types a and b as arguments).foo(a,b) { ... }
Even for the most simple interface, the parse tree structure is larger than you might expect. For example, in the above output, a substantial number of nodes are actually generated by the python.swg configuration file which defines typemaps and other directives. The contents of the user-supplied input file don't appear until the end of the output.$ swig -c++ -python -dump_tags example.i . top (example.i:1) . top . include (example.i:1) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/swig.swg:71) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/swig.swg:71) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/swig.swg:83) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/swig.swg:83) . top . include (example.i:4) . top . include . insert (/r0/beazley/Projects/lib/swig1.3/python/python.swg:7) . top . include . insert (/r0/beazley/Projects/lib/swig1.3/python/python.swg:8) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:19) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:19) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:19) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:20) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:20) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:20) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:21) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:21) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:21) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:22) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:22) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:22) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:23) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:23) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:24) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:24) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:25) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:25) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:26) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:26) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:29) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:29) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:32) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:32) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:42) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:42) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:42) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:42) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:45) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:45) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:46) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:46) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:49) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:49) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:59) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:59) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:59) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:59) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:59) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:59) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:59) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:59) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:59) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:59) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:59) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:61) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:61) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:61) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:62) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:62) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:63) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:63) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:66) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:66) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:66) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:66) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:69) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:69) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:72) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:72) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:75) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:75) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:75) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:84) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:84) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:105) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:105) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:105) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:105) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:105) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:105) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:105) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:105) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:105) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:105) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:105) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:114) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:114) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:114) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:124) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:124) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:137) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:137) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:154) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:154) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:164) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:164) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:173) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:173) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:173) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:182) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:182) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:191) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:191) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:200) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:200) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:205) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:205) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:205) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:205) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:205) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:205) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:205) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:205) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:205) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:205) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:205) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:208) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:208) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:208) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:211) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:211) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:211) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:214) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:214) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:214) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:214) . top . include . typemap (/r0/beazley/Projects/lib/swig1.3/python/python.swg:217) . top . include . typemap . typemapitem (/r0/beazley/Projects/lib/swig1.3/python/python.swg:217) . top . include (example.i:6) . top . include . module (example.i:2) . top . include . insert (example.i:6) . top . include . include (example.i:9) . top . include . include . class (example.h:3) . top . include . include . class . access (example.h:4) . top . include . include . class . constructor (example.h:7) . top . include . include . class . destructor (example.h:10) . top . include . include . class . cdecl (example.h:11) . top . include . include . class . cdecl (example.h:11) . top . include . include . class . cdecl (example.h:12) . top . include . include . class . cdecl (example.h:13) . top . include . include . class . cdecl (example.h:14) . top . include . include . class . cdecl (example.h:15) . top . include . include . class (example.h:18) . top . include . include . class . access (example.h:19) . top . include . include . class . cdecl (example.h:20) . top . include . include . class . access (example.h:21) . top . include . include . class . constructor (example.h:22) . top . include . include . class . cdecl (example.h:23) . top . include . include . class . cdecl (example.h:24) . top . include . include . class (example.h:27) . top . include . include . class . access (example.h:28) . top . include . include . class . cdecl (example.h:29) . top . include . include . class . access (example.h:30) . top . include . include . class . constructor (example.h:31) . top . include . include . class . cdecl (example.h:32) . top . include . include . class . cdecl (example.h:33)
The contents of each parse tree node consist of a collection of attribute/value pairs. Internally, the nodes are simply represented by hash tables. A display of the parse-tree structure can be obtained using swig -dump_tree. For example:
$ swig -c++ -python -dump_tree example.i ... +++ include ---------------------------------------- | name - "example.i" +++ module ---------------------------------------- | name - "example" | +++ insert ---------------------------------------- | code - "\n#include \"example.h\"\n" | +++ include ---------------------------------------- | name - "example.h" +++ class ---------------------------------------- | abstract - "1" | sym:name - "Shape" | name - "Shape" | kind - "class" | symtab - 0x40194140 | sym:symtab - 0x40191078 +++ access ---------------------------------------- | kind - "public" | +++ constructor ---------------------------------------- | sym:name - "Shape" | name - "Shape" | decl - "f()." | code - "{\n nshapes++;\n }" | sym:symtab - 0x40194140 | +++ destructor ---------------------------------------- | sym:name - "~Shape" | name - "~Shape" | storage - "virtual" | code - "{\n nshapes--;\n }" | sym:symtab - 0x40194140 | +++ cdecl ---------------------------------------- | sym:name - "x" | name - "x" | decl - "" | type - "double" | sym:symtab - 0x40194140 | +++ cdecl ---------------------------------------- | sym:name - "y" | name - "y" | decl - "" | type - "double" | sym:symtab - 0x40194140 | +++ cdecl ---------------------------------------- | sym:name - "move" | name - "move" | decl - "f(double,double)." | parms - double ,double | type - "void" | sym:symtab - 0x40194140 | +++ cdecl ---------------------------------------- | sym:name - "area" | name - "area" | decl - "f(void)." | parms - void | storage - "virtual" | value - "0" | type - "double" | sym:symtab - 0x40194140 | +++ cdecl ---------------------------------------- | sym:name - "perimeter" | name - "perimeter" | decl - "f(void)." | parms - void | storage - "virtual" | value - "0" | type - "double" | sym:symtab - 0x40194140 | +++ cdecl ---------------------------------------- | sym:name - "nshapes" | name - "nshapes" | decl - "" | storage - "static" | type - "int" | sym:symtab - 0x40194140 | +++ class ---------------------------------------- | sym:name - "Circle" | name - "Circle" | kind - "class" | bases - 0x40194510 | symtab - 0x40194538 | sym:symtab - 0x40191078 +++ access ---------------------------------------- | kind - "private" | +++ cdecl ---------------------------------------- | name - "radius" | decl - "" | type - "double" | +++ access ---------------------------------------- | kind - "public" | +++ constructor ---------------------------------------- | sym:name - "Circle" | name - "Circle" | parms - double | decl - "f(double)." | code - "{ }" | sym:symtab - 0x40194538 | +++ cdecl ---------------------------------------- | sym:name - "area" | name - "area" | decl - "f(void)." | parms - void | storage - "virtual" | type - "double" | sym:symtab - 0x40194538 | +++ cdecl ---------------------------------------- | sym:name - "perimeter" | name - "perimeter" | decl - "f(void)." | parms - void | storage - "virtual" | type - "double" | sym:symtab - 0x40194538 | +++ class ---------------------------------------- | sym:name - "Square" | name - "Square" | kind - "class" | bases - 0x40194760 | symtab - 0x40194788 | sym:symtab - 0x40191078 +++ access ---------------------------------------- | kind - "private" | +++ cdecl ---------------------------------------- | name - "width" | decl - "" | type - "double" | +++ access ---------------------------------------- | kind - "public" | +++ constructor ---------------------------------------- | sym:name - "Square" | name - "Square" | parms - double | decl - "f(double)." | code - "{ }" | sym:symtab - 0x40194788 | +++ cdecl ---------------------------------------- | sym:name - "area" | name - "area" | decl - "f(void)." | parms - void | storage - "virtual" | type - "double" | sym:symtab - 0x40194788 | +++ cdecl ---------------------------------------- | sym:name - "perimeter" | name - "perimeter" | decl - "f(void)." | parms - void | storage - "virtual" | type - "double" | sym:symtab - 0x40194788
Target language modules may add additional attributes to nodes to assist the generation of wrapper code. The convention for doing this is to place these attributes in a namespace that matches the name of the target language. For example, python:foo or perl:foo.
Now, running SWIG:%rename(foo_i) foo(int); %rename(foo_d) foo(double); void foo(int); void foo(double); void foo(Bar *b);
All symbol-related conflicts and complaints about overloading are based on sym:name values. For instance, the following example uses %rename in reverse to generate a name clash.$ swig -dump_tree example.i ... +++ cdecl ---------------------------------------- | sym:name - "foo_i" | name - "foo" | decl - "f(int)." | parms - int | type - "void" | sym:symtab - 0x40165078 | +++ cdecl ---------------------------------------- | sym:name - "foo_d" | name - "foo" | decl - "f(double)." | parms - double | type - "void" | sym:symtab - 0x40165078 | +++ cdecl ---------------------------------------- | sym:name - "foo" | name - "foo" | decl - "f(p.Bar)." | parms - Bar * | type - "void" | sym:symtab - 0x40165078
When you run SWIG on this you now get:%rename(foo) foo_i(int); %rename(foo) foo_d(double; void foo_i(int); void foo_d(double); void foo(Bar *b);
$ ./swig example.i example.i:6. Overloaded declaration ignored. foo_d(double ) example.i:5. Previous declaration is foo_i(int ) example.i:7. Overloaded declaration ignored. foo(Bar *) example.i:5. Previous declaration is foo_i(int )
The behavior of %feature is very easy to describe--it simply attaches a new attribute to any parse tree node that matches the given prototype. When a feature is added, it shows up in the feature: namespace. You can see this when running with the -dump_tree option. For example:%feature("except") getitem(int) { try { $action } catch (badindex) { ... } } ... class Foo { public: Object *getitem(int index) throws(badindex); ... };
Feature names are completely arbitrary and a target language module can be programmed to respond to any name that it wishes. The data stored in a feature attribute is usually just a raw unparsed string. For example, the exception code above is simply stored without any modifications.+++ cdecl ---------------------------------------- | sym:name - "getitem" | name - "getitem" | decl - "f(int).p." | parms - int | type - "Object" | feature:except - "{\n try {\n $action\n } catc..." | sym:symtab - 0x40168ac8 |
In reality, the generation of code is somewhat more subtle than simply invoking handler functions. This is because parse-tree nodes might be transformed. For example, suppose you are wrapping a class like this:
When the parser constructs a node for the member bar, it creates a raw "cdecl" node with the following attributes:class Foo { public: virtual int *bar(int x); };
To produce wrapper code, this "cdecl" node undergoes a number of transformations. First, the node is recognized as a function declaration. This adjusts some of the type information--specifically, the declarator is joined with the base datatype to produce this:nodeType : cdecl name : bar type : int decl : f(int).p parms : int x storage : virtual sym:name : bar
Next, the context of the node indicates that the node is really a member function. This produces a transformation to a low-level accessor function like this:nodeType : cdecl name : bar type : p.int <-- Notice change in return type decl : f(int).p parms : int x storage : virtual sym:name : bar
In this transformation, notice how an additional parameter was added to the parameter list and how the symbol name of the node has suddenly changed into an accessor using the naming scheme described in the "SWIG Basics" chapter. A small fragment of "action" code has also been generated--notice how the wrap:action attribute defines the access to the underlying method. The data in this transformed node is then used to generate a wrapper.nodeType : cdecl name : bar type : int.p decl : f(int).p parms : Foo *self, int x <-- Added parameter storage : virtual wrap:action : result = (arg1)->bar(arg2) <-- Action code added sym:name : Foo_bar <-- Symbol name changed
Language modules work by registering handler functions for dealing with various types of nodes at different stages of transformation. This is done by inheriting from a special Language class and defining a collection of virtual methods. For example, the Python module defines a class as follows:
The role of these functions is described shortly.class PYTHON : public Language { protected: public : virtual void main(int, char *argv[]); virtual int top(Node *); virtual int functionWrapper(Node *); virtual int constantWrapper(Node *); virtual int variableWrapper(Node *); virtual int nativeWrapper(Node *); virtual int membervariableHandler(Node *); virtual int memberconstantHandler(Node *); virtual int memberfunctionHandler(Node *); virtual int constructorHandler(Node *); virtual int destructorHandler(Node *); virtual int classHandler(Node *); virtual int classforwardDeclaration(Node *); virtual int insertDirective(Node *); virtual int importDirective(Node *); };
When describing the low-level API, the following type name conventions are used:
typedef String SwigType; typedef Hash Parm; typedef Hash ParmList; typedef Hash Node; typedef Hash Symtab; typedef Hash Typetab;
String *NewString(const String_or_char *val)
Creates a new string with initial value val. val may be a char * or another String object. If you want to create an empty string, use "" for val.
String *NewStringf(const char *fmt, ...)
Creates a new string whose initial value is set according to a C printf style format string in fmt. Additional arguments follow depending on fmt.
String *Copy(String *s)
Make a copy of the string s.
void Delete(String *s)
Deletes s.
int Len(String_or_char *s)
Returns the length of the string.
char *Char(String_or_char *s)
Returns a pointer to the first character in the string.
void Append(String *s, String_or_char *t)
Appends t to the end of s.
void Insert(String *s, int pos, String_or_char *t)
Inserts t into s at position pos. The contents of s are shifted accordingly. The special value DOH_END can be used for pos to indicate insertion at the end of the string (appending).
int Strcmp(const String_or_char *s, const String_or_char *t)
Compare strings s and t. Same as the C strcmp() function.
int Strncmp(const String_or_char *s, const String_or_char *t, int len)
Compare the first len characters of strings s and t. Same as the C strncmp() function.
char *Strstr(const String_or_char *s, const String_or_char *pat)
Returns a pointer to the first occurrence of pat in s. Same as the C strstr() function.
char *Strchr(const String_or_char *s, char ch)
Returns a pointer to the first occurrence of character ch in s. Same as the C strchr() function.
void Chop(String *s)
Chops trailing whitespace off the end of s.
int Replace(String *s, const String_or_char *pat, const String_or_char *rep, int flags)
Replaces the pattern pat with rep in string s. flags is a combination of the following flags:Returns the number of replacements made (if any).DOH_REPLACE_ANY - Replace all occurrences DOH_REPLACE_ID - Valid C identifiers only DOH_REPLACE_NOQUOTE - Don't replace in quoted strings DOH_REPLACE_FIRST - Replace first occurrence only.
Hash *NewHash()
Creates a new empty hash table.
Hash *Copy(Hash *h)
Make a shallow copy of the hash h.
void Delete(Hash *h)
Deletes h.
int Len(Hash *h)
Returns the number of items in h.
Object *Getattr(Hash *h, String_or_char *key)
Gets an object from h. key may be a string or a simple char * string. Returns NULL if not found.
int *Setattr(Hash *h, String_or_char *key, Object_or_char *val)
Stores val in h. key may be a string or a simple char *. If val is not a standard object (String, Hash, or List) it is assumed to be a char * in which case it is used to construct a String that is stored in the hash. If val is NULL, the object is deleted. Increases the reference count of val. Returns 1 if this operation replaced an existing hash entry, 0 otherwise.
int *Delattr(Hash *h, String_or_char *key)
Deletes the hash item referenced by key. Decreases the reference count on the corresponding object (if any). Returns 1 if an object was removed, 0 otherwise.
String *Firstkey(Hash *h)
Returns the first hash table key or NULL if the hash is empty. Used for iteration.
String *Nextkey(Hash *h)
Returns the next hash table key or NULL if the end of the hash has been reached. Used for iteration.
List *Keys(Hash *h)
Returns the list of hash table keys.
List *NewList()
Creates a new empty list.
List *Copy(List *x)
Make a shallow copy of the List x.
void Delete(List *x)
Deletes x.
int Len(List *x)
Returns the number of items in x.
Object *Getitem(List *x, int n)
Returns an object from x with index n. If n is beyond the end of the list, the last item is returned. If n is negative, the first item is returned.
int *Setitem(List *x, int n, Object_or_char *val)
Stores val in x. If val is not a standard object (String, Hash, or List) it is assumed to be a char * in which case it is used to construct a String that is stored in the list. n must be in range. Otherwise, an assertion will be raised.
int *Delitem(List *x, int n)
Deletes item n from the list, shifting items down if necessary. To delete the last item in the list, use the special value DOH_END for n.
Object *Firstitem(List *x)
Returns the first item in x or NULL if the list is empty.
Object *Nextitem(List *x)
Returns the next item in x or NULL if the end of the list has been reached. Used for iteration.
void Append(List *x, Object_or_char *t)
Appends t to the end of x. If t is not a standard object, it is assumed to be a char * and is used to create a String object.
void Insert(String *s, int pos, Object_or_char *t)
Inserts t into s at position pos. The contents of s are shifted accordingly. The special value DOH_END can be used for pos to indicate insertion at the end of the list (appending). If t is not a standard object, it is assumed to be a char * and is used to create a String object.
Object *Copy(Object *x)
Make a copy of the object x.
void Delete(Object *x)
Deletes x.
void Setfile(Object *x, String_or_char *f)
Sets the filename associated with x. Used to track objects and report errors.
String *Getfile(Object *x)
Gets the filename associated with x.
void Setline(Object *x, int n)
Sets the line number associated with x. Used to track objects and report errors.
int Getline(Object *x)
Gets the line number associated with x.
int Printf(String_or_FILE *f, const char *fmt, ...)
Formatted I/O. Same as the C fprintf() function except that output can also be directed to a string object. Note: the %s format specifier works with both strings and char *. All other format operators have the same meaning.
int Printv(String_or_FILE *f, String_or_char *arg1,..., NULL)
Prints a variable number of strings arguments to the output. The last argument to this function must be NULL. The other arguments can either be char * or string objects.
int Putc(int ch, String_or_FILE *f)
Same as the C fputc() function.
int Write(String_or_FILE *f, void *buf, int len)
Same as the C write() function.
int Read(String_or_FILE *f, void *buf, int maxlen)
Same as the C read() function.
int Getc(String_or_FILE *f)
Same as the C fgetc() function.
int Ungetc(int ch, String_or_FILE *f)
Same as the C ungetc() function.
int Seek(String_or_FILE *f, int offset, int whence)
Same as the C seek() function. offset is the number of bytes. whence is one of SEEK_SET,SEEK_CUR, or SEEK_END..
long Tell(String_or_FILE *f)
Same as the C tell() function.
File *NewFile(const char *filename, const char *mode)
Create a File object using the fopen() library call. This file differs from FILE * in that it can be placed in the standard SWIG containers (lists, hashes, etc.).
File *NewFileFromFile(FILE *f)
Create a File object wrapper around an existing FILE object.
int Close(String_or_FILE *f)
Closes a file. Has no effect on strings.The use of the above I/O functions and strings play a critical role in SWIG. It is common to see small code fragments of code generated kind of like this:
Similarly, the preprocessor and parser all operate on string-files./* Print into a string */ String *s = NewString(""); Printf(s,"Hello\n"); for (i = 0; i < 10; i++) { Printf(s,"%d\n", i); } ... /* Print string into a file */ Printf(f, "%s\n", s);
All types in SWIG consist of a base datatype and a collection of type operators that are applied to the base. A base datatype is almost always some kind of primitive type such as int or double. The operators consist of things like pointers, references, arrays, and so forth. Internally, types are represented as strings that are constructed in a very precise manner. Here are some examples:
Reading the SWIG encoding is often easier than figuring out the C code---just read it from left to right. For a type of "p.f(int,double).int" is a "pointer to a function(int,double) that returns int".C datatype SWIG encoding (strings) ----------------------------- -------------------------- int "int" int * "p.int" const int * "p.q(const).int" int (*x)(int,double) "p.f(int,double).int" int [20][30] "a(20).a(30).int" int (F::*)(int) "m(F).f(int).int" vector<int> * "p.vector<(int)>"
The following operator encodings are used in type strings:
In addition, type names may be parameterized by templates. This is represented by enclosing the template parameters in <( ... )>. Variable length arguments are represented by the special base type of v(...).Operator Meaning ------------------- ------------------------------- p. Pointer to a(n). Array of dimension n r. C++ reference m(class). Member pointer to class f(args). Function. q(qlist). Qualifiers
If you want to experiment with type encodings, the raw type strings can be inserted into an interface file using backticks `` wherever a type is expected. For instance, here is an extremely perverted example:
This corresponds to the immediately obvious C declaration:`p.a(10).p.f(int,p.f(int).int)` foo(int, int (*x)(int));
Aside from the potential use of this declaration on a C programming quiz, it motivates the use of the special SWIG encoding of types. The SWIG encoding is much easier to work with because types can be easily examined, modified, and constructed using simple string operations (comparison, substrings, concatenation, etc.). For example, in the parser, a declaration like this(*(*foo(int,int (*)(int)))[10])(int,int (*)(int));
is processed in a few pieces. In this case, you have the base type "int" and the declarator of type "a(30).p.". To make the final type, the two parts are just joined together using string concatenation.int *a[30];
void SwigType_add_pointer(SwigType *ty)
Adds a pointer to ty.
void SwigType_del_pointer(SwigType *ty)
Removes a single pointer from ty.
void SwigType_add_reference(SwigType *ty)
Adds a reference to ty.
void SwigType_add_array(SwigType *ty, String_or_char *dim)
Adds an array with dimension dim to ty.
void SwigType_add_qualifier(SwigType *ty, String_or_char *q)
Adds a type qualifier q to ty. q is typically "const" or "volatile".
void SwigType_add_memberpointer(SwigType *ty, String_or_char *cls)
Adds a pointer to a member of class cls to ty.
void SwigType_add_function(SwigType *ty, ParmList *p)
Adds a function to ty. p is a linked-list of parameter nodes as generated by the parser. See the section on parameter lists for details about the representation.
SwigType *SwigType_pop(SwigType *ty)
Removes the last type constructor from ty and returns it. ty is modified.
void SwigType_push(SwigType *ty, SwigType *op)
Pushes the type operators in op onto type ty. The opposite of SwigType_pop().
SwigType *SwigType_pop_arrays(SwigType *ty)
Removes all leading array operators from ty and returns them. ty is modified. For example, if ty is "a(20).a(10).p.int", then this function would return "a(20).a(10)." and modify ty so that it has the value "p.int".
SwigType *SwigType_pop_function(SwigType *ty)
Removes a function operator from ty including any qualification. ty is modified. For example, if ty is "f(int).int", then this function would return "f(int)." and modify ty so that it has the value "int".
SwigType *SwigType_base(SwigType *ty)
Returns the base type of a type. For example, if ty is "p.a(20).int", this function would return "int". ty is unmodified.
SwigType *SwigType_prefix(SwigType *ty)
Returns the prefix of a type. For example, if ty is "p.a(20).int", this function would return "p.a(20).". ty is unmodified.
int SwigType_ispointer(SwigType *ty)
Checks if ty is a standard pointer.
int SwigType_ismemberpointer(SwigType *ty)
Checks if ty is a member pointer.
int SwigType_isreference(SwigType *ty)
Checks if ty is a C++ reference.
int SwigType_isarray(SwigType *ty)
Checks if ty is an array.
int SwigType_isfunction(SwigType *ty)
Checks if ty is a function.
int SwigType_isqualifier(SwigType *ty)
Checks if ty is a qualifier.
int SwigType_issimple(SwigType *ty)
Checks if ty is a simple type. No operators applied.
int SwigType_isconst(SwigType *ty)
Checks if ty is a const type.
int SwigType_isvarargs(SwigType *ty)
Checks if ty is a varargs type.
int SwigType_istemplate(SwigType *ty)
Checks if ty is a templatized type.
To handle typedef, SWIG builds a collection of trees containing typedef relations. For example,
produces two trees like this:typedef int Integer; typedef Integer *IntegerPtr; typedef int Number; typedef int Size;
To resolve a single typedef relationship, the following function is used:int p.Integer ^ ^ ^ ^ / | \ | / | \ | Integer Size Number IntegerPtr
SwigType *SwigType_typedef_resolve(SwigType *ty)
Checks if ty can be reduced to a new type via typedef. If so, returns the new type. If not, returns NULL.Typedefs are only resolved in simple typenames that appear in a type. For example, the type base name and in function parameters. When resolving types, the process starts in the leaf nodes and moves up the tree towards the root. Here are a few examples that show how it works:
For complicated types, the process can be quite involved. Here is the reduction of a function pointer:Original type After typedef_resolve() ------------------------ ----------------------- Integer int a(30).Integer int p.IntegerPtr p.p.Integer p.p.Integer p.p.int
Two types are equivalent if their full type reductions are the same. The following function will fully reduce a datatype:p.f(Integer, p.IntegerPtr, Size).Integer : Start p.f(Integer, p.IntegerPtr, Size).int p.f(int, p.IntegerPtr, Size).int p.f(int, p.p.Integer, Size).int p.f(int, p.p.int, Size).int p.f(int, p.p.int, int).int : End
SwigType *SwigType_typedef_resolve_all(SwigType *ty)
Fully reduces ty according to typedef rules. Resulting datatype will consist only of primitive typenames.
cdecl
Describes general C declarations including variables, functions, and typedefs. A declaration is parsed as "storage T D" where storage is a storage class, T is a base type, and D is a declarator."name" - Declarator name "type" - Base type T "decl" - Declarator type (abstract) "storage" - Storage class (static, extern, typedef, etc.) "parms" - Function parameters (if a function) "code" - Function body code (if supplied) "value" - Default value (if supplied)
constructor
C++ constructor declaration."name" - Name of constructor "parms" - Parameters "decl" - Declarator (function with parameters) "code" - Function body code (if any) "feature:new" - Set to indicate return of new object.
destructor
C++ destructor declaration."name" - Name of destructor "code" - Function body code (if any) "storage" - Storage class (set if virtual) "value" - Default value (set if pure virtual).
access
C++ access change."kind" - public, protected, private
constant
Constant created by %constant or #define."name" - Name of constant. "type" - Base type. "value" - Value. "storage" - Set to %constant "feature:immutable" - Set to indicate read-only
class
C++ class definition or C structure definition."name" - Name of the class. "kind" - Class kind ("struct", "union", "class") "symtab" - Enclosing symbol table. "tdname" - Typedef name. Use for typedef struct { ... } A. "abstract" - Set if class has pure virtual methods. "baselist" - List of base class names. "storage" - Storage class (if any) "unnamed" - Set if class is unnamed.
enum
Enumeration."name" - Name of the enum (if supplied). "storage" - Storage class (if any) "tdname" - Typedef name (typedef enum { ... } name). "unnamed" - Set if enum is unnamed.
enumitem
Enumeration value."name" - Name of the enum value. "type" - Type (integer or char) "value" - Enum value (if given) "feature:immutable" - Set to indicate read-only
namespace
C++ namespace."name" - Name of the namespace. "symtab" - Symbol table for enclosed scope. "unnamed" - Set if unnamed namespace "alias" - Alias name. Set for namespace A = B;
using
C++ using directive."name" - Name of the object being referred to. "uname" - Qualified name actually given to using. "node" - Node being referenced. "namespace" - Namespace name being reference (using namespace name)
classforward
A forward C++ class declaration."name" - Name of the class. "kind" - Class kind ("union", "struct", "class")
insert
Code insertion directive. For example, %{ ... %} or %insert(section)."code" - Inserted code "section" - Section name ("header", "wrapper", etc.)
top
Top of the parse tree."module" - Module name
extend
%extend directive."name" - Module name "symtab" - Symbol table of enclosed scope.
apply
%apply pattern { patternlist }."pattern" - Source pattern. "symtab" - Symbol table of enclosed scope.
clear
%clear patternlist;"firstChild" - Patterns to clear
include
%include directive."name" - Filename "firstChild" - Children
import
%import directive."name" - Filename "firstChild" - Children
module
%module directive."name" - Name of the module
typemap
%typemap directive."method" - Typemap method name. "code" - Typemap code. "kwargs" - Keyword arguments (if any) "firstChild" - Typemap patterns
typemapcopy
%typemap directive with copy."method" - Typemap method name. "pattern" - Typemap source pattern. "firstChild" - Typemap patterns
typemapitem
%typemap pattern. Used with %apply, %clear, %typemap."pattern" - Typemap pattern (a parameter list) "parms" - Typemap parameters.
types
%types directive."parms" - List of parameter types.
extern
extern "X" { ... } declaration."name" - Name "C", "Fortran", etc.