Question

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.

Was it helpful?

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.

OTHER TIPS

It was clear that a refined DCG rule could work, but, alas, it took too much time to me to craft a solution for your problem.

Here it is:

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

colour(X), As --> [A], {
    atom_codes(A, Cs),
    maplist(char2atomic, Cs, L),
    phrase(colour(X), L, As)}.

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

char2atomic(C, A) :- code_type(C, digit) -> number_codes(A, [C]) ; atom_codes(A, [C]).

yields

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

the key it's the use of 'pushback' (i.e. colour(X), As -->...). Here we split the unparsable input, consume a token, and push back the rest...

As usual, most of time was required to understand where my first attempt failed: I was coding char2atomic(C, A) :- atom_codes(A, [C])., but then rating//1 failed...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top