很多人对 Prolog 的印象都是“不就是枚举吗?”。实际上 Prolog 是跟 C/C++/Java 一样的通用编程语言。Prolog程序通常跑在WAM虚拟机上[1]。和JVM不同的是,WAM是一个概念模型,因而各家WAM差别还是蛮大的。

既然 Prolog 是跑在虚拟机上的编程语言,那就有字节码,而对应的字节码也有相应的汇编形式。因此我们也可以对我们的 Prolog 代码进行反汇编。下面介绍如何对 Prolog 代码进行反汇编。

SWI Prolog

在 SWI Prolog 中对代码进行反汇编很简单,可以用 vm_list/1 做到。如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
?- listing(append/3).
lists:append([], L, L).
lists:append([H|T], L, [H|R]) :-
append(T, L, R).

true.

?- vm_list(append/3).
========================================================================
append/3
========================================================================
0 s_virgin
1 i_exit
----------------------------------------
clause 1 (<clause>(0000017A0D4FFD90)):
----------------------------------------
0 h_nil
1 h_void
2 h_var(1)
4 i_exitfact
----------------------------------------
clause 2 (<clause>(0000017A0D4A1BC0)):
----------------------------------------
0 h_list_ff(3,4)
3 h_void
4 h_list
5 h_var(3)
7 h_firstvar(5)
9 h_pop
10 i_enter
11 b_var(4)
13 b_var1
14 b_var(5)
16 i_depart(lists:append/3)
18 i_exit
true.

Sicstus Prolog

在 Sicstus Prolog 中反汇编,可以用 disassembler:disassemble/1 。如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| ?- [user].
% compiling user...
|
is_digesting(X,Y) :- just_ate(X,Y).
is_digesting(X,Y) :-
just_ate(X,Z),
is_digesting(Z,Y).

just_ate(mosquito,blood(john)).
just_ate(frog,mosquito).
just_ate(stork,frog).

end_of_file.
% compiled user in module user, 94 msec 680032 bytes
yes
| ?- use_module(library(disassembler)).
... lots of loading messages ...
yes
| ?- disassemble(is_digesting/2).
% Predicate: user:is_digesting/2 (user)
% Varcase: [2197340771584-2197341614544,2197341444848-2197341099664]
% clause indexed [var,number,atom,list,structure] (user)
% 2197340771584: 'EXECUTEQ'(user:just_ate/2)
% 2197340771600: 'END_OF_CLAUSEQ'(user:is_digesting/2)
% clause indexed [var,number,atom,list,structure] (user)
% 2197341444848: 'GET_FIRST'([y(0,0)=x(1)])
% 2197341444864: 'FIRSTCALLQ'([x(1)=variable(1,0)],user:just_ate/2,2)
% 2197341444892: 'LASTCALLQ'([x(0)=unsafe_value(1),x(1)=value(0)],user:is_digesting/2)
% 2197341444920: 'END_OF_CLAUSEQ'(user:is_digesting/2)
yes

  1. B-Prolog 跑在TOAM上。当然并不是只有这一个 Prolog 实现不用 WAM 。 ↩︎