Syntax and Semantics of MetaC by Example
/* the following
is a metaprogram that adds
control flow tracing */
#include
"internal.mh" /*
here compiler internal metafunctions are declared */
/*
This metafuction will add
code for control flow tracing
* of branches within functions for a single function passed as
* parameter my_func with the new metadata type func, which
* represents a function.
*/
meta void
trace_branch_entries(func my_func)
{
/* The
following defines an array of statements called all_brances.
* Be
aware that MetaC arrays grow in size when the element after
* the
last element is accessed. This is an extension to ISO-C99 for
* meta-functions. ISO-C99
has undefined behaviour for this operation.
*
Additionally, a pointer to meta-data-type statement is defined
*
called branch.
*/
stmt
all_branches[], *branch;
strg msg; /*
the meta-data-type strg represents
string literals */
msg = "entering
branch of " + ((strg) my_func);
msg += " at line
%i\n";
/*
The
following line defines a statement code-structure-pattern,
* which will be used to
instantiate code at the branches in
* control flow.
*/
new_stm
:=
printf(msg,l);
/*
now ask
the compiler for all branches within function my_func */
$get_all_branches(my_func,all_branches);
branch =
all_branches;
while (*branch) {
/*
The following line defines a
variable of metadatatype symbol,
* which can refer to a declaration with an identifier and type
*/
symb l =
$get_symbol("__LINE__");
/* insert code at the beginning of branch, pointed
to by branch */
$begin(codeof
new_stm,*branch);
++branch;
}
}
/*
This is
the $main entry point of the meta-program. It
*
gets
its parameters as array of string litterals, by
*
convention.
*/
meta void $main(strg
arg[])
{
{
func functions[], *f =
functions;
$get_all_functions(functions);
while (*f) {
trace_branch_entries(*f);
++f;
}
}
/* This is the C source code of the program we want to instrument. */
/*
Code in bold fase has been inserted by the metaprogram
during execution in the MetaC compiler. */
extern
int strlen(const char *);
extern int printf(const
char *, ...);
void
handle_args(char *arg)
{
if ((strlen(arg) == 2)
&& (arg[0] == '-')) {
printf("entering
branch of handle_args at line %i\n", 6);
switch (arg[1]) {
case 'a': {
printf("entering
branch of handle_args at line %i\n", 9);
printf("argument a\n");
}
break;
case 'e': {
printf("entering
branch of handle_args at line %i\n", 14);
printf("argument e\n");
}
break;
default: {
printf("entering
branch of handle_args at line %i\n", 19);
printf("unknown argument\n");
}
}
} else {
printf("entering
branch of handle_args at line %i\n", 24);
printf("parameter: %s\n", arg);
}
}
int
main(int argc, char **argv)
{
if (argc > 1) {
int i = 1;
printf("entering
branch of main at line %i\n", 33);
for (int x = argc - 1; x > 0; --x) {
printf("entering
branch of main at line %i\n", 35);
printf("arg[%i] = \"
%s\"
\n", i, argv[i]);
handle_args(argv[i]);
++i;
}
} else {
printf("entering
branch of main at line %i\n", 43);
printf("no arguments");
}
return 0;
}