Constant

The constant attribute on a metavariable declaration will only match an explicit literal value. For instance constant int matches a literal that is considered to have int type.

@r@
int E1;
constant int C;
@@

E1 = C

Because in Linux constant defined using #define are commonly written using only capital letters, an identifier written using only capital letters is considered to be a constant as well. For example, consider the following semantic patch:

@@ identifier C; @@

+ an_identifier(
  C
+ )

@@ constant int C; @@

+ an_int_constant(
  C
+ )

@@ constant C; @@

+ a_constant(
  C
+ )

and the following C file:

int f() {
  return 1 + SOMETHING;
}

the result is:

int f() {
  return an_int_constant(a_constant(1)) + an_identifier(a_constant(SOMETHING));
}

because 1 is both a constant and an integer constant, while SOMETHING is both an identifier and a constant, but not an integer constant, because its type is not known. On the other hand, if the C file also contains:

#define SOMETHING 1

then SOMETHING is also considered to be an integer constant.

While there is a constant attribute, there is no attribute to indicate that a metavariable should not match a constant. This can be done using a disjunction, ( | ), in the pattern, as illustrated by the following example:

@r@
int E;
constant int C;
long E1;
@@

E1 = 
(
   C
|
-  E
+  f(E)
)

This semantic patch wraps a call to f around the right-hand side of an assignment, unless the right-hand side is a constant.

Fresh identifier

The “fresh” attribute on an identifier metavariable declaration allows creating new identifiers to be used in the generated (+) code. The declaration of a fresh identifier x has three possible forms, which determine how the new identifier is chosen:

  • fresh identifier x; : In this case, spatch will prompt the user for the new identifier name, at each occurrence of x. If end_of_file is found, an identifier name will be constructed by concatenating extra_counter to an integer that is incremented each time this strategy is used.
  • fresh identifier x = “prefix”; : In this case, an identifier name will be constructed by concatenating prefix to an integer that is incremented each time this strategy is used.
  • fresh identifier x = “prefix” ## r.y ## “suffix”; : In this case, the identifier is constructed from the concatenation of a collection of strings and identifier metavariable bindings. The metavariables can be either declared in previous rules or earlier in the metavariable declarations of the current one. In the latter case, the value of each metavariable will be its value in the context in which each occurrence of x appears, implying that different occurrences of x can map to different fresh identifiers.

Matching identifier with a regular expression

Metavariable of identifier can not only be used to match any identifier, or exactly the ones defined in a list, but also match according to a regular expression. Some examples are provided below:

@anyid@
type t;
identifier id;
@@

t id () {
...
}

@script:python@
x << anyid.id;
@@

print "Identifier: %s" % x

@contains@
type t;
identifier foo ~= ".*foo";
@@

t foo () {
...
}

@script:python@
x << contains.foo;
@@

print "Contains foo: %s" % x

@nocontain@
type t;
identifier foo !~= ".*foo";
@@

t foo () {
...
}

@script:python@
x << nocontain.foo;
@@

print "Does not contain foo: %s" % x

@endsby@
type t;
identifier foo ~= ".*foo$";
@@

t foo () {
...
}

@script:python@
x << endsby.foo;
@@

print "Ends by foo: %s" % x

@beginsby@
type t;
identifier foo ~= "^foo";
@@

t foo () {
...
}

@script:python@
x << beginsby.foo;
@@

print "Begins by foo: %s" % x

Group, alternative and optional element can be used in the regexp, as illustrated by the following example:

@@
identifier SPAM ~= "\(WINE_\)?\(ERR\|FIXME\|WARN\)";
@@

-SPAM
+bar

Constraints on identifiers

An identifier metavariable can be constrained to be different from either a concrete identifier or an identifier metavariable inherited from a previous rule. Examples of such metavariable declarations are as follows, where some previous rule r has declared an identifier metavariable id.

identifier a != foo;
identifier b != {foo,r.id};
identifier c != r.id;

In the second and third cases, the constraint is that the declared metavariable is different from some binding of r.id, and not that it is different from every binding of r.id, which is somewhat unfortunate and should be fixed at some point. This kind of constraint is thus only useful in practice when r.id has only one possible binding.

Subexpressions

The constraint

<=

on the declaration of an expression metavariable allows declaring a metavariable that matches a subexpression of another one. This is particularly useful in checking that the value of the expression matching an expression metavariable has not changed from one matching instance to another one. An example is as follows:

@r@
expression E;
@@

f(E);

@@
expression subE <= r.E;
expression E1;
@@

f(E);
... when != subE = E1
return E;
 
metavariables.txt · Last modified: 2010/05/24 11:08 by jll
 
Except where otherwise noted, content on this wiki is licensed under the following license:CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki