使用DCG解析语法[SICStus]

时间:2016-02-14 11:49:36

标签: prolog dcg

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

语法的一部分;

Grammar_types

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


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

我尝试在没有DCG的情况下分析这个gramar,例如解析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 个答案:

答案 0 :(得分:2)

您在类型// 1上有left recursion

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

您可以查看this question以获取更多信息。

DCG借用的自上而下的解析器必须具有预测的平均值一个符号,以便在正确的方向上驱动分析。

正如上面的链接所示,这个问题的通常解决方案是引入一个服务非终结符,它离开了罪犯规则的关联递归应用程序,或者是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([])     --> [].