[Next] [Top]

1. UTS Procedure Specification Language

1.1 Concrete Type Expression Syntax
1.2 Underspecified Type Expression Syntax
The procedure specification language portion of UTS is used to specify the interface--essentailly, the number and type of arguments--for each procedure that can be called remotely in the aplication. There is both an import specification and an export specification; the import specification is associated with each component that invokes the remote procedure and the epxort specification is associated with the component containing the code for the procedure. Type-checking between the import and export specifications is done by the runtime system to ensure that the specifications are compatible. The specification file is also used as the basis for automatic generation of stub procedures for each imported and exported procedure to handle conversion of argument values between language- and machine-specific formats and the UTS data rpepresentations. There is one stub compiler for each supported programming language. Currently, there are stub compilers for C (schc) and Fortran (schf), with one for C++ under development.

The stub handles the conversions for most values automatically. However, for those parameters that do not map directly into a single host language data type or that do not map to any host language data type, the encoding and decoding of the UTS value is placed under programmer control. Specifically, a representative for the UTS value is supplied as the argument value. Then, routines in the UTS library can be invoked with the representative as an argument to allow the programmer to inquire as to the UTS type of the corresponding value and to perform explicit conversion of values to and from the UTS language format and the format of the host language. Thus, the representative of a value can be viewed as a ticket that is presented to an agent to gain access to the value. The value itself is maintained by the agent, which also assigns the representative.

The UTS syntax provides for the expression of the most common base types as well as record and array composite types. Support for procedure arguments and arbitrary nesting of composite types is provided. Provision is also made for underspecified types. Import and export specifications have the following format:

	import prog_name prog (args) [returns (type)]
	export prog_name prog (args) [returns (type)]

1.1 Concrete Type Expression Syntax

In what follows, bold-faced words are required, epsilon indicates the entry can be left out, and name is treated as a comment in the specification (though the stub compilers will use it as a variable name). Any line that begins with a pound sign (#) will be treated as a comment by the stub compilers.
    args        ::= epsilon | arg args
    arg         ::= direction represent type
    direction   ::= val | res | var | epsilon
    represent   ::= rep | epsilon
    types       ::= epsilon | type types
    type        ::= name single | name composite
    name        ::= "text-string" | epsilon
    single      ::= basetype | signature | error | null
    composite   ::= record | array | prog
    basetype    ::= simple | varying
    simple      ::= integer | float | double | bool
    varying     ::= string[number] | byte [number]
    record      ::= record{types}
    array       ::= array(name sizes) of type
    sizes       ::= number | number, sizes
    prog        ::= prog(args) | prog(args) returns(name type)

1.2 Underspecified Type Expression Syntax

In order to handle communication with languages with run-time typing, to enable the creation of programs to handle files or streams of arbitrary data, and to allow the creation and specification of programs such as command interpreters that invoke other programs of varying type, the UTS language includes type operations that provide the ability to create type expressions that specify more than one concrete type. These type expressions are called ``underspecified''. The syntax for these operators is shown below in supplemental productions that are added to the grammar given above for concrete types:
    types  ::= type or type | (type) | ? | *
    args   ::= *
    sizes  ::= * | size, sizes
    size   ::= number - number | number - | - number
or is the type union operator; for example, the type constructed by ``integer or float'' contains all values of type integer and all values of type float. The type ``?'' is the universal set; it contains all single UTS values, including values of the composite types. The ``*'' operation, which is valid only as the last field of a record or prog constructor, signifies a series of any number of UTS values of any type. For example, the type denoted by the expression ``record{integer, string[5], *}'' includes any record that has an integer value in its first field and a string of length 5 in its second field, no matter the contents of the rest of the record. The type ``record{integer, string[5], ?}'' contains only the subset of those records that are exactly 3 elements long. The use of ranges is simple; for example, ``string[3-6]'' contains strings with length between 3 and 6 (inclusive). A missing bound in a range operation means that the bound is unspecified, so that the type ``string[3-]'' contains any string with length greater than or equal to 3. Note that a missing lower bound is equivalent to a lower bound of 0. The type ``string[-]'' contains a string of any length.

Where possible, the stub compilers handle underspecified types. For example, the C stub compiler (schc) will automatically handle underspecified strings, dynamically allocating memory as needed, and performing length checks at the upper and lower ends of the specified range of lengths. If the target language does not support dynamic memory, underspecified types have to be handled using a representative.

Examples

import sum prog("arg1" var array[10] of float)
           returns ("ans" float)
export artest prog(res array ["sub1" 500, "sub2" 10] of float)
export cvd prog(var record{float, float}) returns (integer)
export sort prog(var array[100] of
                 record{string[30], array [5] of integer, float})
import recur prog(val integer,
                  val prog(val integer, val integer)
                  returns (integer))
             returns (integer)

[Next] [Top]