Pattern-based Text Generator
The usage of PTG Patterns functions is a very flexible way to construct
the output of a program. However, some
desirable effects can not be achieved using
pattern functions only:
- Pretty Printing
- A pattern function does not have access to the current
column position. Therefore, it cannot know where to insert line breaks to
get the output formatted properly.
- Output destination
- It can be desirable to write the output of PTG patterns to a destination
other than a file,
for example to redirect the output into a
string buffer or to postprocess the output through a filter.
To solve such tasks, PTG does not write its output directly into a
file. Instead, a set of macros is defined that can be adjusted to change
the behavior of PTG. If these macros are not defined, PTG supports default
definitions that process the contents of a PTGNode into a named file or a
given file pointer. In the following, those macros are
explained and small examples are given:
PTG_OUTPUT_FILE
- This macro defines the type name of the
file parameter of the
other macros, the output functions defined in Output Functions, and the function
call insertions. If no definition is supplied, its value is defined to be
FILE * . Its value must be assignable by the C-operator
= . If the definition of PTG_OUTPUT_FILE is changed,
a suitable definition for PTG_OUTPUT_STRING
must also be provided.
PTG_OUTPUT_STRING(file,param)
- This macro is called to write a string value into an output file.
It is used by default for every text written by PTG.
Hence, redefining this macro suffices to change the default
behavior of PTG, for instance to support pretty printing.
This macro has to be redefined if
PTG_OUTPUT_FILE is redefined.
PTG_OUTPUT_INT(file,param)
PTG_OUTPUT_SHORT(file,param)
PTG_OUTPUT_LONG(file,param)
PTG_OUTPUT_CHAR(file,param)
PTG_OUTPUT_FLOAT(file,param)
PTG_OUTPUT_DOUBLE(file,param)
- These macros are used to write typed insertions into
an output file. By default, they are set up in a way that they convert
their second argument into a string and call
PTG_OUTPUT_STRING
to process the output. So, when redefining PTG_OUTPUT_FILE ,
you need not to supply a definition for these macros.
Of course, there may be more efficient ways to output values of the various
data types other than to convert them into strings and send the result
to the string handling function. If you want to supply such an alternative
for writing characters, for example, redefine the default behavior of
PTG_OUTPUT_CHAR to print the character directly. These macros are
provided for efficiency purposes only.
To override the default implementations for these macros, implement a
substitution function in a type .c file. Include the file
ptg_gen.h to supply your new function with definitions for the other
macros, especially PTG_OUTPUT_FILE . Write cpp directives
that define the desired macro(s) into a type .ptg.phi file and include
it in your specification. Eli will then concatenate all those definitions
and supply it as a header file ptg.h to your processor.
As an application of these macros, the following section shows a
simple and easy way to implement pretty printing of the output generated
by PTG.
Sometimes it is necessary to postprocess PTG generated output. For example,
the length of the generated output lines may be limited by an upper bound,
so that certain restricted tools can process the output.
Without postprocessing of the output, there is no way to determine the
current position in a line for a PTG structure being written.
Hence, we adapt the definitions of the output macros to solve that task.
As all output is finally handled by the macro
PTG_OUTPUT_STRING , it is sufficient to modify it such that
it controls the current position in the line. With some more effort, it
would be possible do complete line breaking by buffering one line of output
and looking for suitable break points when the end of the line is encountered.
The following code keeps track of the current column position and implements
a function, that conditionally inserts a line break if the line is longer
than 65 chars.
linepos.c[22]==
#include <string.h>
#include "ptg_gen.h"
static col = 0;
void InitCol(void)
{
col = 0;
}
void OutputLine(FILE *f, char *s)
{
int l;
char *nl;
if (!s) return;
l = strlen(s);
nl = strrchr(s, '\n');
if (!nl)
col += l;
else
col = (l - 1 - (nl - s));
fputs(s, f);
}
void CondNl(FILE *f)
{
if (col > 65)
OutputLine(f, "\n");
}
This macro is attached to a product file.
The function InitCol serves as initialization, if more than one
output file should be generated. The function CondNl inserts a
line break, if the current line is longer than 65 characters. The
function OutputLine overrides the default implementation of
PTG_OUTPUT_STRING .
linepos.ptg.phi[23]==
#define PTG_OUTPUT_STRING(file,param) OutputLine(file,param)
This macro is attached to a product file.
This can be used for example in the following PTG specification:
linepos.ptg[24]==
CommaSeq: $ ", " [CondNl] $
This macro is attached to a product file.
Now, in a large iteration of calls to PTGCommaSeq() , a line break
is inserted automatically, if a line exceeds 65 characters.
Using the online documentation, one can obtain a copy of the attached files.
|