Search code examples
prologswi-prologdcg

parsing stdin with dcg


I am having some difficulties understanding how to parse some text from stdin to the desired variables using DCG.

Players: player1 & player2

Board : 3 moves

1A : player1
5D : player2
8Z : player1

So a game has two player variable names and then some moves by each player, I would like to have predicate that unifies Players = [player1,player2] , turn1 = [1A,8A] , turn2 = [5D].

How Would I do this using DCG ?

I have tried the following:

main :-
    read_string(user_input,"\n","\r",_,FirstLine),
    phrase(readPlayers(Players),FirstLine),
    write(Players).

parsePlayers --> [Players].
parseColon --> [:].
parseSpace --> [ ].
readPlayers([P1,P2]) --> parsePlayers,parseColon,parseSpace,P1,parseSpace,[&], parseSpace,P2.   

However this doesn't work in SWI-Prolog, how can I achieve this?


Solution

  • I would use library(dcg/basics), that offers some relatively low level utilities. It can be coupled with library(dcg/high_order), to further enhance your parser.

    :- use_module(library(dcg/basics)).
    :- use_module(library(dcg/high_order)).
    
    player(P) -->
        code(csymf,C),
        codes(csym,Cs),
        {atom_codes(P,[C|Cs])}.
    
    players(Ps) -->
        "Players",
        sep(":"),
        sequence(player,sep("&"),Ps),
        blanks.
    
    % my utilities
    sep(S) --> whites, S, whites.
    code(T,C) --> [C], {code_type(C,T)}.
    codes(T,Cs) --> sequence(code(T),Cs).
    
    

    To test the grammar you can call directly the nonterminal. Note the grammar accepts more that 2 players and correctly skips white spaces, in a flexible way.

    ?- phrase(players(Ps),`Players: player1 & player2&  player3`).
    Ps = [player1, player2, player3] ;
    false.