The S-Expression Design Language (SEDL) James C. Corbett. September 1, Introduction. 2 Origins of SEDL 2. 3 The Language SEDL 2.

Similar documents
Annex A (Informative) Collected syntax The nonterminal symbols pointer-type, program, signed-number, simple-type, special-symbol, and structured-type

The PCAT Programming Language Reference Manual

1 Lexical Considerations

Process Management And Synchronization

Lexical Considerations

Lexical Considerations

The Compositional C++ Language. Denition. Abstract. This document gives a concise denition of the syntax and semantics

The SPL Programming Language Reference Manual

Solve the Data Flow Problem

Decaf Language Reference Manual

CS 4240: Compilers and Interpreters Project Phase 1: Scanner and Parser Due Date: October 4 th 2015 (11:59 pm) (via T-square)

Programming Languages Third Edition. Chapter 9 Control I Expressions and Statements

CA4003 Compiler Construction Assignment Language Definition

Review of the C Programming Language

Defining Program Syntax. Chapter Two Modern Programming Languages, 2nd ed. 1

SEMANTIC ANALYSIS TYPES AND DECLARATIONS

An Interactive Desk Calculator. Project P2 of. Common Lisp: An Interactive Approach. Stuart C. Shapiro. Department of Computer Science

Programming Languages Third Edition

1 Process Coordination

Functional Programming. Pure Functional Programming

CMa simple C Abstract Machine

Weiss Chapter 1 terminology (parenthesized numbers are page numbers)

CS1622. Semantic Analysis. The Compiler So Far. Lecture 15 Semantic Analysis. How to build symbol tables How to use them to find

Scheme Quick Reference

Scheme Quick Reference

Topic IV. Parameters. Chapter 5 of Programming languages: Concepts & constructs by R. Sethi (2ND EDITION). Addison-Wesley, 1996.

Objectives. Chapter 2: Basic Elements of C++ Introduction. Objectives (cont d.) A C++ Program (cont d.) A C++ Program

Chapter 2: Basic Elements of C++

SMURF Language Reference Manual Serial MUsic Represented as Functions

Chapter 2: Basic Elements of C++ Objectives. Objectives (cont d.) A C++ Program. Introduction

University of Utrecht. 1992; Fokker, 1995), the use of monads to structure functional programs (Wadler,

FRAC: Language Reference Manual

IC Language Specification

Review of the C Programming Language for Principles of Operating Systems

Lexical Analysis. Lexical analysis is the first phase of compilation: The file is converted from ASCII to tokens. It must be fast!

CS /534 Compiler Construction University of Massachusetts Lowell. NOTHING: A Language for Practice Implementation

A Small Interpreted Language

Control Structures. Lecture 4 COP 3014 Fall September 18, 2017

Algorithmic "imperative" language

11/6/17. Functional programming. FP Foundations, Scheme (2) LISP Data Types. LISP Data Types. LISP Data Types. Scheme. LISP: John McCarthy 1958 MIT

Principles of Programming Languages

Language Reference Manual simplicity

Concurrency. Lecture 14: Concurrency & exceptions. Why concurrent subprograms? Processes and threads. Design Issues for Concurrency.

Java Primer 1: Types, Classes and Operators

BoredGames Language Reference Manual A Language for Board Games. Brandon Kessler (bpk2107) and Kristen Wise (kew2132)

Chapter 3. Describing Syntax and Semantics

Example of use. Shared var mutex: semaphore = 1; Process i. begin.. P(mutex); execute CS; V(mutex);.. End;

Theoretical Part. Chapter one:- - What are the Phases of compiler? Answer:

Chapter 2: Functions and Control Structures

GNU ccscript Scripting Guide IV

Topic IV. Block-structured procedural languages Algol and Pascal. References:

Compiler Construction

RSL Reference Manual

Short Notes of CS201

ASML Language Reference Manual

Compiler Construction

Formal Specification and Verification

CS201 - Introduction to Programming Glossary By

Compiler Techniques MN1 The nano-c Language

UNIT 3

Performance Throughput Utilization of system resources

Operating Systems. Designed and Presented by Dr. Ayman Elshenawy Elsefy

A Correctness Proof for a Practical Byzantine-Fault-Tolerant Replication Algorithm

Generating Continuation Passing Style Code for the Co-op Language

CS 457/557: Functional Languages

Chapter 7. - FORTRAN I control statements were based directly on IBM 704 hardware

Typescript on LLVM Language Reference Manual

such internal data dependencies can be formally specied. A possible approach to specify

DAVE. Language Reference Manual. Hyun Seung Hong. October 26, 2015

M/s. Managing distributed workloads. Language Reference Manual. Miranda Li (mjl2206) Benjamin Hanser (bwh2124) Mengdi Lin (ml3567)

programming languages need to be precise a regular expression is one of the following: tokens are the building blocks of programs

ICC++ Language Denition. Andrew A. Chien and Uday S. Reddy 1. May 25, 1995

Functional Programming. Pure Functional Languages

Advanced Algorithms and Computational Models (module A)

Project 2: Scheme Interpreter

G Programming Languages - Fall 2012

Chapter 7 Control I Expressions and Statements

Functional Programming. Pure Functional Languages

Control Structures. Outline. In Text: Chapter 8. Control structures Selection. Iteration. Gotos Guarded statements. One-way Two-way Multi-way

Principles of Programming Languages 2017W, Functional Programming

Summer 2017 Discussion 10: July 25, Introduction. 2 Primitives and Define

VENTURE. Section 1. Lexical Elements. 1.1 Identifiers. 1.2 Keywords. 1.3 Literals

INTRODUCTION Introduction This document describes the MPC++ programming language Version. with comments on the design. MPC++ introduces a computationa

Interprocess Communication By: Kaushik Vaghani

G Programming Languages Spring 2010 Lecture 4. Robert Grimm, New York University

egrapher Language Reference Manual

Decaf Language Reference

Defining Languages GMU

Programming Language Concepts, cs2104 Lecture 04 ( )

Chapter 3: CONTEXT-FREE GRAMMARS AND PARSING Part2 3.3 Parse Trees and Abstract Syntax Trees

YOLOP Language Reference Manual

2 Addressing the Inheritance Anomaly One of the major issues in correctly connecting task communication mechanisms and the object-oriented paradigm is

Lecture Topics. Announcements. Today: Concurrency (Stallings, chapter , 5.7) Next: Exam #1. Self-Study Exercise #5. Project #3 (due 9/28)

Ruby: Introduction, Basics

Introduction to lambda calculus Part 3

Software Engineering using Formal Methods

The Decaf Language. 1 Lexical considerations

Chapter 3. More Flow of Control. Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley

CS3502 OPERATING SYSTEMS

Process Synchronization

Transcription:

The S-Expression Design Language (SEDL) James C. Corbett September 1, 1993 Contents 1 Introduction 1 2 Origins of SEDL 2 3 The Language SEDL 2 3.1 Scopes : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 3 3.2 Tokens : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 3 3.3 Declarations : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 3 3.4 Types : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 5 3.5 Macros : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 6 3.6 Control Flow : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 6 3.7 Expressions : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 7 3.8 Communication : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 8 3.9 Conformance Testing Support : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 10 4 Examples 12 1 Introduction This document species a simple design language based on Ada [5] and CSP [4] for use with the constrained expression toolset [2], which provides tools for automatically verifying certain concurrency and timing properties of concurrent systems. The purpose of the language is to permit the specication of concurrent systems in a compact programming language notation that can easily be translated into nite state automata (FSAs) for analysis by automated tools. SEDL is essentially a subset of Ada written in a Lisp-like syntax (to facilitate parsing by a tool written in Lisp). Despite the functional syntax, SEDL is procedural and contains a basic set of procedural constructs for writing specications that look very much like programs. For example, SEDL has variables (including arrays and records), procedures, assignment statements, conditionals (if, case), and loops. SEDL also has intertask communication primitives like those of Ada. This document is organized as follows. Section 2 describes the origins of SEDL. Section 3 describes the language itself. Section 4 gives several example SEDL specications, pointing out salient features of the language. 1

2 Origins of SEDL SEDL is descended from a previous design language used with the constrained expression toolset called CEDL (Constrained Expression Design Language) [3]. CEDL was a more restricted subset of Ada. It supported only enumerated types and did not allow procedures. CEDL was translated by a deriver tool [1] into a set of regular expressions, some of which were then converted to deterministic nite automata (DFAs). The resulting automata and regular expressions were then used in the analysis of the concurrent system. For reasons discussed below, we split this translation into two parts. First, a new deriver tool translates a concurrent system specied in Ada to the Lisp-like S-expression design language (SEDL); second, a front end to the analysis tools converts the SEDL specication into a set of DFAs for use in the analysis. The reasons for replacing the deriver with this new scheme were: The old deriver is written in Ada and uses prototype versions of language processing tools developed by the Arcadia consortium. As a result, it was slow and brittle (changes in these prototypes often broke the tool). Ada is a much more dicult language in which to develop prototypes than is Lisp, the language in which the other analysis tools are written. Thus adding or changing features of the translation was dicult. We implemented a signicant extension to the translation of program variables; this extension was far easier to implement in Lisp. The new version of the main analysis tool uses DFAs exclusively, thus the regular expressions generated by the old deriver are no longer needed and generating DFAs directly from the specication is much more ecient. The new deriver accepts full Ada as input, allowing the analysis tools to be applied to real programs much more easily (of course, only certain aspects of an Ada program can be modeled). The analyst may specify systems directly in SEDL, which contains special preprocessing constructs (e.g., macros) that make specication of large but regular systems compact. For example, dining philosopher systems have a xed size SEDL specication: the value of a constant declared at the top determines the actual number of philosophers in the system. Also, additional declarations and operations have been included to support special analysis techniques (e.g., for identical tasks, counter variables, conformance checking). 3 The Language SEDL This section describes the syntax and (to a lesser degree) semantics of SEDL. The semantics of our procedural constructs are understood to be like those of similar procedural languages (e.g., Ada). The semantics of the communication constructs will be described in greater detail. We divide the languages into the following parts: scopes, tokens, declarations, types, macros, control ow, expressions, communication, and conformance. Even though the entire text is really a specication (i.e., not executable), we use the term program to denote the entire text and reserve the term specication (abbreviated <spec>) to denote all or part of the sequential code comprising a task or procedure. Note also that the productions for <spec> are distributed over several sections; productions dening all other nonterminals appear completely in a single section. We use a BNF notation for syntax. Literals are written in single quotes. Nonterminals are written in angle brackets. The notation [ <a> ] generates zero or one <a>'s; the notation { <a> } generates zero or more repetitions of <a>. 2

3.1 Scopes SEDL is a \at" language with limited scoping. A single global scope contains the names of all constants, tasks, procedures, and types. Each task or procedure constitutes a scope for the variables, parameters, and entries it contains. Each entry constitutes a scope for its parameters (thus entries may share parameter names). The innermost declaration takes precedence when scopes overlap. As in Ada, an object is available for use forward from its declaration. In SEDL, all specications of task and procedure bodies are considered to come after all declarations, thus only the order of declarations is important. A declaration that uses a constant, type, or macro must come after the declaration of that object. 3.2 Tokens Non-literal tokens (e.g., numbers, names) are dened by the following regular productions over characters: <digit> <sign> ::= '0' '1' '2' '3' '4' '5' '6' '7' '8' '9' ::= '+' '-' <number> ::= [ <sign> ] <digit> { <digit> } <boolean> <letter> <char> <string> ::= 't' 'nil' ::= 'a'.. 'z' 'A'.. 'z' ::= <letter> <digit> '_' '-' ::= '"' { <char> } '"' <name> ::= <letter> { <char> } Names (of variables, types, tasks, etc.) are not case-sensitive. The remainder of any line containing a semicolon (outside double quotes) is considered a comment, as in Lisp. 3.3 Declarations <program> ::= { <top decl> } <top decl> <type decl> <const decl> <task decl> ::= <type decl> <const decl> <task decl> <generic decl> <task array decl> <proc decl> <macro decl> <spec task decl> <spec array decl> ::= '(' 'type' <name spec> <type> ')' ::= '(' 'constant' <name spec> <constant> ')' ::= '(' 'task' <name spec> '(' { <local decl> } ')' <spec> ')' 3

<generic decl> <task array decl> <proc decl> <macro decl> <spec task decl> <spec array decl> <local decl> <var decl> <entry decl> <param decl> <mode> <rep decl> ::= '(' 'generic' <name spec> '(' { <local decl> } ')' name <spec> ')' ::= '(' 'task-array' <name spec> <type> <name spec> ')' ::= '(' 'procedure' <name spec> '(' { <param decl> } ')' <type spec> '(' { <var decl> } ')' <spec> ')' ::= '(' 'macro' '(' { name } ')' <spec> ')' ::= '(' 'specification' <name spec> '(' { <local decl> } ')' <spec> ')' ::= '(' 'specification-array' <name spec> <type> <name spec> ')' ::= <var decl> <entry decl> <rep decl> ::= '(' 'variable' <name spec> <type spec> [ <expr> ] ')' ::= '(' 'entry' <name spec> { <param decl> } ')' '(' 'external-entry' <name spec> <name spec> { <param decl> } ')' ::= '(' <mode> <name spec> <type spec> ')' ::= 'by-value' 'by-reference' ::= '(' 'replicate' <expr> ')' A program is a sequence of top level declarations. A top level declaration declares a type, a constant, a task, a generic, a task array, a procedure, a macro, a specication task, or a an array of specication tasks. A type declaration binds a name to a type expression. A constant declaration binds a name to an ordinal value. A task declaration creates a task with the specied name, declarations, and specication. A generic declaration binds a name to a task declaration and generic parameter. The task declaration may contain references to the generic parameter. When the the generic is instantiated by appearance in an array of tasks, the value of the generic parameter will be the array index to which that instantiation is assigned. A task array declaration creates a constant array whose i th element is an instantiation of the generic named in the declaration with the i th element of the range of the array as the value of the generic parameter. For example, the following array of tasks: (task-array phils (range 0 2) philosopher) (generic philosopher i ((entry next)) (call (index phils (mod (+ i 1) 3)) next)) is equivalent to the following task declarations: (task phil_0 4

((entry next)) (call phil_1 next)) (task phil_1 ((entry next)) (call phil_2 next)) (task phil_2 ((entry next)) (call phil_0 next)) A procedure declaration creates a procedure with parameters, each of which has a parameter mode (pass by value or reference) and a type. The procedure itself has a return type, which may be null (i.e., ()). A macro declaration denes a substitution. A specication task (and arrays thereof) dene an abstract specication for a system for use with a special analysis technique that proves conformance of the system to a specication (see Section 3.9). The declarations of tasks, generics, procedures, and specication tasks include local declarations, which declare variables, entries, and replication factors (this last declaration is for use with a special analysis technique for identical tasks). Only tasks and generics may contain entry and replication factor declarations. A variable declaration includes the name of the variable, its type, and its initial value (which must be compile-time evaluable). An entry declaration contains the signature of the entry call and implicitly declares the parameters as local variables in the task to which the actual parameters from the caller will be assigned at the time of a rendezvous. These variables are implicitly scoped to the body of their accept statement in a manner described in Section 3.8. The mode of an entry parameter must be by-value. A replication factor declaration species that a special analysis technique should be used to create the indicated number of copies of the task. Procedures may not have entry or replication factor declarations. 3.4 Types <type spec> <type> <ordinal> <field decl> ::= <name spec> <type> ::= <ordinal> '(' 'counter' number ')' '(' 'record' { <field decl> } ')' '(' 'array' <type spec> <type spec> ')' ::= '(' 'boolean' ')' '(' 'range' number number ')' '(' 'enumerated' { string } ')' ::= '(' <name spec> <type spec> ')' The only atomic types supported are booleans, integer ranges, and enumerated types. A counter is an integer range from zero to a specied value (for use with a special analysis technique for variables that are only incremented and decremented). All atomic types except counters are considered ordinal types. Composite record and array types may be constructed, as in Ada. Field names need be unique only within a record. The rst type specied in an array declaration is the index type, which must be an ordinal; the second type is the element type. SEDL uses structural equivalence for types. 5

3.5 Macros <spec> <name spec> ::= '(' 'expand-if' <expr> '(' <spec> ')' [ '(' <spec> ')' ] ')' '(' 'expand-for' <name spec> <number> <number> <spec> ')' ::= name '(' 'expand-name' name { <expr> } ')' Before SEDL is compiled into FSAs, the specications and declarations are expanded by folding constant expressions, performing macro substitutions, and processing the following three expansion directives, which are replaced by the expressions they produce. The expression parameters to these directives must be compile-time evaluable atomic values. The expand-if directive evaluates to the rst specication if the expression is true, and evaluates to the second specication (or an empty specication if this is not present) otherwise. Note the extra set of parentheses around these specications. The expand-for directive evaluates to a sequence of specications obtained as follows: the parameter specication is expanded once for each integer value between the two numbers given (in ascending order) and the resulting specications are appended. Within each expansion of the parameter specication, the name parameter is a constant whose value is the corresponding integer. The pair of numbers denes an ascending range, thus (2,1) would dene an empty range and the expand-for would return an empty specication. The expand-name directive simply appends the print name of the value of the expression(s), separated by underscores, to the specied name. For example, the specication: (macro call-server (i) (call server (expand-name request i "status"))) (task one () (expand-for j 1 3 (expand-if (not (= j 2)) ((call-server j))))) expands to (task one () (call server request_1_status) (call server request_3_status)) These directives allow compact specications of regular systems. The rst example in Section 4 shows the use of these constructs to produce a xed sized specication for a dining philosophers system of n philosophers. Macro substitutions are performed recursively, allowing macros to use macros, but care must be taken to avoid circular denitions. A macro substitution will substitute the actual parameter for all instances of the formal in the macro body, thus parameters names must be selected carefully (e.g., 'call' would be a bad parameter name for the above macro). 3.6 Control Flow <spec> ::= '(' { <spec> } ')' '(' 'if' <expr> <spec> [ <spec> ] ')' '(' 'case' <expr> { <case> } [ <default> ] ')' '(' 'while' <expr> <spec> ')' 6

'(' 'loop' <spec> ')' '(' 'for' <name spec> <expr> <expr> <spec> ')' '(' 'exit' [ number ] ')' <proc call> '(' 'return' [ <expr> ] ')' '(' 'abort' ')' '(' 'null' ')' '(' 'internal' string ')' <proc call> ::= '(' name { <expr> } ')' <case> <default> ::= '(' <simple expr> <spec> ')' ::= '(' 'otherwise' <spec> ')' Most of the standard control ow constructs are supported in SEDL. A block specication is a list of specications. An if specication takes a boolean expression, then specication, and optional else specication. A case conditional is also provided. If the otherwise clause is omitted, the default action is abort. Three kinds of loops are provided. A loop specication will iterate until an exit or return statement is executed. A while specication will execute the body of the loop while the boolean expression is true. A for loop specication takes the name of an integer variable and two integer expressions specifying a (possibly empty) integer subrange. The index variable is initialized to the rst element of the subrange before the loop is entered and is incremented after each iteration. The body of the loop is executed as long as the value of the index variable is less then the top of the subrange. Unlike Ada, the index of a for loop is a normal variable and must be declared in the containing task or procedure. Also, modifying the index variable in the body of the loop may change the number of loop iterations, though modifying the variables in the subrange expressions cannot. The exit statement jumps out of the specied number of enclosing loops (one by default). Procedures are called by specifying the procedure name and arguments as a list. All types of variables except counters may be passed as parameters. Values are returned to the caller using the return statement. An abort statement terminates the task that executes it, even if the abort statement is contained in a procedure called by the task. Note that this diers from Ada's abort statement, which is used by one task to abort another. The null and internal statements do nothing, but the internal statement allows the specier to model an internal computation of a task that will not be hidden by the subsequent translation of the task into an automaton. For example, in a real-time analysis, the analyst may want to model a block of computation with a known duration using this construct. The string allows the computation to be named so that its properties (e.g., duration) can be distinguished from those of other internal computations in the analysis. 3.7 Expressions <spec> <expr> ::= '(' 'assign' <expr> <expr> ')' ::= <simple expr> '(' <op> <expr> { <expr> } ')' '(' 'index' <expr> <expr> ')' '(' 'field' <expr> <name spec> ')' <proc call> '(' 'choose' <type spec> ')' 7

<simple expr> <constant> <op> ::= <name spec> <constant> ::= number boolean string 'problem-size' ::= <int op> <bool op> '=' <int op> ::= '+' '-' '*' '/' 'mod' '>' '<' '>=' '<=' <bool op> ::= 'and' 'or' 'not' Expressions are in prex form. Array indexing is performed using the index function, which takes an array and an index and returns the corresponding element of the array. Field selection from a record is performed using the field function, which takes a record and a eld name and returns the eld. Integer, boolean, and enumerated type constants are given by numbers, t/nil, and strings, respectively. Objects of any type may be assigned and compared using =. Integer and boolean operators, dened above, must have arguments of the respective type. The special constant problem-size is set during translation to an integer value specifying the size of the problem. This allows analyses of dierent problem sizes to use the same source le. Calls to procedures that return a value may appear in expressions. The choose function nondeterministically selects an element of the indicated type and returns it. Variables of type counter may appear only in tasks and then only in the following two contexts: assignment statements that increment or decrement them by one, and boolean expressions representing tests that contain no other type of variable. 3.8 Communication <spec> <call> <task spec> <accept> ::= <call> <accept> '(' 'select' { <select clause> } ')' ::= '(' 'call' <task spec> <name spec> { <expr> } ')' ::= <name spec> '(' 'index' <name spec> <expr> ')' ::= '(' 'accept' <name spec> { <spec> } ')' <select clause> ::= <com spec> '(' 'when' <expr> <com spec> { <spec> } ')' '(' 'else' { <spec> } ')' <com spec> ::= <accept> <call> '(' 'terminate' ')' SEDL uses a synchronous communication mechanism like that of CSP and Ada. In some ways, the communication primitives of SEDL are closer to CSP, while in others ways they are closer to Ada. As in Ada, tasks have named entries. For two tasks to communicate, one task calls an entry of the other, specifying both the task and entry name, while the called task executes an accept statement for that entry. For example: 8

(task customer (task resource : ((entry request)) : : (call resource request) (accept request) The communication, termed a rendezvous, does not take place until the calling task reaches the call statement and the called task reaches the accept statement; tasks are blocked if they must wait for communication. Communication statements are not allowed in procedures. The caller of an entry must specify the name of the called task. This specication is either a simple name or an index expression selecting one task from an array of tasks. Data may be passed between the tasks during the synchronization, but only from the calling task to the called task (data transfer is one-way, as in CSP). Each entry has a signature, like that of a procedure, declaring the names of its parameters. A call on an entry with parameters must supply actual values for those parameters. Within the body of an accept statement, the parameters are like ordinary variables, having been set to the values passed by the caller of the entry. The parameters of an entry are scoped to that entry and may not appear outside the body of an accept statement for that entry. As in CSP, synchronizations are atomic. Thus, unlike in Ada, the body of an accept statement cannot be used to create nested rendezvous, which are not supported in SEDL. Conceptually, the synchronization and passing of values occur atomically at the top of the accept body, which serves only to delimit the scope of the parameter variables. For example, in the following system, a task passes a number to another task to be incremented. Since accept parameters are by value, the incrementing task must pass the result back using another rendezvous. This illustrates how Ada's nested rendezvous and out parameters may be simulated using an additional \callback" rendezvous in SEDL. (task customer ((variable x (range 0 10) 5) (entry callback (by-value result (range 0 10)))) (call server increment x) (accept callback (assign x result))) (task server ((entry increment (by-value number (range 0 10)))) ;; number =? (outside accept body) (accept increment ;; Might do other rendezvous here (customer waiting for callback) ;; number = 5 (call customer callback (+ number 1))) ;; does not deadlock ;; number =? (outside accept body) ) As in Ada, a select statement is provided to allow a choice among possible rendezvous. Each clause in the select statement may be guarded by a boolean expression, indicating that the alternative represented by the clause if only available if the expression evaluates to true. Ada allows additional statements to follow the communication statements in a select clause. These can be simulated in SEDL by placing additional statements inside the when cluase (if the communication is not guarded, a guard of t (true) may be used and is equivalent to no guard). Unlike both Ada and CSP, the parameter variables for a guarded accept may occur in the guard expression. This permits entry calls to be accepted or refused based on the actual parameters provided by the caller. For example, the following task will accept calls on its entry only if they provide an even parameter. 9

(task fussy ((entry even (by-value x (range 0 10)))) (select (when (= (mod x 2) 0) (accept even))))) Note that the scope of an accept body includes an associated guard expression. As in Ada, the else clause in a select statement will be executed if no communication clause is ready to execute. This clause can also be used for conditional entry calls or accepts: (select (call resource start) (else (assign not-ready t))) The terminate clause allows a task to terminate normally at the select statement. Ada uses a complex set of rules to determine when such termination would not result in the starvation of the task's callers. In SEDL, the analysis is used to guarantee that the termination of a task will not cause such starvation. As in CSP, a task may be willing to send or receive data at any given point. Thus, unlike in Ada, select clauses may mix calls and accepts and/or contain multiple calls. For example, the following task (with some additional procedures to support insertion and deletion) species an n-slot buer: (task buffer-task ((entry in (by-value p packet)) (variable buf buffer)) (select ;; Willing to accept data if buffer not full (when (< (field buf size) n) (accept in (insert p buf))) ;; Willing to output data if buffer not empty (when (> (field buf size) 0) (call environment out (head buf)) (remove-head buf))))) Entry call parameters must be deterministic expressions they cannot contain the choose operator. Thus, a task that passes an arbitrary boolean cannot be coded as: (task coin-flip () (call customer pass (choose (boolean)))) but must be coded as: (task coin-flip ((variable temp (boolean))) (assign temp (choose (boolean))) (call customer pass temp)) 3.9 Conformance Testing Support To support an analysis technique for testing the conformance of a concurrent system to a specication, special declarations are provided for specication tasks and arrays of specication tasks. A 10

specication task is a more abstract specication of the system's behavior in terms of externally observable events. For example, an n-slot buer might be implemented as a composition of communicating 1-slot buers. The specication task for this system would contain only in and out events for the buer, while the set of n implementation tasks would contain many additional events representing the data being passed between the 1-slot buers. The entries representing the in and out events for the buer are called external because either their caller or acceptor is external to the specication. If the caller of the entry is external, then the entry is declared using a composite name consisting of the name of the matching implementation entry prexed by its task and a dot. This identies the entry of the specication task with a unique entry in one of the implementation tasks and implicitly declares that the entry as external. If the acceptor of the entry is external, then the entry is declared using an external-entry declaration and both the task and entry name are specied. Consider the specication of a 2-slot buer composed of two 1-slot buers: (task one-slot-1 ((entry in)) (accept in) (call one-slot-2 pass))) (task one-slot-2 ((entry pass)) (accept pass) (call environment out))) (specification two-slot ((entry one-slot-1.in) (external-entry environment out) (variable size (range 0 2) 0)) (select (when (< size 2) (accept one-slot-1.in) (assign size (+ size 1))) (when (> size 0) (call environment out) (assign size (- size 1)))))) The in entry of one-slot-1 is an external entry whose caller is external. The out entry is an external entry whose acceptor (i.e., the dummy task environment) is external. The declarations of the specication task dene these entries (and their associated communication events) as external. Specication tasks may communicate amongst themselves just as the tasks in the concurrent system do. The entries of these rendezvous would be internal to the specication. The body of the specication task species a regular pattern of these external events. A special analysis technique can be used to prove that the set of sequences of external events allowed by the specication task contains or is contained in the set of sequences allowed by the implementation tasks. 11

4 Examples This section presents several example specications of common concurrency problems in SEDL to illustrate its salient features. The rst example is a version of the dining philosophers system. In this version, the deadlock is prevented by requiring that philosophers pick up both forks at the same time. This requires replacing the individual fork tasks with a single fork manager task to which philosophers submit requests to eat. The fork manager maintains the state of all the forks and will synchronize with a philosopher to grant that philosopher's forks only if both of those forks are currently free. The philosophers are an array of tasks, while the code for much of the fork manager is generated with macro expansion. The variables to record the current status of the forks are counters. (constant n 3) ;; n = number of philosophers (type phil-range (range 0 (- n 1))) (task-array phil phil-range phil-task) (generic phil-task i () (call manager (expand-name up i)) (call manager (expand-name down i)))) (task manager ((expand-for i 0 (- n 1) (variable (expand-name fork i) (counter 1) 0) (entry (expand-name up i)) (entry (expand-name down i)))) (select (expand-for i 0 (- n 1) (when (and (= (expand-name fork i) 0) (= (expand-name fork (mod (+ i 1) n)) 0)) (accept (expand-name up i) (assign (expand-name fork i) (+ (expand-name fork i) 1)) (assign (expand-name fork (mod (+ i 1) n)) (+ (expand-name fork (mod (+ i 1) n)) 1)))) (accept (expand-name down i) (assign (expand-name fork i) (- (expand-name fork i) 1)) (assign (expand-name fork (mod (+ i 1) n)) (- (expand-name fork (mod (+ i 1) n)) 1))))))) After expansion, the program looks as follows: (task phil_0 () (call manager up_0) (call manager down_0))) (task phil_1 () 12

(call manager up_1) (call manager down_1))) (task phil_2 () (call manager up_2) (call manager down_2))) (task manager ((variable fork_0 (counter 1) 0) (entry up_0) (entry down_0) (variable fork_1 (counter 1) 0) (entry up_1) (entry down_1) (variable fork_2 (counter 1) 0) (entry up_2) (entry down_2)) (select (when (and (= fork_0 0) (= fork_1 0)) (accept up_0 (assign fork_0 (+ fork_0 1)) (assign fork_1 (+ fork_1 1)))) (accept down_0 (assign fork_0 (- fork_0 1)) (assign fork_1 (- fork_1 1))) (when (and (= fork_1 0) (= fork_2 0)) (accept up_1 (assign fork_1 (+ fork_1 1)) (assign fork_2 (+ fork_2 1)))) (accept down_1 (assign fork_1 (- fork_1 1)) (assign fork_2 (- fork_2 1))) (when (and (= fork_2 0) (= fork_0 0)) (accept up_2 (assign fork_2 (+ fork_2 1)) (assign fork_0 (+ fork_0 1)))) (accept down_2 (assign fork_2 (- fork_2 1)) (assign fork_0 (- fork_0 1)))))) The second example is a version of the readers/writers problem in which writers have priority once a request to write has been received, no additional readers will be allowed access to the resource. The number of readers and writers is determined by the special constant problem-size, which appears in a replicate declaration of those tasks. (constant n problem-size) 13

(task controller ((variable readers (range 0 n) 0) (variable writers (range 0 n) 0) (entry req_write) (entry start_write) (entry end_write) (entry start_read) (entry end_read)) (select (when (= writers 0) (accept req_write (while (> readers 0) (accept end_read) (assign readers (- readers 1))) (accept start_write) (assign writers (+ writers 1)))) (accept end_write (assign writers (- writers 1))) (when (= 0 writers) (accept start_read (assign readers (+ readers 1)))) (accept end_read (assign readers (- readers 1)))))) (task writer ((replicate n)) (call controller req_write) (call controller start_write) (call controller end_write))) (task reader ((replicate n)) (call controller start_read) (call controller end_read))) The third example is a simple version of the alternating bit protocol that uses type declarations, records, and entry parameters. Note the use of the nondeterministic choice statement to choose the data bit to send. (type data-type (range 0 1)) (type tag-type (boolean)) (type packet (record (data data-type) (tag tag-type))) (task sender ((variable p packet) 14

(entry ack (by-value ack-tag tag-type))) (assign (field p tag) nil) (assign (field p data) (choose data-type)) (call receiver data p) (accept ack (if (= ack-tag (field p tag)) ((assign (field p data) (choose data-type)) (assign (field p tag) (not (field p tag)))))))) (task receiver ((entry data (by-value p packet)) (variable tag tag-type nil)) (accept data (call sender ack tag) (if (= (field p tag) tag) (assign tag (not tag)))))) The last example is a self-service gas station in which customers pay for gas, pump, and then receive change from an operator. The operator keeps track of the queue of customers waiting for each pump, which must be activated before a customer may pump the gas. When the customer nishes, the pump reports the amount of gas pumped to the operator, who then gives the customer change. This specication uses procedures, arrays, macros, and select guards that test the values of the actual parameters passed by the caller. (constant num-customers 5) (constant num-pumps 1) (type cust-range (range 1 num-customers)) (type cust-range-zero (range 0 num-customers)) (type pump-range (range 1 num-pumps)) (type pump-queue (array cust-range cust-range-zero)) (type station-queue (array pump-range pump-queue)) (task-array cust cust-range customer-task) (task-array pump pump-range pump-task) (generic pump-task i ((entry activate) (entry start) (entry stop)) (accept activate) 15

(accept start) (accept stop) (call operator charge i))) (generic customer-task i ((entry change) (variable pump-selected pump-range)) (assign pump-selected (choose pump-range)) (call operator prepay i pump-selected) (call (index pump pump-selected) start) (call (index pump pump-selected) stop) (accept change))) (task operator ((entry prepay (by-value customer cust-range) (by-value pump-selected pump-range)) (entry charge (by-value pump-id pump-range)) (variable queues station-queue) (variable first-in-line cust-range)) (select (when (not (customer-waiting customer queues)) (accept prepay (if (= 0 (index (index queues pump-selected) 1)) (call (index pump pump-selected) activate)) (enqueue customer (index queues pump-selected)))) (when (customer-waiting-at-pump queues pump-id) (accept charge (assign first-in-line (index (index queues pump-id) 1)) (dequeue (index queues pump-id)) (if (> (index (index queues pump-id) 1) 0) (call (index pump pump-id) activate)) (call (index cust first-in-line) change)))))) (macro customer-waiting-at-pump (queues i) (> (index (index queues i) 1) 0)) (procedure customer-waiting ((by-reference customer cust-range) (by-reference queues station-queue)) (boolean) ((variable pump pump-range) (variable slot cust-range)) (for pump 1 num-pumps (for slot 1 num-customers (case (index (index queues pump) slot) 16

(return nil)) (0 (exit)) (customer (return t)) (otherwise (null))))) (procedure enqueue ((by-reference customer cust-range) (by-reference queue pump-queue)) () ((variable slot cust-range)) (for slot 1 num-customers (if (= (index queue slot) 0) ((assign (index queue slot) customer) (exit))))) (procedure dequeue ((by-reference queue pump-queue)) () ((variable slot cust-range)) (for slot 1 (- num-customers 1) (assign (index queue slot) (index queue (+ slot 1)))) (assign (index queue num-customers) 0)) References [1] S. Avery. A tool for producing constrained expression representations of CEDL designs. Software Development Laboratory Memo 89-2, Department of Computer and Information Science, University of Massachusetts, 1989. [2] G. S. Avrunin, U. A. Buy, J. C. Corbett, L. K. Dillon, and J. C. Wileden. Automated analysis of concurrent systems with the constrained expression toolset. IEEE Trans. Softw. Eng., 17(11):1204{1222, Nov. 1991. [3] L. K. Dillon. A constrained expression formulation of CEDL. Technical Report TRCS86-22, Department of Computer Science, University of California, Santa Barbara, November 1986. [4] C. A. R. Hoare. Communicating sequential processes. Commun. ACM, 21(8):666{677, August 1978. [5] U. S. Department of Defense, Washington, D. C. Reference Manual for the Ada Programming Language, ANSI/MIL-STD-1815A edition, January 1983. 17