使用 DCG [SICStus] 解析语法

Parsing grammar using DCG [SICStus]

到目前为止,我必须解析一个广泛的语法(为了创建一个语法分析器),问题是我在代码的某处得到了冗余,但我不知道它在哪里。

部分语法;

Grammar_types

Type :: =     Basic_Type
            | "PP" "(" Type ")"
            | Type "*" Type
            | "struct" "("    (Ident ":" Type)+","    ")"
            | "(" Type ")" .


Basic_Type :: = "ZZ"| "BOOL" | "STRING" | Ident .

我尝试在没有 DCG 的情况下分析这个语法,解析示例 Id :: = Id ((Id) * ",") *

Example_1

"id","id_0(id1,id2,..)"

Code_1

Entete_ (ID, Id, Ids) - atom_concat(XY,')', ID), 
                        atom_concat(XX,Ids, XY),check_ids(Ids),
                        atom_concat(Id,'(',XX),check_id(Id) ,!.
...

但在一些搜索中,我发现 DCG 是最有效的解析器之一,所以我回来获取下面的代码;

Code_2

type(Type) -->     "struct(", idents_types(Type),")"
                 | "PP(",ident(Type),")"
                 | "(",type(Type),")"
                 | type(Type),"*",type(Type)
                 | basic_type(Type)
                 | "error1_type".

...

Example_Syntaxe ;

"ZZ" ; "PP(ZZ*STRING)" ; "struct(x:personne,struct(y:PP(PP))" ; "ZZ*ZZ" ...

测试

| ?- phrase(type(L),"struct(aa:struct())").
! Resource error: insufficient memory
% source_info

我认为 问题 在这里 (idents_types)

| ?- phrase(idents_types(L),"struct(aa:STRING)").
    ! Resource error: insufficient memory

预期结果

     | ?- type('ZZ*struct(p1:STRING,p2:PP(STRING),p3:(BOOL*PP(STRING)),p4:PP(personne*BOOL))').
p1-STRING
STRING
p2-PP(STRING)
STRING
p3-(BOOL*PP(STRING))
STRING
BOOL
p4-PP(personne*BOOL)
BOOL
personne
ZZ
yes

所以我的问题是,为什么我会收到冗余错误,我该如何解决?

您在类型//1 上有一个 left recursion

type(Type) --> ... | type(Type),"*",type(Type) | ...

您可以查看 this question 了解更多信息。

DCG 借用的自上而下的解析器必须具有先行 驱动正确方向分析的符号。

如上文 link 所示,此问题的通常解决方案是引入一个服务非终结符,该服务非终结符离开了罪魁祸首规则的关联递归应用程序,或者是 epsilon(终止递归)。

一个epsilon规则写成

rule --> [].

转换可能需要相当多的思考...在 this answer 中,我建议采用自下而上的替代实现方式,如果语法无法转换,对于实际或理论问题(LR 语法),这可能是值得的比 LL 更通用)。

您可能想尝试这种头脑简单的转换,但可以肯定的是它留下了一些有待解决的细节。

type([Type,T]) --> "struct(", idents_types(Type),")", type_1(T)
                 | "PP(",ident(Type),")", type_1(T)
                 | "(",type(Type),")", type_1(T)
                 | basic_type(Type), type_1(T)
                 | "error1_type", type_1(T).
type_1([Type1,Type2,T]) --> type(Type1),"*",type(Type2), type_1(T).
type_1([]) --> [].

编辑

我修复了您和我的代码中的几个问题。现在它解析示例...

type([Type,T]) --> "struct(", idents_types(Type), ")", type_1(T)
                 | "PP(", type(Type), ")", type_1(T)
                 | "(", type(Type), ")", type_1(T)
                 | basic_type(Type), type_1(T)
                 | "error1_type", type_1(T).

% my mistake here...
type_1([]) --> [].
type_1([Type,T]) --> "*",type(Type), type_1(T).

% the output Type was unbound on ZZ,etc
basic_type('ZZ') --> "ZZ".
basic_type('BOOL') --> "BOOL".
basic_type('STRING') --> "STRING".
basic_type(Type) --> ident(Type).

% here would be better to factorize ident(Ident),":",type(Type)
idents_types([Ident,Type|Ids]) -->   ident(Ident),":",type(Type),",",
                                     idents_types(Ids).
idents_types([Ident,Type])     -->   ident(Ident),":",type(Type).
idents_types([])               -->   []. 

% ident//1 forgot to 'eat' a character
ident(Id) --> [C], { between(0'a,0'z,C),C\=0'_},ident_1(Cs),{ atom_codes(Id,[C|Cs]),last(Cs,L),L\=0'_}.
ident_1([C|Cs]) --> [C], { between(0'a,0'z,C);between(0'0,0'9,C);C=0'_ },
                    ident_1(Cs).
ident_1([])     --> [].