Prolog 中的 Monadic Parser例如 DIMACS 文件

问题描述

假设我们想在 Prolog 中实现一个 monadic parser(*),它只使用标准的 DCG 并提供一个词法分析器级别和一个解析器级别,它们可以一起工作。我想解析 DIMACS files

简单来说,解析不应该使用回溯或在解析之前进行词法分析,而是在交错词法和解析过程中可以直接逐个字符地读取流。

这是一个示例运行:

?- current_input(S),read_dimacs(S,M).
p cnf 4 2
-1 -3 0
1 2 4 0
^D
M = (~_A+(~_B+0))*((_A+(_C+(_D+0)))*1)

人们将如何着手并在 Prolog 中编写这样的东西?

(*) 快乐 - 2.5。一元解析器
https://www.haskell.org/happy/doc/html/sec-monads.html

解决方法

一个一元词法分析器可以描述如下。解析器不再读取列表 代币。相反,它为每个要读取的新标记调用词法分析函数。这有利于消除中间令牌列表。

为了支持一元词法分析器,我们为词法分析器定义了以下 DCG 实用程序。词法分析器在它的第一个 DCG 输入中假定一个流 S 和一个look-a-head字符C,并返回一个流和新的look-a-head字符。 DCG 实用程序是:

% current_code(-Integer,+Pair,-Pair)
current_code(C,S-C,S-C).

% next_code(+Pair,-Pair)
next_code(S-_,S-E) :- get_code(S,E).

然后可以使用前面的实用程序轻松编写词法分析器:

% read_token(-Term,-Pair)
read_token(integer(T)) --> current_code(C),{0'0 =< C,C =< 0'9},!,next_code,read_integer(L),{number_codes(T,[C|L])}.
read_token(integer(T)) --> current_code(0'-),[0'-|L])}.
read_token(atom(T)) --> current_code(C),{0'a =< C,C =< 0'z},read_atom(L),{atom_codes(T,[C|L])}.
read_token(T) --> current_code(0' ),read_token(T).
read_token(T) --> current_code(0'\n),read_token(T).
read_token(T) --> current_code(0'\r),read_token(T).
read_token(end_of_file) --> current_code(-1).

现在对于解析器,我们使用一些单独的 DCG 实用程序。这些实用程序现在 假设不同的上下文。上下文不仅包含一个流 S 和一个look-a-head字符C,还包含一个look-a-head标记:

% current_token(-Integer,+Triple,-Triple)
current_token(T,S-T-C,S-T-C).

% next_token(+Triple,-Triple)
next_token(S-_-C,R-T-E) :- read_token(T,R-E).

以下是解析器的一些示例代码,读取 DIMACS 子句:

% read_clause(+List,-Clause,-Triple)
read_clause(_,0) --> current_token(integer(0)),next_token.
read_clause(W,(V+L)) --> current_token(integer(N)),{make_variable(N,W,V)},next_token,read_clause(W,L).

代码具有高度可移植性,只需要 ISO 核心标准 get_code/2。它不需要将流读取到列表或其他内容中。这是在 SWI-Prolog 中运行的示例。警告!需要具有良好的最后一次调用优化和中期垃圾收集的 Prolog:

/* SWI-Prolog 8.3.21 */
?- current_input(S),read_dimacs(S,M).
p cnf 4 2
-1 -3 0
1 2 4 0
^D
M =  (~_7606+(~_7740+0))*((_7606+(_7750+(_8130+0)))*1).

开源:

Prolog 中的 Monadic 解析器(DIMACS 文件示例)
https://gist.github.com/jburse/7c71a2ae9ad7651b912f3920693438ad#file-dimacs-pl