Formal Speci cations in Software Maintenance: From code to Z++ and back again Jonathan Bowen
Peter Breuer y
Kevin Lano z
Oxford University Computing Laboratory Programming Research Group Wolfson Building, Parks Road, Oxford OX1 3QD, UK. October 1993
Abstract This paper presents a number of techniques that have been developed as components of the software maintenance process as part of the ESPRIT REDO project. These techniques are all based on formal methods, and the work described has provided the mathematical underpinning to a large collaborative project that has been investigating various aspects of software maintenance. The focus of the project has been on reverse engineering, and methods for this part of the maintenance process are reported on here, along with techniques for subsequent re-engineering. A proposal for speci cation-oriented software maintenance is presented, in which speci cations in an object-oriented extension of the formal notation Z are maintained in step with the corresponding programs.
Keywords: Formal methods, formal speci cation, object-oriented techniques, re-engineering,
reverse engineering, software maintenance, Z notation.
Revised version for Information and Software Technology journal. Funded by ESPRIT II REDO project (no. 2487), 1989{1992. Oxford University Computing Laboratory, Programming Research Group, Wolfson Building, Parks Road, Oxford OX1 3QD, UK. Email:
[email protected]. y Escuela T ecnica Superior de Ingenieros de Telecomunicacion, Universidad Politechica de Madrid, Edi cio B, Ciudad Universitaria, E-28040 Madrid, Spain. Email:
[email protected]. z Lloyd's Register, 29 Wellesley Road, Croydon CR0 2AJ, UK. Email:
[email protected]. 0
i
Contents Introduction
1
Reverse Engineering to the Speci cation Level
2
Re-engineering of Code from Speci cations
7
A Speci cation-based Approach to Maintenance
10
Summary
21
Acknowledgements
22
Project Publications and Reports
22
Other References
24
ii
Introduction Software maintenance is a key aspect of the vast majority of software products and a high percentage of industrial resources are spent on this part of the software lifecycle LPW88. However researchers have often ignored this area in the past Sch87, with one or two notable exceptions (e.g., Lehman's work Leh80). This paper presents some of the results of a European collaborative project dedicated to investigating techniques and developing a potentially integrated toolset to aid the software maintenance process. Here we concentrate on the more formal aspects of the project. More general views of the project may be found elsewhere 1 vanZ92. In this paper we provide an overview of the techniques we have developed, give examples of their use, and provide a selected bibliography of the most important publications and reports produced as a result of this work. The areas include the theoretical development of an intermediate language (\UNIFORM") SC90, reverse engineering, validation, maintenance of future applications. The project has also considered the problems of decompilation of object code to source code which is covered adequately elsewhere 2 3 4 5 . It should be emphasized that while the process of reverse-engineering which we advocate requires a tool that understands the semantics of program and speci cation, it is the taking part in the process that is the means of discovery which eventually leads to program comprehension. We cannot oer a magic route to understanding that bypasses either human intelligence or human interaction. All that is on oer here are the tools and notations that can make understanding possible, together with a process model for the activity. Moreover, while we have encoded this model in our reverse engineering toolset, the sequence of operations is not immutably xed (being available on top-level pull-down menus). Indeed, it may often be necessary in practice to go back from some late stage of the process to make modi cations at a conceptually earlier stage. In a properly integrated toolset, such modi cations may be expected to propagate forwards along the model again, but in our prototype, they merely cause outputs of some of the later process stages to be marked as needing to be redone, and this behaviour needs modi cation if the toolset is to be commercially attractive. But apart from such reservations, we believe that the process model of reverse engineering presented in this paper is appropriate to reverse engineering, and that we have been able to make use of it in our experimental toolset both as a design guideline for ourselves, and as a practical indication to the user of what needs to be done next. ;
;
1
;
;
Experience from case studies has resulted in the evolution of specializations of our approach to particular forms of reverse engineering: design recovery, redocumentation, restructuring, transfer of information to CASE tools, and so forth. These case studies include a 100,000 line COBOL accounting application, of which about 10% of the procedural code, and about 30% of the data model were abstracted using our techniques. Substantial FORTRAN applications, of between 10,000 and 20,000 lines have also been analysed using REDO tools. Commercial con dentiality prevents detailed presentation of these case studies; however, a detailed application of the techniques described in this paper to a representative COBOL '74 application, of 4 programs containing 3,000 lines of code, is described in LH93a. Extracts from other case studies are given in Chapters 7 and 8 of LH93b. The paper is structured as follows. The next section introduces formally-based techniques for reverse engineering, and demonstrates that source codes may be transformed to speci cations which capture their functionalities. Then aspects of code re-generation from the recovered speci cations are discussed. Finally, a coherent account of maintenance at the speci cation level is presented, which is suggested as a future technique for software maintenance.
Reverse Engineering to the Speci cation Level Current practice in reverse engineering or restructuring is concentrated on the extraction of graphical or statistical information from source code, which is useful for detecting design or coding
aws, but does not provide an explicit description of the functionality of code, which is critical for reuse. In contrast, we will describe techniques which have proved eective in extracting both design and functionality from source code, and which have been applied to real data-processing applications in industrial use. The techniques use formal object-oriented speci cations SBC92 as a uni ed representation for design and abstracted functionality. This choice simply represents a preference within the software community for structured design, and a general agreement that object oriented features such as localization of functionalities and data, and inheritance of class characteristics, are both sucient to enable good design to take place and are desirable features of a good design. Other tools may produce Yourdon diagrams, or other box-based top level designs, but our tools ll out objects as Z speci cations Spi92. Of course, we can render them in other formats by suppressing some of the detail and making transformations before the nal presentation, but formal speci cations are generally seen as a useful and distinguishing output 2
from our process, and one that we would not wish to withdraw. Generally, our techniques may be said to be aimed at providing higher level information than is usual (insofar as there is a norm in this nascent area), concentrating particularly on obtaining expressions of functionality. We transform away from the the code level almost immediately, and almost all the interactive operations in the toolset operate thereafter on intermediate and higher level abstractions. More conventional information, such as data- ow and control- ow diagrams, are available as views, but are not the data types manipulated as principals by the toolset. Other approaches to the use of formal methods in reverse engineering are, notably, those of Basili et al. BAC91 , based upon a low-level and intensive validation of code, using classical Hoare-style assertions, and of Ward et al. in the REFORM project WCM89 , which is based upon transformation of assembly language code into a wide-spectrum language which can contain a mixture of programming and speci cation constructs Mor90 MRG88. The work of Linger, utilizing functional abstraction and program transformation LHPH90 , and that of Zimmer, which utilizes code-level object classes Zim90, are also developed approaches that are related to ours. But our approach integrates these separate aspects, functional abstraction, language transformation and the formation of object classes, in order to produce abstract speci cations in a formal speci cation language. In contrast to the approach of Basili et al. BAC91 , for example, we do not require detailed proof and validation procedures at the code level, but at the more easily manipulated abstraction level. This results in an order of magnitude reduction in the number of distinct operations that may be applied, but requires less concrete knowledge (of the source language semantics) of the human operator and more abstract knowledge (of the abstract speci cation language), which may be a disadvantage. The code-level validation approach was tried initially in the REDO project, but abandoned because it was felt that the complication of an approach which implicitly requires the interaction of operations on source code and abstractions would be too great, and that abstraction of the source code to a higher level language should be undertaken rst. Our system requires proof and validation only at the abstraction level, where it can be handled by experts in speci cation. Nothing but detail is lost in the abstraction, and the logic of the operations on the abstraction is the logic common to all possible sources (abstraction is the process of forming a view or image, and dierent operations on the source of the view often have common images as view operations) so the abstraction is always correct with respect to the source code. ;
3
Reverse engineering process model The process of transformation that we have developed can be modelled as shown in Figure 1. This is a generic `step-up' process, in which incoming low-level code is raised to a higher level. In the case of our overall reverse engineering process, the incoming code is COBOL or FORTRAN, and the outgoing speci cation is Z, but the same essential process is repeated at several levels within this overall scheme, and at one intermediate level for example, the incoming code is in a universal intermediate language, UNIFORM SC90 , that abstracts features of both FORTRAN and COBOL. The three major parts of the overall process are elaborated (following the terminology on the project 6) in the following subsections.
Stage 1 (Clean) Reduction of COBOL to the UNIFORM subset.
The system translates incoming COBOL code to UNIFORM SC90 code automatically. UNIFORM may be viewed as a clean subset of an updated, modern version of COBOL (as well as an abstract image).
Approximations away from the precise layout of data are performed in places. For example,
COBOL stores all numerical data as ASCII strings, and string operations can validly be carried out on them. Nevertheless, the intention of a programmer will almost always have been to store a number, not a string, so COBOL numerical elds are left as numbers in UNIFORM, and the arithmetic operations are left as what may have been supposed to have been the programmers intention: the standard arithmetic operators. See Figure 2, for an example. In rare circumstances, it may be that the programmer has deliberately justi ed the numbers abnormally in their elds and ordinary arithmetic is inappropriate; the appropriate representation is as explicit strings and special mixed string and arithmetic operators. If it becomes apparent later in the process that such is the case, then it will be necessary to go over this stage of the process again { to clean part of the incoming code in a dierent way.
Additional information, such as the initial values and possible ranges of variables, is also generated. The [0-10^2] in Figure 2 is an example of such. The resulting code is a slight semantic abstraction of the original, but for all practical purposes, may be deemed equivalent (recall that we are aiming at achieving an abstraction, so that loss of detail is not necessarily 4
bad, provided it is inessential for comprehension). The output code contains a smaller number of dierent keywords (there are vastly fewer than COBOL in UNIFORM). The somewhat arcane control structures of COBOL are rendered in terms of a smaller and simpler set of more structured components in UNIFORM, but GO TOs are preserved.
Stage 2 (Specify) Some conceptual objects
in the UNIFORM program are identi ed by examination of the FILE SECTION and ENVIRONMENT DIVISION holdovers from the COBOL source. The les of the program, and their associated status variables, are obtained immediately from this examination, and treated as objects. Blank forms are set up for these objects in which the names and many of the methods have to be lled in still, but the primary data structures are there, as well as several of the standard methods (for a le, overwriting, appending, deletion, etc.). As well as les, we consider indexed arrays and reports to be primary data structures, and they can all be represented as objects with several pre-assigned attributes and methods.
Data- ow analysis of the UNIFORM program is performed, and this allows us to identify
secondary variables which are logically associated with the primary data structures that have been localized in objects, as well as the global data- ows between the primary structures (these identify `friend' relationships between objects). Decisions over where these secondary data belong must be human in origin, but they can either be placed in an existing object, or can form the nucleus of a new object.
Functions and code which update or modify the main structure of the created objects are
identi ed next. This is essentially a human-mediated operation, aided by computer, but each such data ow corresponds to a candidate method for the object, and we will later initiate a more detailed analysis in order to nd the precise functionality of this operation. The toolset shows where code that in uences a particular data structure lies, and it is up to the user to single out the coherent section of surrounding code that is of interest, and move it into the object form. If the code is still needed for its action on the data of a dierent object, it will have to be duplicated or made available (or the object partitioning reviewed).
5
Some automatic techniques also serve to break up the functionality of the program into
manageable chunks. We split the program into phases , maximal logically connected pieces of code which contain no le OPEN or CLOSE statements. In other words, a phase represents an execution period in which the les are processed in a particular mode, and hence should represent a single input-output function on the tuple of these les. The modalities of the les during a phase gives us the type of the function, and details are extracted from the code of the phase by means of functional abstraction, described below. If suciently many phases do not exist we use program slicing GL91 (restriction to a named set of variables, les and reports) using the variables of an object C and those variables we have identi ed as likely to be used in a method of C as the restriction set, and thus obtain a simpli ed view of the code. This view makes the code which changes these variables stand out from irrelevant functionality, and allows it to be collected together as a method of the object.
Low-level functional abstraction step. We assume now that we have identi ed suitable
sections of code for further analysis. This code still contains the PARAGRAPHs and GO TOs of COBOL, and retains a fall-through semantics that complicates reasoning. We need to simplify and reduce still further the number of code constructs, and this is done by abstracting the code into a simple rst order functional language. In our functional language, there are just two essential constructs: functional composition, f (a ), and conditional expressions, e ! a ; b , which return value a if e is true, b otherwise. From these, and a sucient set of elementary components, we can represent the functionality of any derived program as a series of equations de ning a set of functions, plus the data declarations derived from the UNIFORM program. See Figure 3 for an example. Our prototype toolset does not succeed in retaining all the links between nal abstraction and initial source code, but we believe such linkage to be essential in a production toolset. Then it would be possible to highlight a section of the formal speci cation and have the lines (and subexpressions within the lines) in the source code which formed that functionality picked out for inspection. It is necessary to capture the total functionality of an application if re-engineering is to be performed, since if the client wishes to retain all the existing functionality of an application, it must be re-implemented in the new version after reverse engineering has taken place. Some detail is necessarily destroyed during design abstraction, however, (and, as indicated above, the 6
prototype toolset does not succeed in following the linkages) and so the original code has at present to be retained and correlated with the abstraction as annotations.
Stage 3 (Simplify) Simpli cation of abstractions and design.
We do not suggest that the output of stage 2 is ever optimal. It may be necessary both to rearrange the distribution of methods and data between objects (the design) and to perform further abstractions, or rearrange the formal speci cations until they become more recognizable in terms of known concepts. As part of the further abstraction process, for example, we attempt to form hierarchies of objects and classes. On exiting from stage 2, each object is the unique occupant of its own class (apart from system generic objects such as standard les, which the toolset automatically renders as instances of a class). Recognising commonalities between objects allows us form a common class abstraction, and express the contributing objects as instances of the class. But for recognition, a reformulation of the functional speci cation is frequently required.
Simpli cation of the speci cation. Stage 2 produces an equational-style speci cation, and
this can be loosened to a relational style, and a series of transformations and simpli cations is available for the equational representation. Moreover, a set of normalizing transformations 6 is ordinarily re-applied after every high-level modi cation and this produces a consistent and standard format of speci cation for the user. The top-level menu of equational manipulations includes the set shown in Figure 4. We can prove that the normalizations will always enable us to rewrite an equational speci cation to a certain structured form 7 . In the following sections, we illustrate the complete procedure through an extended example.
Re-engineering of Code from Speci cations Once a program has been reverse engineered to a speci cation, it is generally required to reengineer the speci cation as a new program. This process of forward engineering is in general much better understood, and many techniques, both formal and informal, have been researched and used in practice. However, this section details some of the speci c techniques used on the REDO project, and supported by REDO tools. 7
Data re nement Data and functionality are re ned to procedural code in separate processes. The transformation of data types from abstract forms such as sets, functions and sequences into concrete types such as les, arrays, records, etc., is the basis of re nement, in that this data re nement mapping determines the mapping from speci cations of programs into code. The interpretations of data types defaults to: T[ ; ]
:: speci cation type ! implementation type
T [ seq t ] = T [t ! s ] =
array[1; . . . ; + file of
r
1]
of
T [t ]
selectable by key key1
where r is a new record type: r = record [
key1 :
T [ t ] ; key2 : T [ s ] ]
and similarly for nite partial functions. (UNIFORM allows les and arrays to exist without speci c size bounds.)
Procedural re nement For the most part, the re nement of the functional part of speci cations to procedures follows automatically from the data re nements. When possible we combine assignments into concurrent assignments, and re ne non-deterministic forms of conditional into deterministic ones. This means that a speci cation that uses schema disjunction: S =b S1 _ S2 S1 Decs Pre1 Op1 is expanded out by pre-processing into
S2 Decs Pre2 Op2
8
S Decs (Pre1 ^ Op1 ) _ (Pre2 ^ Op2 )
and becomes a procedure whose command is: IF $E_1$ THEN $Cmd_1$ ELSE IF $E_2$ THEN $Cmd_2$ END IF END IF
where E1 is the re nement of Pre1, Cmd1 of Op1 , and so on. Set comprehensions, quanti cations, and binding operators such as are translated into iterations performing searches over bounded domains. The systematic treatment of these constructs is one of the largest parts of the system. The other critical aspect is the introduction of local variables for such iterations and other hidden operations involved in Z-style speci cations. A nal warning is that we cannot expect the implementation to be perfectly correct with respect to the speci cation or even the abstract axiomatic semantics of the code as provided by 8 9, as the way in which (for instance) arithmetic expressions are evaluated may vary, and the range of de ned numbers may vary. For similar reasons real numbers have been excluded from the Z subset. ;
Implementation from executable speci cations From the rst order functional abstractions which form an intermediate layer for the sequence of abstraction transformations performed by the reverse engineering tools, we can produce COBOL again automatically. This abstraction layer is at the lowest level of abstraction from code, and is normally re-implementable. Any non-determinacy in the speci cation is either explicit (i.e., it appears through the use of `either . . . or . . .' constructs) and can be coded as a random choice, or leads to recursions without outputs in the re-implementation. The result is always like COBOL which has been produced by other code-generators, in that it is not very amenable to human comprehension, but the important point is that it is generated from a much higher level representation, which is so amenable. This mechanism provides an automatic means of animating (certain forms of) speci cations, and is treated elsewhere in more detail 10 11. The system consists of several consecutive transformation and normalization layers. ;
9
A contrasting interactive method for animating higher level speci cations directly is also used, and is discussed below.
Implementation of Z speci cations as UNIFORM procedural code The system which re nes Z speci cations to UNIFORM consists of three parts: a parser for Z; a procedure compiling an internal Prolog CM87 form of the speci cation from the parse tree; and the actual re nement routines which interactively convert this form into UNIFORM code. The second stage involves the expansion of all schema references and types into corresponding sets of declarations or record types, the third stage performs the re nement of the types of the speci cation into UNIFORM types, and prompts for con rmation of these choices. The algorithmic re nement stage is automatic. An internal form of the command will be created and stored in the database, and a visual representation printed on request. For example, in a radar track-former speci cation considered on the REDO project 12, the initialization state of the speci cation Initial becomes the parameterless procedure Initial: Initial STATE 10 ph 0 = hi unused 0 = hi th 0 = hi tracknumber 0 = 0
PROC Initial(); OWNS ptr ph, ptr th, ptr unused, tracknumber; BEGIN ptr ph := 0; ptr th := 0; ptr unused := 0; tracknumber := 0 END
The system has also been extended to deal with formal object-oriented speci cations SBC92 in the Z++ language 13 as its input, and supports manipulation of these speci cations into re nable forms 19.
A Speci cation-based Approach to Maintenance In this part of our research, we used the language Z++ , and a method based upon this language, to support the use of formal methods in software maintenance. The method is centered on the maintenance of the speci cations and the development record, not upon source code or Structured Methodology documentation. It is proposed as a practical approach for software in the medium term future, allowing the mass of programming detail that makes the code maintenance problem so expensive to be ignored. Therefore changes and extensions to application systems can be 10
made more rapidly. We describe the language and give details of the speci cation and re nement system, together with a description of the implementation of this system 14. The components of the method are:
a standard speci cation style for systems; exact semantic correspondences between code and speci cation forms 15; a systematic process of implementing changes to systems by changing the speci cation and updating all documentation in line with this change. In other words we intend to maintain the development record, the entire structure of re nement steps and documentation encompassing the derivation of code from speci cations, as opposed to just maintaining the code. Because of the considerable investment already by some parts of industry in using and learning Z (e.g., on the IBM CICS project Phi90), we felt such a formalism should be chosen, especially as it is widely regarded as one of the best or most usable formal speci cation languages, and much information and experience is increasingly available about the language 16. The signi cant dierence between our language and Z is in the ability to de ne object classes, templates for objects which encapsulate a state, invariant properties of that state, and operations, owned by the object, using this state. We also adopt a wide-spectrum approach; the use of code constructs of UNIFORM, such as DO WHILE and RECEIVE / SEND, which have a precise mathematical meaning 8 .
The Z++ language Only a brief description will be given here. A more detailed description 13 , and information on the formal semantics 17 18 have been produced. Methods of re nement and reasoning about Z++ speci cations 19 , and application examples 6 10 11 20 21 are also available. The general layout of a Z++ speci cation is as follows: ;
;
;
;
;
1. De nitions of global types. 2. De nitions of object classes. 3. The system state including variables used in every operation together with global invariants on these variables. 11
4. The initial state in terms of constraints on the state variables. 5. De nitions of operations in terms of state changes. That is, a speci cation is a sequence of paragraphs of formal text (ideally interspersed, as in Z, with informal explanatory text paragraphs), which are either Z paragraphs in which class names are used as types, and class operations in method calls, or are class de nitions. Full syntactic details of these de nitions have been produced 22. However, the syntax for classes is summarized here.
Class syntax The BNF description of a Z++ class declaration is given in Figure 5. The TypeParameters are a list (possibly empty) of generic type parameters used in the class de nition. A parameter X can be required to be a descendent of a class A via the notation A X here. The EXTENDS list is the set of previously de ned classes that we are incorporating into this class. The Types are type declarations of type identi ers used in declarations of the local variables of the object. The Local variable declarations are attribute declarations, in the style of variable declarations in Z. The OPERATIONS list declares the types of the operations, as functions from a sequence of input domains to an output domain. The RETURNS list of operations de nes the output type of those attributes and functions of the objects internal state that are externally visible; these are operations with no side-eect on the state. The INVARIANT gives a predicate that speci es the properties of the internal state, in terms of the local variables of the object. This predicate is guaranteed to be true of the state of an object class instance between executions of the operations of the object instance. The ACTIONS list gives the de nitions of the various operations that can be performed on instances of the object; for instance we would write: READ x ==> q 0 = tail q ^ x = head q
in a speci cation of queues with contents q . The input parameters are listed before the output parameters in the action de nitions. Code includes Z predicates and procedural UNIFORM SC90 code, both have a precise semantics as predicate transformers 15. Alternative forms of notation, closer to Z or C++ are also available. 12
The HISTORY predicate speci es the admissible execution sequences of objects of the class, using linear temporal logic formulae with operators 2 (henceforth), (next), and (eventually). The formal semantics for the language has been used to provide proof and re nement rules for speci cations 19 . These rules specify when inheritance relationships between classes are also re nement relationships (so that there is type compatibility in the sense of Eiel Mey88 between the inherited and the inheriting class). They also specify when re nements of component classes of a system lead to re nements of an entire system, which is signi cant in the context of software maintenance and reuse: the way in which a component is used does not need to change just because this component has been `improved' via re nement.
Semantics A speci cation describes a hierarchy of type and object class de nitions, in which a class C inherited by class D occurs higher in the hierarchy. Another important relationship between classes is that of re nement: A class D re nes a class C if D can implement all of C 's operations in such a way that the interpretation of C 's operations by D re ne the original de nitions (in the usual procedural sense MRG88). In our semantics for the language, where classes are denoted by logical theories, re nement corresponds to relative theory interpretation, similar to the concept of a morphism in the institutions used by Goguen for object-oriented languages Gog91. Another hierarchy is determined by the client relationship Mey90 between classes: A class is used as a client by another class if it is used as the type of an attribute of this class, and then its operations can be used as method calls in the de nitions of the methods of this class. Because the state of a class is encapsulated, and can only be changed or viewed from the outside via the methods of the class, such a hierarchical organization promotes separation of concerns: a development team can work separately on dierent parts of a speci cation, provided they guarantee that the operations of the classes they de ne meet the requirements of those classes which use them. The internal details of the classes are irrelevant from the point of view of functionality. This also allows changes to be made to classes at one level of the usage hierarchy without necessarily requiring changes to the levels which they use or which use them. A change in a user interface for example would not normally require any change in the layers beneath it, and so forth. Indeed other research undertaken on the REDO project applied the concepts of object-orientation 13
to the extraction of user interfaces from applications and their redesign Smi91. An example of a class, from the marriage base speci cation of 14, is: CLASS OWNS
mclass
contents : Name $ Name
RETURNS
MEMBERS : ! P Name
OPERATIONS
ADDMARR : Name Name ! REMM : Name Name !
;
S
ACTIONS
==> contents ; ==> contents 0 = contents fm 7! f g; ==> contents 0 = fm g ; C contents
MEMBERS ADDMARR m f REMM m f
END CLASS
This is a re nement of a previous version of this class, and this re nement required no changes in the level of the speci cation which used this class. Metrics of maintainability were developed for these speci cations, based on the structural metrics de ned by REDO project Jac90. These metrics favor modularization of a speci cation into moderate-sized classes over monolithic speci cations.
Development, re nement and reusability A transformational approach to re nement is advocated. The path the developer takes in passing from the speci cations to the code is recorded by means of a tree of transformation laws and what sections of speci cation or code they were applied to. Speci c class re nement laws, in a natural deduction proof style, may be found elsewhere 19 . Ideally, such a proof tree can be reused and understood in much the same way as mathematical proofs are intended to be. A proof of a mathematical result is retained because of the insight that it may yield in understanding the critical points of the result, and in obtaining analogous results. Reusability refers to the ability to reuse some aspect of a software development in other new developments. The reusable part is not necessarily restricted to code but may also include speci cations, domain knowledge, development histories and documentation. Much research has been undertaken in assessing program transformation as a means of aiding in the reusability of software components ABFP86 PS83 BM84 BP86 Nei84. The results suggest that a system based on transformations can provide an eective means of recording development histories and veri cation ;
;
;
;
14
proof steps which may be revised and reused to provide alternative implementations. Thus the bene ts of our approach also includes these advantages.
Overview of maintenance methods The maintenance method we have devised can be summarized as follows: 1. Creation of a formal speci cation, either from user requirements, or from a reverse engineered application. 2. Development of the application (in the rst case), using the system to record the development and re nement steps. In the second case abstraction transformations will have been recorded during reverse engineering. 3. Translation of change requests on the application into change requests on the speci cation, using the links established in stages 1 and 2. 4. Implementation of these changes to the speci cation, with guidance for the user on the possible consequences of these changes throughout the system. 5. Regeneration of the application implementation from the changed speci cation, together with revised documentation. Formal speci cations are the central item of information here, bridging the gap between the informal but comprehensible user requirements, and the over-detailed formal description that is the source code. It is the level at which changes can most easily be eected.
Example of Approach In the following we illustrate the maintenance approach by considering a small speci cation, of a ship-loading system, in Z++ . This system consists of the basic components Ship and Compartment : CLASS OWNS
Compartment
height : METERS ; width : METERS ; max load : KILOS ; current load : KILOS ...
15
INVARIANT
current load max load
OPERATIONS
Add load : KILOS ! ; View load : ! KILOS ; Maximum load : ! KILOS ...
END CLASS
This component can be implemented directly in C code, via a suitable record with elds corresponding to the above attributes. In contrast, the Ship class requires a re nement step. This class has the form: CLASS Ship FUNCTIONS
j safe load distribution KILOS Compartment F(Compartment )
OWNS
s compartments : F(Compartment )
OPERATIONS
Load compartment : KILOS Compartment !; Add compartment : Compartment !
ACTIONS
Load compartment ll cc ==> cc 2 s compartments ^ (9 cl ; ml : KILOS cc :View load [cl =load ] ^ cc :Maximum load [ml =load ] ^ cl + ll ml ) ^ safe load distribution (ll ; cc ; s compartments ) ^ cc :Add load [ll =load ] ; Add compartment cc ==> cc 2= s compartments ^ s compartments 0 = s compartments [ f cc g
END CLASS
This class will itself be implemented by a re nement which makes use of a standard class for manipulating ( nite) set-valued variables: CLASS OWNS
Ship 1
f set : FINSET [Compartment ]
OPERATIONS
Load compartment : KILOS Compartment !
ACTIONS
Load compartment ll cc ==> f set :Is member [cc =value ] ^ (9 cl ; ml : KILOS cc :View load [cl =load ] ^
16
cc :Maximum load [ml =load ] ^ cl + ll ml ) ^ safe load distribution (ll ; cc ; f set :contents ) ^ cc :Add load [ll =load ] ; Add compartment cc ==> : f set :Is member [cc =value ] ^ f set :Add element [cc =value ]
END CLASS
The re nement relation is simply Ship vf
set :contents =s compartments
Ship1
Finally, we will have a System class which manipulates sets of ships. As a result of the formal development there exist several forms of information in the development record: 1. A relationship between domain terms and elements and items within the formal speci cation:
$ $
compartment Compartment ship Ship compartments of ship Ship :s compartments maximum loading of compartment Compartment :max load add load to compartment of ship Ship :Load compartment
$
$ $
2. An operation derivation graph, which records how operations are implemented in terms of other operations or accesses to state variables: Ship :Load compartment ;! Compartment :Add load ; Compartment :View load ; Compartment :Maximum load ; FINSET [Compartment ]:Is member ; FINSET [Compartment ]:contents Ship :Add compartment ;! FINSET [Compartment ]:Is member ; FINSET [Compartment ]:Add element
3. A module derivation graph, which records the usage of one speci cation module by others: Compartment ;!by composition Ship ;!re ned by Ship 1 FINSET [Compartment ] ;!by
Ship composition
17
Ship 1
If we now have a maintenance request, we can use these relationships to identify the speci cation components on which these changes must be eected. Particularly in the cases of adaptive and enhancement requests, these requests will be expressed in terms of the domain elements or implementation elements, rather than the intermediate design or speci cation components. For instance, if we have an enhancement request to add a new operation which lists all the compartments associated with a particular ship, we know that:
the operation refers to the domain concept `ship', which is speci ed by the Ship class, so that the operation is likely to be located in this class;
the operation refers to the domain concept of `all compartments of a given ship', which we know is speci ed by the variable s compartments . Thus, we have a high degree of con dence in the assertion that the operation requires a print-out of the value of this particular variable;
we know Ship is implemented by FINSET [Compartment ] via Ship 1, so that we need to identify an operation of this generic class which can implement the new operation. Finally, we have to update the development records by the addition of these new operations. This approach to maintenance has already been successfully adopted for the B formal method ALNSS91 , which is supported by tools for managing the software development life cycle, including automatic code generation from low-level designs. In one example of a development of a re nery database module carried out by BP, a substantial restructuring and reimplementation of 60% of the 20,000 line system was carried out within two person months, using the formally maintained links between speci cations, designs and implementations.
A formal model for maintenance and development A model of the maintenance and development process was also speci ed in Z++ 23, so providing a formal description of the proposed development and maintenance system outlined above. Conceptually, a software module or component can be considered to have several attributes: 1. A user requirement for its behaviour; 2. A speci cation of its behaviour; 3. A development history, a sequence or tree of re nements beginning with 2 and including 4: 18
4. A current re nement, together with logical relationships between these: that the speci cation satis es the requirement and that the descendants of a node in the development history re ne their ancestor. There are also characteristic operations, such as: 1. Apply a re nement rule to the current re nement; 2. Build a speci cation; 3. Select a new current re nement (i.e., start from a new direction in re ning the system), together with several others, which we will want to perform on the module. These attributes and operations are the basis of the meta-level class Software used in our development and maintenance system. In development we will typically begin with an empty development history, and only a user requirement, and work to ll in the other details; in reverse engineering we will have one or possibly more leaf nodes of the development tree, and we will want to work backwards to a useful speci cation and requirement (description) of the system. The items, such as speci cations, used as attributes of the Software class are themselves objects, with attributes like author , date , level 1 and so forth; these can be manipulated in their own right, and linked to several separate Software components. The object style thus gives great freedom and exibility in manipulating and recombining system descriptions: all we need to know about an object instance is its name, and we can then incorporate it as an attribute of a suitable higher-level object, subject to type constraints. For instance, in the reverse engineering of a program, we may derive information, such as a data- ow graph of the code, that we will reuse in several dierent operations (for example, the recognition of outline objects in the code, or in giving a data-complexity metric to the code) and we need to possess this information as a freely available entity, in addition to its use as an attribute of the Code type. The Software class is de ned in Figure 6. The set Law of re nement laws is the set of method identi ers used for re nement in the Code class. Each of these re nements needs certain parameters, which will be requested as part of an interactive process initiated within the Code class. At this level all that need be known is the name of the re nement operation. Another advantage of the object style of design is the enhanced security and maintenance of internal consistency of descriptions: we cannot change the attributes of a class instance in any way other than by its supplied methods, which may in addition require that certain conditions 19
are satis ed before they can change the class instance. In particular we cannot change the root of the development history without changing the speci cation , in an instance of the Software class. An outline of the Code class is given in Figure 7. In addition there are methods which perform re nements of the uniformcode attribute. All of the REDO tools operate on this representation level, implemented via a common database, the TBK (Eclipse) database. At the global level, there is a class which manages the user interaction; it possesses attributes currentS : Software , currentC : Code , and so forth; given a user request to perform a particular high level operation, it selects the appropriate current instance of Software , Code or Class , and the appropriate methods to apply to this instance to carry out the high-level operation.
Formalizing class transformations We can express transformations of code and speci cations as methods of the appropriate class. Class transformations, such as the addition of a new attribute, can be explicitly de ned: v 2= dom signature & Add New Attribute v t ==> signature 0 = signature [ f(v ; t )g
as methods of the class: CLASS OWNS
Class
name of class : Ident ; extends list : F Ident ; types of class : State ; signature : Sig ; instances : F Instances ; class invariant : Exp ; methods : F Method ; actslist : Actslist ; algebraic constraints : F Exp ; history : F Exp
OPERATIONS
...
END CLASS
Similarly transformations also apply for more complicated re ning operations, such as the replacement of a method by a more re ned method. As an example, we can consider the development of the `students who do exercises example' 22 to be carried out in this framework, as the successive application of rules to transform an abstract 20
set of requirements through an algebraic speci cation, to an abstract state-based speci cation, a concrete state-based speci cation, and a procedural pseudo-code description. The transformational paradigm for development Bau85 Bur91 Nei91 has been followed and expressed as the application of methods of object classes representing software and speci cation components. Other approaches, such as the reuse paradigm of Basili BC90 BC91 could be incorporated into the system, simply by allowing more types of software class, and providing operations which return metrics of reusability from these classes. Similar representations can be made for the reverse engineering process 23 . Formalizing the transformation of software allows us to formulate axioms and general properties that are satis ed by these transformations, and these can be veri ed using a precise semantics. For instance, the operations of adding distinct attributes can be performed in either order, with the same result: ;
;
;
8 C : Class ; v ; w : Ident ; t ; s : Ident j v 6= w
Add New Attribute (v ; t ; Add New Attribute (w ; s ; C )) = Add New Attribute (w ; s ; Add New Attribute (v ; t ; C ))
Similarly, if a method m does not mention an attribute v , then adding m after v yields the same class as adding v after m .
Summary We have presented a number of techniques which could be used in the software maintenance process, and for the reverse engineering of existing programs in particular. Research at Oxford University has concentrated on the formal aspects of work undertaken on the collaborative REDO project. In addition, we have produced a number of prototype tools, mostly using Prolog. These have been integrated around a common database with the other tools produced on the project. The overall toolset, or one similar to it, could eventually form the basis of a software maintainer's workbench. Industrial partners on the REDO project have integrated a considerable number of software maintenance tools onto a common platform (including those described in this paper). A signi cant number of publications have resulted directly from the work on the project and the most important of these are listed at the end of this paper. Our experience has convinced us that reverse engineering is essentially a human process requiring air and skill; tools can only aid the maintainer to gain an understanding of the code 21
more quickly, not fully automate the generation of a speci cation from an existing program. Once a speci cation is obtained, a new program may be re-engineered from it using one of the more standard and well understood development techniques. Even if a speci cation of a program is derived or is already available, this introduces the problem of maintaining the speci cation and keeping it in step with the program. This paper has presented a technique, based on an object-oriented version of the formal Z notation, known as Z++ , that could be used to aid the maintenance of programs. It is to be hoped that an increasing amount of software will be well speci ed in the future to allow such an approach to be adopted. The tools and methods developed on the REDO project have been further enhanced by the industrial partners of the consortium, particularly the University of Limerick, via their campus company, Piercom, and by Lloyd's Register. Subsequent projects, such as the DTI SREDM project and the REM Eureka project, are now extending the REDO methods. Investigation of maintenance techniques in the context of the B Abstract Machine Notation and Method is being performed in the UK DTI (Department of Trade and Industry) B User Trials project Sha92.
Acknowledgements We thank our colleagues on the ESPRIT II REDO project (no. 2487) for a stimulating and varied three years on the project. In particular, Howard Haughton of Lloyd's Register (London, UK), and Giorgos Papapanagiotakis, formally at CTC (Athens, Greece), have co-authored a number of reports and publications. Jonathan Bowen is funded by the UK Science and Engineering Research Council.
Project Publications and Reports Please note that copies of REDO project documents and PRG Technical Reports and Monographs are available from the Librarian at the Oxford University Computing Laboratory. [1] J.P. Bowen, P.T. Breuer, and K.C. Lano. A compendium of formal techniques for software maintenance. IEE/BCS Software Engineering Journal, 8(5), September 1993. [2] J.P. Bowen and P.T. Breuer. Decompilation. In H. van Zuylen, editor, The REDO Compendium: Reverse Engineering for Software Maintenance, chapter 9, pages 131{138. John Wiley, 1993.
22
[3] J.P. Bowen. From programs to object code and back again using logic programming: Compilation and decompilation. Journal of Software Maintenance: Research and Practice, to appear. [4] P.T. Breuer and J.P. Bowen. Decompilation: the enumeration of types and grammars. Technical Report PRG-TR-11-92, Oxford University Computing Laboratory, 11 Keble Road, Oxford, UK, May 1992. Provisionally accepted by ACM Transactions on Programming Languages and Systems (TOPLAS). [5] P.T. Breuer and J.P. Bowen. Decompilation is the ecient enumeration of types. In M. Billaud et al., editors, Journees de Travail WSA'92 Analyse Statique, volume BIGRE 81{82, pages 255{273, F-35042 Rennes cedex, France, 1992. IRISA-Campus de Beaulieu. [6] P.T. Breuer and K.C. Lano. Creating speci cations from code: Reverse engineering techniques. Journal of Software Maintenance: Research and Practice, 3:145{162, 1991. [7] K.C. Lano and H.P. Haughton. Extracting functionality and design from COBOL. In Proc. CASE'92. IEEE Press, 1992. [8] K.C. Lano. An axiomatic semantics of UNIFORM. REDO project document 2487-TN-PRG1011, Oxford University, UK, December 1991. [9] K.C. Lano. Intermediate language requirements and the design of UNIFORM. REDO project document 2487-TN-PRG-1014, Oxford University, UK, December 1991. [10] P.T. Breuer and K.C. Lano. Reverse engineering COBOL via formal methods. Journal of Software Maintenance: Research and Practice, 5(1):13{35, March 1993. [11] K.C. Lano, P.T. Breuer, and H.P. Haughton. Reverse engineering COBOL via formal methods. In H. van Zuylen, editor, The REDO Compendium: Reverse Engineering for Software Maintenance, chapter 16, pages 225{248. John Wiley, 1993. [12] K.C. Lano. The speci cation of a real time system in Z. REDO project document 2487-TNPRG-1015, Oxford University, UK, December 1991. [13] K.C. Lano. Z++ , an object-orientated extension to Z. In J.E. Nicholls, editor, Z User Workshop, Oxford 1990, Workshops in Computing, pages 151{172. Springer-Verlag, 1991. [14] K.C. Lano and H.P. Haughton. A speci cation-based approach to maintenance. Journal of Software Maintenance: Research and Practice, 3:193{214, December 1991. [15] K.C. Lano and P.T. Breuer. From programs to Z speci cations. In J.E. Nicholls, editor, Z User Workshop, Oxford 1989, Workshops in Computing, pages 46{70. Springer-Verlag, 1990. [16] J.P. Bowen. Select Z bibliography. In J.P. Bowen and J.E. Nicholls, editors, Z User Workshop, London 1992, Workshops in Computing, pages 309{341. Springer-Verlag, 1993. [17] K.C. Lano and H.P. Haughton. An algebraic semantics for the speci cation language Z++ . In Proc. Algebraic Methodology and Software Technology Conference (AMAST '91). SpringerVerlag, 1992. 23
[18] K.C. Lano and H.P. Haughton. Axiomatic semantics for object-orientated speci cation languages. In ZOOM Workshop, Oxford University, 11 Keble Road, Oxford, UK, August 1991. Preprint. [19] K.C. Lano and H.P. Haughton. Reasoning and re nement in object-oriented speci cation languages. In O.L. Madsen, editor, ECOOP '92: European Conference on Object-Oriented Programming, volume 615 of Lecture Notes in Computer Science, pages 78{97. SpringerVerlag, 1992. [20] K.C. Lano, P.T. Breuer, and H.P. Haughton. Reverse-engineering of library case study. REDO project document 2487-TN-PRG-1064, Oxford University, UK, May 1991. [21] K.C. Lano and H.P. Haughton. Using formal methods in arti cial intelligence. REDO project document 2487-TN-PRG-1070, Oxford University, UK, June 1991. [22] K.C. Lano, P.T. Breuer, and H.P. Haughton. Using object-oriented extensions of Z for maintenance and reverse-engineering. Technical Report PRG-TR-22-91, Oxford University Computing Laboratory, 11 Keble Road, Oxford, UK, December 1991. [23] K.C. Lano. Integrating development and maintenance in an object-orientated environment. REDO project document 2487-TN-PRG-1050, Oxford University, UK, October 1991.
Other References [ALNSS91] Abrial J.R., Lee M.K.O., Neilson D.S., Scharbach P.N., Srensen I.H., The B-method, in Prehn S., Toetenel W.J. (eds), VDM '91, Formal Software Development Methods, Volume 2: Tutorials, Springer-Verlag, Lecture Notes in Computer Science, 552, 1991, 398{405. [ABFP86] Arango G., Baxter I., Freeman P., Pidgeon C., TMM: Software Maintenance by Transformation, in Freeman P. (ed), TUTORIAL: Software Reusability, IEEE Computer Society, 1986. [BC90] Basili V.R., Caldiera G., Re-engineering Existing Software for Reusability, UMAICSTR-90-30, CS-TR-2419, University of Maryland, College Park, Maryland 20742, USA, 1990. [BC91] Basili V.R., Caldiera G., Identifying and qualifying reusable software components, IEEE Computer, February 1991, 61{70. [BAC91] Basili V.R., Abd-El-Ha z S.K., Caldiera G., Towards automated support for extraction of reusable components, Proceedings of IEEE Software Maintenance Conference, Sorrento, Italy, 1991. [Bau85] Bauer F.L., The Munich project CIP. Volume 1: the wide spectrum language CIP-L, Springer-Verlag, Lecture Notes in Computer Science, 183, 1985. [BM84] Boyle J.M., Muralidharan M.N., Program reusability through program transformation, IEEE Transactions on Software Engineering, SE-10 5, September 1984, 574{ 588. 24
[BP86]
Broy M., Pepper P., Program development as a formal activity, in Rich C., Waters R.C. (eds), Readings in A.I. and Software Engineering, Morgan Korfmann, 1986, 123{132. [Bur91] Burton C.T.P., Veri cation and Transformation of Simple Recursive Programs { an Algebraic Approach, in Neumann B., Simpson D., Slater G. (eds), Mathematical Structures for Software Engineering, The Institute of Mathematics and its Applications Conference Series 27, Clarendon Press, Oxford, 1991. [CM87] Clocksin W.F., Mellish C.S., Programming in Prolog, Springer-Verlag, 3rd edition, 1987. [GL91] Gallagher K.B., Lyle J.R., Program slicing in software maintenance, IEEE Transactions on Software Engineering, 17 8, August 1991, 751{761. [Gog91] Goguen J., An algebraic approach to re nement, in Bjrner D., Hoare C.A.R., Langmaack H. (eds), VDM'90: VDM and Z { Formal Methods in Software Development, Springer-Verlag, Lecture Notes in Computer Science, 428, 1991. [Jac90] Jacobs P., Software Metrics, REDO project document 2487-TN-UL-1020, University of Limerick, Ireland, 1990. [LH93a] Lano K.C., Haughton H., Integrating formal and structured methods in reverse engineering, IEEE Workshop on Reverse Engineering, IEEE Computer Society Press, 1993. [LH93b] Lano K.C., Haughton H., Reverse Engineering and Software Maintenance: A Practical Approach, McGraw-Hill International Series in Software Engineering, 1993. [Leh80] Lehman M.M., Programs, life cycles, and laws of software evolution, Proc. IEEE, 68 9, 1980, 1060{1076. [LPW88] Leonard J., Pardoe J., Wade S., Software maintenance { Cinderella is still not getting to the Ball, in Proc. Second IEE/BCS Conference: Software Engineering 88, Conference Publication No. 290, 1988, 104{106. [LHPH90] Linger R.C., Hausler P.A., Pleszlioch M.G., Heruer A.R., Using function abstraction to understand program behavior, IEEE Software, January 1990. [Mey88] Meyer B., Object-Oriented Software Construction, Prentice Hall, 1988. [Mey90] Meyer B., Tools for the new culture: Lessons from the design of the Eiel libraries, Communications of the ACM, 33 9, September 1990. [Mor90] Morgan C.C., Programming from Speci cations, Prentice Hall International Series in Computer Science, 1990. [MRG88] Morgan C.C., Robinson K.A., Gardiner P.H.B., On The Re nement Calculus, Technical Monograph PRG-70, Programming Research Group, Oxford University, October 1988. [Nei84] Neighbors J.M., The Draco approach to constructing software from reusable components, IEEE Transactions on Software Engineering, 10, September 1984, 564{574. 25
[Nei91]
Neilson D., Machine support for Z: the zedB tool, in Nicholls J. (ed), Z User Workshop, Oxford 1990, Springer-Verlag, Workshops in Computing, 1991, 105{128. [PS83] Partsch A., Steinbruggen R., Program transformation systems, Computing Surveys, 15 3, September 1983, 199{236. [Phi90] Phillips M., CICS/ESA 3.1 experience, in Nicholls J. (ed), Z User Workshop, Oxford 1989, Springer-Verlag, Workshops in Computing, 1990, 179{185. [Sch87] Schneidewind N.F., The state of software maintenance, IEEE Transactions on Software Engineering, SE-13 3, March 1987, 303{310. [Sha92] Shaw R., B User Trials Proposal, Lloyd's Register, BUT/Lloyd's/RCS/1/v9, August 1992. [Smi91] Smit E.Y.M., Method for User Interface Analysis and Redesign, REDO project document 2487-TN-WL-1071, Delft Hydraulics, Research and Development, PO Box 177, 2600 MH Delft, The Netherlands, August 1991. [Spi92] Spivey J.M., The Z Notation: A Reference Manual, 2nd edition, Prentice Hall International Series in Computer Science, 1992. [SC90] Stanley-Smith C., Cahill A., UNIFORM: A Language Geared to System Description and Transformation, University of Limerick, Ireland, 1990. [SBC92] Stepney S., Barden R., Cooper D. (eds), Object Orientation in Z, Springer-Verlag, Workshops in Computing, 1992. [vanZ92] van Zuylen H. (ed), The REDO Compendium: Reverse Engineering for Software Maintenance, John Wiley & Sons, 1993. [WCM89] Ward M., Calliss F.W., Munro M., The maintainer's assistant, Proceedings of Conference on Software Maintenance 1989, Miami, Florida, IEEE Computer Society Press, New York, 1989, 307{315. [Zim90] Zimmer J.A., Restructuring for style, Software|Practice and Experience, 20 4, 365{ 389, 1990.
26
Structured design representations
Design refinement
Z++
Design
Control / Data flow analysis
abstraction
UNIFORM representation Language independent metrics
(in Prolog and TBK database) Language specific metrics
Language translation
COBOL
FORTRAN
Schema
Schema
Language specific schemas ...
Loading
COBOL
FORTRAN
Other sources ...
Figure 1: A process model for reverse engineering from source code to speci cations. 27
COBOL
UNIFORM
DATA DIVISION. WORKING-STORAGE SECTION. 02 X PIC 99.
X : N [0-10^2]
...
begin pd section
...
...
PROCEDURE DIVISION. pd SECTION.
X := 0
...
...
MOVE 0 TO X
end
... Figure 2: Abstraction of COBOL data structures to UNIFORM ones: the layout information in the PIC 99 declaration is ignored in the UNIFORM X:N declaration (the [0-10^2] is an advisory).
UNIFORM
Equational Representation
X : N [0-10^2] begin pd section para p1 X := 0; perform thru p2, p3, p4; endpara p1; para p2 perform p3; endpara p2; para p3 X := X+1; if (X = 5) then X := 0; endpara p3; para p4 X := X + 3; endpara p4 end
pd(X) p1(X) p2(X) p3(X) p4(X)
= = = = =
p1(X) p2(5) (X+1=5) (X+1=5) X+3
! p3(0), p3(X+1) ! p4(0), p4(X+1)
)
pd(X) = 10
Figure 3: Abstraction of UNIFORM procedural control ow to a low-level functional language in which the paragraphs are represented as functions on the state, X. The notation e ! a ; b is a conditional; a if e holds, else b . The deduction that pd(X)=10 is immediate on using the toolset to substitute through.
28
1. Substitution of a function body for its calls (unfolding); 2. Eliminating recursion by recognizing an iteration form (meta-folding); 3. Adding in new equations, either as properties to be proved (lemmas), or as assumptions to simplify the description (hypotheses); 4. Using invariants or other equations to substitute one expression for another inside a function description (generalized folding); 5. Renaming a function; 6. Deleting a function; 7. Proving properties of a function; 8. Normalization; 9. Step-by-step retraction of normalizations; 10. Undo. Figure 4: Top-level menu of operations on equational speci cations.
29
Object Class
::= CLASS Identi er TypeParameters [EXTENDS Imported ] [TYPES Types ] [FUNCTIONS Axdefs ] [OWNS Locals ] [RETURNS Optypes ] [OPERATIONS Optypes ] [INVARIANT Predicate ] [ACTIONS Acts ] [CONSTRAINTS Constraints ] [HISTORY History ] END CLASS
TypeParameters ::= [ \[" Parlist \]" ]
::= Identi er [; Parlist ] j Identi er Identi er [; Parlist ] Imported ::= Idlist Types ::= Type Declarations Locals ::= Identi er : Type ; Locals j Identi er : Type Optypes ::= Identi er : Idlist ! Idlist ; Optypes j Identi er : Idlist ! Idlist Acts ::= [Expression &] Identi er Idlist ==> Code ; Acts j [Expression &] Identi er Idlist ==> Code Constraints ::= Equation j Equation ; Constraints History ::= FmlaLTL Parlist
Figure 5: BNF description of a Z++ class declaration.
30
CLASS OWNS
Software
requirement : FormalText ; speci cation : Class ; developmenth : tree [Code ]; currentcode : Code
INVARIANT
(; speci cation ) ) meaning (requirement ) 8 x : (nodes developmenth ) 8 y : descendants x y re nes x (root developmenth ) re nes speci cation currentcode 2 (nodes developmenth )
RETURNS
Ancestors : Code ! seq Code ;
OPERATIONS
Re ne : Law Input ! ; InitiateR : FormalText ! InitiateS : Class !
;
ACTIONS
Ancestors a ==> ancestors (developmenth ; a ) ; InitiateR req ==> requirement 0 = (INITIATE req ) requirement ^ speci cation 0 = INITIATE NULL speci cation ; InitiateS spec ==> requirement 0 = (INITIATE spec ) requirement ^ speci cation 0 = (INITIATE spec ) speci cation ^ 9 dd 0 : Code dd 0 = (INITIATE spec ) (root developmenth ) ^ developmenth 0 = f dd 0 7! ? g; Re ne law inputs ==> currentcode 0 = (law inputs ) currentcode ^ developmenth 0 = (Add Descendant currentcode 0 currentcode ) developmenth
END CLASS
Figure 6: Software class.
31
CLASS OWNS
Code
cobolcode : CCode ; uniformcode : UCode ; funcabstraction : FAbs ; data ow : WeightedGraph
OPERATIONS
InitiateC : CCode ! InitiateU : UCode ! CobolToUni : ! ; Abstract : ! ; Data ow : !
; ;
ACTIONS
CobolToUni ==> uniformcode 0 = convert cobol to uniform (cobolcode ); Abstract ==> funcabstraction 0 = abstraction (uniformcode ); Data ow ==> data ow 0 = data view (uniformcode )
END CLASS
Figure 7: Code class.
32