<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.0 20120330//EN" "JATS-archivearticle1.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink">
  <front>
    <journal-meta />
    <article-meta>
      <title-group>
        <article-title>AST Matching based on Concrete Syntax Patterns: Exploration of the Specification Challenges</article-title>
      </title-group>
      <contrib-group>
        <contrib contrib-type="author">
          <string-name>Arjan J. Mooij</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
          <xref ref-type="aff" rid="aff1">1</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Piërre van de Laar</string-name>
        </contrib>
        <contrib contrib-type="author">
          <string-name>TNO-ESI</string-name>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Eindhoven</string-name>
        </contrib>
        <contrib contrib-type="author">
          <string-name>The Netherlands</string-name>
        </contrib>
        <aff id="aff0">
          <label>0</label>
          <institution>Delft University of Technology</institution>
          ,
          <addr-line>Delft</addr-line>
          ,
          <country country="NL">The Netherlands</country>
        </aff>
        <aff id="aff1">
          <label>1</label>
          <institution>Zürich University of Applied Sciences</institution>
          ,
          <addr-line>Winterthur</addr-line>
          ,
          <country country="CH">Switzerland</country>
        </aff>
      </contrib-group>
      <abstract>
        <p>Software analysis often relies on pattern matching in terms of Abstract Syntax Trees (ASTs), but AST patterns are known to be tedious to specify. Concrete syntax patterns with placeholders have been proposed as a user-friendly alternative. Several designs for this proposal have been implemented, but these typically focus on specific parsing technologies. In this paper we explore the overarching challenges of specifying AST patterns using concrete syntax with placeholders. Using our experience with industrial applications, we take the perspective of an analyst who creates concrete syntax patterns to find matches in a code base. We identify two specification challenges: (1) understanding the underlying AST structure, and (2) ambiguities caused by placeholders. For designs based on black-box parsers we also inventorize the challenge of (3) encoding and recognizing the placeholders in concrete syntax patterns. We illustrate these challenges with examples in the Ada and C/C++ programming languages. Our results can serve as warnings to users of concrete syntax patterns, as additional requirements for parser front-ends, as attention points for language specifications, and as starting points for further research on pattern matching.</p>
      </abstract>
      <kwd-group>
        <kwd>eol&gt;Abstract Syntax Tree</kwd>
        <kwd>pattern matching</kwd>
        <kwd>concrete syntax patterns</kwd>
      </kwd-group>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>1. Introduction</title>
      <p>
        Pattern matching on Abstract Syntax Trees (ASTs) is used widely for analyzing software [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ], and for
defining operational semantics [
        <xref ref-type="bibr" rid="ref2">2</xref>
        ]. In practice, when specifying code patterns in terms of abstract
syntax, it is tedious to specify all the nodes and attributes: it quickly becomes unreadable, and you
easily forget to specify that certain nodes should be absent and certain attributes should have default
values. Similar observations are made in [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ]. Specifications in terms of abstract syntax have a steep
learning curve that easily distracts from the analysis. This is illustrated by the example in Fig. 1.
      </p>
      <p>
        As explained in [
        <xref ref-type="bibr" rid="ref3">3</xref>
        ], “the abstract syntax must be provided behind-the-scenes to enable model management
and manipulation”, whereas “the concrete syntax must be designed so that end-users have a familiar and
accessible syntax”. Parsers first produce a concrete syntax tree, and afterwards reduce it to an abstract
syntax tree by eliminating irrelevant information such as whitespaces and comments. The mapping
from concrete to abstract syntax may be complex.
      </p>
      <p>
        The idea of “native patterns” [
        <xref ref-type="bibr" rid="ref4">4</xref>
        ] is that code patterns should resemble normal code in the object
language. The object language is the language of the code being analyzed, whereas the meta language
describes other aspects of the analysis. Ideally a user of concrete syntax patterns would not need to
understand the underlying AST.
      </p>
      <p>
        We study AST matching based on concrete syntax patterns. The ASTs are matched structurally, but
the AST patterns are described using concrete syntax. Some pattern fragments, each corresponding to
adjacent AST nodes/attributes, can be replaced by meta-language placeholders. As a convention, similar
to [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ], we use ∼ x to denote a placeholder with name x for a single (1..1) AST node/attribute, and ∼ *xs
to denote a placeholder with name xs for a list of multiple (cardinality 0..* ) AST nodes/attributes. Each
placeholder can occur multiple times in a single pattern, e.g., ∼ x + ∼ x, denoting that the AST nodes
that match with these placeholder occurrences should be identical. In practice, parsers may store file
positions and comments as part of the AST, but we exclude such annotations from AST matching. For
example, an Ada-pattern that describes an if-then-else statement with equal then- and else-clauses
could be specified as:
      </p>
      <p>if ∼ c then ∼ *stats; else ∼ *stats; end if;</p>
      <p>
        Concrete syntax patterns have been implemented in, e.g., Stratego, TXL, and Rascal. Their designs
for using concrete syntax are described in, e.g., [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ], [
        <xref ref-type="bibr" rid="ref5">5</xref>
        ], and [
        <xref ref-type="bibr" rid="ref6">6</xref>
        ], respectively, but these descriptions
typically focus on specific parsing technologies. Generally the AST patterns are obtained by parsing
using either:
• Grammar of the object language: embed the object language inside the meta language, and create
a new parser;
• Parser for the object language: encode the placeholders using the object language, and use a
black-box parser.
      </p>
      <p>
        Regarding the first approach, [
        <xref ref-type="bibr" rid="ref4">4</xref>
        ] indicates that “a grammar is always necessary in order to parse the
code” and hence the “restriction that a grammar is necessary for generating a pattern language does not
impose extra work”. However, “developing such grammars is a costly and error-prone endeavor, especially
for real-life programming languages” [
        <xref ref-type="bibr" rid="ref6">6</xref>
        ].
      </p>
      <p>
        In this paper we discuss our experience with concrete syntax for AST patterns from industrial
reengineering projects. [
        <xref ref-type="bibr" rid="ref10 ref7 ref8 ref9">7, 8, 9, 10</xref>
        ]. “Reengineering is an area where technology exchange with the IT
industry is crucial. ... The real problems that are known in the IT industry should become available to
academics” [
        <xref ref-type="bibr" rid="ref4">4</xref>
        ]. In this paper we illustrate our experiences using snippets of code in the programming
languages C++ and Ada. The C++ examples are based on the Eclipse C/C++ Development Tools (CDT)
parser [
        <xref ref-type="bibr" rid="ref11">11</xref>
        ], and the Ada examples are based on the Libadalang parser [
        <xref ref-type="bibr" rid="ref12">12</xref>
        ]. We use such parsers as
“The C++ grammar is known to pose a significant parsing challenge ” [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ], “The C++ grammar is
contextdependent and ambiguous. This makes the creation of a C++ parser a complex hence dificult task ” [
        <xref ref-type="bibr" rid="ref14">14</xref>
        ],
and “keeping up with the pace of development of new C++ language features is challenging” [
        <xref ref-type="bibr" rid="ref15">15</xref>
        ].
      </p>
      <p>In this paper we focus on specifying placeholders inside a single concrete syntax pattern, and ignore
aspects like:
• Dealing with macros and pre-processors,
• Meta-language fragments beyond only placeholders (e.g., more complex expressions),
• Linked find/replace patterns for code transformations.</p>
      <p>
        Although the goal of “pattern matching with concrete syntax is WYSIWYG” (what you see is what you
get) [
        <xref ref-type="bibr" rid="ref2">2</xref>
        ], in this paper we identify three specification challenges:
• Section 2: Understanding the underlying AST structure;
• Section 3: Ambiguities caused by placeholders;
• Section 4: Encoding and recognizing the placeholders.
      </p>
      <p>These are overarching challenges for AST matching based on concrete syntax patterns. We link these
challenges to specific designs in Section 5. Conclusions and future work can be found in Section 6.</p>
    </sec>
    <sec id="sec-2">
      <title>2. Understanding the Underlying AST Structure</title>
      <p>Concrete syntax patterns provide a convenient alternative for writing AST patterns. In this section, we
illustrate that users of concrete syntax patterns are still, sooner or later, confronted with the formal
language structure and/or AST, which may be unfamiliar to them. This can happen in two phases:
• Specification of the concrete syntax patterns;
• Post-processing of AST matches from the code base.</p>
      <p>As far as we know, this challenge does not get attention in the literature on implementing concrete
syntax patterns. In the subsections, we identify groups of related issues. We frequently discuss
diferences between parsers, even though our goal is not to use the same pattern with diferent parsers.
Our goal is to indicate dependencies on implementation decisions from specific parsers, which get
exposed to users of concrete syntax patterns.</p>
      <sec id="sec-2-1">
        <title>2.1. Mental Model may difer from the Formal Language</title>
        <p>Even experienced language users may be surprised by the AST structures of familiar languages. For
example, look at the C++ declaration pattern</p>
        <p>∼ t x
which consists of a specifier ∼ t and a declarator x. Suppose we try to match this pattern with the
following C++ code fragments:
• int x is a match;
• const int x and static int x are also matches, as type qualifiers like const and
storage classes like static are part of the specifier;
• int* x and int&amp; x are no matches, as pointer operators like * and &amp; are part of the declarator.
The last two categories may surprise many C++ developers that did not study the formal language
specification of C++.</p>
        <p>Sometimes there are diferences between related constructs in diferent languages. For example,
AST nodes for if-statements in C++ just contain a condition, then-clause and (optional) else-clause.
However, in Ada there is an additional (possibly-empty) list of elsif-clauses, each with a condition and
statement, which semantically correspond to else-clauses with nested if-statements. This has an impact
on concrete syntax patterns for Ada as the elif-clauses explicitly need to be considered.</p>
        <p>Similarly, the AST of a case-statement in Ada consists of a condition and a list of when-clauses
(containing statements), whereas the AST of the related switch-statement in C++ consists of a condition
and a list of statements (including possibly-nested case- and break-statements, but not grouped by
case-statement). This has an impact on the post-processing of AST matches, even though C++ code
often does not use the full flexibility of the language.</p>
        <p>There are also diferences in multi-variable declarations. A multi-variable declaration in Ada, such as
int x, y := 42;
consists of a list of identifiers and a single optional expression as initial value for all variables. A
multi-variable declaration in C++, such as
consists of a list of declarators, each consisting of an identifier and an optional expression as initial
value. Hence a pattern such as
int ∼ *xs := 3;
int ∼ *xs = 3;
looks useful in Ada as placeholder ∼ *xs can be matched with multiple AST nodes in Ada. However,
the similar pattern
is suspicious in C++, as placeholder ∼ *xs can only be matched with a single AST node in C++.</p>
        <p>
          The challenge discussed in this subsection is caused by matching using the programming languge’s
AST. This challenge may (to some extent) be solvable using diferent matching algorithms like [
          <xref ref-type="bibr" rid="ref16">16</xref>
          ].
        </p>
      </sec>
      <sec id="sec-2-2">
        <title>2.2. AST Representation may be Parser Specific</title>
        <p>The representation of the AST by a specific parser also has an impact. For example, in CDT the AST
node type for unary operators is also used to represent prefix operators, postfix operators, parentheses
and special operators like noexcept(. . .), thus abstracting from their diferent concrete syntax. This
may give unexpected matching results, as C++ expression pattern ∼ op x matches ++x, x++, (x) and
noexcept(x). Moreover C++ function call expression pattern ∼ func(∼ expr) does not match
noexcept(x).</p>
        <p>Another example is the representation of if-then and if-then-else statements. We could imagine the
use of diferent AST node types for these statements, but have only seen a single node type for both
statements in the studied parsers. However, in CDT the else-clause is represented as a single statement
node, which is null if there is no else-clause. In Libadalang the else-clause is represented by a list of
statement nodes, which is empty if there is no else-clause. So in Ada, the pattern</p>
        <p>if ∼ c then ∼ *ts; else ∼ *es; end if;
indicates an optional else-clause, as ∼ *es denotes any number of AST nodes, which may be
counterintuitive from the concrete syntax. This could be solved by introducing a notation like ∼ +es to denote
a placeholder for a non-empty list (1..* ) of AST nodes/attributes.</p>
        <p>Similarly, a qualified name a.b.c.d could be represented as a list [a, b, c, d] or as a tree ((a, b), c),
d). This impacts the behavior of placeholders for lists of nodes, e.g., a.∼ *ps.d. Only in case of a list
representation, ∼ *ps can consist of list of nodes.</p>
        <p>Finally, C++ type qualifiers, like const and volatile, are semantically order-independent. CDT
stores them not as a list, but as a boolean attribute per possible qualifier. Hence const volatile
int x and volatile const int x have identical ASTs, and hence match with each other, which
may look counter-intuitive from the concrete syntax. Also the concrete syntax pattern ∼ *qs int x
cannot be used to specify a declaration with any combination of type qualifiers, as ∼ *qs expects an
(order-dependent) list. Side note: it may also be problematic because all qualifiers are reserved words,
but that is a separate issue that we will address in Section 4.1.</p>
        <p>
          The challenge discussed in this subsection is caused by design decisions from specific languages and
parsers. This challenge may (to some extent) be solvable by taking AST matching into account during
language and parser design; see also the suggestion from [
          <xref ref-type="bibr" rid="ref17">17</xref>
          ] for further research on language design
principles.
        </p>
      </sec>
      <sec id="sec-2-3">
        <title>2.3. Parser-Specific AST may not fulfill your AST Expectations</title>
        <p>
          In Ada, function calls without arguments must omit the bracket pair () in the concrete syntax. In the
AST from Libadalang, this does not lead to a FunctionCall node, but to an Identifier node similar to a
variable reference. According to [
          <xref ref-type="bibr" rid="ref18">18</xref>
          ], the semantic analyzer should use resolution routines to resolve
ambiguous nodes, for example to distinguish procedure calls from entry calls. According to [
          <xref ref-type="bibr" rid="ref3">3</xref>
          ], this
disambiguation should already be resolved in the mapping from concrete syntax to abstract syntax;
see also Section 3.3 on ambiguities caused by missing placeholder context. These expectations are not
fulfilled as no single concrete syntax pattern matches all function calls with any number of arguments.
        </p>
        <p>In addition, decimal literals in Ada can contain optional underscores, like 1_000, to increase
readability, but these underscores are just syntactic sugar. The AST from Libadalang contains the concrete
syntax of the decimal literal, so including any underscores, and hence the ASTs for 1000 and 1_000
difer. Also, the AST from CDT often stores the concrete syntax, causing that for example the long
value 2147483648 is diferent from 2147483648L and that none of the following representations of
the same integer value are identical: 0x10, 0X10, 16, 020, 0b10000, and 0B10000. Yet, the ASTs from
CDT for the strings "con""cat" and "concat" are identical, despite their diferent concrete syntax.</p>
        <p>Furthermore, explicit specifications often do not match their implicit, equivalent specification. In CDT,
the type signed int does not match int and the function declaration with explicitly no parameters,
i.e., void f(void);, does not match the implicit one, i.e., void f();.</p>
        <p>Finally, you may not expect to find parenthesis nodes in an AST, but they are present in Libadalang and
CDT. They are represented in diferent ways: Libadalang represents them using a dedicated ParenExpr
node type, whereas CDT represents them as a unary operator. Thus parenthesis become relevant during
pattern matching, as (x) and x are diferent.</p>
        <p>
          The challenge discussed in this subsection is caused by design decisions from specific languages
and parsers. This challenge may (to some extent) be solvable by taking AST matching into account
during language parser design; see also the suggestion from [
          <xref ref-type="bibr" rid="ref17">17</xref>
          ] for further research on language
design principles.
        </p>
      </sec>
    </sec>
    <sec id="sec-3">
      <title>3. Ambiguities Caused by Placeholders</title>
      <p>
        Specifying AST patterns using concrete syntax with placeholders is less direct than using abstract
syntax, especially when aiming for compactness. In this section, we illustrate that this can easily lead to
ambiguities. In each subsection we identify a source of ambiguity. Additional types of C++ ambiguities
are documented in [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ].
      </p>
      <sec id="sec-3-1">
        <title>3.1. Indistinguishable Object- and Meta Language-Identifiers</title>
        <p>
          Some authors argue for “as few squiggles as possible” [
          <xref ref-type="bibr" rid="ref1">1</xref>
          ] and “minimal syntactic overhead” [
          <xref ref-type="bibr" rid="ref19">19</xref>
          ], and
argue that the ∼ symbol for placeholders should be optional or omitted. However, this can lead to
specifications that are ambiguous in whether an identifier should be interpreted in the meta language
as placeholder name, or in the object language as variable name.
        </p>
        <p>In general, users of concrete syntax patterns may not realise that they are writing a combination of
two languages: the object and meta language. Our own practical experience is that it is useful to have
clearly recognizable placeholder identifiers that are easily distinguishable from variable names.</p>
        <p>The challenge discussed in this subsection is caused by trying to be too compact. This challenge can
be solved by explicitly distinguishing these two types of identifiers.</p>
      </sec>
      <sec id="sec-3-2">
        <title>3.2. Implicit AST Node Type of Placeholders</title>
        <p>
          In some approaches it is possible, or even required, to specify the AST node type of placeholders, either
explicitly or by convention on the placeholder name [
          <xref ref-type="bibr" rid="ref1 ref6">1, 6</xref>
          ]. Sometimes it is possible, or even required,
to omit the AST node type from placeholders. When an AST node type needs to be provided, users of
concrete syntax patterns are exposed to the underlying AST, which is what we aim to avoid or minimize.
However, omitting the AST node type can also introduce ambiguities [
          <xref ref-type="bibr" rid="ref19">19</xref>
          ]. In this section, we focus on
placeholders without explicitly specified AST node type.
        </p>
        <p>Consider the C++ pattern</p>
        <p>∼ x;
for a single statement. Would the type of the placeholder be (any) Statement; an ExpressionStatement;
(any) Expression, nested inside an ExpressionStatement; an IdExpression; or a Name, nested inside an
IdExpression?</p>
        <p>Also consider the C++ enum-declaration pattern</p>
        <p>enum { ∼ member }
where placeholder ∼ member can have two possible AST node types, viz., Enumerator or Name:
• enum { name } is a match for both AST node types.</p>
        <p>• enum { name = 0 } is only a match for AST node type Enumerator.</p>
        <sec id="sec-3-2-1">
          <title>We make the following observations:</title>
          <p>• The more shallow AST node types, e.g., Enumerator, enable the matching of placeholders with
composite AST nodes. Shallow refers to the distance to the root node of the AST, so not to the
node type hierarchy, if any.
• A single AST node type for each placeholder in a concrete syntax pattern avoids case analysis in
the post-processing, e.g., to get the name in all possible matches.</p>
          <p>The combination of these observations suggests to use for each placeholder the most shallow AST node
type within the concrete syntax pattern, which is indeed useful in our experience. This means that for
specifying an enum-member without a default value, either we would need placeholders with cardinality
zero (0..0) in the meta language, or we need to filter out the unwanted matches as post-processing. The
latter option keeps the meta language simpler, yet distributes knowledge over the pattern and the filter.</p>
          <p>A similar situation occurs with the C++ function declaration pattern</p>
          <p>void ∼ func(∼ x) { ∼ *body; }
where placeholder ∼ x can have three possible AST types, viz., ParameterDeclaration,
NamedTypeSpecifier, or Name:
• void f(int) { } is a match for all three placeholder AST types.</p>
          <p>• void f(int i) { } is only a match for a placeholder of type ParameterDeclaration.
Again, the most shallow node type, so ParameterDeclaration, seems to be appropriate. To specify a
parameter declaration without a name, we would again need placeholders with cardinality zero.</p>
          <p>But what about the type of placeholder identifiers that occur more than once? Imagine the C++
pattern for swapping,</p>
          <p>int ∼ t = ∼ x; ∼ x = ∼ y; ∼ y = ∼ t;
in which each placeholder occurs twice. Recall that the pattern matching is applied on the AST, so the
binding of names is not considered. The first occurrence of ∼ t has to be a Name, whereas all other
occurrences of placeholders can be IdExpression and Name. Again, for each placeholder, the most
shallow node type within the full scope of the pattern (so considering all occurrences of the placeholder)
seems to be appropriate, so Name for ∼ t and IdExpression for ∼ x and ∼ y.</p>
          <p>The examples so far can be addressed using the unique most shallow node type, but this is not always
possible. Ada’s SubtypeIndication node type contains an optional constraint of a node type for which
there are 5 possible subtypes. The 2 so-called composite subtypes, Index and Discriminant, just consist
of a non-empty list, but with unrelated node types, DiscreteRange and DiscriminantAssociation, that
can contain just a Name. So there is no unique most shallow node type of placeholder ∼ *xs in pattern
subtype S is T(∼ *xs);.</p>
          <p>The challenge discussed in this subsection is caused by trying to be too compact. This challenge could
be solved by being explicit about the AST node types, but then we would loose some of the benefits of
concrete syntax patterns. An alternative direction would be the use of generalized parsers that produce
all possible ASTs; see also Section 5.1.</p>
        </sec>
      </sec>
      <sec id="sec-3-3">
        <title>3.3. Parsing Dependencies on Name and Type Resolution</title>
        <p>The parsing of languages like C++ requires name and type resolution to resolve ambiguities. For
example, without context about symbols g and ∼ x, statement pattern
is ambiguous in C++. It can be parsed both as a DeclarationStatement that declares a variable ∼ x of
type g, and as an ExpressionStatement that invokes a method g with argument ∼ x. In both cases Name
is a valid AST node type for placeholder ∼ x.</p>
        <p>
          More C++ examples like this are known [
          <xref ref-type="bibr" rid="ref14">14</xref>
          ], including statement
        </p>
        <p>g(∼ x);
∼ x * ∼ y;
that can be parsed as a DeclarationStatement, declaring a variable ∼ y of type ∼ x *, and as an
ExpressionStatement, applying binary operator * to variables ∼ x and ∼ y. In these cases, we noticed
that CDT prefers the parsing as DeclarationStatement, unless we provide a context in which ∼ x and/or
∼ y are declared as variables.</p>
        <p>Such ambiguity aspects have an impact on the specification of concrete syntax patterns in languages
like C++. If we want to disambiguate these patterns, there are two obvious candidates:
1. Solve the ambiguity by annotating some concrete syntax fragments, which are not necessarily
placeholders and which possibly occur within a larger pattern, with the intended AST node type;
2. Solve the ambiguity using a parsing context with declarations of variables, functions, and types.
Note that only the latter candidate requires no additional AST awareness from the user, apart from
knowing when a parsing context needs to be specified. An alternative direction would be the use of
generalized parsers that produce all possible ASTs; see also Section 5.1.</p>
      </sec>
    </sec>
    <sec id="sec-4">
      <title>4. Encoding and Recognizing the Placeholders</title>
      <p>In Section 1 we have described two ways to obtain the ASTs for the patterns. In this section, we focus
on approaches that use a black-box parser for the object language. Such approaches typically consist of
three conceptual steps for handling concrete syntax patterns with placeholders:</p>
      <sec id="sec-4-1">
        <title>1. Encode the placeholders within the concrete syntax;</title>
        <p>2. Parse the concrete syntax into abstract syntax;
3. Recognize the placeholders within the abstract syntax.</p>
      </sec>
      <sec id="sec-4-2">
        <title>For the encoding, we see two overall approaches:</title>
        <p>• The user directly encodes the placeholders;
• Specifications by users are translated into an encoding.</p>
        <p>In this section, we identify challenges for directly encoding the placeholders; note that this is also
relevant when designing a translation to an encoding. In each subsection we identify an aspect of such
a placeholder encoding.</p>
        <sec id="sec-4-2-1">
          <title>4.1. Grammatical Constructs</title>
          <p>The notation ∼ p for placeholders in the previous sections suggests an encoding using an identifier in
the object language, possibly with certain naming conventions. However, usually not all code fragments,
that fully represent one AST node or a list of multiple AST nodes, in the object language can be replaced
by a single identifier. In what follows we discuss two possibilities, which may also be combined, to
address this issue:
• Encode the placeholders using larger language fragments;
• Parse the object language with suficient error recovery.</p>
          <p>As a simple example of an encoding using larger language fragments, consider the pattern for any
statement in C++. The pattern ∼ x is not a valid statement. Appending a semi-colon to the pattern, i.e.,
∼ x;, results in a larger, yet valid statement pattern. This approach is taken by many designs based on
black-box parsers.</p>
          <p>A more complex example is the parameter declaration for functions in Ada. The Ada language
does not support a single name to be used at the place of a parameter declaration, as in function
fun(∼ *xs). Instead, a larger pattern like</p>
          <p>
            function fun(∼ *xs : ∼ Dummy)
could be used, where the special identifier ∼ Dummy would indicate that we do not intend to match
a list of names with this specific type, but a list of (parameter) declarations. In the context of JSON,
the concrete holes in figure 2 from [
            <xref ref-type="bibr" rid="ref6">6</xref>
            ] illustrate the same phenomenon. We have encountered similar
situations, for example, when specifying any list of elsif’s in Ada. The drawback of adding such special
identifiers is that they reduce the understandability of the concrete syntax pattern for users.
          </p>
          <p>
            As an example of parsing with suficient error recovery, consider the C++ declaration pattern
class X { ∼ *f; };
which seems to be a natural way to specify a class with any number of declarations. Even with the extra
semi-colon at the end, this is strictly speaking not valid C++ code, but CDT’s error recovery [
            <xref ref-type="bibr" rid="ref14">14</xref>
            ] parses
∼ *f as a UsingDeclaration with Name ∼ *f. The most shallow node type as discussed in Section 3.2
could then be used to interpret the placeholder as any number of declarations.
          </p>
          <p>Typical examples of concrete syntax fragments that often cannot be resolved in these ways are
reserved words in the object language, as identifiers and reserved words are usually disjoint. Reserved
words could be useful for matching C++ type classifiers such as const and volatile. However,
recall that C++ type classifiers also give another problem in CDT as discussed in Section 2.2.</p>
        </sec>
        <sec id="sec-4-2-2">
          <title>4.2. Name Resolution</title>
          <p>It is convenient if placeholder names can be used in the concrete syntax pattern without explicit
declaration. Although in general the parsing may use declarations to resolve ambiguities, see also
Section 3.3, in our experience the declarations of placeholder names can usually be omitted without
causing problems. The capabilities of the used parsers to deal with incomplete input are key in this
respect.</p>
        </sec>
        <sec id="sec-4-2-3">
          <title>4.3. Naming Scheme</title>
        </sec>
      </sec>
      <sec id="sec-4-3">
        <title>For each placeholder, we usually want to specify:</title>
        <p>• Identifier: name to refer to the specific placeholder;
• Cardinality: how many AST nodes to match, e.g., exactly one node, or any number of nodes;
• AST node types (optional): type of the AST node(s).</p>
        <p>
          The placeholders must be encoded in the concrete syntax, and afterwards be recognized in the
abstract syntax. As noted by [
          <xref ref-type="bibr" rid="ref6">6</xref>
          ], a challenge in concrete syntax patterns is to avoid capture between
placeholder identifiers from the meta language, and normal identifiers from the object language. Some
alternative approaches that we see:
• use a pattern-specific list of placeholder identifiers;
• use a predefined class of placeholder identifiers, which should not be used as normal identifiers
in any pattern.
        </p>
        <p>The first approach might be preferable since each identifier from the language can be used for a
variable and for a placeholder, only not both in the same pattern. However, object and meta-language
identifiers are indistinguishable within a pattern (without considering the list of placeholder identifiers),
a drawback already mentioned in Section 3.1, and a change might afect both the pattern and the list of
placeholder identifiers.</p>
        <p>For brevity reasons, the second approach may be preferable for manually-specified placeholder
encodings. A drawback is that matching actual code is impossible when that code uses variable names
that are in the predefined class of placeholder identifiers. In some cases you can use identifiers that are
illegal according to the object language, but that are supported by the parser. In the Ada language, for
example, identifiers cannot start with a dollar-sign, but Libadalang supports parsing of such identifiers.
In these cases, the drawback is absent and the object and meta-language identifiers can be easily
distinguished.</p>
      </sec>
    </sec>
    <sec id="sec-5">
      <title>5. Related Work</title>
      <p>In this section, we discuss various approaches for concrete syntax patterns from the literature, and
relate them to the specification challenges that we have presented. The subsections correspond to the
two ways to obtain the ASTs for the patterns, as described in Section 1.</p>
      <sec id="sec-5-1">
        <title>5.1. Grammar of the Object Language</title>
        <sec id="sec-5-1-1">
          <title>There are two types of parsing with diferent outputs:</title>
          <p>• Deterministic, like LR (Left-to-right Rightmost derivation) and LL (Left-to-right Leftmost
derivation): produces one single AST;
• Generalized, like GLR (generalized LR) and GLL (generalized LL): produces all possible ASTs.
With respect to the ambiguities from Section 3, generalized parsers can be used to detect ambiguities in
concrete syntax patterns, and to produce all possible interpretations. However, they may complicate
the further processing of matching code fragments, by requiring filtering of duplicate matches, and
case distinctions on specific AST node types.</p>
          <p>
            “Most modern source transformations tools, such as ASF+SDF, Stratego, and DMS, use generalized LR
(GLR) parsers” [
            <xref ref-type="bibr" rid="ref5">5</xref>
            ]. In particular ASF+SDF is used as basis for the native patterns from [
            <xref ref-type="bibr" rid="ref4">4</xref>
            ] and Spoofax.
In contrast, Rascal uses a “scannerless variant of the GLL parsing algorithm” [
            <xref ref-type="bibr" rid="ref20">20</xref>
            ], whereas “TXL ... yields
a deterministic unambiguous parse in all cases” [
            <xref ref-type="bibr" rid="ref5">5</xref>
            ].
          </p>
          <p>
            Stratego in Spoofax uses an approach [
            <xref ref-type="bibr" rid="ref1 ref19">1, 19</xref>
            ] based on language embedding using grammars for the
meta and object language. For meta variables, a squiggle operator (∼ ) is introduced that does not occur
in the object language. To limit the number of squiggles in object patterns, the grammars for meta
variables and object variables may (partially) overlap. Ambiguities are resolved by giving preference to
meta variables over object variables.
          </p>
          <p>
            DMS ([
            <xref ref-type="bibr" rid="ref21">21</xref>
            ]) uses escapes for meta-variables, such as ∖p. Rascal uses placeholders that require a
mandatory indication of the AST node type, e.g., &lt;T p&gt;. TXL [
            <xref ref-type="bibr" rid="ref5">5</xref>
            ] uses p[T] to denote a meta variable
p with AST node type T; cardinality can be expressed using [opt T] and [repeat T]. Native
patterns from [
            <xref ref-type="bibr" rid="ref4">4</xref>
            ] do not visually distinguish between meta and object language variables; they postfix
the placeholder variable for lists with a * or + to denote the cardinality.
          </p>
          <p>
            The approach from [
            <xref ref-type="bibr" rid="ref16">16</xref>
            ] also uses concrete syntax patterns, where :[p] is used to denote holes. The
patterns are parsed using a highly-reusable base grammer that focuses on delimiter pairs. In between
the delimiters, everything is parsed as a sequence of language-specific tokens. This approach avoids
some of our challenges on understanding the underlying AST structure, but cannot handle patterns
that rely on the AST structure beyond the delimiter structure.
          </p>
          <p>
            Coccinelle [
            <xref ref-type="bibr" rid="ref22">22</xref>
            ] uses the Semantic Patch Language (SmPL) to specify patterns using concrete syntax.
However, the underlying pattern matching is based on paths in the control flow graph instead of
structures of the AST. The placeholders are declared with an explicit AST node type.
          </p>
        </sec>
      </sec>
      <sec id="sec-5-2">
        <title>5.2. Parser for the Object Language</title>
        <p>
          ClaiR (C Language Analysis in Rascal) [
          <xref ref-type="bibr" rid="ref6">6</xref>
          ] is based on Eclipse CDT and Rascal. The placeholders are
specified using Rascal’s approach, in which it is mandatory for syntax safety to indicate the AST node
type of placeholders. Placeholders are then automatically encoded in concrete syntax by the lower-step,
and recognized in the abstract syntax by the lift-step. Internally the encoding uses generated placeholder
identifiers. Afterwards “ Rascal’s ordinary pattern evaluation logic takes over” [
          <xref ref-type="bibr" rid="ref6">6</xref>
          ].
        </p>
        <p>
          Mooij et al. [
          <xref ref-type="bibr" rid="ref7">7</xref>
          ] report about an AST pattern matcher for Delphi based on concrete syntax. The same
approach was applied in [
          <xref ref-type="bibr" rid="ref8">8</xref>
          ] for C/C++ using Eclipse CDT, and in [
          <xref ref-type="bibr" rid="ref9">9</xref>
          ] for Ada using Libadalang. During
matching, for each placeholder the most shallow matching AST node type is used. Users encode the
placeholders directly in the concrete syntax using special identifiers, where p can be any valid name:
        </p>
        <sec id="sec-5-2-1">
          <title>Delphi C/C++ Ada</title>
        </sec>
        <sec id="sec-5-2-2">
          <title>Single AST node</title>
          <p>_p
$p
$S_p</p>
        </sec>
        <sec id="sec-5-2-3">
          <title>Multiple AST nodes</title>
          <p>__p
$$p
$M_p
This table illustrates the intricacies of the placeholder naming scheme for diferent languages. The
diferences originate from the identifier syntax that is supported by the parsers. The AST pattern
matcher identifies and interprets the placeholders on-the-fly based on this naming convention. The
following diagnosis information is available in case of failing matches:
• formatted stack-trace with the related pattern and instance nodes, represented both in concrete
and abstract syntax;
• collected placeholders with their values.</p>
        </sec>
      </sec>
    </sec>
    <sec id="sec-6">
      <title>6. Conclusions and Future Work</title>
      <p>We have identified two challenges for specifying concrete syntax patterns for AST matching: (1)
understanding the underlying AST structure, and (2) ambiguities caused by placeholders. For designs
based on black-box parsers we have also inventorized the challenge of (3) encoding and recognizing the
placeholders. Our results can serve
• as warnings to users of concrete syntax patterns,
• as additional requirements for parser front-ends,
• as attention points for language specifications, and
• as starting points for further research on pattern matching.</p>
      <p>
        Note that the third point relates to a research area that was already suggested by [
        <xref ref-type="bibr" rid="ref17">17</xref>
        ], viz., “language
design principles for easily manipulable and transformable programs”.
      </p>
      <p>Future work could explore the debugging functionality in case of unexpectedly failing (or successful)
pattern matches, and the detection of suspicious patterns as discussed in Section 2.1. Other directions
could include ways to specify linked find/replace patterns for code transformations, and other matching
algorithms for concrete syntax patterns.</p>
      <p>
        Acknowledgments The authors thank Jeroen Ketema and Rosilde Corvino for sharing their
experience with the approach from [
        <xref ref-type="bibr" rid="ref8">8</xref>
        ] in industrial contexts, Jef Smits for Spoofax support during our
experiments with the approach from [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ], and Rodin Aarssen for clarifying discussions on the approach
from [
        <xref ref-type="bibr" rid="ref6">6</xref>
        ]. The authors thank Rosilde Corvino and the anonymous reviewers for their feedback on an
earlier version of this article.
      </p>
      <p>Part of the research is carried out as part of the HybridAnalysis program under the responsibility
of TNO-ESI in cooperation with Philips Image Guide Therapy Systems. The research activities are
co-funded by Holland High Tech | TKI HSTM via the PPP Innovation Scheme (PPP-I) for public-private
partnerships.</p>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          [1]
          <string-name>
            <given-names>E.</given-names>
            <surname>Visser</surname>
          </string-name>
          ,
          <article-title>Meta-programming with concrete object syntax</article-title>
          ,
          <source>in: GPCE</source>
          <year>2002</year>
          , volume
          <volume>2487</volume>
          <source>of LNCS</source>
          , Springer,
          <year>2002</year>
          , pp.
          <fpage>299</fpage>
          -
          <lpage>315</lpage>
          . doi:
          <volume>10</volume>
          .1007/3-540-45821-2_
          <fpage>19</fpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          [2]
          <string-name>
            <surname>T. van der Storm</surname>
          </string-name>
          ,
          <article-title>Semantics engineering with concrete syntax</article-title>
          ,
          <source>in: EVCS</source>
          <year>2023</year>
          , volume
          <volume>109</volume>
          of OASIcs,
          <year>2023</year>
          , pp.
          <volume>29</volume>
          :
          <fpage>1</fpage>
          -
          <lpage>29</lpage>
          :
          <fpage>11</fpage>
          . doi:
          <volume>10</volume>
          .4230/OASIcs.EVCS.
          <year>2023</year>
          .
          <volume>29</volume>
          .
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          [3]
          <string-name>
            <given-names>A. S.</given-names>
            <surname>Herrera</surname>
          </string-name>
          ,
          <string-name>
            <given-names>E. D.</given-names>
            <surname>Willink</surname>
          </string-name>
          ,
          <string-name>
            <given-names>R. F.</given-names>
            <surname>Paige</surname>
          </string-name>
          ,
          <article-title>A domain specific transformation language to bridge concrete and abstract syntax</article-title>
          ,
          <source>in: ICMT</source>
          <year>2016</year>
          , volume
          <volume>9765</volume>
          <source>of LNCS</source>
          , Springer,
          <year>2016</year>
          , pp.
          <fpage>3</fpage>
          -
          <lpage>18</lpage>
          . doi:
          <volume>10</volume>
          .1007/978-3-
          <fpage>319</fpage>
          -42064-
          <issue>6</issue>
          _
          <fpage>1</fpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          [4]
          <string-name>
            <given-names>M. P. A.</given-names>
            <surname>Sellink</surname>
          </string-name>
          ,
          <string-name>
            <given-names>C.</given-names>
            <surname>Verhoef</surname>
          </string-name>
          ,
          <article-title>Native patterns</article-title>
          ,
          <source>in: 5th Working Conference on Reverse Engineering</source>
          , WCRE '98, IEEE Computer Society,
          <year>1998</year>
          , pp.
          <fpage>89</fpage>
          -
          <lpage>103</lpage>
          . doi:
          <volume>10</volume>
          .1109/WCRE.
          <year>1998</year>
          .
          <volume>723179</volume>
          .
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          [5]
          <string-name>
            <given-names>J. R.</given-names>
            <surname>Cordy</surname>
          </string-name>
          ,
          <article-title>The TXL source transformation language</article-title>
          ,
          <source>Sci. Comput</source>
          . Program.
          <volume>61</volume>
          (
          <year>2006</year>
          )
          <fpage>190</fpage>
          -
          <lpage>210</lpage>
          . doi:
          <volume>10</volume>
          .1016/j.scico.
          <year>2006</year>
          .
          <volume>04</volume>
          .002.
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          [6]
          <string-name>
            <given-names>R.</given-names>
            <surname>Aarssen</surname>
          </string-name>
          ,
          <string-name>
            <given-names>J. J.</given-names>
            <surname>Vinju</surname>
          </string-name>
          , T. van der Storm,
          <article-title>Concrete syntax with black box parsers</article-title>
          ,
          <source>Programming Journal</source>
          <volume>3</volume>
          (
          <year>2019</year>
          )
          <fpage>15</fpage>
          -
          <lpage>es</lpage>
          . doi:
          <volume>10</volume>
          .22152/programming-journal.org/
          <year>2019</year>
          /3/15.
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          [7]
          <string-name>
            <given-names>A. J.</given-names>
            <surname>Mooij</surname>
          </string-name>
          ,
          <string-name>
            <surname>M. M. Joy</surname>
            , G. Eggen,
            <given-names>P.</given-names>
          </string-name>
          <string-name>
            <surname>Janson</surname>
            ,
            <given-names>A.</given-names>
          </string-name>
          <string-name>
            <surname>Radulescu</surname>
          </string-name>
          ,
          <article-title>Industrial software rejuvenation using open-source parsers</article-title>
          ,
          <source>in: ICMT</source>
          <year>2016</year>
          , volume
          <volume>9765</volume>
          <source>of LNCS</source>
          , Springer,
          <year>2016</year>
          , pp.
          <fpage>157</fpage>
          -
          <lpage>172</lpage>
          . doi:
          <volume>10</volume>
          .1007/978-3-
          <fpage>319</fpage>
          -42064-6_
          <fpage>11</fpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          [8]
          <string-name>
            <given-names>S.</given-names>
            <surname>Klusener</surname>
          </string-name>
          ,
          <string-name>
            <given-names>A. J.</given-names>
            <surname>Mooij</surname>
          </string-name>
          ,
          <string-name>
            <given-names>J.</given-names>
            <surname>Ketema</surname>
          </string-name>
          ,
          <string-name>
            <surname>H. van Wezep</surname>
          </string-name>
          ,
          <article-title>Reducing code duplication by identifying fresh domain abstractions</article-title>
          ,
          <source>in: ICSME</source>
          <year>2018</year>
          , IEEE Computer Society,
          <year>2018</year>
          , pp.
          <fpage>569</fpage>
          -
          <lpage>578</lpage>
          . doi:
          <volume>10</volume>
          .1109/ ICSME.
          <year>2018</year>
          .
          <volume>00020</volume>
          .
        </mixed-citation>
      </ref>
      <ref id="ref9">
        <mixed-citation>
          [9]
          <string-name>
            <surname>P. van de Laar</surname>
          </string-name>
          , A. Mooij, Renaissance-Ada:
          <article-title>Tools for analysis and transformation of Ada code</article-title>
          ,
          <source>Ada User Journal</source>
          <volume>43</volume>
          (
          <year>2022</year>
          )
          <fpage>165</fpage>
          -
          <lpage>170</lpage>
          . https://www.ada-europe.org/archive/auj/auj-43-3
          <article-title>-withcovers</article-title>
          .pdf.
        </mixed-citation>
      </ref>
      <ref id="ref10">
        <mixed-citation>
          [10]
          <string-name>
            <surname>P. van de</surname>
            <given-names>Laar</given-names>
          </string-name>
          ,
          <string-name>
            <given-names>R.</given-names>
            <surname>Corvino</surname>
          </string-name>
          ,
          <string-name>
            <given-names>A. J.</given-names>
            <surname>Mooij</surname>
          </string-name>
          ,
          <string-name>
            <surname>H. van Wezep</surname>
          </string-name>
          ,
          <string-name>
            <given-names>R.</given-names>
            <surname>Rosmalen</surname>
          </string-name>
          ,
          <article-title>Custom static analysis to enhance insight into the usage of in-house libraries</article-title>
          ,
          <source>J. Syst. Softw</source>
          .
          <volume>212</volume>
          (
          <year>2024</year>
          )
          <article-title>112028</article-title>
          . doi:
          <volume>10</volume>
          . 1016/J.JSS.
          <year>2024</year>
          .
          <volume>112028</volume>
          .
        </mixed-citation>
      </ref>
      <ref id="ref11">
        <mixed-citation>
          [11]
          <string-name>
            <surname>Eclipse</surname>
            <given-names>Foundation</given-names>
          </string-name>
          , Eclipse C/C++ Development Tools (CDT), https://github.com/eclipse-cdt,
          <year>2024</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref12">
        <mixed-citation>
          [12]
          <string-name>
            <surname>AdaCore</surname>
          </string-name>
          , Libadalang, https://www.adacore.com/libadalang,
          <year>2024</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref13">
        <mixed-citation>
          [13]
          <string-name>
            <given-names>E.</given-names>
            <surname>Willink</surname>
          </string-name>
          ,
          <article-title>Meta-Compilation for C++</article-title>
          ,
          <string-name>
            <surname>Ph</surname>
          </string-name>
          .D. thesis, University of Surrey,
          <year>2001</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref14">
        <mixed-citation>
          [14]
          <string-name>
            <given-names>D.</given-names>
            <surname>Piatov</surname>
          </string-name>
          ,
          <string-name>
            <given-names>A.</given-names>
            <surname>Janes</surname>
          </string-name>
          ,
          <string-name>
            <given-names>A.</given-names>
            <surname>Sillitti</surname>
          </string-name>
          ,
          <string-name>
            <surname>G.</surname>
          </string-name>
          <article-title>Succi, Using the Eclipse C/C++ development tooling as a robust, fully functional, actively maintained</article-title>
          , open source C+
          <article-title>+ parser</article-title>
          ,
          <source>in: OSS</source>
          <year>2012</year>
          , volume
          <volume>378</volume>
          <source>of AICT</source>
          , Springer,
          <year>2012</year>
          , p.
          <fpage>399</fpage>
          . doi:
          <volume>10</volume>
          .1007/978-3-
          <fpage>642</fpage>
          -33442-9_
          <fpage>45</fpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref15">
        <mixed-citation>
          [15]
          <string-name>
            <given-names>N.</given-names>
            <surname>Ridge</surname>
          </string-name>
          , C++ language support in
          <source>Eclipse CDT</source>
          ,
          <year>2017</year>
          . https://www.eclipse.org/community/eclipse_ newsletter/2017/april/article3.php.
        </mixed-citation>
      </ref>
      <ref id="ref16">
        <mixed-citation>
          [16]
          <string-name>
            <surname>R. van Tonder</surname>
          </string-name>
          ,
          <string-name>
            <surname>C. Le Goues</surname>
          </string-name>
          ,
          <article-title>Lightweight multi-language syntax transformation with parser parser combinators</article-title>
          ,
          <source>in: PLDI</source>
          <year>2019</year>
          , ACM,
          <year>2019</year>
          , pp.
          <fpage>363</fpage>
          -
          <lpage>378</lpage>
          . doi:
          <volume>10</volume>
          .1145/3314221.3314589.
        </mixed-citation>
      </ref>
      <ref id="ref17">
        <mixed-citation>
          [17]
          <string-name>
            <given-names>R. D.</given-names>
            <surname>Cameron</surname>
          </string-name>
          ,
          <string-name>
            <given-names>M. R.</given-names>
            <surname>Ito</surname>
          </string-name>
          ,
          <article-title>Grammar-based definition of metaprogramming systems</article-title>
          ,
          <source>ACM Trans. Program. Lang. Syst</source>
          .
          <volume>6</volume>
          (
          <year>1984</year>
          )
          <fpage>20</fpage>
          -
          <lpage>54</lpage>
          . doi:
          <volume>10</volume>
          .1145/357233.357235.
        </mixed-citation>
      </ref>
      <ref id="ref18">
        <mixed-citation>
          [18]
          <string-name>
            <given-names>J.</given-names>
            <surname>Miranda</surname>
          </string-name>
          , E. Schonberg,
          <source>GNAT: The GNU Ada Compiler</source>
          ,
          <year>2004</year>
          . https://www.adacore.com/uploads/ books/pdf/gnat-book.pdf.
        </mixed-citation>
      </ref>
      <ref id="ref19">
        <mixed-citation>
          [19]
          <string-name>
            <given-names>M.</given-names>
            <surname>Bravenboer</surname>
          </string-name>
          ,
          <string-name>
            <given-names>R.</given-names>
            <surname>Vermaas</surname>
          </string-name>
          ,
          <string-name>
            <given-names>J. J.</given-names>
            <surname>Vinju</surname>
          </string-name>
          , E. Visser,
          <article-title>Generalized type-based disambiguation of meta programs with concrete object syntax</article-title>
          ,
          <source>in: GPCE</source>
          <year>2005</year>
          , volume
          <volume>3676</volume>
          <source>of LNCS</source>
          , Springer,
          <year>2005</year>
          , pp.
          <fpage>157</fpage>
          -
          <lpage>172</lpage>
          . doi:
          <volume>10</volume>
          .1007/11561347_
          <fpage>12</fpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref20">
        <mixed-citation>
          [20]
          <string-name>
            <given-names>B.</given-names>
            <surname>Basten</surname>
          </string-name>
          , J. van den Bos, M. Hills,
          <string-name>
            <given-names>P.</given-names>
            <surname>Klint</surname>
          </string-name>
          ,
          <string-name>
            <given-names>A.</given-names>
            <surname>Lankamp</surname>
          </string-name>
          ,
          <string-name>
            <given-names>B.</given-names>
            <surname>Lisser</surname>
          </string-name>
          , A. van der Ploeg, T. van der Storm,
          <string-name>
            <given-names>J. J.</given-names>
            <surname>Vinju</surname>
          </string-name>
          ,
          <source>Modular language implementation in Rascal - experience report, Sci. Comput</source>
          . Program.
          <volume>114</volume>
          (
          <year>2015</year>
          )
          <fpage>7</fpage>
          -
          <lpage>19</lpage>
          . doi:
          <volume>10</volume>
          .1016/j.scico.
          <year>2015</year>
          .
          <volume>11</volume>
          .003.
        </mixed-citation>
      </ref>
      <ref id="ref21">
        <mixed-citation>
          [21]
          <string-name>
            <given-names>I. D.</given-names>
            <surname>Baxter</surname>
          </string-name>
          ,
          <string-name>
            <given-names>C. W.</given-names>
            <surname>Pidgeon</surname>
          </string-name>
          ,
          <string-name>
            <given-names>M.</given-names>
            <surname>Mehlich</surname>
          </string-name>
          , DMS®:
          <article-title>Program transformations for practical scalable software evolution</article-title>
          ,
          <source>in: ICSE</source>
          <year>2004</year>
          , IEEE Computer Society,
          <year>2004</year>
          , pp.
          <fpage>625</fpage>
          -
          <lpage>634</lpage>
          . doi:
          <volume>10</volume>
          .1109/ICSE.
          <year>2004</year>
          .
          <volume>1317484</volume>
          .
        </mixed-citation>
      </ref>
      <ref id="ref22">
        <mixed-citation>
          [22]
          <string-name>
            <given-names>Y.</given-names>
            <surname>Padioleau</surname>
          </string-name>
          ,
          <string-name>
            <given-names>R. R.</given-names>
            <surname>Hansen</surname>
          </string-name>
          ,
          <string-name>
            <given-names>J. L.</given-names>
            <surname>Lawall</surname>
          </string-name>
          , G. Muller,
          <article-title>Semantic patches for documenting and automating collateral evolutions in Linux device drivers</article-title>
          ,
          <source>in: PLOS</source>
          <year>2006</year>
          , ACM,
          <year>2006</year>
          , p.
          <fpage>10</fpage>
          -
          <lpage>es</lpage>
          . doi:
          <volume>10</volume>
          .1145/1215995.1216005.
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>