previous next top complete contents complete index framed top this page unframed
Text forms serve four main purposes:
Except as noted below, descriptions of the contents of a text form apply only to noncompressed text forms. Compressed text forms, although portable among operating systems, are not intended for human readers, and their format is subject to change.
A detailed understanding of text forms is necessary only if they are to be edited by a human user or parsed by a program; otherwise, the contents of a text form should be self-explanatory.
Except within STRING constants, the case of alphabetic characters in a text form is irrelevant. The hash mark (#) may be used as in MAINSAIL source text to indicate that the remainder of a line in a text form is to be ignored.
A text form consists of a sequence of “attributes” followed by a sequence of “units”.
Table 3–1. \ Escape Sequences in Text Form STRING Constants
For example, a STRING constructed in a program with:
is written out as follows on an ASCII system:
3.1. Constants
Constants are written in text forms
as if they appeared in MAINSAIL source, except:
The \ is used in STRING constants in a text form as an
escape character according to the following table: Escape Sequence Corresponding STRING \d, \dd, or \ddd
the character with code d, dd,
or ddd, where each d is a decimal
digit. If the character after this escape
sequence is a decimal digit, then the
\ddd form must be used (with leading
zero characters if necessary) \n eol (end-of-line) \p eop (end-of-page) \t tab (horizontal tab) \" double quote (same as doubled double quote) \\ backslash (\) \ escape sequences are not used in STRING constants in
MAINSAIL source text.
p.s := ""; cWrite(p.s,1,'2',3,'X');
s = "\0012\3X"
'HD6D40
'HD6D40 + 1 character
'HD6D40 + 2 characters
3.2. Attributes
An attribute is a line in a text form that describes the contents of
the text form.
Attributes may be separated from one another and from the first
unit by one or more blank lines.
There is currently just one valid attribute. It has the form:
systemWrittenOn operatingSystemNameAbbreviation
A list of possible operating system name abbreviations may be found in Appendix B of the MAINSAIL Language Manual. The systemWrittenOn attribute identifies the operating system on which the text form was written, which is used when a text form written on one system is read on another (e.g., to translate escape sequences in STRING constants). If this attribute is not present, it is assumed that the text form was written on the current host system.
Each unit starts with a “header line” that “declares” the unit, followed by a “dash line”, which is a row of hyphens to underline the header line. Typically the dash line is the same length as the header line, but this is not necessary. The dash line must be present.
Each header line starts with an “internal name” for the unit, followed by a colon and a space. Internal names consist of a valid MAINSAIL identifier or INTEGER constant preceded by the character < and followed by the character >. For example, <123> and <foo> are valid internal names. Internal names give a unique name to each unit so that units may be referenced unambiguously within the text form.
3.3.1. CLASS Units
All CLASS units must occur before any chunk units.
The general form of a
CLASS unit is:
<internalName>: CLASS className
-------------------------------
... field declarations...
className is the name of the CLASS. The field declarations are specified one per line. Each has the form:
dataType fieldName
where dataType is a data type name, e.g., BOOLEAN or LONG INTEGER, and fieldName is the name of the field. ADDRESS and POINTER fields cannot be classified. An ARRAY field is declared as a POINTER.
An example of a CLASS unit is shown in Example 3–2.
Example 3–2. A Sample CLASS Unit
| A CLASS unit corresponding to a CLASS declared as:
CLASS strListCls ( would look like:
<51>: CLASS strlistcls |
<recordInternalName>: record of CLASS <classInternalName>
---------------------------------------------------------
... field specifications...
<classInternalName> is the internal name of the CLASS that describes the record fields. Field specifications are specified one per line, except that STRING constants may occupy more than one line. Each specification has the form:
fieldName = constantValue
constantValue must be of the same data type as declared for fieldName. An example of a record unit is shown in Example 3–3.
Example 3–3. A Sample Record Unit
| A record of the CLASS shown in Example 3–2 with
field values "This is a string" for val,
"THIS" for key,
and NULLPOINTER for next would look like:
<52>: record of CLASS <51> # strlistcls |
<internalName>: typeName {LONG} ARRAY(<bounds>) {aryName}
---------------------------------------------------------
... element specifications...
LONG is optional and is ignored. The bounds are a series of (LONG) INTEGER pairs, separated by the word TO, as in MAINSAIL source text. aryName is the name of the ARRAY; it may be omitted since it is possible for an ARRAY name to be the empty STRING. The element specifications are written one per line, except that STRING constants may use more than one line. Each specification has the form:
elementSpecifier {FOR n} = value
where the FOR n part is optional. elementSpecifier is the bracketed subscript part of a MAINSAIL subscripted variable, i.e., [i], [i,j], or [i,j,k] for a one-, two-, or three-dimensional ARRAY, respectively, where i, j, and k are (LONG) INTEGER constants. The elementSpecifiers need not be in any particular order. If FOR n is present, then n elements are initialized to the value, starting at the one specified; otherwise, just one element is initialized. The elementSpecifiers are read and corresponding initializations performed from the first elementSpecifier to the last, so that an element receives the last specified value if initialized more than once. Uninitialized elements have Zero values.
An example of an ARRAY unit is shown in Example 3–4.
Example 3–4. A Sample ARRAY Unit
| An ARRAY unit for an ARRAY declared as:
CHARADR ARRAY(*) cAry; and allocated with:
new(cAry,-2,40); with elements 3 through 6 given non-Zero values might look like:
<88>: CHARADR ARRAY(-2 TO 40) cary |
A vector unit had the form:
<internalName>: typeName VECTOR(0 TO n)
---------------------------------------
... element specifications...
You should not ordinarily find vector units in your text forms,
since the effect of performing a $structureWrite on the sorts of
runtime system objects that could contain vectors has undefined
effects.
3.3.5. DataSec Units
A dataSec unit specifies the values in a data section, and has the
form:
<iName>: dataSection for MODULE modName {of CLASS <cName>}
----------------------------------------------------------
... specifications for interface data fields...
... OWN data specifications...
of CLASS <cName> must be present if the module has any interface data fields, in which case <cName> is the internal name for the CLASS that declares the fields.
A data section consists of the interface data fields followed by the OWN POINTERs, the OWN STRINGs and then any other OWN variables. OWN variables are the “outer” variables for the module (those declared outside of any PROCEDURE, but local to the module), variables declared local to a PROCEDURE but qualified with OWN, and some implicit, undeclared variables maintained by the MAINSAIL runtime system.
The specifications for the interface data fields have the form of the field specifications for a record.
The OWN data specifications have the form:
typeName {variableName} {FOR n} = value
variableName is not currently written out by the Structure Blaster since MAINSAIL does not know at runtime the names of the OWN variables. FOR n gives a repetition factor just as in an ARRAY unit (the repetition factor cannot be used if variableName is present). The OWN specifications must appear in the same order in which they occur in the data section; the user should not edit them.
An example of a dataSec unit is shown in Example 3–5.
Example 3–5. A Sample DataSec Unit
| A module WINMOD with an interface declaration like:
MODULE winMod ( might generate a dataSec unit like:
<94>: dataSection for MODULE winmod of CLASS <93> WINMOD has 23 OWN POINTERs, one OWN STRING, and 9 other OWN variables. The names of the OWN variables are not provided; some of these variables may be implicit variables that have no names. |
BEGIN "foo"
CLASS c (
INTEGER i;
);
CLASS d (
$RECORD(c) rec;
STRING $INPLACEARRAY(0 to 10) ary;
);
INITIAL PROCEDURE;
BEGIN
$structureWrite(logFile,new(d));
END;
END "foo"
produces the following output:
SYSTEMWRITTENON ...
<352>: CLASS c
--------------
INTEGER i
<224>: CLASS d
--------------
$RECORD(<352>) rec
STRING $INPLACEARRAY(0 TO 10) ary
<120>: RECORD OF CLASS <224> # d
--------------------------------
rec = {
i = 0
}
ary = {
[0] FOR 11 = ""
}
Two kinds of discrepancies are permitted to facilitate editing and subsequent reading of existing text forms:
Thus, the user can add or delete CLASS fields without having to update every referencing record or dataSec unit, thereby facilitating the editing of text forms.
The fields of a record unit need not appear in the same order as the fields of the corresponding CLASS unit. When the record is assembled in memory, the order of the memory fields is the order of the fields in the corresponding CLASS unit (this is subject to change if the way fields of a record are laid out in memory changes).
If the warning bit is set in the ctrlBits argument of $structureTextToData or the textFile form of $structureRead, a warning message is given whenever the first kind of discrepancy occurs.
Compressed text forms are detected automatically on input.
MAINSAIL Structure Blaster User's Guide, Chapter 3