Search code examples
prologdcg

DCGs - how to split an atom into a list for further dcg rule processing


I have a simple grammar, which takes 3 list items and runs a different dcg rule on each.

[debug]  ?- phrase(sentence(X), [sky, a, 1], []).
X = [bright, amber, on] .

Code:

sentence([A,C,R]) --> 
    analyse(A),
    colour(C),
    rating(R).

analyse(bright) --> [sky].
analyse(dark) --> [cave].

colour(red) --> [r]. 
colour(amber) --> [a]. 
colour(green) --> [g]. 

rating(on) --> [1].
rating(off) --> [0].

This works fine.

My problem is that my input list needs needs to have 2 items, not 3, and the second atom is a concat atom of colour and rating:

[sky, a1]

So somehow I have to (?) split this atom into [a, 1] and then the colour and rating rules will work with a simple dcg rule.

I can't work out how to do this..obviously with normal prolog, I'd just use atom_chars, but I can't work out how to interleave this with the grammar.

In a perfect world, it feels like I should not have to resort to using atom_chars, and I should be able to come up with a simple dcg rule to split it, but I'm not sure if this is possible, since we are parsing lists, not atoms.


Solution

  • As you have said yourself, you just need to use a predicate like atom_chars/2. You can interleave normal code into a DCG rule by enclosing it in { and }.

    But there is something fishy about your problem definition. As you have also said yourself, you are parsing a list, not an atom. The list you are parsing should be already properly tokenized, otherwise you cannot expect to define a DCG that can parse it. Or am I seeing this wrong?

    So in other words: you take your input, split into single chars, tokenize that using a DCG. Depending on your input, you can do the parsing in the same step.