The swig.swg file contains global configuration information. In addition, this file defines many of SWIG's standard directives as macros. For instance, an excerpt 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 %pragma 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 %readonly %pragma(swig) readonly; #define %readwrite %pragma(swig) readwrite; /* Directives for callback functions */ #define %callback(x) %pragma(swig) callback=`x`; #define %nocallback %pragma(swig) nocallback; /* Directives for attribute functions */ #define %attributefunc(_x,_y) %pragma(swig) attributefunction=`_x`":"`_y`; #define %noattributefunc %pragma(swig) noattributefunction; /* %ignore directive */ #define %ignore %rename($ignore) #define %ignorewarn(x) %rename("$ignore:" x) /* Generation of default constructors/destructors */ #define %nodefault %pragma nodefault #define %makedefault %pragma makedefault ...
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.
Although the SWIG preprocessor is intended to mimic the behavior of the C preprocessor, it is not meant to be a direct replacement. Instead, its behavior is adapted for use with SWIG and it provides a number of a non-standard extensions:
These blocks are used during parsing and code generation to track the relationship between all of the files that were included or imported into an interface. This is especially important when SWIG is being used to create a collection of interrelated extension modules.%includefile "example.i" { ... }
These macros differ from C preprocessor macros in two respects. First, they can span multiple lines. Second, when the macros are expanded, the expanded text is re-parsed by the preprocessor.%define FOO(a,b) ... %enddef
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 form 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, I wanted to make SWIG 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 declarations in which an extra (and unnecessary) grouping operator is used. For example:
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:int (x); /* A variable x */ int (y)(int); /* A function y */
In this case, the return type as well as the types of the arguments are taken 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 stored as a hash table. 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
However, the picture is actually a little more complicated than this. In certain cases, parse tree nodes are transformed.