• No results found

5. Implementing GP 2

5.9. Code Generation

5.9.3. Rule Application

The code generator scans the right-hand side of a rule to generate the function to apply the rule. First, local variables are declared to store the values from the morphism needed for right-hand side labels, namely values of variables and the degrees of host nodes. The right-hand side may not contain all variables in the rule. As mentioned earlier, nodes and variables in the rule data structure are flagged if they participate in a right-hand side label. This informs the code generator to print code to extract the appropriate values from the morphism or from the host graph. This minimises the morphism and host graph querying at runtime. The values of integer variables, the values of string variables and

b o o l match node {

f o r ( n o d e s N o f t h e h o s t graph ) {

i f (N i s n o t a v a l i d match f o r node ) continue ; e l s e { f l a g N a s matched ; c a l l p r e d i c a t e e v a l u a t o r s ; i f ( c o n d i t i o n e v a l u a t e s t o t r u e ) return t r u e ; e l s e r e s e t b o o l e a n v a r i a b l e s ; } } return f a l s e ; }

Figure 5.30.: Generated code for matching a node that participates in the condi- tion

the degrees of host nodes are stored in variables of the appropriate type. The value of a list variable l is not immediately extracted from the morphism because the type information from the assignment is necessary to create right-hand side labels involving l. In our running example, variables i, x, and the outdegree of node 2 are used in right-hand side labels, resulting in the following local variable initialisation code at the start of the rule application function.

void a p p l y M a i n r u l e ( Morphism ∗ morphism , b o o l r e c o r d c h a n g e s ) { i n t v a r 0 = g e t I n t e g e r V a l u e ( morphism , 0 ) ;

Assignment v a r 1 = g e t A s s i g n m e n t ( morphism , 1 ) ; i n t n o d e i n d e x = lookupNode ( morphism , 1 ) ;

i n t o u t d e g r e e 1 = g e t O u t d e g r e e ( h o s t , n o d e i n d e x ) ;

In addition to the morphism, the rule application function takes a boolean argument called record changes. If set to true, the code will push a frame to the graph change stack when a change is made to the host graph. We omit that code for conciseness. Host graph modifications are performed in the following order to prevent conflicts and dangling edges: delete edges, relabel edges, delete nodes, relabel nodes, add nodes, add edges. It follows that the images of e0 and n0 are removed from the host graph first:

i n t h o s t e d g e i n d e x = lookupEdge ( morphism , 0 ) ; i f ( r e c o r d c h a n g e s ) { . . . } removeEdge ( h o s t , h o s t e d g e i n d e x ) ; i n t h o s t n o d e i n d e x = lookupNode ( morphism , 0 ) ; i f ( r e c o r d c h a n g e s ) { . . . } removeNode ( h o s t , h o s t n o d e i n d e x ) ;

The next stage of rule application is to relabel n1 and n2. The code to relabel n1 is below.

h o s t n o d e i n d e x = lookupNode ( morphism , 1 ) ;

H o s t L a b e l l a b e l n 1 = g e t N o d e L a b e l ( h o s t , h o s t n o d e i n d e x ) ; H o s t L a b e l l a b e l ;

i n t l i s t l e n g t h 0 = l i s t v a r l e n g t h 0 + 1 ; HostAtom a r r a y 0 [ l i s t l e n g t h 0 ] ; i n t i n d e x 0 = 0 ; a r r a y 0 [ i n d e x 0 ] . t y p e = ’ i ’ ; a r r a y 0 [ i n d e x 0 ++].num = o u t d e g r e e 1 ; H o s t L i s t ∗ l i s t 0 = m a k e H o s t L i s t ( a r r a y 0 , l i s t l e n g t h 0 , f a l s e ) ; l a b e l = makeHostLabel ( 0 , l i s t l e n g t h 0 , l i s t 0 ) ; i f ( e q u a l H o s t L a b e l s ( l a b e l n 1 , l a b e l ) ) r e m o v e H o s t L i s t ( l a b e l . l i s t ) ; e l s e { i f ( r e c o r d c h a n g e s ) { . . . } r e l a b e l N o d e ( h o s t , h o s t n o d e i n d e x , l a b e l ) ; }

An array of HostAtoms called array04 is created to store the evaluated right- hand side label. The size of the array is the sum of the number of non-list variable atoms in the right-hand side label and the values of all list variables in the right- hand side label. The first value is worked out at compile time, while the second requires a runtime computation if any list variables exist in the label. In this case, the right-hand side label is outdeg(2), a list of length 1 containing no list variables. The first element of the array is assigned the type ‘i‘ and the value of the local variable outdegree1. Before relabelling is performed, the function makeHostList adds the new label to the hash table and returns a pointer to the list. This pointer is passed to makeHostLabel with the mark from the rule label. A mark is represented as an enumerator. The code generator prints the integer value of the enumerator; here 0 represents the absence of a mark. Finally, the new label is compared with the current label of n1. If they are different, then the change is pushed to the graph change stack if necessary and the node is relabelled. Otherwise, removeHostList is called to decrement the reference count of the list in the hash table. The code to relabel the other node is similar, except the array value is set to var 0 * var 0, where var 0 was earlier initialised to the value of variable i.

Finally, the code to add the new node and edge is below.

Populating the array from a list variable is more cumbersome than from an integer or a string variable because the way that the array is populated depends on the type of the assignment. Another complication is that adding an edge to the host graph requires knowledge of its source and target. Nodes incident to added edges are either interface nodes or nodes created by the rule. This information is available from the interface pointers in the structures for rule nodes. If the node is in the interface, the node identifier is found through the morphism. In the second case, the node identifier is found in the rhs node map array created before nodes are added to the host graph. In the running example, the new edge is incident to n2, an interface node, and the new node. The code queries the morphism to get n2’s image, and it queries rhs node map for the added node. The morphism is reset through a function call before function exit so that future matches of the same rule are not corrupted by the existing morphism values.

4

/∗ Array o f h o s t node i n d i c e s i n d e x e d by RHS node . ∗/ i n t r h s n o d e m a p [ 3 ] ; i n t l i s t v a r l e n g t h 2 = 0 ; l i s t v a r l e n g t h 2 += g e t A s s i g n m e n t L e n g t h ( v a r 1 ) ; i n t l i s t l e n g t h 2 = l i s t v a r l e n g t h 2 + 0 ; HostAtom a r r a y 2 [ l i s t l e n g t h 2 ] ; i n t i n d e x 2 = 0 ; i f ( v a r 1 . t y p e == ’ l ’ && v a r 1 . l i s t != NULL) { H o s t L i s t I t e m ∗ i t e m 2 = v a r 1 . l i s t −> f i r s t ; while ( i t e m 2 != NULL) { a r r a y 2 [ i n d e x 2 ++] = item2−>atom ; i t e m 2 = item2−>n e x t ; } } e l s e i f ( v a r 1 . t y p e == ’ i ’ ) { a r r a y 2 [ i n d e x 2 ] . t y p e = ’ i ’ ; a r r a y 2 [ i n d e x 2 ++].num = v a r 1 . num ; } e l s e i f ( v a r 1 . t y p e == ’ s ’ ) { . . . } H o s t L i s t ∗ l i s t 2 = m a k e H o s t L i s t ( a r r a y 2 , l i s t l e n g t h 2 , f a l s e ) ; l a b e l = makeHostLabel ( 0 , l i s t l e n g t h 2 , l i s t 2 ) ; h o s t n o d e i n d e x = addNode ( h o s t , 0 , l a b e l ) ; r h s n o d e m a p [ 0 ] = h o s t n o d e i n d e x ; i f ( r e c o r d c h a n g e s ) { . . . } i n t s o u r c e , t a r g e t ; s o u r c e = r h s n o d e m a p [ 0 ] ; t a r g e t = lookupNode ( morphism , 2 ) ; h o s t e d g e i n d e x = addEdge ( h o s t , b l a n k l a b e l , s o u r c e , t a r g e t ) ; i f ( r e c o r d c h a n g e s ) { . . . }