새 C main() 함수 정의

새 C main() 함수 정의

사용자 정의 C main() 함수를 작성하는 방법을 설명해요.

출처: GNU Prolog Manual - Defining a new C main() function

본문

GNU Prolog는 사용자가 자신의 main() 함수를 정의할 수 있게 해줘요. 이는 Prolog 엔진을 시작하기 전에 여러 작업을 수행하는 데 유용할 수 있어요. 이를 위해 간단히 고전적인 main(argc, argv) 함수를 정의하면 돼요. 그러면 다음 함수들을 사용할 수 있어요:

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)
  • Pl_Start_Prolog(argc, argv) — Prolog 엔진을 초기화(argc와 argv는 명령줄 변수). 이 함수는 모든 연결된 객체(Prolog 파일 컴파일에서 나온)를 수집하고 초기화해요. Prolog 객체 파일의 초기화는 적절한 테이블에 새 원자, 새 술어를 추가하고 그 시스템 지시자를 실행하는 것으로 구성돼요. 시스템 지시자는 op/3(7.1.11절)처럼 컴파일 타임에 실행된 (사용자) 지시자를 반영하기 위해 Prolog-WAM 컴파일러가 생성해요. 실제로 컴파일러가 그런 지시자를 만나면 즉시 실행하고 또한 실행 파일 시작 시 그것을 실행하는 시스템 지시자도 생성해요. 모든 시스템 지시자가 실행되면 Prolog 엔진은 initialization/1(7.1.14절)로 정의된 모든 초기화 지시자를 실행해요. 이 함수는 실행된 사용자 지시자(즉 initialization/1)의 수를 반환해요. 이 함수는 한 번만 호출해야 해요.
  • Pl_Stop_Prolog() — Prolog 엔진을 중지. 모든 Prolog 처리가 끝난 후에 한 번만 호출해야 해요.
  • Pl_Reset_Prolog() — Prolog 엔진을 재초기화(모든 Prolog 스택을 재설정).
  • Pl_Try_Execute_Top_Level() — 연결된 경우(4.4.3절) 최상위를 실행하고 PL_TRUE를 반환. 최상위가 없으면 이 함수는 PL_FALSE를 반환.

다음은 기본 GNU Prolog main() 함수의 정의예요:

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

어떤 상황에서는 main()의 코드를 main()이 호출하는 중간 함수 안에 캡슐화하는 것이 필요하다는 점을 참고해요. 실제로 일부 C 컴파일러(예: gcc)는 main()을 특별히 취급해 GNU Prolog와 관련해 호환되지 않는 코드를 생성해요. 따라서 위와 같이 항상 래퍼 함수를 사용하는 것이 좋아요.

예제: 조상 묻기

이 예에서 다음 Prolog 코드(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).

다음 파일(new_main_c.c)은 사람의 이름을 읽고 그 사람의 모든 후손을 표시하는 main() 함수를 정의해요. 이는 Prolog 쿼리 anc(Result, Name)과 동일해요.

#include <string.h>
#include <gprolog.h>

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

컴파일은 new_main이라는 실행 파일을 만듭니다:

% gplc new_main.pl new_main_c.c

사용 예:

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

더 알아보기