【问题标题】:Converting grammar into prolog将语法转换为序言
【发布时间】:2018-04-05 00:16:41
【问题描述】:

所以我正在尝试转换一种在编程语言中定义变量定义的语法。这是我的第一个序言,它与典型的语言非常不同,所以我很困惑。语法如下:

S -> T S | T

T -> char F 分号 | int F 分号

F -> 标识 |身份证号

G -> 逗号 F

对于“char id semicolon”或“int id comma id semicolon char id semicolon”之类的东西,它会有效地返回true。

我试图把它变成一个序言程序来识别这个语法。到目前为止我所拥有的是:

type([char|T],T).
type([int|T],T).
def([id|T], T).
com([comma|T], T).
semi([semicolon|T], T).

vardef(L,S) :-
  type(L,S1),
  def(S1,S2),
  comma(S2,S3),
  def(S3,S4),
  semi(S4,S).

variable_definition(L) :-
  vardef(L,[]).

但是,这显然只识别特定的“int/char id comma id semicolon”。我不知道如何制作它,所以它在分号之前有一个可变数量的“id comma id”,甚至在第一个之后有一个全新的变量定义。这个网站上关于同一件事的其他问题通常必须处理像这样设置的语法,而不是可以有可变数量输入的语法。

编辑:所以问题是双重的。首先,我如何让它识别两个不同的变量定义,一个接一个。我假设我必须更改最后一行才能完成此操作,但我不确定如何。

其次,如何让它识别可变数量的“id”,后跟逗号。所以如果我想让它识别“char id semicolon”以及“char id comma id semicolon”。

【问题讨论】:

  • 什么是TS?使用这种实现方法,您需要使用递归来识别可变数量的 id 后跟逗号。您是否考虑过使用 DCG,这对于此类程序来说是理想的?
  • TS 是一个 T 后跟一个 S,请在它们之间添加一个空格。我没有使用 DCG 的原因是我们在我正在上课的课程中还没有达到目标,所以我不想继续前进,并可能因为没有使用所提供的系统而被降级

标签: prolog grammar


【解决方案1】:

在 Prolog 中表达这样的语法最自然的方式是使用 Prolog 的 DCG 表示法:

S -> T S | T
T -> char F 分号 | int F 分号
F -> 标识 | id G
G -> 逗号 F

s --> t, s | t.
t --> [char], f, [semicolon] | [int], f, [semicolon].
f --> [id] | [id], g.
g --> [comma], f.

DCG 的好处在于它更直接地表达了符号。然后你可以使用phrase/2 来运行它:

| ?- phrase(s, [char, id, semicolon]).

true ? ;

no

你可以使用这个语法,在某种程度上,生成有效的短语:

| ?- phrase(t, S).

S = [char,id,semicolon] ? ;

S = [char,id,comma,id,semicolon] ? ;

S = [char,id,comma,id,comma,id,semicolon] ? ;
...

不过……

| ?- phrase(s, S).

Fatal Error: local stack overflow (size: 16384 Kb, reached: 16384 Kb,
environment variable used: LOCALSZ)

s 这个词的定义方式是它不会终止。我们可以通过稍后移动递归案例来解决这个问题:

s --> t | t, s.

然后:

| ?- phrase(s, S).

S = [char,id,semicolon] ? ;

S = [char,id,comma,id,semicolon] ? ;

S = [char,id,comma,id,comma,id,semicolon] ? ;
...

您可以通过列出谓词的 Prolog 代码来了解这是如何以标准表示法实现的:

| ?- listing(t).

% file: user

t(A, B) :-
        (   A = [char|C],
            f(C, D),
            D = [semicolon|B]
        ;   A = [int|E],
            f(E, F),
            F = [semicolon|B]
        ).

yes
| ?-

你可以更简洁地写成:

t([char|T], B) :-
    f(T, [semicolon|B]). 
t([int|T], B) :-
    f(T, [semicolon|B]).

这将被称为t(L, [])(等同于phrase(t, L))。


如果我们列出其余谓词,您可以按照您要求的形式获得完整的解决方案:
| ?- listing.
s(A, B) :-
        (   t(A, B)
        ;   t(A, C),
            s(C, B)
        ).

t(A, B) :-
        (   A = [char|C],
            f(C, D),
            D = [semicolon|B]
        ;   A = [int|E],
            f(E, F),
            F = [semicolon|B]
        ).

f(A, B) :-
        (   A = [id|B]
        ;   A = [id|C],
            g(C, B)
        ).

g([comma|A], B) :-
        f(A, B).

稍微重构(使其不那么冗长):

s(L, S) :-
    t(L, S).
s(L, S) :-
    t(L, S1),
    s(S1, S).

t([char|T], S) :-
    f(T, [semicolon|S]). 
t([int|T], S) :-
    f(T, [semicolon|S]).

f([id|S], S).
f([id|S1], S) :-
    g(S1, S).

g([comma|S1], S) :-
    f(S1, S).

您可以从这里致电:variable_definition(D) :- s(D, []).

【讨论】:

  • 虽然这是一个很好的答案,也是对 DCG 的非常简洁的解释,但我可能应该提到的是,这个程序需要以“variable_defintion([int, id, comma , id, 逗号, id, 分号, char, id, 分号])。”并返回真。因此,虽然您的回答很有意义并且效果更好,但我目前在学术界工作,这通常没有什么意义。
  • @bock.steve 我给出的答案应该很容易转换为这种定义。如果您要为我展示的每个 DCG 规则展示标准谓词表示,它们将正是您想要的谓词类型。如果s 是变量的主要定义,那么使用DCG 它将是variable_definition(V) :- phrase(s, V).,或者所描述的等效转换是variable_definition(V) :- s(V, []).
  • @bock.steve 我使用我描述的完整 DCG 转换添加到我的答案中。
  • 非常感谢您的帮助。当我试图找出它为什么不起作用时,我意识到在我的 prolog 的“绿色”中,我什至没有正确运行程序。解决了这个问题,您的解决方案效果很好。
猜你喜欢
  • 2021-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-14
相关资源
最近更新 更多