RES home

Syntax of RES 0.3

A fragment of RES represents a consecutive sequence of hieroglyphic, and is the largest unit within the RES encoding format. A fragment contains names of glyphs and related objects, and operators and functions to indicate relative positioning of these objects.

There are four operators, viz. '-', ':', '*' and '^'. The first three connect pairs of subexpressions of hieroglyphic, the fourth is used to attach notes to glyphs and related objects.

There are also three functions, viz. insert, stack and modify, which can be used for special relative positioning of groups of glyphs. The use of a function consists of the function name (optionally followed by a bracketed list; see below), followed by a round open bracket, followed by one subexpression (in the case of modify) or two subexpression separated by a comma (in the case of insert and stack), and then a round close bracket.

At the beginning of a fragment we may also find a header, which may set two constant properties of the text in the fragment, viz. the direction (e.g. left-to-right versus right-to-left) and the size of the text (height of a line or width of a column) relative to the dimensions of the glyphs. Within a fragment we may also find switches, which change global values.

Below we give a formal definition of the syntax of the RES encoding format. This definition is basically given as a context-free grammar, but includes 'place-holders' X to avoid proliferation of a number of very similar syntactic definitions. (Formally, this is known as a type 0 grammar; we will make only very restricted use of the power of type 0 grammars however.)

For example, glyphs and operators, amongst others, can be modified by adding a bracketed list, i.e. a list of arguments enclosed in square brackets and separated by commas. Such a bracketed list is appended directly behind the name of a glyph or operator. What arguments are allowed differs between glyphs and different operators, but the basic structure of bracketed lists is the same. Instead of providing separate definitions of named_glyph_arg-bracketed_list, op_arg-bracketed_list, etc., we only provide the definition of an X-bracketed_list, where X can stand for nonterminals named_glyph_arg, op_arg, etc., defined elsewhere.

We also use patterns of the form ( ... )* and ( ... )+, which specify that the part between the brackets can be repeated zero or more times (in the case of *) or one or more times (in the case of +). The pattern [ ... ] specifies that the part between the square brackets occurs zero times or one time, in other words that it is optional.

In the grammar, we write characters or sequences of characters between single quotes to specify that those characters or sequences of characters occur verbatim in the encoding. Some characters that cannot be clearly denoted otherwise are named by capital letters and underscores between angled brackets, as for example <HORIZONTAL_TAB>; their meaning should be self-evident.

Main definitions

The first production of the grammar specifies that a fragment may begin with whitespaces, so blanks, newlines, etc., optionally followed by a header, followed by zero or more switches, optionally followed by hieroglyphic.

fragment -> 
	whitespaces [ header ] switches [ hieroglyphic ]

The header influences settings for two constant properties of the text. The first is the direction. The value 'hlr' indicates that the direction of the text is horizontally left-to-right, which is the default. 'hrl' stands for horizontally right-to-left, 'vlr' stands for vertically left-to-right, 'vrl' stands for vertically right-to-left. The former two will be called horizontal directions, and the latter two will be called vertical directions. It makes no sense to indicate more than one direction in the header, but if more than one direction is specified, the last one cancels all others. (This is generally the case for mutually exclusive arguments in a bracketed list; see below.)

The second constant property is the unit size of the text, which is a value that is relevant for scaling. This is the value specified for attribute 'size'. The default value for 'size' is 1.0, the unit being EM. In the case of horizontal directions, the unit size also specifies the height of the line of text, and in the case of vertical directions, it specifies the width of the column of text.

A different unit size may be specified in a group constructed by the operators ':' or '*', but this only has an effect on the scaling of that group, and does not change the global value for the unit size.

header ->
	header_arg-bracketed_list whitespaces

header_arg ->
	direction |
	'size=' non_zero_real

direction ->
	'hlr' | 'hrl' | 'vlr' | 'vrl'

After the optional header, and zero or more switches, we find zero or more top_groups, separated by occurrences of the operator '-', each optionally followed by a bracketed list. Whether '-' indicates horizontal arrangement of the top_groups or vertical arrangement depends on whether the direction is horizontal or vertical, respectively.

After the optional bracketed list we have whitespaces followed by switches. Because of the frequency of the combination of whitespaces and switches, we abbreviate it to ws.

hieroglyphic -> 
		( '-' [ op_arg-bracketed_list ] ws top_group )*

We distinguish between three types of top_group, depending on the outermost operator, if any.

top_group -> 
	vert_group | 
	hor_group | 

A vert_group consists of two or more vert_sub_groups, separated by occurrences of the operator ':', each optionally followed by a bracketed list. The bracketed list attached to the first occurrence of ':' may contain an argument that pertains to the complete vert_group; see the definition of first_op_arg below.

The vert_sub_groups are to be arranged vertically, the first is placed top-most, the last is placed bottom-most. A vert_sub_group consisting of a hor_group is optionally enclosed in round brackets. Such brackets are always superfluous, but they are allowed for the sake of symmetry with the definition of hor_sub_group (see below).

vert_group -> 
		':' [ first_op_arg-bracketed_list ] ws vert_sub_group 
		( ':' [ op_arg-bracketed_list ] ws vert_sub_group )*
vert_sub_group ->
	hor_group |
	'(' ws hor_group ')' ws |

A hor_group is similar to a vert_group, except that the hor_sub_groups are to be arranged horizontally, the first is placed left-most, the last is placed right-most provided the direction is left-to-right; for a right-to-left direction, the first is placed right-most and the last is placed left-most.

hor_group -> 
		'*' [ first_op_arg-bracketed_list ] ws hor_sub_group 
		( '*' [ op_arg-bracketed_list ] ws hor_sub_group )*
hor_sub_group ->
	'(' ws vert_group ')' ws |

An op_arg affects the space between two groups of glyphs at an occurrence of one of the operators '-', ':' or '*'. A value for the attribute 'sep' specifies that the normal (minimal) distance between the two groups is to be multiplied by that value. It overrides the global value specified by an attribute with the same name; see below.

If the argument 'fit' is added, then the specified (minimal) distance between the groups does not refer to the distance between bounding boxes but to the minimal distance between pairs of non-blank pixels within the bounding boxes, the first from the preceding subgroups (plural), and the second from the following subgroup (singular). This implies that we consider the operators to be left-associative. The argument 'nofit' temporarily overrides the global value for fitting.

If the argument 'fix' is added, then there will be no additional space between subgroups to fill up the available space.

For shade_arg see below.

op_arg ->
	'sep=' real |
	'fit' |
	'nofit' |
	'fix' |

In addition to arguments of the form specified by op_arg above, the bracketed list attached to the first ':' in a vert_group and the first '*' in a hor_group may specify a value for attribute 'size'. This represents the unit size as taken for scaling of the entire vert_group or hor_group, respectively. This value can be a non_zero_real or 'inf' (for infinity). A specification of the unit size in a first_op_arg temporarily overrides the global value, which may be different from the default 1.0, due to the specification of a different value for attribute 'size' in a preceding switch.

first_op_arg ->
	op_arg |
	'size=' unit_size 
unit_size ->
	non_zero_real |

There are different types of basic_group, which we will discuss one by one below.

basic_group ->
	named_glyph |
	empty_glyph |
	box |
	stack |
	insert | 

A named_glyph can be named in a number of ways. The name can be a Gardiner code, denoting a glyph from a sign list, or a mnemonic for a sign from that sign list. Only the mnemonics from the 'Manuel de Codage' (1988) are allowed; note that these mnemonics all consist of lower-case and upper-case letters (see the definition of name below), with the exception of '10' and '100'.

The name of a glyph can also be 'open' or 'close', which stand for the unconnected opening and closing 'brackets' of cartouches, which may but need not appear in pairs. These are typically used in the transcription of hieratic.

Lastly, a named_glyph can also represent a modern character, given in a short_string. Such characters will most commonly be single square, round or angled brackets. Other use is strongly discouraged, all the more since the characters will appear mirrored in the case of a right-to-left direction. (This does not hold for modern characters in notes; see below.)

A named_glyph can be changed by the argument 'mirror', which mirrors horizontally, and by the attribute 'rotate', which specifies rotation in degrees; e.g. 'rotate=90' means a quarter turn clock-wise. Rotation takes place after mirroring. The argument 'nomirror' temporarily overrides the global value for mirroring.

The attribute 'scale' can be used to change the normal size of the glyph by the indicated factor; the default value is 1.0. The attribute 'xscale' only scales horizontally, and the attribute 'yscale' only vertically. For example, 'xscale=0.5' makes a glyph half as wide. One can use 'scale' in combination with both 'xscale' and 'yscale', but one would not normally use 'xscale' and 'yscale' at the same time. Scaling takes place before rotation.

For color and shading see further below.

A named_glyph can be followed by zero or more notes. Any switches at the end of a named_glyph must occur after those notes.

named_glyph -> 
	glyph_name [ named_glyph_arg-bracketed_list ]
		whitespaces notes switches

glyph_name -> 
	category non_zero_natural_number [ lower_letter ] |
	mnemonic |
	'open' |
	'close' |
mnemonic ->
	'mSa' | 'xr' | 'Xrd' | 'sr' | 'mniw' | ...
category ->
	'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' |
	'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' |
	'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' | 'Aa'

named_glyph_arg ->
	'mirror' |
	'nomirror' |
	'rotate=' natural_number |
	'scale=' non_zero_real |
	'xscale=' non_zero_real |
	'yscale=' non_zero_real |
	color |

An empty_glyph can be used to represent shaded areas, or additional white space between glyphs. The (unscaled) dimensions can be specified by attributes 'width' and 'height', of which the default values are 1.0. The scaling algorithm may reduce these dimensions, just like in the case of named_glyphs.

A point glyph '.' is shorthand for 'empty[width=0,height=0]'. It can be useful at the beginning or end of a vert_group or hor_group, when the first or last of the actual vert_sub_groups or hor_sub_groups are not to be placed against the bounding box of the larger group.

The argument 'firm' indicates that the surface of the empty_glyph, as determined by the values for the attributes 'width' and 'height', should be treated as non-white for the purposes of fitting; see the argument 'fit' in the definition of op_arg.

An empty_glyph can be followed by at most one note.

empty_glyph -> 
	'empty' [ empty_glyph_arg-bracketed_list ]
		whitespaces [ note ] switches |
	'.' whitespaces [ note ] switches
empty_glyph_arg ->
	'width=' real |
	'height=' real |
	shade_arg |

A box differs from a glyph in that its exact dimensions, in particular the ratio between its height and width, are not fixed but are determined by the dimensions of the optional hieroglyphic that it encloses. Just as the collection of glyphs is not a closed set, there is no natural bound to the collection of box_types that one may need. We assume however that each implementation is at least capable of handling 'cartouche', 'oval' (which is like a cartouche but without the bar at the end), 'serekh' (see p. 72 of Gardiner's Egyptian grammar), 'inb' (cf. O15 from the sign list), 'rectangle', 'Hwtopenover', 'Hwtopenunder', 'Hwtcloseover' and 'Hwtcloseunder'. The last four are similar to 'rectangle' except that there is a square in one of the four corners (cf. O10 from the sign list); the corners are indicated by a combination of 'open' or 'close' and 'over' or 'under', of which the interpretation depends on the direction (see below).

A particular font may provide further box_types. Each box_type is a name different from 'empty', 'stack', 'insert' and 'modify', which were reserved for other purposes.

Note that in the optional hieroglyphic, we may find occurrences of the operator '-', which is interpreted depending on whether the direction is horizontal or vertical, as we have already explained above. By default, the direction of a box and the hieroglyphic in it matches the normal direction determined by the header. By specifying a box_direction, one may choose a different direction. E.g. if the normal text direction is horizontal, then with argument 'v' the text direction of the hieroglyphic inside the box is vertical, and the opening and closing parts are at the top and bottom. Specifying 'v' when the normal text direction is already vertical has no effect. The arguments 'v' and 'h' are mutually exclusive. In the case of embedded box_types, the direction of the outer occurrence does not influence the choice of the direction for the inner occurrence.

The arguments 'mirror' and 'nomirror' have the same meaning as in the case of named_glyphs, namely horizontal mirroring, but this only applies to the boundaries of the box and not to its contents.

Assuming the direction is horizontal (vertical, respectively), the unscaled height (width) of a box depends on the height (width) of the box segments as specified in the font; this is normally 1.0. This can be changed by specifying a value for attribute 'scale'; its default is 1.0.

The color pertains to the boundaries of the box and not to its contents. If no argument color is specified, the global value in effect at the start of the box is taken.

A shade_arg is interpreted as usual, but does not actually lead to shading of the part of the surface that the hieroglyphic inside the box covers; for this, the encoding of the hieroglyphic itself should specify shading.

The attribute 'size' has a similar meaning as the attribute with the same name in the header, but it now refers to the hieroglyphic inside the box. The default for 'size' is 1.0, irrespective of the value set in the header.

For the minimal distance between the boundaries of the box and the hieroglyphic inside it, there are four separate modifying factors, indicated by 'opensep' and 'closesep' for the distances at the opening and closing 'brackets' of the box, and 'undersep' and 'oversep' for the distances to the other two boundaries of the box. For example, if the direction is vertically left-to-right, then 'oversep' refers to the right boundary of the box. For all four attributes, the default is the global value for 'sep'. For 'opensep' and 'closesep', we use fitting to determine the exact distance between the brackets and the hieroglyphic, as if an implicit argument 'fit' were specified (cf. the definition of op_arg).

A box can be followed by zero or more notes.

box -> 
	box_type [ box_arg-bracketed_list ] whitespaces
		'(' ws [ hieroglyphic ] ')' 
		whitespaces notes switches

box_type ->
	'cartouche' | 'oval' | 'serekh' | 'inb' | 'rectangle' | 
	'Hwtopenover' | 'Hwtopenunder' | 'Hwtcloseover' | 'Hwtcloseunder' | ...
box_arg ->
	box_direction |
	'mirror' |
	'nomirror' |
	'scale=' non_zero_real |
	color |
	shade_arg |
	'size=' non_zero_real |
	'opensep=' real |
	'closesep=' real |
	'undersep=' real |
	'oversep=' real 

box_direction ->
	'h' |

A stack combines two top_groups by stacking them on top of each other. The 'x' and 'y' attributes (both with default value 0.5) indicate the position in the first top_group where the center of the second top_group is to be located. (The combination of arguments '[x=0,y=0]' represents the top-left (top-right) position and '[x=1,y=1]' represents the bottom-right (bottom-left) position, provided we assume a left-to-right (right-to-left) text direction.)

In the absence of the arguments 'on' or 'under', the curves from the respective two top_groups simply cross each other. In the case of 'on', the 'internal' pixels from the second top_group erase any pixels from the first top_group, excluding shading, so the second top_group can be said to be put on top of the first. In the case of 'under', the second top_group is put under the first.

Shading arguments inside the first top_group pertain to the area that includes at least the virtual bounding box of the entire stack, which is the smallest bounding box that includes the virtual bounding boxes of the two top_groups. Shading arguments of the second top_group only refer to the bounding box of the second top_group.

The use of stacks when the respective glyphs should not physically overlap is discouraged, and instead one should use an insert or the argument 'fit' at an operator.

stack -> 
	'stack' [ stack_arg-bracketed_list ] whitespaces
		'(' ws top_group ',' ws top_group ')' ws
stack_arg ->
	'x=' low_real |
	'y=' low_real |
	'on' |

Insertion allows the combination of two top_groups by positioning the second somewhere within the (virtual) bounding box of the first. The second is reduced in size with respect to its natural size as little as possible (it can never appear larger than the natural size), within the constraints described below.

One such constraint is that the minimal distance between a non-blank pixel from the first top_group and the second top_group is at least that specified by the 'sep' attribute if present, or the corresponding global value otherwise.

A second constraint is dictated by at most one argument from among 't', 'b', 's', 'e', 'ts', 'te', 'bs' or 'be' (these attributes are mutually exclusive). The letter 't' stands for top, 'b' for bottom, 's' for start (which means either left or right, depending on whether the text direction is left-to-right or right-to-left) and 'e' for end (which means right or left). Furthermore, 'ts' stands for top-start, etc.

For example, assuming a left-to-right direction, if there is an argument 's' then the left boundaries of the bounding boxes of both top_groups are located on the same line. Scaling and positioning can be realized as follows. Initially, the second top_group is made very small, and placed at the middle of the left boundary of the first top_group. It is then increased in size and possibly floats up or down if that allows the second group to be increased further in size.

If the initial vertical position is not to be at the middle of the left boundary of the first top_group, then one may specify a value between 0 and 1 for the attribute 'y', whose default value is 0.5. So, 's,y=0' means the second top_group is initially placed at the top-left corner, and 's,y=1' means it is initially placed at the bottom-left corner. With the arguments 's' and 'e', the value for attribute 'x' is ignored.

As another example, 'te' specifies that the second top_group is to be put in the top-right corner of the first top_group; as before, it is increased in size within the constraints of the minimal distance between non-blank pixels. The attributes 'x' and 'y' are ignored.

If no place is specified, then the second top_group is initially placed at the coordinates specified by the values for 'x' and 'y', which default to 0.5, as already mentioned. This means that if no arguments at all are specified, the second top_group is initially placed in the middle of the first top_group, then increased in size while it may float in all four directions, if that helps increasing it in size.

If there is to be no floating, and the second top_group should stay exactly at the specified 'x' and/or 'y' coordinates, then the argument 'fix' should be added. Note that in the case of the arguments 'ts', 'te', 'bs' and 'be', the values for 'x' and 'y' are ignored, and correspondingly in this case also the argument 'fix' is ignored.

insert -> 
	'insert' [ insert_arg-bracketed_list ] whitespaces
		'(' ws top_group ',' ws top_group ')' ws
insert_arg ->
	place |
	'x=' low_real |
	'y=' low_real |
	'fix' |
	'sep=' real 

place ->
	't' | 'b' | 's' | 'e' | 'ts' | 'te' | 'bs' | 'be' 

If the function modify is applied on a top_group without arguments, the top_group is simply scaled, without constraints on the width or height. If however values are specified for the attributes 'width' and/or 'height', the top_group is scaled down if it is larger than those given dimensions, and extra filling space is added if it is smaller.

In some situations it can be desirable to scale and position a top_group not according to its physical bounding box that tightly encloses its pixels, but according to a smaller 'virtual' bounding box. This can be achieved by specifying values for one or more from the attributes 'above', 'below', 'before' and 'after', which all have 0 as default. By specifying non-zero values, the scaling algorithm pretends that the top_group is smaller than what its normal bounding box would be, and some of its pixels may fall outside this virtual bounding box. Note this normal bounding box of the top_group is scaled as usual, possibly under the influence of values specified for the attributes 'width' and/or 'height'.

For example, 'above=2' states that the part of the normal bounding box above the virtual bounding box is twice as high as the height of the virtual bounding box, and 'before=1' makes the top_group appear to the scaling algorithm to be only half the width it actually is, and the other half 'sticks out' before the virtual bounding box. (i.e. at the left or right depending on the direction).

With the argument 'omit', the part of the top_group that falls outside the virtual bounding box is erased. This can be used for printing parts of glyphs. However, the normal bounding box keeps its size, in particular with respect to the area affected by shading. Furthermore, notes inside the top_group should be printed irrespective of the argument 'omit'.

The shade_args in the modify_arg-bracketed_list differ from similar arguments within the top_group in that only the area of the virtual bounding box is affected. The shading arguments within the top_group are applied as usual, and may shade areas outside the virtual bounding box.

The function modify should be used with care, since it may lead to undesirable overlapping of glyphs.

modify ->
	'modify' [ modify_arg-bracketed_list ] whitespaces
		'(' ws top_group ')' ws

modify_arg ->
	'width=' non_zero_real |
	'height=' non_zero_real |
	'above=' real |
	'below=' real |
	'before=' real |
	'after=' real |
	'omit' |

A named_glyph or box can be followed by zero or more notes, and an empty_glyph can be followed by at most one note. Typically, the string in a note contains a footnote marker or a short word such as in 'A1^"sic"'. The implementation is to place the sequence of characters of a note somewhere near to the named_glyph or box to which it refers. In the case of an empty_glyph, the note is to be placed near to its center, or if it is shaded it can also be placed close to that shaded area. The placement of notes can be influenced by the scaling and positioning of the glyphs, but conversely notes should not influence scaling and positioning of glyphs.

Unlike a modern character in a short_string (cf. the definition of named_glyph), the sizes of the characters in a note are fixed and are determined by the application. Another difference is that the color is not affected by the global value for color; unless there is a color argument, the color is always the same implementation-defined color, usually black. Furthermore, in the case of right-to-left directions, the characters are not mirrored.

Having several long notes after a relatively small named_glyph can pose unsurmountable problems for any realistic implementation. It is therefore up to the encoder to make conscientious use of notes.

notes ->
	( note )*
note ->
	'^' string [ note_arg-bracketed_list ] whitespaces

note_arg ->

The combination of whitespaces followed by switches is indicated by ws. White space is allowed anywhere it could be desirable to improve readability, except before an optional bracketed list, after the operator '^', and before and after '=' in arguments.

Anywhere one can have white space, one can also have switches, except before a header, within a bracketed list, before a round open bracket belonging to a function, and before a note.

ws ->
	whitespaces switches

A switch is used to change global values for color, shading, the 'sep' factor that modifies the distances between glyphs and groups of glyphs and related objects, fitting, and mirroring. At the beginning of the fragment, these five values are black for color, 'off' for shading, 1.0 for the 'sep' factor, 'off' for 'fitting', and 'off' for 'mirroring'.

A color argument in a switch sets the global color to that color. The argument 'shade' sets shading to 'on', even if it was already 'on'; the argument 'noshade' sets it to 'off' even if it was already 'off'. The same rules apply to the arguments 'fit' and 'nofit', and to the arguments 'mirror' and 'nomirror'. A value for attribute 'sep' changes the modifying factor.

As usual, in the case of conflicting arguments, the last such argument overrides the previous ones. This also holds for consecutive switches. For example, '![red,shade,sep=0.5] ![blue,noshade,green] ![sep=1.2]' is equivalent to '![green,noshade,sep=1.2]'.

Note that since the switch_arg-bracketed_list after the exclamation mark is optional (as are all types of bracketed list), a switch may also simply be '!'. This has no other interpretation than as a marker to the (human) reader of the encoding.

switches ->
	( switch )*

switch ->
	'!' [ switch_arg-bracketed_list ] whitespaces

switch_arg ->
	color |
	'shade' |
	'noshade' |
	'sep=' real  |
	'fit' |
	'nofit' |
	'mirror' |

Sixteen colors are allowed that make up a common collection of colors frequently used e.g. in web browsers. For most purposes, one will only need 'black' and 'red'. The color 'white' can be used to make an invisible glyph, or in other words, white space exactly as large as a certain glyph. Such glyphs should however be treated as if they were non-white for the purpose of 'fitting'; see the argument 'fit' in the definition of op_arg.

The other colors have been added to allow marking of glyphs according to e.g. syntactic annotation. It is recommended to have the mapping from annotation to color done by automatic means, rather than to hand-code the colors of individual glyphs.

color -> 
	'black' | 'red' | 'green' | 'blue' | 'white' | 
	'aqua' | 'fuchsia' | 'gray' | 'lime' | 'maroon' | 'navy' | 
	'olive' | 'purple' | 'silver' | 'teal' | 'yellow'

The entire area of a line or column of hieroglyphic is covered by bounding boxes of glyphs and related objects, and by the white space that corresponds to operators. At each of these objects we may indicate shading of the corresponding sub-area.

Such a sub-area may also be partitioned into smaller areas by means of shade_patterns. These are strings that are interpreted from left to right, and each letter divides the area in two: 't' takes the top half of the current area to be the new area, 'b' takes the bottom half, 's' the left (right) half for left-to-right (right-to-left) text directions, and 'e' the right (left) half. The area resulting at the end of the shade_pattern is shaded.

Any shade_arg at an object overrides the global value for shading. The main purpose for the argument 'noshade' is to indicate the present object is not to be shaded if the global value is 'on'.

With the exception of shade and noshade, the shade_args are not mutually exclusive. This means that an area is shaded if at least one occurrence of a shade_arg in a bracketed list indicates it is to be shaded. E.g. [noshade,t,s] is equivalent to [s,t] and [ts,te,bs].

shade_arg ->
	'shade' |
	'noshade' |

shade_pattern ->
	( side )+

side ->
	't' | 'b' | 's' | 'e'

An occurrence of an operator such as '-', a name of a glyph such as 'A1', a function name such as 'stack', etc., may all be followed by an X-bracketed_list, where X is a place-holder for a nonterminal defined above.

A bracketed list contains zero or more arguments. Such an argument may consist of a single name, such as in 'A1[mirror]' or 'A1[shade]', or it may consist of an attribute followed by '=' followed by an attribute value, as in 'A1[rotate=200]' or 'A1[scale=0.5]'.

In one bracketed list, if there are pairs of arguments that are mutually exclusive, the last such arguments overrides all others. E.g. 'A1[black,red]' is treated as 'A1[red]' and 'A1[shade,noshade]' is treated as 'A1[noshade]'.

Apart from mutually exclusive arguments, the order of arguments in a bracketed list is irrelevant. E.g. 'A1[red,mirror]' is equivalent to 'A1[mirror,red]'.

X-bracketed_list -> 
	'[' whitespaces X-list ']' |
	'[' whitespaces ']'
X-list -> 
	X whitespaces ( ',' whitespaces X whitespaces )*

White space does not have any other purpose besides improving readability.

whitespaces -> 
	( whitespace )*
whitespace -> 

Auxiliary definitions

Various general definitions follow.

A natural_number represents an integer between 0 and 999. It is used for specifying degrees of rotation. Numbers higher than 359 are taken modulo 360.

natural_number ->
	digit |
	non_zero_digit digit |
	non_zero_digit digit digit

A non_zero_natural_number represents an integer between 1 and 999. Such numbers are part of named_glyphs consisting of Gardiner codes.

non_zero_natural_number ->
	non_zero_digit |
	non_zero_digit digit |
	non_zero_digit digit digit

A real represents a real number between 0.00 to 9.99. If the denotation includes the decimal dot '.', this must be followed by one or two digits.

real ->
	digit |
	[ digit ] '.' digit [ digit ]

A non_zero_real can be any real, except those denoting zero.

non_zero_real ->
	non_zero_digit |
	non_zero_digit '.' digit [ digit ] |
	[ '0' ] '.' non_zero_digit [ digit ] |
	[ '0' ] '.' '0' non_zero_digit

A low_real can be any real, except those denoting reals strictly larger than 1.0.

low_real ->
	'0' |
	'1' |
	[ '0' ] '.' digit [ digit ] |
	'1' '.' '0' [ '0' ]

Digits, and digits except zero.

digit -> 
	'0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
non_zero_digit -> 
	'1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'

There is no use of name in the above productions, but we include it since typical software may need it for processing mnemonics and names of arguments and attributes. Furthermore, box_types must be names.

name -> 
	( letter )+

The following enumerates the letters that may occur in names. The lower_letters may also be parts of Gardiner codes.

letter -> 
	lower_letter | 
lower_letter ->
	'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' |
	'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' |
	's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z'
upper_letter ->
	'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' |
	'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' |
	'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z'

A string consists of a double-quote followed by one or more graphs (other than double-quote or backslash) or space, followed by another double-quote. Note that we exclude formfeed, newline, carriage return, tab and vertical tab. We will also assume that the soft hyphen is excluded. A double-quote inside a string is represented by a backslash followed by a double-quote, and a backslash inside a string is represented by a sequence of two backslashes. A short_string is a string of length 1.

Implementations should at least be able to handle ASCII characters (by default, we assume the Latin 1 character set, i.e. ISO 8859-1, or possibly Latin 9, i.e. ISO 8859-15), but one may consider extending this to Unicode in the future. Implementations are to ensure that the unscaled height of square bracket '[' used as short_string equals 1 EM; the unscaled sizes of other characters used as short_strings should be proportional to that as determined by the font. For strings, the font size may be freely chosen by the implementation.

string ->
	'"' ( printable )+ '"' 

short_string ->
	'"' printable '"'
printable ->
	' ' |