Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – tendra.SVN – Blame – /branches/tendra5-amd64/doc/user/guides/calculus/calculus.xml – Rev 6

Subversion Repositories tendra.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
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-&gt;component-group
367
        #<subscript>opt</subscript> #<subscript>opt</subscript> field-identifier-list-&gt;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)-&gt;list_type
1537
PTR(t)-&gt;ptr_type
1538
STACK(t)-&gt;stack_type
1539
VEC(t)-&gt;vec_type
1540
VEC_PTR(t)-&gt;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-&gt;{
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>