5. Template files
It is possible to use calculus to generate an output file from a template input file, template, using the syntax:
calculus
The template file consists of a list of either template directives or source lines containing escape sequences which are expanded by calculus. Template directive lines are distinguished by having @
as their first character. Escape sequences consist of %
following by one or more characters.
There are two template directives; loops take the form:
@loop control .... @end
and conditionals take the form:
@if condition .... @else .... @endif
or:
@if condition .... @endif
where .... stands for any sequence of template directives or source lines.
The control statements in a loop can be primitive
, identity
, enum
, struct
or union
to loop over all the primitive, identity, enumeration structure or union types within the input algebra. Within an enum
loop it is possible to use enum.const
to loop over all the enumeration constants of the current enumeration type. Within a struct
loop it is possible to use struct.comp
to loop over all the components of the current structure. Within a union
loop it is possible to use union.comp
to loop over all the shared components of the current union, union.field
to loop over all the fields of the current union, and union.map
to loop over all the maps of the current union. Within a union.field
loop it is possible to use union.field.comp
to loop over all the components of the current union field. Within a union.map
loop it is possible to use union.map.arg
to loop over all the arguments of the current union map.
The valid condition statements in a conditional are true
and false
, plus comp.complex
, which is true if the current structure or union field component has a complex type (i.e. those for which COPY_
type and DEREF_
type require two arguments), and comp.default
, which is true if the current structure or union field component has a default initialiser value.
A number of escape sequences can be used anywhere. %ZX
and %ZV
give the name and version number of the version of calculus used. %Z
and %V
give the name and version number of the input algebra. %%
and %@
give %
and @
respectively, and %
as the last character in a line suppresses the following newline character.
Within a primitive
loop, %PN
gives the primitive name, %PM
gives the short primitive name and %PD
gives the primitive definition.
Within an identity
loop, %IN
gives the identity name, %IM
gives the short identity name and %IT
gives the identity definition.
Within an enum
loop, %EN
gives the enumeration name, %EM
gives the short enumeration name and %EO
gives the enumeration order, ORDER_
enum. Within an enum.const
loop, %ES
gives the enumeration constant name and %EV
gives its value.
Within a struct
loop, %SN
gives the structure name and %SM
gives the short structure name.
Within a union
loop, %UN
gives the union name, %UM
gives the short union name and %UO
gives the union order, ORDER_
union. Within a union.field
loop, %FN
gives the field name. Within a struct.comp
, union.comp
or union.field.comp
loop, %CN
gives the component name, %CT
gives the component type, %CU
gives the short form of the component type and %CV
gives the default component initialiser value (if comp.default
is true). Within a union.map
loop, %MN
gives the map name and %MR
gives the map return type. Within a union.map.arg
loop, %AN
gives the argument name and %AT
gives the argument type.
As an example, the following template file gives a simple algebra pretty printer:
ALGEBRA %X (%V): /* PRIMITIVE TYPES */ @loop primitive %PN (%PM) = "%PD"; @end /* IDENTITY TYPES */ @loop identity %IN (%IM) = %IT; @end /* ENUMERATION TYPES */ @loop enum enum %EN (%EM) = { @loop enum.const %ES = %EV, @end }; @end /* STRUCTURE TYPES */ @loop struct struct %SN (%SM) = { @loop struct.comp %CT %CN; @end }; @end /* UNION TYPES */ @loop union union %UN (%UM) = { @loop union.comp %CT %CN; @end } + { @loop union.field %FN->{ @loop union.field.comp %CT %CN; @end }; @end }; @end