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;
}