6 |
7u83 |
1 |
<?xml version="1.0" standalone="no"?>
|
|
|
2 |
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
|
|
3 |
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
|
|
|
4 |
|
|
|
5 |
<!--
|
|
|
6 |
$Id$
|
|
|
7 |
-->
|
|
|
8 |
|
|
|
9 |
<book>
|
|
|
10 |
<bookinfo>
|
|
|
11 |
<title>Calculus Users' Guide</title>
|
|
|
12 |
|
|
|
13 |
<corpauthor>The TenDRA Project</corpauthor>
|
|
|
14 |
|
|
|
15 |
<author>
|
|
|
16 |
<firstname>Jeroen</firstname>
|
|
|
17 |
<surname>Ruigrok van der Werven</surname>
|
|
|
18 |
</author>
|
|
|
19 |
<authorinitials>JRvdW</authorinitials>
|
|
|
20 |
<pubdate>2004</pubdate>
|
|
|
21 |
|
|
|
22 |
<copyright>
|
|
|
23 |
<year>2004</year>
|
|
|
24 |
<year>2005</year>
|
|
|
25 |
|
|
|
26 |
<holder>The TenDRA Project</holder>
|
|
|
27 |
</copyright>
|
|
|
28 |
|
|
|
29 |
<copyright>
|
|
|
30 |
<year>1998</year>
|
|
|
31 |
|
|
|
32 |
<holder>DERA</holder>
|
|
|
33 |
</copyright>
|
|
|
34 |
</bookinfo>
|
|
|
35 |
|
|
|
36 |
<chapter id="introduction">
|
|
|
37 |
<title>Introduction</title>
|
|
|
38 |
|
|
|
39 |
<para>This document describes a tool, <command>calculus</command>, which
|
|
|
40 |
allows complex type systems to be described in a simple algebraic
|
|
|
41 |
format, and transforms this into a system of C types which implements
|
|
|
42 |
this algebra.</para>
|
|
|
43 |
|
|
|
44 |
<para><command>calculus</command> was initially written as a design tool
|
|
|
45 |
for use with the TenDRA C and C++ producers. The producers' internal
|
|
|
46 |
datatypes reflect the highly complex interdependencies between the C and
|
|
|
47 |
C++ language concepts (types, expressions and so on) which they were
|
|
|
48 |
designed to represent. A tool for managing this complexity and allowing
|
|
|
49 |
changes to the internal datatypes to be made with confidence was
|
|
|
50 |
therefore seen to be an absolute necessity. The tool can also be applied
|
|
|
51 |
in similar situations where a complex type system needs to be
|
|
|
52 |
described.</para>
|
|
|
53 |
|
|
|
54 |
<para>The tool also provides for a separation between the specification of
|
|
|
55 |
the type system and its implementation in terms of actual C types. This
|
|
|
56 |
separation has a number of advantages. The advantages of maintaining a
|
|
|
57 |
level of abstraction in the specification are obvious. It is possible to
|
|
|
58 |
apply extremely rigorous type checking to any program written using the
|
|
|
59 |
tool, thereby allowing many potential errors to be detected at compile
|
|
|
60 |
time. It is also possible to restrict access to the types to certain
|
|
|
61 |
well-specified constructs, thereby increasing the maintainability of
|
|
|
62 |
code written using the tool.</para>
|
|
|
63 |
|
|
|
64 |
<para>This separation also has beneficial effects on the implementation of
|
|
|
65 |
the type system. By leaving all the type checking aspects at the
|
|
|
66 |
specification level, it is possible to impose an extremely homogeneous
|
|
|
67 |
underlying implementation. This means, for example, that a single memory
|
|
|
68 |
management system can be applied to all the types within the system. It
|
|
|
69 |
also opens the possibility of writing operations which apply to all
|
|
|
70 |
types within the system in a straightforward manner. The
|
|
|
71 |
<link linkend="diskoutput">disk reading and writing routines</link>
|
|
|
72 |
described below are an example of this.</para>
|
|
|
73 |
|
|
|
74 |
<sect1 id="options">
|
|
|
75 |
<title>Using calculus</title>
|
|
|
76 |
|
|
|
77 |
<para>The general form for invoking <command>calculus</command> is as
|
|
|
78 |
follows:
|
|
|
79 |
<command>calculus<optional><option>options</option></optional>
|
|
|
80 |
<option>input</option> ....
|
|
|
81 |
<optional><option>output</option></optional></command>
|
|
|
82 |
where <option>input</option> is a file containing the input type
|
|
|
83 |
system description and <option>output</option> is the directory where
|
|
|
84 |
the files implementing this system are to be output. This directory
|
|
|
85 |
must already exist. If no <option>output</option> argument is given
|
|
|
86 |
then the current working directory is assumed. Note that several
|
|
|
87 |
<option>input</option> files can be given. Unless
|
|
|
88 |
<link linkend="module">otherwise specified</link> it is the last file
|
|
|
89 |
which is used to generate the output.</para>
|
|
|
90 |
|
|
|
91 |
<para>The form in which the
|
|
|
92 |
<link linkend="textinput">input type systems</link>
|
|
|
93 |
are expressed is described below. The form of the output depends on
|
|
|
94 |
<option>options</option>. By default, the C implementation of the type
|
|
|
95 |
system is output. If the <option>-t</option> option is passed to
|
|
|
96 |
<command>calculus</command> then
|
|
|
97 |
<ulink url="tcpplus.html#token"><code>#pragma token</code></ulink>
|
|
|
98 |
statements describing the type system specification are output. This
|
|
|
99 |
<link linkend="tokenoutput">specification</link> is given below, with
|
|
|
100 |
some of the more important
|
|
|
101 |
<link linkend="coutput">implementation details</link> being described
|
|
|
102 |
in the following section.</para>
|
|
|
103 |
|
|
|
104 |
<para>Note that it is necessary to check any program written using
|
|
|
105 |
<command>calculus</command> against the <code>#pragma token</code>
|
|
|
106 |
version of the specification in order to get the full benefits of the
|
|
|
107 |
rigorous type checking provided by the tool. Some sections of the
|
|
|
108 |
program (if only the
|
|
|
109 |
<link linkend="coutputsupport">basic functions</link>) may be
|
|
|
110 |
dependent upon the implementation, and so not be suitable for this
|
|
|
111 |
form of checking.</para>
|
|
|
112 |
</sect1>
|
|
|
113 |
|
|
|
114 |
<sect1 id="example">
|
|
|
115 |
<title>Example program</title>
|
|
|
116 |
|
|
|
117 |
<para>The program <command>calculus</command> itself was written using a
|
|
|
118 |
type system specified using the <command>calculus</command> tool. It
|
|
|
119 |
is designed to provide an example of its own application, with some
|
|
|
120 |
features not strictly necessary for the functionality of the program
|
|
|
121 |
being added for illustrative purposes.</para>
|
|
|
122 |
</sect1>
|
|
|
123 |
</chapter>
|
|
|
124 |
|
|
|
125 |
<chapter id="textinput">
|
|
|
126 |
<title>Input syntax</title>
|
|
|
127 |
|
|
|
128 |
<para>The overall input file format is as follows:
|
|
|
129 |
|
|
|
130 |
<programlisting>
|
|
|
131 |
algebra:
|
|
|
132 |
ALGEBRA identifier version<subscript>opt</subscript>: item-list<subscript>opt</subscript>
|
|
|
133 |
|
|
|
134 |
version:
|
|
|
135 |
(integer.integer)
|
|
|
136 |
|
|
|
137 |
item-list:
|
|
|
138 |
item
|
|
|
139 |
item-list item
|
|
|
140 |
|
|
|
141 |
item:
|
|
|
142 |
primitive
|
|
|
143 |
identity
|
|
|
144 |
enumeration
|
|
|
145 |
structure
|
|
|
146 |
union
|
|
|
147 |
</programlisting></para>
|
|
|
148 |
|
|
|
149 |
<para>The initial identifier gives the overall name of the algebra. A
|
|
|
150 |
version number may also be associated with the algebra (if this is
|
|
|
151 |
omitted the version is assumed to be 1.0). The main body of the
|
|
|
152 |
algebra definition consists of a list of items describing the
|
|
|
153 |
primitives, the identities, the enumerations, the structures and the
|
|
|
154 |
unions comprising the algebra.</para>
|
|
|
155 |
|
|
|
156 |
<para>Here <literal>identifier</literal> has the same meaning as in C.
|
|
|
157 |
The only other significant lexical units are
|
|
|
158 |
<literal>integer</literal>, which consists of a sequence of decimal
|
|
|
159 |
digits, and <literal>string</literal>, which consists of any number of
|
|
|
160 |
characters enclosed in double quotes. There are no escape sequences in
|
|
|
161 |
strings. C style comments may be used anywhere in the input. White
|
|
|
162 |
space is not significant.</para>
|
|
|
163 |
|
|
|
164 |
<sect1 id="inputprim">
|
|
|
165 |
|
|
|
166 |
<title>Primitives</title>
|
|
|
167 |
|
|
|
168 |
<para>Primitives form the basic components from which the other types in
|
|
|
169 |
the algebra are built up. They are described as follows:
|
|
|
170 |
|
|
|
171 |
<programlisting>
|
|
|
172 |
primitive:
|
|
|
173 |
object-identifier = quoted-type;
|
|
|
174 |
</programlisting>
|
|
|
175 |
|
|
|
176 |
where the primitive identifier is given by:
|
|
|
177 |
|
|
|
178 |
<programlisting>
|
|
|
179 |
object-identifier:
|
|
|
180 |
#<subscript>opt</subscript>:<subscript>opt</subscript> identifier
|
|
|
181 |
#<subscript>opt</subscript>:<subscript>opt</subscript> identifier(identifier)
|
|
|
182 |
</programlisting>
|
|
|
183 |
|
|
|
184 |
and the primitive definition is a string which gives the C type
|
|
|
185 |
corresponding to this primitive:
|
|
|
186 |
|
|
|
187 |
<programlisting>
|
|
|
188 |
quoted-type:
|
|
|
189 |
string
|
|
|
190 |
</programlisting></para>
|
|
|
191 |
|
|
|
192 |
<para>Note that each primitive (and also each identity, each
|
|
|
193 |
enumeration, each structure and each union) has two names associated
|
|
|
194 |
with it. The second name is optional; if it is not given then it is
|
|
|
195 |
assumed to be the same as the first name. The first name is that which
|
|
|
196 |
will be given to the corresponding type in the output file. The second
|
|
|
197 |
is a short form of this name which will be used in forming constructor
|
|
|
198 |
names etc. in the output.</para>
|
|
|
199 |
|
|
|
200 |
<para>The optional hash and colon which may be used to qualify an object
|
|
|
201 |
identifier are provided for backwards compatibility only and are not
|
|
|
202 |
used in the output routines.</para>
|
|
|
203 |
</sect1>
|
|
|
204 |
|
|
|
205 |
<sect1 id="inputident">
|
|
|
206 |
<title>Identities</title>
|
|
|
207 |
|
|
|
208 |
<para>Identities are used to associate a name with a particular type in
|
|
|
209 |
the algebra. In this they correspond to <code>typedef</code>s in C.
|
|
|
210 |
They are described as follows:
|
|
|
211 |
|
|
|
212 |
<programlisting>
|
|
|
213 |
identity:
|
|
|
214 |
object-identifier = type;
|
|
|
215 |
</programlisting>
|
|
|
216 |
|
|
|
217 |
where the definition type, <literal>type</literal>, is as described
|
|
|
218 |
<link linkend="inputtype">below</link>.</para>
|
|
|
219 |
</sect1>
|
|
|
220 |
|
|
|
221 |
<sect1 id="inputenum">
|
|
|
222 |
<title>Enumerations</title>
|
|
|
223 |
|
|
|
224 |
<para>Enumerations are used to define types which can only take values
|
|
|
225 |
from some finite set. They are described as follows:
|
|
|
226 |
|
|
|
227 |
<programlisting>
|
|
|
228 |
enumeration:
|
|
|
229 |
enum !<subscript>opt</subscript> object-identifier = { enumerator-list };
|
|
|
230 |
enum !<subscript>opt</subscript> object-identifier = base-enumeration + { enumerator-list };
|
|
|
231 |
</programlisting>
|
|
|
232 |
|
|
|
233 |
where:
|
|
|
234 |
|
|
|
235 |
<programlisting>
|
|
|
236 |
base-enumeration:
|
|
|
237 |
identifier
|
|
|
238 |
</programlisting>
|
|
|
239 |
|
|
|
240 |
is the name of a previously defined enumeration type. The latter form
|
|
|
241 |
is used to express extension enumeration types. An enumeration type may
|
|
|
242 |
be qualified by an exclamation mark to indicate that no lists of this
|
|
|
243 |
type will be constructed.</para>
|
|
|
244 |
|
|
|
245 |
<para>The enumeration constants themselves are defined as
|
|
|
246 |
follows:
|
|
|
247 |
|
|
|
248 |
<programlisting>
|
|
|
249 |
enumerator:
|
|
|
250 |
identifier
|
|
|
251 |
identifier = enumerator-value
|
|
|
252 |
|
|
|
253 |
enumerator-list:
|
|
|
254 |
enumerator
|
|
|
255 |
enumerator-list, enumerator
|
|
|
256 |
</programlisting></para>
|
|
|
257 |
|
|
|
258 |
<para>Each enumerator is assigned a value in an ascending sequence,
|
|
|
259 |
starting at zero. The next value to be assigned can be set using an
|
|
|
260 |
<literal>enumerator-value</literal>. This is an expression formed from
|
|
|
261 |
<literal>integer</literal>s, <literal>identifier</literal>s
|
|
|
262 |
representing previous enumerators from the same enumeration, and the
|
|
|
263 |
question mark character which stands for the previous enumeration
|
|
|
264 |
value. The normal C arithmetic operations can be applied to build up
|
|
|
265 |
more complex <literal>enumerator-value</literal>s. All enumerator
|
|
|
266 |
evaluation is done in the <code>unsigned long</code> type of the host
|
|
|
267 |
machine. Values containing more than 32 bits are not portable.</para>
|
|
|
268 |
|
|
|
269 |
<para>Enumerations thus correspond to enumeration types in C, except
|
|
|
270 |
that they are genuinely distinct types.</para>
|
|
|
271 |
</sect1>
|
|
|
272 |
|
|
|
273 |
<sect1 id="inputstruct">
|
|
|
274 |
<title>Structures</title>
|
|
|
275 |
|
|
|
276 |
<para>Structures are used to build up composite types from other types
|
|
|
277 |
in the algebra. They correspond to structures in C. They are described
|
|
|
278 |
as follows:
|
|
|
279 |
|
|
|
280 |
<programlisting>
|
|
|
281 |
structure:
|
|
|
282 |
struct object-identifier = component-group;
|
|
|
283 |
struct object-identifier = base-structure + component-group;
|
|
|
284 |
</programlisting>
|
|
|
285 |
|
|
|
286 |
where:
|
|
|
287 |
|
|
|
288 |
<programlisting>
|
|
|
289 |
base-structure:
|
|
|
290 |
identifier
|
|
|
291 |
</programlisting>
|
|
|
292 |
|
|
|
293 |
is the name of a previously defined structure type. The latter form
|
|
|
294 |
is used to express (single) inheritance of structures. All components
|
|
|
295 |
of the base structure also become components of the derived
|
|
|
296 |
structure.</para>
|
|
|
297 |
|
|
|
298 |
<para>The structure components themselves are defined as follows:
|
|
|
299 |
|
|
|
300 |
<programlisting>
|
|
|
301 |
component-group:
|
|
|
302 |
{ component-list<subscript>opt</subscript> }
|
|
|
303 |
|
|
|
304 |
component-list:
|
|
|
305 |
component-declarations;
|
|
|
306 |
component-list component-declarations;
|
|
|
307 |
|
|
|
308 |
component-declarations:
|
|
|
309 |
type component-declarators
|
|
|
310 |
|
|
|
311 |
component-declarators:
|
|
|
312 |
component-declarator
|
|
|
313 |
component-declarators, component-declarator
|
|
|
314 |
|
|
|
315 |
component-declarator:
|
|
|
316 |
identifier component-initialiser<subscript>opt</subscript>
|
|
|
317 |
|
|
|
318 |
component-initialiser:
|
|
|
319 |
= string
|
|
|
320 |
</programlisting></para>
|
|
|
321 |
|
|
|
322 |
<para>The optional <link linkend="outputstruct">component initialiser
|
|
|
323 |
strings</link> are explained below.</para>
|
|
|
324 |
|
|
|
325 |
<para>Structures are the only algebra construct which prevent the input
|
|
|
326 |
from being a general graph. Unions may be defined in terms of
|
|
|
327 |
themselves, but (as in C) pointers must be used to define structures
|
|
|
328 |
in terms of themselves.</para>
|
|
|
329 |
</sect1>
|
|
|
330 |
|
|
|
331 |
<sect1 id="inputunion">
|
|
|
332 |
<title>Unions</title>
|
|
|
333 |
|
|
|
334 |
<para>Unions are used to build up types which can hold a variety of
|
|
|
335 |
information. They differ from C unions in that they are discriminated.
|
|
|
336 |
They are described as follows:
|
|
|
337 |
|
|
|
338 |
<programlisting>
|
|
|
339 |
union:
|
|
|
340 |
union object-identifier = component-group + field-group map-group<subscript>opt</subscript>;
|
|
|
341 |
union object-identifier = base-union + field-group map-group<subscript>opt</subscript>;
|
|
|
342 |
</programlisting>
|
|
|
343 |
|
|
|
344 |
where:
|
|
|
345 |
|
|
|
346 |
<programlisting>
|
|
|
347 |
base-union:
|
|
|
348 |
identifier
|
|
|
349 |
</programlisting>
|
|
|
350 |
|
|
|
351 |
is the name of a previously defined union type. The latter form is
|
|
|
352 |
used to express (single) inheritance of unions. All components, fields
|
|
|
353 |
and maps of the base union also become components of the derived
|
|
|
354 |
union. Note that only new fields and maps can be added in the derived
|
|
|
355 |
union.</para>
|
|
|
356 |
|
|
|
357 |
<para>The <literal>component-group</literal> gives a set of components
|
|
|
358 |
which are common to all the different union cases. The cases
|
|
|
359 |
themselves are described as follows:
|
|
|
360 |
|
|
|
361 |
<programlisting>
|
|
|
362 |
field-group:
|
|
|
363 |
{ field-list }
|
|
|
364 |
|
|
|
365 |
field:
|
|
|
366 |
#<subscript>opt</subscript> #<subscript>opt</subscript> field-identifier-list->component-group
|
|
|
367 |
#<subscript>opt</subscript> #<subscript>opt</subscript> field-identifier-list->base-field + component-group
|
|
|
368 |
|
|
|
369 |
base-field:
|
|
|
370 |
identifier
|
|
|
371 |
|
|
|
372 |
field-list:
|
|
|
373 |
field
|
|
|
374 |
field-list, field
|
|
|
375 |
|
|
|
376 |
field-identifier:
|
|
|
377 |
identifier
|
|
|
378 |
|
|
|
379 |
field-identifier-list:
|
|
|
380 |
field-identifier
|
|
|
381 |
field-identifier-list, field-identifier
|
|
|
382 |
</programlisting></para>
|
|
|
383 |
|
|
|
384 |
<para>The optional one or two hashes which may be used to qualify a list
|
|
|
385 |
of field identifiers are used to indicate
|
|
|
386 |
<link linkend="diskalias">aliasing</link> in the disk reading and
|
|
|
387 |
writing routines. The <literal>base-field</literal> case is a
|
|
|
388 |
notational convenience which allows one field in a union to inherit
|
|
|
389 |
all the components of another field.</para>
|
|
|
390 |
|
|
|
391 |
<para>Note that a number of field identifiers may be associated with the
|
|
|
392 |
same set of field components. Any such list containing more than one
|
|
|
393 |
identifier forms a field identifier set, named after the first field
|
|
|
394 |
identifier.</para>
|
|
|
395 |
|
|
|
396 |
<para>In addition a number of maps may be associated with a union.
|
|
|
397 |
These maps correspond to functions which take the union, plus a number
|
|
|
398 |
of other map parameter types, and return the map return type. They are
|
|
|
399 |
described as follows:
|
|
|
400 |
|
|
|
401 |
<programlisting>
|
|
|
402 |
map-group:
|
|
|
403 |
:[map-list<subscript>opt</subscript>]
|
|
|
404 |
|
|
|
405 |
map:
|
|
|
406 |
extended-type #<subscript>opt</subscript> identifier(parameter-list<subscript>opt</subscript>)
|
|
|
407 |
|
|
|
408 |
map-list:
|
|
|
409 |
map
|
|
|
410 |
map-list map
|
|
|
411 |
</programlisting>
|
|
|
412 |
|
|
|
413 |
where:
|
|
|
414 |
|
|
|
415 |
<programlisting>
|
|
|
416 |
parameter-list:
|
|
|
417 |
parameter-declarations
|
|
|
418 |
parameter-list; parameter-declarations
|
|
|
419 |
|
|
|
420 |
parameter-declarations:
|
|
|
421 |
extended-type parameter-declarators
|
|
|
422 |
|
|
|
423 |
parameter-declarators:
|
|
|
424 |
identifier
|
|
|
425 |
parameter-declarators, identifier
|
|
|
426 |
</programlisting></para>
|
|
|
427 |
|
|
|
428 |
<para>Note that the map parameter and return types are given by:
|
|
|
429 |
|
|
|
430 |
<programlisting>
|
|
|
431 |
extended-type:
|
|
|
432 |
type
|
|
|
433 |
quoted-type
|
|
|
434 |
</programlisting></para>
|
|
|
435 |
|
|
|
436 |
<para>In addition to the
|
|
|
437 |
<link linkend="inputtype">types derived from the algebra</link> it is
|
|
|
438 |
possible to use quoted C types in this context.</para>
|
|
|
439 |
|
|
|
440 |
<para>A map may be qualified by means of a hash. This means that the
|
|
|
441 |
associated function also takes a
|
|
|
442 |
<link linkend="outputunionmaps">destructor function</link> as a
|
|
|
443 |
parameter.</para>
|
|
|
444 |
</sect1>
|
|
|
445 |
|
|
|
446 |
<sect1 id="inputtype">
|
|
|
447 |
<title>Type constructors</title>
|
|
|
448 |
|
|
|
449 |
<para>The types derived from the algebra may be described as follows:
|
|
|
450 |
|
|
|
451 |
<programlisting>
|
|
|
452 |
type:
|
|
|
453 |
identifier
|
|
|
454 |
PTR type
|
|
|
455 |
LIST type
|
|
|
456 |
STACK type
|
|
|
457 |
VEC type
|
|
|
458 |
VEC_PTR type
|
|
|
459 |
</programlisting></para>
|
|
|
460 |
|
|
|
461 |
<para>The simple types correspond to primitive, identity, enumeration,
|
|
|
462 |
structure or union names. It is possible for a type to be used before
|
|
|
463 |
it is defined, but it must be defined at some point.</para>
|
|
|
464 |
|
|
|
465 |
<para>The derived type constructors correspond to pointers, lists,
|
|
|
466 |
stacks, vectors and pointers into vectors. They may be used to build
|
|
|
467 |
up further types from the basic algebra types.</para>
|
|
|
468 |
</sect1>
|
|
|
469 |
|
|
|
470 |
<sect1 id="module">
|
|
|
471 |
<title>Relations between algebras</title>
|
|
|
472 |
|
|
|
473 |
<para>As <link linkend="options">mentioned above</link>, more than one
|
|
|
474 |
input algebra may be specified to <command>calculus</command>. Each is
|
|
|
475 |
processed separately, and output is generated for only one. By default
|
|
|
476 |
this is the last algebra processed, however a specific algebra can be
|
|
|
477 |
specified using the command-line option <option>-A</option>
|
|
|
478 |
<option>name</option>, where <option>name</option> is the name of the
|
|
|
479 |
algebra to be used for output.</para>
|
|
|
480 |
|
|
|
481 |
<para>Types may be imported from one algebra to another by means of
|
|
|
482 |
commands of the form:
|
|
|
483 |
|
|
|
484 |
<programlisting>
|
|
|
485 |
import:
|
|
|
486 |
IMPORT identifier;
|
|
|
487 |
IMPORT identifier::identifier;
|
|
|
488 |
</programlisting>
|
|
|
489 |
|
|
|
490 |
which fit into the main syntax as an <literal>item</literal>. The
|
|
|
491 |
first form imports all the types from the algebra given by
|
|
|
492 |
<literal>identifier</literal> into the current algebra. The second
|
|
|
493 |
imports a single type, given by the second
|
|
|
494 |
<literal>identifier</literal> from the algebra given by the first
|
|
|
495 |
<literal>identifier</literal>.</para>
|
|
|
496 |
|
|
|
497 |
<para>Note that importing a type in this way also imports all the types
|
|
|
498 |
used in its construction. This includes such things as structure
|
|
|
499 |
components and union fields and maps. Thus an algebra consisting just
|
|
|
500 |
of <literal>import</literal> commands can be used to express
|
|
|
501 |
subalgebras in a simple fashion.</para>
|
|
|
502 |
</sect1>
|
|
|
503 |
</chapter>
|
|
|
504 |
|
|
|
505 |
<chapter id="tokenoutput">
|
|
|
506 |
<title>Output type system specification</title>
|
|
|
507 |
|
|
|
508 |
<para>In this section we document the basic output of
|
|
|
509 |
<command>calculus</command>. Two forms of the output can be generated -
|
|
|
510 |
a description of the output specification in terms of the TenDRA
|
|
|
511 |
<code>#pragma token</code> constructs, and the actual C code which
|
|
|
512 |
implements these tokens.</para>
|
|
|
513 |
|
|
|
514 |
<para>In this section the description given will be at the level of the
|
|
|
515 |
output specification. The more important details of the
|
|
|
516 |
<link linkend="coutput">C implementation</link> are given in the
|
|
|
517 |
following section.</para>
|
|
|
518 |
|
|
|
519 |
<para>The output is split among several header files in the specified
|
|
|
520 |
output directory. The main output is printed into
|
|
|
521 |
<filename>name.h</filename>, where <literal>name</literal> is the
|
|
|
522 |
overall algebra name. Unless otherwise stated, all the objects specified
|
|
|
523 |
below are to be found in <literal>name</literal><code>.h</code>. However
|
|
|
524 |
for each union, <literal>union</literal>, in the algebra certain
|
|
|
525 |
information associated with the union is printed into
|
|
|
526 |
<literal>union</literal><code>_ops.h</code>. If the union has any maps
|
|
|
527 |
associated with it then further output is printed to
|
|
|
528 |
<filename>union_map.h</filename> and <filename>union_hdr.h</filename>.
|
|
|
529 |
</para>
|
|
|
530 |
|
|
|
531 |
<sect1 id="outputinfo">
|
|
|
532 |
<title>Version information</title>
|
|
|
533 |
|
|
|
534 |
<para>Certain basic information about the input algebra is included in
|
|
|
535 |
<literal>name</literal><code>.h</code>. <literal>name</literal>
|
|
|
536 |
<code>_NAME</code> is a string literal giving the overall algebra
|
|
|
537 |
name. <literal>name</literal><code>_VERSION</code> is a string
|
|
|
538 |
literal giving the algebra version number.
|
|
|
539 |
<literal>name</literal><code>_SPECIFICATION</code> and
|
|
|
540 |
<literal>name</literal><code>_IMPLEMENTATION</code> are flags which
|
|
|
541 |
take the values 0 or 1 depending on whether the specification of the
|
|
|
542 |
type system in terms of <code>#pragma token</code> statements or the C
|
|
|
543 |
implementation is included.</para>
|
|
|
544 |
</sect1>
|
|
|
545 |
|
|
|
546 |
<sect1 id="outputbasic">
|
|
|
547 |
<title>Basic types</title>
|
|
|
548 |
|
|
|
549 |
<para>Six abstract type operators, each taking a type as argument and
|
|
|
550 |
returning a type, are specified as follows:
|
|
|
551 |
|
|
|
552 |
<programlisting>
|
|
|
553 |
TYPE PTR(TYPE t);
|
|
|
554 |
TYPE LIST(TYPE t);
|
|
|
555 |
TYPE STACK(TYPE t);
|
|
|
556 |
TYPE VEC(TYPE t);
|
|
|
557 |
TYPE VEC_PTR(TYPE t);
|
|
|
558 |
TYPE SIZE(TYPE t);
|
|
|
559 |
</programlisting></para>
|
|
|
560 |
|
|
|
561 |
<para>These represent a pointer to an object of type
|
|
|
562 |
<literal>t</literal>, a list of objects of type <literal>t</literal>,
|
|
|
563 |
a stack of objects of type <literal>t</literal>, a vector of objects
|
|
|
564 |
of type <literal>t</literal>, a pointer into a vector of objects of
|
|
|
565 |
type <literal>t</literal>, and an allocation block size for type
|
|
|
566 |
<literal>t</literal> respectively. (It is possible to suppress all
|
|
|
567 |
constructs involving <code>VEC</code> or <code>VEC_PTR</code> by
|
|
|
568 |
passing the <code>-x</code> command-line option to
|
|
|
569 |
<command>calculus</command>. Similarly <code>STACK</code> constructs
|
|
|
570 |
may be suppressed using <code>-z</code>.)</para>
|
|
|
571 |
|
|
|
572 |
<para>These constructors can be applied to any type, although in
|
|
|
573 |
practice they are only applied to the types specified in the algebra
|
|
|
574 |
and those derived from them. For example, we may form the type:
|
|
|
575 |
|
|
|
576 |
<programlisting>
|
|
|
577 |
LIST(PTR(int))
|
|
|
578 |
</programlisting>
|
|
|
579 |
|
|
|
580 |
representing a list of pointers to <code>int</code>.</para>
|
|
|
581 |
|
|
|
582 |
<para>An integral type:
|
|
|
583 |
|
|
|
584 |
<programlisting>
|
|
|
585 |
INT_TYPE name_dim;
|
|
|
586 |
</programlisting>
|
|
|
587 |
|
|
|
588 |
is specified, where <literal>name</literal> is the overall algebra
|
|
|
589 |
name. This type is used to represent the sizes of vectors.</para>
|
|
|
590 |
|
|
|
591 |
<para>A function pointer type:
|
|
|
592 |
|
|
|
593 |
<programlisting>
|
|
|
594 |
typedef void (*DESTROYER)();
|
|
|
595 |
</programlisting>
|
|
|
596 |
|
|
|
597 |
is specified, which represents a destructor function. Two destructor
|
|
|
598 |
functions are specified:
|
|
|
599 |
|
|
|
600 |
<programlisting>
|
|
|
601 |
void destroy_name();
|
|
|
602 |
void dummy_destroy_name();
|
|
|
603 |
</programlisting>
|
|
|
604 |
|
|
|
605 |
where <literal>name</literal> is as above.
|
|
|
606 |
<code>destroy_</code><literal>name</literal> is the default
|
|
|
607 |
destructor, whereas <code>dummy_destroy_</code><literal>name</literal>
|
|
|
608 |
is a dummy destructor which has no effect. The details of the
|
|
|
609 |
arguments passed to the destructors and so on are implementation
|
|
|
610 |
dependent.</para>
|
|
|
611 |
</sect1>
|
|
|
612 |
|
|
|
613 |
<sect1 id="outputsize">
|
|
|
614 |
<title>Operations on sizes</title>
|
|
|
615 |
|
|
|
616 |
<para>The <code>SIZE</code> type constructor is used to represent a
|
|
|
617 |
multiple of the size of a type. It is used, for example, in the
|
|
|
618 |
<link linkend="outputptr">pointer stepping construct</link>
|
|
|
619 |
<code>STEP_ptr</code> to specify the number of units the pointer is to
|
|
|
620 |
be increased by. Having a separate abstract type for the size of each
|
|
|
621 |
type greatly increases the scope for type checking of memory
|
|
|
622 |
allocation, and other, functions.</para>
|
|
|
623 |
|
|
|
624 |
<para>For each basic type in the algebra (a primitive, a structure or a
|
|
|
625 |
union), there is a constant expression:
|
|
|
626 |
|
|
|
627 |
<programlisting>
|
|
|
628 |
SIZE ( t ) SIZE_type;
|
|
|
629 |
</programlisting>
|
|
|
630 |
|
|
|
631 |
where <literal>t</literal> denotes the type itself, and
|
|
|
632 |
<literal>type</literal> is the associated type name.</para>
|
|
|
633 |
|
|
|
634 |
<para>For the five other type constructors
|
|
|
635 |
<link linkend="outputbasic">described above</link> there are constant
|
|
|
636 |
expressions:
|
|
|
637 |
|
|
|
638 |
<programlisting>
|
|
|
639 |
SIZE(PTR(t)) SIZE_ptr(TYPE t);
|
|
|
640 |
SIZE(LIST(t)) SIZE_list(TYPE t);
|
|
|
641 |
SIZE(STACK(t)) SIZE_stack(TYPE t);
|
|
|
642 |
SIZE(VEC(t)) SIZE_vec(TYPE t);
|
|
|
643 |
SIZE(VEC_PTR(t)) SIZE_vec_ptr(TYPE t);
|
|
|
644 |
</programlisting>
|
|
|
645 |
|
|
|
646 |
for any type <literal>t</literal>.</para>
|
|
|
647 |
|
|
|
648 |
<para>These constructs allow the size of any type derived from the
|
|
|
649 |
algebra to be built up. There is also a construct which corresponds to
|
|
|
650 |
multiplying the size of a type by a constant. This takes the
|
|
|
651 |
form:
|
|
|
652 |
|
|
|
653 |
<programlisting>
|
|
|
654 |
SIZE(t) SCALE(SIZE(t), INT_TYPE itype);
|
|
|
655 |
</programlisting>
|
|
|
656 |
|
|
|
657 |
for any type <literal>t</literal> and any integral type
|
|
|
658 |
<literal>itype</literal>.</para>
|
|
|
659 |
</sect1>
|
|
|
660 |
|
|
|
661 |
<sect1 id="outputptr">
|
|
|
662 |
<title>Operations on pointers</title>
|
|
|
663 |
|
|
|
664 |
<para>The <code>PTR</code> type constructor is used to represent a
|
|
|
665 |
pointer to an object of type <literal>t</literal>. It should be
|
|
|
666 |
emphasised that this construct is not in general implemented by means
|
|
|
667 |
of the C pointer construct.</para>
|
|
|
668 |
|
|
|
669 |
<sect2 id="simple-pointer-constructs">
|
|
|
670 |
<title>Simple pointer constructs</title>
|
|
|
671 |
|
|
|
672 |
<para>There are several simple operations on pointers, given as
|
|
|
673 |
follows:
|
|
|
674 |
|
|
|
675 |
<programlisting>
|
|
|
676 |
PTR(t) NULL_ptr(TYPE t);
|
|
|
677 |
int IS_NULL_ptr(PTR (t));
|
|
|
678 |
int EQ_ptr(PTR(t), PTR(t));
|
|
|
679 |
PTR(t) STEP_ptr(PTR(t), SIZE(t));
|
|
|
680 |
</programlisting></para>
|
|
|
681 |
|
|
|
682 |
<para>The construct <code>NULL_ptr</code> is used to form the null
|
|
|
683 |
pointer to <literal>t</literal> for a type <literal>t</literal>.
|
|
|
684 |
This is a constant expression. <code>IS_NULL_ptr</code> can be used
|
|
|
685 |
to test whether a given pointer expression is a null pointer.
|
|
|
686 |
Similarly <code>EQ_ptr</code> checks whether two pointers are equal
|
|
|
687 |
(note that we can only compare pointers to the same type). Finally
|
|
|
688 |
<code>STEP_ptr</code> can be used to add a scalar value to a
|
|
|
689 |
pointer.</para>
|
|
|
690 |
</sect2>
|
|
|
691 |
|
|
|
692 |
<sect2 id="unique-pointers">
|
|
|
693 |
<title>Unique pointers</title>
|
|
|
694 |
|
|
|
695 |
<para>There are also constructs for generating and destroying unique
|
|
|
696 |
pointers:
|
|
|
697 |
|
|
|
698 |
<programlisting>
|
|
|
699 |
PTR(t) UNIQ_ptr(TYPE t);
|
|
|
700 |
void DESTROY_UNIQ_ptr(PTR(t));
|
|
|
701 |
</programlisting></para>
|
|
|
702 |
|
|
|
703 |
<para>A unique pointer is guaranteed to be different from all other
|
|
|
704 |
undestroyed pointers. Dereferencing a unique pointer is
|
|
|
705 |
undefined.</para>
|
|
|
706 |
</sect2>
|
|
|
707 |
|
|
|
708 |
<sect2 id="pointer-construction-destruction">
|
|
|
709 |
<title>Pointer construction and destruction</title>
|
|
|
710 |
|
|
|
711 |
<para>The constructs:
|
|
|
712 |
|
|
|
713 |
<programlisting>
|
|
|
714 |
PTR(t) MAKE_ptr(SIZE(t));
|
|
|
715 |
void DESTROY_ptr(PTR(t), SIZE(t));
|
|
|
716 |
</programlisting>
|
|
|
717 |
|
|
|
718 |
are used to respectively create and destroy a pointer to a given
|
|
|
719 |
type.</para>
|
|
|
720 |
</sect2>
|
|
|
721 |
|
|
|
722 |
<sect2 id="construct-assignment-dereference">
|
|
|
723 |
<title>Assignment and dereference constructs</title>
|
|
|
724 |
|
|
|
725 |
<para>The constructs for assigning and dereferencing pointers have one
|
|
|
726 |
of two forms depending on the complexity of the type pointed to. For
|
|
|
727 |
simple types, including primitive, enumeration and union types, they
|
|
|
728 |
have the form:
|
|
|
729 |
|
|
|
730 |
<programlisting>
|
|
|
731 |
void COPY_type(PTR(t), t);
|
|
|
732 |
t DEREF_type(PTR(t));
|
|
|
733 |
</programlisting>
|
|
|
734 |
|
|
|
735 |
where <literal>t</literal> is the type involved and
|
|
|
736 |
<literal>type</literal> is the associated short name.</para>
|
|
|
737 |
|
|
|
738 |
<para>For more complex types, including structures, the assignment or
|
|
|
739 |
dereference cannot be done in a single expression, so the constructs
|
|
|
740 |
are specified to be statements as follows:
|
|
|
741 |
|
|
|
742 |
<programlisting>
|
|
|
743 |
STATEMENT COPY_type(PTR(t), t);
|
|
|
744 |
STATEMENT DEREF_type(PTR(t), lvalue t);
|
|
|
745 |
</programlisting></para>
|
|
|
746 |
|
|
|
747 |
<para>Here the <code>lvalue</code> type qualifier is used to indicate
|
|
|
748 |
that the statement argument is an assignable <code>lvalue</code>. In
|
|
|
749 |
this case it should give the location of an object of type
|
|
|
750 |
<literal>t</literal> into which the pointer will be
|
|
|
751 |
dereferenced.</para>
|
|
|
752 |
|
|
|
753 |
<para>The appropriate assignment and dereference constructs are
|
|
|
754 |
generated for each of the basic algebra types (primitives,
|
|
|
755 |
enumerations, structures and unions). In addition there are generic
|
|
|
756 |
assignment and dereference constructs for pointer types, list types,
|
|
|
757 |
stack types, vector types and vector pointer types. The first three
|
|
|
758 |
are of the first form above, whereas the second two have the second
|
|
|
759 |
form, as follows:
|
|
|
760 |
|
|
|
761 |
<programlisting>
|
|
|
762 |
void COPY_ptr(PTR(PTR(t)), PTR(t));
|
|
|
763 |
PTR(t) DEREF_ptr(PTR (PTR (t)));
|
|
|
764 |
void COPY_list(PTR(LIST(t)), LIST(t));
|
|
|
765 |
LIST(t) DEREF_list(PTR(LIST(t)));
|
|
|
766 |
void COPY_stack(PTR(STACK(t)), STACK(t));
|
|
|
767 |
STACK(t) DEREF_stack(PTR(STACK(t)));
|
|
|
768 |
STATEMENT COPY_vec(PTR(VEC(t)), VEC(t));
|
|
|
769 |
STATEMENT DEREF_vec(PTR(VEC(t)), lvalue VEC(t));
|
|
|
770 |
STATEMENT COPY_vec_ptr(PTR(VEC_PTR(t)), VEC_PTR(t));
|
|
|
771 |
STATEMENT DEREF_vec_ptr(PTR(VEC_PTR(t)), lvalue VEC_PTR(t));
|
|
|
772 |
</programlisting></para>
|
|
|
773 |
</sect2>
|
|
|
774 |
</sect1>
|
|
|
775 |
|
|
|
776 |
<sect1 id="outputlist">
|
|
|
777 |
<title>Operations on lists</title>
|
|
|
778 |
|
|
|
779 |
<para>The <code>LIST</code> type constructor is used to represent a list
|
|
|
780 |
of objects of type <literal>t</literal>.</para>
|
|
|
781 |
|
|
|
782 |
<sect2 id="simple-list-constructs">
|
|
|
783 |
<title>Simple list constructs</title>
|
|
|
784 |
|
|
|
785 |
<para>There are several simple list constructs:
|
|
|
786 |
|
|
|
787 |
<programlisting>
|
|
|
788 |
LIST(t) NULL_list(TYPE t);
|
|
|
789 |
int IS_NULL_list(LIST(t));
|
|
|
790 |
int EQ_list(LIST(t), LIST(t));
|
|
|
791 |
unsigned LENGTH_list(LIST(t));
|
|
|
792 |
PTR(t) HEAD_list(LIST(t));
|
|
|
793 |
LIST(t) TAIL_list(LIST(t));
|
|
|
794 |
PTR(LIST(t)) PTR_TAIL_list(LIST(t));
|
|
|
795 |
LIST(t) END_list(LIST(t));
|
|
|
796 |
LIST(t) REVERSE_list(LIST(t));
|
|
|
797 |
LIST(t) APPEND_list(LST(t), LIST(t));
|
|
|
798 |
</programlisting></para>
|
|
|
799 |
|
|
|
800 |
<para>Empty lists may be constructed or tested for.
|
|
|
801 |
<code>NULL_list</code> is a constant expression. Two lists may be
|
|
|
802 |
checked for equality (note that this is equality of lists, rather
|
|
|
803 |
than element-wise equality). The number of elements in a list can
|
|
|
804 |
be found. The head or tail (or <code>car</code> and
|
|
|
805 |
<code>cdr</code>) of a list may be formed. The end element of a list
|
|
|
806 |
may be selected. The order of the elements in a list can be
|
|
|
807 |
reversed. One list can be appended to another.</para>
|
|
|
808 |
</sect2>
|
|
|
809 |
|
|
|
810 |
<sect2 id="unique-lists">
|
|
|
811 |
<title>Unique lists</title>
|
|
|
812 |
|
|
|
813 |
<para>There are also constructs for generating and destroying unique
|
|
|
814 |
lists:
|
|
|
815 |
|
|
|
816 |
<programlisting>
|
|
|
817 |
LIST(t) UNIQ_list(TYPE t);
|
|
|
818 |
void DESTROY_UNIQ_list(LIST(t));
|
|
|
819 |
</programlisting></para>
|
|
|
820 |
|
|
|
821 |
<para>A unique lists is guaranteed to be different from all other
|
|
|
822 |
undestroyed lists. Taking the head or tail of a unique list is
|
|
|
823 |
undefined.</para>
|
|
|
824 |
</sect2>
|
|
|
825 |
|
|
|
826 |
<sect2 id="list-construction-destruction">
|
|
|
827 |
<title>List construction and destruction</title>
|
|
|
828 |
|
|
|
829 |
<para>For each type <literal>t</literal> there are operations for
|
|
|
830 |
constructing and deconstructing lists. For the basic types
|
|
|
831 |
comprising the algebra these take the form:
|
|
|
832 |
|
|
|
833 |
<programlisting>
|
|
|
834 |
STATEMENT CONS_type(t, LIST(t), lvalue LIST(t));
|
|
|
835 |
STATEMENT UN_CONS_type(lvalue t, lvalue LIST(t), LIST(t)) ;
|
|
|
836 |
STATEMENT DESTROY_CONS_type(DESTROYER, lvalue t, lvalue LIST(t), LIST(t));
|
|
|
837 |
</programlisting>
|
|
|
838 |
|
|
|
839 |
where <literal>type</literal> is the short type name.</para>
|
|
|
840 |
|
|
|
841 |
<para>The operation <code>CONS_</code><literal>type</literal> is used
|
|
|
842 |
to build a list whose head is the first argument and whose tail is
|
|
|
843 |
the second argument. This is assigned to the third argument.
|
|
|
844 |
<code>UN_CONS_</code><literal>type</literal> reverses this process,
|
|
|
845 |
decomposing a list into its head and its tail.
|
|
|
846 |
<code>DESTROY_CONS_</code><literal>type</literal> is similar, but it
|
|
|
847 |
also applies the given destructor function to the decomposed list
|
|
|
848 |
component.</para>
|
|
|
849 |
|
|
|
850 |
<para>There are also generic list construction and deconstruction
|
|
|
851 |
operations which apply to lists of pointers (with a <code>ptr</code>
|
|
|
852 |
suffix), lists of lists (with a <code>list</code> suffix), lists of
|
|
|
853 |
stacks (with a <code>stack</code> suffix), lists of vectors (with a
|
|
|
854 |
<code>vec</code> suffix) and lists of pointers to vectors (with a
|
|
|
855 |
<code>vec_ptr</code> suffix). For example, for lists of pointers
|
|
|
856 |
these have the form:
|
|
|
857 |
|
|
|
858 |
<programlisting>
|
|
|
859 |
STATEMENT CONS_ptr(PTR(t), LIST(PTR(t)), lvalue LIST(PTR(t))) ;
|
|
|
860 |
STATEMENT UN_CONS_ptr(lvalue PTR(t), lvalue LIST(PTR(t)), LIST(PTR(t)));
|
|
|
861 |
STATEMENT DESTROY_CONS_ptr(DESTROYER, lvalue PTR(t), lvalue LIST(PTR(t)), LIST(PTR(t)));
|
|
|
862 |
</programlisting></para>
|
|
|
863 |
|
|
|
864 |
<para>There is also a generic list destruction construct:
|
|
|
865 |
|
|
|
866 |
<programlisting>
|
|
|
867 |
STATEMENT DESTROY_list(LIST(t), SIZE(t));
|
|
|
868 |
</programlisting>
|
|
|
869 |
|
|
|
870 |
which may be used to destroy all the elements in a list.</para>
|
|
|
871 |
</sect2>
|
|
|
872 |
</sect1>
|
|
|
873 |
|
|
|
874 |
<sect1 id="outputstack">
|
|
|
875 |
<title>Operations on stacks</title>
|
|
|
876 |
|
|
|
877 |
<para>The <code>STACK</code> type constructor is used to represent
|
|
|
878 |
stacks of objects of type <literal>t</literal>. Empty stacks can be
|
|
|
879 |
created and tested for:
|
|
|
880 |
|
|
|
881 |
<programlisting>
|
|
|
882 |
STACK(t) NULL_stack(TYPE t);
|
|
|
883 |
int IS_NULL_stack(STACK(t));
|
|
|
884 |
</programlisting></para>
|
|
|
885 |
|
|
|
886 |
<para>For each type <literal>t</literal> there are operations for
|
|
|
887 |
pushing objects onto a stack and for popping elements off. For the
|
|
|
888 |
basic types comprising the algebra these take the form:
|
|
|
889 |
|
|
|
890 |
<programlisting>
|
|
|
891 |
STATEMENT PUSH_type(t, lvalue STACK(t));
|
|
|
892 |
STATEMENT POP_type(lvalue t, lvalue STACK(t));
|
|
|
893 |
</programlisting>
|
|
|
894 |
|
|
|
895 |
where <literal>type</literal> is the short type name. There are also
|
|
|
896 |
generic constructs, such as <code>PUSH_ptr</code> for pushing any
|
|
|
897 |
pointer type, similar to the
|
|
|
898 |
<link linkend="outputlist">generic list constructors</link>
|
|
|
899 |
above.</para>
|
|
|
900 |
|
|
|
901 |
<para>Stacks are in fact just modified lists with pushing corresponding
|
|
|
902 |
adding an element to the start of a list, and popping to removing the
|
|
|
903 |
first element. There are constructs:
|
|
|
904 |
|
|
|
905 |
<programlisting>
|
|
|
906 |
LIST(t) LIST_stack(STACK(t));
|
|
|
907 |
STACK(t) STACK_list(LIST(t));
|
|
|
908 |
</programlisting>
|
|
|
909 |
|
|
|
910 |
for explicitly converting between lists and stacks.</para>
|
|
|
911 |
</sect1>
|
|
|
912 |
|
|
|
913 |
<sect1 id="outputvec">
|
|
|
914 |
<title>Operations on vectors</title>
|
|
|
915 |
|
|
|
916 |
<para>The <code>VEC</code> type constructor is used to represent vectors
|
|
|
917 |
of objects of type <literal>t</literal>. There are a number of simple
|
|
|
918 |
operations on vectors:
|
|
|
919 |
|
|
|
920 |
<programlisting>
|
|
|
921 |
VEC(t) NULL_vec(TYPE t);
|
|
|
922 |
name_dim DIM_vec(VEC(t));
|
|
|
923 |
name_dim DIM_ptr_vec(PTR(VEC(t)));
|
|
|
924 |
PTR(t) PTR_ptr_vec(PTR(VEC(t)));
|
|
|
925 |
</programlisting></para>
|
|
|
926 |
|
|
|
927 |
<para>An empty vector can be constructed (note that, unlike null
|
|
|
928 |
pointers and null lists, this is not a constant expression). The
|
|
|
929 |
number of elements in a vector (or in a vector given by a pointer) can
|
|
|
930 |
be determined (note how the type
|
|
|
931 |
<literal>name</literal><code>_dim</code> is used to represent vector
|
|
|
932 |
sizes). A pointer to a vector can be transformed into a pointer to the
|
|
|
933 |
elements of the vector.</para>
|
|
|
934 |
|
|
|
935 |
<para>In general a vector may be created or destroyed using the
|
|
|
936 |
operators:
|
|
|
937 |
|
|
|
938 |
<programlisting>
|
|
|
939 |
STATEMENT MAKE_vec(SIZE(t), name_dim, lvalue VEC(t));
|
|
|
940 |
STATEMENT DESTROY_vec(VEC(t), SIZE(t));
|
|
|
941 |
</programlisting></para>
|
|
|
942 |
|
|
|
943 |
<para>Finally a vector can be trimmed using:
|
|
|
944 |
|
|
|
945 |
<programlisting>
|
|
|
946 |
STATEMENT TRIM_vec(VEC(t), SIZE(t), int, int, lvalue VEC(t));
|
|
|
947 |
</programlisting>
|
|
|
948 |
|
|
|
949 |
the two integral arguments giving the lower and upper bounds for the
|
|
|
950 |
trimming operation.</para>
|
|
|
951 |
</sect1>
|
|
|
952 |
|
|
|
953 |
<sect1 id="outputvecptr">
|
|
|
954 |
<title>Operations on vector pointers</title>
|
|
|
955 |
|
|
|
956 |
<para>The <code>VEC_PTR</code> type constructor is used to represent a
|
|
|
957 |
pointer to an element of a vector of objects of type
|
|
|
958 |
<literal>t</literal>. Apart from the basic constructors already
|
|
|
959 |
mentioned, there are only two operations on vector pointers:
|
|
|
960 |
|
|
|
961 |
<programlisting>
|
|
|
962 |
VEC_PTR(t) VEC_PTR_vec(VEC(t));
|
|
|
963 |
PTR(t) PTR_vec_ptr(VEC_PTR(t));
|
|
|
964 |
</programlisting></para>
|
|
|
965 |
|
|
|
966 |
<para>The first transforms a vector into a vector pointer (pointing to
|
|
|
967 |
its first argument). The second transforms a vector pointer into a
|
|
|
968 |
normal pointer.</para>
|
|
|
969 |
</sect1>
|
|
|
970 |
|
|
|
971 |
<sect1 id="outputprim">
|
|
|
972 |
<title>Operations on primitives</title>
|
|
|
973 |
|
|
|
974 |
<para>Each primitive specified within the algebra maps onto a
|
|
|
975 |
<code>typedef</code> defining the type in terms of its given
|
|
|
976 |
definition. The only operations on primitives are those listed above
|
|
|
977 |
- the size constructs, the pointer assignment and dereference
|
|
|
978 |
operations, the list construction and deconstruction operations and
|
|
|
979 |
the stack push and pop operations.</para>
|
|
|
980 |
</sect1>
|
|
|
981 |
|
|
|
982 |
<sect1 id="outputident">
|
|
|
983 |
<title>Operations on identities</title>
|
|
|
984 |
|
|
|
985 |
<para>Each identity specified within the algebra maps onto a
|
|
|
986 |
<code>typedef</code> in the output file. There are no operations on
|
|
|
987 |
identities.</para>
|
|
|
988 |
</sect1>
|
|
|
989 |
|
|
|
990 |
<sect1 id="outputenum">
|
|
|
991 |
<title>Operations on enumerations</title>
|
|
|
992 |
|
|
|
993 |
<para>Each enumeration specified within the algebra maps onto an
|
|
|
994 |
unsigned integral type in the output file. The
|
|
|
995 |
<link linkend="outputprim">basic operations</link>
|
|
|
996 |
listed above are always generated unless it has been indicated that
|
|
|
997 |
<link linkend="inputenum">no lists of this type will be formed</link>,
|
|
|
998 |
when <code>CONS_</code><literal>type</literal> and the other list and
|
|
|
999 |
stack operators are suppressed. In addition each enumerator which is a
|
|
|
1000 |
member of this enumeration maps onto a constant expression:
|
|
|
1001 |
|
|
|
1002 |
<programlisting>
|
|
|
1003 |
t enum_member;
|
|
|
1004 |
</programlisting>
|
|
|
1005 |
|
|
|
1006 |
where <literal>t</literal> is the enumeration type,
|
|
|
1007 |
<literal>enum</literal> is the short type name, and
|
|
|
1008 |
<literal>member</literal> is the enumerator name. It is guaranteed
|
|
|
1009 |
that the first enumerator will have value 0, the second 1, and so on,
|
|
|
1010 |
unless the value of the enumerator is explicitly given (as in C).
|
|
|
1011 |
There is also a constant expression:
|
|
|
1012 |
|
|
|
1013 |
<programlisting>
|
|
|
1014 |
unsigned long ORDER_enum;
|
|
|
1015 |
</programlisting>
|
|
|
1016 |
|
|
|
1017 |
giving one more than the maximum enumerator in the enumeration.</para>
|
|
|
1018 |
</sect1>
|
|
|
1019 |
|
|
|
1020 |
<sect1 id="outputstruct">
|
|
|
1021 |
<title>Operations on structures</title>
|
|
|
1022 |
|
|
|
1023 |
<para>Each structure specified within the algebra maps onto a
|
|
|
1024 |
<code>typedef</code> defining the type to be the C structure with the
|
|
|
1025 |
given components. In addition to the
|
|
|
1026 |
<link linkend="outputprim">basic operations</link>
|
|
|
1027 |
listed above there are also field selectors defined.</para>
|
|
|
1028 |
|
|
|
1029 |
<para>Suppose that <literal>t</literal> is a structure type with short
|
|
|
1030 |
name <literal>struct</literal>, and that <literal>comp</literal> is a
|
|
|
1031 |
component of <literal>t</literal> of type <literal>ctype</literal>.
|
|
|
1032 |
Then there is an operation:
|
|
|
1033 |
|
|
|
1034 |
<programlisting>
|
|
|
1035 |
PTR(ctype) struct_comp(PTR(t));
|
|
|
1036 |
</programlisting>
|
|
|
1037 |
|
|
|
1038 |
which transforms a pointer to the structure into a pointer to the
|
|
|
1039 |
component. There is also an operation:
|
|
|
1040 |
|
|
|
1041 |
<programlisting>
|
|
|
1042 |
STATEMENT MAKE_struct(ctype, ...., PTR(t));
|
|
|
1043 |
</programlisting>
|
|
|
1044 |
|
|
|
1045 |
where <literal>ctype</literal> ranges over all the component types
|
|
|
1046 |
which do not have a component initialiser string in the structure
|
|
|
1047 |
definition. This is used to assign values to all the components of a
|
|
|
1048 |
structure. If a component has an initialiser string then this is used
|
|
|
1049 |
as an expression giving the initial value, otherwise the given
|
|
|
1050 |
operation argument is used. The initialiser strings are evaluated in
|
|
|
1051 |
the context of the <code>MAKE_</code><literal>struct</literal>
|
|
|
1052 |
statement. The parameters to the operation may be referred to by the
|
|
|
1053 |
corresponding component name followed by <code>_</code>. The partially
|
|
|
1054 |
initialised object may be referred to by the special character
|
|
|
1055 |
sequence <code>%0</code>. Any remainder operations should be written
|
|
|
1056 |
as <code>%%</code> rather than <code>%</code>.</para>
|
|
|
1057 |
|
|
|
1058 |
<para>Inheritance in structures is handled as follows: if
|
|
|
1059 |
<literal>t</literal> is a derived structure with base structure
|
|
|
1060 |
<literal>btype</literal> then there is an operation:
|
|
|
1061 |
|
|
|
1062 |
<programlisting>
|
|
|
1063 |
PTR(btype) CONVERT_struct_base(PTR(t));
|
|
|
1064 |
</programlisting>
|
|
|
1065 |
|
|
|
1066 |
where <literal>struct</literal> and <literal>base</literal> are the
|
|
|
1067 |
short names of <literal>t</literal> and <literal>btype</literal>
|
|
|
1068 |
respectively.</para>
|
|
|
1069 |
</sect1>
|
|
|
1070 |
|
|
|
1071 |
<sect1 id="outputunion">
|
|
|
1072 |
<title>Operations on unions</title>
|
|
|
1073 |
|
|
|
1074 |
<para>Each union specified within the algebra maps onto an opaque type
|
|
|
1075 |
in the output file. In addition to the
|
|
|
1076 |
<link linkend="outputprim">basic operations</link> listed above there
|
|
|
1077 |
are a number of other constructs output into
|
|
|
1078 |
<literal>name</literal><code>.h</code>, namely:
|
|
|
1079 |
|
|
|
1080 |
<programlisting>
|
|
|
1081 |
unsigned int ORDER_union;
|
|
|
1082 |
t NULL_union;
|
|
|
1083 |
int IS_NULL_union(t);
|
|
|
1084 |
int EQ_union(t, t);
|
|
|
1085 |
</programlisting>
|
|
|
1086 |
|
|
|
1087 |
where <literal>t</literal> denotes the union type, and
|
|
|
1088 |
<literal>union</literal> is the short type name.
|
|
|
1089 |
<code>ORDER_</code><literal>union</literal> is a constant value giving
|
|
|
1090 |
the number of union fields.
|
|
|
1091 |
<code>NULL_</code><literal>union</literal> is a distinguished constant
|
|
|
1092 |
value of type <literal>t</literal>. Values of type
|
|
|
1093 |
<literal>t</literal> may be compared against this distinguished value,
|
|
|
1094 |
or against each other.</para>
|
|
|
1095 |
|
|
|
1096 |
<sect2 id="union-construction-operations">
|
|
|
1097 |
<title>Union construction operations</title>
|
|
|
1098 |
|
|
|
1099 |
<para>Most of the output for the union type <literal>t</literal> is
|
|
|
1100 |
output into the file <filename>union_ops.h</filename>. This contains
|
|
|
1101 |
a construct:
|
|
|
1102 |
|
|
|
1103 |
<programlisting>
|
|
|
1104 |
unsigned int TAG_union(t);
|
|
|
1105 |
</programlisting>
|
|
|
1106 |
|
|
|
1107 |
for extracting the discriminant tag from a union.</para>
|
|
|
1108 |
|
|
|
1109 |
<para>For each shared component, <literal>comp</literal>, of
|
|
|
1110 |
<literal>t</literal> of type <literal>ctype</literal>, say, there is
|
|
|
1111 |
an operator:
|
|
|
1112 |
|
|
|
1113 |
<programlisting>
|
|
|
1114 |
PTR(ctype) union_comp(t);
|
|
|
1115 |
</programlisting>
|
|
|
1116 |
|
|
|
1117 |
which extracts this component from the union.</para>
|
|
|
1118 |
|
|
|
1119 |
<para>For each field, <literal>field</literal>, of the union there are
|
|
|
1120 |
constructs:
|
|
|
1121 |
|
|
|
1122 |
<programlisting>
|
|
|
1123 |
unsigned int union_field_tag;
|
|
|
1124 |
int IS_union_field(t);
|
|
|
1125 |
</programlisting>
|
|
|
1126 |
|
|
|
1127 |
giving the (constant) discriminant tag associated with this field,
|
|
|
1128 |
and a test for whether an object of type <literal>t</literal> has
|
|
|
1129 |
this discriminant.</para>
|
|
|
1130 |
|
|
|
1131 |
<para>In addition, for each unshared component,
|
|
|
1132 |
<literal>comp</literal>, of <literal>field</literal> of type
|
|
|
1133 |
<literal>ctype</literal>, say, there is an operator:
|
|
|
1134 |
|
|
|
1135 |
<programlisting>
|
|
|
1136 |
PTR(ctype) union_field_comp(t);
|
|
|
1137 |
</programlisting>
|
|
|
1138 |
|
|
|
1139 |
which extracts this component from the union.</para>
|
|
|
1140 |
|
|
|
1141 |
<para>There are also operations for constructing and deconstructing
|
|
|
1142 |
objects of type <literal>t</literal> for field
|
|
|
1143 |
<literal>field</literal> given as follows:
|
|
|
1144 |
|
|
|
1145 |
<programlisting>
|
|
|
1146 |
STATEMENT MAKE_union_field(ctype, ...., lvalue t);
|
|
|
1147 |
STATEMENT DECONS_union_field(lvalue ctype, ...., t);
|
|
|
1148 |
STATEMENT DESTROY_union_field(DESTROYER, lvalue ctype, ...., t);
|
|
|
1149 |
</programlisting>
|
|
|
1150 |
|
|
|
1151 |
The operation <code>MAKE_</code><literal>union_field</literal>
|
|
|
1152 |
constructs a value of type <literal>t</literal> from the various
|
|
|
1153 |
components and assigns it into the last argument. The
|
|
|
1154 |
<literal>ctype</literal> arguments range over all the components of
|
|
|
1155 |
<literal>field</literal>, both the shared components and the
|
|
|
1156 |
unshared components, which do not have a component initialiser
|
|
|
1157 |
string in the definition. The union component are initialised either
|
|
|
1158 |
using the <link linkend="outputstruct">initialiser string</link> or
|
|
|
1159 |
the given operation argument.</para>
|
|
|
1160 |
|
|
|
1161 |
<para><code>DECONS_</code><literal>union_field</literal> performs the
|
|
|
1162 |
opposite operation, deconstructing an object of type
|
|
|
1163 |
<literal>t</literal> into its components for this field.
|
|
|
1164 |
<code>DESTROY_</code><literal>union_field</literal> is similar,
|
|
|
1165 |
except that it also applies the given destructor function to the
|
|
|
1166 |
original value. For these two operations <literal>ctype</literal>
|
|
|
1167 |
ranges over all the components, including those with
|
|
|
1168 |
initialiser strings.</para>
|
|
|
1169 |
</sect2>
|
|
|
1170 |
|
|
|
1171 |
<sect2 id="union-field-sets">
|
|
|
1172 |
<title>Union field sets</title>
|
|
|
1173 |
|
|
|
1174 |
<para>Recall that
|
|
|
1175 |
<link linkend="inputunion">a number of union field identifiers</link>
|
|
|
1176 |
may be associated with the same set of components. In this case
|
|
|
1177 |
these fields form a union field set named after the first element of
|
|
|
1178 |
the set. There are operations:
|
|
|
1179 |
|
|
|
1180 |
<programlisting>
|
|
|
1181 |
int IS_union_field_etc(t);
|
|
|
1182 |
PTR(ctype) union_field_etc_comp(t);
|
|
|
1183 |
STATEMENT MAKE_union_field_etc(unsigned int, ctype, ...., lvalue t);
|
|
|
1184 |
STATEMENT MODIFY_union_field_etc(unsigned int, t);
|
|
|
1185 |
STATEMENT DECONS_union_field_etc(lvalue ctype, ...., t);
|
|
|
1186 |
STATEMENT DESTROY_union_field_etc(DESTROYER, lvalue ctype, ...., t);
|
|
|
1187 |
</programlisting>
|
|
|
1188 |
|
|
|
1189 |
defined on these sets. These are exactly analogous to the single
|
|
|
1190 |
field operations except that they work for any field in the set.
|
|
|
1191 |
Note that
|
|
|
1192 |
<code>MAKE_</code><literal>union_field</literal><code>_etc</code>
|
|
|
1193 |
takes an extra argument, giving the tag associated with the
|
|
|
1194 |
particular element of the set being constructed. Also the construct
|
|
|
1195 |
<code>MODIFY_</code><literal>union_field</literal><code>_etc</code>
|
|
|
1196 |
is introduced to allow the tag of an existing object to be modified
|
|
|
1197 |
to another value within the same set.</para>
|
|
|
1198 |
|
|
|
1199 |
<para>The valid range of union tags for this set can be given by the
|
|
|
1200 |
two constants:
|
|
|
1201 |
|
|
|
1202 |
<programlisting>
|
|
|
1203 |
unsigned int union_field_tag;
|
|
|
1204 |
unsigned int union_field_etc_tag;
|
|
|
1205 |
</programlisting></para>
|
|
|
1206 |
|
|
|
1207 |
<para>A union is a member of this set if its tag is greater than or
|
|
|
1208 |
equal to <literal>union_field</literal><code>_tag</code> and
|
|
|
1209 |
strictly less than
|
|
|
1210 |
<literal>union_field</literal><code>_etc_tag</code>.</para>
|
|
|
1211 |
</sect2>
|
|
|
1212 |
|
|
|
1213 |
<sect2 id="inheritance-in-unions">
|
|
|
1214 |
<title>Inheritance in unions</title>
|
|
|
1215 |
|
|
|
1216 |
<para>Inheritance in unions is handled as follows: if
|
|
|
1217 |
<literal>t</literal> is a derived union with base union
|
|
|
1218 |
<literal>btype</literal> then there is an operation:
|
|
|
1219 |
|
|
|
1220 |
<programlisting>
|
|
|
1221 |
btype CONVERT_union_base(t);
|
|
|
1222 |
</programlisting>
|
|
|
1223 |
|
|
|
1224 |
where <literal>union</literal> and <literal>base</literal> are the
|
|
|
1225 |
short names of <literal>t</literal> and <literal>btype</literal>
|
|
|
1226 |
respectively.</para>
|
|
|
1227 |
</sect2>
|
|
|
1228 |
|
|
|
1229 |
<sect2 id="outputunionmaps">
|
|
|
1230 |
<title>Union maps</title>
|
|
|
1231 |
|
|
|
1232 |
<para>For each map, <literal>map</literal>, on the union
|
|
|
1233 |
<literal>t</literal>, we have declared in
|
|
|
1234 |
<literal>union</literal><code>_ops.h</code> an operator:
|
|
|
1235 |
|
|
|
1236 |
<programlisting>
|
|
|
1237 |
map_ret map_union(t, map_par, ....);
|
|
|
1238 |
</programlisting>
|
|
|
1239 |
|
|
|
1240 |
where <literal>map_ret</literal> is the map return type and
|
|
|
1241 |
<literal>map_par</literal> ranges over the map parameter types. This
|
|
|
1242 |
is except for maps with destructors (i.e. those qualified by a
|
|
|
1243 |
<link linkend="inputunion">hash symbol</link>) which have the form:
|
|
|
1244 |
|
|
|
1245 |
<programlisting>
|
|
|
1246 |
map_ret map_union(t, DESTROYER, map_par, ....);
|
|
|
1247 |
</programlisting></para>
|
|
|
1248 |
|
|
|
1249 |
<para>These maps are implemented by having one function per field for
|
|
|
1250 |
each map. The output file
|
|
|
1251 |
<literal>union</literal><code>_map.h</code> contains tables of these
|
|
|
1252 |
functions. These have the form:
|
|
|
1253 |
|
|
|
1254 |
<programlisting>
|
|
|
1255 |
map_ret(*map_union_table[ORDER_union])(t, map_par, ....) = {
|
|
|
1256 |
....
|
|
|
1257 |
map_union_field,
|
|
|
1258 |
....
|
|
|
1259 |
} ;
|
|
|
1260 |
</programlisting>
|
|
|
1261 |
|
|
|
1262 |
where there is one entry per union field.</para>
|
|
|
1263 |
|
|
|
1264 |
<para>In order to aid the construction of these functions a set of
|
|
|
1265 |
function headers is provided in
|
|
|
1266 |
<literal>union</literal><code>_hdr.h</code>. These take the form:
|
|
|
1267 |
|
|
|
1268 |
<programlisting>
|
|
|
1269 |
#define HDR_map_union_field\
|
|
|
1270 |
map_ret map_union_field(name_union, destroyer, par, ....)\
|
|
|
1271 |
t name_union;\
|
|
|
1272 |
DESTROYER destroyer; /* if required */\
|
|
|
1273 |
map_par par;\
|
|
|
1274 |
....\
|
|
|
1275 |
{\
|
|
|
1276 |
ctype comp;\
|
|
|
1277 |
....\
|
|
|
1278 |
DECONS_union_field(comp, ...., name_union);
|
|
|
1279 |
</programlisting></para>
|
|
|
1280 |
|
|
|
1281 |
<para>There is also an alternative function header,
|
|
|
1282 |
<code>HDR_</code><literal>map</literal>_d_<literal>union_field</literal>,
|
|
|
1283 |
which calls <code>DESTROY_</code><literal>union_field</literal>
|
|
|
1284 |
rather than <code>DECONS_</code><literal>union_field</literal>. The
|
|
|
1285 |
destructor function used is <literal>destroyer</literal>, if this
|
|
|
1286 |
parameter is present, or the default destructor,
|
|
|
1287 |
<code>destroy_</code><literal>name</literal>, otherwise.</para>
|
|
|
1288 |
</sect2>
|
|
|
1289 |
</sect1>
|
|
|
1290 |
</chapter>
|
|
|
1291 |
|
|
|
1292 |
<chapter id="coutput">
|
|
|
1293 |
<title>Implementation details</title>
|
|
|
1294 |
|
|
|
1295 |
<sect1 id="coutputtypes">
|
|
|
1296 |
<title>Implementation of types</title>
|
|
|
1297 |
|
|
|
1298 |
<para>The C implementation of the type system
|
|
|
1299 |
<link linkend="tokenoutput">specified above</link> is based on a
|
|
|
1300 |
single type, <literal>name</literal>, with the same name as the input
|
|
|
1301 |
algebra. This is defined as follows:
|
|
|
1302 |
|
|
|
1303 |
<programlisting>
|
|
|
1304 |
typedef union name_tag {
|
|
|
1305 |
unsigned int ag_tag;
|
|
|
1306 |
union name_tag *ag_ptr;
|
|
|
1307 |
unsigned ag_enum;
|
|
|
1308 |
unsigned long ag_long_enum;
|
|
|
1309 |
name_dim ag_dim;
|
|
|
1310 |
t ag_prim_type;
|
|
|
1311 |
....
|
|
|
1312 |
} name;
|
|
|
1313 |
</programlisting></para>
|
|
|
1314 |
|
|
|
1315 |
<para>where <literal>t</literal> runs over all the primitive types. All
|
|
|
1316 |
of the types in the algebra can be packed into a block of cells of
|
|
|
1317 |
type <literal>name</literal>. The following paragraphs describe the
|
|
|
1318 |
implementation of each type, together with how they are packed as
|
|
|
1319 |
blocks of cells. This is illustrated by the following diagram:</para>
|
|
|
1320 |
|
|
|
1321 |
<mediaobject>
|
|
|
1322 |
<imageobject>
|
|
|
1323 |
<imagedata fileref="images/calculus.png" format="PNG"/>
|
|
|
1324 |
</imageobject>
|
|
|
1325 |
<textobject>
|
|
|
1326 |
<phrase>Packing of types</phrase>
|
|
|
1327 |
</textobject>
|
|
|
1328 |
<caption>
|
|
|
1329 |
<para>Packing of types in calculus</para>
|
|
|
1330 |
</caption>
|
|
|
1331 |
</mediaobject>
|
|
|
1332 |
|
|
|
1333 |
<para>Primitive types are implemented by a <code>typedef</code> defining
|
|
|
1334 |
the type in terms of its
|
|
|
1335 |
<link linkend="outputprim">given definition</link>. A primitive type
|
|
|
1336 |
can be packed into a single cell using the appropriate
|
|
|
1337 |
<code>ag_prim_</code><literal>type</literal> field of the
|
|
|
1338 |
union.</para>
|
|
|
1339 |
|
|
|
1340 |
<para>Identity types are implemented by a <code>typedef</code> defining
|
|
|
1341 |
the type as being equal to another
|
|
|
1342 |
<link linkend="outputident">type from the algebra</link>.</para>
|
|
|
1343 |
|
|
|
1344 |
<para>Enumeration types are all implemented as <code>unsigned int</code>
|
|
|
1345 |
if all its values fit into 16 bits, or <code>unsigned long</code>
|
|
|
1346 |
otherwise. An enumeration type can be packed into a single cell using
|
|
|
1347 |
the <code>ag_enum</code> or <code>ag_long_enum</code> field of the
|
|
|
1348 |
union.</para>
|
|
|
1349 |
|
|
|
1350 |
<para>Structure types are implemented by a <code>typedef</code> defining
|
|
|
1351 |
the type to be the C structure with the
|
|
|
1352 |
<link linkend="outputstruct">given components</link>. A structure type
|
|
|
1353 |
may be packed into a block of cells by packing each of the components
|
|
|
1354 |
in turn.</para>
|
|
|
1355 |
|
|
|
1356 |
<para>Union types are all implemented by a pointer to
|
|
|
1357 |
<literal>name</literal>. This pointer references a block of cells.
|
|
|
1358 |
The null pointer represents
|
|
|
1359 |
<code>NULL_</code><literal>union</literal>, otherwise the first cell
|
|
|
1360 |
contains the union discriminant tag (in the <code>ag_tag</code>
|
|
|
1361 |
field), with the subsequent cells containing the packed field
|
|
|
1362 |
components (shared components first, then unshared components). If the
|
|
|
1363 |
union has only one field then the discriminant can be omitted. The
|
|
|
1364 |
union itself can be packed into a single cell using the
|
|
|
1365 |
<code>ag_ptr</code> field of the union.</para>
|
|
|
1366 |
|
|
|
1367 |
<para>Pointer types are all implemented by a pointer to
|
|
|
1368 |
<literal>name</literal>. Null pointers represent
|
|
|
1369 |
<code>NULL_ptr</code>, otherwise the pointer references a single cell.
|
|
|
1370 |
This cell contains a pointer to the packed version of the object being
|
|
|
1371 |
pointed to in its <code>ag_ptr</code> field. A pointer type itself can
|
|
|
1372 |
be packed into a single cell using the <code>ag_ptr</code> field of
|
|
|
1373 |
the union.</para>
|
|
|
1374 |
|
|
|
1375 |
<para>List types are all implemented by a pointer to
|
|
|
1376 |
<literal>name</literal>. Null pointers represent
|
|
|
1377 |
<code>NULL_list</code>, otherwise the pointer references a block of
|
|
|
1378 |
two cells. The first cell gives the tail of the list in its
|
|
|
1379 |
<code>ag_ptr</code> field; the second cell contains a pointer to the
|
|
|
1380 |
packed version of the head of the list in its <code>ag_ptr</code>
|
|
|
1381 |
field. A list type itself can be packed into a single cell using the
|
|
|
1382 |
<code>ag_ptr</code> field of the union.</para>
|
|
|
1383 |
|
|
|
1384 |
<para>Stack types are identical to list types, with the head of the list
|
|
|
1385 |
corresponding to the top of the stack.</para>
|
|
|
1386 |
|
|
|
1387 |
<para>Vector pointer and vector types are all implemented by structures
|
|
|
1388 |
defined as follows:
|
|
|
1389 |
|
|
|
1390 |
<programlisting>
|
|
|
1391 |
typedef unsigned int name_dim;
|
|
|
1392 |
|
|
|
1393 |
typedef struct {
|
|
|
1394 |
name *vec;
|
|
|
1395 |
name *ptr;
|
|
|
1396 |
} name_VEC_PTR;
|
|
|
1397 |
|
|
|
1398 |
typedef struct {
|
|
|
1399 |
name_dim dim;
|
|
|
1400 |
name_VEC_PTR elems;
|
|
|
1401 |
} name_VEC;
|
|
|
1402 |
</programlisting></para>
|
|
|
1403 |
|
|
|
1404 |
<para>The <code>vec</code> field of a vector pointer contains a pointer
|
|
|
1405 |
to a block of cells containing the packed versions of the elements of
|
|
|
1406 |
the vector. The <code>ptr</code> field is a pointer to the current
|
|
|
1407 |
element of this block. A vector type also has a field giving the
|
|
|
1408 |
vector size. A vector pointer type can be packed into a block of two
|
|
|
1409 |
cells, using the <code>ag_ptr</code> field of each to hold its two
|
|
|
1410 |
components. A vector type can similarly be packed into a block of
|
|
|
1411 |
three cells, the first holding the vector size in its
|
|
|
1412 |
<code>ag_dim</code> field.</para>
|
|
|
1413 |
|
|
|
1414 |
<para>All size types are implemented as <code>int</code>.</para>
|
|
|
1415 |
</sect1>
|
|
|
1416 |
|
|
|
1417 |
<sect1 id="coutputsupport">
|
|
|
1418 |
<title>Support routines</title>
|
|
|
1419 |
|
|
|
1420 |
<para>The implementation requires the user to provide certain support
|
|
|
1421 |
functions. Most fundamental are the routines for allocating and
|
|
|
1422 |
deallocating the blocks of cells which are used to store the types.
|
|
|
1423 |
These are specified as follows:
|
|
|
1424 |
|
|
|
1425 |
<programlisting>
|
|
|
1426 |
name *gen_name(unsigned int);
|
|
|
1427 |
void destroy_name(name *, unsigned int);
|
|
|
1428 |
void dummy_destroy_name(name *, unsigned int);
|
|
|
1429 |
</programlisting>
|
|
|
1430 |
|
|
|
1431 |
where <code>gen_</code><literal>name</literal> allocates a block of
|
|
|
1432 |
cells of the given size, <code>destroy_</code><literal>name</literal>
|
|
|
1433 |
deallocates the given block, and
|
|
|
1434 |
<code>dummy_destroy_</code><literal>name</literal> has
|
|
|
1435 |
<link linkend="outputbasic">no effect</link>. The precise details of
|
|
|
1436 |
how the memory management is to be handled are left to the
|
|
|
1437 |
user.</para>
|
|
|
1438 |
|
|
|
1439 |
<para>Certain generic list functions must also be provided, namely:
|
|
|
1440 |
|
|
|
1441 |
<programlisting>
|
|
|
1442 |
void destroy_name_list(name *, unsigned int);
|
|
|
1443 |
name *reverse_name_list(name *);
|
|
|
1444 |
name *append_name_list(name *, name *);
|
|
|
1445 |
name *end_name_list(name *);
|
|
|
1446 |
</programlisting>
|
|
|
1447 |
|
|
|
1448 |
which implement the constructs <code>DESTROY_list</code>,
|
|
|
1449 |
<code>REVERSE_list</code>, <code>APPEND_list</code> and
|
|
|
1450 |
<code>END_list</code> respectively.</para>
|
|
|
1451 |
|
|
|
1452 |
<para>Finally a dummy empty vector:
|
|
|
1453 |
<programlisting>
|
|
|
1454 |
name_VEC empty_name_vec;
|
|
|
1455 |
</programlisting>needs to be defined.</para>
|
|
|
1456 |
|
|
|
1457 |
<para>Examples of these support routines can be found in the
|
|
|
1458 |
<link linkend="example"><command>calculus</command> program</link>
|
|
|
1459 |
itself.</para>
|
|
|
1460 |
</sect1>
|
|
|
1461 |
|
|
|
1462 |
<sect1 id="coutputassert">
|
|
|
1463 |
<title>Run-time checking</title>
|
|
|
1464 |
|
|
|
1465 |
<para>The type checking facilities supported by
|
|
|
1466 |
<command>calculus</command> allow for compile-time detection of many
|
|
|
1467 |
potential programming errors, however there are many problems, such as
|
|
|
1468 |
dereferencing null pointers, deconstructing empty lists and union tag
|
|
|
1469 |
errors which can only be detected at run-time. For this reason
|
|
|
1470 |
<command>calculus</command> can be made to add extra assertions to
|
|
|
1471 |
check for such errors into its output. This is done by specifying the
|
|
|
1472 |
<code>-a</code> command-line option.</para>
|
|
|
1473 |
|
|
|
1474 |
<para>These assertions are implemented by means of macros. If the macro
|
|
|
1475 |
<code>ASSERTS</code> is defined then these macros expand to give the
|
|
|
1476 |
run-time checks. If not the output is exactly equivalent to that which
|
|
|
1477 |
would have been output if the <code>-a</code> option had not been
|
|
|
1478 |
given.</para>
|
|
|
1479 |
|
|
|
1480 |
<para>The assertions require certain support functions which are output
|
|
|
1481 |
into a separate file, <code>assert_def.h</code>. These functions need
|
|
|
1482 |
to be compiled into the program when <code>ASSERTS</code> is defined.
|
|
|
1483 |
Note that the functions are implementation specific.</para>
|
|
|
1484 |
</sect1>
|
|
|
1485 |
</chapter>
|
|
|
1486 |
|
|
|
1487 |
<chapter id="diskoutput">
|
|
|
1488 |
<title>Disk reading and writing</title>
|
|
|
1489 |
|
|
|
1490 |
<para>One of the facilities which the
|
|
|
1491 |
<link linkend="coutputtypes">homogeneous implementation</link> of the
|
|
|
1492 |
type system described above allows for is the addition of persistence.
|
|
|
1493 |
Persistence in this context means allowing objects to be written to, and
|
|
|
1494 |
read from, disk. Also discussed in this section is the related topic of
|
|
|
1495 |
the object printing routines, which allow a human readable
|
|
|
1496 |
representation of objects of the type system to be output for debugging
|
|
|
1497 |
or other purposes.</para>
|
|
|
1498 |
|
|
|
1499 |
<para>The disk reading and writing routines are output into the files
|
|
|
1500 |
<filename>read_def.h</filename> and <filename>write_def.h</filename>
|
|
|
1501 |
respectively if the <option>-d</option> command-line option is passed to
|
|
|
1502 |
<command>calculus</command>. The object printing routines are output if
|
|
|
1503 |
the <option>-p</option> option is given, with additional code designed
|
|
|
1504 |
for use with run-time debuggers being added if the <option>-a</option>
|
|
|
1505 |
option is also given.</para>
|
|
|
1506 |
|
|
|
1507 |
<para>All of these routines use extra constructs output in the main output
|
|
|
1508 |
files (<filename>name.h</filename> and
|
|
|
1509 |
<filename>union_ops.h</filename>), but not normally accessible. The
|
|
|
1510 |
macro <literal>name</literal><code>_IO_ROUTINES</code> should be defined
|
|
|
1511 |
in order to make these available for the disk reading and writing
|
|
|
1512 |
routines to use.</para>
|
|
|
1513 |
|
|
|
1514 |
<sect1 id="diskwrite">
|
|
|
1515 |
<title>Disk writing routines</title>
|
|
|
1516 |
|
|
|
1517 |
<para>The disk writing routines output in
|
|
|
1518 |
<filename>write_def.h</filename> consist of a function:
|
|
|
1519 |
|
|
|
1520 |
<programlisting>
|
|
|
1521 |
static void WRITE_type(t);
|
|
|
1522 |
</programlisting>
|
|
|
1523 |
|
|
|
1524 |
for each type <literal>t</literal> mentioned within the algebra
|
|
|
1525 |
description, which writes an object of that type to disk.</para>
|
|
|
1526 |
|
|
|
1527 |
<para>Note that such routines are output not only for the basic types,
|
|
|
1528 |
such as unions and structures, but also for any composite types, such
|
|
|
1529 |
as pointers and lists, which are used in their definition. The
|
|
|
1530 |
<literal>type</literal> component of the name
|
|
|
1531 |
<code>WRITE_</code><literal>type</literal> is derived from basic types
|
|
|
1532 |
<literal>t</literal> by using the short type name. For composite types
|
|
|
1533 |
it is defined recursively as follows:
|
|
|
1534 |
|
|
|
1535 |
<programlisting>
|
|
|
1536 |
LIST(t)->list_type
|
|
|
1537 |
PTR(t)->ptr_type
|
|
|
1538 |
STACK(t)->stack_type
|
|
|
1539 |
VEC(t)->vec_type
|
|
|
1540 |
VEC_PTR(t)->vptr_type
|
|
|
1541 |
</programlisting></para>
|
|
|
1542 |
|
|
|
1543 |
<para>Such functions are defined for identity types and composite types
|
|
|
1544 |
involving identity types by means of macros which define them in terms
|
|
|
1545 |
of the identity definitions.
|
|
|
1546 |
<code>WRITE_</code><literal>type</literal> functions for the primitive
|
|
|
1547 |
types should be provided by the user to form a foundation on which all
|
|
|
1548 |
the other functions may be built.</para>
|
|
|
1549 |
|
|
|
1550 |
<para>The user may wish to generate
|
|
|
1551 |
<code>WRITE_</code><literal>type</literal> (or other disk reading and
|
|
|
1552 |
writing) functions for types other than those mentioned in the algebra
|
|
|
1553 |
definition. This can be done by means of a command-line option of the
|
|
|
1554 |
form <code>-E</code><literal>input</literal> where
|
|
|
1555 |
<literal>input</literal> is a file containing a list of the extra
|
|
|
1556 |
types required. In the notation
|
|
|
1557 |
<link linkend="textinput">used above</link> the syntax for
|
|
|
1558 |
<literal>input</literal> is given by:
|
|
|
1559 |
|
|
|
1560 |
<programlisting>
|
|
|
1561 |
extra:
|
|
|
1562 |
type-list<subscript>opt</subscript>
|
|
|
1563 |
|
|
|
1564 |
type-list:
|
|
|
1565 |
type;
|
|
|
1566 |
type-list type;
|
|
|
1567 |
</programlisting></para>
|
|
|
1568 |
|
|
|
1569 |
<para>The <code>WRITE_</code><literal>type</literal> functions are
|
|
|
1570 |
defined recursively in an obvious fashion. The user needs to provide
|
|
|
1571 |
the writing routines for the primitives already mentioned, plus
|
|
|
1572 |
support routines (or macros):
|
|
|
1573 |
|
|
|
1574 |
<programlisting>
|
|
|
1575 |
void WRITE_BITS(int, unsigned int);
|
|
|
1576 |
void WRITE_DIM(name_dim);
|
|
|
1577 |
void WRITE_ALIAS(unsigned int);
|
|
|
1578 |
</programlisting>
|
|
|
1579 |
|
|
|
1580 |
for writing a number of bits to disk, writing a vector dimension and
|
|
|
1581 |
writing an <link linkend="diskalias">object alias</link>.</para>
|
|
|
1582 |
|
|
|
1583 |
<para>Any of the <code>WRITE_</code><literal>type</literal> functions
|
|
|
1584 |
may be overridden by the user by defining a macro
|
|
|
1585 |
<code>WRITE_</code><literal>type</literal> with the desired effect.
|
|
|
1586 |
Note that the <code>WRITE_</code><literal>type</literal> function for
|
|
|
1587 |
an identity can be overridden independently of the function for the
|
|
|
1588 |
identity definition. This provides a method for introducing types
|
|
|
1589 |
which are representationally the same, but which are treated
|
|
|
1590 |
differently by the disk reading and writing routines.</para>
|
|
|
1591 |
</sect1>
|
|
|
1592 |
|
|
|
1593 |
<sect1 id="diskread">
|
|
|
1594 |
<title>Disk reading routines</title>
|
|
|
1595 |
|
|
|
1596 |
<para>The disk reading routines output in
|
|
|
1597 |
<filename>read_def.h</filename> are exactly analogous to the disk
|
|
|
1598 |
writing routines. For each type <literal>t</literal> (except
|
|
|
1599 |
primitives) there is a function or macro:
|
|
|
1600 |
|
|
|
1601 |
<programlisting>
|
|
|
1602 |
static t READ_type(void);
|
|
|
1603 |
</programlisting>
|
|
|
1604 |
|
|
|
1605 |
which reads an object of that type from disk. The user must provide
|
|
|
1606 |
the <code>READ_</code><literal>type</literal> functions for the
|
|
|
1607 |
primitive types, plus support routines:
|
|
|
1608 |
|
|
|
1609 |
<programlisting>
|
|
|
1610 |
unsigned int READ_BITS(int);
|
|
|
1611 |
name_dim READ_DIM(void);
|
|
|
1612 |
unsigned int READ_ALIAS(void);
|
|
|
1613 |
</programlisting>
|
|
|
1614 |
|
|
|
1615 |
for reading a number of bits from disk, reading a vector dimension and
|
|
|
1616 |
reading an <link linkend="diskalias">object alias</link>. The
|
|
|
1617 |
<code>READ_</code><literal>type</literal> functions may be overridden
|
|
|
1618 |
by means of macros as before.</para>
|
|
|
1619 |
</sect1>
|
|
|
1620 |
|
|
|
1621 |
<sect1 id="diskprint">
|
|
|
1622 |
<title>Object printing routines</title>
|
|
|
1623 |
|
|
|
1624 |
<para>The object printing routines output in
|
|
|
1625 |
<filename>print_def.h</filename> consist of a function or macro:
|
|
|
1626 |
|
|
|
1627 |
<programlisting>
|
|
|
1628 |
static void PRINT_type(FILE *, t, char *, int);
|
|
|
1629 |
</programlisting>
|
|
|
1630 |
|
|
|
1631 |
for each type <literal>t</literal>, which prints an object of type
|
|
|
1632 |
<literal>t</literal> to the given file, using the given object name
|
|
|
1633 |
and indentation value. The user needs to provide basic output
|
|
|
1634 |
routines:
|
|
|
1635 |
|
|
|
1636 |
<programlisting>
|
|
|
1637 |
void OUTPUT_type(FILE *, t);
|
|
|
1638 |
</programlisting>
|
|
|
1639 |
|
|
|
1640 |
for each primitive type. The
|
|
|
1641 |
<code>PRINT_</code><literal>type</literal> functions may be overridden
|
|
|
1642 |
by means of macros as before.</para>
|
|
|
1643 |
|
|
|
1644 |
<para>The printing routines are under the control of three variables
|
|
|
1645 |
defined as follows:
|
|
|
1646 |
|
|
|
1647 |
<programlisting>
|
|
|
1648 |
static int print_indent_step = 4;
|
|
|
1649 |
static int print_ptr_depth = 1;
|
|
|
1650 |
static int print_list_expand = 0;
|
|
|
1651 |
</programlisting></para>
|
|
|
1652 |
|
|
|
1653 |
<para>These determine the indentation to be used in the output, to what
|
|
|
1654 |
depth pointers are to be dereferenced when printing, and whether lists
|
|
|
1655 |
and stacks are to be fully expanded into a sequence of elements or
|
|
|
1656 |
just split into a head and a tail.</para>
|
|
|
1657 |
|
|
|
1658 |
<para>One application of these object printing routines is to aid
|
|
|
1659 |
debugging programs written using the <command>calculus</command> tool.
|
|
|
1660 |
The form of the type system implementation means that it is not easy
|
|
|
1661 |
to extract information using run-time debuggers without a detailed
|
|
|
1662 |
knowledge of the structure of this implementation. As a more
|
|
|
1663 |
convenient alternative, if both the <code>-p</code> and
|
|
|
1664 |
<code>-a</code> command-line options are given then
|
|
|
1665 |
<command>calculus</command> will generate functions:
|
|
|
1666 |
|
|
|
1667 |
<programlisting>
|
|
|
1668 |
void DEBUG_type(t);
|
|
|
1669 |
</programlisting>
|
|
|
1670 |
|
|
|
1671 |
defined in terms of <code>PRINT_</code><literal>type</literal>, for
|
|
|
1672 |
printing an object of the given type to the standard output. Many
|
|
|
1673 |
debuggers have problems passing structure arguments, so for structure,
|
|
|
1674 |
vector and vector pointer types
|
|
|
1675 |
<code>DEBUG_</code><literal>type</literal> takes the form:
|
|
|
1676 |
|
|
|
1677 |
<programlisting>
|
|
|
1678 |
void DEBUG_type(t *);
|
|
|
1679 |
</programlisting>
|
|
|
1680 |
|
|
|
1681 |
These debugging routines are only defined conditionally, if the macro
|
|
|
1682 |
<code>DEBUG</code> is defined.</para>
|
|
|
1683 |
</sect1>
|
|
|
1684 |
|
|
|
1685 |
<sect1 id="diskalias">
|
|
|
1686 |
<title>Aliasing</title>
|
|
|
1687 |
|
|
|
1688 |
<para>An important feature of the disk reading and writing routines,
|
|
|
1689 |
namely aliasing, has been mentioned but not yet described. The problem
|
|
|
1690 |
to be faced is that many of the objects built up using type systems
|
|
|
1691 |
defined using <command>calculus</command> will be cyclic - they will
|
|
|
1692 |
include references to themselves in their own definitions. Aliasing
|
|
|
1693 |
is a mechanism for breaking such cycles by ensuring that only one copy
|
|
|
1694 |
of an object is ever written to disk, or that only one copy is created
|
|
|
1695 |
when reading from disk. This is done by associating a unique number as
|
|
|
1696 |
an alias for the object.</para>
|
|
|
1697 |
|
|
|
1698 |
<para>For example, when writing to disk, the first time the object is
|
|
|
1699 |
written the alias definition is set up. Consequently the alias number
|
|
|
1700 |
is written instead of the object it represents. Similarly when reading
|
|
|
1701 |
from disk, an alias may be associated with an object when it is read.
|
|
|
1702 |
When this alias is encountered subsequently it will always refer to
|
|
|
1703 |
this same object.</para>
|
|
|
1704 |
|
|
|
1705 |
<para>The objects on which aliasing can be specified are the
|
|
|
1706 |
<link linkend="inputunion">union fields</link>. A union field may be
|
|
|
1707 |
qualified by one or two hash symbols to signify that objects of that
|
|
|
1708 |
type should be aliased.</para>
|
|
|
1709 |
|
|
|
1710 |
<para>The two hash case is used to indicate that the user wishes to gain
|
|
|
1711 |
access to the objects during the aliasing mechanism. In the disk
|
|
|
1712 |
writing case, the object to be written, <literal>x</literal> say, is
|
|
|
1713 |
split into its components using the appropriate
|
|
|
1714 |
<code>DECONS_</code><literal>union_field</literal> construct. Then the
|
|
|
1715 |
user-defined routine, or macro:
|
|
|
1716 |
|
|
|
1717 |
<programlisting>
|
|
|
1718 |
ALIAS_union_field(comp, ...., x);
|
|
|
1719 |
</programlisting>
|
|
|
1720 |
|
|
|
1721 |
(where <literal>comp</literal> ranges over all the union components)
|
|
|
1722 |
is called prior to writing the object components to disk.</para>
|
|
|
1723 |
|
|
|
1724 |
<para>Similarly in the disk reading case, the object being read,
|
|
|
1725 |
<literal>x</literal>, is initialised by calling the user-defined
|
|
|
1726 |
routine:
|
|
|
1727 |
|
|
|
1728 |
<programlisting>
|
|
|
1729 |
UNALIAS_union_field(x);
|
|
|
1730 |
</programlisting>
|
|
|
1731 |
|
|
|
1732 |
prior to reading the object components from disk. Each object
|
|
|
1733 |
component is then read into a local variable, <literal>comp</literal>.
|
|
|
1734 |
Finally the user-defined routine:
|
|
|
1735 |
|
|
|
1736 |
<programlisting>
|
|
|
1737 |
UNIFY_union_field(comp, ...., x);
|
|
|
1738 |
</programlisting>
|
|
|
1739 |
|
|
|
1740 |
(where <literal>comp</literal> ranges over all the union components)
|
|
|
1741 |
is called to assign these values to <literal>x</literal> before
|
|
|
1742 |
returning.</para>
|
|
|
1743 |
|
|
|
1744 |
<para>In the single hash case the object is not processed in this way.
|
|
|
1745 |
It is just written straight to disk, or has its components immediately
|
|
|
1746 |
assigned to it when reading from disk.</para>
|
|
|
1747 |
|
|
|
1748 |
<para>Note that aliasing is used, not just in the disk reading and
|
|
|
1749 |
writing routines, but also in the object printing functions. After
|
|
|
1750 |
calling any such function the user should call the routine:
|
|
|
1751 |
|
|
|
1752 |
<programlisting>
|
|
|
1753 |
void clear_name_alias(void);
|
|
|
1754 |
</programlisting>
|
|
|
1755 |
|
|
|
1756 |
to clear all aliases.</para>
|
|
|
1757 |
|
|
|
1758 |
<para>Aliases are implemented by adding an extra field to the objects to
|
|
|
1759 |
be aliased, which contains the alias number, if this has been
|
|
|
1760 |
assigned, or zero, otherwise. A list of all these extra fields is
|
|
|
1761 |
maintained. In addition to the routine
|
|
|
1762 |
<code>clear_</code><literal>name</literal>_alias mentioned above, the
|
|
|
1763 |
user should provide support functions and variables:
|
|
|
1764 |
|
|
|
1765 |
<programlisting>
|
|
|
1766 |
unsigned int crt_name_alias;
|
|
|
1767 |
void set_name_alias(name *, unsigned int);
|
|
|
1768 |
name *find_name_alias(unsigned int);
|
|
|
1769 |
</programlisting>
|
|
|
1770 |
|
|
|
1771 |
giving the next alias number to be assigned, and routines for adding
|
|
|
1772 |
an alias to the list of all aliases, and looking up an alias in this
|
|
|
1773 |
list. Example implementations of these routines are given in the
|
|
|
1774 |
<link linkend="example"><command>calculus</command> program</link>
|
|
|
1775 |
itself.</para>
|
|
|
1776 |
</sect1>
|
|
|
1777 |
|
|
|
1778 |
<sect1 id="application">
|
|
|
1779 |
<title>Application to calculus</title>
|
|
|
1780 |
|
|
|
1781 |
<para>As <link linkend="example">mentioned above</link>, the
|
|
|
1782 |
<command>calculus</command> program itself is an example of its own
|
|
|
1783 |
application. It therefore contains routines for reading and writing a
|
|
|
1784 |
representation of an algebra to and from disk, and for pretty-printing
|
|
|
1785 |
the contents of an algebra. These may be accessed using the
|
|
|
1786 |
<link linkend="options">command-line options</link> mentioned
|
|
|
1787 |
above.</para>
|
|
|
1788 |
|
|
|
1789 |
<para>If the <option>-w</option> command-line option is specified to
|
|
|
1790 |
<command>calculus</command> then it reads its input file,
|
|
|
1791 |
<literal>input</literal>, as normal, but writes a disk representation
|
|
|
1792 |
of the input algebra to <literal>output</literal>, which in this
|
|
|
1793 |
instance is an output file, rather than an output directory. An output
|
|
|
1794 |
file produced in this way can then be specified as an input file to
|
|
|
1795 |
<command>calculus</command> if the <option>-r</option> option is
|
|
|
1796 |
given. Finally the input algebra may be pretty-printed to an output
|
|
|
1797 |
file (or the standard output if no <literal>output</literal> argument
|
|
|
1798 |
is given) by specifying the <option>-o</option> option.</para>
|
|
|
1799 |
</sect1>
|
|
|
1800 |
</chapter>
|
|
|
1801 |
|
|
|
1802 |
<chapter id="template-files">
|
|
|
1803 |
<title>Template files</title>
|
|
|
1804 |
|
|
|
1805 |
<para>It is possible to use <command>calculus</command> to generate an
|
|
|
1806 |
output file from a template input file, <literal>template</literal>,
|
|
|
1807 |
using the syntax:
|
|
|
1808 |
|
|
|
1809 |
<programlisting>
|
|
|
1810 |
calculus [ options ] input .... -Ttemplate output
|
|
|
1811 |
</programlisting></para>
|
|
|
1812 |
|
|
|
1813 |
<para>The template file consists of a list of either template directives
|
|
|
1814 |
or source lines containing escape sequences which are expanded by
|
|
|
1815 |
<command>calculus</command>. Template directive lines are distinguished
|
|
|
1816 |
by having <code>@</code> as their first character. Escape sequences
|
|
|
1817 |
consist of <code>%</code> following by one or more characters.</para>
|
|
|
1818 |
|
|
|
1819 |
<para>There are two template directives; loops take the form:
|
|
|
1820 |
|
|
|
1821 |
<programlisting>
|
|
|
1822 |
@loop control
|
|
|
1823 |
....
|
|
|
1824 |
@end
|
|
|
1825 |
</programlisting>
|
|
|
1826 |
|
|
|
1827 |
and conditionals take the form:
|
|
|
1828 |
|
|
|
1829 |
<programlisting>
|
|
|
1830 |
@if condition
|
|
|
1831 |
....
|
|
|
1832 |
@else
|
|
|
1833 |
....
|
|
|
1834 |
@endif
|
|
|
1835 |
</programlisting>
|
|
|
1836 |
|
|
|
1837 |
or:
|
|
|
1838 |
|
|
|
1839 |
<programlisting>
|
|
|
1840 |
@if condition
|
|
|
1841 |
....
|
|
|
1842 |
@endif
|
|
|
1843 |
</programlisting>
|
|
|
1844 |
|
|
|
1845 |
where <code>....</code> stands for any sequence of template directives
|
|
|
1846 |
or source lines.</para>
|
|
|
1847 |
|
|
|
1848 |
<para>The <literal>control</literal> statements in a loop can be
|
|
|
1849 |
<code>primitive</code>, <code>identity</code>, <code>enum</code>,
|
|
|
1850 |
<code>struct</code> or <code>union</code> to loop over all the
|
|
|
1851 |
primitive, identity, enumeration structure or union types within the
|
|
|
1852 |
input algebra. Within an <code>enum</code> loop it is possible to use
|
|
|
1853 |
<code>enum.const</code> to loop over all the enumeration constants of
|
|
|
1854 |
the current enumeration type. Within a <code>struct</code> loop it is
|
|
|
1855 |
possible to use <code>struct.comp</code> to loop over all the components
|
|
|
1856 |
of the current structure. Within a <code>union</code> loop it is
|
|
|
1857 |
possible to use <code>union.comp</code> to loop over all the shared
|
|
|
1858 |
components of the current union, <code>union.field</code> to loop over
|
|
|
1859 |
all the fields of the current union, and <code>union.map</code> to loop
|
|
|
1860 |
over all the maps of the current union. Within a
|
|
|
1861 |
<code>union.field</code> loop it is possible to use
|
|
|
1862 |
<code>union.field.comp</code> to loop over all the components of the
|
|
|
1863 |
current union field. Within a <code>union.map</code> loop it is possible
|
|
|
1864 |
to use <code>union.map.arg</code> to loop over all the arguments of the
|
|
|
1865 |
current union map.</para>
|
|
|
1866 |
|
|
|
1867 |
<para>The valid <literal>condition</literal> statements in a conditional
|
|
|
1868 |
are <code>true</code> and <code>false</code>, plus
|
|
|
1869 |
<code>comp.complex</code>, which is true if the current structure or
|
|
|
1870 |
union field component has a complex type (i.e. those for which
|
|
|
1871 |
<code>COPY_</code><literal>type</literal> and
|
|
|
1872 |
<code>DEREF_</code><literal>type</literal> require two arguments), and
|
|
|
1873 |
<code>comp.default</code>, which is true if the current structure or
|
|
|
1874 |
union field component has a default initialiser value.</para>
|
|
|
1875 |
|
|
|
1876 |
<para>A number of escape sequences can be used anywhere. <code>%ZX</code>
|
|
|
1877 |
and <code>%ZV</code> give the name and version number of the version of
|
|
|
1878 |
<command>calculus</command> used. <code>%Z</code> and <code>%V</code>
|
|
|
1879 |
give the name and version number of the input algebra. <code>%%</code>
|
|
|
1880 |
and <code>%@</code> give <code>%</code> and <code>@</code> respectively,
|
|
|
1881 |
and <code>%</code> as the last character in a line suppresses the
|
|
|
1882 |
following newline character.</para>
|
|
|
1883 |
|
|
|
1884 |
<para>Within a <code>primitive</code> loop, <code>%PN</code> gives the
|
|
|
1885 |
primitive name, <code>%PM</code> gives the short primitive name and
|
|
|
1886 |
<code>%PD</code> gives the primitive definition.</para>
|
|
|
1887 |
|
|
|
1888 |
<para>Within an <code>identity</code> loop, <code>%IN</code> gives the
|
|
|
1889 |
identity name, <code>%IM</code> gives the short identity name and
|
|
|
1890 |
<code>%IT</code> gives the identity definition.</para>
|
|
|
1891 |
|
|
|
1892 |
<para>Within an <code>enum</code> loop, <code>%EN</code> gives the
|
|
|
1893 |
enumeration name, <code>%EM</code> gives the short enumeration name and
|
|
|
1894 |
<code>%EO</code> gives the enumeration order,
|
|
|
1895 |
<code>ORDER_</code><literal>enum</literal>. Within an
|
|
|
1896 |
<code>enum.const</code> loop, <code>%ES</code> gives the enumeration
|
|
|
1897 |
constant name and <code>%EV</code> gives its value.</para>
|
|
|
1898 |
|
|
|
1899 |
<para>Within a <code>struct</code> loop, <code>%SN</code> gives the
|
|
|
1900 |
structure name and <code>%SM</code> gives the short structure
|
|
|
1901 |
name.</para>
|
|
|
1902 |
|
|
|
1903 |
<para>Within a <code>union</code> loop, <code>%UN</code> gives the union
|
|
|
1904 |
name, <code>%UM</code> gives the short union name and <code>%UO</code>
|
|
|
1905 |
gives the union order, <code>ORDER_</code><literal>union</literal>.
|
|
|
1906 |
Within a <code>union.field</code> loop, <code>%FN</code> gives the field
|
|
|
1907 |
name. Within a <code>struct.comp</code>, <code>union.comp</code> or
|
|
|
1908 |
<code>union.field.comp</code> loop, <code>%CN</code> gives the component
|
|
|
1909 |
name, <code>%CT</code> gives the component type, <code>%CU</code> gives
|
|
|
1910 |
the short form of the component type and <code>%CV</code> gives the
|
|
|
1911 |
default component initialiser value (if <code>comp.default</code> is
|
|
|
1912 |
true). Within a <code>union.map</code> loop, <code>%MN</code> gives the
|
|
|
1913 |
map name and <code>%MR</code> gives the map return type. Within a
|
|
|
1914 |
<code>union.map.arg</code> loop, <code>%AN</code> gives the argument
|
|
|
1915 |
name and <code>%AT</code> gives the argument type.</para>
|
|
|
1916 |
|
|
|
1917 |
<para>As an example, the following template file gives a simple algebra
|
|
|
1918 |
pretty printer:
|
|
|
1919 |
|
|
|
1920 |
<programlisting>
|
|
|
1921 |
ALGEBRA %X (%V):
|
|
|
1922 |
|
|
|
1923 |
/* PRIMITIVE TYPES */
|
|
|
1924 |
@loop primitive
|
|
|
1925 |
%PN (%PM) = "%PD";
|
|
|
1926 |
@end
|
|
|
1927 |
|
|
|
1928 |
/* IDENTITY TYPES */
|
|
|
1929 |
@loop identity
|
|
|
1930 |
%IN (%IM) = %IT;
|
|
|
1931 |
@end
|
|
|
1932 |
|
|
|
1933 |
/* ENUMERATION TYPES */
|
|
|
1934 |
@loop enum
|
|
|
1935 |
|
|
|
1936 |
enum %EN (%EM) = {
|
|
|
1937 |
@loop enum.const
|
|
|
1938 |
%ES = %EV,
|
|
|
1939 |
@end
|
|
|
1940 |
};
|
|
|
1941 |
@end
|
|
|
1942 |
|
|
|
1943 |
/* STRUCTURE TYPES */
|
|
|
1944 |
@loop struct
|
|
|
1945 |
|
|
|
1946 |
struct %SN (%SM) = {
|
|
|
1947 |
@loop struct.comp
|
|
|
1948 |
%CT %CN;
|
|
|
1949 |
@end
|
|
|
1950 |
};
|
|
|
1951 |
@end
|
|
|
1952 |
|
|
|
1953 |
/* UNION TYPES */
|
|
|
1954 |
@loop union
|
|
|
1955 |
|
|
|
1956 |
union %UN (%UM) = {
|
|
|
1957 |
@loop union.comp
|
|
|
1958 |
%CT %CN;
|
|
|
1959 |
@end
|
|
|
1960 |
} + {
|
|
|
1961 |
@loop union.field
|
|
|
1962 |
%FN->{
|
|
|
1963 |
@loop union.field.comp
|
|
|
1964 |
%CT %CN;
|
|
|
1965 |
@end
|
|
|
1966 |
};
|
|
|
1967 |
@end
|
|
|
1968 |
};
|
|
|
1969 |
@end
|
|
|
1970 |
</programlisting></para>
|
|
|
1971 |
</chapter>
|
|
|
1972 |
|
|
|
1973 |
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude"
|
|
|
1974 |
href="../../../common/colophon-dera.xml"/>
|
|
|
1975 |
</book>
|