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

Ant*_*lov 6 prolog ebnf dcg

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

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

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

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

我正在申请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 )
}, ";".
Run Code Online (Sandbox Code Playgroud)

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

问题:

我的解决方案有什么问题?

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

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

mat*_*mat 6

从第一眼看,主要问题是你是不正确地将 DCG与常规的Prolog谓词混合在一起.

留在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,以便更清晰地表示任务.

  • 别客气!使用 `!/0` 可以防止您在所有方向上使用语法,例如*生成*答案。如果您概括了 `decimal//1`,这将是可能的。 (2认同)