我正在为Prolog中的proto文件实现Google Protobuf编译器,以生成Prolog程序.Prolog是SWI-Prolog.
我正在将EBNF定义翻译成DCG,并遇到了一些问题:
我必须处理[ ... ]和{ ... }EBNF构造 - 意思 optional(可执行零或一次)和repeatative(可执行任意次);
我必须使用DCG的构造将回调插入到DCG代码中以实现编译器功能的一部分(语法切换/导入/等){ ... },这允许在DCG规则内的Prolog语法中实现目标.
我正在申请optional和repeatative元谓词:$$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规则的替代方案是什么?
从第一眼看,主要问题是你是不正确地将 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,以便更清晰地表示任务.