我正在为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 )
}, ";".
对我来说尴尬(如果不是说难看)......
问题:
我的解决方案出了什么问题?
我应该在不使用元谓词的情况下手动将EBNG转换为DCG吗?
尴尬地渗透到DCG规则的替代方案是什么?
答案 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,以便更清晰地表示任务。