Difficulties with implementing DSL in Prolog from EBNF using DCG

I am working on an implementation of the Google Protobuf compiler for proto files in Prolog to generate Prolog programs. Prolog SWI-Prolog .

I translated EBNF definitions into DCG and ran into several problems:

  • I need to deal with the [ ... ] and { ... } EBNF construct, meaning optional (executable zero or once) and repeatative (executable any number of times);

  • I need to insert callbacks into DCG code in order to implement some of the compiler functions (syntax switching / import / etc) using the DCG { ... } construct, which allows targets in the Prolog syntax inside DCG rules.

I apply for optional and repeatative meta-predicates: $$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 ) }, ";". 

The look is awkward (if not ugly) for me ...

Questions:

What is wrong with my decisions?

Should I manually translate EBNG to DCG without using meta predicates?

What is the alternative for inconveniently breaking into a DCG rule?

+5
source share
1 answer

At first glance, the main problem is that you are uncleanly mixing DCG with regular Prolog predicates.

Stay in DCG to identify all non-terminals. For instance:

  optional (NT) -> [] |  NT.

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

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

In the following example:

  a -> [a].

We can publish messages:

  ? - 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].

This seems to work the way you need it.

For a callback, you can simply bypass the predicate you need to call with a common outline:

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

It looks quite normal.

If such patterns occur frequently, you can always consider creating such DCGs from another view that allows you to complete the task more cleanly.

+5
source

Source: https://habr.com/ru/post/1267257/


All Articles