Defining a new C main() function

### 9.7 Defining a new C `main()` function

- Example: asking for ancestors

GNU Prolog allows the user to define his own `main()` function. This can be useful to perform several tasks before starting the Prolog engine. To do this simply define a classical `main(argc, argv)` function. The following functions can then be used:

      int    Pl_Start_Prolog         (int argc, char *argv[])
      void   Pl_Stop_Prolog          (void)
      void   Pl_Reset_Prolog         (void)
      PlBool Pl_Try_Execute_Top_Level(void)

The function `Pl_Start_Prolog(argc, argv)` initializes the Prolog engine (`argc` and `argv` are the command-line variables). This function collects all linked objects (issued from the compilation of Prolog files) and initializes them. The initialization of a Prolog object file consists in adding to appropriate tables new atoms, new predicates and executing its system directives. A system directive is generated by the Prolog to WAM compiler to reflect a (user) directive executed at compile-time such as `op/3` (section 6.1.10). Indeed, when the compiler encounters such a directive it immediately executes it and also generates a system directive to execute it at the start of the executable. When all system directives have been executed the Prolog engine executes all initialization directives defined with `initialization/1` (section 6.1.13). The function returns the number of user directives (i.e. `initialization/1`) executed. This function must be called only once.

The function `Pl_Stop_Prolog()` stops the Prolog engine. This function must be called only once after all Prolog treatment have been done.

The function `Pl_Reset_Prolog()` reinitializes the Prolog engine (i.e. reset all Prolog stacks).

The function `Pl_Try_Execute_Top_Level()` executes the top-level if linked (section 3.4.3) and returns `PL_TRUE`. If the top-level is not present the functions returns `PL_FALSE`.

Here is the definition of the default GNU Prolog `main()` function:

      static int
      Main_Wrapper(int argc, char *argv[])
      {
        int nb_user_directive;
        PlBool top_level;

        nb_user_directive = Pl_Start_Prolog(argc, argv);

        top_level = Pl_Try_Execute_Top_Level();

        Pl_Stop_Prolog();

        if (top_level || nb_user_directive)
          return 0;

        fprintf(stderr,
                "Warning: no initial goal executed\n"
                "   use a directive :- initialization(Goal)\n"
                "   or remove the link option --no-top-level"
                " (or --min-bips or --min-size)\n");

        return 1;
      }

      int
      main(int argc, char *argv[])
      {
        return Main_Wrapper(argc, argv);
      }

Note that under some circumstances it is necessary to encapsulate the code of `main()` inside an intermediate function called by `main()`. Indeed, some C compilers (e.g. gcc) treats `main()` particularly, producing an incompatible code w.r.t GNU Prolog. So it is a good idea to always use a wrapper function as shown above.

#### 9.7.1 Example: asking for ancestors

In this example we use the following Prolog code (in a file called `new_main.pl`):

      parent(bob,   mary).
      parent(jane,  mary).
      parent(mary,  peter).
      parent(paul,  peter).
      parent(peter, john).

      anc(X, Y):-
              parent(X, Y).

      anc(X, Z) :-
              parent(X, Y),
              anc(Y, Z).

The following file (called `new_main_c.c`) defines a `main()` function read the name of a person and displaying all successors of that person. This is equivalent to the Prolog query: `anc(Result, Name)`.

      static int
      Main_Wrapper(int argc, char *argv[])
      {
        int func;
        PlTerm arg[10];
        char str[100];
        char *sol[100];
        int i, nb_sol = 0;
        PlBool res;

        Pl_Start_Prolog(argc, argv);

        func = Pl_Find_Atom("anc");
        for (;;)
          {
            printf("\nEnter a name (or 'end' to finish): ");
            fflush(stdout);
            scanf("%s", str);

            if (strcmp(str, "end") == 0)
       break;

            Pl_Query_Begin(PL_TRUE);

            arg[0] = Pl_Mk_Variable();
            arg[1] = Pl_Mk_String(str);
            nb_sol = 0;
            res = Pl_Query_Call(func, 2, arg);
            while (res)
       {
         sol[nb_sol++] = Pl_Rd_String(arg[0]);
         res = Pl_Query_Next_Solution();
       }
            Pl_Query_End(PL_RECOVER);

            for (i = 0; i < nb_sol; i++)
       printf("  solution: %s\n", sol[i]);
            printf("%d solution(s)\n", nb_sol);
          }

        Pl_Stop_Prolog();
        return 0;
      }

      int
      main(int argc, char *argv[])
      {
        return Main_Wrapper(argc, argv);
      }

The compilation produces an executable called `new_main`:

  `% gplc new_main.pl new_main_c.c`

Examples of use:

      Enter a name (or 'end' to finish): john
        solution: peter
        solution: bob
        solution: jane
        solution: mary
        solution: paul
      5 solution(s)

      Enter a name (or 'end' to finish): mary
        solution: bob
        solution: jane
      2 solution(s)

      Enter a name (or 'end' to finish): end

Copyright (C) 1999-2009 Daniel Diaz Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved. More about the copyright