• No results found

On the Impact of ‘Fork and Modify’ Customizations on Source Code Metrics in X++

N/A
N/A
Protected

Academic year: 2021

Share "On the Impact of ‘Fork and Modify’ Customizations on Source Code Metrics in X++"

Copied!
84
0
0

Bezig met laden.... (Bekijk nu de volledige tekst)

Hele tekst

(1)

On the Impact of ‘Fork and Modify’

Customizations on Source Code Metrics

in X++

Thesis

in partial fulfilment of the requirements for the degree of

Master of Science in Software Engineering

at the University of Amsterdam

to be defended publicly

in room L120 at the Centrum Wiskunde & Informatica

on October 14, 2016 at 10:15

by Olav Christiaan Trauschke,

approved on October 12, 2016

by supervisor dr. T. van der Storm,

tutored by dr. M.R.H. Kooistra

from the host organization Avanade Netherlands B.v.

Publication status: Published

Graduation committee:

(2)

On the Impact of ‘Fork and Modify’ Customizations on Source Code Metrics in X++

ii

Table of Contents

Abstract ... 1

Preface ... 2

Chapter 1 Introduction ... 3

Chapter 2 Background ... 4

Chapter 3 Problem analysis ... 5

Chapter 4 Experiment setup... 7

4.1 Global setup... 7

4.2 Pre-processing ... 7

4.3 Parsing X++ code ... 9

4.4 Metrics ... 10

Chapter 5 Results... 14

Chapter 6 Analysis ... 15

Chapter 7 Discussion ... 18

Chapter 8 Conclusion ... 18

Bibliography ... 19

Appendix A: SIG Maintainability Model ... 21

Appendix B: xpo-files ... 23

Appendix C: X++ grammar ... 25

Appendix D: eXPODigger ... 41

(3)

Abstract

Different metrics have been developed to measure source code quality. Software vendors who want

to improve the quality of their products are interested in the impact of changes on the quality of

software. Companies customizing software that allows customizations in different ways are

interested in differences between these ways with respect to the quality of their software.

The impact of customizations by overlayering on source code quality are researched here, by

measurements of volume, complexity, coupling, duplication, unit size, depth in tree and number of

children. Overlayering can be thought of as customization by ‘forking and modifying’. The

aforementioned measurements are performed on customized code of the enterprise resource

planning system Microsoft Dynamics AX. Here we show why we were unable to base a valid

conclusion on the described research. We also show that we developed a Rascal parser and analysis

tools for X++ code that may be of use to future research.

(4)

On the Impact of ‘Fork and Modify’ Customizations on Source Code Metrics in X++

2

Preface

After receiving a bachelor’s degree in medical information sciences and completing the six other

courses of the Master of Science in Software Engineering at the University of Amsterdam, the time

had come for me to show what I have learned in my Masterproject. I started researching the

relevance of different sub-characteristics of maintainability for the implementation of a fail-safety

mechanism in an enterprise resource planning (ERP) system to be used in operating rooms. My

supervisor, however, discouraged me to apply the method I had found for this project and finally I

even found an error in a key publication about this method that was confirmed to be an error by one

of the authors. Therefore, I was forced to adapt this research plan.

After the aforementioned change of plans, the result of my Masterproject and therefore the result of

many years of education, is the text you are currently reading: my master’s thesis On the Impact of

‘Fork and Modify’ Customizations on Source Code Metrics in X++. The Masterproject that resulted in

this thesis, provided a way for me to not only show what I have learned, but to start doing what I

have wanted to for the past years: working with software to improve healthcare. I sincerely hope the

results described in this thesis will be of use for the development of AX4Health and possibly even

other (healthcare-related or not) implementations of large systems that require customization with

code.

Before continuing this thesis with what it is all about, I would like to take this opportunity to thank

everyone who helped me to complete this thesis. Trying to list everyone who helped me to even get

to the moment I was allowed to start working on my Masterproject, would take far too long and I

would certainly forget to mention people if I would try to do that. Therefore, without being any less

grateful for their help, I will not try to list all these people here and will instead focus on the people

who helped me complete this project from the moment I started working on it.

First of all, I would like to thank the wonderful people at Avanade Netherlands, for providing me with

an idea for my Masterproject and their help when I had to change this plan, for a great environment

to work in and for many good advices when I needed them. Specifically, I would like to thank Gertjan

van der Linden for allowing me to do my Masterproject at Avanade Netherlands, for keeping track of

my progress and providing me with great advice whenever I needed it, whether I asked for it or not.

Furthermore, I would like to thank Nicole Holla for ensuring I kept track of the progress of my project

and for providing me with useful trainings and feedback. The last, but certainly not the least person

from Avanade I would like to thank specifically, is my tutor Matthijs Kooistra. Matthijs has been the

first person to read many versions of different deliverables of my project and always invested his

time to provide me with feedback.

Besides Avanade employees, I would like to thank Tijs van der Storm, my supervisor from the

University of Amsterdam. Tijs was the person who received drafts for parts of this thesis and other

deliverables for review after feedback I had processed any feedback from Matthijs. Despite knowing I

would not always immediately express gratitude for his efforts when they made me realize I should

have done something completely differently, Tijs remained critical and helped me understand his

feedback when I was too focused on my own opinion to understand what he meant immediately.

Finally, I would like to thank my parents. They supported me mentally, provided me with a place to

rest, enjoy a rare day off or work out of office hours. Now, without further ado, on with what you are

probably reading this for: a thesis On the Impact of ‘Fork and Modify’ Customizations on Source Code

Metrics in X++.

(5)

Chapter 1 Introduction

Source code quality

Source code quality has different characteristics: functional suitability, performance efficiency,

compatibility, usability, reliability, security, maintainability and portability. [2]. Different metrics have

been developed to measure these characteristics [3-5, 9, 11, 16, 20, 35, 36, 38]. In the research

described in this thesis, the metrics number of lines of code, cyclomatic complexity, coupling

between objects, depth in tree, number of children, duplicated blocks over six lines and unit size are

applied to measure the impact of overlayering on the quality of the software. These metrics are

selected because they can be measured by static code analysis and are considered important to the

domain the research described here was executed in, as described in Chapter 2.

Cyclomatic complexity is a metric for the number of ways a program can be executed in depending

on the circumstances (input in any possible way). As the other metrics, this metric is described in

more detail in Chapter 4. Coupling between objects measures the number of other objects an object

depends on. Depth in tree is the number of objects above an object in an inheritance tree, which is a

tree in which any object is a child of other objects it extends. Number of children is the number of

children an object has in the inheritance tree. Duplicated blocks of six lines are blocks of six lines of

code appearing more than once within the analyzed domain. Unit size, finally, is the volume of a unit

within the analyzed domain. Metrics that are measured per object or per unit are aggregated to

obtain a result for the whole domain of an analysis.

Customization

Overlayering is a specific way of making changes to software. When overlayering a “developer must

create a new model that overlays the model they want to customize” in “order to customize

metadata and source code of a model” [18]. In this context, a model is a collection of elements (such

as classes, macros and tables) that are compiled into one assembly [17]. Overlayering can be thought

of as customization by ‘forking and modifying’. When overlayering, programmers make changes just

like they are changing the original code, while in fact only the changes they make are stored. This

allows programmers to customize a basic system in different ways for usage in different settings.

The difference between overlayering and another way of making changes to software called

extension, is that when a programmer changes software by extension, he does not make changes to

the original source code, but writes his own source code that is somehow integrated in the

execution, e.g. by means of some event-driven mechanism in which the original system throws

events, which can be caught from other code to execute a modification [18].

Methods and conclusion

In this research the X++ code of the classes in Microsoft Dynamics AX as it is produced by Microsoft

(the default version) and in the customized version of this product called AX4Health is exported,

pre-processed and parsed and the aforementioned metrics of this software are measured. AX4Health is a

product built on Microsoft Dynamics AX to serve as an enterprise resource planning (ERP) system for

hospitals. AX4Health was created by overlayering the source code of Microsoft Dynamics AX, which is

written in Microsoft’s domain specific language X++ [24]. The pre-processing, parsing and measuring

steps are performed by tools created during this research. We find that the validity of the research

here is threatened and therefore no conclusion can be based on the results.

(6)

On the Impact of ‘Fork and Modify’ Customizations on Source Code Metrics in X++

4

Chapter 2 Background

ERP “allows companies to integrate various departmental information. (…) The essence of it is the

fundamental premise that the whole is greater than the sum of its parts. (…) Supply-chain capabilities

of ERP increase efficiency and productivity of their users” ([8], pp. 114-115) Jenkins and Christenson

reported that due “to significant differences between manufacturing and patient care, ERP-based

systems do not easily translate to the healthcare setting” ([10], p. 48).

They also noted that – despite this disadvantage – vendors – such as Avanade – developed ERP

systems “that offer administrative and logical solutions for large healthcare systems” and concluded

that “an ERP-based system can help a healthcare organization integrate many functions, including

patient scheduling, human resources management, workload forecasting, and management of

workflow, that are not directly dependent on clinical decision making” ([10], p. 48).

Given the difficult position of systems such as AX4Health, the manufacturer of this system – Avanade

– is interested in the quality of this software, to improve sales and client satisfaction. This topic is

specifically interesting to Avanade at this time, because Microsoft recently allowed extension as “a

new way of customizing an application by using extensions” in Dynamics AX, as opposed

(7)

Chapter 3 Problem analysis

Product quality

The product quality model of ISO standard 25010 distinguishes eight characteristics of systems that

influence their quality, which are further divided into sub-characteristics as shown in Table 1 below

[2]. This table shows which characteristics the product quality model of ISO standard 25010

distinguishes and how they are divided into 31 unique sub-characteristics. E.g. functional suitability is

divided into functional completeness, functional correctness and functional appropriateness.

Table 1 Characteristics and sub-characteristics in the product quality model in ISO standard 25010 ([2], p. 10)

Characteristic

Sub-characteristics

Functional

suitability

Functional completeness

Functional correctness

Functional appropriateness

Performance

efficiency

Time behavior

Resource utilization

Capacity

Compatibility

Co-existence

Interoperability

Usability

Appropriateness recognizability

Learnability

Operability

User error protection

User interface aesthetics

Accessibility

Reliability

Maturity

Availability

Fault tolerance

Recoverability

Security

Confidentiality

Integrity

Non-repudiation

Accountability

Authenticity

Maintainability Modularity

Reusability

Analyzability

Modifiability

Testability

Portability

Adaptability

Installability

Replaceability

The research described in this thesis, focuses on characteristics from Table 1

-

that are expected to be differ between functionality implemented using overlayering and the

same functionality implemented using an extension;

-

that are considered important for ERP systems;

(8)

On the Impact of ‘Fork and Modify’ Customizations on Source Code Metrics in X++

6

For the aforementioned reasons, the research described here does not focus on functional suitability

(how much as system provides needed functions), compatibility (how much as system or component

can share information and hard- and software environments), usability (how much a system can be

used effectively, efficiently and satisfying), security (how much a system protects information and

data so that others have the degree of access appropriate for them) or portability (how effectively

and efficiently a system or component can be brought to another environment) [2].

No complete model is found to measure the reliability of software (“degree to which a system,

product or component performs specified functions under specified conditions for a specified period

of time” [2]), but separate metrics for reliability that meet the above criteria and are used in the

research described here are number of lines of code, cyclomatic complexity [11], coupling between

objects, depth in tree and number of children [35]. For measuring maintainability (how effectively

and efficiently a system can be modified by its maintainers [2]), metrics used in the SIG

Maintainability Model are applied. This model contains the following metrics that were not

mentioned before and met the criteria described above: duplicated “blocks over six lines” and unit

size [9, 38].

Aim

The research described in this thesis, aims to gather insight in what characteristics of source code

quality suffer from customizations implemented by ‘forking and modifying’ (stronger than or even

opposed to other characteristics). This insight is expected to raise awareness of the impact of this

technique among programmers applying it and this is expected to help them take appropriate

countermeasures (such as refactoring and application of evolutionary algorithms [19]) before the

effects of the customizations they make become a serious problem for the quality of the software.

More concretely, the research described in this thesis aims to answer the following question: How

does customizing a system by overlayering affect the quality of the system’s source code with respect

to reliability and maintainability?

Hypotheses

Since customizations can specify things more, they are expected to increase the number of lines of

code. Because customizations by ‘forking and modifying’ are changes to existing code, they are not

expected to influence the class hierarchy in a system significantly, as programmers who make

changes to an existing system are not expected to change more than they directly need to reach

their goal in most cases. Customizations by ‘forking and modifying’ are therefore not expected to

make a relevant difference with respect to the coupling between classes and the depth in tree and

number of children of classes.

Customizations by ‘forking and modifying’ are expected to increase duplication, because different

parts of a system can be modified separately in similar ways. Furthermore, customizations by ‘forking

and modifying’ are expected to increase the complexity of source code, because they involve

changes to existing code. For the same reason, these customizations are expected to increase the

unit size in the source code.

Characteristics

The default version of the analyzed ERP system Microsoft Dynamics AX contains 16,218 classes.

AH4Health, the implementation of Microsoft Dynamics AX customized for hospitals, is bigger and

contains 16,600 classes.

(9)

Chapter 4 Experiment setup

4.1 Global setup

As described in Chapter 3 our experiment focuses on metrics of the version of the code of Microsoft

Dynamics AX as it is delivered and the version used in AX4Health that are found to be used for

measuring maintainability and reliability. How these metrics are applied and why they are

implemented the way they are, is described in detail in Section 4.4.

Notably, the volume is measured as the number of statements instead of the number of lines of code

as this is expected to be the easiest to measure out of twelve volume metrics that were previously

found to be internally consistent. The unit size is interpreted as the volume of a method and in this

metric statements are again used as unit of volume. Because the metric used for measuring

duplication (duplicated blocks over six lines) is a based on a number of lines, actual lines (and not

statements) were used as unit of volume in the calculation of this metric. Table 2 below summarizes

the metrics obtained from the literature and the corresponding metric measured in the research

described here. Reasons for differences the differences are given in Section 4.4.

Table 2 Metrics obtained from literature and corresponding metrics measured in the research described here

Metric from literature

Measured metric

Number of lines of code

Statement count

Cyclomatic complexity

Cyclomatic complexity

Coupling between objects

Coupling between objects (classes in this context)

Depth in tree

Depth in tree

Number of children

Number of children

Duplicated blocks over six lines

Percentage “of all code that occurs more than once

in equal blocks of at least six lines” [9]

Unit size

Statement count per unit (methods in this context)

The files exported from Microsoft Dynamics AX (and AX4Health) to represent classes cannot be

parsed immediately, because they do not contain just X++ code. Therefore, we developed

eXPODigger, a tool to process the exported files to get input for our X++ parser. This

pre-processing is described in section 4.2 Pre-pre-processing. The parsing itself is described in section 4.3

Parsing X++ code. Finally, section 4.4 Metrics describes how another tool we developed – eXPyMeter

is used to measure the quality of the source code of classes in the default Microsoft Dynamics AX and

in AX4Health.

4.2 Pre-processing

Need for pre-processing

No way is found to export source code from Microsoft Dynamics AX 2012 other than as xpo-files,

including not just the code, but also metadata about the class and not including all code as an

uninterrupted text. The structure of xpo-files is described in more detail in Appendix B: xpo-files. In

addition, no way is found to export the customized versions of classes, but only a way to export the

original classes and the customizations in separate files.

Exporting customizations using the built in export functionality of Microsoft Dynamics AX resulted in

xpo-files containing only methods that were changed as part of the customization and the

declaration of the class itself was also included in these files only if it was changed. When

(10)

On the Impact of ‘Fork and Modify’ Customizations on Source Code Metrics in X++

8

and classes that were added as part of the customizations are exported in the same way the

unmodified versions of classes were exported.

Pre-processing tool: eXPODigger

eXPODigger is a tool that we developed to reconstruct source code based on xpo-files. The source

code of eXPODigger is presented in Appendix D: eXPODigger. In its simplest mode, eXPODigger

creates one X++ source code file (xpp-file) per xpo-file it is presented. When eXPODigger is presented

a folder with customizations and a folder with the uncustomized version of the same code, it does

not just create one xpp-file for each xpo-file it processes. Instead, in case eXPODigger finds a

representation of (customizations to) a class in both folders, it integrates the code it extracts from

the file representing the customization into the file representing the uncustomized version of the

class.

For this integration, eXPODigger first collects the methods and – if present – the class declaration

from the file with customizations. It then adds any methods from the uncustomized version of the

class that were not found before, as well as the class declaration if it was not found in the file with

customizations. eXPODigger compares methods in the same way as Microsoft Dynamics AX 2012

differentiates between overloading and overriding: by method signature (name, return type and

parameter types). [22] eXPODigger recognizes the elements of a method’s signature by their

positions at the start of the declaration of the method, ignoring any comments and calls to macros

that may precede them.

Standardization of marks signaling the start of blocks of never executed code in eXPODigger

Before writing the reconstructed code to a results file, eXPODigger performs one last operation: it

standardized marks that signal the start of blocks of code that are never executed (and can thus be

dealt with in the same way as is dealt with comments). These marks consist of the string “#if.never”,

but allow arbitrary numbers of whitespace characters between words and are not case sensitive, so

e.g. “#if . NeVer” is also valid. This standardization was performed, because no way is found to deal

with the possible whitespace characters in these marks during parsing.

Example of the use of eXPODigger

The following example demonstrates the use of eXPODigger. eXPODigger is presented a folder “AX”

with two files: A.xpo and B.xpo called A and B respectively. It is also presented a folder “AX4Health”

with another two files, one of which is also called B.xpo and the other C.xpo. A.xpo and C.xpo are

both unique in one of the folders. Therefore, the files representing them both have to contain the

complete code of the classes they contain. This code is extracted from these files and written to files

A.xpp and C.xpp in an automatically created results folder.

Both folders contain a file representing a class B. eXPODigger is told that the folder “AX” contains the

original source code, while the folder “AX4Health” contains customizations. It therefore first collects

the methods and the class definition it finds in B.xpo in “AX4Health”. It then adds any methods to

this collection that it finds in B.xpo in “AX” that have signatures that differ from the methods found

in B.xpo in “AX4Health”. This does not include the class definition, because that was already found in

B.xpo in “AX4Health”. Finally, the whole collection of methods and the class definition is written to a

file B.xpp in the results folder.

(11)

4.3 Parsing X++ code

Applied tooling: Rascal syntax definition and parser generation

The Rascal Metaprogramming Language (Rascal) integrates source code analysis, transformation and

generation primitives “on the language level” [6]. Rascal is used for the measurements of software

metrics, because this was specifically developed for metaprogramming. Syntax “definitions make it

possible to define new and existing languages and to write tools for them” in this language ([13], p.

5). Furthermore, Rascal offers the functionality needed for source code analysis and transformation

combined in one language. Also, it facilitates encapsulation and reuse [14].

The syntax definition that is created as described below and is used for the analyses that are part of

the research described here, is given in Listing 2 in Appendix C: X++ grammar. Readers may want to

consult this listing while reading the rest of this section for a better understanding of how concepts

were defined in the created Rascal syntax definition for X++ code. X++ is an object-oriented

programming language comparable to C#. A difference in the syntax of X++ as compared to C# is that

X++ contains keywords like SQL statements (such as “select”), which can be used for accessing

relational databases directly from X++ code, without having to call a separate database query written

in SQL [24].

Defining the syntax of X++ code

To parse X++ code with Rascal to perform analyses, a grammar of X++ code has to be defined in a

Rascal syntax definition [15]. A grammar describes how constructs of a language (such as words in

English) can be used to construct other language constructs (such as English sentences). To create

this syntax definition, the X++ grammar used by the X++ compiler (found at [7]) is first translated to a

Rascal syntax definition.

An important step in this translation is the definition of terminals (structures of a language that

cannot be split into smaller structures further, such as letters in English), which are not included in

[7]. This includes the definition of identifiers and accompanying reservation of keywords. Keyword

reservation has to be defined separately for different kinds of identifiers, because keywords that

have to be restricted in one place to avoid ambiguity, are found to be valid identifiers in another

place. The definitions of identifiers are redefined iteratively until all files that were analyzed in the

research described in this thesis can be parsed without errors or ambiguities.

Keywords in X++

X++ threats keywords in a case insensitive way. Rascal developer Jurgen Vinju explained case

insensitive disambiguations are not implemented in Rascal (yet). Keywords are therefore defined in

lowercase, uppercase and camel case manually in this syntax definition and other alternative

notations are added when they are found in the analyzed files.

Empty non-terminals

Furthermore, empty non-terminals (structures of a language that can be split into smaller structures,

such as words in English which can be split into letters), which – as X++ developer Peter Villadsen told

the author – are used to communicate status information between the lexer and the parser in the

original X++ compiler, are removed, because they would not be of use to an automatically generated

lexer and parser as is created with Rascal for the research described here. By consequence, no way is

found to distinguish between two concepts the original X++ compiler distinguishes in the syntax

definition used for the research described here: functions and intrinsic functions (see [26] for more

information about intrinsic functions in X++).

(12)

On the Impact of ‘Fork and Modify’ Customizations on Source Code Metrics in X++

10

Literals

Formats for literals of different types are also added to the syntax definition, because these were not

defined in [7]. No distinction is made between integers of different lengths. These definitions are

again refined iteratively until all files analyzed for the research described here can be parsed

unambiguously.

Layout

Besides whitespace characters, single- and multi-line comments blocks of never executed code are

included in the definition of layout in the syntax definition used for the research described here, to

stop the parser generated from this definition from attempting to parse them as code. Blocks of

never executed code are if-directives – which stop compilation if and only if a specified macro is

undefined – with the name “never”, that is by convention never used to define a macro. The

non-breaking space character is also included in the definition of layout, because it is present in some of

the export files with code that are analyzed at unpredictable places and for no apparent reason.

Macros

Finally, macros have to be included in the syntax definition, because these are not considered in the

grammar provided in [7], because this is the grammar used by the X++ compiler, while macros are

normally handled “before the text reaches the compiler” [7, 37]. Macros in X++ are constant strings

of characters that can be referred to by identifiers preceded by a hashtag [29]. Macros cannot be

replaced by the code they represent like is done by the pre-processor, because extraction of code for

macros from xpo-files was not included in the research described here, due to time constraints.

Constructs related to macros are allowed to occur wherever they are found in the code that is

analyzed for the research described here, if and only if this is found to be possible without

introducing ambiguities (which happens if the macro calls replace too many keywords or other

structuring elements). Files with calls to macros that cannot be parsed without introducing

ambiguities, are excluded from the analyses. This resulted in 16,174 out of 16,218 classes of

uncustomized code and 16,554 out of 16,600 classes of customized code being parsed successfully

and being included in the metrics.

4.4 Metrics

The number of lines of code, cyclomatic complexity, coupling between objects, depth in tree, number

of children, duplicated “blocks over six lines” and unit size of the original source code of Microsoft

Dynamics AX and a version that was modified for usage in AX4Health applying overlayering are

measured. Due to time constraints and the way code objects can be exported from Microsoft

Dynamics AX 2012, the research described here focusses on classes and does not include other

constructs such as macros, enumerations, extended data types or tables. Unless stated otherwise,

these metrics are calculated by iterating over the parse trees resulting from the parsing described in

the previous section. This is done by another tool we developed for the research described here (in

Rascal): eXPyMeter. The source code of eXPyMeter is presented in Appendix E: eXPyMeter.

Volume

Li and Cheung found twelve internally consistent volume metrics: statement count, line count

excluding comments, unique operand count, operator count, operand count and seven metrics

calculated from the (unique) operand and operator counts [16]. Of these metrics, statement count is

expected to be the easiest to calculate based on parse trees and is therefore used to measure the

volume of the analyzed software, because eXPyMeter measures the statement count by counting

statements while visiting the parse tree resulting from parsing the analyzed code. This metric is

(13)

expected to be the easiest to calculate based on a parse tree because it does not require handling of

metadata resulting from the parsing such as the source code location of an element from the parse

tree and less different kinds of statements are expected to exist than kinds of operators or operands.

Cyclomatic complexity

The cyclomatic complexity is measured per unit – i.e. per method – and based on these results, the

relative volume of code with any complexity is calculated, as was done by Heitlager, Kuipers and

Visser [9]. Unlike they did, complexities are not aggregated in the research described here, to allow

for more fine-grained comparisons. Also, Heitlager, Kuipers and Visser used lines of code as metric of

the (relative) volume and – as stated above – the number of statements is used in the research

described here instead.

Each metric that does not measure a system as a whole but measures smaller units of code, is

calculated in a similar way [9]. The relative volume with any complexity is calculated by visiting each

method body in the parse tree and counting the statements in it and measuring the complexity of it.

It is important to note only (both volume and complexity of) contents of method bodies are thus

considered in this metric.

McCabe defined cyclomatic complexity as 𝑣 = 𝑒 − 𝑛 + 2𝑝, where 𝑒 is the number of arcs, 𝑛 is the

number of nodes and 𝑝 is the number of connected components in the program’s control flow graph.

McCabe also showed this can be simplified as the number of conditions plus one [20].

Based on the above, the cyclomatic complexity of the body of a method in X++ is defined as:

-

the sum of the number of conditions in the predicates determining the control flow in

while-statements, for-while-statements, do while-statements and (inline) if-statements;

-

plus the number of search statements, because they are effectively for-each statements

(thus for statements with a single condition) combined with database queries to obtain the

data to iterate over;

-

plus the number of occurrences of the CaseHeader construct, because that equals the

number of cases in switch statements, excluding default cases, which do not create an extra

path in the control flow graph, because they are executed in the same path as any code

following the switch statement they are part of;

-

plus one.

The above definition does not include catch, retry or transaction abort statements, because they only

define what happens along a specific path (when an exception has been thrown, when an exception

should lead to retrying something and when a transaction should be aborted respectively) and the

extra paths they may seem to imply are actually created elsewhere (when an exception is thrown in a

specific case or when a program determines whether or not something should be retried after an

exception has been thrown or a transaction should be aborted). eXPyMeter measures this metric by

counting (conditions in) the aforementioned constructs while visiting the parse tree.

Coupling between objects

Coupling between objects is defined as “a count of the number of other classes to which a class is

coupled. It is measured by counting the number of distinct non-inheritance related class hierarchies

on which a class depends” [5]. eXPyMeter calculates this metric by visiting each class’s body in the

code and counting the total number of statements and the number of unique

-

DeclTypeIds (identifiers for types of declared variables);

-

ClrTypes (qualified identifiers for common language runtime types of declared variables),

without ClrArraySpecs (pairs of brackets used to define an array of a type) [21, 30];

(14)

On the Impact of ‘Fork and Modify’ Customizations on Source Code Metrics in X++

12

-

StdIds after the keywords “as” and “is” in expressions;

-

StdIds in constants, preceding DblColonSyms (a symbol consisting of two colons) that are

used to separate types form elements within them (such as fields)

-

and StdIds and EvalClrTypes in EvalNames (names of things that are evaluated, mainly

method calls) following the keyword “new”

in it.

Depth in tree

Chidamber and Kemerer define the depth in tree of a class as its height in the inheritance tree of the

system it is part of ([4], p. 201). eXPyMeter calculates the depth in tree by filling a map from each

class to the class it extends, based on the extends clause in the class declaration and counting the

number of statements in the body of each class, while visiting the parse tree. Then, it builds an

inheritance tree based on the resulting map, with a single root class at the top and it calculates the

depth in tree for each class using this inheritance tree. Finally, eXPyMeter calculates the relative

volume of code with any depth in tree based on the collected data.

Number of children

Chidamber and Kemerer defined the number of children of a class as its number of immediate

descendants in the inheritance tree of the system it is part of ([4], p. 201). The relative volume of

code with any number of children is calculated for the research described here. To calculate this

metric, eXPyMeter uses the same inheritance tree and relative volume as used to calculate the

relative volume of code with any depth in tree. This time it counts the number of children of each

class in the tree instead of the height in the tree.

Unit size

Heitlager, Kuipers and Visser defined the unit size as the volume of a unit and stated a unit is a

method in Java or C# [9]. As X++ has similarities to C#, a unit is defined as a method for X++ as well.

The unit size is therefore calculated as the number of statements per method. How this metric is

calculated, was described in the description of how the relative volume of code with any complexity

is calculated above. As units of code with a larger unit size have a larger volume by definition, unit

sizes are aggregated differently and the number of methods with any unit size is calculated.

Duplication

The metric used to measure duplication (duplicated “blocks over six lines”), is a line based metric; it

is defined as “the percentage of all code that occurs more than once in equal code blocks of at least 6

lines” [9]. Therefore, lines are used as a unit for volume (instead of statements) to calculate this

metric. To avoid converting back and forth between parsed structure and lines, type-1 duplication is

measured and calculated based on the (unparsed) source code. Type-1 duplication defines clones as

parts of code that are identical “except for variations in whitespace, layout and comments” ([36], p.

472). The relative number of lines of code that is part of a block of at least six lines of duplicated code

is calculated.

eXPyMeter reads all lines from input files, excluding blank lines and comments. It then iterates over

all but the last five lines of each file and stores the block of six consecutive lines – including their

locations in the source files – starting at this line in a duplication class, i.e. a collection of all (already

categorized) occurrences of a specific block of six lines of code. It then iterates over the duplication

classes and creates a set of locations of lines that are part of a duplication class containing more than

one block of code. To calculate the relative number of lines of code that is part of a block, the

(15)

number of lines in the generated set is finally divided by the total number of lines that are processed.

The component of eXPyMeter responsible for this functionality was based on [32].

(16)

On the Impact of ‘Fork and Modify’ Customizations on Source Code Metrics in X++

14

Chapter 5 Results

The analyzed uncustomized code is found to consist of 1,467,725 statements. The analyzed

customized code is found to consist of 1,504,616 statements. In the uncustomized code the relative

number of lines of code that is part of a block of at least six lines of duplicated code, finally, is

28.0991%. In the customized code this is 28.4807%. Table 3 presents the results of the metrics that

are measured for smaller units than complete systems. Because the data were found not to be

distributed normally (see Chapter 6 Analysis), the medians and interquartile ranges (IQLs) are given.

Means are also provided to show the direction of a difference when the medians are equal.

Table 3 shows the complexity has a median of four with an interquartile range of nine in both the

uncustomized and the customized code. The mean complexity is, however, 9.846 in the

uncustomized code and 9.891 in the customized code, showing the average complexity is 0.045

higher in the customized code. The coupling has a median of 109 related classes in the uncustomized

code and 110 related classes in the customized code, both with an interquartile range of 82 related

classes. As the medians, the means show an increase in coupling from the uncustomized code to the

customized code.

Like for the complexity, Table 3 shows no difference in mean or interquartile range is found with

respect to the unit size, depth in tree and number of children. However, the means show a decrease

in unit size and an increase in depth in tree and number of children from the uncustomized code to

the customized code.

Table 3 Results for metrics not measured per system

Metric

Uncustomized code

Customized code

Median

IQL

Mean

Median

IQL

Mean

Complexity

4

9

9.846

4

9

9.891

Coupling

(related

classes)

109

82

39.18

110

82

39.32

Unit size

(statements)

3

5

6.636

3

5

6.629

Depth in

tree

1

1

1.636

1

1

1.638

Number of

children

0

0

1.642

0

0

1.646

This table shows the median, interquartile range and mean for both the uncustomized and customized code for the metrics that were not measured for the complete systems and therefore had to be aggregated to obtain system-wide results

.

(17)

Chapter 6 Analysis

We analyze the results presented above using IBM SPSS Statistics 24. We retract the null hypothesis

of a statistical test (that a result was found by coincidence) when the chance it is true (p) was found

to less than 0.05. A chi-square test is performed to calculate the significance of the difference in

volume between the uncustomized and the customized code. The result of this test was p<0.000,

meaning the increment in volume caused by the customizations is found to be significant. This result

was expected as customizations can be used for adding functionality and adding functionality to a

program obviously requires code to be added to the system (at least in some cases).

Visual inspection of the scatter plots below shows the complexity, coupling, unit size, depth in tree

and number of children are not normally distributed for both the uncustomized and the customized

code. For the sake of completeness all used scatter plots are presented, although plots for the same

metric for both versions of the code may look similar to humans due to the small size of the

customizations as compared to the total size of the analyzed code.

We therefore perform a (non-parametric) Mann-Whitney U-test to test the significance of

differences between the uncustomized and the customized code. The differences in complexity

(p=0.081), unit size (p=0.418) and depth in tree (p=0.451) are found to be insignificant. The

differences in coupling (p=0.013) and number of children (p=0.005) are found to be significant.

Figure 1 Scatter plot of complexity in uncustomized code Figure 2 Scatter plot of complexity in customized code

(18)

On the Impact of ‘Fork and Modify’ Customizations on Source Code Metrics in X++

16

Figure 5 Scatter plot of unit size in uncustomized code Figure 6 Scatter plot of unit size in customized code

Figure 7 Scatter plot of depth in tree in uncustomized code Figure 8 Scatter plot of depth in tree in customized code

Figure 9 Scatter plot of number of children in Figure 10 Scatter plot of number of children in

uncustomized code customized code

The significance of the difference in the relative number of lines of code that is part of a block of at

least six lines of duplicated code is tested by performing a chi-square test. The result of this test is

(19)

p<0.000, meaning the increment with respect to this metric caused by the customizations is found to

be significant.

(20)

On the Impact of ‘Fork and Modify’ Customizations on Source Code Metrics in X++

18

Chapter 7 Discussion

The analysis described above shows significant impact was found on the volume, coupling, number of

children and duplication. This suggests ‘fork and modify’ customizations have (more) impact on these

metrics (than on complexity, unit size and depth in tree). However, the research described here is

subject to threats to the validity of this possible conclusion.

First and foremost, the customizations the difference between the compared versions of the

analyzed code consist of, may partially be a direct consequence of the addition of functionalities. The

results may therefore be a consequence of characteristics of these functionalities instead of the way

of customizing the code. Also, macros are excluded from the analysis, due to which some code is

unparseable and is excluded from the analysis. Code that programmers put in macros, may differ

from other code, making this a potential bias.

Another reason the comparison between the uncustomized and the customized version of the code

may be invalid is that the observed differences may be caused by different characteristics between

the uncustomized code and the code written as part of the customizations. Although no evidence

was found to support this claim, this chance is expected to be increased by the fact the

customizations are made by another party (thus likely other developers) than the uncustomized

code.

Furthermore, units size and cyclomatic complexity are measured per method, causing code that is

not part of the body of a method to be ignored for the calculation of these metrics. Also, the

generalizability of a conclusion based on the research described here would be questionable,

because the analyzed customizations are made by one specific group of programmers, that may have

specific characteristics which are not accounted for.

Finally, due to time constraints, we have not been able to validate eXPODigger and eXPyMeter

against other tools and it thus remains unproven these tools provide valid measurements of metrics

in X++ code. Especially after validation, these tools may however be of use for other research for

which X++ code is analyzed.

Chapter 8 Conclusion

In the research described in this thesis, metrics regarding the maintainability and reliability of X++

code are measured to compare code of Microsoft Dynamics AX as it is delivered by Microsoft to a

customized version of the code used in the product AX4Health to measure the impact customizations

on these aspects of source code quality. Tools are developed to pre-process and parse the code and

to measure the number of statements, cyclomatic complexity, coupling between objects, depth in

tree, number of children, percentage of the code that is part of duplicated blocks over six lines and

unit size.

The research described here is subject to multiple threats to the validity, that would make any

conclusion based on the results untrustworthy. Therefore, even although the results are conclusive,

the author is not able to present a conclusion that answers the research question described in the

introduction to this thesis. However, the tools that are created for the performed analyses –

eXPODigger and eXPyMeter – may be of use to any future research projects regarding X++ code.

(21)

Bibliography

Besides research papers, sources about Microsoft Dynamics AX and the used tools are referenced.

For clarity, references to research papers and other evidence based sources are highlighted in this

bibliography.

[1] Bilous B. What's new in X++ for AX 7, 2016. Available at

https://axforce.wordpress.com/2016/01/18/whats-new-in-x-for-ax-7/. Accessed 9/26/2016.

[2] British Standards Institution Systems and software engineering — Systems and software Quality

Requirements and Evaluation (SQuaRE) — System and software quality models, BS ISO/IEC

25010:2011, (2011).

[3] Brooks A. MSc Software Maintenance, Fyrirlestur 42, Maintainability Index Revisited, 2016.

Available at http://staff.unak.is/andy/MScMaintenance0809/Lectures/SMLec42.ppt. Accessed

5/10/2016.

[4] Chidamber S.R. & Kemerer C.F. Towards a metrics suite for object oriented design, Proc ACM Conf

OOPSLA 6 (1991) 197-211.

[5] Cho E.S., Kim M.S. & Kim S.D. Component metrics to measure component quality, Aspec 8 (2001)

419-426.

[6] CWI. Rascal Metaprogramming Language, 2014. Available at http://www.rascal-mpl.org/.

Accessed 5/23/2016.

[7] Dynamic AX Developer Reference. X++ Syntax, 2016. Available at

https://ax.help.dynamics.com/en/wiki/x-syntax/. Accessed 7/11/2016.

[8] Gupta A. Enterprise resource planning: the emerging organizational value systems, Industrial

Management & Data Systems 100 (3) (2000) 114-118.

[9] Heitlager I., Kuipers T. & Visser J. A practical model for measuring maintainability, QUATIC 6

(2007) 30-39.

[10] Jenkins E.K. & Christenson E. ERP (enterprise resource planning) systems can streamline

healthcare business functions, Healthc Financ Manage 55 (5) (2001) 48-52.

[11] Kaur G. & Bahl K. Software Reliability, Metrics, Reliability Improvement Using Agile Process,

IJISET 1 (3) (2014) 143-147.

[12] Khan S. Working with dates in X++, 2015. Available at

https://dynamicsaxed.wordpress.com/2015/06/04/working-with-dates-in-x/. Accessed 9/26/2016.

[13] Klint P., Van Der Storm T. & Vinju J. EASY Meta-programming with Rascal, Springer, 2009,

222-289.

[14] Klint P., Van Der Storm T. & Vinju J. Rascal: A domain specific language for source code analysis

and manipulation, (2009) 168-177.

[15] Klint P. & Vinju J. Syntax Definition, 2016. Available at

http://tutor.rascal-mpl.org/Rascal/Declarations/SyntaxDefinition/SyntaxDefinition.html. Accessed 7/11/2016.

[16] Li H.F. & Cheung W.K. An Empirical Study of Software Metrics, IEEE Trans Software Eng 13 (6)

(1987) 697-708.

[17] Maertens M. Model split, 2016. Available at

https://ax.help.dynamics.com/en/wiki/understanding-the-model-split/. Accessed 6/27/2016.

[18] Maertens M. Customization: Overlayering and extensions, 2015. Available at

https://ax.help.dynamics.com/en/wiki/customization-overlayering-and-extensions/. Accessed

6/10/2016.

[19] Martens A. et al. Automatically improve software architecture models for performance,

reliability, and cost using evolutionary algorithms, (2010) 105-116.

[20] McCabe T.J. A complexity measure, IEEE Trans Software Eng 2 (4) (1976) 308-320.

[21] Microsoft. How to: Use X++ Syntax for CLR Arrays [AX 2012], 2012. Available at

https://msdn.microsoft.com/en-us/library/cc557456.aspx. Accessed 7/13/2016.

[22] Microsoft. Overriding a Method [AX 2012], 2012. Available at

https://msdn.microsoft.com/en-us/library/aa880278.aspx. Accessed 7/11/2016.

(22)

On the Impact of ‘Fork and Modify’ Customizations on Source Code Metrics in X++

20

[23] Microsoft. update_recordset [AX 2012], 2012. Available at

https://msdn.microsoft.com/en-us/library/aa674382.aspx. Accessed 9/26/2016.

[24] Microsoft. X++ Language Programming Guide [AX 2012], 2012. Available at

https://msdn.microsoft.com/nl-nl/library/aa867122.aspx. Accessed 5/23/2016.

[25] Microsoft. Best Practices for Indexes [AX 2012], 2011. Available at

https://msdn.microsoft.com/en-us/library/aa617587.aspx. Accessed 9/26/2016.

[26] Microsoft. Intrinsic Functions [AX 2012], 2011. Available at

https://msdn.microsoft.com/en-us/library/aa626893.aspx. Accessed 9/11/2016.

[27] Microsoft. utcdatetime [AX 2012], 2011. Available at

https://msdn.microsoft.com/nl-nl/library/cc597805.aspx. Accessed 9/26/2016.

[28] Microsoft. GUID's, 2009. Available at https://msdn.microsoft.com/en-us/library/cc967363.aspx.

Accessed 9/26/2016.

[29] Microsoft. How to: Use #define and #if to Test a Macro [AX 2012, 2009. Available at

https://msdn.microsoft.com/en-us/library/cc197117.aspx. Accessed 10/11/2016.

[30] Microsoft. Common Language Runtime (CLR). Available at

https://msdn.microsoft.com/en-us/library/8bs2ecf4(v=vs.110).aspx. Accessed 7/13/2016.

[31] Parnas D.L. On the criteria to be used in decomposing systems into modules, Commun ACM 15

(12) (1972) 1053-1058.

[32] Poot E. & Trauschke O.C. software-evolution-assignment-1, 2015. Available at

https://github.com/edwardmp/software-evolution-assignment-1. Accessed 8/15/2016.

[33] Reddy S. Get underlying SQL query using getSQLStatement [Dynamics AX 2012], 2012. Available

at

https://dynamicsaxgyan.wordpress.com/2012/05/11/get-underlying-sql-query-using-getsqlstatement-dynamics-ax-2012/. Accessed 9/26/2016.

[34] Reddy S. Unchecked keyword in Dynamics AX [unchecked(Uncheck::TableSecurityPermission)]

using X++, 2011. Available at

https://dynamicsaxgyan.wordpress.com/2011/04/05/unchecked-keyword-in-dynamics-ax-uncheckedunchecktablesecuritypermission-using-x/. Accessed 9/26/2016.

[35] Rosenberg L., Hammer T. & Shaw J. Software metrics and reliability, 9th ISSRE (1998).

[36] Roy C.K., Cordy J.R. & Koschke R. Comparison and evaluation of code clone detection techniques

and tools: A qualitative approach, Sci Comput Program 74 (7) (2009) 470-495.

[37] Villadsen P. Macros - definitions and ptifalls, 2007. Available at

https://blogs.msdn.microsoft.com/x/2007/11/12/macros-definitions-and-pitfalls/. Accessed

7/11/2016.

[38] Visser J. SIG/TÜViT Evaluation Criteria Trusted Product Maintainability, version 6.1, (2014).

(23)

Appendix A: SIG Maintainability Model

The SIG Maintainability model is intended for standardized evaluation of the internal technical

quality of source code with respect to maintainability and its sub-characteristics (as listed in Table 1

on page 5) ([38], p.6). Maintainability and its sub-characteristics are qualified based on properties of

the analyzed source code: volume, duplication, unit complexity, unit size, unit interfacing, module

coupling, component balance and component independence ([38], p. 9). Below, these properties are

defined.

Volume is the size of the source code, expressed as the number of lines of code in it. Duplication

expresses (the part of the source code involved in) occurrence of identical fragments on multiple

places in the source code.

An earlier publication about the SIG Maintainability Model defines a unit as “the smallest piece of

code that can be executed and tested individually. In Java or C# a unit is a method, in C a unit is a

procedure” ([9], p. 33). Unit complexity expresses how hard an individual unit is to understand. Unit

size is the volume of a unit. Unit interfacing expresses the size of a unit’s interfaces in terms of the

number of parameters in the interface. Module coupling is the number of other modules a module

depends on [9]. The notion of module corresponds to a grouping of related units” ([38], p. 9). The

statement that “a module in Java or C# is a class” ([3], p. 12). Corresponds to the definition that

decomposition into modules can be based on information hiding [31].

“Component balance is the product of the system break-down, which is a rating for the number of

top-level components in the system, and the component size uniformity, which is a rating for the size

distribution of those top-level components. The notion of top-level components corresponds to the

first subdivision of the source code modules of a system into components, where a component is a

grouping of source code modules. (…) Component independence is a rating for the percentage of

code in modules that have no incoming dependencies form modules in other top-level components.

(…) The determination of these software product properties is based on objective, repeatable, and

accurate measurements at the level of source code lines, units, modules and components” ([38], pp.

9-10).

Evaluation

“The evaluation leads to an assignment of evaluation results as a number of stars between one and

five, where more stars represent better performance. The assignment is done for every product

property, for every quality sub-characteristic, and for the main characteristic of maintainability”

([38], p. 11). Table 4 shows which product property influences which sub-characteristic of

maintainability.

(24)

On the Impact of ‘Fork and Modify’ Customizations on Source Code Metrics in X++

22

Table 4 Influence on sub-characteristics of maintainability per product property, ([38], p. 12)

Maintainability

sub-characteristic

P

ro

d

u

ct

p

ro

p

ert

y

Vo

lu

m

e

D

u

p

licatio

n

Un

it size

Un

it

co

m

p

lexit

y

Un

it

in

te

rfaci

n

g

M

o

d

u

le

co

u

p

lin

g

Co

m

p

o

n

ent

b

ala

n

ce

Co

m

p

o

n

ent

in

d

epend

ence

Analyzability

x

x

x

x

Modifiability

x

x

x

Testability

X

x

X

Modularity

x

x

X

Reusability

x

X

A cross (X) indicates that a product property contributes to the maintainability sub—characteristic. All five

sub-characteristics contribute to the main quality characteristic of maintainability. The weights of the different contribution are discussed in the following chapter.

(25)

Appendix B: xpo-files

Objects exported from Microsoft Dynamics AX 2012 are saved in xpo-files. For classes, these files are

structured as follows: A file starts with some metadata about the export and the exported class (such

as version numbers). This is followed by a mark signaling the start of the contents of a class, of the

form CLASS #[class name]. At the end of the file, just before a final mark signaling the end of the

export (“***Element: END”), is a matching “ENDCLASS” mark. In between these two marks are two

other blocks. The first block starts with “PROPERTIES” and ends with “ENDPROPERTIES” and contains

metadata about the class, such as its name and location and which class it extends (if any). Names

and parents, are however also mentioned in class declarations. Therefore, we did not use this

metadata at all for our analyses.

The second block found between the marks signaling the start and end of the contents of classes

starts with a “METHODS” mark and ends with an “ENDMETHODS” mark. Between these marks, one

block can be found for each method in the export, as well as one for the class declaration, if present

in the export. These blocks all start with a mark of the form SOURCE #[method name] and end with

an “ENDSOURCE” mark. In case of a class declaration, “classDeclaration” is used as method name.

Between these marks, the contents of a method or class declaration can be found, with each line

preceded by a number of whitespace characters and a hash. Listing 1 below gives a graphical

overview of the contents of xpo-files representing classes.

(26)

On the Impact of ‘Fork and Modify’ Customizations on Source Code Metrics in X++

24

Listing 1 xpo-file format

Square brackets indicate places in the file structure where concrete values are, that can differ per

file. Ellipses indicate preceding items can be present zero or more times.

[Metadata about export and exported class]

CLASS #[Class name]

PROPERTIES

[Property] [Value]

ENDPROPERTIES

METHODS

SOURCE #[method name]

#[source code line]

ENDSOURCE

SOURCE #classDeclaration

#[source code line]

ENDSOURCE

SOURCE #[method name]

#[source code line]

ENDSOURCE

ENDMETHODS

ENDCLASS

***Element: END

(27)

Appendix C: X++ grammar

When concepts were found in the grammar used by the X++ parser without any definition,

definitions were searched via Google and validated by searching the analyzed source code for the

found definitions.

Listing 2 X++ grammar

/*When empty directives were removed, Function and Intrinsics became special cases of Eval and were therefore removed*/

keyword Reserved = TrueSym | FalseSym | NullSym | SuperSym;

keyword FuncReserved = EventhandlerSym | SuperSym | ReturnSym | ThrowSym;

keyword TypeReserved = StrTypeSym | IntTypeSym | Int64TypeSym | DblTypeSym | DateTypeSym | DatetimeTypeSym | GuidTypeSym | QueueTypeSym | VoidTypeSym | AnyTypeSym

| ThrowSym | ReturnSym | SelectSym | DeleteSym | NextSym | FlushSym | PrintSym;

layout Layout = LayoutOccurence* !>> Whitespace !>> "//" !>> "/*" !>> "#if.never";

lexical LayoutOccurence = Whitespace | SingleLineComment | MultiLineComment

| NeverExecutedCode; //Code containns non-breaking space characters (U+00A0)

keyword Whitespace = [\ \t\n\r\u00A0];

lexical SingleLineComment = BeforeCommentStart

<< ActualSingleLineComment;

lexical BeforeCommentStart = ^NoIncompleteStrings;

lexical NoIncompleteStrings = NoIncompleteString*;

lexical NoIncompleteString = NoQuotes | StrSym;

lexical NoQuotes = ![\'\"];

lexical ActualSingleLineComment = "//" NotNewLine* "\n";

lexical NotNewLine = ![\n];

lexical MultiLineComment = BeforeCommentStart << ActualMultiLineComment;

lexical ActualMultiLineComment = "/*" NotMultiLineCommentEnd* "*/";

lexical NotMultiLineCommentEnd = NotStar | StarNotFollowedBySlash;

lexical NotStar = ![*];

lexical StarNotFollowedBySlash = "*" !>> "/";

syntax NeverExecutedCode = MacroStart IfNever EndIfClause | MacroStart IfNeverClause;

syntax IfNever = "if.never";

lexical IfNeverClause = IfNever Whitespace+ NotEndIfWords Whitespace+ EndIfClause | IfNever Whitespace* SemicolonSym

Whitespace+ (NotEndIfWords Whitespace+)? EndIfClause;

lexical NotEndIfWords = (NotEndIfWords Whitespace+)? NotEndIfWord;

lexical NotEndIfWord = Word \ EndIfSym;

lexical Word = ![\ \t\n\r\u00A0]+ !>> ![\ \t\n\r\u00A0];

(28)

On the Impact of ‘Fork and Modify’ Customizations on Source Code Metrics in X++

26

keyword EndIfSym = "#endif" | "#Endif" | "#endIf" | "#EndIf" | "#ENDIF" | "#endif;"| "#Endif;" | "#endIf;" | "#EndIf;" | "#ENDIF;";

//Body

start syntax ClassDecl = MacrosBeforeClass ClassHeader LeftbrSym DclList? FuncDecls? RightbrSym;

syntax MacrosBeforeClass = (CallToMacro | MacroDefinition)*;

syntax ClassHeader = AttributeDef? ClassMods? Classorinterface StdId ExtendsClause?

ImplementsClause?;

syntax AttributeDef = LeftBrktSym AttributeInit? AttributeList RghtBrktSym;

lexical AttributeInit = ".";

syntax AttributeList = (AttributeList ListSepSym)? Attribute;

syntax Attribute = StdId

| AttributeWithArgsBegins AttributeWithArgsEnds | CallToMacro Attribute?;

syntax AttributeWithArgsBegins = StdId LeftParSym;

syntax AttributeWithArgsEnds = AttributeArgs? RghtParSym;

syntax AttributeArgs = (AttributeArgs ListSepSym)? AttributeConstant;

syntax AttributeConstant = IntSym | DblSym | StrSym | DateSym | DatetimeSym | StdId DblcolonSym StdId | True | False | AttributeIntrinsic | CallToMacro;

syntax AttributeIntrinsic = StdId LeftParSym IArgs? RghtParSym;

syntax IArgs = StrSym | StdId (ListSepSym StdId)?;

syntax ClassMods = ClassMods? ClassModifier;

syntax ClassModifier = Public | Final | Static | Abstract | Private;

syntax Classorinterface = Class | Interface;

syntax ExtendsClause = Extends StdId;

syntax ImplementsClause = Implements Implementlist;

syntax Implementlist = (Implementlist ListSepSym)? StdId;

syntax FuncDecls = FuncDecls? (FuncDecl

| MacroInsteadOfFuncDecl);

syntax MacroInsteadOfFuncDecl = CallToMacro | MacroDefinition | LocalOrGlobalMacroClause;

syntax FuncDecl = FuncHead Body;

syntax FuncHead = AttributeDef? Funcname ParmDclList;

syntax Funcname = Functype FuncId;

syntax Functype = FuncMods? DeclType;

lexical FuncId = ([_@a-zA-Z][_@a-zA-Z0-9]*) !>> [_@a-zA-Z0-9] \ FuncReserved;

syntax FuncMods = FuncMods? FuncModifier | FuncMods CallToMacro;

syntax FuncModifier = Public | Private | Protected | Final

| Static | Abstract | Display | Edit | Server | Client | Delegate;

Referenties

GERELATEERDE DOCUMENTEN

Results from 762 annual reports of 310 firms in 2 countries indicate that the number of key audit matters is significantly higher for firms with a high leverage ratio.. On top of

Lemma 7.3 implies that there is a polynomial time algorithm that decides whether a planar graph G is small-boat or large-boat: In case G has a vertex cover of size at most 4 we

Gedurende deze dagen was het onmogelijk zonder ontvochtiging verschillen in luchtvochtigheid tussen de behandelingen te realiseren omdat de het vochtdeficit op die momenten niet

The iterative coupling scheme developed between HOST and WAVES is based on the method used in [7], [8] and [9] to couple Full- Potential codes with rotor dynamics codes. Since

For this data set, we compare the original LC solution by Owen and Videras, the first splits of a binary LCT, and an LCT with a more appro- priate number of child classes at the

The standard mixture contained I7 UV-absorbing cornpOunds and 8 spacers (Fig_ 2C)_ Deoxyinosine, uridine and deoxymosine can also be separated; in the electrolyte system

Om het gebied archeologisch te kunnen evalueren luidde het advies van het Agentschap R-O Vlaanderen - entiteit Onroerend Erfgoed dat minimaal 12% van het terrein onderzocht moest

It is shown that by exploiting the space and frequency-selective nature of crosstalk channels this crosstalk cancellation scheme can achieve the majority of the performance gains