Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Beazley D.M.SWIG users manual.pdf
Скачиваний:
14
Добавлен:
23.08.2013
Размер:
1.53 Mб
Скачать

SWIG Users Guide

SWIG and Perl5

123

 

 

 

A simple Perl example

In the next few sections, use of the Perl5 module will be illustrated through a series of increasingly complex examples. In the example, we will write some simple graph algorithms to illustrate how C and Perl can interact with each other.

Graphs

A directed graph is simply a collection of nodes (or vertices) that are connected to each other by a collection of edges :

A graph

To represent simple graphs, we can use the following C data structures :

/* File : graph.h */

/* Simple data structures for directed graph of Nodes and Edges */

struct Edge;

 

 

 

typedef struct Node {

 

 

int

v;

/* Vertex number

*/

struct Edge

*adj;

/* Adjacency List

*/

} Node;

 

 

 

typedef struct Edge {

 

 

Node

*node;

/* Connecting Node

*/

double

w;

/* Weight (optional)

*/

struct Edge

*next;

/* Next edge

*/

} Edge;

 

 

 

Each node contains a unique number v for identifying it, and a linked list of other nodes that are nearby. This linked list is managed by the Edge structure. Associated with each edge is an optional weighting factor. This could be something like miles between cities, bandwidth, or some other numerical property about a particular link. Okay, enough talk about data structures for now.

To construct nodes and add edges, we can use the following C code :

/* File : graph.c

*/

/* Directed graph functions */

#include "graph.h"

 

static int node_count = 0;

/* Number of nodes created */

Version 1.1, June 24, 1997

SWIG Users Guide

SWIG and Perl5

124

 

 

 

/* Create a new Node */ Node *new_Node() {

Node *node;

node = (Node *) malloc(sizeof(Node));

node->v = node_count++; /* Bump up the count */ node->adj = (Edge *) 0;

return node;

}

/* Add an "edge" to another node. */

Edge *Node_addedge(Node *mynode, Node *othernode, double w) { Edge *edge;

edge = (Edge *) malloc(sizeof(Edge)); edge->node = othernode;

edge->w = w;

edge->next = mynode->adj; /* add to my adjacency list */ mynode->adj = edge;

return edge;

}

A simple SWIG interface file

So far, the code doesn’t do much, but it’s enough to wrap into Perl5 module. Since the C code is fairly simple right now, we can do this by creating the following interface file :

%module graph

 

%{

 

#include “graph.h”

 

%}

 

%include graph.h

// Get structure definition

%include graph.c

// Get support functions

We’ll call our module “graph” and simply read in both the files graph.h and graph.c to build an interface.

Sample Perl Script

Once compiled, we can now start using our new module. All of the C functions found in graph.h and graph.c can be called normally . Even though we are using pointers, this is not a problem. Here is a very simple script :

# Perl code to use our graph code

0

use graph; package graph;

1

# Create some nodes

2

$n0 = new_Node(); $n1 = new_Node(); $n2 = new_Node();

# Make some edges

 

 

 

 

Node_addedge($n0,$n1,0);

#

0

->

1

Node_addedge($n0,$n2,0);

#

0

->

2

Version 1.1, June 24, 1997

SWIG Users Guide

SWIG and Perl5

 

 

 

125

 

 

 

 

 

Node_addedge($n1,$n2,0);

#

1

->

2

Node_addedge($n2,$n0,0);

#

2

->

0

# A procedure to print out a node and its adjacency list sub print_node {

my $node = shift;

print "Node : ", Node_v_get($node), ", Adj : ";

my $adj = Node_adj_get($node);

 

while (defined($adj)) {

# This checks for a NULL pointer

my $anode = Edge_node_get($adj);

 

my $v = Node_v_get($anode);

 

print "$v ";

 

$adj = Edge_next_get($adj);

# Move to next node

}

 

print "\n";

 

}

# Print out node information print_node($n0); print_node($n1); print_node($n2);

When executed, this script produces the following output :

Node : 0, Adj : 2 1

Node : 1, Adj : 2

Node : 2, Adj : 0

While our two C functions are used in the script, SWIG also created a collection of accessor functions for managing the two C data structures. The functions Node_v_get(),

Node_adj_get(), Edge_node_get(), and Edge_next_get() are used to access the corresponding members of our Node and Edge structures. As arguments, these functions simply take a pointer to the corresponding structure.

There are a few other things to notice about the code.

Pointers to complex objects are manipulated like ordinary scalar values, but in reality they are blessed references. For all practical purposes, you should think of them as funny opaque objects (in other words, don’t worry about it).

To check for a NULL pointer, use the expression defined($ptr). This will return true if a pointer is non-NULL, false if it isn’t. In our example, we use this to walk down a linked list of pointers until we reach a NULL value.

Even though the original C code was rather useless by itself, we have used it to build a simple graph in Perl along with a debugging function for printing out node information. In fact, without making any modifications to the C code, we can use this to build up something more complex such as a database of cities and mileages.

Version 1.1, June 24, 1997

SWIG Users Guide

SWIG and Perl5

126

 

 

 

Denver, Cheyenne,

100

Denver, Santa Fe,

362

Denver, Kansas City,

600

Santa Fe, Albuquerque,

55

Santa Fe, Durango,

214

...

 

Durango, Moab,

160

Moab, Salt Lake City,

237

Moab, Denver,

310

Cheyenne, Salt Lake City,

436

Some cities and mileages

Here’s a slightly more complicated Perl script to read in the above mileage table and turn it into

agraph:

#Read a file with cities into a graph

use graph; package graph;

%Cities = ();

# Hash table mapping cities to nodes

%Nodes = ();

# Mapping of Node indicies to cities

sub read_cities {

 

my $filename = shift; open(CITIES,$filename); while (<CITIES>) {

chop;

my @a = split(/, +/); my $node1;

my $node2;

#Check to see if a given city is already a node if (!exists $Cities{$a[0]}) {

$node1 = new_Node(); $Cities{$a[0]} = $node1;

my $node_num = Node_v_get($node1); $Nodes{$node_num} = $a[0];

} else {

$node1 = $Cities{$a[0]};

}

if (!exists $Cities{$a[1]}) { $node2 = new_Node(); $Cities{$a[1]} = $node2;

my $node_num = Node_v_get($node2); $Nodes{$node_num} = $a[1];

} else {

$node2 = $Cities{$a[1]};

}

#Add edges

Node_addedge($node1,$node2,$a[2]);

Node_addedge($node2,$node1,$a[2]);

}

}

Version 1.1, June 24, 1997