使用DCG从EBNF在Prolog中实现DSL的困难

时间:2017-04-28 06:31:57

标签: prolog dcg ebnf

我正在为Prolog中的 proto 文件实施Google Protobuf编译器,以生成Prolog程序。 Prolog SWI-Prolog

我正在将 EBNF 定义翻译成DCG并遇到一些问题:

  1. 我必须处理[ ... ]{ ... } EBNF构造 - 意味着optional(可执行零或一次)和repeatative(可执行任意次数) );

  2. 我必须将回调插入到DCG代码中,以使用DCG的构造{ ... }实现编译器功能的一部分(语法切换/导入/等),这允许目标在DCG规则中的Prolog语法中。

  3. 我正在申请optionalrepeatative元谓词:$$rep/1$$opt/1

    EBNF
    decimals  = decimalDigit { decimalDigit }
    exponent  = ( "e" | "E" ) [ "+" | "-" ] decimals 
    
    DCG
    decimals  --> decimalDigit, '$$rep'( decimalDigit ).
    exponent  --> ( "e"; "E" ), '$$opt'( "+"; "-" ), decimals.
    
    '$$rep'( Goal ) :- repeat, call(Goal); !, fail.
    
    '$$opt'( Goal ) :- once(Goal) ; \+ Goal.
    
    "Callback:"
    import --> "import", opt(( "weak" ; "public", { record(public)} )), strLit,
    {
         import(public, strlit )
    }, ";".
    

    对我来说尴尬(如果不是说难看)......

    问题:

    我的解决方案出了什么问题?

    我应该在不使用元谓词的情况下手动将EBNG转换为DCG吗?

    尴尬地渗透到DCG规则的替代方案是什么?

1 个答案:

答案 0 :(得分:6)

从快速的第一眼看,主要问题是你用常规的Prolog谓词不洁混合 DCG。

留在DCG内以定义所有非终结符号。例如:

optional(NT) --> [] | NT.

once_or_more(NT) --> NT, or_more(NT).

or_more(NT) --> [] | NT, or_more(NT).

使用以下示例定义:

a --> [a].

我们可以发布:

?- phrase(optional(a), Ls).
Ls = [] ;
Ls = [a].

?- phrase(once_or_more(a), Ls).
Ls = [a] ;
Ls = [a, a] ;
Ls = [a, a, a] ;
Ls = [a, a, a, a] ;
Ls = [a, a, a, a, a] .

这似乎可以在您需要时使用。

对于回调,您可以简单地传递需要调用的谓词,并使用一般大纲:

parse_with_callback(Goal) -->
        ...,
        { Goal },
        ...

这似乎很好。

如果频繁出现此类模式,您可以始终考虑从不同的表示中生成此类DCG,以便更清晰地表示任务。