与输入的其余部分匹配的 DCG [英] A DCG that matches the rest of the input

查看:59
本文介绍了与输入的其余部分匹配的 DCG的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是做它应该做的事情的谓词,即,当 DCG 的一部分时,收集输入中剩下的任何内容:

This is the predicate that does what it should, namely, collect whatever is left on input when part of a DCG:

rest([H|T], [H|T], []).
rest([], [], []).

但我很难将其定义为 DCG... 或者它完全可行吗?

but I am struggling to define this as a DCG... Or is it at all doable?

这当然不一样(尽管以相同的方式使用时它的作用相同):

This of course is not the same (although it does the same when used in the same manner):

rest([H|T]) --> [H], !, rest(T).
rest([]) --> [].

认为我需要这个的原因是 rest//1 是我需要解析输入的一组 DCG 规则的一部分.我可以做 phrase(foo(T), Input, Rest),但是我必须调用另一个 phrase(bar(T1), Rest).

The reason I think I need this is that the rest//1 is part of a set of DCG rules that I need to parse the input. I could do phrase(foo(T), Input, Rest), but then I would have to call another phrase(bar(T1), Rest).

假设我知道我在输入上只剩下一串我想要作为整数的数字:

Say I know that all I have left on input is a string of digits that I want as an integer:

phrase(stuff_n(Stuff, N), `some other stuff, 1324`).

stuff_n(Stuff, N) -->
    stuff(Stuff),
    rest(Rest),
    {   number_codes(N, Rest),
        integer(N)
    }.

推荐答案

回答我自己的愚蠢问题:

Answering my own silly question:

@CapelliC 给出了一个有效的解决方案 (+1).它做了一些我不明白的事情:-(,但真正的问题是我不明白我试图解决的问题.真正的问题是:

@CapelliC gave a solution that works (+1). It does something I don't understand :-(, but the real issue was that I did not understand the problem I was trying to solve. The real problem was:

您有一个需要解析的代码列表作为输入.结果应该是一个术语.您在此代码列表的开头非常了解其余部分的样子.换句话说,它以定义内容的关键字"开头.在某些情况下,在输入中的某个点之后,其余内容不需要解析:相反,它们作为代码列表收集在结果术语中.

You have as input a code list that you need to parse. The result should be a term. You know quite close to the beginning of this list of codes what the rest looks like. In other words, it begins with a "keyword" that defines the contents. In some cases, after some point in the input, the rest of the contents do not need to be parsed: instead, they are collected in the resulting term as a code list.

一种可能的解决方案是将解析分解为对 phrase/3 的两次调用(因为没有理由不这样做?):

One possible solution is to break up the parsing in two calls to phrase/3 (because there is no reason not to?):

  1. 读取关键字(第一次调用 phrase/3)并使其成为一个原子;
  2. 在表格中查找其余部分应该是什么样子;
  3. 解析只解析需要解析的内容(第二次调用 phrase/3).
  1. Read the keyword (first call to phrase/3) and make it an atom;
  2. Look up in a table what the rest is supposed to look like;
  3. Parse only what needs to be parsed (second call to phrase/3).

代码

因此,使用 (O'Keefe 1990) 中的方法并利用 SWI-Prolog 中可用的 library(dcg/basics) 和文件 rest.pl>:

:- use_module(library(dcg/basics)).

codes_term(Codes, Term) :-
    phrase(dcg_basics:nonblanks(Word), Codes, Codes_rest),
    atom_codes(Keyword, Word),
    kw(Keyword, Content, Rest, Term),
    phrase(items(Content), Codes_rest, Rest).

kw(foo, [space, integer(N), space, integer(M)], [], foo(N, M)).
kw(bar, [], Text, bar(Text)).
kw(baz, [space, integer(N), space], Rest, baz(N, Rest)).

items([I|Is]) -->
    item(I),
    items(Is).
items([]) --> [].

item(space) --> " ".
item(integer(N)) --> dcg_basics:integer(N).

重要的是,其余"完全不需要由 DCG 规则处理.

这个解决方案很好,因为它是确定性的,而且很容易扩展:只需将子句添加到 kw/4 表和 item//1 规则.(注意在启动 SWI-Prolog 时使用 --traditional 标志,用于双引号分隔的代码列表)

This solution is nice because it is deterministic, and very easy to expand: just add clauses to the kw/4 table and item//1 rules. (Note the use of the --traditional flag when starting SWI-Prolog, for double-quote delimited code lists)

$ swipl --traditional --quiet
?- [rest].
true.

?- codes_term("foo 22 7", T).
T = foo(22, 7).

?- codes_term("bar 22 7", T).
T = bar([32, 50, 50, 32, 55]).

?- codes_term("baz 22 7", T).
T = baz(22, [55]).

这篇关于与输入的其余部分匹配的 DCG的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆