Tartan Language Design For The Ironman Requirement - Reference M
Tartan Language Design For The Ironman Requirement - Reference M
6-1978
Paul N. Hilfinger
William Allan. Wulf
This Technical Report is brought to you for free and open access by the School of Computer Science at Research Showcase @ CMU. It has been
accepted for inclusion in Computer Science Department by an authorized administrator of Research Showcase @ CMU. For more information, please
contact [email protected].
CMU-CS-78-133
TAHTAN
Language Design for the Ironman Requirement:
Reference Manual
Mary Shaw
Paul Hilfinger
Wm. A. Wulf
Computer Science Department
Carnegie-Mellon University
Pittsburgh, Pa. 15213
June, 1373
Abstract: Tartan is an experiment in language design. The goal was to determine whether
a "simple" language could meet substantially all of the Ironman requirement for a common
high-order programming language.
We undertook this experiment because we believed that all the designs done in the first
phase of the COO effort were too large and too compiex. We saw that complexity as a
serious failure of the designs; excess complexity in a programming language can interfere with
its use even to the extent that any beneficial properties are of little consequence. We wanted
to find out whether the requirements inherently lead to such complexity or whether a
substantially simpler language would suffice
T
Three ground rules drove the experiment First, no more than two months April 1 to
May 31 would be devoted to the project Second, the language would meet ail the
Ironman requirements except for a few points at which it would anticipate Steelman
requirements. Further, the language would contain no extra features unless they resulted in a
simpler language. Third, simplicity would be the overriding objective.
The resulting language, Tartan, is based on ail available information, including the designs
already produced. The language definition is presented here; a companion report provides an
overview of the language, a number of examples, and more expository explanations of some of
the language features.
W e believe that Tartan is a substantial improvement over the earlier designs, particularly in
its simplicity. There is, of course, no objective measure of simplicity, but the syntax, the size
of the definition, and the number of concepts r^quirnd are ail smaller in Tartan
Moreover, Tartan substantially meets ail of the Ironman requirement (The exceptions lie in a
few places where we anticipated Steelman requirements and where details are still missing
from this report) Thus, we believe that a simple language can meet the Ironman requirement
Tartan is an existence proof of that
We must emphasize again that this effort is an experiment, not an attempt to compete with
DCO contractors. Tartan is, however, an open challenge to the Phase II contractors; The
language can be at least this simple! Can you do better?
D
T
TTC a a l(monitored
^ ^ J i byH2L
* Scientific Research).
'*
S*=y * r contract
F44620-73-C-0074
Hi*?'
Air^*
Force Office of
F44S0
A d V 3 n e 8 d
e s 8 a r c h
P r o
c U
UNIVERSITY l l - B R A W
CARN6<f-M-llQN U N i V t r i
rMTlSSIIKGH. P E W V S U f A i m
\b2ii
Blocks
Sequenced Statements
Assignment Statement
Conditional Statements
Loop Statements
Unconditional Control Transfer
Exceptions
Parallel Process Control
5. T y p e s
5.1.
5.2.
5.3.
5.4.
5.5.
Scalar Types
Composite Structures
Dynamic Types
Process Control Types
Defined Types
Declarations
Modules
Routines
Exceptions
Type Definitions
Generic Definitions
Translation Issues
I. Standard Definitions
1.1. System-Dependent Characteristics
1.2. Properties of Types
1.2.1. Fixed
1.22 Float
1.2.3. Enumerations
1.2.4. Boolean
1.2.5. Characters
1.26. Latches
1.2.7. Arrays
1.2.8. Sets
1.2.9. Dynamic Types
1.2.10. Records
1.211. Variants
1.212. Strings
1.213. Activations
1.214. Actnames
1.215. Files
1.3. Alphabets
II. Collected Syntax
-1-
-2-
Identifiers that are exported from an inner scope or imported from an outer scope have the status of
identifiers defined in the scope. Redefinition of identifiers within a scope is not permitted; however,
this does not prohibit overloading of routine names. In addition, the same identifier may be imported
with different meanings from two different scopes. Such identifiers are qualified with the names of the
"modules in which they were defined; thus they are not duplicate definitions. Similarly, literals and
constructors are qualified with their types to prevent ambiguity. In either case, the module or type
qualifier may be omitted if no ambiguity arises.
In Tartan, extent is controlled exclusively by blocks. Only instantiated objects (variables, constants)
have extent. Variables are instantiated by the elaboration of declarations (for named variables) and by
explicit construction of variables having dynamic types (dynamically created variables). Named
variables have extent coincident with the surrounding block. Dynamically created variables have extent
coincident with the block containing the definitions of their dynamic types. Formal parameters of
routines are considered to have extent coincident with the routine body.
Tartan provides a facility for making generic definitions of routines and modules. This allows the
programmer to write a single textual definition that serves as an abbreviation for many closely-related
specific definitions. The definitions may accept parameters; the parameters are completely processed
during translation. The effect of using a generic definition is that of lexically substituting the definition
in the program at the point of use.
T h e syntactic definition of Tartan uses conventional BIMF with the following
additions
and
conventions:
-
Key words (reserved words) and symbols are denoted with boldface.
- Metasymbols are denoted by lower-case letters enclosed in angular brackets, e.g., "<stmt>".
- The symbols { and } (not in boldface) are meta-brackets and are used to group constructs in
the meta-notation.
- Three superscript characters, possibly in combination with a subscript character, are used to
denote the repetition of a construct (or a group of constructs enclosed in {}):
"*"
denotes "zero or more repetitions of"
"+"
denotes "one or more repetitions of"
"*"
denotes "precisely zero or one instance of".
Since it is often convenient to denote lists of things that are separated by some single
punctuation mark, we denote this by placing the punctuation mark directly below the
repetition character.
T h e semantics of the language are described in English. In the interest of a compact and regular
syntax, we have allowed syntactic constructs that are disallowed on semantic grounds.
This is
consistent with standard practice with respect to, for example, undeclared identifiers.
^Literals and identifiers for variables that are declared manifest are manifest objects; hence
they are inherited.
-3-
2 . Basic Structures
2.1. Primitive Expressions
<const>
<constructor>
Primitive expressions form the basis for the recursive defintion of expressions.
They are the
elements referred to as constants, literals, and constructors In programming languages and as
generators in algebras.
Constants and literals denote values. The type of a constant is determined by its declaration.
types of literals are determined as follows:
The
- A sequence of digits containing no decimal point is of type Int. Type Int is defined in terms
of type fixed for each machine as described in Appendix 1.1.
- A sequence of digits containing a decimal point is of type Real.
terms of type float for each machine as described in Appendix 1.1.
- If a sequence of digits, with or without a decimal point, is qualified by a fixed or float type
or by a defined type that is ultimately defined in terms of fixed or float, the type of the
literal is determined by the qualifier.
- True and false denote boolean values. Nil denotes the null value for any dynamic type. Open
and closed denote values for latches. Empty denotes the empty set Mint denotes an
activation of any process in mint state.
- A character string containing one character is a literal of type char. Any other character
string is a constructor of type string.
Literals and manifest expressions are evaluated during translation with the same algorithms and
accuracy as are used during execution.
If an <id> is to be a <const>, it must have been declared const or be a member of an enumerated
type. If an <expr> is to be a <const>, it must be a manifest expression.
T h e type of a constructor may be indicated by a prefixed qualifier. If the qualifier is omitted, the
constructor is assumed to give the value of an array indexed with integers beginning at 1.
Constructors are provided for composite and dynamic types.
- If the constructor has a record type, the <expr>s in parentheses give the field values in the
order of their declaration
- If the constructor has an array type, the parenthesized list gives the element values. If the
constructor is a simple expression list, it gives the values in order from lowest index to
highest.
If the constructor uses the form with options, the expressions in the <option>s
indicate the array position to which each value corresponds. The special constant others may
appear as the last <option>; it will match any constant that is not included in any other
<option>. The constructor form with options is legal only for arrays and for types ultimately
defined in terms of arrays; the expressions in the <option>s must be manifest
- If the constructor has a variant type, the first expression in the parenthesized list is the tag
and the remainder of the list is a constructor for the corresponding variant.
-4-
- If the constructor has dynamic type, the result is a pointer to a new variable having the
attributes supplied in the type qualifier and the value given by the parenthesized list.
A constructor containing no <expr> provides an uninitialized instance of the indicated type.
2.2. Identifiers
<var id>
<qual id> | <var id> ( <actuais> ) | <var id> . <id> | <var id> ( <range> ) | Rap' <id>
<range>
<option>
<qual id>
<id>
Identifiers have no inherent meanings. They are associated with objects, routines, modules, types,
statements, and exceptions. Declarations and definitions establish the meanings of identifiers within
particular scopes.
Identifiers may be simple, or they may be qualified with module or type names in order to resolve
ambiguity among names exported from several modules.
Identifiers that name objects are <var id>s. They may be simple identifiers, they may be qualified
to indicate where they were defined^ or they may name elements or substructures of composite
structures.
- Simple <var id>s (i.e., <qual id>s used as <var id>s) are identifiers declared in variable
declarations or by the <formals> in a routine header.
- The form <var id>{<actuais>), where <var id> denotes an array, denotes the element of that
array indexed by the <actual>s. The types of the actuals must match the index types for the
array. 1
- The form <var id>{<actuals>), where <var id> denotes a variable of a variant type and the
<actual>s consist of a single <expr>, indicates that the tag field of the <var id> must be
<expr> and denotes the value of that option of the variant type. On the left side of an
assignment, this form has the effect of setting the tag field; the expression on the right side
of the assignment must be of compatible type.
- The form <var id>(<range>) denotes a subarray. The <var id> must denote an array and the
limits of the <range> must match the declared type of the array's index set and be a
subrange of the declared range. The subarray consists of the indicated elements of the <var
id>, in the same order as they appear in the <var id>. If the index type of the array is fixed
or defined in terms of fixed, the subarray is indexed by integers beginning with 1; otherwise
it is indexed from the minimum value of the index set of the array.
- If <var id> denotes a record object, the form <var id>.<id> denotes the field named <id> in
that record object If <var id> denotes an object of dynamic type, then <var id>.<id> denotes
the field named <id> in the record object pointed to by the value of <var id>; <var id> must
not have the value nil. This form is also used to access the value of a variant tag or the
attributes associated with the type of a value or variable. In addition, if T is a variable of
dynamic type, T.all is the complete value (all components) of the object associated with T.
-5-
- The form Rep'<id> is used in the same scope as the definition of the <id>'s type to indicate
that the <id> is to be regarding as having the underlying type. This permits operations on
the underlying type to be used for defining operations on the new type.
Identifiers that refer to definitions (e.g., of routines, types, or modules) are <qual id>s.
When an identifier is exported from a module, in the scope to which it is exported it is referred to
by a <qual id> or <var id> constructed by prefixing the identifier with the name of the module from
which it is exported: The qualifier is separated from the identifier with an apostrophe. Qualifiers may
be omitted if no ambiguity results.
A <type> used as a range must be fixed, an enumerated type, or a defined type that is ultimately
defined in terms of fixed or an enumeration.
2.3. Lexical Considerations
Spaces may be inserted freely between lexemes without altering the meaning of the program. An
end-of-line is equivalent to a space and may not be part of a lexeme. At least one space must
appear between any two adjacent lexemes composed of letters, digits, under bar, and decimal points. In
identifiers, ail characters are significant, but alphabetic case is not
Comments are introduced by the character V and terminated by the next following end-of-line.
T h e y have no effect on the elaboration of the program.
Although the language as presented in this report takes advantage of characters that are not in the
64-character ASCII subset, simple substitution to map programs into that alphabet are defined in
Appendix I.
-6-
3 . Expressions
<expr>
<unop>
<bnop>
<func cail>
<actuals>
<expr> *
f
Expressions describe computations that yield values. The elaboration of an expression produces an
object containing the value of the expression. The type of the object is determined by the following
rules:
- The type of an <expr> that is a <var id>, <const>, <func cail>, or selection of a field from a
computed composite value is determined by the appropriate declaration (or rule for literals).
- The type of a parenthesized expression is the type of the expression inside the parentheses.
- The type of a binary infix expression or a unary
of the appropriate binary or unary operator
invocations of functions that may be overloaded.
therefore be determined on the basis of the types
* /
+ < S > >
A cand
v cor
-7-
An invocation causes the elaboration of a procedure or function body with the elements of the
<formals> list of the routine bound to the elements of the <actuals> list provided by the Invocation. If
a routine name is overloaded, the definition whose formal parameter types match the types of the
actual parameters is selected. Procedure and function invocations (<proc call> and <func call>) differ in
that procedure invocations are statements, whereas function invocations are expressions having values.
An invocation consists of the following steps:
- Elaborate each of the <actuals> in an unspecified order, yielding a sequence of objects.
- For each result formal, create a variable having the same type and attributes as the
corresponding actual. Bind the result formals to these variables.
- For each const or manifest formal, create an object of the specified type with the same
attributes as the corresponding actual. Copy the value of the actual into the new object. 1
- Bind each var formal to the corresponding actual, which must be a variable (i.e., a <var id>).
Thus var formals are passed by reference.
- With the bindings established, elaborate the body of the routine
- For each result formal, copy the final value of the variable bound to that formal back into
the corresponding actual, which must be a variable (i.e., a <var id>). Note that this actual is
determined before the elaboration of the routine (i.e., for the actual A(i), it is the initial and
not the final value of i that determines the variable that receives the result).
T h e result of a function is treated as a result parameter instantiated at the call site with extent as
described above and passed as an implicit parameter to the function. During the elaboration of the
function, its value is developed in this result parameter.
During elaboration of a function, assignment to a variable that is not local to the function body (or to
the body of a routine it invokes, directly or indirectly) is permitted only if the function is never
invoked in a scope where such a change is made to a variable or component that is directly
accessible by the caller.
Actual parameters are matched with formal parameters positionally. They must satisfy restrictions on
type, binding and aliasing.
- The type of an actual parameter is acceptable if its <type name> exactly matches the <type
name> of the corresponding formal parameter. Type attributes (instantiation parameters of a
type) play no role in type checking. Chapter 5 gives rules for determining <type name>s.
- The binding of the actual parameter is acceptable if it matches the <binding> of the
. corresponding formal parameter according to the following rules:
If the formal parameter is
var
const
manifest
result
- Finally, the set of actual parameters must satisfy the following nonaliasing restriction: A
variable may not be used in more than one var or result position of a single procedure or
iNote that for dynamic types, this is a pointer copy.
-8-
Each such
Attributes of the dynamic type are provided when the constructor is used. Thus it is possible to
associate objects with different attributes with the same dynamic variable at different times.
-9-
4 . Statements
<stmt>
<proc call>
<block>
<code body>
Statements designate actions to be performed Their elaboration results in changes in the execution
state of the program. The <empty> statement has no effect Labels are used by goto statements in
altering the flow of control in a program. A label is accessible only within the <stmt> it labels and
within a compound statement (sequence of <stmt>s separated by semicolons) of which it is a <stmt>.
4.1. Blocks
Some examples are:
bagin var x : boolaan; x : - trua and
bagin x : y ; y : z; and
Blocks control extent. A <block> is elaborated when control flows into it, either because the <block>
is the body of a routine that has been invoked or because the elaboration of another <stmt> has
transferred control to it. First, all declarations and the texts of all module definitions are elaborated, in
lexical order. Next, the <stmt>s are elaborated as described elsewhere in this chapter. Finally, the
<block> is exited or terminated. If it is exited, control waits for all activations declared in this <block>
to become dead or mint, then the extent defined by the <block> is closed and all nondynamic variables
instantiated in the <block> are deallocated If the <block> is terminated, ail activations declared in the
<block> are forcibly terminated, and then the <block> is exited The choice between exiting and
terminating the block depends* on how control arrived at the end of the block. If the block came to
an end because a handler completed or an enclosing process was terminated, the block is terminated.
Otherwise, it is exited.
A <biock> is not permitted to export identifiers. Except when used as a routine body, it is an open
scope and has no need to import any.
4.2. Sequenced Statements
Some examples are:
x
lj
SumSq
2; 2 : 3
8; for i in 1.. 18 do SuwSq
SumSq V ( i ) t 2 od
Sequenced statements are elaborated in the order given, except when that order is interrupted by a
goto or an exception.
4.3. Assignment Statement
Some examples are:
V(5).Sum
3
x
(3 + u) * y
-10-
,,
for arbitrary type T. The value of the second parameter is assigned to the object named by the first
parameter. The parameters are of the same type, and the normal type-checking rules apply.
Assignment operators are defined for all primitive types. Assignment operators are defined for
arrays, records, variants, and programmer-defined types if and only if they have no components that
are declared const or are nonassignable by virtue of this rule. An assignment operator that copies the
whole value is automatically supplied for each user-defined type. For dynamic types this is a pointer
copy. Although assignment may be invoked with any variable and value of the type, it requires that
the attributes of its left and right operands be identical, and signals the BadAssign exception if they
are not. The BadAssign exception is also signalled if an assignment involving mismatched array, string,
or set sizes or an activation not in mint state is attempted
4.4. Conditional Statements
Some examples are:
if A < 3 then x : * y fi
if x
8 cand y/x > 8 then z :* ut(y/x) tise ui
1.3; q ; * y/x fi
case T i n t
on f u c h s i a - > Hue :* c o o l ; D e s c r i p t i o n : " P u r p l i s h - r e d "
on puce - > Hue : warm; D e s c r i p t i o n : "Brownish-purple"
esac
In the statement "if B then S I else S2 fi , B must have type boolean. First, B is elaborated. If the
resulting value is true, S I is elaborated; otherwise S2 is elaborated. In the absence of an else clause,
S2 is taken to be the empty statement, which has no effect
w
T h e expression
if 81 then S I eiif B2 then 52 . . . eJif Bn then Sn else S* fi
is equivalent to
if 61 then S I else
if 82 then 32 eise
if Bn then Sn else S>v fi
fi
fi
In the statement
case E3
on E l l
Elk - > SI
on E 2 1 , . . . , E 2 l - > S2
on E n l . . . . , E n m - > Sn
on others - > S*
esac
T h e E's must all be expressions of the same type, and all except EO must be manifest The type of
the ITs must be fixed, an enumerated type, or a defined type that is ultimately defined in terms of
fixed or an enumeration. Any of the E's except EO may be a <range>; such an Eij is treated as the
sequence of values in the range. First, EO is elaborated The Eij are elaborated and the results are
compared to EO (in unspecified order). If EO is equal to some Eij, the corresponding Si is elaborated.
If all comparisons yield false, S* is elaborated Exactly one Si is elaborated for each correct
elaboration of the case statement If the special constant others does not appear as the last <option>
and no match is found, an exception (CaseFailed) is signalled
-11-
T h e effect of a goto statement is to force control to the beginning of the statement with the given
label. Since the scope rules prevent inheritance of labels across closed scope boundaries and
importation of labels, a goto can not be used to transfer out of a routine or module.
4.7. Exceptions
Some examples are:
signal TooB i g
assart x < 8
r e a d < f i l e . x ) { on EOF - > goto E x i t }
x ; x+1 { on O v e r f l o w - > x : - 8 }
Exceptions are processed by handier clauses associated with individual statements. Each handier
clause associates processing code with given exceptions. The special identifier others may appear as
the last <id> list of a handler clause; it matches any exception that is not named in some other
exception <id> list of the same clause.
When an exception is signalled, control is transferred to the nearest dynamically enclosing handler
clause that handles the exception, either explicitly or through an others clause; the elaboration of the
handler replaces the elaboration of the remainder of the statement If this handler is not in the
currently-executing block, all intervening blocks will be terminated. If a handler is not found within
the currently-executing routine, that routine is terminated and the exception is resignalled at the point
of call of the routine. If a handler is not found within the currently-executing process, that process is
terminated and the exception is resignalled at the end of the block in which the process activation
was declared after waiting for control to reach that point and for ail other activations declared in that
block to terminate. If no handler is found in the scope of the exception name, a default handler will
be supplied to terminate that block.
Exiting a handler causes termination of the <stmt> with which it is associated. If the handler
resignals the same exception or raises a new one, the normal rules for exception processing apply.
T h e resignal command may be used in any handler body to resend the signal that caused that
handler to be invoked.
-12-
T h e assert statement raises the assertion exception if the <expr> is false. It is exactly equivalent
to the statement "if - <expr> then signal assertion fi".
There is one exception to the rule that an exception must be handled by the block in which it is
signalled or by a caller of that block: the Notify operation on activations or actnames. The effect of a
Notify is as if the Terminate exception were signalled in the currently-executing statement of the
activation named by the Notify command.
4.8. Parallel Process Control
Some examples are:
create P(S)
activate(Pl)
if I sB locked ( P I ) then . . .
T h e create command instantiates a process, P, as an object of type activation-of-P. The <var id>
in a create must name an object of type activation-of-P that is in mint state. If a process takes any
var parameters, the corresponding actual parameters must have extent at least as great as the
activation variable. The effect of the create is to instantiate an activation of P, bind the actuals of the
create to the formals of P, and set the activation in suspended state.
Each activation has a unique identifying token value of type aciname, and it may be named by one
or more objects of type actname. Except for create, all operations that control parallelism are special
routines that operate on either actnames or activations. These routines control the processes and
parallelism by changing and interrogating the states of individual activations; they are described in
Appendix 1.2.
Note that the extent rules require an activation to be dead or mint before the block in which it is
declared can be exited. This provides an implicit join operation. A fork can be obtained with a
series of creates and activates.
-13-
5. Types
<type>
<type name>
In Tartan, a <type name> may be either a simple identifier or an identifier inflected with additional
type names. The <type name> so formed captures ail the information needed for type checking.
- The <type name>s for the primitive scalar and simple nonscalar types are the keywords used
to declare them: fixed, float, boolean, latch, char, set, string, actname, file.
- The <type name> for an array declared "array<a.b) of 0" is "array^D]", where I is the <type
name> of a and b.
- The <type name> for an enumeration declared enum(Ll,L2.,..Ln] is enum(Li,L2....,Ln].
- T h e <type name> for an activation declared activation of P is activation[P].
- T h e <type name> for a dynamic type declared dynamic T is dynamic T.
- T h e <type name> for a record type is based on the sequence of field names and <type
name>9 in its declaration. For a record declared "recordfFl.Tl, F2.T2,
Fn:Tn]" the <type
name> is "recordfFl.TNl, F2:TN2,
Fn:TNn]" where the Fi are lists of field names, the Ti
are types, and the TNi are type names. Bindings in the declaration do not appear in the
type name.
- The <type name> for a variant is "variant(TT,Tl->\/l,T2->V2.>^,Tn->\/n] where T T is the
<type name> of the tag, Ti is the i* value of the tag type, and Vi is the <type name> that
corresponds to the ith value of the tag type As a result, two variant <type>s are the same if
they specify the same <type>s for all values of the tag.
w
- T h e <type name> for a defined type is the name given in the type definition.
5.1. Scalar Types
Some examples are:
Real
1. .18
enumCfuchsia, o c h r e , puce, saffron]
Built-in scalar types include fixed, float, boolean, latch, and character. Integer and real must be
constructed as special cases of fixed and float Ordered scalar enumerated types are defined by
providing an ordered list of values.
T y p e s fixed and float require <actuals> lists to provide range, scale, and precision when they are
used in declarations. These are attributes and do not affect the type. Although bindings for attributes
may in general be const or manifest, the specifications of fixed and float require manifest attributes.
T o define a type, the <expr>s in an explicit range must be const or manifest
5.2. Composite Structures
Some examples are:
-14-
a r r a y d . .18) of C o l o r
array (Co I o r ) of Real
string (10)
record [Name:str i n g ( 3 5 ) , Age:Int3
variant b: boolean Con true - > I n t on faise -> char)
Nonscalar data structures may be built up in three ways: with arrays (homogeneous indexed linear
structure), with records (nonhomogeneous structures with named fields), and with variants (structures
whose substructure may vary with time). In addition, the nonscalar types set, string, and file are
defined.
Legal bindings for fields of records and variants are var, const, and manifest. If a <binding> is
empty, it is taken to be var.
A variant type must have exactly one tag field. The special constant others may appear as the last
<option> of a <variant type>; it matches any constant that does not appear in any other <option>.
T h e syntax for arrays provides an abbreviation for a set of types pre-defined as
"array[IxType,EltType](r) where IxType is the index type, EltType is the element type, and r is a
(sub)range of IxType.
Thus array(1..10) of float" means "array(int,float](1..10T. Its type name,
"array[int,float]'\ is written "arraypnt] of float*. As for any type, when an <array type> is used as a
formal parameter, the attributes are not supplied. The type "array(A,B) of T* is an abbreviation for
"array(A) of array(B) of T". Similarly, the array accessor "V(ij)" s an abbreviation for "V(i)CT.
M
Values of a dynamic type are pointers to variables whose structure corresponds to the type
definition. They are initialized to nil. The extent of these variables covers the entire scope of the
type definition. Elaborating a constructor for the dynamic type yields a pointer to a new variable
distinct from ail others. The constructor supplies the attributes for this variable; they are not supplied
in the declaration of the named variable of the dynamic type Thus a named variable of dynamic type
may at different times point to, several different variables having different attributes.
5.4. Process Control Types
Some examples are:
activation of P
actname
Parallel processes are controlled with data of two types activations of processes and actnames,
or names of activations. Activations are instantiations of a given process; an activation may contain at
most one process activation during its lifetime and then only of the process given in its <type>. An
actname value is a pointer to an activation, Actname variables may contain pointers to activations of
any processes; an actname variable may refer to different instantiations of different processes from
time to time.
An activation is used to control parallel or pseudo-parallel execution of a process. At any time it
may be in one of four states: mint, active, suspended, and dead The extent of an activation variable
coincides with its scope. The immediately enclosing block cannot be exited until all activations declared
within it are dead or mint. An activation is associated with exactly one process, which must be named
by the <qual id>.
An actname may refer to any instantiated process. A newly-declared actname or activation variable
is initialized to mint
5.5. Defined Types
Some examples are:
T(n)
Sequence ( i n t ] (58)
Programmers may define new types. See section 6.5 on Type Definitions.
-15-
<dectaration> | <mod def> 1 <routine def> | <type def> | generic def> I <emotv>
| Imports <qual id> | exports <quai id> | exception <id> + 1 disable <id>
I prag <proc cail>. ;* garp
'
'
<decfaration>
<mod def>
<mod text>
<routine def>
<func text>
<proc text>
<type def>
::-
Hm
<generic def>
<remote inst>
<formais>
generic module <id> [ <forma!s> ] <mod text> | generic func <id> [ <formais> ] <func text>
| generic proc <d> [ <formals> ] <proc text> j generic process <id> [ <formais> ] <proc text>
is <quai id> [ <actuais> ] | is assumed ( <id> )
{ <bnding> <id> * : <type name> } *
<binding>
var.
x : Real
y : * true
H u e l . Hue2. Hue3: Color
T i n t :* enumCsaffron, puce, fuchsia, ochreJ
V: array<5. .7) of I n t
r i l : r 1 a r k ( S ) , n2:Hark(7)
manifest
P I : Real
3.14
T h e syntax for declarations allows three kinds of abbreviations. If the initialization expression
appears, the type of the variable is evident from the <expr> and the ":<type>" may be omitted. In
addition, lists of <id>s with the same types or bindings may be condensed. These abbreviations are
illustrated by the following five declarations, ail of which have the same effect:
var
var
var
var
var
x , y :* 8
x , y : I n t : 8
x : 8, y : 8
x : I n t : 8. y . I n t : 8
x : I n t : * 8; var y : I n t :* 8
Elaboration of a declaration causes instantiation of an object which is the variable. Each variable
has a type and a value. The type is determined when it is instantiated, but the value may be changed
by further elaboration of the program. A variable may be restricted to be const (value fixed at block
entry) or manifest (value fixed during translation).
Elaboration of a declaration proceeds as follows:
- Evaluate the <expr>, if present. It must be present in manifest or const declarations.
be manifest in manifest declarations.
It must
- If the <binding> is manifest, bind the value of the <expr> to the identifier(s).
- If the <binding> is const or var, elaborate any <actual>s in the <type> and instantiate a new
variable with the indicated type and attributes for each identifier. If there was an <expr>,
assign its value to each of the new variables.
W h e n the type is dynamic, the declaration supplies the <type name> only (no attributes). In this case,
only the pointer is allocated at block entry; the attributes are supplied when the dynamic type is
actually (dynamically) allocated.
-16-
6.2. Modules
An example is:
module C o u n t e r Q e f ;
begin
exports C o u n t e r , Reset. I n c r , Value;
type Counter - I n t ;
proc Reset (result C : C o u n t e r ) ; begin C : 8 end;
proc I n c r (var C : C o u n t e r ) ; begin C : C + 1 end;
func Value (const C:Counter) x:Counter; begin x
C end
end
T h e elaboration of a module takes place during the elaboration of declarations for the block in
w h i c h the module is defined This elaboration consists of elaborating the declarations of the module in
lexical order, then elaborating the statements of the module
A module or routine inherits identifiers for definitions (modules, routines, exceptions, and types) from
its enclosing scope. It may explicitly import identifiers of objects from that scope, provided the
objects have global extent. A module, but not a routine, may export definition and object identifiers to
its enclosing scope. Types, named routines, field accessors for records, and variables are exported by
including their names in the exports list of the module. The right to apply infix operators,
constructors, subscripts, ".air, or the create command for a type T are exported by including the
special names Tinfix, Tconstr, Psubscr, Tail, and Tcreate, respectively, in the exports list. Literals
of enumerated types are exported automatically if the types are exported
5.3. Routines
Some examples are:
proc F (var x : I n t ) ; begin x :* - x; end
proc G is GenG C53
func I sNi I ( x : 0 y n T ) y : boolean; begin y
(x nil) end
func
(a,b:gorp)c:gorp;
begin
imports B i a s ;
c :* gorp' (a. left+b. Ieft+Bias. a.right+b.right+Bias)
end
A routine is a closed scope whose body is a block. Thus its body controls extent for local
declarations, but does not inherit identifiers for (non-manifest) objects or labels. The <formais> list
declares the identifiers for parameters.
A routine may be a function (func), which returns a vaiue and has no visible side effects; it may be
a procedure (proc), which can modify its parameters but must be called as a statement; or it may be a
process, which is a potentially-parallel procedure. Special type-specific routines are described in
Appendix 1.2.
Routine names may be overloaded by binding the same identifier to several definitions with different
numbers or types of parameters. The functions for which special infix notation is provided are
obvious candidates for overloading.
If a <binding> in a routine header is omitted, it is assumed to be const The result binding may be
used only in procedures. No duplication of identifiers within the <formals> list is permitted, and
parameter names may not conflict with declarations or imports in the routine body.
6.4. Exceptions
Some examples are:
exception TooBig, TooSmall. Late, Singular
disable TooBig, TooSmall
-17-
A user may introduce a new type into his program with a type definition. The type definition itself
merely introduces the <type name> and defines the representation of the type. Operations are
introduced by writing routines whose formal parameters are of the newly-defined type.
Scope
boundaries, particularly module boundaries, play no role in the definition of the type. There is, as a
consequence, no notion of the complete set of operations on a type.
A type definition may be parameterized. The bindings in the formal parameter list must be const or
manifest. If a <binding> is omitted, it will be assumed to be const The names of the formal parameters
of the type are available throughout the elaboration of the program as constants, called attributes.
T h e y are accessed by treating the <var ident> as a record and the type attribute as a field.
Attributes for primitive types are given as part of the type definitions.
Within the scope in which the type is defined, the qualifier Rep may be used to indicate that the
object named by the identifier Rep qualifies is to be treated as if it had the underlying type. This
allows operations on the new type to be written using operations on its representation. When no
ambiguity arises, the Rep qualification may be omitted.
6.6. Generic Definitions
Some examples are:
generic proc Reset CT: type] (var x : T ) ; begin x
proc R e s e t C o l o r is Reset [Color]
proc ResetX is Rese t tSamp I e]
module Stack is assumed(StackOef)
generic module R i ngOe f (K; I n t J ;
begin
exports R i n g , Next;
type Ring - f i x e d d , 8 . B . K - 1 ) ;
func Next (R: R i n g ) N . fixed U . 8 , 8 , K - l ) ;
end
module R5 is RingOefCS]
module R3 is R i n g O e f O ]
begin N
x'min and
nod(R+l,K)| end
A generic definition is syntactically like the corresponding specific definition except that it is
prefixed by the word generic and it may have a set of generic parameters (enclosed in square
brackets) after the definition name. For generic definitions, type is acceptable as a formal <type name>.
T h e actual parameters supplied in an instantiation of a generic definition may be any defined
identifiers, including those for variables, functions, types, or modules, or any expression. When the
generic definition is instantiated, the text of the actual parameters replaces the identifiers that
represent the formal parameters. The substitution is done on a lexical, rather than a strictly textual,
basis. That is, the identifiers in the generic definition are renamed as necessary to avoid conflicts
with the identifiers in the actual parameters.
-18-
Both generic definitions and remotely-defined modules or routines may be incorporated in a program
as remote instances. A remote instance may be an instantiation of a generic definition or a reference
to a definition given elsewhere.
A module or routine that is used by the program but whose definition is given elsewhere (e.g., in a
library) is incorporated by writing is assumed(<id>) as the body of a module or routine definition. The
<id> is used by a pragmat to locate the remote definition.
A generic definition is instantiated by referring to it as the body of a module or routine definition.
T h e effect of the instantiation is as if the generic definition were lexically substituted in place of the
reference to it. That is, the body of the module or routine being defined becomes a copy of the
generic definition.
An instantiation of a generic definition may be used as the body of a specific module or routine. The
usual restrictions on defining new identifiers apply to the module or routine being defined in terms of a
generic.
Generic type definitions arise from generic modules. They are instantiated when the module is
instantiated. Thereafter, they may be used in declarations or definitions.
If the generic definition has generic parameters, the actual parameters supplied with the
instantiation must have correponding types and be syntactically suitable for substitution.
If a generic definition is instantiated more than once in a scope, ambiguous names may be
introduced. The usual rules for resolving such ambiguities apply.
6.7. Translation Issues
An example is:
prag O p t i m i z e ( s p a c e ) ; L i s t i n g (Off) garp
A program is a <block>. The extent defined by the outer block of the program is the global extent.
T h e translator may be guided by <pragmat>s. Pragmats have the same syntax as procedure calls.
T h e set of pragmat names and the interpretations of the arguments are determined by each translator.
Translators will ignore pragmats whose names they do not recognize.
A program may be broken into separately defined segments. This decomposition must take place in
the global extent. The units of separate definition are modules and routines. The definition
module Q is assumed ( I )
in a segment has the effect of making the semantics of the segment the same as if the (separately
defined) text of Q had been substituted for "is assumed(I)". The identifier I refers to a file, library, or
other facility for storing separately defined segments. The relation between the identifier I and that
storage facility may be established by a pragmat
It is a matter of optimization whether the separate definition is included as text or separately
translated and linked in. In order to perform independent translation of a separately defined component,
it is necessary to embed the module or routine being translated in an environment that supplies
definitions for all the names it inherits or imports. This environment must form a complete program.
It is assumed that the translation system provides commands for selecting which components of such a
translation to save and for determining where and in what form they are to be saved.
-19-
I. Standard Definitions
1.1. System-Dependent Characteristics
T h e translator for each system is assumed to provide a module in the global extent that defines
appropriate system constants. Such constants are assumed at various points in the language definitionthese and certain others are summarized here in the form of a skeleton module.
module S y s ;
begin
exports . . .
exports a l l d e f i n i t i o n s below
type I n t - fixed(.
const . . .
proc . . .
exceptions . . .
scale
end
digit strings
Min, Max, Precision, Scale
Arithmetic and relational
rounding, truncation
1.2.2. Float
Literals:
Attributes:
Infix operations:
Special routines:
1.2.3* Enumerations
order
Literals:
Attributes:
Infix operations:
Special routines:
r d e r e d
l i , e r a l s
a r e
As given in definition
Min, Max
Relational
succ. pred
UN1VERS T*
^
CARNEGlt-*"
V^SITY
r i l T S B U R G H , Ft?<r.vic*<*iA 15213
S
-20-
1.2.4. Boolean
Literals:
Attributes:
Infix operations:
Special routines:
true, false
none
logical
none
1.2.5. Characters
Literals:
Attributes:
Infix operations:
Special routines:
Quoted characters
Min, Max
none
as for enumerations
L2.S. Latches
A latch is a simple spinlock for mutual exclusion, If the latch is open, it is available for siezure; if it
is closed, a Lock command will wait on it
Literals:
Attributes:
Infix operations:
Special routines:
open, closed
none
none
Lock, IfLock, Unlock
1.2-7. Arrays
Literals:
Attributes:
Infix operations:
Special operations:
none
Range, EltType
none
subscript, subarray, catenation, upper bound, lower bound
1.2.8. Sets
"Sets" are boolean vectors on which some additional operations are defined
Literals:
Attributes:
Infix operations:
Special operations:
empty
EltType, MaxSize
logical
subscript
The named variable does not itself have attributes, but the dynamic
variable that it references may.
none
.
.
.all denotes whole value of dynamic object, as distinguished from
the reference. A dynamic constructor allocates a new dynamic object
none
1.2.10. Records
Literals:
Attributes:
Infix operations:
Special operations:
Special routines:
none
individually defined with record type
none
field selection, constructors
none
-21-
L 2 . i l . Variants
Literals:
Attributes:
Infix operations:
Special operations:
Special routines:
none
individually defined with variant type
none
variant must be designated to reference contents
none
1.2.12. Strings
Literals:
Attributes:
Infix operations:
Special operations:
Quoted strings
Length
none
subscript, substring, catenation
1.2.13. Activations
Literals:
Attributes:
Infix operations:
Special operations:
mint
none
none
create
Special routines:
Assignment causes the BadAssign exception if either the value or the variable to which it is being
assigned is in a state other than mint
1.2*14. Act names
Literals:
Attributes:
Infix operations:
Special operations:
Special routines:
mint
none
none
none
Same as for activations
1.2.15. Files
A minimal input-output facility will be provided
1.3. Alphabets
<>
and
or
- -I-
*l/l*|-|<!<l>l>l-i*iA|cand|v|cor|t
<proc cail>
<biocK>
<code body>
<type>
: <code body>
begin { <de1-de<:\> ; }* <stmt>.* end
fixed( <actuals> ) { float( <actuais> ) ) boolean I latch j char | fiie< <actuais> )
| enum( <id> ] | enum( { " <char> " } ] | <expr> . . <expr>
| sei( <actuals> ) I siring ( <actuals> ) '
| array ( <range>^ ) of <type> | record [ <declaration> ]
j variant <declaration> ( { on <option> -> <type> }+]
| dynamic <type> f activation of <qual id> | actname
j <type name> { ( <actuals> ) J
: fixed | float | boolean | latch | char j file | set | string
<type name>
I enum( <id> * ] \ enum( { " <char> " } * ]
j array [ <type name> * j of <type name> | record [ { <id> * : <type name> } + ]
| variant [ <type name> { on <option> -> <type name> }* ]
| dynamic <type name> | activation [ <qual id> ] | actname
| <qual id> ( [ <qual id> ] }*
<declaration> I <mod def> I <routine def> | <type def> I <gener ic def> j <empty>
<def-deci>
| imports <qual id> j exports <qual id> J exception <id> * | disable <id>
| prag <proc call>.* ;* garp
<declaration>
<binding> { <d> ( : <type> }* { : <expr> J* }* | <binding> { <id> + : <type name> } +
module <id> <mod text>
<mod def>
; <code body> J <remote inst>
<mod text>
<routine def> :: proc <id> <proc text> | func <id> <func text> | process <id> <proc text>
| func " { <unop> | <binop> } " <func text>
<func text>
( <formals> ) <id> : <type> ; <blocK> | <remote inst>
<proc text>
( <formals> ); <block> | <remote inst>
<type def>
type <type name> { ( <formals> ) }* <type>
<generic def>
generic module <id> [ <formals> ] <mod text> j generic func <id> [ <formals> ] <func text>
| generic proc <id> [ <formals> ] <proc text> | generic process <id> [ <formals> ] <proc text
<remote inst>
is <qual id> [ <actuals> ] | is assumed ( <id> )
<formals>
{ <binding> <*<i> + : <type name> )*
<binding>
<empty> | var | const j manifest | result
+