116 87 10MB
English Pages 1875 [955] Year 1999
Lecture Notes in Computer Science Edited by G. Goos, J. Hartmanis and J. van Leeuwen
1709
3
Berlin Heidelberg New York Barcelona Hong Kong London Milan Paris Singapore Tokyo
Jeannette M. Wing Jim Woodcock Jim Davies (Eds.)
FM’99 – Formal Methods World Congress on Formal Methods in the Development of Computing Systems Toulouse, France, September 20-24, 1999 Proceedings, Volume II
13
Series Editors Gerhard Goos, Karlsruhe University, Germany Juris Hartmanis, Cornell University, NY, USA Jan van Leeuwen, Utrecht University, The Netherlands Volume Editors Jeannette M. Wing Carnegie Mellon University, Computer Science Department 5000 Forbes Avenue, Pittsburgh, PA 15213, USA E-mail: [email protected] Jim Woodcock Jim Davies Oxford University Computing Laboratory Software Engineering Programme Wolfson Building, Parks Road, Oxford OX1 3QD, UK E-mail: {jim.woodcock,jim.davies}@comlab.ox.ac.uk
Cataloging-in-Publication data applied for
Die Deutsche Bibliothek - CIP-Einheitsaufnahme Formal methods : proceedings / FM ’99, World Congress on Formal Methods in the Development of Computing Systems, Toulouse, France, September 20 - 24, 1999 / Jeannette M. Wing . . . (ed.). - Berlin ; Heidelberg ; New York ; Barcelona ; Hong Kong ; London ; Milan ; Paris ; Singapore ; Tokyo : Springer Vol. 2. - (1999) (Lecture notes in computer science ; Vol. 1709) ISBN 3-540-66588-9
CR Subject Classification (1998): F.3, D.2, F.4.1, D.3, D.1, C.2, C.3, I.2.3, B, J.2 ISSN 0302-9743 ISBN 3-540-66588-9 Springer-Verlag Berlin Heidelberg New York This work is subject to copyright. All rights are reserved, whether the whole or part of the material is concerned, specifically the rights of translation, reprinting, re-use of illustrations, recitation, broadcasting, reproduction on microfilms or in any other way, and storage in data banks. Duplication of this publication or parts thereof is permitted only under the provisions of the German Copyright Law of September 9, 1965, in its current version, and permission for use must always be obtained from Springer-Verlag. Violations are liable for prosecution under the German Copyright Law. © Springer-Verlag Berlin Heidelberg 1999 Printed in Germany Typesetting: Camera-ready by author SPIN: 10705018 06/3142 – 5 4 3 2 1 0
Printed on acid-free paper
Preface
Formal methods are coming of age. Mathematical techniques and tools are now regarded as an important part of the development process in a wide range of industrial and governmental organisations. A transfer of technology into the mainstream of systems development is slowly, but surely, taking place. FM’99, the First World Congress on Formal Methods in the Development of Computing Systems, is a result, and a measure, of this new-found maturity. It brings an impressive array of industrial and applications-oriented papers that show how formal methods have been used to tackle real problems. These proceedings are a record of the technical symposium of FM’99 : alongside the papers describing applications of formal methods, you will find technical reports, papers, and abstracts detailing new advances in formal techniques, from mathematical foundations to practical tools. The World Congress is the successor to the four Formal Methods Europe Symposia, which in turn succeeded the four VDM Europe Symposia. This succession reflects an increasing openness within the international community of researchers and practitioners: papers were submitted covering a wide variety of formal methods and application areas. The programme committee reflects the Congress’s international nature, with a membership of 84 leading researchers from 38 different countries. The committee was divided into 19 tracks, each with its own chair to oversee the reviewing process. Our collective task was a difficult one: there were 259 high-quality submissions from 35 different countries. Each paper was reviewed within a track, the track chairs resolved conflicts between reviewers, and the recommendations of each track chair were considered by the executive programme committee. This resulted in 92 papers being accepted, along with 15 abstracts describing work in progress and industrial applications. We thank all those members of the programme and organising committees for their hard work, carried out under necessarily short deadlines. Thanks are due also to our able administrators, Maureen York and Anna Curtis; they did an excellent job and they deserve our gratitude for their contribution. Finally, thanks to all those who submitted papers and attended the Congress: it is your hard work that has made it such a timely and important event.
July 1999
Jeannette Wing Jim Woodcock Jim Davies
Technical Tracks The tracks that structure the technical symposium may be divided into three groups. First, there are application areas: • • •
Avionics Co-design Open information systems
• • •
Safety Security Telecommunications
Second, there are processes and techniques: • • • •
Composition and synthesis Integration Model checking Software architecture
• • • •
Object orientation Program verification Refinement Testing
Finally, there are groups of users and researchers: • • • •
European Association for Theoretical Computer Science Foundations of System Specification Formal Description of Programming Concepts Abstract State Machines
• • • •
European Theory and Practice of Software Algebraic Methods in Software Technology OBJ / CafeOBJ / Maude The B method
Our five distinguished invited speakers are Tony Hoare of the University of Oxford, Cliff Jones of the University of Manchester, Amir Pnueli of the Weizmann Institute, Joseph Sifakis of Verimag, John Rushby of SRI International, and Michael Jackson, independent consultant.
Symposium Committee Keijiro Araki, Japan Egidio Astesiano, Italy Albert Benveniste, France Didier Bert, France Dines Bjørner, Denmark Robin Bloomfield, UK Dominique Bolignano, France Egon B¨orger, Italy Jonathan Bowen, UK Wilfried Brauer, Germany Ed Brinksma, NL Manfred Broy, Germany Andrew Butterfield, Ireland Jacques Cazin, France Edmund Clarke, USA Dan Craigen, Canada Jorge Cu´ellar, Germany Aristides Dasso, Argentina Jim Davies, UK Tim Denvir, UK Jin Song Dong, Singapore Steve Dunne, UK Hartmut Ehrig, Germany John Fitzgerald, UK Laure Pauline Fotso, Cameroon Birgitte Fr¨ohlich, Austria Kokichi Futatsugi, Japan David Garlan, USA Marie-Claude Gaudel, France Chris George, Macau David Gries, USA Henri Habrias, France Armando Haeberer, Brazil Nicolas Halbwachs, France Kirsten Mark Hansen, Denmark Anne Haxthausen, Denmark Ian Hayes, Australia Rick Hehner, Canada Val´erie Issarny, France Rene Jacquart, France Randolph Johnson, USA Bengt Jonsson, Sweden Leonid Kalinichenko, Russia Kanchana Kanchanasut, Thailand
Kyo Chul Kang, Korea Marite Kirikova, Latvia Derrick Kourie, South Africa Souleymane Koussoube, Burkina Faso Reino Kurki-Suonio, Finland Axel van Lamsweerde, Belgium Jean-Claude Laprie, France Peter Gorm Larsen, Denmark Shaoying Liu, Japan Peter Lucas, Austria Micheal Mac an Airchinnigh, Ireland Tom Maibaum, UK Zohar Manna, USA Lynn Marshall, Canada Kees Middelburg, NL Markus Montigel, Austria Peter Mosses, Denmark Friederike Nickl, Germany Nikolai Nikitchenko, Ukraine Roger Noussi, Gabon Ernst-R¨ udiger Olderog, Germany Jos´e Nuno Oliveira, Portugal Fernando Orejas, Spain Paritosh Pandya, India Jan Peleska, Germany Frantisek Pl´ asil, Czech Republic Igor Pr´ıvara, Slovakia Hans Rischel, Denmark Ken Robinson, Australia Teodor Rus, USA Augusto Sampaio, Brazil Georgy Satchock, Belarus Kaisa Sere, Finland Natarajan Shankar, USA Joseph Sifakis, France Doug Smith, USA Radu Soricut, Rumania Andrzej Tarlecki, Poland T.H. Tse, Hong Kong Bogdan Warinski, Rumania Jeannette Wing, USA Jim Woodcock, UK Pamela Zave, USA Zhou Chaochen, Macau
VIII
Congress Organisation
Congress General Chair Dines Bjørner Programme Committee Co-chairs Jeannette Wing and Jim Woodcock Organisation Committee Chair Rene Jacquart Local Organisation and Publicity Jacques Cazin Congress Public Relations Officer Jonathan Bowen
Congress Sponsors AMAST A´erospatiale Airbus Alcatel Space CCIT CEPIS CNES CNRS Cap Gemini Carnegie-Mellon University Conseil Regional Midi-Pyrenees DGA EATCS ESA ETAPS European Union FACS FME
France Telecom IFIP INRIA IPSJ IRIT JSSST LAAS Mairie de Toulouse Matra Marconi Space ONERA Technical University of Delft Technical University of Denmark Technical University of Graz Translimina University of Oxford University of Reading
Table of Contents
IX
Table of Contents Foundations of System Specification (IFIP WG 1.3) From Informal Requirements to COOP: A Concurrent Automata Approach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 939 P. Poizat, C. Choppy, and J.-C. Royer A Framework for Defining Object-Calculi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 963 F. Lang, P. Lescanne, and L. Liquori
European Theory and Practice of Software (ETAPS) A Translation of Statecharts to Esterel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 983 S. A. Seshia, R. K. Shyamasundar, A. K. Bhattacharjee, and S. D. Dhodapkar An Operational Semantics for Timed RAISE . . . . . . . . . . . . . . . . . . . . . . . . . .1008 X. Yong and C. George Data Abstraction for CSP-OZ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1028 H. Wehrheim Systems Development Using Z Generics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1048 F. Polack and S. Stepney A Brief Summary of VSPEC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1068 P. Alexander, M. Rangarajan, and P. Baraona Enhancing the Pre- and Postcondition Technique for More Expressive Specifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1087 G. T. Leavens and A. L. Baker
Program Verification On Excusable and Inexcusable Failures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1107 M. M¨ uller-Olm and A. Wolf Interfacing Program Construction and Verification . . . . . . . . . . . . . . . . . . . . .1128 R. Verhoeven and R. Backhouse Software Verification Based on Linear Programming . . . . . . . . . . . . . . . . . . .1147 S. Dellacherie, S. Devulder, and J.-L. Lambert
X
Table of Contents
Integration of Notation and Techniques Sensors and Actuators in TCOZ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1166 B. Mahony and J. S. Dong The UniForM Workbench, a Universal Development Environment for Formal Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1186 B. Krieg-Br¨ uckner, J. Peleska, E.-R. Olderog, and A. Baer Integrating Formal Description Techniques . . . . . . . . . . . . . . . . . . . . . . . . . . .1206 B. Sch¨ atz and F. Huber Formal Description of Programming Concepts (IFIP WG 2.2) A More Complete TLA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1226 S. Merz Formal Justification of the Rely-Guarantee Paradigm for Shared-Variable Concurrency: A Semantic Approach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1245 F. S. de Boer, U. Hannemann, and W.-P. de Roever Relating Z and First-Order Logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1266 A. Martin Open Information Systems Formal Modeling of the Enterprise JavaBeansTM Component Integration Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1281 J. P. Sousa and D. Garlan Developing Components in the Presence of Re-entrance . . . . . . . . . . . . . . . .1301 L. Mikhajlov, E. Sekerinski, and L. Laibinis Communication and Synchronisation Using Interaction Objects . . . . . . . . .1321 H. B. M. Jonkers Modelling Microsoft COM Using π-Calculus . . . . . . . . . . . . . . . . . . . . . . . . . .1343 L. M. G. Feijs
Co-design Validation of Mixed Signal-Alpha Real-Time Systems through Affine Calculus on Clock Synchronisation Constraints . . . . . . . . . . . . . . . . . . . . . . . .1364 I. M. Smarandache, T. Gautier, and P. Le Guernic
Table of Contents
XI
Combining Theorem Proving and Continuous Models in Synchronous Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1384 S. Nadjm-Tehrani and O. ˚ Akerlund ParTS: A Partitioning Transformation System . . . . . . . . . . . . . . . . . . . . . . . .1400 J. Iyoda, A. Sampaio, and L. Silva A Behavioral Model for Co-design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1420 J. He Refinement A Weakest Precondition Semantics for an Object-Oriented Language of Refinement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1439 A. Cavalcanti and D. A. Naumann Reasoning About Interactive Systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1460 R. Back, A. Mikhajlova, and J. von Wright Non-atomic Refinement in Z . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1477 J. Derrick and E. Boiten Refinement Semantics and Loop Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1497 E. C. R. Hehner and A. M. Gravell Safety Lessons from the Application of Formal Methods to the Design of a Storm Surge Barrier Control System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1511 M. Chaudron, J. Tretmans, and K. Wijbrans The Value of Verification: Positive Experience of Industrial Proof . . . . . . . .1527 S. King, J. Hammond, R. Chapman, and A. Pryor Formal Development and Verification of a Distributed Railway Control System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1546 A. E. Haxthausen and J. Peleska Safety Analysis in Formal Specification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1564 K. Sere and E. Troubitsyna Formal Specification and Validation of a Vital Communication Protocol . .1584 A. Cimatti, P. L. Pieraccini, R. Sebastiani, P. Traverso, and A. Villafiorita Incremental Design of a Power Transformer Station Controller Using a Controller Synthesis Methodology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1605 H. Marchand and M. Samaan
XII
Table of Contents
OBJ/Cafe OBJ/Maude Verifying Behavioural Specifications in CafeOBJ Environment . . . . . . . . . .1625 A. Mori and K. Futatsugi Component-Based Algebraic Specification and Verification in CafeOBJ . . .1644 R. Diaconescu, K. Futatsugi, and S. Iida Using Algebraic Specification Techniques in Development of Object-Oriented Frameworks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1664 S. Nakajima Maude as a Formal Meta-tool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1684 M. Clavel, F. Dur´ an, S. Eker, J. Meseguer, and M.-O. Stehr Hiding More of Hidden Algebra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1704 J. Goguen and G. Ro¸su
Abstract State Machines (ASM) and Algebraic Methods in Software Technology (AMAST) A Termination Detection Algorithm: Specification and Verification . . . . . .1720 R. Eschbach Logspace Reducibility via Abstract State Machines . . . . . . . . . . . . . . . . . . . .1738 E. Gr¨ adel and M. Spielmann Formal Methods for Extensions to CAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1758 M. N. Dunstan, T. Kelsey, U. Martin, and S. Linton An Algebraic Framework for Higher-Order Modules . . . . . . . . . . . . . . . . . . . .1778 R. Jim´enez and F. Orejas
Avionics Applying Formal Proof Techniques to Avionics Software: A Pragmatic Approach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1798 F. Randimbivololona, J. Souyris, P. Baudin, A. Pacalet, J. Raguideau, and D. Schoen Secure Synthesis of Code: A Process Improvement Experiment . . . . . . . . . .1816 P. Garbett, J. P. Parkes, M. Shackleton, and S. Anderson Cronos: A Separate Compilation Toolset for Modular Esterel Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1836 ´ Nassor O. Hainque, L. Pautet, Y. Le Biannic, and E.
Table of Contents
XIII
Works-in-Progress Tool Support for Production Use of Formal Techniques . . . . . . . . . . . . . . . . .1854 J. C. Knight, P. T. Fletcher, and B. R. Hicks Modeling Aircraft Mission Computer Task Rates . . . . . . . . . . . . . . . . . . . . . .1855 J. S. Dong, B. P. Mahony, and N. Fulton A Study of Collaborative Work: Answers to a Test on Formal Specification in B . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1856 H. Habrias, P. Poizat, and J.-Y. Lafaye Archived Design Steps in Temporal Logic . . . . . . . . . . . . . . . . . . . . . . . . . . . .1858 P. Kellom¨ aki and T. Mikkonen A PVS-Based Approach for Teaching Constructing Correct Iterations . . . .1859 M. L´evy and L. Trilling A Minimal Framework for Specification Theory . . . . . . . . . . . . . . . . . . . . . . .1861 B. Baumgarten A Model of Specification-Based Testing of Interactive Systems . . . . . . . . . .1862 I. MacColl and D. Carrington Algebraic Aspects of the Mapping between Abstract Syntax Notation One and CORBA IDL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1863 R. Ocic˘ a and D. Ionescu Retrenchment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1864 R. Banach and M. Poppleton Proof Preservation in Component Generalization . . . . . . . . . . . . . . . . . . . . . .1866 A. M. Moreira Industrial Experience Formal Modelling and Simulation of Train Control Systems Using Petri Nets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1867 M. Meyer zu H¨ orste and E. Schnieder Formal Specification of a Voice Communication System Used in Air Traffic Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1868 J. H¨ orl and B. K. Aichernig Model-Checking the Architectural Design of a Fail-Safe Communication System for Railway Interlocking Systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1869 B. Buth and M. Schr¨ onen
XIV
Table of Contents
Analyzing the Requirements of an Access Control Using VDMTools and PVS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1870 G. Droschl Cache Coherence Verification with TLA+ . . . . . . . . . . . . . . . . . . . . . . . . . . . .1871 H. Akhiani, D. Doligez, P. Harter, L. Lamport, J. Scheid, M. Tuttle, and Y. Yu Author Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1873
Table of Contents, Volume I
XV
Table of Contents, Volume I Invited Papers Theories of Programming: Top-Down and Bottom-Up Meeting in the Middle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C. A. R. Hoare
1
Scientific Decisions which Characterise VDM . . . . . . . . . . . . . . . . . . . . . . . . . . 28 C. B. Jones Mechanized Formal Methods: Where Next? . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 J. Rushby Integration, the Price of Success . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 J. Sifakis The Role of Formalism in Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 M. Jackson Integration into the Development Process Formal Design for Automatic Coding and Testing: The ESSI/SPACES Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 E. Conquet and J.-L. Marty A Business Process Design Language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 H. Eertink, W. Janssen, P. O. Luttighuis, W. Teeuw, and C. Vissers
Software Architecture Refinement of Pipe-and-Filter Architectures . . . . . . . . . . . . . . . . . . . . . . . . . . 96 J. Philipps and B. Rumpe A Formalization of Software Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 J. Herbert, B. Dutertre, R. Riemenschneider, and V. Stavridou
European Association for Theoretical Computer Science (EATCS) Component and Interface Refinement in Closed-System Specifications . . . . 134 R. Kurki-Suonio Semantics of First Order Parametric Specifications . . . . . . . . . . . . . . . . . . . . 155 D. Pavlovi´c
XVI
Table of Contents, Volume I
Model Checking A Perfecto Verification: Combining Model Checking with Deductive Analysis to Verify Real-Life Software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 Y. Kesten, A. Klein, A. Pnueli, and G. Raanan Error Detection with Directed Symbolic Model Checking . . . . . . . . . . . . . . . 195 F. Reffel and S. Edelkamp Formal Modeling and Analysis of Hybrid Systems: A Case Study in Multi-robot Coordination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212 R. Alur, J. Esposito, M. Kim, V. Kumar, and I. Lee On-the-Fly Controller Synthesis for Discrete and Dense-Time Systems . . . 233 S. Tripakis and K. Altisen On-the-Fly Verification of Linear Temporal Logic . . . . . . . . . . . . . . . . . . . . . . 253 J.-M. Couvreur Symbolic Model Checking with Fewer Fixpoint Computations . . . . . . . . . . . 272 D. D´eharbe and A. M. Moreira Formula Based Abstractions of Transition Systems for Real-Time Model Checking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289 R. Barbuti, N. De Francesco, A. Santone, and G. Vaglini IF: An Intermediate Representation and Validation Environment for Timed Asynchronous Systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 M. Bozga, J.-C. Fernandez, L. Ghirvu, S. Graf, J.-P. Krimm, and L. Mounier Automatic Verification of Pointer Data-Structure Systems for All Numbers of Processes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328 F. Wang
The B Method The Use of the B Formal Method for the Design and the Validation of the Transaction Mechanism for Smart Card Applications . . . . . . . . . . . . . . . 348 D. Sabatier and P. Lartigue M´et´eor: A Successful Application of B in a Large Project . . . . . . . . . . . . . . . 369 P. Behm, P. Benoit, A. Faivre, and J.-M. Meynadier Formal Development of Databases in ASSO and B . . . . . . . . . . . . . . . . . . . . . 388 B. Matthews and E. Locuratolo
Table of Contents, Volume I
XVII
Interpreting the B-Method in the Refinement Calculus . . . . . . . . . . . . . . . . . 411 Y. Rouzaud Compositional Symmetric Sharing in B . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431 M. B¨ uchi and R. Back Structural Embeddings: Mechanization with Method . . . . . . . . . . . . . . . . . . . 452 C. Mu˜ noz and J. Rushby The Safe Machine: A New Specification Construct for B . . . . . . . . . . . . . . . . 472 S. Dunne csp2B: A Practical Approach to Combining CSP and B . . . . . . . . . . . . . . . . 490 M. Butler Test Criteria Definition for B Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509 S. Behnia and H. Waeselynck
Composition and Synthesis Bunches for Object-Oriented, Concurrent, and Real-Time Specification . . . 530 R. F. Paige and E. C. R. Hehner Applications of Structural Synthesis of Programs . . . . . . . . . . . . . . . . . . . . . . 551 E. Tyugu, M. Matskin, and J. Penjam Towards a Compositional Approach to the Design and Verification of Distributed Systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 570 M. Charpentier and K. M. Chandy
Telecommunications Formal Modeling in a Commercial Setting: A Case Study . . . . . . . . . . . . . . . 590 A. Wong and M. Chechik KVEST: Automated Generation of Test Suites from Formal Specifications 608 I. Burdonov, A. Kossatchev, A. Petrenko, and D. Galter Feature Interaction Detection Using Testing and Model-Checking Experience Report . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 622 L. du Bousquet Emma: Developing an Industrial Reachability Analyser for SDL . . . . . . . . . 642 N. Husberg and T. Manner Correction Proof of the Standardized Algorithm for ABR Conformance . . 662 J.-F. Monin and F. Klay
XVIII Table of Contents, Volume I
Verifying a Distributed Database Lookup Manager Written in Erlang . . . . 682 T. Arts and M. Dam Security Secure Interoperation of Secure Distributed Databases . . . . . . . . . . . . . . . . . 701 F. Gilham, R. A. Riemenschneider, and V. Stavridou A Formal Security Model for Microprocessor Hardware . . . . . . . . . . . . . . . . . 718 V. Lotz, V. Kessler, and G. Walter Abstraction and Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 738 S. Schneider Formal Analysis of a Secure Communication Channel: Secure Core-Email Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 758 D. Zhou and S.-K. Chin Probabilistic Polynomial-Time Equivalence and Security Analysis . . . . . . . 776 P. Lincoln, J. Mitchell, M. Mitchell, and A. Scedrov A Uniform Approach for the Definition of Security Properties . . . . . . . . . . . 794 R. Focardi and F. Martinelli Group Principals and the Formalization of Anonymity . . . . . . . . . . . . . . . . . 814 P. F. Syverson and S. G. Stubblebine
Object-Orientation Developing BON as an Industrial-Strength Formal Method . . . . . . . . . . . . . 834 R. F. Paige and J. S. Ostroff On the Expressive Power of OCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 854 L. Mandel and M. V. Cengarle A Systematic Approach to Transform OMT Diagrams to a B Specification 875 E. Meyer and J. Souqui`eres
Testing Verifying Consistency and Validity of Formal Specifications by Testing . . . 896 S. Liu A GSM-MAP Protocol Experiment Using Passive Testing . . . . . . . . . . . . . . 915 M. Tabourier, A. Cavalli, and M. Ionescu Author Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 935
From Informal Requirements to COOP: A Concurrent Automata Approach Pascal Poizat1 , Christine Choppy2 , and Jean-Claude Royer1 1
IRIN, Universit´e de Nantes & Ecole Centrale 2 rue de la Houssini`ere, B.P. 92208, F-44322 Nantes cedex 3, France {Poizat, Royer}@irin.univ-nantes.fr http://www.sciences.univ-nantes.fr/info/perso/permanents/poizat/ phone: +33 2 51 12 58 22 — fax: +33 2 51 12 58 12 2 LIPN, Institut Galil´ee - Universit´e Paris XIII, Avenue Jean-Baptiste Cl´ement, F-93430 Villetaneuse, France [email protected]
Abstract. Methods are needed to help using formal specifications in a practical way. We herein present a method for the development of mixed systems, i.e. systems with both a static and a dynamic part. Our method helps the specifier providing means to structure the system in terms of communicating subcomponents and to give the sequential components using a semi-automatic concurrent automata generation with associated algebraic data types. These components and the whole system may be verified using common set of tools for transition systems or algebraic specifications. Furthermore, our method is equipped with object oriented code generation in Java, to be used for prototyping concerns. In this paper, we present our method on a small example: a transit node component in a communication network. Keywords: Concurrent systems, specification method, automata, object oriented (Java) code generation.
Stream: Foundations and Methodology Mini-Track: FoSS (Foundations of Software Specifications)
1
Introduction
The use of formal specifications is now widely accepted in software development. Formal specifications are mainly useful to provide an abstract, rigorous and complete description of a system. They are also essential to prove properties, to prototype the system and to generate tests. The need for a method that helps and guides the specifier is another well-known fact. A last point is the need for mixed specifications: i.e. specifications able to describe both the dynamic (process control) and the static aspects (data types). We think that mixed specifications also enable, at a specification level, to have a clear separation of concerns between these two aspects of systems that should be orthogonal as J. Wing, J. Woodcock, J. Davies (Eds.): FM’99, Vol. II, LNCS 1709, pp. 939–962, 1999. c Springer-Verlag Berlin Heidelberg 1999
940
Pascal Poizat, Christine Choppy, and Jean-Claude Royer
advocated (at the implementation level) by recent Concurrent Object Oriented Programming (COOP) research. We herein present a method based on LOTOS [7, 20] and SDL1 [11] experiences [25, 24]. Our method was first presented in [26] and is here elaborated in terms of agenda and extended to Java code generation. We chose to describe our method in terms of the agenda concept [17, 16] because it describes a list of activities for solving a task in software engineering, and is developed to provide guidance and support for the application of formal specification techniques. Our method mixes constraint-oriented and state oriented specification styles [33] and produces a modular description with a dynamic behaviour and its associated data type. The dynamic behaviour extraction is based on a guarded automaton that is progressively and rigorously built from requirements. Type information and operation preconditions are used to define states and transitions. The dynamic behaviour is computed from the automaton using some standard patterns. The last improvement is the assisted computation of the functional part. Our method reuses a technique [3] which allows one to get an abstract data type from an automaton. This technique extracts a signature and generators from the automaton. Furthermore, the automaton drives the axiom writing so that the specifier has only to provide the axioms right hand sides. Our method is extended here to code generation. Code generation is a really useful tool from a practical point of view. It allows to generate from a specification a prototype which may be used as the basis for the future system, to validate client requirements or to test the system. We use Java [15] as a target language for the static part and we focus on the dialect ActiveJava [1] for the dynamic part. The paper is structured as follows. We briefly present the case study: a transit node case in a telecommunications network [5]. In Section 3, the general process of our method is given. Section 4 is devoted to code generation, namely it consists in two subsections: the static generation part in Java and the dynamic generation part in ActiveJava. The conclusion summarizes the main points of our method.
2
Case-Study Presentation
This case study was adapted within the VTT project [5] from one defined in the RACE project 2039 (SPECS : Specification Environment for Communication Software). It consists of a simple transit node where messages arrive, are routed, and leave the node. The informal specification reads as follows: clause 1 The system to be specified consists of a transit node with: one Control Port-In, one Control Port-Out, N Data Ports-In, N Data Ports-Out, M Routes Through. The limits of N and M are not specified. 1
Both are used for the specification of distributed systems and are mixed specification languages.
From Informal Requirements to COOP: A Concurrent Automata Approach
941
clause 2 (a) Each port is serialized. (b) All ports are concurrent to all others. The ports should be specified as separate, concurrent entities. (c) Messages arrive from the environment only when a Port-In is able to treat them.
clause 3 The node is “fair”. All messages are equally likely to be treated, when a selection must be made, clause 4 and all data messages will eventually transit the node, or become faulty. clause 5 Initial State : one Control Port-In, one Control Port-Out. clause 6 The Control Port-In accepts and treats the following three messages: (a) Add-Data-Port-In-&-Out(n) gives the node knowledge of a new Port-In(n) and a new Port-Out(n). The node commences to accept and treat messages sent to the Port-In, as indicated below on Data Port-In. (b) Add-Route(m,ni ) , associates route m with Data-Port-Out(ni ). (c) Send-Faults routes some messages in the faulty collection, if any, to Control Port-Out. The order in which the faulty messages are transmitted is not specified. clause 7 A Data Port-In accepts only messages of the type : Route(m).Data. (a) The Port-In routes the message, unchanged, to any one (non determinate) of the open Data Ports-Out associated with route m. If no such port exists, the message is put in the faulty collection. (b) (Note that a Data Port-Out is serialized – the message has to be buffered until the Data Port-Out can process it). (c) The message becomes a faulty message if its transit time through the node (from initial receipt by a Data Port-In to transmission by a Data Port-Out) is greater than a constant time T. clause 8 Data Ports-Out and Control Port-Out accept messages of any type and will transmit the message out of the node. Messages may leave the node in any order. clause 9 All faulty messages are eventually placed in the faulty collection where they stay until a Send-Faults command message causes them to be routed to Control Port-Out. clause 10 Faulty messages are (a) messages on the Control Port-In that are not one of the three commands listed, (b) messages on a Data Port-In that indicate an unknown route, or (c) messages whose transit time through the node is greater than T.
942
Pascal Poizat, Christine Choppy, and Jean-Claude Royer
clause 11 (a) Messages that exceed the transit time of T become faulty as soon as the time T is exceeded. (b) It is permissible for a faulty message not to be routed to Control Port-Out by a Send-Faults command (because, for example, it has just become faulty, but has not yet been placed in a faulty message collection), (c) but all faulty messages must eventually be sent to Control Port-Out with a succession of Send-Faults commands. clause 12 It may be assumed that a source of time (time-of-day or a signal each time interval) is available in the environment and need not be modeled within the specification.
3
A New Specification Method
Overall Presentation
1
informal description
2
concurrent activity
3
sequential components
4
data types
Fig. 1. The step dependencies at the overall level Our method is composed of four steps for obtaining the specification (cf. Fig. 1): the informal description of the system to be specified, the concurrent activity description, the sequential component descriptions by an automaton, the data type specifications. Two validation steps may also be associated to the specification steps but they are not detailed here. Each step is described below with a proper agenda and is briefly described. A more complete presentation of our method may be found in [25] and the whole application to the case study in [24]. Step 1: Informal description (Fig. 2) step
expression / schema
validation conditions
1.1: system functionalities
Fi : text
◦ no redundancy
1.2: system constraints
Ci : text
◦ consistency
1.3: system data
Di : sort
Fig. 2. Informal description agenda The aim of this first step is to sketch out the system characteristics.
From Informal Requirements to COOP: A Concurrent Automata Approach
943
Step 1.1: Description of the system functionalities. In this substep all possible operations are inventoried, given a name (Fi in Fig. 2) and described. For instance, in our example, some operations are given by clauses 6 and 7: – at the Control Port In: the reception of a command message (in cmde) – at the Data Ports In: the reception of a data message (in data).
Step 1.2: System constraints description. The system constraints relative to orders, operations ordering, size limits, . . . are expressed here and should be consistent, i.e. without contradiction. Step 1.3: System data description. The point of view is very abstract here. The system data are given a name (and a sort name). The transit node data are a list of open ports numbers (clause 6a), a list of routes (clauses 6b and 7a) and a list of faulty messages (clauses 4, 6c, 7a and 9).
Step 2: Concurrent activity In this step the components that are executed in parallel are identified. Each one is modeled by a process. The process decomposition into subprocesses is inspired by the constraint-oriented and the resource-oriented specification styles [32, 33]. For each process there is a control part (dynamic part). Moreover, a data type (static part) may be associated with sequential processes and a variable of this type used as a formal parameter for the process. This unifies with the object-oriented encapsulation concept used later on. This step is decomposed in the following way: 2.1 communications, 2.2 decomposition and distribution, 2.3 parallel composition. As shown in Fig. 3, the substeps 2.2 and 2.3 may be iterated.
2.1
2.2
2.3
Fig. 3. Step dependencies for the concurrent activity Step 2.1: Communications. step 2.1.1: communication ports and data. The components interactions are modeled by communications on formal ports that represent the component services. Both communication ports and data are given by the informal description (step 1) or a previous decomposition (step 2).
944
Pascal Poizat, Christine Choppy, and Jean-Claude Royer
step
expression / schema
2.1.1: communication ports and data
2.1.2: typing
communications
PROCESS ... Di : sort ... ... Fi ...
Fi : ?xj :sj !xk :sk
validation conditions ◦ no omission: the Fi and Di from 1.1 and 1.3 are all taken into account ◦ no omission: the Fi from 1.1 are all taken into account ◦ emission sorts are available
Fig. 4. Communications agenda step 2.1.2: communications typing. The data that are either emitted (denoted by !x:T) or received (denoted by ?x:T) on the ports are typed. The communication typing is used to describe the processes interface, and also to specify the static part. A validation criteria is to make sure that the emission sorts of a process are “available”. A sort s is available for a process when: – either it is directly available, that is predefined and imported, defined within the process, or received by the process – or there exists an imported operation f: d∗ → s such that all sorts in d∗ are available. Since the data specification is achieved at step 4 this criteria validation may not be completed at this level. We use a type Msg as an abstraction to represent the different messages in the transit node: – reception of a command message: in cmde : ?m:Msg – reception of a data message: in data : !id:PortNumber ?m:Msg ?r: RouteNumber – emission of a list of faulty messages: out cmde : !l:List[Msg] – emission of a data message: out data : !m:Msg
Step 2.2: Decomposition and distribution. The process decomposition into subprocesses is done using pieces of information (constraints) from the informal description (or a previous decomposition), using the data and/or functionalities. The decomposition may be done in such a way that already specified components may be reused. Clause 1 leads to consider four components in the transit node: the Control Port In (CPI), the Data Ports In (DPI), the Control Port Out (CPO) and the Data Ports Out (DPO). The CPI manages the declared routes and the open ports (clause 6). The DPI needs access to information about which ports are related to which routes (clause 2a). Given the pieces of information collected from the preceding steps, the system may be represented as in Fig. 6 (see also Fig. 8).
From Informal Requirements to COOP: A Concurrent Automata Approach step
expression / schema PROCESS a ... Di: sort ...
2.2.1: data distribution
...
Fn
PROCESS ... sort Dj :... Fk ...
Fl
Fn
PROCESS
2.2.2: functionalities distribution
PROCESS a ... Di: sort ... F k
c
PROCESS b ... sort Dj :...
b
945
validation conditions ◦ all data should be distributed in the subprocesses (cf. 2.1.1)
◦ functionalities and related data ◦ all functionalities should be distributed in the subprocesses (cf. 2.1.1)
F m
Fig. 5. Decomposition and distribution agenda Control Port In
Data Port In
in_cmde ?m:Msg
in_data !id:PortNumber ?m:Msg ?r:RouteNumber Control Port Out
Data Port Out
out_cmde !l:List[Msg]
out_data !m:Msg routes : List[Route] faulties : List[Msg] ports : List[PortNumber]
Fig. 6. Transit node external view (from Step 2.2) Step 2.3: Parallel composition (Fig. 7). Processes composition often follows already known patterns, such as the synchronization schemata or the architectural styles given in [21, 18, 31]. Therefore we suggest to use a library of “composition schemata” that may be extended as needed. The specification of the subprocesses parallel composition may be derived from the set of the composition schemata using language specific features such as LOTOS operators [25] or SDL block structure and channels [24]. The process composition may lead to create new (internal) communications and possibly new data that have to be specified. Let us note that the process parallel composition is a way to express some constraints between the processes. Thus, clause 2b leads to a constraint on the parallel composition between the different ports. In order to take this into account, the DPI (resp. DPO) should be rather composed by interleaving than by synchronization. Faulty messages. They are saved in the CPO collection (clause 9). They are (clause 10) either incorrect command messages (wrong cmde, received by the CPI), or data messages with an unknown route (wrong route, received by a DPI), or obsolete messages (timeout, from a DPO). Information on routes. The DPI needs information on the transit node routes (whether a route is declared, and what are its associated ports). These pieces of information are held by the CPI, and will be transmitted to the DPI through
946
Pascal Poizat, Christine Choppy, and Jean-Claude Royer
step
expression / schema PROCESS
2.3.1: composition schema choice
PROCESS
PROCESS a ... Di: sort ... F k
b
... sort Dj :...
Fl
Fn
2.3.2: schema application (cf. steps 2.2 and 2.3.1)
c
PROCESS
PROCESS a ... Di: sort ...
validation conditions
c
PROCESS b ... sort Dj :...
◦ relations between the process constraints and the constraints obtained through the subprocesses composition
F m
Fig. 7. Parallel composition agenda
question/answer communications between the DPI and the CPI (ask route and reply route). Message routing. When the data message route is correct, the message is routed (correct communication) by the DPI to one of the corresponding DPOs (clause 7a). New ports. When the CPI receives the Add-Data-Port-In-&-Out command, it creates the corresponding ports (clause 6). In our modelization, this is taken into account by the fact that the Data Ports are enabled (enable communication) by the CPI on reception of this command. New data. New data may arise from decomposition (or recomposition). Here, the DPOs are serialized (clause 7b) and have a buffer for messages. The Data Ports have an identifier used in enabling and routing communications. Step 2 was iterated until obtaining the Fig. 8 schema. In the sequel, we shall focus on the DPI communication typing which is the following: correct : !ident:PortNumber !m:Msg ask route : !r:RouteNumber enable : !ident:PortNumber wrong route : !m:Msg reply route : !r:RouteNumber ?l:List[PortNumber] in data : !id:PortNumber ?m:Msg ?r:RouteNumber
Step 3: Sequential components (Fig. 9) Each sequential component is described by a guarded finite state automaton.
From Informal Requirements to COOP: A Concurrent Automata Approach
947
ask_route CPI
DPI
routes : List[Route] in_cmde ?m:Msg
reply_route
i : PortNumber
ports : List[PortNumber]
enable
correct
wrong_cmde
send_fault
wrong_route
enable
CPO out_cmde !l:List[Msg]
in_data !id:PortNumber ?m:Msg ?r:RouteNumber
faulties : List[Msg]
DPO i : PortNumber
out_data !m:Msg
l : List[Msg] timeout
Fig. 8. Transit node internal view (from Step 2.3) Steps 3.1 to 3.4: Conditions. The ports are put in four disjoint sets depending on whether they modify (C and CC) or not (O and OC) the state of the process and whether they are conditioned (CC and OC) or not (C and O). The names stand for Constructor (C), Conditioned Constructor (CC), Observer (O) and Conditioned Observer (OC). The term “condition” refers to preconditions required for a communication to take place, and also to conditions that affect the behaviour when a communication takes place. It should be checked that all conditions mentioned in step 1.2 are taken into account. However, some of them will be taken into account when dealing with the parallel composition of processes (step 2.3). Applying the steps 3.1 and 3.2 to the DPI leads to identify the following conditions: enabled (the port is enabled), received (a message is received and not yet routed), requested (routing information was requested), answered (the answer on routing information is received), and routeErr2 (routing error). For instance, the wrong route operation in CC has the following conditions: enabled ∧ received ∧ requested ∧ answered ∧ ¬routeErr. Relationships between conditions are expressed by formulas ( φi (Cj )). The relationship formula have to be consistent and may lead to simplify some conditions (possibly eliminating some). In the DPI example, we have: answered ⇒ requested, requested ⇒ received, received ⇒ enabled. This is consistent and leads to: answered ∧ ¬routeErr when applied to the condition on wrong route. Steps 3.5 to 3.7: States retrieval. Whether a process may perform a service (through a communication on a port) depends on which abstract state the process is in. The states are thus retrieved by composition of the communications conditions (these conditions were identified in steps 3.2 to 3.4, and a truth table is constructed in 3.5). The formulas (φi (Cj )) expressing relationships between 2
The routeErr condition bears on the value of the variable l of reply route after the communication took place (see the communication typing at the end of step 2).
948
Pascal Poizat, Christine Choppy, and Jean-Claude Royer
step
expression / schema
3.1: obtaining ports of O, OC, C, CC 3.2: conditions on ports of OC or CC category: precondition or behaviour 3.3: relationships between conditions
O, OC, C, CC
Fi : Cj (category)
3.6: elimination of impossible cases
◦ disjoint sets ◦ 1.2 (cf also 2.3) λ consistency: ∧i φi (Cj )
φi (Cj )
3.4: simplification of conditions 3.5: creating the conditions table
validation conditions
λ simplifications ... C ... i
interpretation
reference
... C ... i
interpretation
reference
λ φi (Cj ) (3.3)
3.7: states
Ei =< ..., v(Cj ), ... > v(Cj ) ∈ {T, F }
3.8: operations preconditions
Pk =< ..., v(Cj ), ... > v(Cj ) ∈ {T, F, ∀}
λ consistency of preconditions w.r.t. φi (Cj ) correction w.r.t. 3.2
3.9: operations postconditions
Qk =< ..., Φi (C’j ), ... >
C’ : C + new conditions
3.10: relationships between conditions
φi (C’j )
λ consistency: ∧i φi (C’j ) λ consistency of postconditions w.r.t. φi (C’j )
3.11: computing the transitions 3.12: choice of an initial state from possible (Oi ) and impossible (Oj ) operations 3.13: automaton simplifications 3.14: translating the automaton to the target language 3.15: simplifying the specification
T = f (E , P, Q) Einit
λ consistency of ∧i POi ∧j ¬POj λ only one initial state equivalences automaton / specification correct tions
Fig. 9. Sequential components agenda
simplifica-
From Informal Requirements to COOP: A Concurrent Automata Approach
949
these conditions are used to eliminate incoherent states (3.6). Table 1 gives the DPI coherent states. Table 1. State conditions table for the Data Port In enabled received requested answered routeERR state T T T T T IR (Incorrect Route) T T T T F CR (Correct Route) T T T F F WA (Waiting for Answer) T T F F F RfR (Ready for Request) T F F F F RfI (Ready for Input) F F F F F NA (Not Authorized)
Steps 3.8 to 3.11: Transitions retrieval. To retrieve the transitions, we shall define each operation in terms of possible source states (preconditions) and corresponding target states (postconditions). Therefore, preconditions (P, 3.8) and postconditions (Q, 3.9) are expressed in terms of the conditions values, respectively before and after the communications take place. The case where the condition value is not relevant is denoted by ∀, and = denotes the case where the value is not modified after the communication. Verifications and simplifications may be achieved on both preconditions and postconditions [25]. Examples of preconditions and postconditions for some DPI operations are given below with the following notation: en for enabled, rec for received, req for requested, rep for answered, and rerr for routeErr. reply route en rec req rep rerr ask route en rec req rep rerr P T T ∀ F ∀ P T T T F ∀ = = T = = = = = T l=[] Q Q There are generally critical cases [25] and some postconditions may not be expressed using only state conditions. It is thus necessary to use new conditions to check whether the process data type is in a critical state. Informally, critical state conditions act as transition guards to avoid infinite state automata. Operationally to retrieve the transitions, and for each operation: – start from a given state e (a condition boolean tuple) – if this tuple yields the operation precondition, find the tuple for the corresponding postcondition and the associated state f – there is therefore a transition from e to f – start over with another state. Some improvements of this operational method are given in [25]. This automatic method leads to deal with cases that might not have been detected otherwise, as the critical cases. Step 3.12: Initial state. In order to determine the initial state, it is necessary to identify the services (associated to some ports) the process should give or not in that state (constraints). It is a requirement based choice. The potential initial
950
Pascal Poizat, Christine Choppy, and Jean-Claude Royer
states are found from the ports preconditions and the state table. If no initial state is found, this means that the specifier gave inconsistent constraints for it. In order to be able to generate code, a single initial state is needed. When several potential initial states are found, it possible to choose one of them arbitrarily or by adding some constraint on the services. The DPI automaton is given in Fig. 10.
enable enable
CR correct
NA
enable
RfI
IR wrong_route
in_data
reply_route [l=[]]
enable
RfR
enable
reply-route [l[]]
init(id)
WA ask_route ask_route enable
Fig. 10. Data Port In automaton Steps 3.13 to 3.15: Simplifications and translation. It is possible to translate the automaton to various specification languages by applying translation schemata. This technique was applied to LOTOS [25] and to SDL [24]. Whenever the translation is not optimal, some simplifications may possibly be applied [25, 24]. The automaton may also be simplified before the translation, for instance by hierarchical grouping of states achieved using the conditions [24]. Step 4: Data types The last step is the specification of the abstract data types associated to each process, and of the data types used within the processes. As regards the data types associated to each process, the work achieved in the preceding steps yields most of the signature (cf. [25] from a description of the automatic processing). Thus, the operations names and profiles are retrieved automatically from the communication typing, and from the conditions identified upon building the automata. Let us note that with each communication m, one or several algebraic operations may be associated (Fig. 11). Some additional operations may be needed to express the axioms. Most of the axioms are written in a “constructive” style which requires to identify the generators. [3] describes a method to retrieve the data type associated to an automaton and to compute a minimal set of operations necessary to reach all states.
From Informal Requirements to COOP: A Concurrent Automata Approach
m !e:T
m ?e:T
951
for emissions: m-c : DPI → DPI m-o : DPI → T for receptions: m-c : DPI × T → DPI m-o : DPI → T (optional)
Fig. 11. Correspondence between communications and algebraic operations In our example, this set is init, enable, in data, ask route, reply route. [3] uses Ω-derivation [6] to write the axioms (conditional equations). In order to extract the axioms describing the properties of the operation op(dpi:DPI), the states where this operation is allowed should be identified together with the generators to reach these states, thus yielding the premises and the axioms left hand sides. Part of this automatic processing is shown here for the axioms of the correct c operation, the internal operation associated with the correct transition. The premises express conditions on the source states and on the l variable. % correct-c : DPI -> DPI CR(dpi) => correct-c(enable-c(dpi)) = correct-c(dpi) WA(dpi) /\ not(l=[]) => correct-c(reply-route-c(ask-route-c(dpi),l)) = correct-c(reply-route-c(dpi,l)) WA(dpi) /\ not(l=[]) => correct-c(reply-route-c(enable-c(dpi),l)) = correct-c(reply-route-c(dpi,l)) RfR(dpi) /\ not(l=[]) => correct-c(reply-route-c(ask-route-c(enable-c(dpi)),l)) = correct-c(reply-route-c(ask-route-c(dpi),l)) RfI(dpi) /\ not(l=[]) => correct-c(reply-route-c(ask-route-c(in-data-c(dpi,m,r)),l)) = dpi
The algebraic specification may then be used for proving properties needed for the specification verification and validation.
4
Code Generation
Once we get a formal specification it is not necessarily executable. Often the dynamic part is executable because it is based on operational models (state transition diagrams). This is not always true for the static part (algebraic abstract data type). We will illustrate assisted code generation in Java, however the method is suitable for other object-oriented languages. The general method is depicted on Fig. 12 and is split in two parts: the static part (on the right of Fig. 12) and the dynamic part (on the left of Fig. 12). 4.1
Static Part Generation
Java classes are generated for each abstract data type in the specification, and this process is achieved by four intermediate steps (cf. Fig. 12). The translations
952
Pascal Poizat, Christine Choppy, and Jean-Claude Royer Formal Specification Guarded Automaton and Compositions
Algebraic Abstract Data Types Specification Refinement
Executable Specifications Choice of a Hierarchy
Controller structures
Single Generator Specifications Sequential components
Object Translation
Formal Class Design Automatic Translation
Active Classes (ActiveJava)
Static Classes (pure Java)
Active Classes encapsulated Static Parts Java Code
Fig. 12. Object code generation scheme are partly automatic, for instance to get a simpler or a more efficient result may require some specifier (or programmer) interaction. The first step is to obtain an executable specification (possibly through refinements). Then, code generation is decomposed into (i) the choice of a hierarchy for representing the specification generators, (ii) the translation into formal classes (i.e. abstractions of classes in object-oriented languages), from which (iii) a generation in a given language (e.g. Java) may be done. Executable Specification. The “constructive” style adopted for the specifications associated with the automatons is likely to yield executable specifications (e.g. through rewriting, where tools, e.g. [14], may be used to check the convergence). However, other specification modules may be introduced (e.g. for the data managed by the processes) with other specification styles (e.g. observational style). A refinement process (abstract implementation [12]) is then needed to add elements for executability such as algorithmic choices, etc. Single Generator Specifications. In object-oriented languages, classes have a single generation operation called for instance “new” (or the class name), while algebraic specifications allow several generators. The problem addressed here is how to represent these generators within classes, or more precisely how to transform (e.g. by abstract implementation) the original algebraic specifications into single generator specifications from which classes may be derived. We propose
From Informal Requirements to COOP: A Concurrent Automata Approach
953
several solutions to this issue. A first solution is to associate to the several generators of the algebraic specification a single generator with a “switch” (to each original generator), we refer to this solution as the “flat organization”. Another solution is to use the associated class as an interface to subclasses, where each subclass is associated to one generator of the original specification, this will be denoted as the “two level hierarchy organization”. Then, of course, it is possible to mix these two solutions as appropriate. Several frameworks are available for abstract implementation [12], a first sketch is to follow the general framework of Hoare’s representation [19]. It consists into defining an abstraction function, to prove it is an onto function and to prove the implementation of operations. These aspects are not detailed here. In the following, we present the alternative organizations for single generator specifications. When the abstract data type has only one generator we directly apply the simple representation described below to get a class. Flat Organization. In this organization, a specification module with several generators is transformed into a single generator specification module with a “switch” to each original generator. For example, in the DPI specification module, the generators are init, enable, in data, ask route, reply route. We define SwitchDPI = {init, enable, in data, ask route, reply route} and the single generator newSDPI (SDPI stands for Switch DPI) with the profile newSDPI : Switch PortNumber Msg RouteNumber List SDPI -> SDPI (note that this profile may be easily computed from the DPI generators profiles). The abstraction function Abs is defined as usual, e.g.: Abs(newSDPI(reply route, Bport, Bmsg, Broute, Z, T)) == reply route c(T, Z)... Terms beginning by B are don’t care values. We also introduce selectors associated to relevant arguments occurring in the single generator, e.g.: switch(newSDPI(S, X, Y, R, Z, T)) = S (S = reply route ∧ WA(T)) => selRoutes(newSDPI(S, X, Y, R, Z, T)) = Z...
The axioms are then transformed within this framework to complete the specification. Two Level Hierarchy Organization. In this approach, several specification modules are associated with the original specification module: one module that is just an interface to modules that introduce (each) one of the original generators together with the appropriate subsort. Clearly, this approach may yield semantics issues (depending on the framework adopted), and may not be as practical and straightforward as the previous one. However, in some cases the specification style may be more legible. Mixed Organization. Of course between these two previous extrema there are many other ways to transform the type depending of the chosen hierarchy. We studied in [2] how to get a better hierarchy and we presented a general process for it. However some important problems remain: metrics to define a best hierarchy and problems linked with inheritance of properties.
954
Pascal Poizat, Christine Choppy, and Jean-Claude Royer
In case of abstract data types with less than five generators, the flat organization is acceptable but with more complex ones this will not be the case. Another way to solve this problem is to introduce a kind of inheritance or subsort (OBJ subsort) in the method. This problem is known to be difficult in itself and rather complex with concurrent systems. Formal Class Design: The Model. This model [4] defines the notion of formal class as an abstraction of a concrete class in languages like C++, Eiffel, Java or Smalltalk. A formal class is an algebraic specification (as abstract data type) with an object-orientation. This general model is functional and unifies the major concepts of object-oriented programming. It can be used both to build formal specifications and to design a system. An abstract operational semantics [4] was given to this model using conditional term rewriting [10]. Figure 13 shows a formal class example associated to the SDPI specification module obtained with the flat organization.
FCDPI field selectors switch : FCDPI −→ Switch ident : FCDPI −→ PortNumber requires: switch(Self) = init selRoutes : FCDPI −→ List requires: switch(Self) = reply route ∧ WA(previous(Self)) ... methods correct c : FCDPI −→ FCDPI ;; correct c : internal operation associated to a correct route (switch(Self) = enable ∧ CR(previous(Self))) => correct c(Self) = correct c(previous(Self)) (switch(Self) = reply route ∧ switch(previous(Self)) = ask route ∧ WA(previous(Self)) ∧ is empty(list(Self))) => correct c(Self) = correct c(new(reply route, Bport, Bmsg, Broute, selRoutes(Self), previous(previous(Self)))) ...
Fig. 13. Formal Class FCDPI The translation into (purely functional) Java code is straightforward. A formal class is translated to an interface (corresponding to the signature) and an implementation class. We use abstract methods and classes when needed (depending on the chosen organization). The structure is represented by private instance variables. Fields selectors are coded by a public accessor to the corresponding instance variable with a condition corresponding to the precondition.
From Informal Requirements to COOP: A Concurrent Automata Approach
955
A tool to generate Java classes is not available yet, but experimental tools have been done for Eiffel and Smalltalk. Formal Class Design: A Simple Representation. The simple representation allows one to translate a single generator type into a formal class, denoted by FCADT. This generator will be the newFCADT instantiation function of the object model. We must identify selectors, i.e. operations seli such that seli (new(X1, ..., Xn )) = Xi . These field selectors yield the instance variables of the class. We assume that the specification (axioms and preconditions) has no variable named Self. A term is said to be in a receiver position if it appears at first position in an operation different from the generator. If a variable appears in a receiver position in the left conclusion term then it will be replaced by Self. In our model this variable denotes the object receiver. An important translation rule is to replace newSADT(e1, ..., en ) by V with V : FCADT. This leads to a set of equations: seli (V) = ei . 1. This rule is applied on every newSADT occurrence in a receiver position in the left conclusion term, where V is named Self. If ei is a variable then it is replaced by seli (Self) in axioms. If ei is neither a variable nor a don’t care term, the equation seli (Self) = ei is added to the axiom condition. 2. This rule is applied on all other occurrences in the left conclusion term with any variable other than Self. This representation was processed over the single generator specification SDPI and the result is the above formal class (Fig. 13). 4.2
Dynamic Part Generation
This part deals with the code generation for the dynamic part in an object oriented language. The language we aim at is ActiveJava [1], a Java dialect (pre-processed into pure Java) based on ATOM [23]. The ActiveJava model defines abstract states, state predicates, methods activation conditions and state notification. Its main advantages are that: (i) its syntax is defined as a Java extension, (ii) it permits to model both inter and intraobject concurrency, and (iii) it supports both asynchronous and synchronous message passing. ActiveJava presents a good adequation between reusability of components (through separation of concerns into a dynamic and a static part) and expressivity. The dynamic part generation is build upon (i) coding subsystems structuration and LOTOS-like communication semantics, (ii) coding sequential automata, and (iii) integrating dynamic and static parts. Structuration and Communication Semantics. LOTOS communication semantics is more strict than the ActiveJava (object oriented) one. For this purpose and for better structuration matters, we choose to model each subsystem
956
Pascal Poizat, Christine Choppy, and Jean-Claude Royer
structuration with a controller. This approach is close to Coordinated Roles [22] and aims at the same properties: a better structuration and reusability of composition patterns. The system specification is taken as a tree with sequential components at the leaves and controllers at the nodes where the LOTOS structuring mechanisms are encoded. The subtrees under a given controller will be called its sons. Structuration for the transit node is given in Fig. 14 where coordinators are drawn as square boxes and sequential components as round boxes. This is another representation of Fig. 8. Transit Node Control Ports CPI
CPO [in_data, ask_route, reply_route, enable, correct, wrong_route]
Data Ports |[correct]| DPIS
|||
DPI 1 ... DPI n
DPOS
|||
DPO 1 ... DPO n
Fig. 14. Sketch of structuration and coordinators of the transit node We have three main communication mechanisms for structuration: interleaving, synchronization and hidden synchronization. Common mechanisms. The communication is achieved in three phases as shown in Fig. 15. In the run phase, controllers dispatch calls to a run method to their non waiting sons. Thus, in Fig. 15-1, C sends a run method to P but not to E. When these calls reach non controller components (i.e. the leaves, as P in Fig. 15-1) or controller with all sons blocked, then the second phase, return phase begins. In this return phase, sons return the communications they are ready to get involved with in a runnable list: a list of tuples containing the communication name and its arguments, with values for emission arguments and a special indicator ( ) for reception arguments. P returns [(‘‘m’’, ,4),(‘‘n’’,3)] to assess it is ready for a m or n communication (Fig. 15-2). The controller then computes a common intersection of the runnable lists and sends it up. Here, n from P does not match with anything from E whereas two m elements match to make the intersection that C sends upwards. Since some E and P runnable lists elements are in the common intersection, E and P are called participants. Elements with the same communication name have to match in the same way LOTOS offers match. Matching cases are given in Table. 2. All other cases mismatch. The second phase ends when there is no intersection (this yields a blocking status) or at the root where a final intersection in computed. The controller where the second phase ends is called temporary root. In the third phase (Fig. 15-3), the temporary root sends down the message corresponding to the final intersection it has previously computed. This message has to be unique, and non determinism (whether a received value has not been bound or there is communication non determinism) is solved by the temporary
From Informal Requirements to COOP: A Concurrent Automata Approach
957
Table 2. Matching elements and intersections element 1 (“m”, :T) (“m”,value:T) (“m”,value:T) (“m”, :T)
element 2 (“m”,value:T) (“m”, :T) (“m”,value:T) (“m”, :T)
common intersection (“m”,value:T) (“m”,value:T) (“m”,value:T) – same values (“m”, :T)
root controller [27]. Controllers send the message only to participants (both P and E for C) and then erase their table entry. Non participant sons are left waiting. To end, the temporary root controller relaunches the first phase by sending again the run method to its non waiting sons.
[("m",3,4)]
C.run() C |[m,n]|
E : ("m",3,_) P: ?
C |[m,n]| [("m",_,4), ("n",3)]
P.run() P [m,n]
E |[m]|
waiting on ("m",3,_)
P [m,n]
E |[m]|
m ?x !4 [] n !3 2. Return Phase
temporary root
1. Run Phase
E : ("m",3,_) P : [("m",_,4), ("n",3)]
C.m(3,4) E: ? C |[m,n]| P: ? P.m(3,4) P [m,n]
E.m(3,4) E |[m]|
3. Application Phase
Fig. 15. A communication scheme example
Interleaving. As soon as a controller receives a non synchronized element in a runnable list, it transmits it up. Synchronization. When two sons are composed in order to synchronize on a given method, their parent controller will transmit the corresponding element in runnable lists only if it has received this element in both sons runnable lists. Hidden synchronization. In the return phase, when the runnable lists reach a node, elements referring to hidden messages are not returned upwards but are kept at this node level. When only hidden messages reach a controller which has to block them, this controller acts as the temporary root controller. If there are also non hidden messages, the controller chooses whether to transmit them upwards or to act as the temporary root (this choice simulates non determinism).
958
Pascal Poizat, Christine Choppy, and Jean-Claude Royer
Coding the Automata in ActiveJava. The precondition and postcondition tables are used to code the automaton. But this has to be slightly modified to take into account run message receptions. The schema given in Fig. 16 is applied to each state.
m1
B
A
A m2
run
m2
C
a) without run
m1
B
C
b) with run
Fig. 16. Adding run in the automata Operation preconditions are defined as “activation conditions” in ActiveJava. Optionally, condition variables may be set (postconditions) in the “post actions” methods of ActiveJava. In the class constructor, initial values for the conditions are set according to the automaton initial state. Fig. 17 illustrates this on a part of the DPI example.
active class DPI(CPI cpi, FC fc, DPO dpo) { boolean v_a, v_r, v_d, v_rep, v_rerr; PortNumberList received_l; ... abstract state definitions {a as is_a(); ...} activations conditions { reply_route(RouteNumber r, PortNumberList l) with reply_route_precondition(); ...} synchronization actions { reply_route(RouteNumber r, PortNumberList l) with post_actions reply_route_postcondition(); ...} implement synchronization { boolean is_a() {return v_a;} ... boolean reply_route_precondition() { return v_a==TRUE && v_r==TRUE && v_d==TRUE && v_rep==FALSE;} ... void reply_route_postcondition() { v_rep=TRUE; v_rerr=received_l.isEmpty();} ... }}
Fig. 17. (Part of) Active Class for DPI
From Informal Requirements to COOP: A Concurrent Automata Approach
959
Integrating the Static and the Dynamic Parts The integration of the static and the dynamic part is done using encapsulation of a static class instance into the dynamic class with static methods called into dynamic methods bodies (Fig. 18). Observers are called in the run method to compute some of the run list elements arguments. Statics methods are also called in each corresponding dynamic method.
import StaticClass; active class DynamicClass { StaticClass nested; < ActiveClass part > public methods { public DynamicClass( < arguments > ) { nested = new StaticClass( < arguments > ); < dynamic initialization (initial state) > } public RunnableList run() { // uses nested.observers return values in runnable list } public void otherMethod( < arguments > ) { nested.otherMethod( < arguments > ); }}}
Fig. 18. Integration of static and dynamic parts
5
Conclusion
While there are good motivations for the use of formal specifications in software development, the lack of methods may restrict it to “few experts”. There are several points which may cause problems: the use of formal notation, the structure of the system, the proofs of properties and the code generation (or refinement for others) are some of the most important. In this paper, we address a specification method for systems where both concurrency and data types issues have to be taken into account. One important feature is the help provided to the user: help to build dynamic behaviours, help to decompose the system, help to extract the data types and help to generate code. Our method takes advantage of both the constraint and state oriented approaches that are used for LOTOS or SDL specifications. The system is described in terms of parallel components with well defined external interfaces (the gates and communication typing). The behaviour of the component is described by a sequential process associated with an internal data type. The study of the communications and their effect on this data type allows one to build, in a semi-automatic way, an automaton describing the process internal behaviour. The automaton is then translated
960
Pascal Poizat, Christine Choppy, and Jean-Claude Royer
into a specification language (LOTOS or SDL). The data type is extracted by a semi-automatic method from this automaton. The components and the whole system may then be verified using common set of tools for transition systems [13] or algebraic specifications [14]. Our specification method is equipped with a prototype generation. Objectoriented languages are another major phenomenon in software engineering. One cannot ignore the qualities of such code, however writing such code may be a hard task. We choose to generate Java code but our method may be applied to other object oriented languages. This code generation is mainly automatic and modular. We plan to experiment code generation on other frameworks for concurrent object oriented programming such as [8]. One future research direction is the extension of this approach to other specification languages, like Raise [30] or Object-Z [28]. Other connected areas of research are about object-oriented analysis and design methods. We currently work on the use of UML [29] diagrams to improve system architecture and to validate the automaton behaviour (with communication diagrams for instance). Therefore, we plan to provide our specification model with inheritance, more complete communication (experimenting new controller semantics) and structuration mechanisms as in related models [9].
References ´ [1] Luis A. Alvarez, Juan M. Murillo, Fernando S´ anchez, and Juan Hern´ andez. ActiveJava, un modelo de programaci´ on concurrente orientado a objeto. In III Jornadas de Ingener´ıa del Software, Murcia, Spain, 1998. [2] Pascal Andr´e. M´ethodes formelles et a ` objets pour le d´ eveloppement du logiciel : Etudes et propositions. PhD Thesis, Universit´e de Rennes I (Institut de Recherche en Informatique de Nantes), Juillet 1995. [3] Pascal Andr´e and Jean-Claude Royer. How To Easily Extract an Abstract Data Type From a Dynamic Description. Research Report 159, Institut de Recherche en Informatique de Nantes, September 1997. [4] Pascal Andr´e, Dan Chiorean, and Jean-Claude Royer. The formal class model. In Joint Modular Languages Conference, pages 59–78, Ulm, Germany, 1994. GI, SIG and BCS. [5] M. Bidoit, C. Choppy, and F. Voisin. Validation d’une sp´ecification alg´ebrique du “Transit-node” par prototypage et d´emonstration de th´eor`emes. Chapitre du Rapport final de l’Op´eration VTT, Validation et v´erification de propri´et´es Temporelles et de Types de donn´ees (commune aux PRC PAOIA et C3), LaBRI, Bordeaux, 1994. [6] Michel Bidoit. Types abstraits alg´ebriques : sp´ecifications structur´ees et pr´esentations gracieuses. In Colloque AFCET, Les math´ ematiques de l’informatique, pages 347–357, Mars 1982. [7] Tommaso Bolognesi and Ed Brinksma. Introduction to the ISO Specification Language LOTOS. Computer Networks and ISDN Systems, 14(1):25–29, January 1988. [8] D. Caromel and J. Vayssi`ere. A Java Framework for Seamless Sequential, Multithreaded, and Distributed Programming. In ACM Workshop “Java for High-
From Informal Requirements to COOP: A Concurrent Automata Approach
[9]
[10]
[11] [12]
[13]
[14]
[15] [16]
[17]
[18]
[19] [20]
[21]
[22]
[23]
961
Performance Network Computing”, pages 141–150, Stanford University, Palo Alto, California, 1998. Eva Coscia and Gianna Reggio. JTN: A Java-Targeted Graphic Formal Notation for Reactive and Concurrent Systems. In Jean-Pierre Finance, editor, Fundamental Approaches to Software Engineering (FASE’99), volume 1577 of Lecture Notes in Computer Science, pages 77–97. Springer-Verlag, 1999. Nachum Dershowitz and Jean-Pierre Jouannaud. Rewrite Systems, volume B of Handbook of Theoretical Computer Science, chapter 6, pages 243–320. Elsevier, 1990. Jan Van Leeuwen, Editor. Jan Ellsberger, Dieter Hogrefe, and Amardeo Sarma. SDL : Formal Objectoriented Language for Communicating Systems. Prentice-Hall, 1997. M. Navarro F. Orejas and A. Sanchez. Implementation and behavioural equivalence: a survey. In M. Bidoit and C. Choppy (Eds.), editors, Recent Trends in data Type Specification, volume 655 of Lecture Notes in Computer Science, pages 93–125. Springer-Verlag, August 1993. Jean-Claude Fernandez, Hubert Garavel, Alain Kerbrat, Radu Mateescu, Laurent Mounier, and Mihaela Sighireanu. CADP: A Protocol Validation and Verification Toolbox. In 8th Conference on Computer-Aided Verification, pages 437–440, New Brunswick, New Jersey, USA, 1996. S. Garland and J. Guttag. An overview of LP, the Larch Prover. In Proc. of the Third International Conference on Rewriting Techniques and Applications, volume 355 of Lecture Notes in Computer Science, pages 137–151. Springer-Verlag, 1989. Gosling, Joy, and Steele. The Java Language Specification. Addison Wesley, 1996. Wolfgang Grieskamp, Maritta Heisel, and Heiko D¨ orr. Specifying Embedded Systems with Statecharts and Z: An Agenda for Cyclic Software Components. In Egidio Astesiano, editor, FASE’98, volume 1382 of Lecture Notes in Computer Science, pages 88–106. Springer-Verlag, 1998. Maritta Heisel. Agendas – A Concept to Guide Software Development Activities. In R. N. Horspool, editor, Proceedings Systems Implementation 2000, pages 19–32. Chapman & Hall, 1998. Maritta Heisel and Nicole L´evy. Using LOTOS Patterns to Characterize Architectural Styles. In Michel Bidoit and Max Dauchet, editors, TAPSOFT’97 (FASE’97), volume 1214 of Lecture Notes in Computer Science, pages 818–832, 1997. C.A.R. Hoare. Proof of Correctness of Data Representations. Acta Informatica, 1:271–281, 1972. ISO/IEC. LOTOS: A Formal Description Technique based on the Temporal Ordering of Observational Behaviour. ISO/IEC 8807, International Organization for Standardization, 1989. Thomas Lambolais, Nicole L´evy, and Jeanine Souqui`eres. Assistance au d´eveloppement de sp´ecifications de protocoles de communication. In AFADL’97 Approches Formelles dans l’Assistance au D´ eveloppement de Logiciel, pages 73–84, 1997. ´ Juan M. Murillo, Juan Hern´ andez, Fernando S´ anchez, and Luis A. Alvarez. Coordinated Roles: Promoting Re-usability of Coordinated Active Objects Using Event Notification Protocols. In Paolo Ciancarini and Alexander L. Wolf, editors, Third International Conference, COORDINATION’99, volume 1594 of Lecture Notes in Computer Science, Amsterdam, The Nederlands, April 1999. Springer-Verlag. M. Papathomas, J. Hern` andez, J. M. Murillo, and F. S` anchez. Inheritance and expressive power in concurrent object-oriented programming. In LMO’97 Langages et Mod`eles ` a Objets, pages 45–60, 1997.
962
Pascal Poizat, Christine Choppy, and Jean-Claude Royer
[24] Pascal Poizat, Christine Choppy, and Jean-Claude Royer. Un support m´ethodologique pour la sp´ecification de syst`emes “mixtes”. Research Report 180, Institut de Recherche en Informatique de Nantes, Novembre 1998. /papers/rr180.ps.gz in Poizat’s web page. [25] Pascal Poizat, Christine Choppy, and Jean-Claude Royer. Une nouvelle m´ethode pour la sp´ecification en LOTOS. Research Report 170, Institut de Recherche en Informatique de Nantes, F´evrier 1998. /papers/rr170.ps.gz in Poizat’s web page. [26] Pascal Poizat, Christine Choppy, and Jean-Claude Royer. Concurrency and Data Types: A Specification Method. An Example with LOTOS. In J. Fiadeiro, editor, Recent Trends in Algebraic Development Techniques, Selected Papers of the 13th International Workshop on Algebraic Development Techniques WADT’98, volume 1589 of Lecture Notes in Computer Science, pages 276–291, Lisbon, Portugal, 1999. Springer-Verlag. [27] Pascal Poizat, Christine Choppy, and Jean-Claude Royer. From Informal Requirements to Object Oriented Code using Structured Concurrent Sequential Communicating Automata. Research Report, Institut de Recherche en Informatique de Nantes, 1999. [28] Graeme Smith. A Fully-Abstract Semantics of Classes for Object-Z. Formal Aspects of Computing, 7(E):30–65, 1995. [29] Rational Software and al. Unified Modeling Language, Version 1.1. Technical report, Rational Software Corp, http://www.rational.com/uml, September 1997. [30] The Raise Method Group. The RAISE Development Method. The Practitioner Series. Prentice-Hall, 1995. [31] K. Turner. Relating architecture and specification. Computer Networks and ISDN Systems, 29(4):437–456, 1997. [32] Kenneth J. Turner, editor. Using Formal Description Techniques, An introduction to Estelle, Lotos and SDL. Wiley, 1993. [33] C.A. Vissers, G. Scollo, M. Van Sinderen, and E. Brinksma. Specification styles in distributed systems design and verification. Theoretical Computer Science, (89):179–206, 1991.
A Framework for Defining Object-Calculi Extended Abstract Fr´ed´eric Lang, Pierre Lescanne, and Luigi Liquori ´ Ecole Normale Sup´erieure de Lyon Laboratoire de l’Informatique du Parall´elisme 46, All´ee d’Italie, F–69364 Lyon Cedex 07, FRANCE E-mail: {flang,plescann,lliquori}@ens-lyon.fr
Abstract. In this paper, we give a general framework for the foundation of an operational (small step) semantics of object-based languages with an emphasis on functional and imperative issues. The framework allows classifying very naturally many object-based calculi according to their main implementation techniques of inheritance, namely delegation and embedding, and their particular strategies. This distinction comes easily from a choice in the rules. Our framework is founded on two previous works: λObj+ , a version of the Lambda Calcua lus of Objects of Fischer, Honsell, and Mitchell, for the object aspects, and λσw of Benaissa, Lescanne, and Rose, for the description of the operational semantics and sharing. The former is the formalization of a small delegation-based language which contains both lambda calculus and object primitives to create, update, and send messages to objects, while the latter is designed to provide a generic description of functional language implementations and is based on a calculus of explicit substitution extended with addresses to deal with memory management. The framework is presented as a set of modules, each of which captures a particular aspect of object-calculi (functional vs. imperative, delegation vs. embedding, and any combination of them). Above all, it introduces and illustrates a new promising approach to formally reason about the operational semantics of languages with (possibly) mutable states. Keywords. Design of functional and imperative object-oriented languages, operational semantics, implementation issues, memory management.
1 Introduction An (operational) semantics for a programming language is aimed to help the programmer and the designer of a compiler to better understand her (his) work and possibly to prove mathematically that what she (he) does is correct. For instance, the designers of Java proposed a description of an operational semantics of the Java Virtual Machine [16], but unfortunately its informal character does not fulfill the above aim. In this paper, we set the foundation for a formal description of the operational semantics (small step) of object-based languages. One main characteristic of our framework, called λObj+a , is that it induces an easy classification of the object-based languages and their semantics, making a clear distinction between functional and imperative languages. Moreover, the present formal system is generic, which means that it presents J. Wing, J. Woodcock, J. Davies (Eds.): FM’99, Vol. II, LNCS 1709, pp. 963–982, 1999. c Springer-Verlag Berlin Heidelberg 1999
964
Fr´ed´eric Lang, Pierre Lescanne, and Luigi Liquori
many semantics in one framework which can be instantiated to conform to specific wishes. For this, it proposes a set of several modules, each of which captures a particular aspect of object-calculi (functional vs. imperative1, delegation vs. embedding, and any combination of them). Genericity comes also from a total independence from the strategy, the latter being sometimes crucial when dealing with imperative semantics. The framework λObj+a describes both static and dynamic aspects of object-oriented languages. Static aspects are the concepts related to the program, namely its syntax, including variable scoping, and above all its type system. The type system (not presented in this paper for obvious lack of space) avoids the unfortunate run-time error message-not-understood, obtained when one sends a message, say m, to an object which has no m in its protocol. Dynamic aspects are related to its behavior at run-time i.e., its operational semantics, also known as the implementation choices. In addition, this paper introduces in the world of the formal operational semantics of object-based languages, the concepts of addresses and simultaneous rewriting, which differ from the classical match and replace technique of rewriting. “Road Map”. Section 2 sets the context of the framework λObj+a . Section 3 addresses mostly the implementation aspects of object-based languages. Section 4 introduces ancestors of λObj+a , namely λObj+ , a slightly modified version of the Lambda Calculus a , a weak lambda-calculus with explicit substitution and addresses. of Objects, and λσw Section 5 is the real core of the paper as it details the notion of simultaneous rewriting, and presents λObj+a through its four modules L, C, F, and I. Section 6 gives some examples motivating our framework. Finally, Section 7 compares our framework with some related works. A richer version of this paper (containing some open problems) can be found in [14].
2 The Context of λObj+a The framework λObj+a is founded on an object-based calculus, enriched with explicit substitution and addresses. We explain this in the current section. 2.1 Object-Based Calculi The last few years have addressed the foundation of object-oriented languages. The main goal of this research was twofold: to understand the operational behaviour of object-oriented languages and to build safe and flexible type systems which analyze the program text before execution. In addition (and not in contrast) to the traditional class-based view, where classes are seen as the primitive notion to build object instances, recent years have seen the development of the, so called, object-based (or prototype-based) languages. Object-based languages can be either viewed as a novel object-oriented style of programming (such as in Self [22], Obliq [6], Kevo [19], Cecil 1
The terminology “functional” and ”imperative” seems to be more or less classical in the scientific object-oriented community. However, we could use “calculi of non-mutable (resp. mutable) objects” as synonymous for functional (resp. imperative) calculi.
A Framework for Defining Object-Calculi
965
[7], O-{1,2,3} [1]) or simply as a way to implement the more traditional class-based languages. In object-based languages there is no notion of class: the inheritance takes place at the object level. Objects are built “from scratch” or by inheriting the methods and fields from other objects (sometimes called prototypes). Most of the theoretical papers on object-based calculi address the study of functional object-calculi; nevertheless, it is well-known that object-oriented programming is inherently “imperative” since it is based on a notion of “mutable state”. However, those papers are not a simple exercise of style, since, as stated in [1, 5], it may happen that a type system designed for a functional calculus can be “well fitted” for an imperative one. Among the proposals firmly setting the theoretical foundation of object-oriented languages, two of them have spurred on an intense research. The Object Calculus of Abadi and Cardelli [1], is a calculus of typed objects of fixed size in order to give an account of a standard notion of subtyping. The operations allowed on objects are method invocation and method update. The calculus is computationally complete since the lambda calculus can be encoded via suitable objects. The calculus has both functional and imperative versions, the latter being obtained by simply modifying (with the help of a strategy and suitable data structures) the dynamic semantics of the former. Classes can be implemented using the well-known recordof-premethods approach: a class A is an object which has a method called new creating an instance a of the class and a set of “premethods” which become real methods when embedded (i.e., installed) into a. Class inheritance can be treated by “reusing” the premethods of the superclass. The Lambda Calculus of Objects λObj of Fisher, Honsell, and Mitchell [11] is an untyped lambda calculus enriched with object primitives. Objects are untyped and a new object can be created by modifying and/or extending an existing prototype object. The result is a new object which inherits all the methods and fields of the prototype. This calculus is also (trivially) computationally complete, since the lambda calculus is built in the calculus itself. Classes can also be implemented in λObj: in a simplified view, a class A has a method new which first creates an instance b of the superclass B of A and then adds (or updates) this instance with all the fields/methods declared in A. In [5], an imperative version of λObj featuring an encapsulation mechanism obtained via abstract data types, was introduced. In [9], a modified version of λObj, called λObj+ (see Subsection 4.1), was introduced together with a more powerful type system. 2.2 Explicit Substitution Calculi and Addresses Explicit Substitution Calculi (see for instance [2, 15]) were invented in order to give a finer description of operational semantics of the functional programming languages. Roughly speaking, an explicit substitution calculus fully includes the meta substitution operation as part of the syntax, adding suitable rewriting rules to deal with it. These calculi give a good description of implementations by modeling the concept of closure, but do not give an account of the sharing needed in lazy functional languages implementations. In [8], a weak lambda-calculus of explicit substitution, called λσw , was
966
Fr´ed´eric Lang, Pierre Lescanne, and Luigi Liquori
introduced; here weak means a calculus in which one can not compute inside abstraca , was presented (see Subsection 4.2); this tions. In [4], an extension of λσw , called λσw calculus added the notion of address and simultaneous rewriting, introduced by Rose in his thesis [18]. Addresses are global annotations on terms, which allow to handle sharing of arguments. 2.3 The Framework The framework λObj+a is founded on λObj+ for the object aspects, to which we add a . The reason why we are addresses and explicit substitution, following the lines of λσw interested in addresses in the context of an object-based calculus is not only their ability to express sharing of arguments, as in lazy languages, but much more because objects are typical structures which need to be shared in a memory, independently of the chosen strategy. The framework λObj+a deals also with graphs. As a positive consequence of having addresses, the technique of “stack and store” used to design static and dynamic features of imperative languages [10, 20, 24, 1, 5] is substituted in our framework by a technique of graphs (directed and possibly cyclic) which can undergo destructive updates through mutation of objects. This makes our framework more abstract, as it involves no particular structure for computing. Moreover it provides a small step semantics of object mutation. This is in fact a generalization of Wadsworth’s graph reduction technique of implementation of functional languages [23, 21], which, by essence, forbids destructive updates. Moreover, our graphs are represented as special terms, called addressed terms, exploiting the idea of simultaneous rewriting, already mentioned in [18, 4], and slightly generalized in this paper (see [13]). The framework λObj+a is much more than a simple calculus. One of the consequences of this abstraction is that λObj+a allows to define many calculi. A specific calculus is therefore a combination of modules plus a suitable strategy. Hence, what makes our approach original are the following features: genericity, independence of the strategy, and capture of both dynamic and static aspects of a given language. Thanks to these features, our framework handles in a unified way and with a large flexibility, functional and imperative object-oriented languages, using both embedding- and delegation-based inheritance techniques, and many different evaluation strategies.
3 Implementation of Object-Based Languages While issues related to the soundness of the various type systems of object-calculi are widely studied in the literature, a few papers address how to build formally a general framework to study and implement inheritance in the setting of object-based calculi. Among the two main categories of object-based calculi (i.e., functional and imperative ones, or with non-mutable and with mutable objects) there are two different techniques of implementation of inheritance, namely the embedding-based and the delegationbased ones, studied in this section. The following schematic example will be useful to understand how inheritance can be implemented using the embedding-based and the delegation-based techniques.
A Framework for Defining Object-Calculi
967
Example 1. Consider the following (untyped) definition of a “pixel” prototype. object pixel is x:=0; y:=0; onoff:=true; set(a,b,c){((self.x:=a).y:=b).onoff:=c} end
Consider the following piece of code. let p=clone(pixel) in let q=p.set(a,b,c):={((self.x:=self.x*a).y:=self.y*b).onoff:=c} in let r=q.switch():={self.onoff:=not(self.onoff)}
where := denotes both a method override and an object extension. In the following we discuss the two models of implementation of inheritance and we highlight the differences between functional versus imperative models of object-calculi. Before we start, we explain (rather informally) the semantics of the clone operator, present in many real object-oriented programming languages. 3.1 The clone Operator The semantics of the clone operator changes depending on the delegation-based or embedding-based technique of inheritance, and is orthogonal to the functional or imperative features of the framework. In delegation-based inheritance, a clone operation produces a “shallow” copy of the prototype i.e., another object-identity which shares the same object-structure as the prototype itself. On the contrary, in embedding-based inheritance, a clone operation produces a “hard copy” of the prototype, with a proper object-identity and a proper object-structure obtained by “shallowing” and “refreshing” the object-structure of the prototype. This difference will be clear in the next subsections which show possible implementations of the program of Example 1. 3.2 Functional Object-Calculi As known, functional calculi lack a notion of mutable state. Although people feel that object-calculi have only little sense in functional setting, we will show in this paper that they are worth studying and that it may be possible to include an object calculus in a pure functional language, like Haskell [17], with much of the interesting features of objects. Delegation-based Inheritance. The main notion is this of object since there are no classes. Some objects are taken as prototypical in order to build other objects. An “update” operation (indicated in the example as :=) can either override or extend an object with some fields or methods. A functional update always produces another object, which owns a proper “object-identity” (i.e., a memory location containing a reference to the object-structure, represented as a small square in figures). The result of an update is a “new” object, with a proper object-identity, which shares all the methods of the prototype except the one affected by the update operation. A clone operator builds another object with a proper object-identity which shares the structure of the prototype. By looking at Figure 1, one sees how Example 1 can be implemented using a delegation-based technique.
968
Fr´ed´eric Lang, Pierre Lescanne, and Luigi Liquori
empty r x
0
y
0
switch
code of switch onoff true
set set
code of set
pixel
new code of set
p q
Fig. 1. Functional Delegation-based Inheritance.
empty
empty
x
x
0
r
0 switch
y
y
0
0 code of switch
onoff true
onoff true
set
set
set
code of set code of set pixel
p
new code of set
q
Fig. 2. Functional Embedding-based Inheritance.
Embedding-based Inheritance. In embedding-based inheritance a new object is built by a “hard copy” of the prototype; in fact, clone really builds another object with a proper object-identity and a proper copy of the object-structure of the prototype. By looking at Figure 2 one can see how Example 1 can be implemented using an embedding-based technique. 3.3 Imperative Object-Calculi Imperative object-calculi have been shown to be fundamental in describing implementations of class-based languages like Smalltalk and Java. They are also essential as foundations of object-based programming languages like Obliq and Self. The main goal when one tries to define the semantics of an imperative object-based language is to say how an object can be modified while maintaining its object-identity. Particular attention must be paid to this when dealing with object extension. This makes the semantics
A Framework for Defining Object-Calculi
969
empty x
0
y
0
switch
code of switch onoff true
set
code of set p pixel
clone(pixel)
q r
q.switch():+
set
...
new code of set
p.set(a,b,c):= ...
Fig. 3. Imperative Delegation-based Inheritance.
empty
empty
x
0
x
0
y
0
y
0
switch
code of switch onoff true
onoff true
set
set code of set
code of set set
clone(pixel)
pixel
p
q.switch():+ ...
q r
p.set(a,b,c):= ...
new code of set
Fig. 4. Imperative Embedding-based Inheritance.
of the imperative update operation subtle because of side effects. Figure 3 shows the implementation of Example 1 with delegation-based inheritance, and Figure 4 with embedding-based inheritance. Dashed lines represent pointers due to the evaluation of some expression indicated as annotation. Each dashed line cancels the others i.e., there is only one dashed line at each moment. In both cases, observe how the override of the set method and the addition of the switch method change the object structure of p (later on also called q,r) without changing its object-identity.
4 Some Ancestors of λObj+a In this section we give a gentle introduction to calculi which inspired our framework, a . namely λObj+ and λσw
970
Fr´ed´eric Lang, Pierre Lescanne, and Luigi Liquori
Syntax. M, N ::= λx.M | M N | x | c
(Lambda Calculus)
| | M ← m = N | M ⇐ m | Sel (M, m, N )
(Objects) (Auxiliary)
Operational Semantics. (λx.M ) N → M {N/x} M ⇐ m → Sel (M, m, M ) Sel (M ← m = N , m, P ) → N P
(Beta) (Select) (Success)
Sel(M ← n = N , m, P ) → Sel (M, m, P ) m = n
(Next)
Fig. 5. The Lambda Calculus of Objects with Self-inflicted Extension λObj+ . 4.1 The Lambda Calculus of Objects with Self-Extension λObj+ The calculus λObj+ [9] is a calculus in the style of λObj. The type system of λObj+ allows to type the, so called, “self-inflicted extensions” i.e., the capability of objects to extend themselves upon receiving a message. The syntax and the operational semantics are defined in Figure 5. Observe that the (Beta) rule is given using the meta substitution (denoted by {N/x}), as opposed to the explicit substitution used in λObj+a . The main difference between the syntax of λObj+ and that of λObj [11] lies in the use of a single operator ← for building an object from an existing prototype. If the object M contains m, then ← denotes an object override, otherwise ← denotes an object extension. The principal operation on objects is method invocation, whose reduction is defined by the (Select) rule. Sending a message m to an object M containing a method m reduces to Sel (M, m, M ). The arguments of Sel in Sel (M, m, P ) have the following intuitive meaning (in reverse order): – P is the receiver (or recipient) of the message; – m is the message we want to send to the receiver of the message; – M is (or reduces to) a proper sub-object of the receiver of the message. By looking at the last two rewrite rules, one may note that the Sel function “scans” the recipient of the message until it finds the definition of the method we want to use. When it finds the body of the method, it applies this body to the recipient of the message. Example 2 (An object with “self-inflicted extension”). Consider the object self ext defined as follows: self ext = ← add n = λself.self ← n = λs.1. If we send the message add n to self ext, then we get the following computation: self ext ⇐ add n −→ Sel(self ext, add n, self ext) −→ (λself.self ← n = λs.1) self ext −→ self ext ← n = λs.1,
A Framework for Defining Object-Calculi
971
Terms. M, N ::= λx.M | M N | x | c U, V, E ::= M [s] | (U V ) s ::= U/x; s | id a
a
a
(Lambda Calculus) (Evaluation Contexts) (Substitution)
where a ranges over an infinite set of addresses.
Rules. a (λx.M )[s]b U → M [U/x; s]a (M N )[s]a → (M [s]b N [s]c )a x[E /x; s] → E
b
x[E /x; s] → E
a
b b
a a
b, c fresh
(App) (FVarG) (FVarE)
x[U/y; s] → x[s] a
(B)
a
x ≡ y
(RVar)
a . Fig. 6. The Weak Lambda Calculus with Explicit Substitution and Addresses λσw
resulting in the method n being added to self ext. On the other hand, if we send the message add n twice to self ext instead, the method n is only overridden with the same body; hence we obtain an object which is “operationally equivalent” to the previous one.
a 4.2 The Weak Lambda Calculus with Explicit Substitution and Addresses λσw a We introduce the weak lambda calculus with explicit substitution and addresses λσw [4], where for the sake of simplicity, and in the style of Rose [18], we replace de Bruijn indexes with variable names. By “weak”, we mean a lambda calculus in which reductions may not occur under abstractions, as standard in many programming languages. The syntax and the rules of this calculus are given in Figure 6. The explicit substitution gives an account of the concept of closure, while addresses give an account of sharing. Both are essential in efficient implementations of functional languages. There are three levels of expressions. The first level is static. It gives the syntax of programs code (terms written M, N, . . . ), and it contains no address. The second and third levels are dynamic. They contain addresses and they are the level of evaluation contexts, and the level of substitutions. Evaluation contexts (terms written U, V, . . . ) model states of abstract machines. An evaluation context contains the temporary structure needed to compute the result of an operation. It denotes a term closed by a list of bindings also called substitution. There is an evaluation context associated with each construct of the language. Addresses (denoted by a, b, . . . ) label evaluation contexts. Intuitively, an address a models a reference to a unique term graph which is denoted
972
Fr´ed´eric Lang, Pierre Lescanne, and Luigi Liquori
as a standard term by simply unraveling it. The sharing information is kept through addresses, as superscripts of terms. This leads to two associated notions, namely admissible terms and simultaneous rewriting. An admissible term is a term in which there is not two different subterms at the same address. In the following, we only deal with admissible terms. A simultaneous rewriting (see also Subsection 5.1) means that, if a subterm U at address a is reduced to a term V , then all the subterms at the same address a are reduced in the same step to V . In other words, the simultaneous rewriting is a rewriting relation meant to preserve admissibility. To be seen as a program i.e., to enable a computation, a closed lambda term M must be given a substitution s (also called environment), initially the empty substitution id, and a location a to form an evaluation context called addressed closure M [s]a . The environment s is the list of bindings of the variables free in M . To reduce terms, environments have to be distributed inside applications (App) until reaching a function or a variable. Hence, applications of weak lambda terms are also evaluation contexts. In this step of distributing the environment, “fresh” addresses are provided to evaluation contexts. A fresh address is an address unused in the global term. Intuitively, the address of an evaluation context is the address where the result of the computation will be stored. Since in a closure M [s]a , the terms in s are also addressed terms, it follows that the duplication of s in (App) induces duplications of lists of pointers. Not only a duplication does not loose sharing, but it increases it. When an abstraction is reached by a substitution, one gets a redex ((λx.M )[s]b U )a (provided there is an argument U ), hence one can apply the rule (B). This redex is reduced locally i.e., U is not propagated to the occurrences of x, but the environment is just enlarged with the new pair U/x. Moreover, the result of the reduction is put at the same location as this of the redex in the left hand side, namely a. As a matter of fact, the result of the rewriting step is shared by all the subterms that occur at address a. When a variable x is reached, and the environment scanned by several steps of rule (RVar), x has eventually to be replaced by the evaluation context it refers to. The a proposes two rules to do this, namely (FVarG), and (FVarE). The reason calculus λσw is that a choice has to be made on the address where to “store” the right hand side: it may be either the address of the evaluation context bound to x (FVarG), or the address of the main evaluation context (FVarE). In the first case, a redirection of the pointer which refers to the address a is performed toward the address b (where the term E lies), whereas in the latter case a copy of the part of the term E from address b to address a is made. In both cases, the result of the rewriting step is shared. In the case of a copy, further sharing between the original node and the copied node will not be possible, but this has no influence on efficiency if the copied node denoted a value i.e., a term of the form (λx.M )[s]a or c[s]a , because there may be no more further reductions on them. A detailed discussion on this choice of rules can be found in [3, 4]. Example 3. The term ((V U )a U )b where U ≡ ((λx.x)[id]c true[id]d )e and V is any evaluation context, may reduce in one step by rule (B) of Figure 6 to ((V x[true[id]d /x; id]e )a x[true[id]d /x; id]e )b ,
A Framework for Defining Object-Calculi e
973
e
but not to e.g., ((V x[true[id]d /x; id] )a ((λx.x)[id]c true[id]d ) )b since the two distinct underlined subterms have a same address, namely e. If we set V to (λy.λz.y)[id]f , then the computation may proceed as follows: (((λy.λz.y)[id]f x[true[id]d /x; id]e )a x[true[id]d /x; id]e )b ∗ y[x[true[id]d /x; id]e /z; x[true[id]d /x; id]e /y; id]b − →
(B+B)
→ y[x[true[id] /x; id] /y; id]
(RVar)
d
e
b
→ x[true[id] /x; id]
(FVarG)
→ true[id] ,
(FVarE)
d
e
e
where we chose to use both (FVarG) and (FVarE) for the sake of illustration. All along this paper, we use the helpful intuition that an address corresponds to a location in a physical memory. However, we warn the reader that this intuition may be error prone. Access and allocation in a physical memory are expensive and often avoidable. Since a fresh address is given to every new evaluation context, the reader may think that we are not aware of this cost and have in mind an implementation which overuse locations. In fact, addresses capture more than locations. This has been shown in [12] where the states of an environment machine (with code, environment, stacks, a . This translation showed that many addresses are and heap) are translated into λσw artificial i.e., do not have a physical reality in the heap, but correspond to components of states. It was also shown that the abstraction of sharing with addresses fits well with the environment machine, because it captures the strategy of the machine. The moral is that everything which could have a physical location, in a particular implementation, has an address in the framework.
5 The Syntax and the Operational Semantics of λObj+a This section presents our framework. It is split into separated modules, namely L for the lambda calculus, C for the common operations on objects, F for the functional object part, and I for the imperative object part. All these modules can be combined, giving the whole λObj+a . The union of modules L, C, and F can be understood as the the functional fragment of λObj+a . As described in Figure 7, we find in λObj+a the a , plus a dynamic level of internal structures of objects (or simply same levels as in λσw object-structures). To the static level, we add some constructs: constructors of objects, method invocations, and explicit duplicators. There are operations to modify objects: the functional update, denoted by ←, and the imperative update, denoted by ←: . An informal semantics of these operators has been given in Section 3. As in [9], these operators can be understood as extension as well as override operators, since an extension is handled as a particular case of an override. One has also two imperative primitives for “copying” objects: shallow(x) is an operator which gives a new object-identity to the object pointed by x but still shares the same object-structure as the object x itself; refresh(x)
974
Fr´ed´eric Lang, Pierre Lescanne, and Luigi Liquori
Code M, N ::= λx.M | M N | x | c | M ⇐m | | M ← m = N | M ←: m = N | shallow(x) | refresh(x)
(Lambda Calculus) (Message Sending) (Object Initialization) (Object Updates) (Duplication Primitives)
where x ranges over variables, c ranges over constants and m ranges over methods.
Evaluation Contexts U, V ::= M [s]a | (U V )a
(Closure) (Application)
| (U ⇐ m)a | U ← m = V a | U ←: m = V a a
| •a | Sela O, m, U | O
(Message Sending) (Object Updates) (Objects) (Lookup)
where a ranges over an infinite set of addresses.
Object-structures O ::= a | O ← m = V a | •a
(Internal Objects)
| copy(O)
(Duplicator)
s ::= U/x; s | id
(Substitution)
a
Environments
Fig. 7. The Syntax of λObj+a .
A Framework for Defining Object-Calculi
975
is a kind of dual to shallow(x) as it makes a “hard copy” of the object-structure of x, and reassigns this structure to x. Therefore, the object-identity of x is not affected. Similarly, some constructs are added as evaluation contexts. The evaluation cona text O represents an object whose internal object-structure is O and whose objectidentity is a . In other words, the address a plays the rˆole of an entry point of the object-structure O. An expression like Sela (O, m, Ob ) is an evaluation context (at address a). It looks up in the object-structure O of the receiver (represented by an evaluation context Ob ), gets the method body and applies it to the receiver itself. The term •a is a back pointer [18], its rˆole is explained in Subsection 5.5 when we deal with the cyclic aspects of objects i.e., the possibility to create “loops in the store”. Only •a can occur inside a term having the same address a, therefore generalizing our informal notion of admissible term and simultaneous rewriting. Internal objects O model the object-structures in memory. They are permanent structures which may only be accessed through the address of an object (denoted by a in Oa ), and are never destroyed nor modified (but by the garbage collector, if there is one). Our calculus being inherently delegation-based, objects are implemented as linked lists (of fields/methods). Embedding-based inheritance can however be simulated thanks to the refresh(x) and shallow(x) operators. In particular, refresh(x) is defined in terms of an auxiliary operator called copy(O) which makes a copy of the objectstructure. Again, because of imperative traits, object-structures can contain occurrences of •a . 5.1 The Simultaneous Rewriting Simultaneous rewriting [18, 3] is a key concept in this paper and we would like to warn the reader not to take it as just a slight variant of the usual term rewriting. Actually, due mostly to imperative features introduced in module I, simultaneous rewriting goes much beyond the classical match and replace paradigm of the traditional first order rewriting and must be defined extremely carefully in order to preserve: Horizontal Admissibility, i.e., all the subterms at the same address should be equal and rewritten together, as shown in Example 3. Vertical Admissibility, i.e., a term can contain its own address a as the address of one of its proper subterms, only if this subterm is a •a . This ensures that back-pointers for terms at address a are only denoted by the term •a . Roughly speaking, in order to maintain these requirements the definition proceeds as follows to rewrite a term U into V . 1. Match a subterm of U at address say a with a left hand side of a rule, compute the corresponding right hand side and create the new fresh addresses (if required), then replace all the subterms of U at address a with the obtained right hand side. 2. Replace some subterms by back-pointers (a fold operation), or some back-pointers by particular terms (an unfold operation), following some specific techniques (see [13]), so that the result is a vertically admissible term.
976
Fr´ed´eric Lang, Pierre Lescanne, and Luigi Liquori
Instantiation [s]a → b
a
b fresh
(OI)
b fresh
(CP)
Message Sending (M ⇐ m)[s]a → (M [s]b ⇐ m)a a b b
O ⇐ m → Sela O, m, O Sela O ← m = V b , m, U → (V U )a Sela O ← n = V b , m, U → Sela O, m, U
(SE) (SU) (NE)
Fig. 8. The Common Object Module C.
5.2 The Module L a , and needs no comments. The module L is the calculus λσw
5.3 The Common Object Module C The Common Object module is shown in Figure 8. It handles object instantiation and message sending. Object instantiation is characterized by the rule (OI) where an empty object is given an object-identity. More sophisticated objects may then be obtained by functional or imperative update. Message sending is formalized by the four remaining rules. The rule (CP) which propagates a given substitution into the receiver of the message; apply this rule means to “install” the evaluation context needed to actually proceed. The meaning of the remaining rules is quite intuitive: (SE) performs message sending, while (SU), and (NE) perform the method-lookup. We can observe here the similarity with the operational semantics of λObj+ .
Functional Update M ← m = N [s]a → M [s]b ← m = N [s]c a
b, c fresh
(FP)
Ob ← m = V a → O ← m = V c a
c fresh
(FC)
Fig. 9. The Functional Object Module F.
A Framework for Defining Object-Calculi
977
5.4 The Functional Object Module F The Functional Object module gives the operational semantics of a calculus of non mutable objects. It contains only two rules (Figure 9). Rule (FP) “pre-computes” the functional update, installing the evaluation context needed to actually proceed. Rule (FC) describes the actual update of an object of identity b. The update is not made in place and no mutation is performed, but the result is a new object (with a different objectidentity). This is why we call this operator “functional” or “non mutating”.
Imperative Update M ←: m = N [s]a → M [s]b ←: m = N [s]c a b
c b
O ←: m = V → O ← m = V a
b, c fresh
(IP)
c fresh
(IC)
x ≡ y
(VS)
Cloning Primitives shallow(x)[U/y; s]a → shallow(x)[s]a b
shallow(x)[ O /x; s] → O a
a
(SC)
refresh(x)[U/y; s] → refresh(x)[s] a
b
a
c b
refresh(x)[ O /x; s] → copy(O) a
x ≡ y
(RS)
c fresh
(RE)
copy( ) → b a
a
(CE)
copy(O ← m = V ) → copy(O) ← m = V b a
c
a
c fresh
(CO)
Fig. 10. The Imperative Object Module I.
5.5 The Imperative Object Module I The Imperative Object module (Figure 10) contains rules for the mutation of objects (imperative update) and cloning primitives. Imperative update is formalized in a way close to the functional update. Rules (IP) and (IC) are much like (FP) and (FC); they differ in address management and they are self-explaining. Indeed let us look at the address b in rule (IC). In the left hand side, b is the identity of an object O, when in the right hand side it is the identity of the whole object modified by the rule. Since b may be shared from anywhere in the context of evaluation, this modification is observable non locally, hence a mutation is performed. It is worth to note that the rule (IC) may create cycles and therefore back pointers. Intuitively, when we deal with imperative traits, we can create non admissible terms b because of cyclic references. Every reference to O in V must be replaced by •b to b avoid O ← m = V to contain itself.
978
Fr´ed´eric Lang, Pierre Lescanne, and Luigi Liquori
The primitives for cloning are shallow(x) and refresh(x). – A shallow(x) creates an object-identity for an object, but x and shallow(x) share the same object-structure. The rule (SC) can be seen as the imperative counterpart b of the rule (FVarE) of module L in case E b ≡ O , for a given b. – A refresh(x) creates for x a new object-structure isomorphic to the previous one. A refresh(x) calls, through the rule (RE), an auxiliary operator named copy. A copy(O) recursively performs a copy of the linked list, via the rules (CE), and (CO). An intuitive representation of the behaviour of those operators is given in Figure 11.
6 Understanding λObj+a 6.1 Examples of Terms b
b
Example 4. The term a ←: m = (λself.x)[ a /x; id]c d does not reduce to
a ← m = (λself.x)[ a b /x; id]c d
b
(which is a non admissible term) but instead to b
a ← m = (λself.x)[•b /x; id]c d . It is crucial to note that the sense of the two terms is essentially different, since the latter expresses a loop in the store whereas the former does not mean anything consistent, since two semantically distinct subterms have the same address b.
d
Example 5. The term a ← m = M [•d/x; id]b c ← n = N [id]e f does not reduce to
a ← m = M [•d/x; id]b c ← n = N [id]e g
f
(which is not admissible) but instead to d
f
a ← m = M [ •c /x; id]b c ← n = N [id]e g . In this last term, the back pointer •d has been unfolded following the definition of d simultaneous rewriting i.e., replaced by the term it refers to, namely •c (c is still c in the context of the subterm, and therefore • is not unfolded). This unfolding is due to the removal of the surrounding address d, which otherwise could lead to a loss of information on the shape of the term associated to the address d.
A Framework for Defining Object-Calculi
979
6.2 Examples of Derivations Example 6. Let self ext be the term defined in Example 2, and N denote the subterm λself.self ← n = λs.1. ∗ ( [id]d ← add n = N [id]c b ⇐ add n)a → (self ext ⇐ add n)[id]a − e d
→ ( ← add n = N [id] ⇐ add n) c b
a
b
→ ( e ← add n = N [id]c f ⇐ add n)a
(1) (2) (3)
O
b
→ Sela (O, add n, O )
(4) b a
→ ((λself.self ← n = λs.1)[id]c O ) b
(5)
a
→ self ← n = λs.1[ O /self; id]
(6)
∗ − →
O ← n = λs.1[ O /self; id]
(7)
b
b
g a
g h a
→ O ← n = λs.1[ Ob /self; id]
(8)
In (1,2), two steps are performed to distribute the environment inside the expression by rules (CP) and (FP), then the empty object is given an object-structure and an object identity (OI). In (3), this new object is functionally extended (FC), hence it shares the structure of the former object but has a different object-identity. In (4,5), two steps are performed to look-up the method add n (rules (NE) and (SU)). Step (6) is an application of (B). In (7), the environment is distributed inside the functional extension (FP), and then self is replaced by the object it refers (FVarG). Step (8) is simply an application of rule (FC) i.e., the proceeding of a functional extension. The final term contains some sharing, as the object-structure denoted by O and rooted at address b occurs twice. Example 7. We give a similar example, where a functional update is replaced by an imperative one. Let self ext denote the term ← add n = N , where N is λself.self ←: n = λs.1. b
∗ ( e ← add n = N [id]c f ⇐ add n)a → (self ext ⇐ add n)[id]a −
(1)
O
∗ O ←: n = λs.1[ O /self; id]g a − → b
b
b
→ O ← n = λs.1[•b /self; id]g h
(2) (3)
The first steps (1,2) are similar to the first steps (1 to 7) of the previous example. In (3), the imperative extension is performed (IC), and a subterm replaced by •b to denote the loop to the root, since the object in the environment has the same identity as the object the environment belongs to.
980
Fr´ed´eric Lang, Pierre Lescanne, and Luigi Liquori
6.3 Functional vs. Imperative (Non Mutable vs. Mutable) The functional module F can be simulated by the imperative one I. This can be simply done by combining the shallow(x) operation with an imperative update. Indeed, a functional object obtained by inheriting the properties of a prototype can be encoded by a shallow followed by an imperative method update. This proves the fact that F ⊆ I. The encoding of M ← m = N is (λx.shallow(x) ←: m = N ) M . 6.4 Cloning It is possible, using the Imperative Object module, to define a clone operation. The clone used in Figures 2 and 4, whose intuitive semantics is illustrated in Figure 11, is defined as follows: clone(x) = (refresh ◦ shallow)(x) = (λy.refresh(y)) shallow(x). The clone used in Figures 1 and 3, instead, is defined as follows: clone(x) = shallow(x).
a x
b y clone(x)
c
(1)
d
(2)
(1) y = shallow(x) (2) clone(x)= refresh (y)
Fig. 11. The embedding-based clone(x) Operator.
Since λObj+ is inherently delegation-based, it follows that an embedding-based technique of inheritance can be encoded using the Imperative Object module I. Other interesting operators can be defined by combining the different features of λObj+a .
7 Related Work – The framework λObj+a generalizes a novel technique to implement programming languages: we call this technique address-based. Addresses are attached to every entities of our framework. The graph-based implementation technique a` la Wadsworth, as well as others, can be subsumed within our framework. A type system can be defined quite easily by adding in the “context soup” also the type of addresses. As such, a type soundness result can be proved relatively simply, if we compare it with the traditional approaches of stack (a function from variables to results) and store (a function from store locations to “closures”). It is worth to note that the choice of the target calculus (an object based one) is not important; the address-based technique can be used, in principle, to implement other calculi, but it fits well to object-calculi.
A Framework for Defining Object-Calculi
981
– The framework λObj+a performs an imperative object extension: an imperative (mutable) object is a “functional (non-mutable) internal object-structure” pointed by an object-identity. To extend an imperative object means to functionally extend its object-structure while keeping its object-identity. Note that the same mechanism is used to implement method override. Among the many imperative object calculi presented in the literature, the closest are the one described in [1] (Chapter 10-11), and [5]. The first is the ςimp calculus of Abadi and Cardelli, while the second is the imperative version of λObj of Fisher, Honsell, and Mitchell. Both calculi use a stack and store technique to present the semantics of the calculus and to prove type soundness. Both calculi have an imperative override that (in contrast to our approach) substitutes the old body of a field/method with the new one. Both calculi adopt a call-by-value strategy. In addition, the calculus presented in [5] have a functional object extension. The divergence from those calculi is shown in the following table, where s&s stands for stack and store, addr. for address-based, and c.b.v. for call-by-value: [1] [5] λObj+a
model override extension self-infliction strategies s&s imperative no no c.b.v. s&s imperative functional no c.b.v. addr. funct./imp. funct./imp. yes many
Less specifically, a work is in progress [13] to formalize in a general setting all the notions of sharing, cycles, and mutation, mentioned in this paper.
8 Conclusions We have defined λObj+a , a framework for object calculi which is intended to give a firm foundation for the operational semantics of object oriented languages. Future works will focus on specific calculi as combination of modules and strategies e.g., the functional fragment with embedding and call-by-need, or the imperative fragment with delegation and call-by-value. It should also be interesting to study specific aspects like typing, strategies (see [14]) and distribution of objects across networks. Other useful extensions of this framework should be studied, such as providing an imperative override of fields in the style of [1, 5] i.e., a field look up and replacement. To this aim, a distinction has to be made between fields (and may be more generally procedures or functions that do not have a self-reference) and methods. The formalism used to describe λObj+a provides the suited tools for such an extension. Acknowledgement. The authors are grateful to Zine-El-Abidine Benaissa, Furio Honsell, and Kristoffer Høgsbro Rose for their useful comments on this work.
References [1] M. Abadi and L. Cardelli. A Theory of Objects. Springer-Verlag, 1996. [2] M. Abadi, L. Cardelli, P.-L. Curien, and J.-J. L´evy. Explicit substitutions. Journal of Functional Programming, 1(4):375–416, 1991.
982
Fr´ed´eric Lang, Pierre Lescanne, and Luigi Liquori
[3] Z.-E.-A. Benaissa. Les calculs de substitutions explicites comme fondement de l’implantation des langages fonctionnels. PhD thesis, Universit´e Henri Poincar´e Nancy 1, 1997. In french. [4] Z.-E.-A. Benaissa, K.H. Rose, and P. Lescanne. Modeling sharing and recursion for weak reduction strategies using explicit substitution. In Proc. of PLILP, number 1140 in Lecture Notes in Computer Science, pages 393–407. Springer-Verlag, 1996. [5] V. Bono and K. Fisher. An imperative first-order calculus with object extension. In Proc. of ECOOP, volume 1445 of Lecture Notes in Computer Science, pages 462–497. SpringerVerlag, 1998. [6] L. Cardelli. A language with distributed scope. Computing Systems, 8(1):27–59, 1995. [7] C. Chambers. The Cecil language specification, and rationale. Technical Report 93-03-05, University of Washington, Department of Computer Science and Engineering, 1993. [8] P.-L. Curien, T. Hardin, and J.-J. L´evy. Confluence properties of weak and strong calculi of explicit substitutions. Journal of the ACM, 43(2):362–397, 1996. [9] P. Di Gianantonio, F. Honsell, and L. Liquori. A lambda calculus of objects with selfinflicted extension. In Proc. of OOPSLA, pages 166–178. The ACM Press, 1998. [10] M. Felleisen and R. Hieb. The revised report on the syntactic theories of sequential control and state. Theoretical Computer Science, 102, 1992. [11] K. Fisher, F. Honsell, and J. C. Mitchell. A lambda calculus of objects and method specialization. Nordic Journal of Computing, 1(1):3–37, 1994. ´ [12] F. Lang. Mod`eles de la β-r´eduction pour les implantations. PhD thesis, Ecole Normale Sup´erieure de Lyon, 1998. In french. [13] F. Lang, D. Dougherty, P. Lescanne, and K. H. Rose. Addressed term rewriting systems. ´ Research Report RR 1999-30, Laboratoire de l’Informatique du Parall´elisme, Ecole Normale Sup´erieure de Lyon, 1999. [14] F. Lang, P. Lescanne, and L. Liquori. A framework for defining object calculi. Research Re´ port RR 1998-51, Laboratoire de l’Informatique du Parall´elisme, Ecole Normale Sup´erieure de Lyon, 1998. [15] P. Lescanne. From λσ to λυ, a journey through calculi of explicit substitutions. In Proc. of POPL, pages 60–69, 1994. [16] T. Lindholm and F. Yellin. The Java Virtual Machine specification. Addison-Wesley Publishing Company, 1996. [17] J. Peterson, K. Hammond, L. Augustsson, B. Boutel, W. Burton, J. Fasel, A. Gordon, J. Hughes, P. Hudak, T. Johnsson, M. Jones, E. Meijer, S. Peyton Jones, A. Reid, and P. Wadler. Haskell 1.4, a non strict purely functional language, 1997. [18] K. H. Rose. Operational reduction models for functional programming languages. PhD thesis, DIKU, København, 1996. [19] A. Tailvalsaari. Kevo, a prototype-based object-oriented language based on concatenation and modules operations. Technical Report LACIR 92-02, University of Victoria, 1992. [20] M. Tofte. Type inference for polymorphic references. Information and Computation, 89(1):1–34, 1990. [21] D. A. Turner. A new implementation technique for applicative languages. Software Practice and Experience, 9:31–49, 1979. [22] D. Ungar and B. Smith, R. Self: the power of simplicity. In Proc. of OOPSLA, pages 227–241. The ACM Press, 1987. [23] C. P. Wadsworth. Semantics and pragmatics of the lambda calculus. PhD thesis, Oxford, 1971. [24] A. K. Wright and M. Felleisen. A syntactic approach to type soundness. Information and Computation, 115(1):38–94, 1994.
A Translation of Statecharts to Esterel S.A. Seshia1 , R.K. Shyamasundar1, A.K. Bhattacharjee2, and S.D. Dhodapkar2 1
2
School of Technology & Computer Science, Tata Institute of Fundamental Research, Mumbai 400 005, India [email protected] Reactor Control Division, Bhabha Atomic Research Centre, Mumbai 400 025, India {anup,sdd}@magnum.barc.ernet.in
Abstract. Statecharts and Esterel are two formalisms that have been widely used in the development of reactive systems. Statecharts are a powerful graphical formalism for system specification. Esterel is a rich synchronous programming language with supporting tools for formal verification. In this paper, we propose a translation of Statecharts to Esterel and discuss such an implementation. A characteristic feature of the translation is that deterministic Statechart programs can be effectively translated to Esterel and hence, the tools of verification of Esterel can be used for verifying Statechart programs as well. The translation serves as a diagnostic tool for checking nondeterminism. The translation is syntax-directed and is applicable for synchronous and asynchronous (referred to as the superstep model) models. In the paper, we shall describe the main algorithms for translation and implementation and illustrate the same with examples. We have built a prototype system based on the translation. It has the advantages of the visual power usually liked by engineers reflected in Statecharts and of a language that has a good semantic and implementation basis such as Esterel that can be gainfully exploited in the design of reliable reactive systems.
1
Introduction
Significant amount of research has been done in the last decade in the design and development of reactive systems. The class of synchronous languages and various visual formalisms are two approaches that have been widely used in the study of reactive systems. The family of synchronous languages has based on perfect synchrony hypothesis which can be interpreted to mean that the program reacts rapidly enough to perceive all the external events in a suitable order and produces the output reactions before reacting to a new input event set. Embedded controllers can be abstracted in this way. Some of the prominent languages of the family include Esterel, Lustre, Signal etc. These languages are also being used widely in industry. Significant advantages of the family of synchronous
Current address:School of Computer Science, Carnegie Mellon University, Pittsburgh,PA 15217, USA, email: [email protected]
J. Wing, J. Woodcock, J. Davies (Eds.): FM’99, Vol. II, LNCS 1709, pp. 983–1007, 1999. c Springer-Verlag Berlin Heidelberg 1999
984
S.A. Seshia et al.
languages include the availability of idealized primitives for concurrency, communication and preemption, a clean rigorous semantics, a powerful programming environment with the capability of formal verification. The advantages of these languages are nicely paraphrased by Gerard Berry, the inventor of Esterel, as follows: What you prove is what you execute. Statecharts is a visual formalism which can be seen as a generalization of the conventional finite automata to include features such as hierarchy, orthogonality and broadcast communication between system components. Being a formalism rather than a language, there is no unique semantics in the various implementations and further Statechart specifications can be nondeterministic. For these reasons, even though there are powerful programming environments for Statecharts such as Statemate1 (which includes simulators), environments lack formal verification tools. Textual and graphical formalisms have their own intrinsic merits and demerits. For instance consider the following reactive system design: Consider the specification of control flow (switching of tasks) among various computing tasks and interrupt service tasks in a control software. The computing tasks switch from one to another in cyclic fashion and are shown as substates of compute proc. The interrupt service tasks are entered as a result of the occurrence of interrupt events. The history notation has been used to indicate that on return from interrupt tasks, the system returns to last executing compute task (except when event 100 ms occurs, the control returns to compute task hpt). The event wdt int occurs on system failure and it can be verified that when wdt isr is entered, the system will toggle between states wdt isr and nmi isr, which is the intended behavior. Such systems can be specified using graphical formalisms easily. The statechart for the above system is shown in Figure 1. Arguing the formal correctness from such descriptions, however, is not easy. Our work is concerned with methods that will combine advantages of using graphical formalisms for the design of reactive systems with that of using formal verification tools in textual formalisms. In this paper, we study a method of translating Statechart formalisms into Esterel with the idea that the powerful verification tools and code optimization tools of Esterel can be applied for Statechart programs. Our aim has been to provide a clean formally verifiable code for Statechart programs rather than yet another attempt to define the semantics of Statecharts. For this reason, we stick to using the Statemate semantics (refer [7]), which is an industrial strength version of Statecharts. It must be noted that Esterel is deterministic and hence, our study will confine to the deterministic class of Statecharts. However, it may be noted that the translation procedure will detect the underlying nondeterminism if any. We discuss algorithms of translation and discuss the implementations and also compare our study with respect to other similar translations of Statecharts. 1
Statemate is a registered trademark of I-Logix Inc.
A Translation of Statecharts to Esterel
985
Root
control_proc
H e_nmi
compute_proc 100ms
hpt e_hpt/s_dt1
e_nt nt
s_nt/e_nt
s_dt1/e_dt1
sc
rti_int rti_isr
dt1
nmi
nmi_isr
e_dt1/s_dt2 e_dt2
s_dt2/e_dt2 dt2
H
not_100ms wdt_int
wdt_int
net_int/e_net_int e_net_int net_isr wdt_int
wdt_isr
Fig. 1. Example of Switching Interrupts The main advantage of our translation is that the code generated is verifiable and also, Esterel optimizers can used for efficient code generation. We are currently in the process of evaluating the quality of code generated vis-a-vis other Statechart code generators. The rest of the paper is organized as follows: Section 2 briefly introduces Statecharts, Esterel and the Statemate semantics. In section 3, we discuss how we abstract out the essential details of the Statechart and the core ideas in the translation process, along with illustrative examples. Section 4 sums up the work along with comparisons to other works.
2 2.1
Background Statecharts
In this section, we present a brief overview of Statecharts (see [6] for complete details). Statechart shown in Figure 2 (derived from the example in [6]) is used for illustrative purposes. Components of a Statechart: States: These are of three types: basic states, and states and or states. Basic States are those states which do not contain any other state, e.g. lap is a basic state. An Or-state is a compound state containing two or more other states. To be in a Or-state is to be in one of its component states. In this paper, we will
986
S.A. Seshia et al.
watch stopwatch
regular
watch
zero H*
a regular
alarm
b
d (in off)
a
nonzero
mode
zero
state
reg. d (in on)
stopwatch
on d
lap
b
non-zero
alarm b
a
mode
state
off reg
Fig. 2. Statechart of stopwatch within a wristwatch - with deep history
lap
on
off
Fig. 3. AND-OR tree representation of the Statechart of wristwatch
use Or-State synonymously with XOR-state, i.e. we can be in only one of the component states at a given time. An example of an Or-state in Figure 2 is stopwatch. An And-state is also a compound state and staying in an And-state implies staying in each one of its substates. These are provided to model concurrency. The substates of an And-state may contain transitions which may be executed simultaneously. nonzero shown in Figure 2 is an And-state. Transitions: A Transition in the Statechart is a five-tuple ( source, target, event, action, condition ). The arrow on the Statechart goes from source to target and is labelled as e[C]/a, meaning that event e triggered the transition when condition C was valid and action a was carried out when the transition was taken. In general, a could be a list of actions to be taken. History and Defaults: Statecharts incorporates the idea of a history state in a OR-State. The history state keeps track of the substate most recently visited. This is denoted by H in a Or-state, as in the or-state stopwatch in Figure 2. A default state, marked by a shaded circle, is a substate of an or-state such that if a transition is made to the or-state and no other condition (e.g. enter-by-history ) is specified, then that substate must be entered by default. e.g. regular is the default substate for the watch. In Figure 2, we have a deep-history state, which means that a transition to that state implies being in the maximal most recent set of basic substates. This can be represented by history states in each one of the Or-substates. 2.2
Statemate
The informal semantics of the Statemate version of Statecharts is provided through rules describing the semantics of a step. The main rules are listed below. For detailed discussions, the reader is referred to [7].
A Translation of Statecharts to Esterel
987
1. Reactions to external/internal events and changes that occur in a step can be sensed only after completion of the step. 2. Events are “live” for the duration of the step following the one in which they occur only. 3. Calculations in a step are based on the situation at the beginning of the step 4. If two transitions are in conflict, then priority is given to that transition whose scope is higher in the hierarchy. The scope as defined in [7] is: The scope of a transition tr is the lowest Or-state in the hierarchy of states that is a proper common ancestor of all sources or targets of tr, including nonbasic states that are explicit sources or targets of transition arrows appearing in tr. 5. Each step follows the Basic Step Algorithm as described in [7]. 2.3
Esterel
The basic object of Esterel without value passing (referred to as Pure Esterel) is the signal. Signals are used for communication with the environment as well as for internal communication. The programming unit is the module. A module has an interface that defines its input and output signals and a body that is an executable statement: module M: input I1, I2; output 01, 02; input relations statement end module Input relations can be used to restrict input events and a typical exclusion relation is declared as relation I1 # I2; Such a relation states that input events cannot contain I1 and I2 together. That is, it is an assertion on the behavior of the asynchronous environment. At execution time, a module is activated by repeatedly giving it an input event consisting of a possibly empty set of input signals assumed to be present and satisfying the input relations. The module reacts by executing its body and outputs the emitted output signals. We assume that the reaction is instantaneous or perfectly synchronous in the sense that the outputs are produced in no time. Hence, all necessary computations are also done in no time. In Pure Esterel these computations are either signal emissions or control transmissions between statements; in full Esterel they can be value computations and variable updates as well. The only statements that consume time are the ones explicitly requested to do so. The reaction is also required to be deterministic: for any state of the program and any input event, there is exactly one possible output event. In perfectly synchronous languages, a reaction is also called an instant. There is one predefined signal, the tick , which represents the activation clock of the reactive program.
988
S.A. Seshia et al.
Statements: Esterel has two kinds of statements: the kernel statements, and the derived statements (those that can be expanded by macro-expansions) to make the language user-friendly. The list of kernel statements is: nothing halt emit S stat1; stat2 loop stat end present S then stat1 else stat2 end do stat watching S stat1 || stat2 trap T in stat end exit T signal S in stat end
Kernel statements are imperative in nature, and most of them are classical in appearance. The trap-exit constructs form an exception mechanism fully compatible with parallelism. Traps are lexically scoped. The local signal declaration “signal in stat end” declares a lexically scoped signal S that can be used for internal broadcast communication within stat. The then and else parts are optional in a present statement. If omitted, they are supposed to be nothing. Informal semantics of the kernel constructs are given in Appendix C.
3
The Translation
A Statechart basically denotes a network of automata with hierarchy and other properties. The crux of the translation lies in (A) Extracting the hierarchy of states and transitions, (B) Resolving the conflict in the transitions as per the Statemate semantics, (C) Generating the code corresponding to the transitions between states, (D) Generating code that models system state between transitions, and, (E) Generating code that supports communication via events and actions. In the following, we shall highlight the underlying issues of representation, resolution of conflicts and code generation. Note that we refer to signals in the Statechart as actions or events, while those in Esterel are referred to simply as signals. We first present the underlying ideas and the full code generation algorithm is presented at the end. 3.1
AND-OR Tree Representation of Statecharts
The Statechart can be represented as an AND-OR tree: being in an AND-node meaning that the system is in each of its child nodes, while being in an OR-node means that we are in exactly one of its child nodes. Such a representation allows us to express the hierarchy of states of the Statecharts in a convenient manner
A Translation of Statecharts to Esterel
989
to trace the path of arbitrary transitions. This also allows us to resolve conflicts between enabled transitions, by calculating the scope(refer to section 2.2). For purposes of code generation, we actually use an annotated representation of AND-OR tree described in the following section. An AND-OR tree representation of the Statechart of Figure 2 is shown in Figure 3. Annotated AND-OR Tree Representation: The annotated AND-OR tree keeps track of information about the Statechart pertinent for the translation, such as (i) the states and their types, (ii) hierarchy of States, and (iii) Transitions between states, which includes Entry and Exit points for each transition & Inner states that need to be hidden (signals suppressed) during a transition that exits a state. Each node A of the AND-OR tree is represented as a seven-tuple2 : (N ame, T ype, Tentry , Texit , Tloop , Tdef ault , Thistory ), where, N ame: Name of the state, viz. A. T ype: AND, OR or BASIC. Tentry : The set of all transitions that enter A. Texit : The set of all transitions that exit A. Tloop : The set of all transitions that exit one of A’s immediate child states and enters another(possibly same) child state. Tdef ault : The single transition to an immediate child state from A. Thistory : The set of transitions to the history state of A. For translating Statecharts, we need to keep track of the Entry and Exit Point Information so that the transitions including the inter-level transitions can be enabled in the translated Esterel code preserving the Statemate semantics. The actual information we need to keep track of will be clear by considering the states between which the transition takes place. Transitions in Statecharts can be broadly classified as: T1: T2: T3: T4:
Between child states of the same parent. From a parent state to its (not necessarily immediate) child state. From a child state to its (not necessarily immediate) parent state. Any transition that is not of type T1, T2 or T3.
Note that all of these transitions may not occur in a given Statechart. In particular, types T2 and T3 may not occur, but the way they are translated forms part of the translation for type T4. The book keeping of the above classes of transitions is achieved through the Node-Labelling Algorithm by keeping the appropriate entry and exit information in each node of the AND-OR tree. Node-Labelling Algorithm: Assuming levels of the nodes in the tree have already been computed (with root node having level 0, and increasing level for its child nodes), for each transition in the set Tr of transitions, the algorithm 2
We shall use node synonymously with state and vice-versa.
990
S.A. Seshia et al.
traverses the path from source node n1 to target node n2 , labelling these two nodes as well as intermediate nodes with: (i) name of the transition, (ii) type of the transition, viz. T1, T2, T3 or T4 and (iii) the fact whether the transition is entering that node or exiting it. This information is used to generate code in the translation. S
S
t3:loop:T4
B t3:y/b
t3:exit:T4, t4:entry:T1
t1:a/b
A C
D
E
B
A
t3:entry:T4, t4:exit:T1
F
t2:x/a t4:a/c
E
F
C t1:exit:T1, t2:entry:T1
Fig. 4. Example Statechart
3.2
D t1:entry:T1, t2:exit:T1, t3:entry:T4
Fig. 5. Corresponding Nodelabelled AND-OR tree
Labelling for Transition Conflict Resolution
As per Statemate semantics, two transitions are in conflict if they exit a common state A. Further, conflict resolution is based on the following: Transition t1 has priority over transition t2 if the lowest3 Or-state exited by t1 is lower than the lowest Or-state exited by t2 . Given this, if trigger events for t1 and t2 occur simultaneously then, we must ensure that t2 is not taken along with its actions. This is done by a signal hide A. On taking t1 , hide A will be emitted. Therefore, before t2 is taken, a check must be made for the presence of signal hide A. This is indicated in the AND-OR tree by traversing the tree top-down, maintaining a list of “hide-signals” that we need to label the nodes with. At a node, which has at least one transition that exits it, and which is either the source of that transition, or the last state exited by it, we label all of its children with hide A. This is to ensure that while translating, a statement to check for the presence of hide A is executed before any transition is taken. This will perform the job of hiding internal signals. The algorithm to implement hide signal labeling is omitted here for brevity. 3.3
Code-Generation
The Code-Generation is done in a top down manner traversing the AND-OR tree. In short, the process is as follows : (1) Declare all necessary signals, (2) generate code for states and transitions between states, (3) generate code to 3
Lowest means closest to the root node.
A Translation of Statecharts to Esterel
991
module A : ....
S A
a/b C
B D
trap TA’ in [ loop [ await immediate goC; trap TC in [ [[ C ]] || await immedaite a; await STEP; emit b; emit sig_C_to_A; exit TC ] end trap ] present sig_C_to_A then
module S : .... loop [ await immediate goA; trap TA in [ [[A]]; exit TA; end trap present sig_A_to_S then emit goB; end present ] end loop || loop [ await immedaite goB; trap TB in [ [[ B ]] end trap ] end loop
emit sig_A_to_S; exit TA’ /* module A exits and returns to S */ end present; ] end loop .... ] end trap ] end module
Fig. 6. Translation of a transition of type T4
do communication within the Statechart, (4) generate code to deal with special constructs such as history substates.
Declarations: Information about the following kinds of signals is stored in the annotated AND-OR tree and these are declared at each node while generating code for the module corresponding to that node. 1. External Input signals. 2. Internal Input events generated during transitions out of substates of parent node A. 3. Internal Output events(actions) generated during transitions out of substates of parent node A. 4. If A is a substate of an Or-state with history, then a valued signal new history A is used so that the history can be changed appropriately whenever transition to a substate Ai of A takes place. 5. Dummy signals for T2 or T4 transitions that enter A: In this case signals of the form sig BtoA or sig AtoB would be needed, where B is either an immediate parent or an immediate child of A. This list is built up for each such node A, during the Node -Labelling Algorithm. These signals are used to build a chain of signals that trigger transitions between immediate parentchild states, and the whole chain generates the entire transition. 6. Dummy signals for T3 or T4 transitions that exit A. Similar to 5 above.
992
S.A. Seshia et al.
7. Valued History signals for all Or-sub-states having history; for each such OR-state these store the value of the most recent substate. While building the AND-OR tree we can maintain a list of Or-states which have history. 8. Signals that indicate transition to a history4 substate of a substate of A, or if A is an Or-state, to indicate transition to history substate of A. 9. Characteristic signals (in, enter, exit) for each substate of A. To generate this list, traverse the AND-OR tree bottom-up (postorder) and at each node, add to a list of child nodes. Then while generating code for node A, declare all characteristic signals for each of its child nodes as listed. We have a new module only for each OR-node, therefore, we need not keep a list of all nine types of signals with an AND-node or BASIC-node unless it is the ROOT node. The ST EP Signal: In the Esterel code generated, each step occurs on receipt of an external signal called ST EP . This signal is needed to provide a tick on which transitions can be made even when there are no input signals from the environment (i.e. when all triggering events are internally generated). Use of STEP is necessary to implement the super-step semantics of Statemate, wherein several steps are executed starting with some initial triggering events, till the system reaches a set of stable states (i.e., states with no enabled transitions out of them). Transitions: Consider code generation for the translation for a transition t of type T , with source state A and target state B. In brief, the translation involves the following : (1) Generate code to await the occurrence of the triggering event, and, (2) on occurrence of the STEP (as in Statemate semantics), if the triggering condition is true and no transition pre-empts t, emit : (a) a signal to activate the next state (called a “go” signal), (b) a signal to activate a chain of transitions (for types T2 through T4), (c) signals to exit the current state, i.e., to terminate emission of signals that depict the current state as active. Figure 6 illustrates translations with respect to T4 transition. The complete procedure translate-transition is given in Appendix A. The parameter curr node is the node for which we are generating code. Note: For lack of space, we give only snippets of the most essential parts of the Esterel code. The full code generated is well formed and syntactically correct. Code-Generation Algorithm: In the following, we describe the basic-code generation algorithm. Code to be emitted for immediate states like history and special actions are omitted for brevity. Notation: In the code-generation algorithms, algorithm details are in Roman font while the code is boxed in Typewriter font. 4
We have implemented deep-history as a sequence of transitions between history states. Such signals are used to make transitions between history states.
A Translation of Statecharts to Esterel
993
Algorithm 1 Basic Code-Generation Algorithm: The main algorithmic steps are sketched below. 1. Traverse the AND-OR tree top-down. (in preorder) 2. For each node A do • If A is an OR-node: (a) Begin a new module, and declare all signals that occur A’s signal list, or in the signal list of child nodes of A, till the first child Or-node is encountered. (b) Generate code for each block representing the substate of A. Let A1 , A2 , ..., An be the immediate child nodes of node A. Let ei1 , ei2 , ... eim be the external or internal events on which transitions are made out of the Ai . Let the corresponding actions be acti1 to actim . Further, let the conditions under which the transitions are to be taken be Ci1 to Cim . Let the list of hide signals for the nodes Ai , ∀ i be hide1 to hidet . ST EP is a signal that indicates that the next step must be performed. It is an external signal. Steps of the translation are described below: Step 1. Emit preamble code. If A is a substate of an OR-state B with history, then appropriate newhist signals are emitted to update history. Code to be emitted from this step is given below: emit enter A; [ trap TA in [ sustain in A; [ await tick; emit newhistB(A); ] [ signal goA1 , goA2 , ..., goAn in [ · · · % to be completed in other steps
Step 2. Emit code to check for T2 and T4 transitions, or for transitions to the history substate of A. If none of these are true then default state is entered. Code from this step is given below: present case sig AtoAj do emit goAj % This is repeated for each sig AtoAj % case enterhist A do [ if histA = 1 then emit goA1 % Check for each i% elseif histA = 2 then emit goA2 else emit goAk % Ak is the default substate for A% end if end present;
Step 3. For each i, emit code to handle transitions out of Ai and also the refinement of Ai . The code for each of the i are composed in parallel. The respective codes to be emitted are given in the substeps below:
994
S.A. Seshia et al.
Substep 1. Preamble code for Ai . [ loop [ await immediate goAi ; trap TAi in · · · % Subsequent codes will be completed by other steps %
Substep 2. Emit code corresponding to the refinement of Ai . We indicate the refinement of Ai by >. If Ai is an AND-node or BASIC-node then this is the block for Ai . If Ai is an Or-node, then this is a “run Ai ” statement. In this case, add it to a queue5 of Ornodes Qnodes , so that we emit code for it and its child nodes later. When the node is visited during the preorder tree traversal, the entire subtree under that node Ai is skipped to be processed later. [ >; exit TAi ; · · · % subsequent codes will be completed by other steps %
Substep 3. Emit code for each transition triggered by eij , j = 1..m, i , and compose in parallel with the above code. i.e., 6 ∀ ti ∈ Texit call translate-transition(ti ,TYPE of ti ,Ai ); end trap % TAi
Substep 4. Code emitted in case there are transitions of type T3 or T4. Thus, for all transitions t of type T3 or T4 which exit state Ai we would have: call exit-code-trans(t,TYPE of t,Ai );
Substep 5. Postamble code for the substate Ai is given below: ] end loop ]
Step 4. The postamble code to be emitted is given below: end signal ] end trap % TA ] end module
• If A is an AND-node: (a) Generate code to emit enter and in signals for A, or for updating history, as in preamble code above. (b) Generate code for each one of A’s child nodes, Ai , and compose these in parallel. 5 6
Note that queue is implicit in the underlying tree traversal algorithm. For two transitions out of the same state with the same priority, we assume some priority order known in advance and instead of composing code for these transitions in parallel, we use the await case .. end await construct of Esterel.
A Translation of Statecharts to Esterel
995
(c) Generate code for each transition that quits a child node of A and compose each in parallel with that in item 2 above. The translation for the individual transitions is exactly as for an Or-node. There are no looping transitions of type T4 for an AND-node. • If A is an BASIC-node: Generate code to emit enter and in signals for A, or for updating history of its parent state, just as was done for the Or-state. Also generate code to begin, await a return signal from or end an activity. 3. Generate code for each of the Or-nodes in the queue Qnodes till no more Or-nodes remain in the queue. Note: Algorithm 1 preserves the priority structure of transitions based on scope by appropriately nesting the traps and using the Esterel semantics of nesting of traps. Generation of ST EP Signal: In the above Algorithm 1, each step occurs on receipt of an artificially created external signal called ST EP . Clearly, this ST EP signal cannot be generated internally, as it will not generate a tick then. Further, ST EP must be given to the state machine (system) as long as there are enabled transitions (enabled on internally generated signals). In our translation, this indication is obtained from the enter and exit signals emitted. We define a new signal “give step” which is emitted whenever an enter or exit signal is emitted. Thus, whenever give step is emitted, a ST EP signal must be emitted. Additionally, ST EP must be emitted on occurrence of an external input. The state machine generated by the Esterel compiler must interface with the environment through a driver routine. The driver routine executes the state machine whenever there is an input from the external environment. Thus, our problem is to execute the state machine under certain conditions(namely when give step is emitted) even when there is no external input. The trick here (as in [11]) is to set a bit for every occurrence of give step that is checked by the driver routine; the bit indicates that the driver routine must generate a tick (and supply a ST EP )7 . Thus, due to the presence of “await STEP” in the translation for transitions, although the actions are “activated” in the current step, they take effect only in the next step. This is in accordance with the Statemate semantics. Our translation faithfully represents all behaviors of the Statemate Statecharts, in both the Step and Superstep time models. In our translation, the STEP of Statecharts is mapped to the tick of Esterel. Time instants are indicated by a separate TIME signal. In the Superstep time model, the STEP and TIME signals are distinct, while in the Step model they always occur together. As noted in [7], a Statechart using the Superstep time model can have possible infinite loops in the same TIME instant. This can also happen in our Esterel translation, and cannot be detected using the present Esterel tools. 7
During simulation with the standard Esterel tool xes, we supply ST EP as an external input in much the same way as a tick is supplied.
996
S.A. Seshia et al.
ROOT A
t1: a/b
B t2: b/c
t3: c/a C
Fig. 7. Statechart with cycle
Let us consider the Statechart shown in fig. 7. Following are the steps executed when the event a occurs. – STEP 1: Transition t1 is enabled because of occurrence of a and the system goes from the configuration {R,A} to {R,B} and the event b is generated in the system. – STEP 2: In this step since event b is available, transition t2 is enabled and the system leaves the configuration {R,B} and goes to {R,C} and the event c is generated. – STEP 3: In this step since event c is available, transition t3 is enabled In the asynchronous time model [7], all these steps will constitute one superstep and be executed in one time instant. Each of these steps is executed when the external signal STEP is given. It is possible to detect such loops, however, we shall not discuss it here. 3.4
History
As noted in [7], history states can occur only within Or-states. History is implemented using valued history signals for each Or-state having history. The value 0 corresponds to the default state, i.e. no history. The emission of the history signal for a state S, histS is done only by the root module ROOT, of the entire Statechart. When a new state is entered within an Or-state S, the module corresponding to that state emits a newhistS signal which is captured by ROOT which in turn updates histS. The history itself is maintained as a integer valued signal8 , the integer indicating which substate of the Or-state is the most recent one. Below, we show the code part of ROOT which updates the history values. module ROOT : ··· var x in [ % the below block exists for each Or-state with history 8
However, if we use a shared variable for keeping track of the history, there will be no need to sustain the integer valued signal used for that purpose.
A Translation of Statecharts to Esterel
997
every immediate newhistS x := ?newhistS ; sustain histS(x) ; end ··· ] ··· end module 3.5
Illustrative Examples
Here, we shall discuss two examples developed and verified using the above system. Example 1. Figure 8 shows an example of the Priority Inversion problem arising due to nondeterministic behavior of the Statechart. Processes P1, P2 and P3 have priorities 1,2 and 3 respectively, and P1 and P3 share a common resource, access through which is controlled by a mutex. It can be shown (by automata reduction) that the configuration (Root, Sys, P1blocked, P2run, P3premp) is a case of priority inversion and the system is deadlocked because of the following sequence : P3 enters critical region, P1 blocks on mutex, P2 pre-empts P3 with P1 and P3 now blocked, and thus priority of P1 and P2 has been inverted. It has been verified that this will always lead to the configuration (Root,Error). To overcome deadlock, we can add one transition between the states Error and Sys, which will again bring the system to default configuration and normal operation can resume. A sample snippet of the Esterel code generated by our system is given in the Appendix. Note that the actual code generator slightly deviates from the abstract algorithms as it uses some implementation optimizations. Example 2. This is the example of switching interrupts described in section 1 depicted by the Statechart shown in Figure 1. Our translation described earlier has been applied to the Statechart shown in Figure 1 and the Esterel code obtained, tested, simulated and verified (using the Auto/Autograph tools). Some of specific properties that have been verified are: Event wdt int occurs on system failure and when wdt isr is entered, the system will toggle between states wdt isr and nmi isr, which is the intended behaviour. The actual code is not given for brevity.
4
Conclusions and Related Work
In this paper, we have proposed a translation from Statecharts to Esterel, and have applied this translation to successfully model and analyze some systems that might occur in real world problems. The translation is syntax-directed so that the translation of the entire Statecharts specification can be put together from the translation of its individual components. We have only sketched some of the algorithms for lack of space.
998
S.A. Seshia et al.
Fig. 8. Priority Inversion Example
4.1
Related Work
An early attempt towards a graphical formalism avoiding the anomalies of Statecharts was the definition of Argos (see [8]). Very recently efforts have also been reported in combining Argos and the synchronous languages Estereldescribed in [5]. Another effort of translating Statemate Statecharts to Signal has been reported in [3] where the aim has been to use Signal (another synchronous language) and its environment for formal verification purposes. Signal and Esterel are quite different considered from the point of view of verification basis and flexibility. Our approach provides the possibility of using various automatabased/temporal logic based tools for verification in a fairly natural way. A recent approach is that of Mikk et al.[9], in which the authors discuss the translation of Statecharts into another graphical formalism called Extended Hierarchical Automata(EHA). In this formulation, the inter-level transitions are eliminated, by extending the labels to include source restriction and target determinator sets. Our translation does something similar to the one that is resorted to for EHAs, in that we use dummy signals to make interlevel transitions, one for each level transcended. It must be noted that the translation in [9] is from one graphical language to another, ours is from a graphical language to a textual language. In a subsequent work [10], which is of a similar flavour as ours, Mikk et al. have translated EHAs into Promela for use with the model checker SPIN. This enables them to do LTL model checking on Statecharts. With our translation, we are able to use Esterel tools such as FC2Tools to do equivalence checking, checking for deadlock, livelock and divergent states; and
A Translation of Statecharts to Esterel
999
Hurricane, which does verification of LTL safety properties. We also support special Statechart features such as timing primitives and history. Another approach taken with the spirit of providing an integration of Argos and Esterel has been the work on SyncCharts reported in [1] and [2]. SyncCharts have a precise semantics, and is translatable to Esterel. It does not allow for inter-level transitions, and history, which are very useful features of Statecharts, and which are part of Statemate Statecharts (which we have worked with). SyncCharts however has explicit syntactic constructs for preemption such as suspension, weak abortion, and strong abortion, much like Esterel. The semantics of these constructs is the same as that of corresponding constructs in Esterel. Unlike such an approach of having another language, our aim has been to translate the existing Statecharts that is pragmatically very attractive and used widely, into an existing framework that permits formal verification. We have illustrated how the behaviours of a large class of Statecharts can be captured through the use of the unifying threads that run through the semantics of synchronous languages, both textual and graphical. Also, our aim has not been to define yet another semantics of Statecharts. Our goal has been to show how a class of Statecharts which have constructs like inter-level transitions and global communication of events, and which is used in the industrial strength tool Statemate, can be translated to a textual synchronous language and formally verified. 4.2
Summary of Work
We have translated Statecharts to Esterel version 5.10 described in [4] and a prototype system is in use. We have been using the tools of Esterel verification such as FC2tools based on bisimulation and Hurricane (from INRIA/CMA); we are also working on integrating the system with a tool being developed here by Paritosh Pandya on generating synchronous observers from DC specification of properties. A spectrum of industrial scale examples have been verified using Esterel and our translation will help combine ease of specification with this advantage of verification. The system implemented has shown that it is possible to integrate the advantages of Statecharts and Esterel in the design of reactive systems. While it is true that Statemate Statecharts and Esterel have different semantics, our translation works for a subset of deterministic Statecharts, and using a subset of Esterel constructs in a limited manner. We have thus maintained Statemate semantics while restricting the class of Statecharts we translate. The current translation also considers only simple events and actions; work is in progress to extend this to more general events and actions. To sum up, this work is interesting from many standpoints. Considered from view of Statecharts, we have found it useful as a way to incorporate formal verification and as a diagnostic tool for detecting nondeterminism. From the point of view of Esterel, it provides an integration of textual and graphical formalisms. From a practical perspective, it is possible to use heterogeneous systems such as Statecharts and Esterel together in the development of reactive systems and the use of the industrial strength Statemate shows this work has
1000
S.A. Seshia et al.
potential worth in industrial system verification. There has been a large effort in integrating synchronous languages such as Esterel, Lustre and Signal. This work has attempted to bring Statecharts in a restricted way under this umbrella. The prototype has been built and found to be effective in the design of smallscale reactive systems. Experiments are going on in the development of large complex systems using the system.
Acknowledgments We thank the anonymous referees for their valuable suggestions and comments. The work was initiated while Sanjit Seshia was with I.I.T., Bombay working on a summer project with R.K. Shyamasundar at TIFR, Bombay. He thanks I.I.T. Bombay, TIFR and CMU for their support. R.K. Shyamasundar thanks IFCPAR, New Delhi for the partial support under the project 2202-1.
References [1] Andr´ e, C. SyncCharts: A Visual Representation of Reactive Behaviors. Tech. Rep. RR 95-52, I3S, Sophia-Antipolis, France, 1995. [2] Andr´ e, C. Representation and Analysis of Reactive Behaviors: A Synchronous Approach. Tech. Rep. 96-28, Universit´e de Nice, Sophia-Antipolis, France, 1996. [3] Beauvais, J.-R. et al. A Translation of Statecharts to Signal/DC+. Tech. rep., IRISA, 1997. [4] Berry, G. A Quick Guide to Esterel Version 5.10, release 1.0. Tech. rep., Ecole des Mines and INRIA, February 1997. [5] Berry, G., Halbwachs, N., and Maraninchi, F. Unpublished note on Esterel and Argos. 1995. [6] Harel, D. Statecharts: A Visual Formalism for Complex Systems. Science of Computer Programming 8 (1987), 231–274. [7] Harel, D., and Naamad, A. The STATEMATE Semantics of StateCharts. ACM Transactions on Software Engineering and Methodology 5, 4 (October 1996). [8] LeGuernic, P. et al. Programming Real-time applications with Signal. Proceedings of the IEEE 79, 9 (September 1991), 1321–1336. [9] Mikk, E., Lakhnech, Y., and Siegel, M. Hierarchical automata as model for statecharts. In LNCS (Dec. 1997), 1345, pp. 181–197. [10] Mikk, E., Lakhnech, Y., Siegel, M., and Holzmann, G. Implementing Statecharts in Promela/SPIN. In Proc. of the 2nd IEEE Workshop on IndustrialStrength Formal Specification Techniques (1999), IEEE Computer Society. [11] Puchol, C. et al. A Formal Approach to Reactive Systems Software: A Telecommunications Application in Esterel. In Proc. of the Workshop on Industrial Strength Formal Specification Techniques (April 1995).
A Translation of Statecharts to Esterel
1001
Appendix A: Code Generation for Transitions This procedure gives the translation for a transition t of type T , with source state A and target state B. curr node is the node which we are generating code for. As mentioned before, the algorithm details are in Roman font while the emitted code is boxed and in typewriter font. procedure translate-transition (t,T,curr node) begin A := source(t); B := target(t); et := event(t); at := action(t); Ct := condition(t); /* Let hideS be signal corresponding to transition t which hides other transitions of scope less than that of t. let t be hidden by signals hide1 , hide2 , ..., hiden .*/ if ( A = curr node ) then begin EMIT :loop await (immediate) e_t; (await STEP;) if C_t then [ present hide_1 else present hide_2 else ... present hide_n else emit hideS; emit a_t; emit exit_A; if ( T = T1 ) then begin EMIT :emit goB; exit T_A; end if ( T = T2 OR T = T4 ) then begin /* Let S1 , S2 , ..., Sn be intermediate states between A and B. */ EMIT :emit sig_AtoS_1; exit T_A; % exit trap end EMIT :-
1002
S.A. Seshia et al.
/* Complete all present statements */ end present ... end present ] end if ] end loop end /* if A==curr node */ else /* if A = curr node, i.e., t of type T2 or T4 */ begin EMIT :/* Let A1 and A2 be the two immediate child nodes of A */ present sig_AtoA_1 then emit sig_A_1toA_2; end present; end end procedure Note: Above, we have assumed that the condition is a boolean expression, as in Esterel syntax. If the condition is the test of presence of a signal it must be replaced by a present SIG then ... else ... end present translation. If the condition involves testing values of shared valued signals, which could possibly change value “simultaneously”, then we need to ensure that the value tested is the one at the time of occurrence of the triggering event. This code is omitted for brevity. Further, for transitions of type T3 and T4, on exiting a state, code must be emitted for continuing the chain of transitions. This code generates signals that trigger transitions in child states. The code generation routine for this is referred to in Algorithm 1 as procedure exit-code-trans (trans, Type-of-transition, States). We omit the detailed description of this routine in this paper.
A Translation of Statecharts to Esterel
Appendix B: Esterel Code : Priority Inversion Problem Below we attach code snippets for the states P1 and P1ready. module P1ready: % Signal Declarations output EnterP1ready, InP1ready, ExitP1ready; % Program Body -------------emit EnterP1ready; do sustain InP1ready watching ExitP1ready; end module %----------------------------module P1: % Declarations deleted for brevity signal goP1ready, goP1incrit, goP1blocked, goP1, goP2ready, goP2run, goP2prempt, goP2, goP3ready, goP3incrit, goP3prempt, goP3,goSys in [ % Program Body -------------emit goP1ready; emit EnterP1; do sustain InP1 watching ExitP1; || loop await immediate goP1ready; trap outP1ready in run P1ready; || loop await % Exit case immediate [a] do present InP3incrit or InP3prempt then [ % Testing condition present HideSys then await STEP else [ await STEP;emit ExitP1ready;
1003
1004
S.A. Seshia et al.
emit goP1blocked; exit outP1ready;] end ] else [ present HideSys then await STEP else [ await STEP; emit ExitP1ready; emit goP1incrit; exit outP1ready ] end % end present ] end % end present end % end await end % end loop end % end trap end % end loop || loop await immediate goP1incrit; trap outP1incrit in run P1incrit; || loop await % Exit case immediate [ap] do present HideSys then await STEP else [ await STEP; emit ExitP1incrit; emit goP1ready; exit outP1incrit ] end % end present end % end await end % end loop end % end trap end % end loop || loop await immediate goP1blocked; trap outP1blocked in run P1blocked; || loop await % Exit case immediate [cp] do present HideSys then await STEP else [ await STEP; emit bq; emit ExitP1blocked; emit goP1incrit; exit outP1blocked; ]
A Translation of Statecharts to Esterel
1005
end % end present end % end await end % end loop end % end trap end % end loop ] end % end signal end module
Appendix C: Intuitive Semantics of Esterel At each instant, each interface or local signal is consistently seen as present or absent by all statement, ensuring determinism. By default, signals are absent; a signal is present if and only if it is an input signal emitted by the environment or a signal internally broadcast by executing an emit statement. To explain how control propagates, consider first examples using the simplest derived statement that takes time: the waiting statement “await S”, whose kernel expansion “do halt watching S” will be explained later. When it starts executing, this statement simply retains the control up to the first future instant where S is present. If such an instant exists, the await statement terminates immediately; that is the control is released instantaneously; If no such instant exists, then the await statements waits forever and never terminates. If two await statements are put in sequence, as in “await S1; await S2”, one just waits for S1 and S2 in sequence: control transmission by the sequencing operator ’;’ takes no time by itself. In the parallel construct “await S1 || await S2”, both await statements are started simultaneously right away when the parallel construct is started. The parallel statement terminates exactly when its two branches are terminated, i.e. when the last of S1 and S2 occurs. Again, the “||” operator takes no time by itself. Instantaneous control transmission appears everywhere. The nothing statement is purely transparent: it terminates immediately when started. An “ emit S ” statement is instantaneous: it broadcasts S and terminates right away, making the emission of S transient. In “emit S1; emit S2”, the signals S1 and S2 are emitted simultaneously. In a signal-presence test such as “present S ...”, the presence of S is tested for right away and the then or else branch is immediately started accordingly. In a “loop stat end” statement, the body stat starts immediately when the loop statement starts, and whenever stat terminates it is instantaneously restarted afresh (to avoid infinite instantaneous looping, the body of a loop is required not to terminate instantaneously when started). The watching and trap-exit statements deal with behavior preemption, which is the most important feature of Esterel. In the watchdog statement “do state watching S”, the statement stat is executed normally up to proper termination or up to future occurrence of the signal S, which is called the guard. If stat terminates strictly before S occurs, so does the whole watching statement; then the guard has no action. Otherwise, the occurrence of S provokes immediate
1006
S.A. Seshia et al.
preemption of the body stat and immediate termination of the whole watching statement. Consider for example the statement do do await I1; emit 01 watching I2; emit 02 watching I3 If I1 occurs strictly before I2 and I3, then the internal await statement terminates normally; 01 is emitted, the internal watching terminates since its body terminates, 02 is emitted, and the external watching also terminates since its body does. If I2 occurs before I1 or at the same time as it, but strictly before I3, then the internal watching preempts the await statement that should otherwise terminate, 01 is not emitted, 02 is emitted, and the external watching instantaneously terminates. If I3 occurs before I1 and I2 or at the same time as then, then the external watching preempts its body and terminates instantaneously, no signal being emitted. Notice how nesting watching statements provides for priorities. Now the translation of “await S” as “do halt watching S” will be clear. The semantics of halt is simple: it keeps the control forever and never terminates. When S occurs, halt is preempted and the whole construct terminates. Note that halt is the only kernel statement that takes time by itself. The trap-exit construct is similar to an exception handling mechanism, but with purely static scoping and concurrency handling. In trap T in stat end, the body stat is run normally until it executes an exit T statement. Then execution of stat is preempted and the whole construct terminates. The body of a trap statement can contain parallel components; the trap is exited as soon as one of the components executes an exit T statement, the other components being preempted. However, exit preemption is weaker than watching preemption, in the sense that concurrent components execute for a last time when exit occurs. Consider for example the statement trap T in await I1; emit 01 || await I2; exit T end If I1 occurs before I2, then 01 is emitted and one waits for I2 to terminate. If I2 occurs before I1, then the first branch is preempted, the whole statement terminates instantaneously, and 01 will never be emitted. If I1 and I2 occur simultaneously, then both branches do execute and 01 is emitted. Preemption occurs only after execution at the concerned instant: by exiting a trap, a statement can preempt a concurrent statement, but it does leave it its “last wills”. The rule for exiting from nested traps is simple:only the outermost trap matters, the other ones being discarded. For example, in
A Translation of Statecharts to Esterel
1007
trap T1 in trap T2 in exit T1 || exit T2 end; emit 0 end traps T1 and T2 are exited simultaneously, the internal trap T2 is discarded and 0 is not emitted. Traps also provide a way of breaking loops, which would otherwise never terminate as reflected by: trap T in loop ... exit T ... end end One can declare local variables by the statement var X in stat end Variables deeply differ from signals by the fact that they cannot be shared by concurrent statements. Variables are updated by instantaneous assignments “X:=exp” or by instantaneous side effect procedure calls “call P(...)”, where a procedure P is an external host language piece of code that receives both value and reference arguments.
An Operational Semantics for Timed RAISE Xia Yong and Chris George United Nations University/International Institute for Software Technology, P.O.Box 3058, Macau {xy,cwg}@iist.unu.edu http://www.iist.unu.edu/{∼xy,∼cwg}
Abstract. The reliability of software is an increasingly important demand, especially for safety critical systems. RAISE is a mathematically based method which has been shown to be useful in the development of many kinds of software systems. However, RAISE has no particular features for specifying real-time requirements, which often occur in safety critical systems. Adding timing features to RAISE makes a new specification language, Timed RAISE Specification Language (TRSL), and gives it the power of specifying real-time applications. We then have to find a theoretical foundation for TRSL. In this paper, an operational semantics of TRSL is first introduced. Then we define a pre-order and test equivalence relation for TRSL. Some proof rules for TRSL are listed, and their soundness corresponding to our operational model is also explained.
1
Introduction
The reliability of software is an increasingly important demand, especially for critical systems like train control systems or banking systems, for which failures may have very severe consequences. Mathematically based “formal” methods for specification and stepwise development of software have been invented in order to increase the reliability of software. Some of these languages provide facilities to specify concurrent systems, and therefore, they can capture various qualitative aspects of system behaviour, such as deadlock, synchronisation and safety. However, in a real-time system we may be concerned with the timing of events. We might want not merely to say that an event occurs, but to say that it occurs within a particular time interval. RAISE is a mathematically based method which has been shown to be useful in the development of many kinds of software systems. However, RAISE has no particular features for specifying such real-time requirements. Adding real-time features to RAISE Specification Language (RSL) is not only an interesting topic for theoretical computer science research, but also a requirement of some RAISE users. Integrating RSL with a real-time logic, the Duration Calculus (DC) [ZHR91], seems a good choice to achieve the above aim. RAISE has good features (in particular modularity) for describing large systems, while DC is concerned only with timing properties. The degree of overlap between the two languages is therefore very small. J. Wing, J. Woodcock, J. Davies (Eds.): FM’99, Vol. II, LNCS 1709, pp. 1008–1027, 1999. c Springer-Verlag Berlin Heidelberg 1999
An Operational Semantics for Timed RAISE
1009
We do not wish to perform a syntactic integration of RSL and DC. This would create a large language and probably cause the added complications of time to permeate much of RSL. Instead we note that adding time to a description can be seen as a design step. For example, going from “B must follow A” to “B must follow A within 3 time units” adds an extra constraint, a design decision. It therefore seems reasonable to add time within the part of RSL that is used later in design. The idea is then to be able to (partially) interpret TRSL descriptions in terms of DC formulae, and show that these formulae satisfy the timing requirements, also written in DC. So we have two tasks. The first is extending original RSL to Timed RSL (TRSL) by introducing some real-time constructs. The second step is relating TRSL to DC. This paper concentrates on the first of these. The proposed TRSL, the syntactic extension to RSL, can be found in [GX98]. Section 2 summarises the proposed extension and discusses its effect on the existing language and its proof system. After syntactically proposing TRSL, we should establish a theoretical foundation for this new specification language. The theoretical foundation we need is the proof system, the collection of rules that enable us to reason about specifications. In this paper we propose an operational semantics and show how it can be used to establish validity of proof rules. We give an operational semantics of TRSL in Section 3, define an equivalence relation among TRSL expressions in Section 4, and apply it to the proof of soundness of TRSL proof rules in Section 5. Section 6 considers future and related work.
2
Adding Time to RSL
We would like the addition of time to RSL to be the smallest extension that gives us a useful language, and if possible for it to be a conservative extension, i.e. for it to leave the existing proof rules unchanged. By “useful” we mean expressive and convenient for establishing properties. The latter implies an intuitive and simple proof system, which in turn suggests a simple semantics. The simplest extension to RSL to include time would seem to be to add a wait expression. Since we want eventually to relate timed RSL (TRSL) to DC we will make the parameter type of wait non-negative reals, which we will define as the type Time. For convenience, we allow natural numbers as arguments of wait by overloading it. A Nat argument is converted to Time by the existing RSL prefix operator real. For example, wait 1 is equivalent to wait 1.0. If we need a parallel expansion rule, it seems necessary also to add a new construct, “time dependence”, to input and output. An input, as well as returning the value input, will also return a time value representing the time elapsed between the input being ready and the the communication taking place. Similarly, an output will return the time elapsed between the output being ready and the the communication taking place. The extension defined here owes much to the work of Wang Yi [Wang91]. He in particular introduced time dependence. We also follow him in making only
1010
Xia Yong and Chris George
wait expressions, and input and output, cause or allow time to elapse. All other evolutions of expressions are regarded as instantaneous. We also follow Wang Yi in adopting the maximal progress assumption. This means that the time between an input or output being ready and the communication taking place is minimised. In other words, when an expression can evolve without waiting for the environment, it will not wait. This raises a question of what we mean by an internal (non-deterministic) choice like e1 wait 1 ; e2 where e1 and e2 do not initially wait. Blindly applying the maximum progress assumption leads to this expression evolving only to e1. But this would remove the possibility of specifying an expression that might immediately perform e1, or might (non-deterministically) wait for one time unit and then perform e2. We want to allow this possibility in specification. This leads to the need for a new operator to replace internal choice in the parallel and interlock expansion rules, where we need the “maximal progress” version of internal choice. But this is no more than the addition of another special function internal to the proof rules: it is not needed in the language. To see how wait can be used in parallel or interlocked composition, consider c? ; normal() wait 1 ; time out() The intention is that this expression initially waits for its environment to offer an output on channel c. If this output on channel c is available within 1 time unit then the communication should be accepted and normal() is executed. If the output is not available within 1 time unit then it should instead execute time out(). We can specify these behaviours using the RSL interlock operator –. Interlocked composition is like parallel composition in that the expressions evolve concurrently, but more aggressive: it forces them to communicate only with each other until one of them terminates. We expect the following equivalences to hold for any strictly positive k, assuming that time out() can not itself initially wait: (c? ; normal() wait 1 ; time out()) – (wait(1 − k) ; c!()) ≡ wait(1 − k) ; normal() (c? ; normal() wait 1 ; time out()) – wait(1 + k) ≡ wait 1 ; (time out() – wait k)
2.1
Conservative Extension
Conservative extension of RSL to make TRSL, i.e. all existing RSL proof rules being unchanged, would be ideal but does not seem to be achievable. There are two problems.
An Operational Semantics for Timed RAISE
1011
First, introducing time can reduce non-determinacy. For example, specifying an expression like the one we considered earlier, that will take a special action (time-out) if some event does not occur within a specified period, can only be specified without time as a non-deterministic choice between the normal and time-out behaviour. When time is included we may be able to calculate which behaviour will be taken; the non-determinacy may be reduced. Secondly, there are are some rules in RSL that we expect not to hold because of the kind of properties we are interested in when we want to relate TRSL to DC. DC is concerned with the duration of states, i.e. for how long properties hold. We expect properties to be reflected in the values of imperative variables in RSL. Now consider the following equivalence that is valid in RSL, provided the expression e does not involve input or output and is convergent: c? ; v := e ≡ v := e ; c? The assignment and the input can be commuted. In TRSL in general we have to introduce a let expression for the time dependence. We would expect from the RSL proof rules, provided again e does not involve input or output and is convergent, and provided also that t is not free in e, to be able to derive the following: let t = c? in v := e end ≡ let t = v := e ; c? in skip end ≡ v := e ; let t = c? in skip end It is not immediately clear what the meaning of the second expression should be, but it is clear that the last would differ from the first in changing the duration of the state in which v has the value e; the possible wait for the communication on c shifts from before the assignment to after it. So this derivation cannot be allowed in TRSL. These two examples, of reduced non-determinism and restrictions on commuting expressions, do seem, however, to encompass the problems. It also seems likely (though this is the subject of further work) that there is a reduction from TRSL to RSL (just throwing away the timing information) that is consistent with a “more deterministic” ordering: the ordering derived later in in Section 4.2. That is, any behaviour of a timed specification will be a possible behaviour of its reduction to an untimed one. The second problem involves the strengthening of applicability conditions for commuting sequential expressions.
3
Operational Semantics
For the sake of clarity, we follow the approach of [HI93, BD93, Deb94]: the operational semantics in this paper for untimed part of TRSL is closely based on them, and we only consider a core syntax of TRSL. Our operational semantics can be viewed as a version of Timed CCS [Wang91] without τ s.
1012
3.1
Xia Yong and Chris George
The Core Syntax
For simplicity we restrict the types of expressions to be Unit, Bool and Real. The set of allowed expressions includes: – As constants the reals, the booleans true and false, the Unit value (). The basic expression skip is an expression that immediately terminates successfully. We consider also the basic expression stop which represents deadlock and the basic expression chaos which stands for the divergent process. – Three binding operators that are the abstraction, the recursion and the let definition (λ, rec, let). The reader should notice that the rec is not an RSL binding operator: RSL does not syntactically distinguish recursion. In the core syntax, it is convenient to indicate where recursion may occur. – Imperative aspects are supported through the notion of variables and assignment. – We have the following combinators:
: Nondeterministic choice between two expressions (also called internal choice). One of the two expressions is selected nondeterministically for evaluation. : External choice between two expressions. The choice is context de pendent, i.e. the environment influences the choice between the two expressions. : Parallel composition of two expressions. – : The interlock operator. It is similar to the parallel operator, but more aggressive. In other words, two interlocked expressions will communicate if they are able to communicate with one another. If they are able to communicate with other concurrently executing value expressions but not with each other, they deadlock unless one of them can terminate. The interlock operator is the main novelty in the RSL process algebra. It has been devised mainly to allow implicit specification of concurrency. ; : Sequencing operator. The above operators in TRSL have the same meanings as those in RSL. We also have the extensions to be included: – TRSL is essentially independent of the time domain. For simplicity, in our core syntax of TRSL, we just assume the time Domain to be Real+0 . – The expression wait E means we first evaluate the expression E, get the result d, then delay exactly d units of time. – Expressions may communicate through unidirectional channels. The expression let t = c!E1 in E2 means: evaluate E1, send the result (when possible) on the channel c, and then evaluate E2. t records the time between the communication on c being ready and it occurring. The expression let t = c?x in E means: assign any value received on the channel c to variable x, and then evaluate E. Again, t records the time between the communication on c being ready and it occurring. More formally the BNF syntax of our language is:
An Operational Semantics for Timed RAISE
1013
Syntactic Categories: – – – – – – – –
E in Expressions x in Variables t, id in Identifiers c in Channels r in Reals T in Time τ in Types V in ValueDefinitions
Expression The BNF grammar of expressions is: V ::= id : τ | id : τ , V E ::= () | true | false | r | T | id | x | skip | stop | chaos | x := E | if E then E else E | let id = E in E | wait E | let t = c?x in E | let t = c!E in E | E E | E E | E E | E – E | E ; E | λ id : τ • E | E E | rec id : τ • E | In fact E ; E is equivalent to let id = E in E provided id is chosen so as not to be free in E. We include E ; E to give a conventional presentation. 3.2
Definition
Store A store s is a finite map from variables (noted x) to values (noted v): s = [x → v, ...] Environment An environment ρ is a finite map from identifiers (noted id) to values (noted v): ρ = [id → v, ...] Closures A closure, [ λ id : τ • E, ρ]], is a pair made of – a lambda expression : λ id : τ • E – an environment : ρ Computable Values V is the least set which satisfies: – V contains values from our types: (), true, false, ... , -1, ..., 0, ..., 1, .... – if ρ is an environment, then V contains [ λ id : τ • E, ρ]] Expressions and Computable Values The set EV of expressions and computable values is defined as EV = E ∪ V
1014
Xia Yong and Chris George
3
Events “ ” denotes any event; “” denotes visible events and silent events. Visible events Visible events a consist of : – input events : c?v – output events : c!v where c is a channel and v is a value in V. a ¯ denotes the complement action of a (e.g. : c?v = c!v). Time-measurable events ε(d) denotes waiting d unit of time, where d is a value from the time domain and d > 0. Silent events ε denotes internal moves, including internal behaviours of communication (which is denoted as “τ ” in CCS). Time Model We assume that all silent events can perform instantaneously and will never wait unnecessarily. Once both sides of a channel are ready for communication, the communication will happen without any delay (unless some other visible event or silent event happens instead) and the communication takes no time. The above assumptions are conventional and the reason for adopting them is just to make proof theory easier. Notations We introduce some notations that are used later. 1. 2. 3. 4. 5. 6. 7.
v, v , ... represent values drawn from V d, d , ... represent values drawn from the Time domain. ev, ev , ... represent values drawn from EV, a, a ¯, ε(d), ε, , ... represent events, E, Ei , ... represent expressions. x, y, ... represent variables. s, s , s , ... represent stores.
3
Configurations Our operational semantics is based on the evolution of configurations. The set of basic configurations BC is defined as: BC = {< ev, s > | ev ∈ EV ∧ s ∈ Store} The set of configurations, C, is the least set which satisfies: 1. 2. 3. 4.
BC ⊂ C α, β ∈ C implies α op β ∈ C where: op = , , , – α, β ∈ C implies α op s op β ∈ C where: op = , – α ∈ C implies α ; E, wait α, x := α, (α E) ∈ C
An Operational Semantics for Timed RAISE
1015
5. α ∈ C implies αv ∈ C 6. α ∈ C implies : (a) [ λ id : τ • α, ρ]] v ∈ C (b) [ λ id : τ • E, ρ]] α ∈ C 7. α ∈ C implies : (a) let id = α in E ∈ C (b) if α then E1 else E2 ∈ C (c) let t = c! α in E ∈ C 3.3
Operational Rules
The operational rules are given in Figure 1 and Figure 2. Each rule is divided into two parts: the lower part describes the possible evolution of the configurations, and the upper part presents the precondition of that evolution. 2 indicates that there is no precondition. We use the standard notation E[v/t] to describe the substitution of v for all free occurrences of the identifier t in E. 3.4
Semantic Function : Merge
merge(s, s, s) = s † [ x → s(x) | x ∈ dom(s) ∩ dom(s) 3.5
•
s(x) = s(x) ]
Meaning of “Sortd ” and “SORTd ”
Sortd Sortd (α) is a set of ports (channel names tagged as input or output), whose intuitive meaning is the possible (input or output) visible events that α can evolve to within the next d units of time. We define “Sortd” inductively according to configuration structures. We find that there are three kinds of configuration that can evolve with ε(d): wait, input and output. So, they are named “Basic Forms”. There are some other kinds of configurations that can evolve with ε(d), if their components are in Basic Forms. They are named “Extended Forms”. BASIC FORMS: – – – – –
Sort0 (α) = ∅ for α ∈ C Sortd (c?) = Sortd (c!) and Sortd (c!) = Sortd (c?) for any channel c Sortd ( wait < (d + d ), s >) = ∅ Sortd ( < let t = c?x in E , s >) = {c?} Sortd ( let t = c! < v, s > in E = {c!}
EXTENDED FORMS: Assume that α and β are one of the Basic Forms. – Sortd+d (waitd; E) = Sortd (E) – Sortd (α ; E) = Sortd (α)
1016
Xia Yong and Chris George
Basic Expressions
when { d > 0 }
2
2
ε
ρ < skip, s >→< (), s > ε(d)
ρ < stop, s >−→< stop, s >
2
Input
2
ε
ρ < chaos, s >→< chaos, s >
Configuration Fork ε
ε
ρ wait < (0), s >−→< (), s >
2
c?v
ρ < let t = c?x in E, s >−→< E[0/t], s † [x → v] >
2
2
ρ < E1 op E2 , s >→< E1 , s > op < E2 , s >
ε(d)
ρ < let t = c?x in E, s >−→< let t = c?x in E[t + d/t], s >
Output
where op = ,
2
Look Up
2
ε
ρ < let t = c ! E in E, s >→ let t = c ! < E, s > in E ε
ρ † [id → v] < id, s >→< v, s >
2
ε
ρ < id, s † [id → v] >→< v, s † [id → v] >
Sequencing
3 3
ρ α → α ρ let t = c ! α in E → let t = c ! α in E
2
c!v
2
ρ let t = c ! < v, s > in E −→< E[0/t], s >
2
ε
ρ < E1 ; E2 , s >→< E1 , s > ; E2
3 3
ρ α → α
ε(d)
ρ let t = c ! < v, s > in E −→ let t = c ! < v, s > in E[t + d/t]
Internal Choice
2
ρ α ; E → α ; E
2
ε
ρ < v, s >; E →< E, s >
Assignment
2
External Choice ε
ρ < x := E, s >→ x :=< E, s >
ρx
3 ρ α → α 3 := α → x :=
2
a
ρ α → α a
α
ρ α [] β → α a β [] α → α ε(d)
ε
ρ x :=< v, s >→< (), s † [x → v] >
Waiting
ε(d)
ρ α −→ α , ρ β −→ β ε(d)
ρ α [] β −→ α [] β ε(d)
β [] α −→ β [] α
2
ε
ρ < wait E, s >→ wait < E, s >
3 3
ρ α → α ρ wait α → wait α
2
ε
ρα β →α ε →β
ε(d)
ρ wait < (d + d ), s >−→ wait < d , s >
ε
ρ α → α ε
ρ α [] β → α [] β ε β [] α → β [] α
2
ε
ρ < v, s > [] α →< v, s > ε α [] < v, s >→< v, s >
Fig. 1. Operational Rules for TRSL : Part 1
An Operational Semantics for Timed RAISE
3 3
ρ α → α
Parallel Combinator
2
ε
ρ α − s − s → α − s − s 3 s − s − α → s − s − α
ρ < E1 E2 , s >→< E1 , s > s < E2 , s > a
ε
a ¯
ε
ρ α s β → α s β ε β s α → β s α
Function
2
ρ < E1 E2 , s >→< E1 , s > E2
ρ α → α
ε
ρ α s β → α s β
β s α→β s α ε(d)
3 3
ρ α → α
ε(d)
ρ α E → α E
ρ α −→ α , ρ β −→ β ε(d)
2
ε(d)
ρ < λ id : τ • E, s >→< [ λ id : τ • E, ρ ] , s >
ρ α s β −→ α s β β s α −→ β s α [ Sortd (α) ∩ Sortd (β) = ∅ ; Sortd (α) ∩ SORTd = ∅ ; Sortd (β) ∩ SORTd = ∅ ]
ε
2
9 =
3 ρ α → α 3 ρ [ λ id : τ • E, ρ ] α → [ λ id : τ • E, ρ
ε
ρ α s < v, s >→ α s s ε < v, s > s α → s s α
3 3 s → α 3 α → s
2
ρ [λ s s s α
ε
ρ < v, s > s s →< v, merge(s, s , s ) > ε s s < v, s >→< v, merge(s, s , s ) >
2
1
] α
3
ρ [ λ id : τ • E, ρ1 ] < v, s >→ [ λ id : τ • < E, s >, ρ1 ] v
ρ α → α
ε
ρ < [ λ id : τ • E1 , ρ1 ] , s > E2 → [ λ id : τ • E1 , ρ1 ] < E2 , s >
1
2
ρα s s s
2
ρ < v, s > −s − s → < v, merge(s, s , s ) > ε s − < v, s >→ < v, merge(s, s , s ) > s −
ρ α → α , ρ β → β
8 when :
1017
3 ρ1 † [id → v] α → α 3 id : τ • α, ρ ] v → [ λ id : τ • α , ρ 1
1
3
] v
< v , s >
ρ1 † [id → v] α →
3
ρ [ λ id : τ • α, ρ1 ] v →< v , s >
Let Expression
2
Interlocking
ε
ρ < let id = E1 in E2 , s >→ let id =< E1 , s > in E2
2
ε
ρ < E1 − E2 , s >→< E1 , s > −s − < E2 , s > a
3 3
ρ α → α ρ let id = α in E → let id = α in E
2
a ¯
ρ α → α , ρ β → β ε
ρα − s − β → α − s − β ε β − s − α → β − s − α
ρ let id =
ε
< v, s > in E →
2
ε
ρ α → α ε
ρα − s − β → α − s − β ε s − α β − s − α→β − ε(d)
ε(d)
ρ α − s − β −→ α − s − β ε(d)
β − s − α −→ β − s − α when { Sortd (α) ∩ Sortd (β) = ∅}
2
ε
ρ < if E then E1 else E2 , s >→ if < E, s > then E1 else E2
3 3
ρ α → α
ε(d)
ρ α −→ α , ρ β −→ β
< E[v/id], s >
If Expression
ρ if α then E1 else E2 → if α then E1 else E2
2
ε
ρ if < true, s > then E1 else E2 →
2
ε
ρ if < false, s > then E1 else E2 →
< E1 , s > < E2 , s >
Recursion ε
ρ α − s − < v, s >→ α − s − s ε < v, s > −s − α → s − s − α
ε
2
ρ < rec id : τ • E, s >→< E[rec id : τ • E/id], s >
Fig. 2. Operational Rules for TRSL : Part 2
1018
– – – – – – – – – – –
Xia Yong and Chris George
Sortd (x := α) = Sortd (α) Sortd (wait α) = Sortd (α) Sortd (let t = c! α in E) = Sortd (α) Sortd (α s s ) = Sortd (s s α) = Sortd (α) Sortd (α – s – s ) = Sortd (s – s– α) = Sortd (α) Sortd (α E) = Sortd (α) Sortd (α v) = Sortd (α) Sortd ([[λ id : τ • α, ρ]] v) = Sortd (α) Sortd (let id = α in E) = Sortd (α) Sortd (if α then E1 else E2 ) = Sortd (α) ”, “” Sortd (α op β) = Sortd (α) ∪ Sortd (β) where op = “
SORTd SORTd is a set of ports. Its definition is just same as Sortd , but can only be calculated if we know what the environment expressions are. I.e. port c? (c!) ∈ SORTd means that within d units of time, there are some other processes that will be ready for complementary communication, c! (c?), on channel c. 3.6
Commentary on Operational Rules
The transition relation is defined as the smallest relation satisfying the axioms and rules given in our operational rules. We note in particular: Time-measurable event A configuration can evolve with a time-measurable event only if all its sub-configurations on both sides of combinators , and , can evolve with this same time-measurable event. – Maximal progress Maximal progress in RSL means that once a communication on a channel is ready, it will never wait. In the rules for interlocking, the semantic function, Sortd , is used to specify that only if no pair of complementary actions, one from each side of the combinator, is ready for communication, can this configuration evolve with a time-measurable event. In the rules for parallel combinator, the condition is stronger: a configuration can evolve with a time-measurable event only when no communication is possible, either internal (between the parallel expressions) or external (between one of them and the environment). (c.f. Section 2). Using “Sort (SORT)” to guarantee that the composite processes satisfy maximal progress was first proposed by Wang Yi in his work on Timed CCS [Wang91].
4 4.1
Time Test Equivalence Definitions
– Let l be a sequence of events, α, β two configurations in C, d ∈ Time and l d > 0. We define α ⇒ β by:
ε 1. α =⇒ β if α (→)∗ β.
An Operational Semantics for Timed RAISE al
1019
a
2. α =⇒ β if for some α, α , α we have : α =⇒ α , α → α , and l
α =⇒ β. ε(d)l
ε(d)
3. α =⇒ β if for some α, α , α we have : α =⇒ α , α −→ α , and l
α =⇒ β. where stands for the empty sequence. Moreover, we merge successive time-measurable events by treating the sequence ε(d1 )ε(d2 )...ε(dn ) as the event ε(d1 + d2 + ... + dn ). – Let L be set of traces of a configuration, defined as : l
L(α) = {l | f or some β , α =⇒ β} – We define the following convergence predicates: 1. We write α ↓ if there is no infinite sequence of internal moves: ε
ε
α = α0 → α1 → ... 2. α ↓ if α ↓ a 3. α ↓ al if α ↓ and for all α if α ⇒ α then α ↓ l ε(d)
4. α ↓ ε(d)l if α ↓ and for all α if α =⇒ α then α ↓ l 5. α ↑ if α ↓ is false and α ↑ l if α ↓ l is false. – We define the set S(α) of the next possible moves of the configuration α by: c?v
S(α) = {c? | f or some v and β, α =⇒ β} ∪ c!v
{c! | f or some v and β, α =⇒ β} – We define A(α, l), the acceptance set of events of α after performing the events in the sequence l by : A(α, l) = {S(α ) | α =⇒ α } l
ε(d)
– We define : T(α) = π2 (α), if for some d > 0 and α −→ ( i.e. α can evolve an event of ε(d) in the next step ). Otherwise T(α) is defined as ∅. π2 is a “projection” function, which returns the set of stores in a configuration that can perform a time-measurable event: • For basic configurations: π2 () = {s} • For configurations, α op β where op = , – : π2 (α op β) = π2 (α) π2 (β) β) = π2 (α) ∪ π2 (β) • For configurations: π2 (α • For other configurations, e.g. π2 (α ; E) = π2 (α) The function “” is defined by {s1 , ..., sn1 } {t1 , ..., tn2 } =
i = 1...n1 j = 1...n2
{si ∪ tj }
1020
Xia Yong and Chris George
– We define W(α, l), the store set of events of α after performing the events in the sequence l by : W (α, l) = {T (α ) | α =⇒ α } l
– We define also R(α, l), the set of possible returned pairs (of values and stores) after l: l R(α, l) = {(v, s) | α =⇒< v, s >} 4.2
Equivalence of TRSL Expressions
We first define a pre-order between TRSL configurations. Definition. For α, β in C, α SOS β if for every l and for any given ρ: α ↓ l ⇒ a) β ↓ l b) A(β, l) ⊂⊂ A(α, l) c) W (β, l) ⊂⊂ W (α, l) d) R(β, l) ⊆ R(α, l) where: A ⊂⊂ B is defined by: ∀ X ∈ A • ∃ Y ∈ B • Y ⊆ X Now, we begin to define the equivalence between TRSL expressions through their operational semantics. Actually, the equivalence between TRSL configurations: α , β, can be defined as : α SOS β and β SOS α. For simplicity of future proof, we rewrite that equivalence definition as follows. – α ↑ l iff β ↑ l – if α ↓ l and β ↓ l then 1. A(α, l) ⊂⊂ A(β, l) and A(β, l) ⊂⊂ A(α, l) 2. W(α, l) ⊂⊂ W(β, l) and W(β, l) ⊂⊂ W(α, l) 3. R(α, l) = R(β, l) Definition. For any TRSL expressions: P and Q, P = Q iff for any s and for any given ρ, = 4.3
Commentary and Examples
Pre-order Our definition of the pre-order relation on two configuration : α SOS β stands for 1. 2. 3. 4.
α α α α
is is is is
more general than β, or more nondeterministic than β, or implemented by β, or more unstable than β, ...
Therefore, in order to guarantee the condition 2, we ask A(β, l) ⊂⊂ A(α, l) to hold; and to guarantee the condition 4, we ask W(β, l) ⊂⊂ W(α, l) to hold.
An Operational Semantics for Timed RAISE
d
b
2
d’ c’
c
3
b’
1 0
1021
Time a
a’ Fig. 3. A Trajectory in Two-dimension Time Space
Time Model We view processes under a super-dense model [MP93] as a trajectory in a two dimensional time space [ZH96, PD97, QZ97]. We suppose there are countably infinite time axes, indexed by natural numbers. Events and processes happen and evolve in this space. A process starts at some time on a time axis. When the process executes a time-measurable event, time progresses horizontally, and the process stays on the same time axis. When the process executes visible and silent events, it jumps vertically up to another time axis, and may have a new state there. A trajectory of a super-dense behaviour is shown in Figure 3. There are two types of turning point. One is called a start turning point (points a, b, c, d in Figure 3), from which the process will execute a timemeasurable event. The other is called an end turning point (points a’, b’, c’, d’ in Figure 3), from which the process will execute a visible or silent event. The super-dense model distinguishes clearly between time measurable events like delays and waits for synchronisation, and visible and silent events like synchronisation and assignments. It allows arbitrary numbers of the latter to occur instantaneously but in some order, which matches well with the interleaving semantics of concurrency in (T)RSL. In our time test equivalence definition, for two equivalent processes (expressions), α and β, demanding A(α, l) = A(β, l) guarantees the same possible temporal order of visible events and time-measurable events of the two processes. Demanding W(α, l) = W(β, l) guarantees that the stores (variable states) of two processes (expressions) on every start turning point are the same. Demanding R(α, l) = R(β, l) guarantees that two expressions, if they terminate, can return the same sets of possible values and final stores.
5 5.1
Soundness of Proof Rules Proof Rules of TRSL
One of the major reasons for expressing specifications in a formal language like (T)RSL is to prove properties of specification. Therefore, a proof system for
1022
Xia Yong and Chris George
TRSL should be set up. We list some of the proof rules involving newly added time constructs. [ wait annihilation ] wait 0.0 skip [ wait plus ] wait er ; wait er
˙ er) wait(er +
[ wait introduction ] e wait er ; shift(e, er) when pure(er) ∧ convergent(er) ∧ er ≥ 0.0 ∧ must wait(e, er) The complete set of proof rules can be found in [GX98]. The original “special functions” convergent, pure, express,etc. are defined in [RMG95]. New special functions must wait, shift, etc. are defined in [GX98]. The parallel expansion rule is changed to: eu eu if parallel ints(eu, eu) ≡ swap parallel exts(eu, eu) then parallel exts(eu, eu) else parallel exts(eu, eu) parallel ints(eu, eu))"˙ (parallel exts(eu, eu) parallel ints(eu, eu ) end when isin standard form(eu) ∧ isin standard form(eu) ∧ (2 assignment disjoint(eu, eu)) ˙ is the “maximal progress” version of the internal choice where the operator “"” operator mentioned in Section 2 and defined in [GX98]. The other “dotted” ˙ are simple extensions of the standard arithmetic operators, operators like “+” returning zero if the result would otherwise be negative. The revised definitions of parallel exts, parallel ints, and interlock ints are (showing just one case of each): parallel exts(wait er ; let (b,t) = c? in eu end, eu) ˙ t) end wait er ; let (b,t) = c? in eu shift(eu, er + when no capture(b, eu) ∧ no capture(t, eu) ∧ no capture(b, er) ∧ no capture(t, er) parallel ints(wait er ; let (b,t) = c? in eu end, wait er ; let t = c!e in eu end) ); wait max(er,er ˙ ˙ er,t,eu) end ˙ er,t,eu) subst expr(er − let b = e in subst expr(er − when no capture(b, eu ) ∧ no capture(b, er) ∧ no capture(b, er)
An Operational Semantics for Timed RAISE
1023
interlock ints(wait er ; let (b,t) = c? in eu end, wait er ; let t = c!e in eu end) ); wait max(er,er ˙ ˙ er,t,eu) end ˙ er,t,eu) – subst expr(er − let b = e in subst expr(er − when no capture(b, eu ) ∧ no capture(b, er) ∧ no capture(b, er)
5.2
Soundness
We would like to show that – The original RSL Proof Rules for the TRSL expressions not involving time (e.g. simple assignment expressions) still hold in our semantic model. – Most of the original RSL Proof Rules for TRSL expressions involving time (e.g. input expressions, output expressions) with newly added side conditions hold in our semantic model. – New rules applied to extended operators are sound with respect to our operational semantics – In our semantic model, no new rules for the original RSL syntax are generated. As mentioned in Section 2.1, not all the original RSL proof rules are sound with respect to our semantic model. However, it is trivial to prove that all the original proof rules for TRSL expressions not involving time-measurable events still hold in our semantic model, because our semantics and the definition of equivalence are just the same as the original one, if we ignore the “ε(d)” transitions. For the same reason, it is clear that no new rules for the original RSL syntax are generated in our semantic model. We need to add side conditions to some of the proof rules for TRSL expressions involving time-measurable events. We are interested in proving the soundness of these rules with respect to our semantic model. Most of the rules that we need to study are listed on page 457 of [RMG95]. Of course we should also prove the soundness of rules for the extended operators too. above recommendations.
Proof Here we just show one example. Other detailed proofs can be seen in [GX98] [ ext choice replacement ] e e e e when (e ≡ e) ∧ (e ≡ e)
1024
Xia Yong and Chris George
Proof for any s, for any given ρ, – For Divergence: if one of the configuration is divergent, w.l.g. suppose ↑ l, because e ≡ e, we have ↑ l too. then from the 3rd rule in External Choice (c.f. Section ??), we know ↑ l and ↑ l
– if none of configurations are divergent, we would like to prove e, s>, l) : 1. for any l, we have A(, l) = A(, l) = A(, and A(, l) ⊇ A(, l). So A(, l) = l) ∪ A(, l). For the same reason, we know A(, l). So A(, l) = A(, l) : 2. for any l, we have W(, l) = W(, l) = W(, l) ∪ W(, l). Because l) and W(, l). So, we get W(, l) = W(, l) : 3. for any l, we have R(, l) = R(, l) = R(, l) ∪ R(, l). because l) and R(, l) at last. We get R(, l) = R( Z_PART(v_1’,...,v_n’) -- event within Z_PART(ini(v_1), ...,ini(v_n)) ||α(main) main The abbreviation α(main) stands for the alphabet of the process main (the set of channel names occurring in it) and |~|DIV is a special internal choice operator capturing the case that the index set of the iterated |~| is empty, in this case the process diverges. The intuition behind the use of this operator is the following: if an operation is enabled but its effect is not defined for the current state (yielding an empty effect set), the process behaves as completely undetermined, it diverges. The structure of the translated class can be further simplified when there are no input or no output parameters of a channel, or when the effect of an
Data Abstraction for CSP-OZ
1033
operation is deterministic, i.e. the effect set contains a single value. None of our examples will use the general structure, most often the Z part is simply of the form guard1 & ch_1 -> Z(...) [] guard2 & ch_2 -> Z(...) .... The translation of the class Pool given above is: Elem = {0..10} channel signal channel in, out: Elem POOL = let -- CSP part main = in?x -> signal -> main [] out?x -> main -- Z part Z_PART(pool) = (true & signal -> Z_PART(pool)) [] (true & in?x -> Z_PART(union(pool,{x}))) [] (not(empty(pool)) & |~| el:pool @ out.el -> Z_PART(diff(pool,{el}))) within Z_PART({}) [| {| signal,in,out |} |] main 2.3
CSP Semantics
The standard semantic model of CSP is the failure-divergence model. The same model has been used in [7] to give a semantics to CSP-OZ, by defining a failuredivergence semantics for the Z part. Thus a uniform semantics is achieved. An alternative weaker semantic model which is also supported by FDR is the trace model. We will use both models here. The trace model is sufficient for studying safety properties, while for liveness properties (e.g. deadlock or livelock freedom) a more discriminating semantics has to be chosen. Traces record the possible runs of a process, failures additionally give sets of events that are refused after some run, and divergences describe the set of traces after which the process may diverge, i.e. perform an infinite number of internal events. Thus, given a set of events Σ (typically of the form ch.v , where ch is a channel name and v a value), we have ∗ traces(P ) ⊆ 2Σ ∗
failures(P ) ⊆ 2Σ ×2 ∗ divergences(P ) ⊆ 2Σ
Σ
These semantic models are used to compare processes and check properties on them. The most important comparison concept in CSP theory is refinement: Definition 1. A CSP process P1 is a failure-divergence refinement of a process P2 (denoted P2 %F P1 ) if failures(P2 ) ⊇ failures(P1 ) and divergences(P2 ) ⊇ divergences(P1 ). They are failure-divergence equivalent (P1 =F P2 ) if P1 %F P2 and P2 %F P1 .
1034
Heike Wehrheim
If P1 is a refinement of P2 , it can be seen as an implementation of P2 since it is more deterministic than P2 . A weaker refinement notion is obtained when only the traces are used for comparison: Definition 2. A CSP process P1 is a trace refinement of a process P2 (denoted P2 %T P1 ) if traces(P2 ) ⊇ traces(P1 ). Both refinement notions are compositional (or monotone): given two processes P1 , P2 and a CSP context C [·], then P1 % P2 ⇒ C [P1 ] % C [P2 ], where % ∈ {%T , %F }. There are two possibilities for deriving the semantics of a CSP process: by a denotational semantics which compositionally computes traces, failures and divergences, or via a structured operational semantics which constructs a transition system for a process, from which traces, failures and divergences are computed. Both semantics are consistent: they compute the same traces, failures and divergences of a process. We refer to [18]) for details. A summary of CSP operators in FDR syntax can be found in the appendix. The two operators which will be used in our results are – parallel composition with sychronisation on some set of events A: ||A , and – renaming: [R], which renames all events according to the renaming relation R. We use general renaming relations, not just injective functions. As an example for a CSP process with renaming: Let P = a → SKIP and R = {(a, b), (a, c)}, then P [R] is equal to b → SKIP 2 c → SKIP .
3
Data Abstraction
Since CSP-OZ specifications may contain rather large amounts of data, the state space of the resulting CSP process can often be too large to be processed by FDR. Several techniques have already been proposed to overcome this problem; especially in the book of Roscoe [18] several methods can be found together with various application examples. The technique we propose here is based on abstract interpretation of programs [4] and can be seen as complementing the other techniques. Abstract interpretation is a technique for program analysis which is often used in compiler design for static analysis (e.g. data-flow analysis, strictness analysis, etc.). The results of an abstract interpretation can for instance be used in type checking or optimisation. The idea of abstract interpretation is to interpret a program in an abstract domain using abstract operations. The main advantage is that the concrete program does not have to be executed while still being able to obtain information about its real execution. For verification of formal specifications, the basis of abstract interpretation is to construct an abstract model of the specification on which abstract properties can be proven which give information on the concrete model [5, 1, 14]. For this, the data domain of the concrete program
Data Abstraction for CSP-OZ
1035
has to be abstracted and operations of the program are abstractly interpreted on the new data domain. In order to apply data abstraction techniques to CSP-OZ, we first have to make clear what the data is we want to abstract, and what the operations are we want to interpret abstractly. Since the goal is to use FDR for automatic verification of properties on the abstracted systems, we certainly cannot change the semantics of CSP operators in any way. What may be interpreted abstractly are the enable and effect operations coming from the Z part of the CSP-OZ specification. The relevant data domains to be abstracted are the domains of the state variables: D1 , . . . , Dn for variables v1 , . . . , vn , and the domains of the channels: M1 , . . . , Mk for channels ch1 , . . . , chk . We assume that a domain of a channel chi is split into a domain for input parameters Miin and for output parameters Miout . Then the enable and effect operations have the following signature (we will refer to this concrete semantics of enable and effect by using the semantic brackets [ ·]]): →B [ enable chi ] : D1 × . . . × Dn out [ effect chi ] : (D1 × . . . × Dn × Miin ) → 2Mi ×D1 ×...×Dn Instead of interpreting the CSP program on these concrete data domains with the concrete meaning of enable and effect operations, we use abstract data domains and abstract interpretations of enable and effect. For this, we first choose abstract data domains DiA and MjA and abstraction functions: hi : Di → DiA gj : Mj → Mj A We define h(d1 , . . . dn ) := (h1 (d1 ), . . . , hn (dn )) and let (h, g)(d1 , . . . , dn , m) stand for (h1 (d1 ), . . . , hn (dn ), g(m)). In the following, we will abbreviate (d1 , . . . , dn ) simply by d . For a given abstraction function g of channel values, we let G denote the corresponding renaming function on events: G(chi .w ) = chi .g(w ). An abstract interpretation [ ·]]A of enable and effect operations operates on abstract data domains: →B [ enable chi ] A : D1A × . . . × DnA out A A A A [ effect chi ] A : (D1A × . . . × DnA × Miin ) → 2Mi ×D1 ×...×Dn In order to use FDR as a model-checker on abstracted systems, we have to replace the concrete enable and effect predicates by abstract predicates enable A A A and effect A such that [ enablech ] = [ enablechi ] A and [ effectch ] = [ effectchi ] A i i holds, i.e. the concrete semantics of the new enable and effects must equal the abstract semantics of the old ones. Furthermore channels have to be declared over the abstract domains. These changes can already be done in the CSP-OZ specification, the designer does not have to look at the CSP code at all. So far, we are free to use whatever abstract interpretation we want. Of course, the abstracted system should somehow reflect the behaviour of the concrete system: we want to abstractly observe the events of the concrete system. To
1036
Heike Wehrheim
ensure this, we have to impose conditions on the abstract interpretations. We consider two types of abstract interpretations: safe and optimal interpretations. Definition 3. An abstract interpretation [ ·]]S of enable and effect predicates is safe with respect to abstraction functions h and g iff ∀ d ∈ D A : [ enable chi ] S (d A ) ⇔ ∃ d ∈ D : h(d ) = d A ∧ [ enable chi ] (d ) and ∀ d ∈ D A, m ∈ M A : [ effect chi ] S (d A , m A ) =
(h, giout )([[effect chi ] (d , m))
(d,m)∈D×M h(d)=d A ,gi (m)=m A
A safe abstract interpretation guarantees that in a state of the abstract system a communication over some channel is possible whenever there is some corresponding concrete state in which this communication is enabled. The result of a safe abstraction is an abstract system that allows more moves than the concrete system. An abstraction which more faithfully represents the concrete system, is an optimal abstraction. Definition 4. An abstract interpretation [ ·]]O of enable and effect predicates is optimal with respect to abtraction functions h and g iff and ∀ d ∈ D A : [ enable chi ] O (h(d )) ⇔ [ enable chi ] (d ) ∀ d ∈ D , m ∈ M A : [ effect chi ] O (h(d ), gi (m)) = (h, giout )([[effect chi ] (d , m) A
An optimal abstracted system exactly mimics the behaviour of the concrete system, only the precise values of communication cannot be observed anymore. Depending on the choice of abstraction functions, it may not be possible to find an optimal abstract interpretation. Optimality requires abstraction functions which guarantee that all concrete states which are abstracted into the same abstract state abstractly behave ”the same”. Note that every optimal abstraction is safe. Tool support for proving optimality or safety of interpretations is available in the form of theorem provers for Z [13, 15]. Given a specification S , we let S S refer to a safe and S O to an optimal abstraction of S . What is now the relationship between the behaviour of the abstracted and the concrete system? Our goal is to express this relationship completely in terms of process algebra notions. This enables us to use all of the process algebra theory for further manipulation of the result. In the abstracted system we can, of course, only observe communications with abstract values. This is the nature of abstract interpretation, we have lost some information about the concrete system, in our case the concrete values of communication. Thus we can only compare the abstracted system with the renamed concrete system:
Data Abstraction for CSP-OZ
1037
Theorem 1. Let S be a CSP process in CSP-OZ form, g1 , h1 abstraction functions for a safe and g2 , h2 for an optimal interpretation. Then the following holds: S S %T S [G1 ] S [G2 ] =F S O .
and
The proof can be found in the appendix. This result can be the basis for further process algebraic computations; for instance compositionality of trace refinement immediately gives us (S S )[G −1 ] %T (S [G])[G −1 ]. The latter is equal to S [G ◦ G −1 ] which itself can easily be shown to be trace refined by S : S [G ◦ G −1 ] %T S . All in one, we therefore get: (S S )[G −1 ] %T S This result refers directly to the concrete system S . With the help of this abstraction theorem, we are now able to proof properties of a CSP-OZ class S in the following way: – construct an abstract class specification: choose abstract domains, abstraction functions and abstract enable and effect predicates, – show safety/optimality of abstraction (supported by some theorem prover extension for Z), – translate the abstract specification into FDR-CSP (in future automatic), – show property for S S /S O (FDR), e.g. Prop %T S S , – conclude the holding of a concretised property for S (abstraction theorem), e.g. Prop[G −1 ] %T S . Most of these steps in the verification are tool-supported or even automatic. Nevertheless, the crucial part of abstraction, finding good abstract domains and abstraction functions, is still left to the user. [1] gives some heuristics for the choice of abstraction functions.
4
First Example: An Optimal Abstraction
The following example gives a first impression of data abstractions for CSPOZ. It is an optimal abstraction, that reduces an equivalence check between an infinite state and a finite state specification to an equivalence check between two finite state systems. Although both systems are very simple, this already shows the potential of abstract interpretation. Both specifications describe a simple clock with alternating tick and tock events. While in the first clock the alternation is encoded by the usage of enabling predicates (the Z part uses a counter), Clock1 = let -- empty CSP part
1038
Heike Wehrheim
main = SKIP -- Z part Z_PART(n) = odd(n) & tock -> Z_PART(n+1) [] even(n) & tick -> Z_PART(n+1) within Z_PART(0) ||| main the second clock encodes alternation in the CSP part. Clock2 = let -- CSP part main = tick -> tock -> main -- Z part Z_PART = true & tick -> Z_PART [] true & tock -> Z_PART within Z_PART [| tick,tock |] main Hence an equivalence proof of both clocks by separate data and process refinement proofs is not possible. FDR can also not be used since the state space of the first clock is infinite. We now apply the following abstraction function h to the first clock 0 if even(k ) h : k → 1 if odd (k ) and replace the enabling and effect operations by their following abstract versions: (+1)A (k ) := (+1)(k )mod 2, even A (k ) := even(k ), odd A (k ) := odd (k ). This is an optimal abstract interpretation for Clock1 with respect to h. Note that in this case no abstraction function for channel values is needed and thus the renaming function G of Theorem 1 is empty. Thus we get the first result: Clock 1O =F Clock 1. The abstracted clock is now finite state, thus we can use FDR for checking whether Clock 1O =F Clock 2 (the answer is yes), and this implies Clock 1 =F Clock 2. This rather simple example (without input and output parameters) also reveals close similarities between data abstraction and data refinement (which is the standard refinement notion within Z). The data abstraction we have used here is in fact also a valid data refinement (from Clock 1 to Clock 1O and vice versa). In general, in our setting every optimal data abstraction can also be seen as a data refinement plus a renaming.
5
Compositionality
In this section, we will be concerned with the issue of compositionality of data abstractions. Two aspects will be considered here: – combining abstraction results for different objects of a system, and – combining different abstractions of the same object. The results we get here are formulated within the traces model, thus we only deal with safety properties.
Data Abstraction for CSP-OZ
5.1
1039
Composing Objects
In general, we will not be interested in a single object alone, but in a system which is composed out of a number of objects operating in parallel. Thus we have to extend our abstraction theorem to parallel compositions of objects. Two aspects are helpful for this extension: the first is the fact that the abstraction theorem for objects is completely formulated within process algebra theory, and the second is the compositionality (monotonicity) of both trace and failure refinement. Consider a system S composed out of two objects S1 and S2 operating in parallel with synchronisation on some set A ⊆ Σ: S = S1 ||A S2 . So far, we are able to prove properties of S1 and S2 alone by for instance using some safe abstraction with respect to abstraction functions h1 , g1 , h2 , g2 respectively. By our abstraction theorem, we know that S1S %T S1 [G1 ] and S2S %T S2 [G2 ]. The first prerequisite for a combination of the abstracted objects is the preservation of their communication ability: the abstraction functions for the channel values have to agree on joint channels. Definition 5. Let g1 , g2 be abstraction functions for S1 ’s and S2 ’s channel values and let A = α(S1 ) ∩ α(S2 ) be the set of joint events, with channel names Ch in A. g1 and g2 agree on A iff for all ch ∈ Ch, v ∈ Dch , g1,ch (v ) = g2,ch (v ). When the abstraction functions of the components agree on the joint events of the components, we can look at the abstracted system as S S = S1S ||G1 (A) S2S . Compositionality of trace refinement already gives us the following result: S1S ||G1 (A) S2S %T S1 [G1 ] ||G1 (A) S2 [G2 ] However, the left hand side is not the system we are actually interested in, namely S1 ||A S2 . The next proposition helps us towards this goal. Proposition 1. Let f : Σ → Σ be a renaming function and A ⊆ Σ a set of events such that a ∈ A ⇔ f (a) ∈ f (A) holds; let P1 , P2 be CSP processes. Then P1 [f ] ||f (A) P2 [f ] %T (P1 ||A P2 )[f ] All renaming functions G generated by some abstraction function g have the above stated property, thus we immediately get: S1 [G1 ] ||G1 (A) S2 [G2 ] %T (S1 ||A S2 )[G1 ∪ G2 ] Combining these two parts, we get the following compositionality result: Corollary 1. Let S1 , S2 be CSP processes in CSP-OZ form, g1 , g2 abstraction functions which agree on joint events of S1 and S2 . Then S1S ||G1 (A) S2S %T (S1 ||A S2 )[G1 ∪ G2 ] . Thus we have extended our abstraction theorem for safe abstractions to parallel compositions of objects. Unfortunately, this result cannot be extended to optimal abstractions in the sense, that we may replace trace refinement by failures equivalence. Proposition 1 does not even hold for trace equivalence since the concrete components may fail to synchronise while their abstractions communicate.
1040
5.2
Heike Wehrheim
Combining Abstractions
Besides compositions of objects, we are also interested in composing different abstraction results of the same object. The idea is to use different abstractions to prove different properties of an object and afterwards combine these abstractions to show that also their combination holds. Consider an object S and two different safe abstractions wrt. h1 , g1 and wrt. h2 , g2 . We prove two properties of the object via abstractions, using FDR to show Prop1 %T S S1 and Prop2 %T S S2 . With the abstraction theorem and monotonicity of trace refinement we get Prop1 [G1−1 ] %T S and Prop2 [G2−1 ] %T S which can again be combined to give Prop1 [G1−1 ] ||α(S ) Prop2 [G2−1 ] %T S ||α(S ) S Furthermore, S ||α(S ) S =T S . Combining these two parts, we obtain as a corollary: Corollary 2. Let S be a CSP process in CSP-OZ form, g1 , g2 abstraction functions for its channels, Prop1 , Prop2 arbitrary CSP processes. Then Prop1 [G1−1 ] ||α(S ) Prop2 [G2−1 ] %T S . Afterwards we can use process algebra theory to compute the overall property Prop = Prop1 [G1−1 ]||α(S ) Prop2 [G2−1 ]. When the abstractions have been carefully chosen (and when they fit together well), Prop might indeed be the property of interest. The following example demonstrates the use of both kinds of compositionality results. 5.3
Illustrating Example
The example is a 1-to-2n router with n stages (Figure 1 shows a router with two stages). Stage i contains 2i switches which one input (in) and two outputs out 0 (out 0, out 1) each. 0 in The messages which are send through the router out 0 in consist of an address (a biout 1 1 nary number of length n) out 1 out 0 2 and a data part. The address is used for routing: a in switch at stage i looks at out 1 3 the i-th bit of the address; when it is 0 it sends the Fig. 1. A 1-to-2n router message to the upper channel (out 0), otherwise to the lower channel (out 1). Receipt of messages is acknowledged (ack ) and the switches delay the next input until an acknowledge has been received (rack ). Thus the router contains at most one message. The following CSP specification in CSP-OZ form describes a router with 2 stages.
Data Abstraction for CSP-OZ
1041
Adr = {|x1 rack0 -> SKIP [] out1?x -> rack1 -> SKIP); ack -> main -- Z Part Z_Part(adr,msg) = (true & in?a?d -> Z_Part(a,d)) [] (nth(adr,i) == 0 & out0.adr.msg -> Z_Part(adr,msg)) [] (nth(adr,i) == 1 & out1.adr.msg -> Z_Part(adr,msg)) within Z_Part(,0) [| {| in,out0,out1 |} |] main ROUTER = ( SWITCH(1) -- the router [out0 in0, out1 in1, rack0 ack0, rack1 ack1] (SWITCH(2)[[in OUTA(x) OUTA(adr) = (adr == & out0.adr.0 -> ACBUF) [] (adr == & out1.adr.0 -> ACBUF) [] (adr == & out2.adr.0 -> ACBUF) [] (adr == & out3.adr.0 -> ACBUF)
DCBUF = in?x?y -> OUTD(y) OUTD(d) = out0..d -> DCBUF [] out1..d -> DCBUF [] out2..d -> DCBUF [] out3..d -> DCBUF
and we ask FDR whether the following two assertions are valid (a check for trace refinement): assert ACBUF [T= ROUTERA1 assert DCBUF [T= ROUTERA2 The answer is yes. This so far proves that ACBUF[G1−1 ] %T ROUTER and DCBUF[G2−1 ] %T ROUTER. Combining these two abstractions we get: ACBUF[G1−1 ] ||α(ROUTER) DCBUF[G2−1 ] %T ROUTER
Data Abstraction for CSP-OZ
1043
It is easy to prove within process algebra theory (by giving a divergence respecting bisimulation relation) that ACBUF[G1−1 ] ||α(ROUTER) DCBUF[G2−1 ] is failures equivalent to BUF. Thus we have proven the desired property: BUF %T ROUTER. For the here chosen domain for Data, the refinement check is still possible for FDR; nevertheless the abstraction reduces a check of 16975474 states in about 170 minutes (on a SUN Ultra 2C with two processors at 300 MHZ each and 896 MB) to one of 1152511 states in 5 minutes.
6
Conclusion
In this paper we have proposed a data abstraction technique for CSP-OZ, which was based on the idea of abstract interpretation of specifications. We have shown how properties of concrete specifications are preserved by abstraction by relating the abstract to the renamed concrete specification. We studied compositionality of class abstractions and showed how abstraction results can be combined to give more information about the concrete system. The advantage of our method is that it is both simple to carry out (abstraction requires only small local changes in the CSP-OZ specification) and the results are easy to interpret. Specification, verification and abstraction is formulated within the CSP setting. So far, the object-oriented nature of the specification language has played no role in the verification. We intend to further investigate how the object-oriented structuring of specifications can be exploited to facilitate verification. Related work. Besides the work already discussed in the introduction, we want to further comment on some related work, especially on the work of Roscoe, both because it deals with CSP and because of its great variety of techniques. The book [18] presents several methods that can be used to analyse CSP programs which are per se too large to be processed with FDR. These techniques include – abstraction techniques based on hiding, – local deadlock analysis and – data independent property checks. Especially the last point is of interest for data abstraction: data independence (first studied by Wolper [23]) is concerned with the behaviour of programs independent of some of their parameters. For instance, one might be interested in knowing whether a buffer specification works like a buffer independently of the stored elements. Roscoe [18] reports on some work (together with Lasic) that allows to compute thresholds on the size of data domains used for particular parameters, such that it is sufficient to check a property on a given program with parameters instantiated with a domain of this size and conclude correctness for all instantiations with larger domains. This could very much facilitate correctness checks for CSP programs, since it is to be expected that usually a data independent program with a small data domain already exhibits all the ”relevant” behaviour. The router example could profit from this technique; it is possibly sufficient to check the trace refinement on a domain of Data of size 2.
1044
Heike Wehrheim
The clock example is, however, not amenable to such techniques since it is not data independent: it contains tests on data values (even, odd ). Data independence has also been an issue in other work on verification; a very interesting approach in a process algebraic setting is [12]. Jonsson and Parrow study programs which are completely data independent (no modification on data, no testing of values) and show that bisimulation is decidable on this class of systems, even when the data domain is infinite. Their idea could possibily also be used for refinement, but is limited to this restricted class. Acknowledgements. Many thanks to E.-R.Olderog, C.Fischer, H.Dierks and J.Bredereke for discussions on the paper.
References [1] E.M. Clarke, O. Grumberg, and D.E. Long. Model checking and abstraction. In 19th ACM POPL, 1992. [2] R. Cleaveland and J. Riely. Testing-based abstractions for value-passing systems. In B. Jonsson and J. Parrow, editors, CONCUR’94, volume 836 of Lecture Notes in Computer Science, pages 417–432, 1994. [3] J. Corbett. Constructing abstract models for concurrent real time software. In International Symposium on Software Testing and Analysis, 1996. [4] P. Cousot and R. Cousot. Abstract interpretation: A unified lattice model for static analysis of programs by construction or approximation of fixpoints. In 4th ACM POPL, 1977. [5] D. Dams, O. Grumberg, and R. Gerth. Abstract interpretation of reactive systems: Abstractions preserving ∀ CTL∗ , ∃ CTL∗ and CTL∗ . In E.-R. Olderog, editor, Programming concepts, methods and calculi, volume A-56, pages 573–592. Elsevier, 1994. [6] R. Duke, G. Rose, and G. Smith. Object-Z: A specification language advocated for the description of standards. Computer Standards and Interfaces, 17:511–533, 1995. [7] C. Fischer. CSP-OZ: A combination of Object-Z and CSP. In H. Bowman and J. Derrick, editors, Formal Methods for Open Object-Based Distributed Systems (FMOODS ’97), volume 2, pages 423–438. Chapman & Hall, 1997. [8] C. Fischer and H. Wehrheim. Model-checking CSP-OZ specifications with FDR. In IFM ’99: International Workshop on Integrated Formal Methods, Workshops in Computing. Springer, 1999. [9] Formal Systems (Europe) Ltd. Failures-Divergence Refinement: FDR2 User Manual, Oct 1997. [10] J.F. Groote and A. Ponse. Proof theory for μ-CRL: A language for processes with data. In Semantics of specification languages, Workshops in Computing. Springer, 1993. [11] C. A. R. Hoare. Communicating Sequential Processes. Prentice-Hall, 1985. [12] B. Jonsson and J. Parrow. Deciding bisimulation equivalence for a class of nonfinite state programs. Information and Computation, pages 272–302, 1993. [13] Kolyang, T. Santen, and B. Wolff. A structure preserving encoding of Z in Isabelle/HOL. In J. von Wright, J. Grundy, and J. Harrison, editors, Theorem Proving in Higher Order Logics, LNCS 1125, pages 283–298. Springer Verlag, 1996.
Data Abstraction for CSP-OZ
1045
[14] C. Loiseaux, S. Graf, J. Sifakis, A. Bouajjani, and S. Bensalem. Property preserving abstractions for the verification of concurrent systems. Formal methods in system design, 6:1–35, 1995. [15] I. Meisels and M. Saaltink. The Z/EVES Reference Manual. ORA Canada, 1997. http://www.ora.on.ca/z-eves/. [16] A. Mota and A. Sampaio. Model-checking CSP-Z. In Proceedings of the European Joint Conference on Theory and Practice of Software, volume 1382 of LNCS, pages 205–220, 1998. [17] J. Quemada, editor. Revised working draft on enhancements to LOTOS (V4). 1996. [18] A. W. Roscoe. The Theory and Practice of Concurrency. Prentice-Hall, 1997. [19] A. W. Roscoe, J. C. P. Woodcock, and L. Wulf. Non-interference through determinism. In D. Gollmann, editor, ESORICS 94, volume 875 of LNCS, pages 33–54. Springer-Verlag, 1994. [20] G. Smith. A semantic integration of Object-Z and CSP for the specification of concurrent systems. In J. Fitzgerald, C. B. Jones, and P. Lucas, editors, Proceedings of FME 1997, volume 1313 of LNCS, pages 62–81. Springer, 1997. [21] J. M. Spivey. The Z Notation: A Reference Manual. Prentice-Hall International Series in Computer Science, 2nd edition, 1992. [22] K. Taguchi and K. Araki. Specifying concurrent systems by Z + CCS. In International Symposium on Future Software Technology (ISFST), pages 101–108, 1997. [23] P. Wolper. Expressing interesting properties of programs in propositional temporal logic. In ACM POPL, pages 184–193, 1986. [24] J. Woodcock and J. Davies. Using Z. Prentice-Hall International, 1996.
A
Brief Introduction to CSP Operators
We briefly describe the main CSP operators in the syntax that FDR uses. – SKIP, STOP: empty processes with successful/unsuccessful termination, – a -> P: action prefix, first a and then P, – c?x -> P: complex prefix, first communication on c with input value v bound to x, then P[v /x ], – P;Q: sequential composition, – P\a: hiding, – P[[c