GNU Prolog 컴파일러
GNU Prolog 컴파일러
gplc 컴파일러와 컴파일 방식, 실행, 대화형 인터프리터 생성, 이름 변형(mangling) 방식을 설명해요.
본문
서로 다른 종류의 코드
GNU Prolog의 주요 장점 중 하나는 독립 실행형 실행 파일을 생성할 수 있다는 점이에요. Prolog 프로그램은 GNU Prolog 컴파일러를 사용해 네이티브 코드로 컴파일되어 기계 의존적인 실행 파일을 만들 수 있어요. 그러나 네이티브 코드 술어는 나열하거나 완전히 디버깅할 수 없어요. 그래서 네이티브 코드 컴파일의 대안인 바이트코드 컴파일이 있어요. 기본적으로 GNU Prolog 컴파일러는 네이티브 코드를 생성하지만 명령줄 옵션을 통해 바이트코드 로딩에 적합한 파일을 생성할 수 있어요. 이것이 위에서 설명한 것처럼 consult/1이 하는 일이에요(4.2.3절).
GNU Prolog는 또한 Prolog로 작성된 Prolog 인터프리터를 사용해 해석 코드를 관리해요. 당연히 해석 코드는 바이트코드보다 느리지만 GNU Prolog 컴파일러의 호출을 요구하지 않아요. 이 인터프리터는 call/1(7.2.3절)처럼 메타 호출이 필요할 때마다 사용돼요. 동적으로 assert된 절도 마찬가지예요. 다음 표는 이 세 가지 종류의 코드를 요약해요:
| 유형 | 속도 | 디버그? | 용도 |
|---|---|---|---|
| 해석 코드 | 느림 | 예 | 메타 호출 및 동적으로 assert된 절 |
| 바이트코드 | 중간 | 예 | consult된 술어 |
| 네이티브 코드 | 빠름 | 아니요 | 컴파일된 술어 |
컴파일 방식
네이티브 코드 컴파일: Prolog 소스는 실행 파일을 만들기 위해 GNU Prolog 라이브러리에 링크되는 객체 파일을 생성하도록 여러 단계로 컴파일돼요. Prolog 소스는 먼저 WAM [9] 파일을 얻기 위해 컴파일돼요. WAM에 대한 자세한 연구는 "Warren's Abstract Machine: A Tutorial Reconstruction" [1]을 참조할 수 있어요. WAM 파일은 GNU Prolog에 특별히 설계된 기계 독립 언어로 번역돼요. 이 언어는 (보편적인) 어셈블리 언어에 가깝고 매우 축소된 명령어 집합을 기반으로 해요. 이런 이유로 이 언어를 mini-assembly(MA)라고 불러요. mini-assembly 파일은 그런 다음 대상 기계의 어셈블리 언어로 매핑돼요. 이 어셈블리 파일은 어셈블되어 객체 파일을 만들고, 그 객체 파일은 GNU Prolog 라이브러리와 링크되어 실행 파일을 제공해요.
컴파일러는 또한 유한 도메인 제약 정의 파일도 고려해요. 그것들을 C로 번역하고 C 컴파일러를 호출해 객체 파일을 얻어요. 다음 그림은 이 컴파일 방식을 제시해요. 당연히 모든 중간 단계는 단순히 Prolog 파일(들)(및 다른 파일: C 등)에서 컴파일러를 호출하고 실행 파일을 얻는 사용자에게 숨겨져 있어요. 그러나 주어진 단계에서 컴파일러를 중지하는 것도 가능해요. 이는 예를 들어 생성된 WAM 코드를 보는 데(아마 WAM을 배울 때) 유용할 수 있어요.
마지막으로 어떤 종류의 파일이든 컴파일러에 주어질 수 있으며, 컴파일러는 그 유형에 해당하는 단계에서 컴파일 체인에 삽입해요. 파일의 유형은 파일 이름의 접미사를 사용해 결정돼요. 다음 표는 인식되는 모든 유형/접미사를 제시해요:
| 파일 접미사 | 파일 유형 | 처리자 |
|---|---|---|
.pl, .pro, .prolog |
Prolog 소스 파일 | pl2wam |
.wam |
WAM 소스 파일 | wam2ma |
.ma |
Mini-assembly 소스 파일 | ma2asm |
.s |
어셈블리 소스 파일 | 어셈블러 |
.c, .C, .CC, .cc, .cxx, .c++, .cpp |
C 또는 C++ 소스 파일 | C 컴파일러 |
.fd |
유한 도메인 제약 소스 파일 | fd2c |
| 그 외 어떤 접미사(.o, .a 등) | 그 외 어떤 유형(객체, 라이브러리 등) | 링커(C 링커) |
바이트코드 컴파일: 같은 컴파일러를 사용해 소스 Prolog 파일을 바이트코드로 컴파일할 수 있어요. 그 경우 Prolog-WAM 컴파일러는 특정 옵션으로 호출되어 나중에 load/1(8.23.2절)로 로드될 수 있는 바이트코드용 WAM 소스 파일(.wbc 접미사)을 생성해요. 이것이 위에서 설명한 것처럼 consult/1(8.23.1절)이 하는 일임을 참고해요(4.2.3절).
컴파일러 사용
GNU Prolog 컴파일러는 gcc 같은 Unix C 컴파일러와 정신이 비슷한 명령줄 컴파일러예요. 컴파일러를 호출하려면 gplc 명령을 다음과 같이 사용해요:
% gplc [ OPTION ]… FILE …
(% 기호는 운영체제 셸 프롬프트)
gplc의 인자는 이전에 설명한 것처럼(4.4.2절) 그 접미사에서 결정된 유형에 따라 컴파일 방식으로 배치되는 파일 이름이에요. 모든 객체 파일은 그런 다음 실행 파일을 만들기 위해 링크돼요. GNU Prolog에는 모듈 기능이 없다는 점(Prolog 모듈에 대한 ISO 참조가 아직 없으므로)을 참고해요. 따라서 Prolog 파일에 정의된 술어는 다른 어떤 파일에 정의된 다른 술어에서도 볼 수 있어요. GNU Prolog는 큰 Prolog 소스를 여러 파일로 분할할 수 있게 해주지만 다른 술어로부터 술어를 숨기는 방법은 제공하지 않아요.
Prolog 소스 파일 prog.pl에서 실행 파일을 얻는 가장 단순한 방법은 다음을 사용하는 것이에요:
% gplc prog.pl
이것은 prog라는 네이티브 실행 파일을 생성하며, 다음과 같이 실행할 수 있어요:
% prog
그러나 컴파일을 제어하는 데 사용할 수 있는 여러 옵션이 있어요:
일반 옵션:
-o FILE,--output FILE— FILE을 출력 파일의 이름으로 사용.-W,--wam-for-native— WAM 파일(들) 생성 후 중지.-w,--wam-for-byte-code— 바이트코드용 WAM 파일(들) 생성 후 중지(강제--no-call-c).-M,--mini-assembly— mini-assembly 파일(들) 생성 후 중지.-S,--assembly— 어셈블리 파일(들) 생성 후 중지.-F,--fd-to-c— FD 제약 정의 파일(들)에서 C 파일(들) 생성 후 중지.-c,--object— 객체 파일(들) 생성 후 중지.--temp-dir PATH— PATH를 임시 파일 디렉토리로 사용.--no-del-temp— 임시 파일을 삭제하지 않음.--no-demangling— 술어 이름을 디코딩하지 않음(이름 demangling).-v,--verbose— 실행된 명령을 출력.-h,--help— 도움말을 출력하고 종료.--version— 버전 번호를 출력하고 종료.
Prolog-WAM 컴파일러 옵션:
--pl-state FILE— FILE을 읽어 초기 Prolog 상태를 설정.--wam-comment COMMENT— COMMENT를 WAM 파일의 주석으로 출력.--no-susp-warn— 의심스러운 술어에 대한 경고를 표시하지 않음.--no-singl-warn— 이름 붙은 singleton 변수에 대한 경고를 표시하지 않음.--no-redef-error— 내장 술어 재정의에 대한 오류를 표시하지 않음.--foreign-only— foreign/1-2 지시자만 컴파일.--no-call-c—fd_tell,'$call_c'등의 사용을 허용하지 않음.--no-inline— 술어를 인라인하지 않음.--no-reorder— 술어 인자를 재정렬하지 않음.--no-reg-opt— 레지스터를 최적화하지 않음.--min-reg-opt— 레지스터를 최소한으로 최적화.--no-opt-last-subterm— 마지막 하위 항 컴파일을 최적화하지 않음.--fast-math— 빠른 수학 모드 사용(정수 산술 가정).--keep-void-inst— 출력 파일에 void WAM 명령을 유지.--compile-msg— 컴파일 메시지를 출력.--statistics— 통계 정보를 출력.
WAM-mini-assembly 번역기 옵션:
--comment— 출력 파일에 주석 포함.
Mini-assembly-어셈블리 번역기 옵션:
--comment— 출력 파일에 주석 포함.--pic— 위치 독립 코드(PIC) 생성.
C 컴파일러 옵션:
--c-compiler FILE— FILE을 C 컴파일러/링커로 사용.-C OPTION— OPTION을 C 컴파일러에 전달.
어셈블러 옵션:
-A OPTION— OPTION을 어셈블러에 전달.
링커 옵션:
--linker FILE— FILE을 링커로 사용.--local-size N— 기본 지역 스택 크기를 N Kb로 설정.--global-size N— 기본 전역 스택 크기를 N Kb로 설정.--trail-size N— 기본 트레일 스택 크기를 N Kb로 설정.--cstr-size N— 기본 제약 스택 크기를 N Kb로 설정.--max-atom N— 기본 원자 테이블 크기를 N 원자로 설정.--fixed-sizes— 실행 시 환경 변수를 consult하지 않음(기본 크기 사용).--gui-console— GUI 콘솔과 링크(Windows 전용).--new-top-level— 최상위 main을 링크(최상위 명령줄 옵션을 인식하도록).--no-top-level— 최상위를 링크하지 않음(강제--no-debugger).--no-debugger— Prolog/WAM 디버거를 링크하지 않음.--min-pl-bips— 사용된 Prolog 내장 술어만 링크.--min-fd-bips— 사용된 FD 솔버 내장 술어만 링크.--min-bips— 다음의 축약:--no-top-level --min-pl-bips --min-fd-bips.--min-size— 다음의 축약:--min-bips --strip.--no-fd-lib— FD 라이브러리를 찾지 않음(유지 관리 전용).-s,--strip— 실행 파일을 스트립.-L OPTION— OPTION을 링커에 전달.
모호함이 없으면 옵션의 접두사만 주는 것도 가능해요. 출력 파일의 이름은 -o FILE 옵션으로 제어돼요. 있으면 생성된 출력 파일은 FILE로 이름이 지정돼요. 지정되지 않으면 출력 파일 이름은 컴파일러가 도달한 마지막 단계에 따라 달라져요. 링크가 수행되지 않으면 출력 파일 이름(들)은 마지막 단계와 연관된 접미사를 가진 입력 파일 이름(들)이에요. 링크가 수행되면 실행 파일의 이름은 명령줄에서 만난 첫 번째 파일 이름의 이름(접미사 없이)이에요. 링크가 수행되지 않을 때 여러 입력 파일 이름이 있으면 -o는 의미가 없으므로 주의해요. 이런 이유로 FILE에서 대체할 수 있는 여러 메타 문자가 있어요:
%f— 전체 입력 파일 이름으로 대체.%F—%f와 비슷하지만 디렉토리 부분이 생략.%p— 전체 접두사 파일 이름(접미사 생략)으로 대체.%P—%p와 비슷하지만 디렉토리 부분이 생략.%s— 파일 접미사(점 포함)로 대체.%d— 디렉토리 부분(디렉토리가 지정되지 않으면 빈 것)으로 대체.%c— 1에서 시작해 자동 증가하는 내부 카운터의 값으로 대체.
기본적으로 컴파일러는 네이티브 코드 컴파일 방식으로 실행돼요. 바이트코드용 WAM 파일을 생성하려면 --wam-for-byte-code 옵션을 사용해요. 결과 파일은 load/1(8.23.2절)로 로드될 수 있어요. 주어진 읽기 환경(연산자 정의, 문자 변환 테이블 등)에서 Prolog-WAM 컴파일러를 실행하려면 --pl-state FILE을 사용해요. 상태 파일은 write_pl_state_file/1(8.22.5절)로 생성되어야 해요.
기본적으로 Prolog-WAM 컴파일러는 일부 결정적 내장 술어(예: arg/3과 functor/3)에 대한 호출을 인라인해요. 즉 그런 술어에 대한 호출은 고전적인 술어 호출을 생성하지 않고 단순한 C 함수 호출(당연히 더 빠름)을 생성해요. --no-inline을 사용해 이를 피할 수 있어요.
Prolog-WAM 컴파일러가 수행하는 또 다른 최적화는 통일 재정렬(unification reordering)이에요. 술어의 인자는 통일을 최적화하기 위해 재정렬돼요. --no-reorder를 사용해 이를 비활성화할 수 있어요. 컴파일러는 또한 중첩된 복합 항의 통일/로딩을 최적화해요. 더 정확히, 복합 항의 마지막 하위 항이 그 자체로 복합 항(예: 리스트)일 때 컴파일러는 최적화된 명령을 발행해요. --no-opt-last-subterm을 사용해 이를 비활성화할 수 있어요.
기본적으로 Prolog-WAM 컴파일러는 생성된 명령 수와 사용된 레지스터 수를 모두 줄이기 위해 레지스터 할당을 완전히 최적화해요. 좋은 할당은 --keep-void-inst가 지정되지 않으면 생성된 파일에서 제거되는 많은 void 명령을 생성해요. 어떤 최적화도 방지하려면 --no-reg-opt를 사용하고, --min-reg-opt는 컴파일러가 간단한 레지스터 최적화만 수행하도록 강제해요.
Prolog-WAM 컴파일러는 제어 구조나 내장 술어가 재정의될 때 오류를 발행해요. --no-redef-error를 사용해 이를 피할 수 있어요. 컴파일러는 또한 -/2 같은 의심스러운 술어 정의에 대한 경고도 발행해요. 이는 종종 더 이른 구문 오류(예: _ 대신 -)에 대응하기 때문이에요. --no-susp-warn을 지정해 이를 비활성화할 수 있어요. 마지막으로 컴파일러는 singleton 변수가 이름을 가질 때(즉 일반 익명 이름 _가 아닐 때) 경고해요. --no-singl-warn을 지정해 이를 비활성화할 수 있어요.
내부적으로 술어 이름은 (어셈블리) 식별자의 구문에 맞도록 인코딩돼요. 이를 위해 GNU Prolog는 자신의 이름 변형(mangling) 방식을 사용해요. 이는 나중에 더 자세히 설명돼요(4.4.6절). 기본적으로 링커의 오류 메시지(예: 주어진 술어에 대한 다중 정의, 정의되지 않은 술어에 대한 참조 등)는 내부 이름 표현을 실제 술어 이름으로 대체하기 위해 필터링돼요(demangling). --no-demangling을 지정하면 gplc가 링커 출력 메시지를 필터링하지 못하게 해요(내부 식별자가 그런 다음 표시됨).
실행 파일을 생성할 때 기본 스택 크기를 지정하고(각 --STACK_NAME-size) 이전에 설명한 것처럼(4.3절) 환경 변수를 consult하지 않도록 하는 것(--fixed-sizes)이 가능해요. 기본적으로 생성된 실행 파일은 최상위, Prolog/WAM 디버거, 모든 Prolog 및 FD 내장 술어를 포함해요. --no-top-level을 지정해 최상위를 링크하지 않을 수 있어요(4.2절). 그 경우 적어도 하나의 initialization/1 지시자(7.1.14절)가 정의되어야 해요. --no-debugger 옵션은 디버거를 링크하지 않아요. 실제로 사용되는 내장 술어만 포함하려면 --no-pl-bips 및/또는 --no-fd-bips 옵션을 지정할 수 있어요. 가장 작은 실행 파일을 위해 이 모든 옵션을 지정해야 해요. 이는 축약 옵션 --min-bips로 줄일 수 있어요. 기본적으로 실행 파일은 스트립되지 않아요. 즉 그 심볼 테이블이 제거되지 않아요. 이 테이블은 C 디버거에만 유용해요(예: Prolog와 C를 연동할 때). 심볼 테이블을 제거(최종 실행 파일의 크기를 줄임)하려면 --strip을 사용해요. 마지막으로 --min-size는 --min-bips와 --strip의 단축키이며, 즉 생성된 실행 파일은 가능한 한 작아요.
예: 두 Prolog 소스 prog1.pl과 prog2.pl을 컴파일하고 링크. 결과 실행 파일은 prog1로 이름이 지정될 거예요(-o가 지정되지 않았으므로):
% gplc prog1.pl prog2.pl
예: 기본 WAM 코드를 연구하기 위해 Prolog 파일 prog.pl을 컴파일. 결과 파일은 prog.wam으로 이름이 지정될 거예요:
% gplc -W --no-inline --no-reorder --keep-void-inst prog.pl
예: Prolog 파일 prog.pl과 그 C 인터페이스 파일 utils.c를 컴파일해 mycommand라는 독립 실행 파일을 제공. 실행 파일은 C 디버거 사용을 허용하도록 스트립되지 않음:
% gplc -o mycommand prog.pl utils.c
예: Prolog 파일 prog.pl을 컴파일하는 모든 단계를 자세히 수행(결과 실행 파일은 스트립됨). 모든 중간 파일이 생성됨(prog.wam, prog.ma, prog.s, prog.o 및 실행 파일 prog):
% gplc -W prog.pl
% gplc -M --comment prog.wam
% gplc -S --comment prog.ma
% gplc -c prog.s
% gplc -o prog -s prog.o
실행 파일 실행
이 절에서는 GNU Prolog 네이티브 코드 컴파일러가 생성한 실행 파일을 실행할 때 무슨 일이 일어나는지 설명해요. 기본 main 함수는 먼저 Prolog 엔진을 시작해요. 이 함수는 모든 연결된 객체(Prolog 파일 컴파일에서 나온)를 수집하고 초기화해요. Prolog 객체 파일의 초기화는 적절한 테이블에 새 원자, 새 술어를 추가하고 그 시스템 지시자를 실행하는 것으로 구성돼요. 시스템 지시자는 op/3(7.1.11절)처럼 컴파일 타임에 실행된 (사용자) 지시자를 반영하기 위해 Prolog-WAM 컴파일러가 생성해요. 실제로 컴파일러가 그런 지시자를 만나면 즉시 실행하고 또한 실행 파일 시작 시 그것을 실행하는 시스템 지시자도 생성해요.
모든 시스템 지시자가 실행되면 Prolog 엔진은 initialization/1(7.1.14절)로 정의된 모든 초기화 지시자를 실행해요. 같은 파일에 여러 초기화 지시자가 나타나면 나타난 순서로 실행돼요. 다른 파일에 여러 초기화 지시자가 나타나면 실행 순서는 기계에 의존해요. 그러나 대부분의 기계에서 순서는 연관된 파일이 링크된 순서의 역순이 될 거예요(네이티브 win32에서는 사실이 아님).
모든 초기화 지시자가 실행되면 기본 main 함수는 GNU Prolog 최상위를 찾아요. 있으면(즉 링크되었으면) 호출되고, 그 외에는 프로그램이 단순히 끝나요. 최상위가 링크되지 않고 초기화 지시자가 없으면 프로그램은 어떤 작업도 하지 않고 단순히 끝나므로 쓸모없음을 참고해요. 기본 main 함수는 그런 동작을 감지하고 경고 메시지를 발행해요.
예: 빈 파일 prog.pl을 최상위를 링크하지 않고 컴파일하고 실행:
% gplc --no-top-level prog.pl
% prog
Warning: no initial goal executed
use a directive :- initialization(Goal)
or remove the link option --no-top-level (or --min-bips or --min-size)
새 대화형 인터프리터 생성
이 절에서는 GNU Prolog 대화형 인터프리터를 새로운 술어 정의로 확장하는 새 최상위를 정의하는 방법을 보여줘요. 얻어진 최상위는 기본 GNU Prolog 최상위의 강화 버전으로 간주될 수 있어요(4.2절). 실제로 추가된 각 술어는 다른 어떤 내장 술어와 마찬가지로 미리 정의된 술어로 볼 수 있어요. 이는 이 술어들을 컴파일하고 링크 타임에 최상위를 포함해 이룰 수 있어요.
진짜 질문은: GNU Prolog 최상위에서 단순히 consult하는 대신 왜 일부 술어를 새 최상위에 포함할까요? 여기에는 두 가지 이유가 있어요:
- 술어를 consult할 수 없음. 이는 C와 연동하는 술어(10절)나 새 FD 제약을 정의하는 술어처럼 foreign 코드를 호출하는 술어의 경우예요.
- 술어의 성능이 중요함. 네이티브 코드로 컴파일되므로 그런 술어는 매우 빠르게 실행될 거예요. consult는 그것을 바이트코드로 로드할 거예요. 프로그램이 디버거 아래에서 실행되면 이득이 훨씬 더 두드러져요. 포함된 버전은 디버거의 영향을 받지 않는 반면 consult된 버전은 몇 배 느릴 거예요. 당연히 술어는 네이티브 코드 디버깅이 어려우므로 자체적으로 디버깅됐을 때만 새 최상위에 포함해야 해요.
새 최상위를 정의하려면 원하는 술어 집합을 컴파일하고 gplc(4.4.3절)를 사용해 GNU Prolog 최상위와 함께 링크하면 돼요(이것이 기본).
예: prog.pl에 정의된 모든 술어를 포함하는 my_top_level이라는 새 최상위를 정의:
% gplc -o my_top_level prog.pl
그런데 prog.pl이 빈 Prolog 파일이면 이전 명령은 GNU Prolog 최상위와 비슷한 새 대화형 인터프리터를 단순히 만들 거예요.
예: prog.pl의 일부 술어가 utils.c에 정의된 C 함수를 호출하는 경우:
% gplc -o my_top_level prog.pl utils.c
완전히 확장된 실행 파일을 얻으려면 --init-goal 같은 원래 최상위와 같은 옵션 집합을 받아들이는 것이 바람직해요(4.2절 참조). 이를 위해 원래 최상위가 사용하는 main() 함수를 링크해야 해요. 이는 gplc에 --new-top-level을 전달해 이룰 수 있어요:
% gplc --new-top-level -o my_top_level prog.pl utils.c
결론적으로 특정 최상위를 정의하는 것은 네이티브 코드 컴파일의 특수한 경우에 불과해요. 하기 쉽고 실제로 매우 유용해요.
이름 변형 방식
GNU Prolog 컴파일러가 Prolog 소스를 객체 파일로 컴파일할 때 각 술어 이름에 심볼을 연관시켜야 해요. 그러나 심볼의 구문은 식별자로 제한돼요: 문자, 숫자 또는 밑줄 문자만 포함하는 문자열. 반면 술어 이름(즉 원자)은 필요하면 따옴표로 어떤 문자도 포함할 수 있어요(예: 'x+y=z'는 유효한 술어 이름). 컴파일러는 따라서 식별자 구문을 지키며 술어 이름을 인코딩해야 할 수 있어요. 추가로 Prolog는 같은 이름과 다른 항수의 여러 술어를 정의할 수 있게 해주므로, GNU Prolog는 술어 지시자(술어 이름 뒤에 항수)를 인코딩해요. 마지막으로 미래에 모듈을 지원하기 위해 모듈 이름도 인코딩돼요.
버전 1.4.0부터 GNU Prolog는 다음 이름 변형 방식을 채택해요. [MODULE:] PRED / N(MODULE은 생략될 수 있음) 형태의 술어 지시자는 다음 형태의 식별자를 만들 거예요:
X K _ [ E(MODULE) __ ] E(PRED) __a N
여기서:
- K는 MODULE과 PRED에 대한 코딩 정보를 저장하는 0..5의 숫자. 가능한 값:
- 0: 모듈 없음, PRED는 인코딩되지 않음.
- 1: 모듈 없음, PRED는 인코딩됨.
- 2: MODULE은 인코딩되지 않음, PRED는 인코딩되지 않음.
- 3: MODULE은 인코딩되지 않음, PRED는 인코딩됨.
- 4: MODULE은 인코딩됨, PRED는 인코딩되지 않음.
- 5: MODULE은 인코딩됨, PRED는 인코딩됨.
- E(STR)는 문자열을 인코딩하는 함수이며, 반환해요:
- STR 자체(인코딩되지 않음): STR이 문자, 숫자 또는
_만 포함하지만__부분 문자열을 포함하지 않고_로 시작하거나 끝나지 않을 때(즉 정규식:[a-zA-Z0-9]([-]?[a-zA-Z0-9])*). - 그 외에는 문자열의 각 문자의 16진수 표현.
- STR 자체(인코딩되지 않음): STR이 문자, 숫자 또는
예: E(x+y=z)는 782B793D7A를 반환하는데, 78은 x의 ASCII 코드의 16진수 표현, 2B는 +의 코드 등이기 때문이에요.
예:
| 술어 지시자 | 내부 식별자 |
|---|---|
father/2 |
X0_father__a2 |
'x+y=z'/3 |
X1_782B793D7A__a3 |
util:same/2 |
X2_util__same__a2 |
util:same__1/3 |
X3_util__73616D655F5F31__a3 |
그래서 mini-assembly 단계부터 각 술어 지시자는 이름 변형 식별자를 통해 처리돼요. 이 방식에 대한 지식은 보통 사용자(즉 Prolog 프로그래머)에게 관심이 없어요. 이런 이유로 GNU Prolog 컴파일러는 이 변형을 숨겨요. 술어에서 오류가 발생하면(정의되지 않은 술어, 다중 정의를 가진 술어 등) 컴파일러는 술어 지시자와 연관된 심볼을 디코딩해야 해요(이름 demangling). 이를 위해 gplc는 링커가 발행한 각 메시지를 필터링해 잠재적인 술어 지시자를 찾고 디코딩해요. 이 필터링은 gplc를 호출할 때 --no-demangling을 지정해 비활성화할 수 있어요(4.4.3절).
이 필터는 다음과 같이 hexgplc 명령을 사용해 호출할 수 있는 유틸리티로 제공돼요:
% hexgplc [ OPTION ]… FILE …
(% 기호는 운영체제 셸 프롬프트)
옵션:
--decode또는--demangling— 디코딩 모드(이것이 기본 모드).--encode또는--mangling— 인코딩 모드.--relax— 술어 이름도 디코딩(술어 지시자뿐만 아니라).--printf FORMAT— 인코딩/디코딩된 문자열을 C printf(3)에 FORMAT으로 전달.--aux-father— 보조 술어를 그 아버지로 디코딩.--aux-father2— 보조 술어를 그 아버지 + 보조 번호로 디코딩.--cmd-line— 명령줄의 각 인자를 인코딩/디코딩.-E또는-M—--cmd-line --encode --relax와 같음.-P또는-D—--cmd-line --decode --relax --quote와 같음.--help— 도움말을 출력하고 종료.--version— 버전 번호를 출력하고 종료.
모호함이 없으면 옵션의 접두사를 주는 것이 가능해요. 인자 없이 hexgplc는 표준 입력을 읽고 술어 지시자에 대응하는 각 심볼을 디코딩(demangling)하며 디코딩 모드로 실행돼요. 인코딩(mangling) 모드로 hexgplc를 사용하려면 --encode 옵션을 지정해야 해요. 기본적으로 hexgplc는 술어 지시자만 디코딩하며, --relax를 사용해 단순 술어 이름도(항수는 생략될 수 있음) 고려하도록 완화할 수 있어요. --printf FORMAT을 사용해 인코딩/디코딩된 문자열의 출력을 형식화하는 것이 가능해요. 그 경우 각 문자열 S는 printf(FORMAT, S)로 C printf(3) 함수에 전달돼요.
보조 술어는 절의 본문에 ';'/2 같은 일부 제어 구조를 단순화할 때 Prolog-WAM 컴파일러가 생성해요. 그것들은 '$NAME/ARITY_$aux N' 형태이며, NAME/ARITY는 단순화된(즉 아버지) 술어의 술어 지시자이고 N은 순차 번호예요(술어는 여러 보조 술어를 만들 수 있음). --aux-father를 사용해 보조 술어를 그 아버지 술어 지시자로, --aux-father2를 사용해 그 아버지 술어 지시자 뒤에 순차 번호가 따르는 것으로 hexgplc가 디코딩하도록 강제할 수 있어요.
파일이 지정되지 않으면 hexgplc는 표준 입력을 처리하고, 그 외에는 각 파일을 순차적으로 처리해요. --cmd-line 옵션을 지정하면 각 인자가 파일 이름이 아니라 인코딩(또는 디코딩)되어야 하는 문자열임을 hexgplc에 알려줘요. 이는 특정 문자열을 인코딩/디코딩하는 데 유용해요. 이런 이유로 -E(인코딩)와 -D(디코딩) 옵션이 축약으로 제공돼요. 그런 다음 술어 PRED의 변형 표현을 얻으려면:
% hexgplc -E PRED
NB: PRED가 복잡한 원자이면 인용해야 해요(따옴표는 hexgplc에 전달되어야 함). bash 아래의 예:
% hexgplc -E \'x+y=z\'/3
X1_782B793D7A__a3
또는 더 안전하게(bash에 특수 문자를 해석하지 않도록 bash 따옴표 사용):
% hexgplc -E \'''x+y=z'\'/3
X1_782B793D7A__a3