* introduction
this docuements outlines a rather simple sourcecode preprocessing method of which
you can gain tremendous benefits from if used creatively (anyone said properly ?).
the idea is to to use the includefile concept, except we define our includes directly
in our files that we use them from (or in friendly units).
we define our includes in a "$template name <templateparamn> begin .. end" fashion inside
multiline comments. our templates output will be emedded in the original sourcecode
where the templateinstanciation or call was made. template parameters are strings
or identifiers (or expressions, pieces of code, pieces of templatefragments (!)) that
will replace their equal identifier in the templatefragment (ie, the caller renames
the parameter specific tokens as it emits the code).
* implementation hints
we're simple people so we keep it simple. preprocessing needs to be fast in amount
of thruput code, but the thruput of actual code that need to be processed is likely
to be rather low (and if not, at least we bypass that dreary XXX parser :p).
1 ) parse sourcefiles to tokenlist, you don't have to be very accurate, you just need to
get the the big picture like template/fragment header, the code block and be able to
replace identifiers.
2) parse the tokenlist for templateheaders and copy them to separate tokenlists and
store suitable description (like the templateheader in programmable form).
3) parse the tokenlist for template instantiation. for each occurace, replace the
call in the source with the directive driven template engine (simple implementation).
template engine, for now a simple substitution engine which is interfaced from an
intermediate api. can defer type if symbol and typetables are presented, but due to the
nature of this research it's more interesting to let the user specify everything to
allow for greater compiler/language abstraction.
* some further ideas
building on the $template name <t0, .., tn> we can add specific typing when we
call our fragmentcode generation by some substring approach ala the following:
templateinclude("min<a:byte, b:single, dst:single>");
it is unsure at the moment why this would be useful, but perhaps it would be nice to
perform ifdefs and conditional program output on template parameter types
{
* sourcecode (note: tailored and formatted for presentation, not compilable)
- "{" is the usualy multiline comment initiator character, whatever content between
that and "}" is considered being directives and comments only, unless the preprocess
overrides this for level 1 pascal parsing.
- {$define} & {$undef} inside a comment is processed by preprocessor only, not the compiler
- $ifdef will cause the preprocessor to emit or process anything between it and the
following $endif only if the token it queries for is defined.
}
{
// define blend operator fragment to blend between two floating point values
$template genericblendop <src0, src1, dst, factor, operator>
begin
{$define operator}
// replace dst with linear blend between src and dst by factor
{$ifdef src_alpha__one_minus_src_alpha}
dst := (src0 * factor) + ((1 - factor) * src1);
{$endif}
// passhtur define, no changes
{$ifdef zero__one}
dst := src1;
{$endif}
// replace dst with src
{$ifdef one__zero}
dst := src0;
{$endif}
// replace dst with src+dst
{$ifdef one__one}
dst := src0 + src1;
{$endif}
{$undef operator}
end
}
// this code will blend src and dst by some blendoperator and factor and store in dst
procedure testing;
var
src, dst : single;
factor : single;
begin
src := 2;
dst := 8;
factor := 0.5;
// include the code to do a more or less complex code to variables,
// which may have small differences to exactly what we want now, meaning
// that the templaceinclude(..) call will be replaced by inline code (!).
// the call itself is implemented in the library to allow pascal to be
// able to run the code without intercepting delphi makefiles.
templateinclude("genericblendop<src, dst, dst, factor, src_alpha__one_minus_src_alpha>");
end;