【发布时间】:2016-05-22 23:23:38
【问题描述】:
我正在尝试为命令接口编写 DCG。这个想法是读取输入字符串,将其拆分为空格,然后将生成的令牌列表交给 DCG 以将其解析为命令和参数。解析的结果应该是一个术语列表,我可以将其与=.. 一起使用来构建要调用的目标。但是,我对 SWI-Prolog(版本 7.2.3)中的字符串类型情况感到非常困惑。 SWI-Prolog 包含一个basic DCG functionality 库,其中包括一个目标integer//1,它应该解析一个整数。它由于类型错误而失败,但更大的问题是我无法弄清楚如何使用“令牌列表”在 SWI-Prolog 中使 DCG 正常工作。
这是我想要做的:
:- use_module(library(dcg/basics)).
% integer//1 is from the dcg/basics lib
amount(X) --> integer(X), { X > 0 }.
cmd([show,all]) --> ["show"],["all"].
cmd([show,false]) --> ["show"].
cmd([skip,X]) --> ["skip"], amount(X).
% now in the interpreter:
?- phrase(cmd(L), ["show","all"]).
L = [show, all].
% what is the problem with this next query?
?- phrase(cmd(L), ["skip", "50"]).
ERROR: code_type/2: Type error: `character' expected, found `"50"' (a string)
我已经阅读了 SWI 手册的Section 5.2,但它并没有完全回答我的问题:
-
integer//1在dcg/basics库中需要什么类型?错误消息显示“字符”,但我找不到任何有用的参考来说明这究竟意味着什么以及如何为其提供“正确”输入。 - 如何将字符串(令牌)列表传递给
phrase/2,以便我可以使用integer//1将令牌解析为整数? - 如果无法使用
integer//1原语将一串数字解析为整数,我应该如何完成?
我做了很多实验,在 SWI-Prolog 中为 double_quote 标志使用不同的值,以及不同的输入格式,例如使用原子列表,使用单个字符串作为输入,即 "skip 50"而不是["skip", "50"],等等,但我觉得关于DCG如何工作的假设我不明白。
我也研究了这三个页面,其中有很多示例,但没有一个完全解决我的问题(一些链接被省略,因为我没有足够的声誉来发布所有这些):
- Anne Ogborn 的教程“在 SWI-Prolog 中使用定句语法”
- Amzi 的教程!关于将命令接口编写为 DCG 的 Prolog。
- J. R. Fisher 的 Prolog 教程第 7.3 节
第三个更广泛的问题是,如果需要整数但无法解析为整数,如何生成错误消息,如下所示:
% the user types:
> skip 50x
I didn't understand that number.
一种方法是将上面 DCG 中的变量 X 设置为某种错误值,然后稍后检查(如假设的 skip/1 目标应该由命令调用),但是也许有更好/更惯用的方式?我编写解析器的大部分经验来自使用 Haskell 的 Parsec 和 Attoparsec 库,它们具有相当的声明性,但工作方式略有不同,尤其是在错误处理方面。
【问题讨论】:
-
您的 DCG 中如何定义
integer? -
它是 SWI-Prolog 附带的库的一部分,记录在 here。我将使用此信息编辑帖子。
-
根据文档,该谓词 (
integer(X)) 需要一个整数参数,但您正在尝试用它解析一个原子 ('50')(我假设您的 SWI 序言配置为解释"50"作为原子'50')。