Scholarly article on topic 'Action Semantics and ASF+SDF —System Demonstration—'

Action Semantics and ASF+SDF —System Demonstration— Academic research paper on "Computer and information sciences"

Share paper

Abstract of research paper on Computer and information sciences, author of scientific article — Peter D. Mosses

Abstract Modularity and tool support are crucial features for practical use of formal descriptions of programming languages. The combination of unrestricted context-free grammars with action semantics allows complete language descriptions with exceptionally good modularity. Moreover, by specifying the descriptions in ASF+SDF, the ASF+SDF Meta-Environment can be used to provide appropriate tool support.

Academic research paper on topic "Action Semantics and ASF+SDF —System Demonstration—"

Electronic Notes in Theoretical Computer Science 65 No. 3 (2002) URL: 7 pages

Action Semantics and ASF+SDF — System Demonstration —

Peter D. Mosses12

BRICS & Department of Computer Science University of Aarhus, Denmark


Modularity and tool support are crucial features for practical use of formal descriptions of programming languages. The combination of unrestricted context-free grammars with action semantics allows complete language descriptions with exceptionally good modularity. Moreover, by specifying the descriptions in ASF+SDF, the ASF+SDF Meta-Environment can be used to provide appropriate tool support.

1 Introduction

As pointed out by Heering and Klint [3], it is highly desirable to be able to give complete formal descriptions of programming languages, and to use these for generating various tools, such as parsers, static analyzers, interpreters, and compilers. For practical applications, it is important that language descriptions have good modularity. Regarding syntax, regular expressions and grammars formulated in (extended) BNF are generally regarded as appropriate for describing context-free syntax, and are well-supported by parser-generators. Most of them, however, restrict grammars to be LALR or LL, and this seriously undermines modularity; a notable exception is SGLR parser generation [6], which allows the use of arbitrary context-free grammars.

In connection with semantic descriptions, there is less agreement about which formalism to use. Many would advocate attribute grammars for static semantics, and in fact the Eli system supports generation of static analyzers from attribute grammars with good modularity. Other formalisms for static semantics generally have some drawbacks concerning modularity. For dynamic semantics, the main frameworks supporting modular specification are monadic semantics, modular SOS, ASM, and—the topic of this paper—action semantics.

1 Email:

2 BRICS: Basic Research in Computer Science, the Danish National Research Foundation

©2002 Published by Elsevier Science B. V.

The ASF+SDF Meta-Environment [1] provides tool support for implementing various kinds of languages, including specification languages. Using an early version of the Meta-Environment, van Deursen and the author implemented the ASD Tools [8], providing tool support for writing and checking the well-formedness of action semantic descriptions, as well as for parsing programs and generating actions from them. Subsequent enhancements to ASF+SDF have made it more attractive to formulate action semantic descriptions directly in ASF+SDF, and the ASD Tools have now become redundant.

After briefly recalling the main concepts of action semantics, this paper sketches how we write action semantic descriptions in ASF+SDF, explaining their modular structure and pointing out some advantages of our approach. The reader is assumed to be familiar with the ASF+SDF formalism [7].

2 Action Semantics

The action semantics framework [5] is a hybrid of denotational and operational semantics: inductively-defined semantic functions map programming language constructs to semantic entities called actions, whereas the semantics of the action notation used to express actions is itself defined operationally. Action notation includes some standard datatypes (numbers, characters, lists, etc.), and further datatypes can be added.

The crucial feature of action notation is that the same notation is used for combining actions (e.g. sequentially) regardless of how complex those actions might be. This ensures good modularity: a semantic equation defining the semantics of a particular construct is specified independently of which other constructs are included in the described language. The original version of action notation was developed during the late 1980's and early 1990's; it has recently been revised, and substantially simplified.

3 Modules

The modular structure of action semantic descriptions was originally as in de-notational semantics: a description was divided into three main modules, specifying (abstract) syntax, semantic entities, and semantic functions. The abstract syntax and semantic functions were usually sub-divided into separate (mutually-dependent) modules according to the sorts of constructs of the described language: expressions, statements, declarations, etc. The semantic entities were also subdivided into modules according to sorts of data: values, variables, arrays, records, etc.

However, although this modular structure was rather natural, and helpful for navigation within a single action semantic description, there was little opportunity to reuse an entire semantic functions module, since it is unusual for two different languages to have exactly the same constructs of any sort—except when one of them is simply an extension of the other.

With the aim of allowing direct reuse, a new modular structure for action semantics was proposed by Doh and the author at LDTA'01 [2]. The main idea, taken from the Montages framework [4], is to let the description of each individual programming construct be a separate module. Such a module specifies both the syntax and semantics of a construct—together with any assumptions that have to be made about the semantic entities involved. The same semantic entities may be required in connection with more than one construct, so they are still specified in separate modules, and imported where needed. A description of a particular programming language is now essentially just a composition of particular modules, and modules for common constructs such as arithmetic expressions and conditional statements can be reused without change in many different language descriptions.

One remaining obstacle to direct reuse of semantic descriptions of individual constructs was that the notation conventionally used for abstract syntax in action semantics was strongly suggestive of the corresponding concrete syntax. A module describing, say, conditional statements in Pascal would use the notation [["if" E "then" S1 "else" S2]] for abstract syntax; it could in principle be reused in a description of C, but it would look quite strange. One could use renaming to convert the abstract syntax notation from Pascal-style to C-style, but that might be tedious on a large scale. To facilitate reuse it seems best to go over to a neutral notation for abstract syntax, reflecting familiar semantic concepts and terminology rather than the lexical symbols of some particular concrete syntax.

The specification of the concrete syntax of a construct and its mapping to abstract syntax is separated from the module that gives the semantics of the construct, so that the latter can be reused directly in descriptions of all languages that have corresponding constructs, regardless of their concrete syntax.

4 Illustrations

The system demonstration at the workshop shows how complete language descriptions with exceptionally good modularity can be formulated in ASF+SDF, using action semantics to achieve reusability of semantic descriptions of individual language constructs. It also shows how the Meta-Environment can be used to check the well-formedness of action semantic descriptions, as well as to parse programs in the described language and map them to actions.3

Most of the modules shown in the demonstration are used in a complete description of JOOS (a sub-language of Java). Many of them could be reused without change in descriptions of other programming languages. The rest of this section explains the roles of the various kinds of modules, giving some excerpts to illustrate the use of ASF+SDF. The complete modules themselves are available at

The modules are considered roughly in order of decreasing reusability, start-

3 An action interpreter and an action compiler are to be incorporated in future versions of the system, allowing programs to be run according to their semantics.

ing with the fixed modules that define the action notation normally used in action semantic descriptions, and finishing with the ad hoc modules that specify particular combinations of concrete syntax and action semantics for individual constructs, which are used directly in complete descriptions of entire programming languages.

4.1 Kernel Action Notation

The kernel of action notation consists of a fixed set of primitive actions and action combinators, together with a few standard datatypes such as integers and strings. Its specification in ASF+SDF is divided into modules concerned with the notation associated with the following features of actions: flow of control and data, scopes of bindings, effects on storage, and interaction between concurrent agents performing separate actions. The basic compositional structure of actions is specified by SDF rules such as:

Action ActionInfix Action -> Action {left}

so particular action combinators can be specified as follows:

"and" -> ActionInfix

One primitive action may involve arbitrary data:

"provide" Data -> Action

The sort Data is essentially a parameter of action notation, instantiated by embedding other sorts in it as subsorts (rather than by renaming).

The kernel action notation modules are reused without change in all language descriptions that make (direct or indirect) use of the action primitives and combi-nators specified in them.

4.2 Further Action Notation

The modules extending kernel action notation to the full standard action notation are organized in the same way as the kernel action notation modules themselves. Each standard action combinator is declared by an SDF rule, e.g.:

"moreover" -> ActionInfix

and defined as an abbreviation by an ASF equation that can be used in the expansion of standard action notation to kernel action notation:4

[0] A1 moreover A2 = (A1 and A2) then give overriding_

Above, A1 and A2 are variables of sort Action, the symbols 'and' and 'then' are kernel action combinators, and 'give overriding' is a kernel action that applies the kernel data operation 'overriding' to the data given to it.

The modules that specify the extension to standard action notation are reused just as widely as the kernel modules. Users may also declare their own nonstandard abbreviations for action compositions, in the same way as illustrated above,

4 The defining equations are actually specified in a separate module, so that they can easily be inhibited if desired.

and those that become widely used may subsequently be incorporated in a future version of the standard action notation.

4.3 Kernel Data

Various sorts of data are needed in connection with particular features of actions, e.g., the sort Cell of data representing storage cells is required in connection with effects on storage (allocation, updating, etc.). Other kernel data sorts include commonly-required entities such as integers and strings. Notation for operations on data is specified in the same style as action combinators:

Data DataOpInfix Data -> Data {left} "+" | "-" | "*" -> DataOpInfix

4.4 Further Data

New sorts of data are specified by declaring their constructors and selectors. For instance, the constructors and selectors for a subsort Object of Data are declared thus:

object | class | bindings | identity -> DataOpPrefix corresponding to an un-sorted version of the following SDF2 declaration:


-> Object {cons}

Abbreviations for compositions of data operations may be declared and defined in the same way as action abbreviations.

4.5 Abstract Syntax

An abstract syntax module either declares a single new sort (and some variables ranging over it):

sort Stm

variables "S"[0-9]* -> Stm or a single new abstract syntax construct:

conditional(Cond,Stm,Stm) -> Stm {cons}

Constructor symbols such as 'conditional' are deliberately chosen to avoid any reference to lexical symbols, like 'if', that might be used for expressing conditionals in a particular language (breaking with the previous style used in action semantics). The adoption of neutral symbols in abstract syntax should allow its direct reuse for quite different-looking languages, e.g. Pascal and C.

4.6 Abstract Semantics

The module for the action semantics of an abstract syntax sort or construct imports the corresponding abstract syntax module, as well as the modules providing whatever semantic entities are required. In the case of a syntactic sort, it also declares

the semantic function for that sort, determining the sort of semantic entity used to represent it—usually an action:5

execute Stm -> Action

For an abstract syntactic construct, the abstract semantics specifies one particular semantics for it, e.g.:

[0] execute sequence(S1,S2) = execute S1 and then execute S2

With statement sequencing as above, there is no alternative semantics; but for expression evaluation, for instance, alternative modules for the same construct would specify sequential and interleaved evaluation of sub-expressions.

4.7 Concrete Language Constructs

To obtain an action semantics for concrete language constructs, we declare an operation 'abs' mapping concrete syntax to abstract syntax:

sort Statement

variables "S"[0-9]* -> Statement context-free syntax abs Statement -> Stm

and define it (inductively) by giving an equation for each concrete construct— possibly with a separate module for each construct, to facilitate reuse:

context-free syntax

"if" "("Expression")" Statement "else" Statement -> Statement equations

[1] abs if (E) S1 else S2 =

conditional(cond(abs E), abs S1, abs S2)

Note that the mapping abs does not have to preserve the order of the branches, so one could map both a let-declaration and a where-declaration to the same abstract local-declaration construct.

4.8 Concrete Languages

Finally, a complete language module imports all the modules that provide the desired concrete constructs—possibly adding priority declarations, and fixing the relationship between various standard sorts of data:

module JOOS

imports JOOS/Statements JOOS/Statements/IfElse ...

5 Potential Improvements

One awkward aspect of the way that new data operations are declared (as object -> DataOpPrefix, for instance) is the lack of information about the domain and

5 The range of a semantic function would be a sort of data for a sort of construct that has a direct mathematical interpretation.

range sorts of the operations, and about which are constructors or selectors. This information is needed to allow the use of data operations in actions to be type-checked; currently, it has to be provided in a special additional notation, and passed explicitly along the module import hierarchy. It would be attractive to use a metalevel operation to allow data operations to be declared as usual in SDF modules, and extract the required information.

Regarding the ease of writing and reading our many small modules, ASF+ SDF requires various keywords such as exports and context-free syntax when collecting declarations into a module. It would be desirable to develop a variant of ASF+SDF that avoids such "boiler-plate", and let the Meta-Environment convert it directly to its internal representation.

Even without such enhancements, however, it seems that ASF+SDF already supports the specification of action semantics rather well.


Implementing action semantics in the Meta-Environment is in collaboration with J0rgen Iversen. Special thanks to Mark van den Brand, Jurgen Vinju, and their colleagues at CWI for much helpful advice and cooperation.


[1] The ASF+SDF meta-environment. Home page: projects/MetaEnv/meta/.

[2] K.-G. Doh and P. D. Mosses. Composing programming languages by combining action-semantics modules. In M. van den Brand and D. Parigot, editors, Electronic Notes in Theoretical Computer Science, volume 44. Elsevier Science Publishers, 2001.

[3] J. Heering and P. Klint. Semantics of programming languages: A tool-oriented approach. ACMSIGPLANNotices, Mar. 2000.

[4] P. Kutter and A. Pierantonio. Montages: Specifications of realistic programming languages. JUCS, 3(5):416-442, 1997.

[5] P. D. Mosses. Action semantics. Home page: Projects/AS/.

[6] M. G. J. van den Brand, J. Scheerder, J. J. Vinju, and E. Visser. Disambiguation filters for scannerless generalized LR parsers. In R. N. Horspool, editor, Compiler Construction (CC'02), volume 2304 of LNCS, pages 143-158. Springer-Verlag, 2002.

[7] A. van Deursen, J. Heering, and P. Klint, editors. Language Prototyping, volume 5 of AMAST Series in Computing. World Scientific, 1996.

[8] A. van Deursen and P. D. Mosses. ASD: The action semantic description tools. In AMAST'96, Proc. 5th Intl. Conf. on Algebraic Methodology and Software Technology, Munich, volume 1101 of LNCS, pages 579-582. Springer-Verlag, 1996.