Defining a new C main() function
Author: Daniel Diaz
Keywords: GNU Prolog, manual, Prolog, compiler, constraints, finite domains

### 10.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 7.1.11). 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 7.1.14). 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 4.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.

#### 10.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-2021 Daniel Diaz Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved. More about the copyright