如何在Prolog中创建一个与另一个DCG规则相反的规则?

3

我正在用Prolog编写Commodore BASIC解释器,并编写一些DCG来解析它。除了variable之外,我已经验证了下面的DCG可以工作。我的目标是:对于不是布尔值、整数、浮点数或字符串的任何东西都是变量。然而,无论我通过phrase给它什么,都只能得到no

bool --> [true].
bool --> [false].
integer --> [1]. % how to match nums?
float --> [0.1].
string --> [Str], {atom_chars(Str, ['"' | Chars]), last(Chars, '"')}.
literal --> bool; integer; float; string.

variable --> \+ literal.

我用 gprolog 跑了这样一个堆栈跟踪。
main :- trace, phrase(variable, [bar]).

看着这个,我无法理解为什么variable会失败,因为它在literal的每种情况下都失败了。我猜想错误可能很简单,但我仍然感到困惑,所以有谁擅长Prolog能够知道我做错了什么吗?

| ?- main.
The debugger will first creep -- showing everything (trace)
      1    1  Call: phrase(variable,[bar]) ? 
      2    2  Call: variable([bar],_321) ? 
      3    3  Call: \+literal([bar],_348) ? 
      4    4  Call: literal([bar],_348) ? 
      5    5  Call: bool([bar],_348) ? 
      5    5  Fail: bool([bar],_348) ? 
      5    5  Call: integer([bar],_348) ? 
      5    5  Fail: integer([bar],_348) ? 
      5    5  Call: float([bar],_348) ? 
      5    5  Fail: float([bar],_348) ? 
      5    5  Call: string([bar],_348) ? 
      6    6  Call: atom_chars(bar,['"'|_418]) ? 
      6    6  Fail: atom_chars(bar,['"'|_418]) ? 
      5    5  Fail: string([bar],_348) ? 
      4    4  Fail: literal([bar],_348) ? 
      3    3  Exit: \+literal([bar],_348) ? 
      2    2  Exit: variable([bar],[bar]) ? 
      1    1  Fail: phrase(variable,[bar]) ? 

(2 ms) no
{trace}
2个回答

3
你可以像这样检测一个整数字符串(我添加了一个参数来收集数字):
integer([H|T]) --> digit(H), integer(T).
integer([]) -->  [].
digit(0) --> "0".
digit(1) --> "1".
    ...
digit(9) --> "9".

关于变量--它需要消耗文本,因此您需要类似于上面的整数,但将digit(H)更改为识别属于“变量”的字符。
如果您想要进一步的线索(尽管有时会使用稍微高级的技巧):https://www.swi-prolog.org/pldoc/man?section=basics ,代码在这里:https://github.com/SWI-Prolog/swipl-devel/blob/master/library/dcg/basics.pl

3
稍微解释一下另一个答案,主要问题在于DCG规则\+ literal不会消耗输入中的项,它仅检查下一个项(如果有),是否不是literal
为了实际消耗一个项,您需要使用列表目标,类似于如何使用目标[1]来消耗元素1。所以:
variable -->
    \+ literal,  % if there is a next element, it's not a literal
    [_Variable]. % consume this next element, which is a variable

例如:
?- phrase(variable, [bar]).
true.

?- phrase((integer, variable, float), [I, bar, F]).
I = 1,
F = 0.1.

那个单例变量 _Variable 有点奇怪-- 当你像这样解析时,你会丢失变量的名称。当你的解析器稍微扩展一下,你将需要使用 DCG 规则的参数来在规则之间传递信息:

variable(Variable) -->
    \+ literal,  
    [Variable].

例如:
?- phrase((integer, variable(Var1), float, variable(Var2)), [I, bar, F, foo]).
Var1 = bar,
Var2 = foo,
I = 1,
F = 0.1.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接