Academia.eduAcademia.edu

Object-Oriented Action Semantics Specifications

2003, Journal of Universal Computer Science

Journal of Universal Computer Science, vol. 9, no. 8 (2003), 910-934 submitted: 24/2/03, accepted: 30/5/03, appeared: 28/8/03  J.UCS Object-Oriented Action Semantics Specifications Claudio Carvilhe (Catholic University of Paraná, Brazil carvilhe@ppgia.pucpr.br) Martin A. Musicante (Federal University of Paraná, Brazil mam@inf.ufpr.br) Abstract: Action Semantics is a framework for the formal specification of programming languages. Two different, recently proposed approaches provide modularity to the framework, allowing for specification reusability and extension. In this work, we analyze the previous approaches, and introduce Object-Oriented Action Semantics, a new form of modular organization of Action Semantics descriptions. Object-oriented Action Semantics does not modify the syntax in which actions are written; the addition of object-oriented features (like classes and objects) is done as an upper layer to the semantic entities and functions. A simple Pascal-like, imperative programming language is described using the formalism. The extension and reuse capabilities of Object-Oriented Action Semantics are demonstrated by adding new features to the description. The semantics of the object-oriented action notation is also presented. Key Words: formal semantics, action semantics, object-oriented specification. Category: F.3.2, D.3.1, D.3.2 1 Introduction Action Semantics [Mosses, 1992, Watt, 1991, Mosses, 1999] is a formal framework for the definition of programming languages. One of the goals of the Action Semantics project is to provide a notation that is both formal and suitable to be used in the description of real programming languages. Action Semantics descriptions have shown to have good reusability and extensibility properties [Mosses and Musicante, 1994]; however, the standard Action Semantics notation lacks of syntactic support for the definition of libraries, whose components would be reused in new descriptions [Labra Gayo, 2002]. Two solutions for this problem have been addressed by different authors. In [Doh and Mosses, 2003], the standard Action Notation is extended to define modules. In [Menezes and Moura, 2001] the notation is adapted to define components. These solutions have important pros and cons. In this work, we propose the use of Object-Oriented concepts for the definition of a new extension of Action Notation. Our proposal tries to solve some problematic aspects of the previous Action Semantics extensions. A main advantage of our approach is the use of the standard Action Notation for the Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications 911 specifications “in-the-small”, combined with class constructors, to provide an object-oriented way of composing specifications. This work is organized as follows: The next section briefly presents Action Semantics. Sections 3 and 4 summarize the introduction of modules and components in the formalism. Section 5 introduces Object-Oriented Action Semantics by means of an example. The operational semantics of our notation is also given in this section. Section 6 presents a case study: a simple imperative language is specified. This description is extended, in order to demonstrate the capabilities of our proposal. Section 7 is devoted to the conclusions of this work. 2 Action Semantics Action Semantics [Mosses, 1992], [Watt, 1991], [Mosses, 1999] is a formal framework for describing programming languages semantics. In Action Semantics, the meaning of each phrase of a language is specified using ad-hoc entities called actions. Actions can be performed, processing data. Actions are defined using a special Action Notation, which defines basic actions and action combinators. Action semantics uses English words to enhance readability. As in operational or denotation semantics, specifications in Action Semantics are traditionally structured using semantic functions and semantic equations. In Action Semantics, the meaning of each phrase of a language is represented in terms of special entities called actions. Actions can be performed to process information, with various possible outcomes: normal termination (performance of the action completes), exceptional termination (it escapes), unsuccessful termination (it fails) or non-termination (it diverges). Action notation provides some primitive actions, and various combinators for forming complex actions, corresponding to the main fundamental concepts of programming languages. A data notation is used to describe the information processed by actions. The standard data notation (included in action notation) provides a collection of algebraically defined abstract data types, including numbers, characters, strings, sets, tuples, maps, etc.; further data may be specified ad hoc. There is also a third class of entities in action notation, called yielders. A yielder represents data whose value depends on the current information available to the primitive action in which it occurs. Yielders are evaluated to yield data. An example of a standard yielder is the data bound to I , which depends on the current bindings that are received by the enclosing primitive action. Action notation possesses five so-called ‘facets’: Basic: This facet deals with pure control flow, without reference to information processing issues. This facet includes combinators for sequencing, interleaving and non-deterministic, angelic choice between actions. For example, the compound action 912 Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications A1 and then A2 performs the action A1 first; The action A2 is performed after A1 completes. Functional: This facet deals with transient data, which is given to or by an action. For example, when the primitive action give the successor of the given natural is given a natural number n as transient data, it completes, giving n + 1 as a transient. The compound action A1 then A2 performs the action A1 first; all transient data given by A1 is passed on to A2 , which is performed after A1 completes. The primitive action choose D, where D is a sort of data, makes a nondeterministic choice of an individual of sort D, giving the chosen datum as a transient. Declarative: This facet deals with the manipulation of scoped information, represented by associations of tokens to bindable data. For example, performance of the primitive action bind ‘‘max-length’’ to 256 completes, producing a binding of the token ‘‘max-length’’ to the natural number 256. Imperative: This facet is concerned with storage handling. A storage in action notation is simply a mapping from (the currently allocated) cells to storable data. For example, consider the action allocate a cell then store 26 in the given cell This action combines features of the functional and imperative facets. Notice that indentation was used to indicate precedence of operators and combinators. Communicative: This facet provides a system of agents, which can each be ‘contracted’ to perform particular actions. Initially only a special ‘user’ agent is active. Agents can communicate using asynchronous message passing: the Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications 913 sending of a message is non-blocking. Each agent has its own communication buffer , in which all the messages sent to the agent are placed. Communication is reliable, in the sense that no message can be lost during transmission; however, there is no bound to the amount of time taken for a message to reach its destination agent. Moreover, each agent is created with its own storage, which cannot be affected (nor inspected) by other agents. Arbitrary data can be contained in messages, including the identities of agents. Most of the primitive actions have a use in connection with only one facet each, but the action combinators generally involve a mixture of the basic, functional, and declarative facets, determining the flow of control, transient data, and bindings between the subactions. Encapsulation of actions as data is also provided within action notation. This feature gives a simple way to support the description of procedure and function abstractions in programming languages. An abstraction is an item of data which encapsulates an action. Abstractions can be enacted; this operation results in the performance of the encapsulated action. Both transients and bindings can be supplied to abstractions before their enaction, for use by the encapsulated action. Abstractions can be treated just like any other data, i.e., given as transients, bound to tokens, stored in cells, and sent in messages. They are also used to determine the ‘contracts’ offered to agents in the communicative facet. Apart from the communicative facet (which deals with communicating actions), all of the facets and combinators described above are used for specifying “in the small”. They define the internal organization of a processing block. As reported in [Doh and Mosses, 2003], Action Semantics specifications are inherently modular. However, in standard Action Semantics there are no constructors available to explicitly define and compose reusable blocks. Such capability would constitute an important feature in the context of the creation of new languages specifications, based on existing ones. Two methods were recently proposed to improve modularity. Both methods are summarized in the following sections. 3 Adding modular structure to Action Semantics In [Doh and Mosses, 2003], the use of modules to structure Action Semantics descriptions is proposed. In this approach, the specification of a programming language is constructed by the combination (or extension) of modules. Each module is specified by two main sections: Syntax and Semantics. The first section defines the syntax of the phrases to be defined by the module. The semantics part defines the meaning of these phrases, using (action) semantic functions. The following example (adapted from [Doh and Mosses, 2003]) illustrates the definition and extension of a module to define arithmetic expressions. 914 Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications Base Expressions { syntax: Expr. semantics: datum >= expressible. (*) evaluate: Expr -> action [giving an expressible] } The module above states that Expr is a syntactic sort, and that evaluate is a semantic function, taking an expression and being defined by an action. This module captures the basic behavior of expressions. The module can be extended to define any kind of expressions. For example, the definition of arithmetic expressions can be done by defining a new module (which imports the above one), as follows: Arithmetic Expressions { import Base Expressions. syntax: Expr ::= Num | [[ Expr "+" Expr ]]. Num ::= [[ digit+ ]]. E1, E2 : Expr; N: Num. semantics: expressible >= natural. (1) evaluate N = give decimal string-of-characters N. (2) evaluate [[ E1 "+" E2 ]] = ( evaluate E1 and evaluate E2) then give the sum(the given natural #1, the given natural#2). } The module Arithmetic Expressions defines the syntax and semantics of sum expressions (of natural numbers). The semantics of these expressions is given in the usual Action Semantics style. Other specific expressions modules can be constructed, in order to define the syntax and semantics of different kinds of expressions, like Boolean Expressions, Relational Expressions, etc. All these modules can be imported into an Expressions module, to describe all the expressions of a given programming language. Further composition of modules could lead us to the definition of a complete programming language. For instance, an imperative programming language can be described as a combination of library modules, as follows: Imp Imperative Language { import Expressions, Commands, Declarations syntax: Program ::= [[Decl ";" Cmd]]. D:Decl; C:Cmd. Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications 915 semantics: bindable >= cell. storable >= expressible. run [[D ; C]] = elaborate [[ D ]] hence execute [[ C ]]. } The organization of actions proposed by the modular Action Semantics facilitates the construction of module libraries, from which predefined modules can be used in new programming language projects. A main advantage of the modular Action Semantics is that the actions used in the semantic functions can be exactly the same as in traditional Action Semantics; furthermore, the notation can be straightforwardly changed in accordance to the advent of new versions of Action Semantics, as long as its algebraic base does not change [Doh and Mosses, 2003]. This contributes to the easy transformation of previous specifications, at the same time in which only a small amount of retraining would be needed for users who already work with the framework. It must be noticed that the module import operation has the effect of merging the involved modules, yielding to a flat organization of the items being defined. As noticed in [Doh and Mosses, 2003], this form of module combination can be problematic, since it can lead to inconsistencies, in some cases, when the same name is used to describe different language constructors. Let us now resume the characteristics of the modular approach: – The notation for defining modules is simple, improving the readability of the resulting specifications; – Reusability is enhanced. Specification parts can be used in new specifications; – Modules can be combined, including already existing ones in a current project; – Modules combination is problematic, and can cause inconsistencies. 4 Component-based Action Semantics Component-based Action Semantics [Menezes and Moura, 2001], allows the creation of generic components and component libraries, using some ideas present in Montages [Kutter and Pierantonio, 1997]. The specification of a programming language is constructed by the combination of building blocks, called components. As in the modular approach, components can contain both syntactic and semantic definitions. Let us exemplify the use of components in the definition of a programming language. Our description is adapted from [Menezes and Moura, 2001]. Initially, an auxiliary generic component called binary is defined, to be used to define binary operators: 916 Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications binary _ _ _ :: component, string, yielder -> component binary c s y = syntax [[ c s c ]] semantics | | semantics of the c defined by the subtree #1 | and semantics of the c defined by the subtree #3 then give y The (component) operation semantics of takes a component and returns an action. In this case, to evaluate the sub-expressions of a sum. The (higher order) component binary expects three parameters: a component (to define which kind of expressions are to be evaluated), a string, representing an operator (name) and a yielder, to represent the operation on values. The above component is meant to be the skeleton of other components. It can be used to define a new component for arithmetic expressions: Expression = ... ++ binary Expression "+" (the sum of them) ++ binary Expression "-" (difference of them) ++ ... The operator “++” is provided by the new notation to be the composition of components. The application of this operator permits to define the Expression component above as the combination of the components defining each constant and operation of the language. Notice that in the final component, the semantics of each syntactic part is defined locally, having no need to merge and unify the sorts and operations that are being defined. In order to define programming languages, the notation needs to include primitives to deal with the definition and extension of predefined modules. This is done in Component-based Action Semantics by the introduction of new syntactic constructors, to deal with languages. Two primitives for language construction are the combinators extends and and. The former is used to build and extend languages, while the latter is used to combine languages to obtain new ones. The signature of these operations can be given as follows: extends [ _ ] with _ :: identifier, component -> language description. _ and _ :: language description, language description -> language description. Let us exemplify the use of these combinators to construct the specification of an imperative programming language. Suppose that there already exist language descriptions for the declarations, expressions and commands of this language. In this case, the description of programs can be given by: Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications Imperative Language = | Declarations and Commands and | extends [ Program ] with | syntax [[ Declaration ";" | semantics | | | semantics of the | | hence semantics of the 917 and Expressions Command ]] subcomponent #1 subcomponent #2 Let us now resume the characteristics of the component-based approach: – Component notation and Programming Language Notation provide an advanced way to create components and to define language specifications; – Components are generic and can be used in new projects, avoiding repetition; – A component library can be defined; – Functions and operators provided by the framework are cumbersome. Specifications can be obscure. 5 Object-Oriented Action Semantics In the previous sections we present two approaches to the introduction of modularity in Action Semantics. The first approach (Modular Action Semantics) has the advantage of using previous versions of Action Notation, without introducing new constructors for actions (new syntax is added just to define modules). However, the modular approach can be problematic in certain cases, since the locality of definitions is not enforced by the formalism. On the other hand, the component-based approach does not have this problem, but at the cost of significantly changing the syntax of actions, as well as its usage. In both approaches, specification parts can be reused in new projects. A module or component can be written in an abstract way and extended to meet actual needs. The readability is increased in relation to traditional Action Semantics, since small specification parts can compose a large project. In this context, we introduce (yet) another approach for the organization of specifications in Action Semantics. Our proposal, consists in the use of ObjectOriented concepts for structuring specifications. An Object-Oriented Action Semantics specification consists on the definition of a hierarchy of objects and classes, in which the methods and attributes are defined by means of a standard Action Semantics semantic functions and data. The class hierarchy for a given language is derived from its syntactic structure. Each language phrase (declarations, commands, expressions, etc) is represented by one or more objects. 918 Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications Command Null Assignment DoWhile Sequencing Figure 1: Toy command language class hierarchy. Let us exemplify these concepts using a toy language of commands, whose syntax is defined as follows: Cmd ::= “skip” | Id := Expr | “do” Cmd “while” Expr | Cmd ; Cmd The non-terminal symbol Cmd defines the commands present in the language: the null command, assignments, iterations and sequences. There exist some features that are common to all commands. However, each one of them presents a particular structure and meaning. Such context can be represented using the class hierarchy, defined in Figure 1. In that figure, each box represents a class. The class Command should contain all the features common to all commands. Specific features can be expressed by the Command sub-classes: Null, Assignment, DoWhile and Sequencing. As in the previous sections, we shall organize classes in Object-Oriented Action Semantics as having two basic parts: syntax and semantics. The top level class of commands can be represented as follows. Class Command syntax: Cmd semantics: execute[[ _ ]] : Cmd -> Action End Class The class Command, detailed above, is defined to be the basic class for commands. In the syntax section (syntax), the syntactic sort Cmd is introduced. This sort will be extended by the subclasses of command to contain all the command syntactic trees. Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications 919 A semantic function ‘execute [[ _ ]]’ is defined in the semantics section (semantics) indicating a mapping from syntactic sort Cmd to an Action. It is worth noticing that the sort Action corresponds to the same sort as in traditional Action Semantics. In our framework, semantic functions and semantic equations are respectively similar to methods and method definitions [Rumbaugh, 1994], [Meyer, 1997]. The semantic function ‘execute’ is seen as a method of the class Command, and can be overloaded by its sub-classes. (This concept is usually called polymorphism by the Object-Oriented community.) Let us now construct the sub-class of command dealing with the do-while loop: Class Do-WhileCommand extending Command using E:Expression, C:Command syntax: Cmd ::= "do" C "while" E semantics: execute[[ "do" C "while" E ]]= unfolding ( (execute C and then evaluate E) then (unfold else complete)) End Class The extending directive indicates that the Do-WhileCommand class is a subclass of Command. Two objects (E:Expression and C:Command) are instantiated by the using directive. These objects will match the sub-phrases of commands. The syntax section of the class adds a new command structure, redefining the syntax tree (Cmd). The ‘execute’ method is then overloaded and the do-while command Action Semantics is given. The classes Command and Expression must provide the methods ‘execute’ and ‘evaluate’, respectively. These methods will be called within the definition of the method execute= for the Do-WhileCommand class. The next subsection extends standard Action Notation to express objectoriented concepts. The big-step operational semantics of the notation is given in section 5.2. 5.1 Syntax Specifications in Object-Oriented Action Semantics are structured as a finite set of classes. The relationship between classes is specified using directives, indicating which objects will be instantiated by the actual class, as well as its position in the class hierarchy. The syntactic structure for classes is defined next. This 920 Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications syntax definition simply extends the standard Action Notation to include the class apparatus. (1) Class-Module ::= “Class” Class-Name Class-Body “End-Class” (2) Class-Body ::=  “extending” Base-Class-Name ?  “using” Objects-Declaration ?  Class-Definition ? (3) Base-Class-Name ::= Class-Name | Class-Name “::” Base-Class-Name (4) Objects-Declaration ::= Object-Declaration Object-Declaration “,” Objects-Declaration (5) Object-Declaration ::= Identifier “:” Class-Name (6) Class-Definition ::= “syntax” “:” Syntactic-Part “semantics” “:” Semantic-Part (7) Syntactic-Part ::= TokenName (8) Semantic-Part ::=  Semantic-Functions ?  Semantic-Equations ? (9) Semantic-Functions ::= Semantic-Function Semantic-Function Semantic-Functions (10) Semantic-Function ::= Function-Name “[[” “ ”* “]]” Tokens “->” ‘‘Action” data (11) Tokens ::= TokenName (12) Semantic-Equations ::= Semantic-Equation Semantic-Equation Semantic-Equations (13) Semantic-Equation ::= Function-Name “[[” syntax-tree “]]” ‘‘=” Action (14) “fail” “unfold” Action ::= “complete” Action “and” Action Action “and then” Action “unfolding” Action “give” Yielder “check” Yielder Action “then” Action “bind” Yielder “to” Yielder “furthermore” Action Action “hence” Action Action “moreover” Action Action “before” Action “store” Yielder “in” Yielder “deallocate” Yielder “allocate a” Sort “enact” Yielder Action “else” Action “recursively” “bind” Yielder “to” Yielder TokenName “::=” syntax-tree TokenName “,” Tokens Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications (15) Yielder ::= “the” Sort “#”n “the” Sort “bound” “to” k “the” Sort “stored” “in” Yielder Yielder “with” Yielder “closure” Yielder “abstraction of” Action (16) Sort ::= “bindable” “cell” “cell” “[” Sort “]” “storable” “abstraction” “datum” “integer” “value” “truth-value” Sort “|” Sort 921 Rules (1) to (13) define the structure of classes in our approach, as exemplified in section 5. Rules (14) to (16) incorporate Action Semantics to classes. The following subsection defines the operational semantics of this notation. 5.2 Semantics Base-classes defined using our notation are implicitly part of a hierarchy. We shall define a class to which all classes belong. This super-class is called State. All classes defined in Object Oriented Action Semantics are sub-classes of State. The class State has generic attributes, corresponding to transient information, bindings and storage; and provide operations, allowing us to handle such attributes. These operations are all the basic actions and action combinators. Both attributes and operations of State are visible to its sub classes. Notice that although this is a new way of looking at actions, nothing is changed in the practical use of them to define semantic functions. We define the State methods behavior by means of a big-step operational semantics [Winskel, 1993], characterized by the following relation: B, t, b, s ⊢ o ✄ o′ , t′ , b′ , s′ The relation schema above identifies B as a methods environment (containing references to all user-defined methods), t as the transient information, b as bindings and s as the current store. We say that the operation (action) o, when performed, produces the outcome o′ , together with transient information t′ , bindings b′ and storage s′ . The definition of this relation is adapted from [Moura, 1993]. Let us now give some examples of the definition of the big step operational semantics for actions in our context. B, t, b, s ⊢ complete ✄ completed, {}, {}, s (1) B, t, b, s ⊢ fail ✄ failed, {}, {}, s (2) 922 Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications B, t, b, s ⊢ a1 ✄ completed, t1 , b1 , s1 B, t, b, s1 ⊢ a2 ✄ completed, t2 , b2 , s2 mergeable t1 t2 mergeable b1 b2 B, t, b, s ⊢ a1 and then a2 ✄ completed, t1 ⊕ t2 , b1 ⊕ b2 , s2 (3) B, t, b, s ⊢ a1 ✄ o1 , t1 , b1 , s1 o1 = completed B, t, b, s ⊢ a1 and then a2 ✄ o1 , t1 , b1 , s1 (4) B, t, b, s ⊢ a1 ✄ completed, t1 , b1 , s1 B, t, b, s1 ⊢ a2 ✄ o2 , t2 , b2 , s2 o2 = completed B, t, b, s ⊢ a1 and then a2 ✄ o2 , t2 , b2 , s2 (5) Rules (1) and (2) define the semantics of the operations complete and fail, respectively. Both of them terminate. The former represents successful termination, while the latter finishes without success. Rules (3), (4) and (5) define the behavior of the and then operation. Rule (3), establishes the behavior of the and then operation when both sub-operations (sub-actions) a1 and a2 complete. Operator (⊕) defines merging of transient and bindings as defined in [Moura, 1993]. All the information received by the compound action is passed to each sub-action. If both sub-actions terminate with success, then the transients and bindings that resulted from the execution of these sub-actions are merged to compound the transients and bindings returned by the compound action. Rule (4) defines the behavior of the and then operation when the first sub-operation a1 does not complete, and rule (5) establishes the behavior when sub-operation a2 does not complete. In both cases, the result of the compound action is obtained from the unsuccessful sub-action, propagating its outcome. The semantics of the other actions and yielders are given using the same specification style. The complete set of equations can be found in [Carvilhe, 2002]. 5.2.1 Methods environment All user-defined methods are stored in the methods environment. Two operations are needed to handle methods: insertion and fetch. The definition of these operations is given next. Methods are syntactically structured as f [[H]] = O, where H is a syntax-tree schema and O is an operation (action). A syntax tree schema is defined as a syntax tree with (free) variables standing for sub-trees. The behavior of methods definitions is then defined by the following rules: B ⊢ f [[H]] = O ✄ B[f [[H]] → O] (6) Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications 923 (f [[H]] → O) ∈ dom(B), B, t, b, s ⊢ O[H/h] ✄ o, t′ , b′ , s′ B, t, b, s ⊢ f [[h]] ✄ o, t′ , b′ , s′ (7) Rule (6) indicates that methods whose syntax is ‘f [[H]] = O’ are added to the methods environment. The notation B[f [[H]] → O] indicates that a new method is inserted. The resulting method environment is similar to the original one (B), with the addition of a new method (f ), which will be applied to syntactic trees that match the tree schema H. Rule (7) states that methods defined as f [[h]] produce the result o, t′ , b′ , s′ , provided that the method f exists in the methods environment B, and that it can be executed, after substituting the syntax-tree schema H by the matching syntax-tree h on the action O. 6 A case study - The µ-Pascal Language In this section we present the use of Object-Oriented Action Semantics to define a toy language similar to Pascal. µ-Pascal is a simple imperative programming language which contains commands and expressions. The language possesses a block-structure. The Object-Oriented Action Semantics of µ-Pascal is defined in this work to exemplify the extensibility properties of our framework. In section 6.2, the µ-Pascal Object-Oriented Action Semantics will be extended to a language with procedures and functions. µ-Pascal syntax is defined as follows. (1) Program ::= Declaration “;” Command (2) Declaration ::= “var” Identifier “:” Type  “=” Expression ? “const” Identifier “:” Type “=” Expression (3) Type ::= “boolean” “integer” A Program is formed by a declaration followed by commands. Constants and Variables can be declared indicating their type. (4) Command ::= “let” Declaration “in” Command Identifier “:=” Expression “if” Expression “then” Command  “else” Command ? “repeat” Command “until” Expression Command “;” Command (5) “false” Numeral Identifier Expression ::= “true” Expression (“+” “-” “*” “<” “=”) Expression (6) Identifier ::= Letter  Letter | Digit * 924 (7) Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications Numeral ::= Digit  Digit * Commands in µ-Pascal contain assignments, selections, iterations and sequences. Expressions can be arithmetical or logical. 6.1 µ-Pascal Semantics The syntax of the language is our departing point to construct the class hierarchy of the specification. The syntactic rules of the language definition can be mapped into objects which incorporate syntax and semantics. Some diagrams will be constructed, using a tree notation to express the class hierarchy. Let us begin by constructing classes to represent the language identifiers, numerals and types. After this phase, we define the declarations, commands and expressions hierarchy to express the meaning of the language. Class Identifier syntax: Id ::= letter [ letter | digit ]* End Class Class Numeral syntax: N ::= digit+ semantics: valuation [[ _ ]] : N -> integer End Class Class Type syntax: T ::= "boolean" | "integer"" semantics: allocate-for-type [[ _ ]] : T -> Action allocate-for-type[[ "boolean" ]] = allocate a cell [ truth-value ] allocate-for-type[[ "integer" ]] = allocate a cell [ integer ] End Class The class Identifier represents names (variables and constants). This class has only syntactic definition. The class Numeral represents integer numbers. In the semantics section a valuation [[ _ ]] method is defined to map numerals to integers. The definition of the valuation function is straightforward. As it is usual in semantic descriptions, the double bracket notation is used to remark that the function parameter is a syntactic entity. Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications 925 Declaration ConstantDec VariableDec Figure 2: µ-Pascal declarations hierarchy. The class Type represents the language data types. The method allocatefor-type is defined, establishing truth-value or integer data types allocation. Constants and variables can be declared in µ-Pascal. The declarations hierarchy can be constructed in accordance to Figure 2, as follows. Class Declaration using I:Identifier, E:Expression syntax: Dec semantics: elaborate [[ _ ]]: Dec -> Action End Class The class Declaration instantiates two objects: I and E, respectively of classes Identifier and Expression. Both objects are not used by the class itself. They are defined at this point to be available to the sub-classes of Declaration. Notice that the class hierarchy allows us to instantiate those objects only in the base-class Declaration, inhibiting repetition. A non-terminal symbol Dec is introduced at the syntax section to be redefined by the sub-classes. A method called elaborate [[ _ ]] is declared in the semantics section, to be overloaded by the sub-classes. Let us now give a sub-class of Declaration, to define the meaning of constant definitions: Class ConstantDec extending Declaration using T:Type syntax: Dec ::= "const" I ":" T "=" E semantics: elaborate[["const" I ":" T "=" E]]= evaluate E then bind I to the value End Class The Dec token is redefined in the ConstantDec class (above), establishing the syntax if constant definitions. In the semantics part, the elaborate [[ _ ]] 926 Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications Command DecCommand Assignment Selection Repeat Sequencing Figure 3: µ-Pascal commands hierarchy. method is overloaded, to deal with the new syntax. The objects I:Identifier and E:Expression are used at this point, and the semantics of a constant declaration is defined using standard Action Notation. The following class deals with variable declarations in µ-Pascal: Class VariableDec extending Declaration using T:Type syntax: Dec ::= "var" I ":" T ["=" E] semantics: elaborate[["var" I ":" T]]= allocate-for-type T then bind token I to the cell #0 elaborate[["var" I ":" T "=" E]]= (evaluate E and allocate-for-type T) then (bind I to the cell #1 and store the value #0 in the cell #1) End Class The Dec token is redefined in the VariableDec class (above), establishing the structure for variable declarations. This class instantiates a T:Type object. The variable declaration syntax is redefined at the syntax section. The elaborate [[ _ ]] method is redefined twice, considering the absence (or not) of an expression E. The T:Type object is not defined in the base-class Declaration, but it is used both in ConstantDec and VariableDec. The semantics of a variable declaration is defined using standard Action Notation. The commands class hierarchy is depicted in Figure 3. The main class of this hierarchy is Command, defined as follows. Class Command syntax: Com semantics: execute [[ _ ]] : Com -> Action End Class Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications 927 In the syntax section, the token Com is introduced to represent the syntactic sub-trees of commands. The method execute [[ _ ]] is declared in the semantics section to be redefined by the sub-classes of Command. These sub-classes are defined next. Class DecCommand extending Command using D:Declaration, C:Command syntax: Com ::= "let" D "in" C semantics: execute[["let" D "in" C]]= (furthermore elaborate D) hence execute C End Class The class DecCommand defines the syntax and semantics of command blocks. Two objects are instantiated by DecCommand class: D:Declaration and C:Command. In the syntax section the sort Com is redefined to express command blocks. In the semantics section the (standard) Action Semantics description of blocks is given. Class Assignment extending Command using I:Identifier, E:Expression syntax: Com ::= I ":=" E semantics: execute[[I ":=" E]]= evaluate E then store the value in the cell bound to I End Class The class Assignment, above, instantiates two objects I:Identifier and E: Expression. In the syntax section the structure of assignments is defined. The semantics of an assignment is given by the evaluation of the expression, followed by the storage of the resulting value. The remaining classes of the command hierarchy (Selection, Repeat and Sequencing) are structured in the same way as DecCommand and Assignment; they are omitted here. Let us now define the expressions of the language, whose class hierarchy is defined in figure 4. The super-class Expression, defined below, presents a similar structure to that of Command. In the syntax section a token Exp is introduced to repre- 928 Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications Expression SumExp Equality SubtExp LessThan ProductExp FalseExp NumeralExp TrueExp IdentifierExp Figure 4: µ-Pascal expressions hierarchy. sent the syntactic sub-trees of expression. In the semantics section the method evaluate [[ _ ]] is introduced. Class Expression syntax: Exp semantics: evaluate [[ _ ]] : Exp -> Action End Class All the subclasses of Expression can be defined in a similar way as the subclasses of Command. The definition of the addition operation can be given as: Class SumExp extending Expression using E1:Expression, E2:Expression syntax: Exp ::= E1 "+" E2 semantics: evaluate[[ E1 "+" E2 ]] = (evaluate E1 and evaluate E2) then give sum(the integer#1, the integer#2) End Class The class SumExp, instantiates two objects from classes Expression (E1 and E2). The syntactic sort Exp is redefined in the syntax section. The semantics of a sum expression is specified by evaluating both sub-expressions and adding their results. All the operators of the language can be defined in a similar manner. Let us now define the meaning of identifiers within expressions: Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications 929 Class IdentifierExp extending Expression using I:Identifier syntax: Exp :: = I semantics: evaluate [[ I ]] = (give the value bound to I) or (give the value stored in the cell bound to I) End Class The class IdentifierExp instantiates an object I:Identifier. The syntax of expressions is extended to represent identifiers. In the semantics section, the meaning of a identifier is defined. Notice that an identifier can be a constant or variable; both cases are covered by the previous specification by using the action combinator ’ or ’. The other classes of expressions can be defined using the same principles. Once the language’s declarations, commands and expressions are represented using hierarchies, it is possibly to specify a class representing the whole µ-Pascal language: Class muPascalLanguage using D:Declaration, C:Command syntax: Prog ::= D ";" C semantics: run[[ _ ]] : Prog -> Action run[[ D ";" C ]] = elaborate D hence execute C End Class Two objects are instantiated in the muPascalLanguage class: D:Declaration and C:Command. The Prog token defines the µ-Pascal program general structure. In the semantics section, a run[[ _ ]] method is defined mapping a program to an action. 6.2 Extending the Specification - The m-Pascal Language Let us now use the class hierarchy defined in the previous sections, to create a new language, which we will call m-Pascal. The language incorporates procedure and function abstractions to µ-Pascal. Let us now extend the language to contain the new structures: 930 Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications Declaration ConstantDec VariableDec ProcedureDec FunctionDec Figure 5: m-Pascal declarations hierarchy. (1) Declaration ::= (2) Formal-Par ::= “var” Identifier “:” Type (3) Command ::= ... “call” Identifier “(”  Actual-Par  “)” (4) Expression ::= ... Identifier “(”  Actual-Par  “)” (5) Actual-Par ::= Expression ... “proc” Identifier “(” Formal-Par “)” “=” Command “func” Identifier “(” Formal-Par “)” “=” Expression The abstract syntax of declarations is extended by rule (1) to define procedure and function definitions. Commands and expressions are also changed in (3) and (4) respectively, to include procedure and function calls. The objects containing the definitions of procedures and functions are expressed by extending the Declaration class defined in the µ-Pascal specification. The declarations hierarchy will be changed to include two new sub-classes: ProcedureDec and FunctionDec (Figure 5): Class ProcedureDec extending Declaration using C:Command, FP:FormalPar syntax: Dec ::= "proc" I "(" FP ")" ":" C semantics: elaborate[["proc" I "(" FP ")" ":" C]] = recursively bind I to (closure abstraction of (furthermore elaborateFP FP hence execute C)) End Class The class ProcedureDec, gives the syntax and semantics of procedure declarations. The class representing function declarations is similar to the above one: Class FunctionDec extending Declaration Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications 931 Command DecCommand Assignment Selection Repeat Sequencing ProcedureCom Figure 6: m-Pascal commands hierarchy. Expression SumExp FunctionExp SubtExp ProductExp NumeralExp IdentifierExp Equality LessThan FalseExp TrueExp Figure 7: m-Pascal expressions hierarchy. using FP:FormalPar syntax: Dec ::= "func" I "(" FP ")" ":" E semantics: elaborate[["func" I "(" FP ")" ":" E]] = recursively bind I to (closure abstraction of ( furthermore elaborateFP FP hence (evaluate E then give the value) ) ) End Class Notice that an auxiliary class FormalPar, which represents formal parameters, is instantiated by ProcedureDec and FunctionDec; its definition is straightforward, and it is omitted here. Procedure calls and function applications require additions to the Command and Expression hierarchies. These changes are represented in Figure 6 and Figure 7, respectively. The classes corresponding to the new language constructions are given below: 932 Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications Class ProcedureCommand extending Command using I:Identifier, AP:ActualPars syntax: Com ::= "call" I "(" AP ")" semantics: execute[["call" I "(" AP ")"]] = evaluateAP AP then enact (the procedure bound to I with the value) End Class Class FunctionExpression extending Expression using I:Identifier, AP:ActualPars syntax: Exp ::= I "(" AP ")" semantics: execute[["call" I "(" AP ")"]] = evaluateAP AP then enact(the function bound to I with the value) End Class The class definitions above use an auxiliary class ActualPar, which represents actual parameters and the operations over them. The definition of this class is omitted here for space reasons. Object-Oriented features were applied to extend the µ-Pascal language. ProcedureDec and FunctionDec objects were created extending Declaration, to represent procedures and functions. Procedure calls were incorporated to Command, by the creation of the ProcedureCommand object and function applications were incorporated to expressions. This allows us to define the main class of the language specification as: Class mPascalLanguage using D:Declaration, C:Command syntax: Prog ::= "declare" D "used-in" C semantics: run _ : Prog -> Action run[[ "declare" D "used-in" C ]] = elaborate D hence execute C End Class Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications 933 Notice that since the language was redefined at the declarations, commands and expressions levels, the body of the most general class for the language remains unchanged. 7 Conclusions Object-Oriented Action Semantics is a new framework to organize Action Semantics descriptions. In this new framework, semantic functions are seen as methods, describing the meaning of constructions, defined locally within a class. The hierarchical structure of the specifications makes it possible to choose which methods are to be applied to each syntactic object. Our proposal does not change the syntax of actions, maintaining the traditional style of writing Action Semantics specifications. Reusability and extension are the main motivations of our proposal. Reusability is achieved in Object-Oriented Action Semantics by using class instantiation. Extension is improved by the definition of class hierarchies. We have shown, in a simple case study, a way to construct objects, as well as their instantiation and specialization. In the case study, we have built a class hierarchy for a simple Pascal-like language. The specification of this language was then changed to add new syntactic constructions. The (big step) operational semantics of the new notation is given. The only addition to the existent operational semantics of Action Notation is the use of a methods environment, to contain the definition of methods. The characteristics of our proposal can be summarized as: • Object-Oriented Action Notation is simple. The class structure is based on the modules notation introduced by [Doh and Mosses, 2003], and was inspired by the notions of classes and hierarchy from object-oriented programming; • Reusability is improved. Instantiation and extension permit the construction of libraries of programming languages concepts, that can be instantiated in programming languages projects. References [Carvilhe, 2002] Carvilhe, C. (2002). Object-oriented action semantics. Master’s thesis, Federal University of Paraná. Available at http://www.ppgia.pucpr.br/~carvilhe/full. (In portuguese). [Doh and Mosses, 2003] Doh, K.-G. and Mosses, P. D. (2003). Composing programming languages by combining action-semantics modules. Science of Computer Programming, 47(1):3–36. Elsevier Science Publishers. 934 Carvilhe C., Musicante M.A.: Object-Oriented Action Semantics Specifications [Kutter and Pierantonio, 1997] Kutter, P. and Pierantonio, A. (1997). Montages specifications of realistic programming languages. Journal of Universal Computer Science, 3(5):416–442. [Labra Gayo, 2002] Labra Gayo, J. (2002). Reusable semantic specifications of programming languages. In SBLP 2002 - VI Brazilian Symposium on Programming Languages, Rio de Janeiro, Brazil. Pontifı́cia Universidade Católica do Rio de Janeiro - PUC-Rio. [Menezes and Moura, 2001] Menezes, L. C. and Moura, H. (2001). Component-based action semantics: A new approach for programming language specifications. In SBLP 2001 - V Brazilian Symposium on Programming Languages, pages 152–163, Curitiba, Brazil. Universidade Federal do Paraná. [Meyer, 1997] Meyer, B. (1997). Object-oriented software construction. In ObjectOriented Software Construction 2nd ed. Prentice-Hall. [Mosses, 1992] Mosses, P. D. (1992). Action semantics. In Action Semantics. Cambridge University Press. [Mosses, 1999] Mosses, P. D. (1999). A modular SOS for Action Notation. Technical Report BRICS RS-99-56, University of Aarhus, Dep. of Computer Science. [Mosses and Musicante, 1994] Mosses, P. D. and Musicante, M. A. (1994). An Action Semantics for ML concurrency primitives. Number 873 in Lecture Notes in Computer Science, Barcelona, Spain. FME, Springer-Verlag. [Moura, 1993] Moura, H. (1993). In Action Notation Transformations - Ph.D. Thesis. University of Glasgow. [Rumbaugh, 1994] Rumbaugh, J. (1994). In Object-Oriented Modeling and design. Campus. [Watt, 1991] Watt, D. A. (1991). Programming Language Syntax and Semantics. Prentice Hall International Series in Computer Science. Prentice Hall. [Winskel, 1993] Winskel, G. (1993). The Formal Semantics of Programming Languages: An Introduction. Foundations of Computing Series. MIT Press.