A recurring problem with C++ consists of the fact that different compilers may have somewhat different ways of instantiating templates. ComPact addresses this situation by means of its own, built-in template mechanism. By using it, you can gain complete control of when and how instantiation takes place. In fact, it is possible to avoid most practical applications of compiler-driven instantiation altogether. Software production in heterogenous development environments, thereby, looses one of its more notorious impediments.
The idea is to provide a general, language-independent way of making a source file generic. On the file level, what you must do consists of inserting a header with a syntax of
/* comment */
// comment
`TEMPLATE' `@'FormalName `<' `@'FormalParam [ ( `,' `@'FormalParam ) + ] `>'
`RECURSIVE' `(' `)'
where FormalName and each instance of
FormalParam are unquoted identifiers.
ComPact parses up to and including the end of the line
containing the closing bracket of the recursion statement.
Whenever a template is instantiated, that what has been
parsed is removed and, at the same time, all subsequent
occurences of @FormalName are
replaced by an actual name. Likewise, actual paramaters
replace all subsequent occurences of a formal parameter that
are directly preceded by @. The
substitution is entirely syntactic. In particular, it is
un-affected by whether something is source code, a comment,
or a compiler directive. The empty recursion statement has to be present to provide compatibility with future releases of ComPact.
The intended use of the template mechanism is such that generic C/C++ header and source code files are written as if they were non-generic. Apart from the header, the only difference is the occurrence of strings preceded by @, which are to be so substituted as to generate proper C/C++ code. An example of such a generic module can be found as part of the distribution.
The remainder of this chapter is concerned with template handling on the package description level. First of all, the syntax of declaring generic files and modules is as expected:
Decl ::= C-GenericHeaderDecl
| C-GenericSourceDecl
| C-GenericModuleDecl
| CC-GenericHeaderDecl
| CC-GenericSourceDecl
| CC-GenericModuleDecl
C-GenericHeaderDecl ::= `c_generic_header' '(' PathParam [ ExpDecl ] ')' NL
C-GenericSourceDecl ::= `c_generic_source' '(' PathParam [ ExpDecl ] ')' NL
C-GenericModuleDecl ::= `c_generic_module' '(' FileParam [ ExpDecl ] ')' NL
CC-GenericHeaderDecl ::= `cc_generic_header' '(' PathParam [ ExpDecl ] ')' NL
CC-GenericSourceDecl ::= `cc_generic_source' '(' PathParam [ ExpDecl ] ')' NL
CC-GenericModuleDecl ::= `cc_generic_module' '(' FileParam [ ExpDecl ] ')' NL
To instantiate a generic file or module, what you must do consists of supplying its name, the name of the new file or module, and a list of substitution pairs, each one being of the form IdentParam `:=' IdentParam. The first IdentParam is the formal name or parameter stated without @; the second IdentParam is the actual name or parameter. Note that the formal name must be substituted at the beginning. The remaining substitutions must adhere to the order imposed by the header(s) of the generic file or module being instantiated.
Decl ::= C-GenericHeaderInstanceDecl
| C-GenericSourceInstanceDecl
| C-GenericModuleInstanceDecl
| CC-GenericHeaderInstanceDecl
| CC-GenericSourceInstanceDecl
| CC-GenericModuleInstanceDecl
C-GenericHeaderInstanceDecl ::= `c_generic_header_instance' `(' InstantiationData [ ExpDecl ] `)' NL
C-GenericSourceInstanceDecl ::= `c_generic_source_instance' `(' InstantiationData [ ExpDecl ] `)' NL
C-GenericModuleInstanceDecl ::= `c_generic_module_instance' `(' InstantiationData [ ExpDecl ] `)' NL
CC-GenericHeaderInstanceDecl ::= `cc_generic_header_instance' `(' InstantiationData [ ExpDecl ] `)' NL
CC-GenericSourceInstanceDecl ::= `cc_generic_source_instance' `(' InstantiationData [ ExpDecl ] `)' NL
CC-GenericModuleInstanceDecl ::= `cc_generic_module_instance' `(' InstantiationData [ ExpDecl ] `)' NL
InstantiationData ::= PathParam `,' PathParam `,' SubstitutionList NL SubstitutionList ::= SubstitutionPair [ `,' SubstitutionList ] SubstitutionPair ::= IdentParam `:=' IdentParam IdentParam ::= TokenOrString
To perform the actual instantiation, ComPact invokes a utility called instgen (cf. Chapter 6). To see how instgen is used, you might want to type instgen -h. Currently, the syntax is very simple:
instgen source target formalname actualname [formalpar actualpar ...]