我正在尝试为命令界面编写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
标志的不同值以及使用单个字符串作为输入的不同输入格式(例如使用原子列表)进行了相当多的实验,即{ {1}}而不是"skip 50"
,等等,但我觉得有关DCG如何工作的假设,我不明白。
我也研究了这三个页面,其中有很多例子,但没有一个完全解决我的问题(由于我没有足够的声誉来发布所有这些,所以省略了一些链接):
第三个更广泛的问题是,如果预期整数但不能解析为一个整数,如何生成错误消息,如下所示:
["skip", "50"]
一种方法是将上面的DCG中的变量% the user types:
> skip 50x
I didn't understand that number.
设置为某种错误值,然后稍后检查(就像假定的X
目标应该由命令),但也许有更好/更惯用的方式?我编写解析器的大部分经验都来自于使用Haskell的Parsec和Attoparsec库,这些库是相当具体的声明,但工作方式有所不同,特别是在错误处理方面。
答案 0 :(得分:0)
Prolog没有字符串。双引号字符序列的传统表示是代码列表(整数)。对于efficiency reasons,SWI-Prolog ver。 > = 7引入了字符串作为新的原子数据类型:
?- atomic("a string").
true.
和反引号文字现在具有以前由字符串保存的角色:
?- X=`123`.
X = [49, 50, 51].
毋庸置疑,这导致some confusion,同时也给出了Prolog的弱类型性质......
无论如何,DCG仍然可以处理(差异)字符代码列表,只需将转换器扩展为接受字符串作为终端。你的代码可能是
cmd([show,all]) --> whites,"show",whites,"all",blanks_to_nl.
cmd([show,false]) --> whites,"show",blanks_to_nl.
cmd([skip,X]) --> whites,"skip",whites,amount(X),blanks_to_nl.
可以像
一样调用?- phrase(cmd(C), ` skip 2300 `).
C = [skip, 2300].
修改的
如果需要整数,如何生成错误消息
我会尝试:
...
cmd([skip,X]) --> whites,"skip",whites,amount(X).
% integer//1 is from the dcg/basics lib
amount(X) --> integer(X), { X > 0 }, blanks_to_nl, !.
amount(unknown) --> string(S), eos, {print_message(error, invalid_int_arg(S))}.
prolog:message(invalid_int_arg(_)) --> ['I didn\'t understand that number.'].
试验:
?- phrase(cmd(C), ` skip 2300x `).
ERROR: I didn't understand that number.
C = [skip, unknown] ;
false.